Index: user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c (nonexistent) @@ -1,200 +0,0 @@ -/*- - * Copyright (c) 2012 Cisco Systems, Inc. - * All rights reserved. - * - * This software was developed by Bjoern Zeeb under contract to - * Cisco Systems, Inc.. - * - * 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$ - */ - -/* - * Regression test on SO_SETFIB setsockopt(2). - * - * Check that the expected domain(9) families all handle the socket option - * correctly and do proper bounds checks. - * - * Test plan: - * 1. Get system wide number of FIBs from sysctl and convert to index (-= 1). - * 2. For each protocol family (INET, INET6, ROUTE and LOCAL) open socketes of - * type (STREAM, DGRAM and RAW) as supported. - * 3. Do a sequence of -2, -1, 0, .. n, n+1, n+2 SO_SETFIB sockopt calls, - * expecting the first two and last two to fail (valid 0 ... n). - * 4. Try 3 random numbers. Calculate result based on valid range. - * 5. Repeat for next domain family and type from (2) on. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static struct t_dom { - int domain; - const char *name; -} t_dom[] = { -#ifdef INET6 - { .domain = PF_INET6, .name = "PF_INET6" }, -#endif -#ifdef INET - { .domain = PF_INET, .name = "PF_INET" }, -#endif - { .domain = PF_ROUTE, .name = "PF_ROUTE" }, - { .domain = PF_LOCAL, .name = "PF_LOCAL" }, -}; - -static struct t_type { - int type; - const char *name; -} t_type[] = { - { .type = SOCK_STREAM, .name = "SOCK_STREAM" }, - { .type = SOCK_DGRAM, .name = "SOCK_DGRAM" }, - { .type = SOCK_RAW, .name = "SOCK_RAW" }, -}; - -/* - * Number of FIBs as read from net.fibs sysctl - 1. Initialize to clear out of - * bounds value to not accidentally run on a limited range. - */ -static int rt_numfibs = -42; - -/* Number of test case. */ -static int testno = 1; - - -/* - * Try the setsockopt with given FIB number i on socket s. - * Handle result given on error and valid range and errno. - */ -static void -so_setfib(int s, int i, u_int dom, u_int type) -{ - int error; - - error = setsockopt(s, SOL_SOCKET, SO_SETFIB, &i, sizeof(i)); - /* For out of bounds we expect an error. */ - if (error == -1 && (i < 0 || i > rt_numfibs)) - printf("ok %d %s_%s_%d\n", testno, t_dom[dom].name, - t_type[type].name, i); - else if (error != -1 && (i < 0 || i > rt_numfibs)) - printf("not ok %d %s_%s_%d # setsockopt(%d, SOL_SOCKET, " - "SO_SETFIB, %d, ..) unexpectedly succeeded\n", testno, - t_dom[dom].name, t_type[type].name, i, s, i); - else if (error == 0) - printf("ok %d %s_%s_%d\n", testno, t_dom[dom].name, - t_type[type].name, i); - else if (errno != EINVAL) - printf("not ok %d %s_%s_%d # setsockopt(%d, SOL_SOCKET, " - "SO_SETFIB, %d, ..) unexpected error: %s\n", testno, - t_dom[dom].name, t_type[type].name, i, s, i, - strerror(errno)); - else - printf("not ok %d %s_%s_%d\n", testno, t_dom[dom].name, - t_type[type].name, i); - - /* Test run done, next please. */ - testno++; -} - -/* - * Main test. Open socket given domain family and type. For each FIB, out of - * bounds FIB numbers and 3 random FIB numbers set the socket option. - */ -static void -t(u_int dom, u_int type) -{ - int i, s; - - /* PF_ROUTE only supports RAW socket types, while PF_LOCAL does not. */ - if (t_dom[dom].domain == PF_ROUTE && t_type[type].type != SOCK_RAW) - return; - if (t_dom[dom].domain == PF_LOCAL && t_type[type].type == SOCK_RAW) - return; - - /* Open socket for given combination. */ - s = socket(t_dom[dom].domain, t_type[type].type, 0); - if (s == -1) { - printf("not ok %d %s_%s # socket(): %s\n", testno, - t_dom[dom].name, t_type[type].name, strerror(errno)); - testno++; - return; - } - - /* Test FIBs -2, -1, 0, .. n, n + 1, n + 2. */ - for (i = -2; i <= (rt_numfibs + 2); i++) - so_setfib(s, i, dom, type); - - /* Test 3 random FIB numbers. */ - for (i = 0; i < 3; i++) - so_setfib(s, (int)random(), dom, type); - - /* Close socket. */ - close(s); -} - -/* - * Returns 0 if no program error, 1 on sysctlbyname error. - * Test results are communicated by printf("[not ]ok .."). - */ -int -main(int argc __unused, char *argv[] __unused) -{ - u_int i, j; - size_t s; - - if (geteuid() != 0) { - printf("1..0 # SKIP: must be root"); - return (0); - } - - /* Initalize randomness. */ - srandomdev(); - - /* Get number of FIBs supported by kernel. */ - s = sizeof(rt_numfibs); - if (sysctlbyname("net.fibs", &rt_numfibs, &s, NULL, 0) == -1) - err(1, "sysctlbyname(net.fibs, ..)"); - - printf("1..%lu\n", - (nitems(t_dom) - 1) * nitems(t_type) * (2 + rt_numfibs + 2 + 3)); - - /* Adjust from number to index. */ - rt_numfibs -= 1; - - /* Run tests. */ - for (i = 0; i < sizeof(t_dom) / sizeof(struct t_dom); i++) - for (j = 0; j < sizeof(t_type) / sizeof(struct t_type); j++) - t(i, j); - - return (0); -} - -/* end */ Property changes on: user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_socket_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_socket_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_socket_test.c (nonexistent) @@ -1,84 +0,0 @@ -/*- - * Copyright (c) 2006 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$ - */ - -/* - * Simple UNIX domain socket regression test: create and tear down various - * supported and unsupported socket types. - */ - -#include -#include -#include - -#include -#include -#include - -int -main(void) -{ - int sock, socks[2]; - - sock = socket(PF_LOCAL, SOCK_STREAM, 0); - if (sock < 0) - err(-1, "socket(PF_LOCAL, SOCK_STREAM, 0)"); - close(sock); - - sock = socket(PF_LOCAL, SOCK_DGRAM, 0); - if (sock < 0) - err(-1, "socket(PF_LOCAL, SOCK_DGRAM, 0)"); - close(sock); - - sock = socket(PF_LOCAL, SOCK_RAW, 0); - if (sock >= 0) { - close(sock); - errx(-1, "socket(PF_LOCAL, SOCK_RAW, 0) returned %d", sock); - } - if (errno != EPROTONOSUPPORT) - err(-1, "socket(PF_LOCAL, SOCK_RAW, 0)"); - - if (socketpair(PF_LOCAL, SOCK_STREAM, 0, socks) < 0) - err(-1, "socketpair(PF_LOCAL, SOCK_STREAM, 0, socks)"); - if (socks[0] < 0) - errx(-1, "socketpair(PF_LOCAL, SOCK_STREAM, 0, socks) [0] < 0"); - if (socks[1] < 0) - errx(-1, "socketpair(PF_LOCAL, SOCK_STREAM, 0, socks) [1] < 1"); - close(socks[0]); - close(socks[1]); - - if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks) < 0) - err(-1, "socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks)"); - if (socks[0] < 0) - errx(-1, "socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks) [0] < 0"); - if (socks[1] < 0) - errx(-1, "socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks) [1] < 1"); - close(socks[0]); - close(socks[1]); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_socket_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/shutdown_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/shutdown_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/shutdown_test.c (nonexistent) @@ -1,110 +0,0 @@ -/*- - * Copyright (C) 2005 The FreeBSD Project. 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 - -int -main(void) -{ - struct sockaddr_in sock; - socklen_t len; - int listen_sock, connect_sock; - u_short port; - - listen_sock = -1; - - /* Shutdown(2) on an invalid file descriptor has to return EBADF. */ - if ((shutdown(listen_sock, SHUT_RDWR) != -1) && (errno != EBADF)) - errx(-1, "shutdown() for invalid file descriptor does not " - "return EBADF"); - - listen_sock = socket(PF_INET, SOCK_STREAM, 0); - if (listen_sock == -1) - errx(-1, - "socket(PF_INET, SOCK_STREAM, 0) for listen socket: %s", - strerror(errno)); - - bzero(&sock, sizeof(sock)); - sock.sin_len = sizeof(sock); - sock.sin_family = AF_INET; - sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sock.sin_port = 0; - - if (bind(listen_sock, (struct sockaddr *)&sock, sizeof(sock)) < 0) - errx(-1, "bind(%s, %d) for listen socket: %s", - inet_ntoa(sock.sin_addr), sock.sin_port, strerror(errno)); - - len = sizeof(sock); - if (getsockname(listen_sock, (struct sockaddr *)&sock, &len) < 0) - errx(-1, "getsockname() for listen socket: %s", - strerror(errno)); - port = sock.sin_port; - - if (listen(listen_sock, -1) < 0) - errx(-1, "listen() for listen socket: %s", strerror(errno)); - - connect_sock = socket(PF_INET, SOCK_STREAM, 0); - if (connect_sock == -1) - errx(-1, "socket(PF_INET, SOCK_STREAM, 0) for connect " - "socket: %s", strerror(errno)); - - bzero(&sock, sizeof(sock)); - sock.sin_len = sizeof(sock); - sock.sin_family = AF_INET; - sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sock.sin_port = port; - - if (connect(connect_sock, (struct sockaddr *)&sock, sizeof(sock)) < 0) - errx(-1, "connect() for connect socket: %s", strerror(errno)); - /* Try to pass an invalid flags. */ - if ((shutdown(connect_sock, SHUT_RD - 1) != -1) && (errno != EINVAL)) - errx(-1, "shutdown(SHUT_RD - 1) does not return EINVAL"); - if ((shutdown(connect_sock, SHUT_RDWR + 1) != -1) && (errno != EINVAL)) - errx(-1, "shutdown(SHUT_RDWR + 1) does not return EINVAL"); - - if (shutdown(connect_sock, SHUT_RD) < 0) - errx(-1, "shutdown(SHUT_RD) for connect socket: %s", - strerror(errno)); - if (shutdown(connect_sock, SHUT_WR) < 0) - errx(-1, "shutdown(SHUT_WR) for connect socket: %s", - strerror(errno)); - - close(connect_sock); - close(listen_sock); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/shutdown_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_sendtorace_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_sendtorace_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_sendtorace_test.c (nonexistent) @@ -1,215 +0,0 @@ -/*- - * Copyright (c) 2006 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$ - */ - -/* - * Attempts to exercise UNIX domain socket races relating to the non-atomic - * connect-and-send properties of sendto(). As the result of such a race is - * a kernel panic, this test simply completes or doesn't. - * - * XXX: Despite implementing support for sendto() on stream sockets with - * implied connect, the appropriate flag isn't set in the FreeBSD kernel so - * it does not work. For now, don't call the stream test. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#define ITERATIONS 1000000 - -static char socket_path[] = "tmp.XXXXXX"; - -static void -stream_server(int listenfd) -{ - int acceptfd; - - while (1) { - acceptfd = accept(listenfd, NULL, NULL); - if (acceptfd < 0) { - warn("stream_server: accept"); - continue; - } - sleep(1); - close(acceptfd); - } -} - -static void -stream_client(void) -{ - struct sockaddr_un sun; - ssize_t len; - char c = 0; - int fd, i; - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, socket_path); - for (i = 0; i < ITERATIONS; i++) { - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - warn("stream_client: socket"); - return; - } - len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun, - sizeof(sun)); - if (len < 0) - warn("stream_client: sendto"); - close(fd); - } -} - -static void -stream_test(void) -{ - struct sockaddr_un sun; - pid_t childpid; - int listenfd; - - listenfd = socket(PF_UNIX, SOCK_STREAM, 0); - if (listenfd < 0) - err(-1, "stream_test: socket"); - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, socket_path); - - if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) - err(-1, "stream_test: bind"); - - if (listen(listenfd, -1) < 0) - err(-1, "stream_test: listen"); - - childpid = fork(); - if (childpid < 0) - err(-1, "stream_test: fork"); - - if (childpid != 0) { - sleep(1); - stream_client(); - kill(childpid, SIGTERM); - sleep(1); - } else - stream_server(listenfd); - - (void)unlink(socket_path); -} - -static void -datagram_server(int serverfd) -{ - ssize_t len; - char c; - - while (1) { - len = recv(serverfd, &c, sizeof(c), 0); - if (len < 0) - warn("datagram_server: recv"); - } -} - -static void -datagram_client(void) -{ - struct sockaddr_un sun; - ssize_t len; - char c = 0; - int fd, i; - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, socket_path); - for (i = 0; i < ITERATIONS; i++) { - fd = socket(PF_UNIX, SOCK_DGRAM, 0); - if (fd < 0) { - warn("datagram_client: socket"); - return; - } - len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun, - sizeof(sun)); - if (len < 0) - warn("datagram_client: sendto"); - close(fd); - } -} - -static void -datagram_test(void) -{ - struct sockaddr_un sun; - pid_t childpid; - int serverfd; - - serverfd = socket(PF_UNIX, SOCK_DGRAM, 0); - if (serverfd < 0) - err(-1, "datagram_test: socket"); - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, socket_path); - - if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) - err(-1, "datagram_test: bind"); - - childpid = fork(); - if (childpid < 0) - err(-1, "datagram_test: fork"); - - if (childpid != 0) { - sleep(1); - datagram_client(); - kill(childpid, SIGTERM); - sleep(1); - } else - datagram_server(serverfd); - - (void)unlink(socket_path); -} - -int -main(void) -{ - - if (mkstemp(socket_path) == -1) - err(1, "mkstemp failed"); - (void)unlink(socket_path); - datagram_test(); - if (0) - stream_test(); - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_sendtorace_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_sorflush_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_sorflush_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_sorflush_test.c (nonexistent) @@ -1,99 +0,0 @@ -/*- - * Copyright (c) 2008 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. - */ - -/* - * Reproduce a race in which: - * - * - Process (a) is blocked in read on a socket waiting on data. - * - Process (b) is blocked in shutdown() on a socket waiting on (a). - * - Process (c) delivers a signal to (b) interrupting its wait. - * - * This race is premised on shutdown() not interrupting (a) properly, and the - * signal to (b) causing problems in the kernel. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include - -#include -#include -#include -#include -#include - -static void -receive_and_exit(int s) -{ - ssize_t ssize; - char ch; - - ssize = recv(s, &ch, sizeof(ch), 0); - if (ssize < 0) - err(-1, "receive_and_exit: recv"); - exit(0); -} - -static void -shutdown_and_exit(int s) -{ - - if (shutdown(s, SHUT_RD) < 0) - err(-1, "shutdown_and_exit: shutdown"); - exit(0); -} - -int -main(void) -{ - pid_t pida, pidb; - int sv[2]; - - if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) < 0) - err(-1, "socketpair"); - - pida = fork(); - if (pida < 0) - err(-1, "fork"); - if (pida == 0) - receive_and_exit(sv[1]); - sleep(1); - pidb = fork(); - if (pidb < 0) { - warn("fork"); - (void)kill(pida, SIGKILL); - exit(-1); - } - if (pidb == 0) - shutdown_and_exit(sv[1]); - sleep(1); - if (kill(pidb, SIGKILL) < 0) - err(-1, "kill"); - sleep(1); - printf("ok 1 - unix_sorflush\n"); - exit(0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_sorflush_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/kqueue_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/kqueue_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/kqueue_test.c (nonexistent) @@ -1,368 +0,0 @@ -/*- - * Copyright (c) 2004 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 - -static int curtest = 1; - -/*- - * This test uses UNIX domain socket pairs to perform some basic exercising - * of kqueue functionality on sockets. In particular, testing that for read - * and write filters, we see the correct detection of whether reads and - * writes should actually be able to occur. - * - * TODO: - * - Test read/write filters for listen/accept sockets. - * - Handle the XXXRW below regarding datagram sockets. - * - Test that watermark/buffer size "data" fields returned by kqueue are - * correct. - * - Check that kqueue does something sensible when the remote endpoing is - * closed. - */ - -#define OK(testname) printf("ok %d - %s\n", curtest, testname); \ - curtest++; - -static void -fail(int error, const char *func, const char *socktype, const char *rest) -{ - - printf("not ok %d\n", curtest); - - if (socktype == NULL) - printf("# %s(): %s\n", func, strerror(error)); - else if (rest == NULL) - printf("# %s(%s): %s\n", func, socktype, - strerror(error)); - else - printf("# %s(%s, %s): %s\n", func, socktype, rest, - strerror(error)); - exit(-1); -} - -static void -fail_assertion(const char *func, const char *socktype, const char *rest, - const char *assertion) -{ - - printf("not ok %d - %s\n", curtest, assertion); - - if (socktype == NULL) - printf("# %s(): assertion %s failed\n", func, - assertion); - else if (rest == NULL) - printf("# %s(%s): assertion %s failed\n", func, - socktype, assertion); - else - printf("# %s(%s, %s): assertion %s failed\n", func, - socktype, rest, assertion); - exit(-1); -} - -/* - * Test read kevent on a socket pair: check to make sure endpoint 0 isn't - * readable when we start, then write to endpoint 1 and confirm that endpoint - * 0 is now readable. Drain the write, then check that it's not readable - * again. Use non-blocking kqueue operations and socket operations. - */ -static void -test_evfilt_read(int kq, int fd[2], const char *socktype) -{ - struct timespec ts; - struct kevent ke; - ssize_t len; - char ch; - int i; - - EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL); - if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) - fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD"); - OK("EVFILT_READ, EV_ADD"); - - /* - * Confirm not readable to begin with, no I/O yet. - */ - ts.tv_sec = 0; - ts.tv_nsec = 0; - i = kevent(kq, NULL, 0, &ke, 1, &ts); - if (i == -1) - fail(errno, "kevent", socktype, "EVFILT_READ"); - OK("EVFILT_READ"); - if (i != 0) - fail_assertion("kevent", socktype, "EVFILT_READ", - "empty socket unreadable"); - OK("empty socket unreadable"); - - /* - * Write a byte to one end. - */ - ch = 'a'; - len = write(fd[1], &ch, sizeof(ch)); - if (len == -1) - fail(errno, "write", socktype, NULL); - OK("write one byte"); - if (len != sizeof(ch)) - fail_assertion("write", socktype, NULL, "write length"); - OK("write one byte length"); - - /* - * Other end should now be readable. - */ - ts.tv_sec = 0; - ts.tv_nsec = 0; - i = kevent(kq, NULL, 0, &ke, 1, &ts); - if (i == -1) - fail(errno, "kevent", socktype, "EVFILT_READ"); - OK("EVFILT_READ"); - if (i != 1) - fail_assertion("kevent", socktype, "EVFILT_READ", - "non-empty socket unreadable"); - OK("non-empty socket unreadable"); - - /* - * Read a byte to clear the readable state. - */ - len = read(fd[0], &ch, sizeof(ch)); - if (len == -1) - fail(errno, "read", socktype, NULL); - OK("read one byte"); - if (len != sizeof(ch)) - fail_assertion("read", socktype, NULL, "read length"); - OK("read one byte length"); - - /* - * Now re-check for readability. - */ - ts.tv_sec = 0; - ts.tv_nsec = 0; - i = kevent(kq, NULL, 0, &ke, 1, &ts); - if (i == -1) - fail(errno, "kevent", socktype, "EVFILT_READ"); - OK("EVFILT_READ"); - if (i != 0) - fail_assertion("kevent", socktype, "EVFILT_READ", - "empty socket unreadable"); - OK("empty socket unreadable"); - - EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) - fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE"); - OK("EVFILT_READ, EV_DELETE"); -} - -static void -test_evfilt_write(int kq, int fd[2], const char *socktype) -{ - struct timespec ts; - struct kevent ke; - ssize_t len; - char ch; - int i; - - EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL); - if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) - fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD"); - OK("EVFILE_WRITE, EV_ADD"); - - /* - * Confirm writable to begin with, no I/O yet. - */ - ts.tv_sec = 0; - ts.tv_nsec = 0; - i = kevent(kq, NULL, 0, &ke, 1, &ts); - if (i == -1) - fail(errno, "kevent", socktype, "EVFILT_WRITE"); - OK("EVFILE_WRITE"); - if (i != 1) - fail_assertion("kevent", socktype, "EVFILT_WRITE", - "empty socket unwritable"); - OK("empty socket unwritable"); - - /* - * Write bytes into the socket until we can't write anymore. - */ - ch = 'a'; - while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {}; - if (len == -1 && errno != EAGAIN && errno != ENOBUFS) - fail(errno, "write", socktype, NULL); - OK("write"); - if (len != -1 && len != sizeof(ch)) - fail_assertion("write", socktype, NULL, "write length"); - OK("write length"); - - /* - * Check to make sure the socket is no longer writable. - */ - ts.tv_sec = 0; - ts.tv_nsec = 0; - i = kevent(kq, NULL, 0, &ke, 1, &ts); - if (i == -1) - fail(errno, "kevent", socktype, "EVFILT_WRITE"); - OK("EVFILT_WRITE"); - if (i != 0) - fail_assertion("kevent", socktype, "EVFILT_WRITE", - "full socket writable"); - OK("full socket writable"); - - EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) - fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE"); - OK("EVFILT_WRITE, EV_DELETE"); -} - -/* - * Basic registration exercise for kqueue(2). Create several types/brands of - * sockets, and confirm that we can register for various events on them. - */ -int -main(void) -{ - int kq, sv[2]; - - printf("1..49\n"); - - kq = kqueue(); - if (kq == -1) - fail(errno, "kqueue", NULL, NULL); - OK("kqueue()"); - - /* - * Create a UNIX domain datagram socket, and attach/test/detach a - * read filter on it. - */ - if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) - fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); - OK("socketpair() 1"); - - if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); - OK("fcntl() 1"); - if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); - OK("fnctl() 2"); - - test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM"); - - if (close(sv[0]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); - OK("close() 1"); - if (close(sv[1]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); - OK("close() 2"); - -#if 0 - /* - * XXXRW: We disable the write test in the case of datagram sockets, - * as kqueue can't tell when the remote socket receive buffer is - * full, whereas the UNIX domain socket implementation can tell and - * returns ENOBUFS. - */ - /* - * Create a UNIX domain datagram socket, and attach/test/detach a - * write filter on it. - */ - if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) - fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); - - if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); - if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); - - test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM"); - - if (close(sv[0]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); - if (close(sv[1]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); -#endif - - /* - * Create a UNIX domain stream socket, and attach/test/detach a - * read filter on it. - */ - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) - fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); - OK("socketpair() 2"); - - if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); - OK("fcntl() 3"); - if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); - OK("fcntl() 4"); - - test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM"); - - if (close(sv[0]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); - OK("close() 3"); - if (close(sv[1]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); - OK("close() 4"); - - /* - * Create a UNIX domain stream socket, and attach/test/detach a - * write filter on it. - */ - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) - fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); - OK("socketpair() 3"); - - if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); - OK("fcntl() 5"); - if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) - fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); - OK("fcntl() 6"); - - test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM"); - - if (close(sv[0]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); - OK("close() 5"); - if (close(sv[1]) == -1) - fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); - OK("close() 6"); - - if (close(kq) == -1) - fail(errno, "close", "kq", NULL); - OK("close() 7"); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/kqueue_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_bindconnect_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_bindconnect_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_bindconnect_test.c (nonexistent) @@ -1,318 +0,0 @@ -/*- - * 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 - -/* - * Simple regression test to exercise some error cases relating to the use of - * bind() and connect() on UNIX domain sockets. In particular, make sure - * that when two sockets rendezvous using the file system name space, they - * get the expected success/failure cases. - * - * TODO: - * - Check that the resulting file mode/owner are right. - * - Do the same tests with UNIX domain sockets. - * - Check the results of getsockaddr() and getpeeraddr(). - */ - -#define SOCK_NAME_ONE "socket.1" -#define SOCK_NAME_TWO "socket.2" - -#define UNWIND_MAX 1024 - -static int unwind_len; -static struct unwind { - char u_path[PATH_MAX]; -} unwind_list[UNWIND_MAX]; - -static void -push_path(const char *path) -{ - - if (unwind_len >= UNWIND_MAX) - err(-1, "push_path: one path too many (%s)", path); - - strlcpy(unwind_list[unwind_len].u_path, path, PATH_MAX); - unwind_len++; -} - -static void -unwind(void) -{ - int i; - - for (i = unwind_len - 1; i >= 0; i--) { - unlink(unwind_list[i].u_path); - rmdir(unwind_list[i].u_path); - } -} - -static int -bind_test(const char *directory_path) -{ - char socket_path[PATH_MAX]; - struct sockaddr_un sun; - int sock1, sock2; - - sock1 = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock1 < 0) { - warn("bind_test: socket(PF_UNIX, SOCK_STREAM, 0)"); - return (-1); - } - - if (snprintf(socket_path, sizeof(socket_path), "%s/%s", - directory_path, SOCK_NAME_ONE) >= PATH_MAX) { - warn("bind_test: snprintf(socket_path)"); - close(sock1); - return (-1); - } - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_UNIX; - if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path) - >= (int)sizeof(sun.sun_path)) { - warn("bind_test: snprintf(sun.sun_path)"); - close(sock1); - return (-1); - } - - if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) < 0) { - warn("bind_test: bind(sun) #1"); - close(sock1); - return (-1); - } - - push_path(socket_path); - - /* - * Once a STREAM UNIX domain socket has been bound, it can't be - * rebound. Expected error is EINVAL. - */ - if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) == 0) { - warnx("bind_test: bind(sun) #2 succeeded"); - close(sock1); - return (-1); - } - if (errno != EINVAL) { - warn("bind_test: bind(sun) #2"); - close(sock1); - return (-1); - } - - sock2 = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock2 < 0) { - warn("bind_test: socket(PF_UNIX, SOCK_STREAM, 0)"); - close(sock1); - return (-1); - } - - /* - * Since a socket is already bound to the pathname, it can't be bound - * to a second socket. Expected error is EADDRINUSE. - */ - if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { - warnx("bind_test: bind(sun) #3 succeeded"); - close(sock1); - close(sock2); - return (-1); - } - if (errno != EADDRINUSE) { - warn("bind_test: bind(sun) #2"); - close(sock1); - close(sock2); - return (-1); - } - - close(sock1); - - /* - * The socket bound to the pathname has been closed, but the pathname - * can't be reused without first being unlinked. Expected error is - * EADDRINUSE. - */ - if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { - warnx("bind_test: bind(sun) #4 succeeded"); - close(sock2); - return (-1); - } - if (errno != EADDRINUSE) { - warn("bind_test: bind(sun) #4"); - close(sock2); - return (-1); - } - - unlink(socket_path); - - /* - * The pathname is now free, so the socket should be able to bind to - * it. - */ - if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) < 0) { - warn("bind_test: bind(sun) #5"); - close(sock2); - return (-1); - } - - close(sock2); - return (0); -} - -static int -connect_test(const char *directory_path) -{ - char socket_path[PATH_MAX]; - struct sockaddr_un sun; - int sock1, sock2; - - sock1 = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock1 < 0) { - warn("connect_test: socket(PF_UNIX, SOCK_STREAM, 0)"); - return (-1); - } - - if (snprintf(socket_path, sizeof(socket_path), "%s/%s", - directory_path, SOCK_NAME_TWO) >= PATH_MAX) { - warn("connect_test: snprintf(socket_path)"); - close(sock1); - return (-1); - } - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_UNIX; - if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path) - >= (int)sizeof(sun.sun_path)) { - warn("connect_test: snprintf(sun.sun_path)"); - close(sock1); - return (-1); - } - - /* - * Try connecting to a path that doesn't yet exist. Should fail with - * ENOENT. - */ - if (connect(sock1, (struct sockaddr *)&sun, sizeof(sun)) == 0) { - warnx("connect_test: connect(sun) #1 succeeded"); - close(sock1); - return (-1); - } - if (errno != ENOENT) { - warn("connect_test: connect(sun) #1"); - close(sock1); - return (-1); - } - - if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) < 0) { - warn("connect_test: bind(sun) #1"); - close(sock1); - return (-1); - } - - if (listen(sock1, 3) < 0) { - warn("connect_test: listen(sock1)"); - close(sock1); - return (-1); - } - - push_path(socket_path); - - sock2 = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock2 < 0) { - warn("socket(PF_UNIX, SOCK_STREAM, 0)"); - close(sock1); - return (-1); - } - - /* - * Do a simple connect and make sure that works. - */ - if (connect(sock2, (struct sockaddr *)&sun, sizeof(sun)) < 0) { - warn("connect(sun) #2"); - close(sock1); - return (-1); - } - - close(sock2); - - close(sock1); - - sock2 = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock2 < 0) { - warn("socket(PF_UNIX, SOCK_STREAM, 0)"); - return (-1); - } - - /* - * Confirm that once the listen socket is closed, we get a - * connection refused (ECONNREFUSED) when attempting to connect to - * the pathname. - */ - if (connect(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { - warnx("connect(sun) #3 succeeded"); - close(sock2); - return (-1); - } - if (errno != ECONNREFUSED) { - warn("connect(sun) #3"); - close(sock2); - return (-1); - } - - close(sock2); - unlink(socket_path); - return (0); -} -int -main(void) -{ - char directory_path[PATH_MAX]; - int error; - - strlcpy(directory_path, "/tmp/unix_bind.XXXXXXX", PATH_MAX); - if (mkdtemp(directory_path) == NULL) - err(-1, "mkdtemp"); - push_path(directory_path); - - error = bind_test(directory_path); - - if (error == 0) - error = connect_test(directory_path); - - unwind(); - return (error); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_bindconnect_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/accf_data_attach_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/accf_data_attach_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/accf_data_attach_test.c (nonexistent) @@ -1,216 +0,0 @@ -/*- - * Copyright (c) 2004 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 - -#define ACCF_NAME "dataready" - -/* - * A number of small tests to confirm that attaching ACCF_DATA accept filters - * to inet4 ports works as expected. We test: - * - * - That no accept filter is attached on a newly created socket. - * - That bind() has no affect on the accept filter state. - * - That we can't attach an accept filter to a socket that isn't in the - * listen state. - * - That after we fail to attach the filter, querying the kernel shows no - * filter attached. - * - That we can attach an accept filter to a socket that is in the listen - * state. - * - That once an accept filter is attached, we can query to make sure it is - * attached. - * - That once an accept filter is attached, we can remove it and query to - * make sure it is removed. - */ -int -main(void) -{ - struct accept_filter_arg afa; - struct sockaddr_in sin; - socklen_t len; - int lso, ret; - - printf("1..11\n"); - - /* - * Step 0. Open socket(). - */ - lso = socket(PF_INET, SOCK_STREAM, 0); - if (lso == -1) - errx(-1, "not ok 1 - socket: %s", strerror(errno)); - printf("ok 1 - socket\n"); - - /* - * Step 1. After socket(). Should return EINVAL, since no accept - * filter should be attached. - */ - bzero(&afa, sizeof(afa)); - len = sizeof(afa); - ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); - if (ret != -1) - errx(-1, "not ok 2 - getsockopt() after socket() succeeded"); - if (errno != EINVAL) - errx(-1, "not ok 2 - getsockopt() after socket() failed with " - "%d (%s)", errno, strerror(errno)); - printf("ok 2 - getsockopt\n"); - - /* - * Step 2. Bind(). Ideally this will succeed. - */ - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(8080); - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - if (bind(lso, (struct sockaddr *)&sin, sizeof(sin)) < 0) - errx(-1, "not ok 3 - bind %s", strerror(errno)); - printf("ok 3 - bind\n"); - - /* - * Step 3: After bind(). getsockopt() should return EINVAL, since no - * accept filter should be attached. - */ - len = sizeof(afa); - ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); - if (ret != -1) - errx(-1, "not ok 4 - getsockopt() after bind() succeeded"); - if (errno != EINVAL) - errx(-1, "not ok 4 - getsockopt() after bind() failed with %d (%s)", - errno, strerror(errno)); - printf("ok 4 - getsockopt\n"); - - /* - * Step 4: Setsockopt() before listen(). Should fail, since it's not - * yet a listen() socket. - */ - bzero(&afa, sizeof(afa)); - strcpy(afa.af_name, ACCF_NAME); - ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); - if (ret == 0) - errx(-1, "not ok 5 - setsockopt() before listen() succeeded"); - printf("ok 5 - setsockopt\n"); - - /* - * Step 5: Getsockopt() after pre-listen() setsockopt(). Should - * fail with EINVAL, since setsockopt() should have failed. - */ - len = sizeof(afa); - ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); - if (ret == 0) - errx(-1, "not ok 6 - getsockopt() after pre-listen() setsockopt() " - "succeeded"); - if (errno != EINVAL) - errx(-1, "not ok 6 - pre-listen() getsockopt() failed with %d (%s)", - errno, strerror(errno)); - printf("ok 6 - getsockopt\n"); - - /* - * Step 6: listen(). - */ - if (listen(lso, -1) < 0) - errx(-1, "not ok 7 - listen: %s", strerror(errno)); - printf("ok 7 - listen\n"); - - /* - * Step 7: Getsockopt() after listen(). Should fail with EINVAL, - * since we have not installed accept filter yet. - */ - len = sizeof(afa); - ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); - if (ret == 0) - errx(-1, "not ok 8 - getsockopt() after listen() but before " - "setsockopt() succeeded"); - if (errno != EINVAL) - errx(-1, "not ok 8 - getsockopt() after listen() but before " - "setsockopt() failed with %d (%s)", errno, strerror(errno)); - printf("ok 8 - getsockopt\n"); - - /* - * Step 8: After listen(). This call to setsockopt() should succeed. - */ - bzero(&afa, sizeof(afa)); - strcpy(afa.af_name, ACCF_NAME); - ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); - if (ret != 0) - errx(-1, "not ok 9 - setsockopt() after listen() failed with %d " - "(%s)", errno, strerror(errno)); - printf("ok 9 - setsockopt\n"); - - /* - * Step 9: After setsockopt(). Should succeed and identify - * ACCF_NAME. - */ - bzero(&afa, sizeof(afa)); - len = sizeof(afa); - ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); - if (ret != 0) - errx(-1, "not ok 10 - getsockopt() after listen() setsockopt() " - "failed with %d (%s)", errno, strerror(errno)); - if (len != sizeof(afa)) - errx(-1, "not ok 10 - getsockopt() after setsockopet() after " - "listen() returned wrong size (got %d expected %zd)", len, - sizeof(afa)); - if (strcmp(afa.af_name, ACCF_NAME) != 0) - errx(-1, "not ok 10 - getsockopt() after setsockopt() after " - "listen() mismatch (got %s expected %s)", afa.af_name, - ACCF_NAME); - printf("ok 10 - getsockopt\n"); - - /* - * Step 10: Remove accept filter. After removing the accept filter - * getsockopt() should fail with EINVAL. - */ - ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0); - if (ret != 0) - errx(-1, "not ok 11 - setsockopt() after listen() " - "failed with %d (%s)", errno, strerror(errno)); - bzero(&afa, sizeof(afa)); - len = sizeof(afa); - ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); - if (ret == 0) - errx(-1, "not ok 11 - getsockopt() after removing " - "the accept filter returns valid accept filter %s", - afa.af_name); - if (errno != EINVAL) - errx(-1, "not ok 11 - getsockopt() after removing the accept" - "filter failed with %d (%s)", errno, strerror(errno)); - printf("ok 11 - setsockopt\n"); - - close(lso); - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/accf_data_attach_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/listen_backlog_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/listen_backlog_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/listen_backlog_test.c (nonexistent) @@ -1,383 +0,0 @@ -/*- - * 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 - -/* - * This regression test is intended to validate that the backlog parameter - * set by listen() is properly set, can be retrieved using SO_LISTENQLIMIT, - * and that it can be updated by later calls to listen(). We also check that - * SO_LISTENQLIMIT cannot be set. - * - * Future things to test: - * - * - That if we change the value of kern.ipc.somaxconn, the limits really - * do change. - * - * - That limits are, approximately, enforced and implemented. - * - * - All this on multiple socket types -- i.e., PF_LOCAL. - * - * - That we also test SO_LISTENQLEN and SO_LISTENINCQLEN. - */ - -/* - * We retrieve kern.ipc.somaxconn before running the tests in order to use a - * run-time set value of SOMAXCONN, rather than compile-time set. We assume - * that no other process will be simultaneously frobbing it, and these tests - * may fail if that assumption is not held. - */ -static int somaxconn; - -/* - * Retrieve the current socket listen queue limit using SO_LISTENQLIMIT. - */ -static int -socket_get_backlog(int sock, int *backlogp, const char *testclass, - const char *test, const char *testfunc) -{ - socklen_t len; - int i; - - len = sizeof(i); - if (getsockopt(sock, SOL_SOCKET, SO_LISTENQLIMIT, &i, &len) < 0) { - warn("%s: %s: %s: socket_get_backlog: getsockopt(" - "SOL_SOCKET, SO_LISTENQLIMIT)", testclass, test, - testfunc); - return (-1); - } - - if (len != sizeof(i)) { - warnx("%s: %s: %s: socket_get_backlog: getsockopt(" - "SOL_SOCKET, SO_LISTENQLIMIT): returned size %d", - testclass, test, testfunc, len); - return (-1); - } - - *backlogp = i; - - return (0); -} - -/* - * Create a socket, check the queue limit on creation, perform a listen(), - * and make sure that the limit was set as expected by listen(). - */ -static int -socket_listen(int domain, int type, int protocol, int backlog, - int create_backlog_assertion, int listen_backlog_assertion, int *sockp, - const char *domainstring, const char *typestring, const char *testclass, - const char *test) -{ - int backlog_retrieved, sock; - - sock = socket(domain, type, protocol); - if (sock < 0) { - warn("%s: %s: socket_listen: socket(%s, %s)", testclass, - test, domainstring, typestring); - close(sock); - return (-1); - } - - if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, - "socket_listen") < 0) { - close(sock); - return (-1); - } - - if (backlog_retrieved != create_backlog_assertion) { - warnx("%s: %s: socket_listen: create backlog is %d not %d", - testclass, test, backlog_retrieved, - create_backlog_assertion); - close(sock); - return (-1); - } - - if (listen(sock, backlog) < 0) { - warn("%s: %s: socket_listen: listen(, %d)", testclass, test, - backlog); - close(sock); - return (-1); - } - - if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, - "socket_listen") < 0) { - close(sock); - return (-1); - } - - if (backlog_retrieved != listen_backlog_assertion) { - warnx("%s: %s: socket_listen: listen backlog is %d not %d", - testclass, test, backlog_retrieved, - listen_backlog_assertion); - close(sock); - return (-1); - } - - *sockp = sock; - return (0); -} - -/* - * This test creates sockets and tests default states before and after - * listen(). Specifically, we expect a queue limit of 0 before listen, and - * then various settings for after listen(). If the passed backlog was - * either < 0 or > somaxconn, it should be set to somaxconn; otherwise, the - * passed queue depth. - */ -static void -test_defaults(void) -{ - int sock; - - /* - * First pass. Confirm the default is 0. Listen with a backlog of - * 0 and confirm it gets set that way. - */ - if (socket_listen(PF_INET, SOCK_STREAM, 0, 0, 0, 0, &sock, "PF_INET", - "SOCK_STREAM", "test_defaults", "default_0_listen_0") < 0) - exit(-1); - close(sock); - - /* - * Second pass. Listen with a backlog of -1 and make sure it is set - * to somaxconn. - */ - if (socket_listen(PF_INET, SOCK_STREAM, 0, -1, 0, somaxconn, &sock, - "PF_INET", "SOCK_STREAM", "test_defaults", "default_0_listen_-1") - < 0) - exit(-1); - close(sock); - - /* - * Third pass. Listen with a backlog of 1 and make sure it is set to - * 1. - */ - if (socket_listen(PF_INET, SOCK_STREAM, 0, 1, 0, 1, &sock, "PF_INET", - "SOCK_STREAM", "test_defaults", "default_0_listen_1") < 0) - exit(-1); - close(sock); - - /* - * Fourth pass. Listen with a backlog of somaxconn and make sure it - * is set to somaxconn. - */ - if (socket_listen(PF_INET, SOCK_STREAM, 0, somaxconn, 0, somaxconn, - &sock, "PF_INET", "SOCK_STREAM", "test_defaults", - "default_0_listen_somaxconn") < 0) - exit(-1); - close(sock); - - /* - * Fifth pass. Listen with a backlog of somaxconn+1 and make sure it - * is set to somaxconn. - */ - if (socket_listen(PF_INET, SOCK_STREAM, 0, somaxconn+1, 0, somaxconn, - &sock, "PF_INET", "SOCK_STREAM", "test_defaults", - "default_0_listen_somaxconn+1") < 0) - exit(-1); - close(sock); -} - -/* - * Create a socket, set the initial listen() state, then update the queue - * depth using listen(). Check that the backlog is as expected after both - * the first and second listen(). - */ -static int -socket_listen_update(int domain __unused, int type __unused, - int protocol __unused, int backlog, - int update_backlog, int listen_backlog_assertion, - int update_backlog_assertion, int *sockp, const char *domainstring, - const char *typestring, const char *testclass, const char *test) -{ - int backlog_retrieved, sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) { - warn("%s: %s: socket_listen_update: socket(%s, %s)", - testclass, test, domainstring, typestring); - return (-1); - } - - if (listen(sock, backlog) < 0) { - warn("%s: %s: socket_listen_update: initial listen(, %d)", - testclass, test, backlog); - close(sock); - return (-1); - } - - if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, - "socket_listen_update") < 0) { - close(sock); - return (-1); - } - - if (backlog_retrieved != listen_backlog_assertion) { - warnx("%s: %s: socket_listen_update: initial backlog is %d " - "not %d", testclass, test, backlog_retrieved, - listen_backlog_assertion); - close(sock); - return (-1); - } - - if (listen(sock, update_backlog) < 0) { - warn("%s: %s: socket_listen_update: update listen(, %d)", - testclass, test, update_backlog); - close(sock); - return (-1); - } - - if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, - "socket_listen_update") < 0) { - close(sock); - return (-1); - } - - if (backlog_retrieved != update_backlog_assertion) { - warnx("%s: %s: socket_listen_update: updated backlog is %d " - "not %d", testclass, test, backlog_retrieved, - update_backlog_assertion); - close(sock); - return (-1); - } - - *sockp = sock; - return (0); -} - -/* - * This test tests using listen() to update the queue depth after a socket - * has already been marked as listening. We test several cases: setting the - * socket < 0, 0, 1, somaxconn, and somaxconn + 1. - */ -static void -test_listen_update(void) -{ - int sock; - - /* - * Set to 5, update to -1, which should give somaxconn. - */ - if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, -1, 5, somaxconn, - &sock, "PF_INET", "SOCK_STREAM", "test_listen_update", - "update_5,-1") < 0) - exit(-1); - close(sock); - - /* - * Set to 5, update to 0, which should give 0. - */ - if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, 0, 5, 0, &sock, - "PF_INET", "SOCK_STREAM", "test_listen_update", "update_5,0") - < 0) - exit(-1); - close(sock); - - /* - * Set to 5, update to 1, which should give 1. - */ - if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, 1, 5, 1, &sock, - "PF_INET", "SOCK_STREAM", "test_listen_update", "update_5,1") - < 0) - exit(-1); - close(sock); - - /* - * Set to 5, update to somaxconn, which should give somaxconn. - */ - if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, somaxconn, 5, - somaxconn, &sock, "PF_INET", "SOCK_STREAM", "test_listen_update", - "update_5,somaxconn") < 0) - exit(-1); - close(sock); - - /* - * Set to 5, update to somaxconn+1, which should give somaxconn. - */ - if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, somaxconn+1, 5, - somaxconn, &sock, "PF_INET", "SOCK_STREAM", "test_listen_update", - "update_5,somaxconn+1") < 0) - exit(-1); - close(sock); -} - -/* - * SO_LISTENQLIMIT is a read-only socket option, so make sure we get an error - * if we try to write it. - */ -static void -test_set_qlimit(void) -{ - int i, ret, sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) - err(-1, "test_set_qlimit: socket(PF_INET, SOCK_STREAM)"); - - i = 0; - ret = setsockopt(sock, SOL_SOCKET, SO_LISTENQLIMIT, &i, sizeof(i)); - if (ret < 0 && errno != ENOPROTOOPT) { - warn("test_set_qlimit: setsockopt(SOL_SOCKET, " - "SO_LISTENQLIMIT, 0): unexpected error"); - close(sock); - } - - if (ret == 0) { - warnx("test_set_qlimit: setsockopt(SOL_SOCKET, " - "SO_LISTENQLIMIT, 0) succeeded"); - close(sock); - exit(-1); - } - close(sock); -} - -int -main(void) -{ - size_t len; - - len = sizeof(somaxconn); - if (sysctlbyname("kern.ipc.somaxconn", &somaxconn, &len, NULL, 0) - < 0) - err(-1, "sysctlbyname(kern.ipc.somaxconn)"); - - test_defaults(); - test_listen_update(); - test_set_qlimit(); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/listen_backlog_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/pr_atomic_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/pr_atomic_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/pr_atomic_test.c (nonexistent) @@ -1,109 +0,0 @@ -/*- - * Copyright (c) 2006 Bruce M. Simpson - * 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$ - */ - -/* - * Regression test for uiomove in kernel; specifically for PR kern/38495. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static char socket_path[] = "tmp.XXXXXX"; - -static jmp_buf myjmpbuf; - -static void handle_sigalrm(int signo __unused) -{ - longjmp(myjmpbuf, 1); -} - -int -main(void) -{ - struct sockaddr_un un; - pid_t pid; - int s; - - if (mkstemp(socket_path) == -1) - err(1, "mkstemp"); - s = socket(PF_LOCAL, SOCK_DGRAM, 0); - if (s == -1) - errx(-1, "socket"); - memset(&un, 0, sizeof(un)); - un.sun_family = AF_LOCAL; - unlink(socket_path); - strcpy(un.sun_path, socket_path); - if (bind(s, (struct sockaddr *)&un, sizeof(un)) == -1) - errx(-1, "bind"); - pid = fork(); - if (pid == -1) - errx(-1, "fork"); - if (pid == 0) { - int conn; - char buf[] = "AAAAAAAAA"; - - close(s); - conn = socket(AF_LOCAL, SOCK_DGRAM, 0); - if (conn == -1) - errx(-1,"socket"); - if (sendto(conn, buf, sizeof(buf), 0, (struct sockaddr *)&un, - sizeof(un)) != sizeof(buf)) - errx(-1,"sendto"); - close(conn); - _exit(0); - } - - sleep(5); - - /* Make sure the data is there when we try to receive it. */ - if (recvfrom(s, (void *)-1, 1, 0, NULL, NULL) != -1) - errx(-1,"recvfrom succeeded when failure expected"); - - (void)signal(SIGALRM, handle_sigalrm); - if (setjmp(myjmpbuf) == 0) { - /* - * This recvfrom will panic an unpatched system, and block - * a patched one. - */ - alarm(5); - (void)recvfrom(s, (void *)-1, 1, 0, NULL, NULL); - } - - /* We should reach here via longjmp() and all should be well. */ - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/pr_atomic_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_cmsg_test.sh =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_cmsg_test.sh (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_cmsg_test.sh (nonexistent) @@ -1,85 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cmd=`echo $0 | sed -e 's,_test$,,'` - -IFS= -n=0 - -run() -{ - result=`${cmd} -t $2 $3 ${5%% *} 2>&1` - if [ $? -ne 0 ]; then - echo -n "not " - fi - echo "ok $1 - $4 ${5#* }" - echo ${result} | grep -E "SERVER|CLIENT" | while read line; do - echo "# ${line}" - done -} - -echo "1..47" - -for t1 in \ - "1 Sending, receiving cmsgcred" \ - "4 Sending cmsgcred, receiving sockcred" \ - "5 Sending, receiving timeval" \ - "6 Sending, receiving bintime" \ - "7 Check cmsghdr.cmsg_len" -do - for t2 in \ - "0 " \ - "1 (no data)" \ - "2 (no array)" \ - "3 (no data, array)" - do - n=$((n + 1)) - run ${n} stream "-z ${t2%% *}" STREAM "${t1} ${t2#* }" - done -done - -for t1 in \ - "2 Receiving sockcred (listening socket)" \ - "3 Receiving sockcred (accepted socket)" -do - for t2 in \ - "0 " \ - "1 (no data)" - do - n=$((n + 1)) - run ${n} stream "-z ${t2%% *}" STREAM "${t1} ${t2#* }" - done -done - -n=$((n + 1)) -run ${n} stream "-z 0" STREAM "8 Check LOCAL_PEERCRED socket option" - -for t1 in \ - "1 Sending, receiving cmsgcred" \ - "3 Sending cmsgcred, receiving sockcred" \ - "4 Sending, receiving timeval" \ - "5 Sending, receiving bintime" \ - "6 Check cmsghdr.cmsg_len" -do - for t2 in \ - "0 " \ - "1 (no data)" \ - "2 (no array)" \ - "3 (no data, array)" - do - n=$((n + 1)) - run ${n} dgram "-z ${t2%% *}" DGRAM "${t1} ${t2#* }" - done -done - -for t1 in \ - "2 Receiving sockcred" -do - for t2 in \ - "0 " \ - "1 (no data)" - do - n=$((n + 1)) - run ${n} dgram "-z ${t2%% *}" DGRAM "${t1} ${t2#* }" - done -done Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_cmsg_test.sh ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_close_race_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_close_race_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_close_race_test.c (nonexistent) @@ -1,143 +0,0 @@ -/*- - * Copyright (c) 2010 Mikolaj Golub - * 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$ - */ - -/* - * This regression test attempts to trigger a race that occurs when both - * endpoints of a connected UNIX domain socket are closed at once. The two - * close paths may run concurrently leading to a call to sodisconnect() on an - * already-closed socket in kernel. Before it was fixed, this might lead to - * ENOTCONN being returned improperly from close(). - * - * This race is fairly timing-dependent, so it effectively requires SMP, and - * may not even trigger then. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static char socket_path[] = "tmp.XXXXXXXX"; - -#define USLEEP 100 -#define LOOPS 100000 - -int -main(void) -{ - struct sockaddr_un servaddr; - int listenfd, connfd, pid; - u_int counter, ncpus; - size_t len; - - len = sizeof(ncpus); - if (sysctlbyname("kern.smp.cpus", &ncpus, &len, NULL, 0) < 0) - err(1, "kern.smp.cpus"); - if (len != sizeof(ncpus)) - errx(1, "kern.smp.cpus: invalid length"); - if (ncpus < 2) - warnx("SMP not present, test may be unable to trigger race"); - - if (mkstemp(socket_path) == -1) - err(1, "mkstemp failed"); - unlink(socket_path); - - /* - * Create a UNIX domain socket that the child will repeatedly - * accept() from, and that the parent will repeatedly connect() to. - */ - if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) - err(1, "parent: socket error"); - (void)unlink(socket_path); - bzero(&servaddr, sizeof(servaddr)); - servaddr.sun_family = AF_LOCAL; - strcpy(servaddr.sun_path, socket_path); - if (bind(listenfd, (struct sockaddr *) &servaddr, - sizeof(servaddr)) < 0) - err(1, "parent: bind error"); - if (listen(listenfd, 1024) < 0) - err(1, "parent: listen error"); - - pid = fork(); - if (pid == -1) - err(1, "fork()"); - if (pid != 0) { - /* - * In the parent, repeatedly connect and disconnect from the - * socket, attempting to induce the race. - */ - close(listenfd); - sleep(1); - bzero(&servaddr, sizeof(servaddr)); - servaddr.sun_family = AF_LOCAL; - strcpy(servaddr.sun_path, socket_path); - for (counter = 0; counter < LOOPS; counter++) { - if ((connfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { - (void)kill(pid, SIGTERM); - err(1, "parent: socket error"); - } - if (connect(connfd, (struct sockaddr *)&servaddr, - sizeof(servaddr)) < 0) { - (void)kill(pid, SIGTERM); - err(1, "parent: connect error"); - } - if (close(connfd) < 0) { - (void)kill(pid, SIGTERM); - err(1, "parent: close error"); - } - usleep(USLEEP); - } - (void)kill(pid, SIGTERM); - } else { - /* - * In the child, loop accepting and closing. We may pick up - * the race here so report errors from close(). - */ - for ( ; ; ) { - if ((connfd = accept(listenfd, - (struct sockaddr *)NULL, NULL)) < 0) - err(1, "child: accept error"); - if (close(connfd) < 0) - err(1, "child: close error"); - } - } - printf("OK\n"); - exit(0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_close_race_test.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/zerosend_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/zerosend_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/zerosend_test.c (nonexistent) @@ -1,290 +0,0 @@ -/*- - * 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 - -#define PORT1 10001 -#define PORT2 10002 - -static void -try_0send(const char *test, int fd) -{ - ssize_t len; - char ch; - - ch = 0; - len = send(fd, &ch, 0, 0); - if (len < 0) - err(-1, "%s: try_0send", test); - if (len != 0) - errx(-1, "%s: try_0send: returned %zd", test, len); -} - -static void -try_0write(const char *test, int fd) -{ - ssize_t len; - char ch; - - ch = 0; - len = write(fd, &ch, 0); - if (len < 0) - err(-1, "%s: try_0write", test); - if (len != 0) - errx(-1, "%s: try_0write: returned %zd", test, len); -} - -static void -setup_udp(const char *test, int *fdp) -{ - struct sockaddr_in sin; - int sock1, sock2; - - 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(PORT1); - sock1 = socket(PF_INET, SOCK_DGRAM, 0); - if (sock1 < 0) - err(-1, "%s: setup_udp: socket", test); - if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) - err(-1, "%s: setup_udp: bind(%s, %d)", test, - inet_ntoa(sin.sin_addr), PORT1); - sin.sin_port = htons(PORT2); - if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) - err(-1, "%s: setup_udp: connect(%s, %d)", test, - inet_ntoa(sin.sin_addr), PORT2); - - sock2 = socket(PF_INET, SOCK_DGRAM, 0); - if (sock2 < 0) - err(-1, "%s: setup_udp: socket", test); - if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) - err(-1, "%s: setup_udp: bind(%s, %d)", test, - inet_ntoa(sin.sin_addr), PORT2); - sin.sin_port = htons(PORT1); - if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) - err(-1, "%s: setup_udp: connect(%s, %d)", test, - inet_ntoa(sin.sin_addr), PORT1); - - fdp[0] = sock1; - fdp[1] = sock2; -} - -static void -setup_tcp(const char *test, int *fdp) -{ - fd_set writefds, exceptfds; - struct sockaddr_in sin; - int 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); - - /* - * First set up the listen socket. - */ - sin.sin_port = htons(PORT1); - sock1 = socket(PF_INET, SOCK_STREAM, 0); - if (sock1 < 0) - err(-1, "%s: setup_tcp: socket", test); - if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) - err(-1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr), - PORT1); - if (listen(sock1, -1) < 0) - err(-1, "%s: listen", test); - - /* - * Now connect to it, non-blocking so that we don't deadlock against - * ourselves. - */ - sock2 = socket(PF_INET, SOCK_STREAM, 0); - if (sock2 < 0) - err(-1, "%s: setup_tcp: socket", test); - if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0) - err(-1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test); - if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0 && - errno != EINPROGRESS) - err(-1, "%s: setup_tcp: connect(%s, %d)", test, - inet_ntoa(sin.sin_addr), PORT1); - - /* - * Now pick up the connection after sleeping a moment to make sure - * there's been time for some packets to go back and forth. - */ - if (sleep(1) < 0) - err(-1, "%s: sleep(1)", test); - sock3 = accept(sock1, NULL, NULL); - if (sock3 < 0) - err(-1, "%s: accept", test); - if (sleep(1) < 0) - err(-1, "%s: sleep(1)", test); - - 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); - if (ret < 0) - err(-1, "%s: setup_tcp: select", test); - if (FD_ISSET(sock2, &exceptfds)) - errx(-1, "%s: setup_tcp: select: exception", test); - if (!FD_ISSET(sock2, &writefds)) - errx(-1, "%s: setup_tcp: select: not writable", test); - - close(sock1); - fdp[0] = sock2; - fdp[1] = sock3; -} - -static void -setup_udsstream(const char *test, int *fdp) -{ - - if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0) - err(-1, "%s: setup_udsstream: socketpair", test); -} - -static void -setup_udsdgram(const char *test, int *fdp) -{ - - if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0) - err(-1, "%s: setup_udsdgram: socketpair", test); -} - -static void -setup_pipe(const char *test, int *fdp) -{ - - if (pipe(fdp) < 0) - err(-1, "%s: setup_pipe: pipe", test); -} - -static void -setup_fifo(const char *test, int *fdp) -{ - char path[] = "0send_fifo.XXXXXXX"; - int fd1, fd2; - - if (mkstemp(path) == -1) - err(-1, "%s: setup_fifo: mktemp", test); - unlink(path); - - if (mkfifo(path, 0600) < 0) - err(-1, "%s: setup_fifo: mkfifo(%s)", test, path); - - fd1 = open(path, O_RDONLY | O_NONBLOCK); - if (fd1 < 0) - err(-1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path); - - fd2 = open(path, O_WRONLY | O_NONBLOCK); - if (fd2 < 0) - err(-1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path); - - fdp[0] = fd2; - fdp[1] = fd1; -} - -static void -close_both(int *fdp) -{ - - close(fdp[0]); - fdp[0] = -1; - close(fdp[1]); - fdp[1] = -1; -} - -int -main(int argc, char *argv[]) -{ - int fd[2]; - - setup_udp("udp_0send", fd); - try_0send("udp_0send", fd[0]); - close_both(fd); - - setup_udp("udp_0write", fd); - try_0write("udp_0write", fd[0]); - close_both(fd); - - setup_tcp("tcp_0send", fd); - try_0send("tcp_0send", fd[0]); - close_both(fd); - - setup_tcp("tcp_0write", fd); - try_0write("tcp_0write", fd[0]); - close_both(fd); - - setup_udsstream("udsstream_0send", fd); - try_0send("udsstream_0send", fd[0]); - close_both(fd); - - setup_udsstream("udsstream_0write", fd); - try_0write("udsstream_0write", fd[0]); - close_both(fd); - - setup_udsdgram("udsdgram_0send", fd); - try_0send("udsdgram_0send", fd[0]); - close_both(fd); - - setup_udsdgram("udsdgram_0write", fd); - try_0write("udsdgram_0write", fd[0]); - close_both(fd); - - setup_pipe("pipe_0write", fd); - try_0write("pipd_0write", fd[0]); - close_both(fd); - - setup_fifo("fifo_0write", fd); - try_0write("fifo_0write", fd[0]); - close_both(fd); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/zerosend_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_cmsg.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_cmsg.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_cmsg.c (nonexistent) @@ -1,1969 +0,0 @@ -/*- - * Copyright (c) 2005 Andrey Simonenko - * 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. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * There are tables with tests descriptions and pointers to test - * functions. Each t_*() function returns 0 if its test passed, - * -1 if its test failed, -2 if some system error occurred. - * If a test function returns -2, then a program exits. - * - * If a test function forks a client process, then it waits for its - * termination. If a return code of a client process is not equal - * to zero, or if a client process was terminated by a signal, then - * a test function returns -1 or -2 depending on exit status of - * a client process. - * - * Each function which can block, is run under TIMEOUT. If timeout - * occurs, then a test function returns -2 or a client process exits - * with a non-zero return code. - */ - -#ifndef LISTENQ -# define LISTENQ 1 -#endif - -#ifndef TIMEOUT -# define TIMEOUT 2 -#endif - -static int t_cmsgcred(void); -static int t_sockcred_1(void); -static int t_sockcred_2(void); -static int t_cmsgcred_sockcred(void); -static int t_timeval(void); -static int t_bintime(void); -static int t_cmsg_len(void); -static int t_peercred(void); - -struct test_func { - int (*func)(void); - const char *desc; -}; - -static const struct test_func test_stream_tbl[] = { - { - .func = NULL, - .desc = "All tests" - }, - { - .func = t_cmsgcred, - .desc = "Sending, receiving cmsgcred" - }, - { - .func = t_sockcred_1, - .desc = "Receiving sockcred (listening socket)" - }, - { - .func = t_sockcred_2, - .desc = "Receiving sockcred (accepted socket)" - }, - { - .func = t_cmsgcred_sockcred, - .desc = "Sending cmsgcred, receiving sockcred" - }, - { - .func = t_timeval, - .desc = "Sending, receiving timeval" - }, - { - .func = t_bintime, - .desc = "Sending, receiving bintime" - }, - { - .func = t_cmsg_len, - .desc = "Check cmsghdr.cmsg_len" - }, - { - .func = t_peercred, - .desc = "Check LOCAL_PEERCRED socket option" - } -}; - -#define TEST_STREAM_TBL_SIZE \ - (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0])) - -static const struct test_func test_dgram_tbl[] = { - { - .func = NULL, - .desc = "All tests" - }, - { - .func = t_cmsgcred, - .desc = "Sending, receiving cmsgcred" - }, - { - .func = t_sockcred_2, - .desc = "Receiving sockcred" - }, - { - .func = t_cmsgcred_sockcred, - .desc = "Sending cmsgcred, receiving sockcred" - }, - { - .func = t_timeval, - .desc = "Sending, receiving timeval" - }, - { - .func = t_bintime, - .desc = "Sending, receiving bintime" - }, - { - .func = t_cmsg_len, - .desc = "Check cmsghdr.cmsg_len" - } -}; - -#define TEST_DGRAM_TBL_SIZE \ - (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0])) - -static bool debug = false; -static bool server_flag = true; -static bool send_data_flag = true; -static bool send_array_flag = true; -static bool failed_flag = false; - -static int sock_type; -static const char *sock_type_str; - -static const char *proc_name; - -static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX"; -static int serv_sock_fd; -static struct sockaddr_un serv_addr_sun; - -static struct { - char *buf_send; - char *buf_recv; - size_t buf_size; - u_int msg_num; -} ipc_msg; - -#define IPC_MSG_NUM_DEF 5 -#define IPC_MSG_NUM_MAX 10 -#define IPC_MSG_SIZE_DEF 7 -#define IPC_MSG_SIZE_MAX 128 - -static struct { - uid_t uid; - uid_t euid; - gid_t gid; - gid_t egid; - gid_t *gid_arr; - int gid_num; -} proc_cred; - -static pid_t client_pid; - -#define SYNC_SERVER 0 -#define SYNC_CLIENT 1 -#define SYNC_RECV 0 -#define SYNC_SEND 1 - -static int sync_fd[2][2]; - -#define LOGMSG_SIZE 128 - -static void logmsg(const char *, ...) __printflike(1, 2); -static void logmsgx(const char *, ...) __printflike(1, 2); -static void dbgmsg(const char *, ...) __printflike(1, 2); -static void output(const char *, ...) __printflike(1, 2); - -static void -usage(bool verbose) -{ - u_int i; - - printf("usage: %s [-dh] [-n num] [-s size] [-t type] " - "[-z value] [testno]\n", getprogname()); - if (!verbose) - return; - printf("\n Options are:\n\ - -d Output debugging information\n\ - -h Output the help message and exit\n\ - -n num Number of messages to send\n\ - -s size Specify size of data for IPC\n\ - -t type Specify socket type (stream, dgram) for tests\n\ - -z value Do not send data in a message (bit 0x1), do not send\n\ - data array associated with a cmsghdr structure (bit 0x2)\n\ - testno Run one test by its number (require the -t option)\n\n"); - printf(" Available tests for stream sockets:\n"); - for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i) - printf(" %u: %s\n", i, test_stream_tbl[i].desc); - printf("\n Available tests for datagram sockets:\n"); - for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i) - printf(" %u: %s\n", i, test_dgram_tbl[i].desc); -} - -static void -output(const char *format, ...) -{ - char buf[LOGMSG_SIZE]; - va_list ap; - - va_start(ap, format); - if (vsnprintf(buf, sizeof(buf), format, ap) < 0) - err(EXIT_FAILURE, "output: vsnprintf failed"); - write(STDOUT_FILENO, buf, strlen(buf)); - va_end(ap); -} - -static void -logmsg(const char *format, ...) -{ - char buf[LOGMSG_SIZE]; - va_list ap; - int errno_save; - - errno_save = errno; - va_start(ap, format); - if (vsnprintf(buf, sizeof(buf), format, ap) < 0) - err(EXIT_FAILURE, "logmsg: vsnprintf failed"); - if (errno_save == 0) - output("%s: %s\n", proc_name, buf); - else - output("%s: %s: %s\n", proc_name, buf, strerror(errno_save)); - va_end(ap); - errno = errno_save; -} - -static void -vlogmsgx(const char *format, va_list ap) -{ - char buf[LOGMSG_SIZE]; - - if (vsnprintf(buf, sizeof(buf), format, ap) < 0) - err(EXIT_FAILURE, "logmsgx: vsnprintf failed"); - output("%s: %s\n", proc_name, buf); - -} - -static void -logmsgx(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vlogmsgx(format, ap); - va_end(ap); -} - -static void -dbgmsg(const char *format, ...) -{ - va_list ap; - - if (debug) { - va_start(ap, format); - vlogmsgx(format, ap); - va_end(ap); - } -} - -static int -run_tests(int type, u_int testno1) -{ - const struct test_func *tf; - u_int i, testno2, failed_num; - - sock_type = type; - if (type == SOCK_STREAM) { - sock_type_str = "SOCK_STREAM"; - tf = test_stream_tbl; - i = TEST_STREAM_TBL_SIZE - 1; - } else { - sock_type_str = "SOCK_DGRAM"; - tf = test_dgram_tbl; - i = TEST_DGRAM_TBL_SIZE - 1; - } - if (testno1 == 0) { - testno1 = 1; - testno2 = i; - } else - testno2 = testno1; - - output("Running tests for %s sockets:\n", sock_type_str); - failed_num = 0; - for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) { - output(" %u: %s\n", i, tf->desc); - switch (tf->func()) { - case -1: - ++failed_num; - break; - case -2: - logmsgx("some system error or timeout occurred"); - return (-1); - } - } - - if (failed_num != 0) - failed_flag = true; - - if (testno1 != testno2) { - if (failed_num == 0) - output("-- all tests passed!\n"); - else - output("-- %u test%s failed!\n", - failed_num, failed_num == 1 ? "" : "s"); - } else { - if (failed_num == 0) - output("-- test passed!\n"); - else - output("-- test failed!\n"); - } - - return (0); -} - -static int -init(void) -{ - struct sigaction sigact; - size_t idx; - int rv; - - proc_name = "SERVER"; - - sigact.sa_handler = SIG_IGN; - sigact.sa_flags = 0; - sigemptyset(&sigact.sa_mask); - if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) { - logmsg("init: sigaction"); - return (-1); - } - - if (ipc_msg.buf_size == 0) - ipc_msg.buf_send = ipc_msg.buf_recv = NULL; - else { - ipc_msg.buf_send = malloc(ipc_msg.buf_size); - ipc_msg.buf_recv = malloc(ipc_msg.buf_size); - if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) { - logmsg("init: malloc"); - return (-1); - } - for (idx = 0; idx < ipc_msg.buf_size; ++idx) - ipc_msg.buf_send[idx] = (char)idx; - } - - proc_cred.uid = getuid(); - proc_cred.euid = geteuid(); - proc_cred.gid = getgid(); - proc_cred.egid = getegid(); - proc_cred.gid_num = getgroups(0, (gid_t *)NULL); - if (proc_cred.gid_num < 0) { - logmsg("init: getgroups"); - return (-1); - } - proc_cred.gid_arr = malloc(proc_cred.gid_num * - sizeof(*proc_cred.gid_arr)); - if (proc_cred.gid_arr == NULL) { - logmsg("init: malloc"); - return (-1); - } - if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) { - logmsg("init: getgroups"); - return (-1); - } - - memset(&serv_addr_sun, 0, sizeof(serv_addr_sun)); - rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path), - "%s/%s", work_dir, proc_name); - if (rv < 0) { - logmsg("init: snprintf"); - return (-1); - } - if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) { - logmsgx("init: not enough space for socket pathname"); - return (-1); - } - serv_addr_sun.sun_family = PF_LOCAL; - serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun); - - return (0); -} - -static int -client_fork(void) -{ - int fd1, fd2; - - if (pipe(sync_fd[SYNC_SERVER]) < 0 || - pipe(sync_fd[SYNC_CLIENT]) < 0) { - logmsg("client_fork: pipe"); - return (-1); - } - client_pid = fork(); - if (client_pid == (pid_t)-1) { - logmsg("client_fork: fork"); - return (-1); - } - if (client_pid == 0) { - proc_name = "CLIENT"; - server_flag = false; - fd1 = sync_fd[SYNC_SERVER][SYNC_RECV]; - fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND]; - } else { - fd1 = sync_fd[SYNC_SERVER][SYNC_SEND]; - fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV]; - } - if (close(fd1) < 0 || close(fd2) < 0) { - logmsg("client_fork: close"); - return (-1); - } - return (client_pid != 0); -} - -static void -client_exit(int rv) -{ - if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 || - close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) { - logmsg("client_exit: close"); - rv = -1; - } - rv = rv == 0 ? EXIT_SUCCESS : -rv; - dbgmsg("exit: code %d", rv); - _exit(rv); -} - -static int -client_wait(void) -{ - int status; - pid_t pid; - - dbgmsg("waiting for client"); - - if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 || - close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) { - logmsg("client_wait: close"); - return (-1); - } - - pid = waitpid(client_pid, &status, 0); - if (pid == (pid_t)-1) { - logmsg("client_wait: waitpid"); - return (-1); - } - - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != EXIT_SUCCESS) { - logmsgx("client exit status is %d", - WEXITSTATUS(status)); - return (-WEXITSTATUS(status)); - } - } else { - if (WIFSIGNALED(status)) - logmsgx("abnormal termination of client, signal %d%s", - WTERMSIG(status), WCOREDUMP(status) ? - " (core file generated)" : ""); - else - logmsgx("termination of client, unknown status"); - return (-1); - } - - return (0); -} - -int -main(int argc, char *argv[]) -{ - const char *errstr; - u_int testno, zvalue; - int opt, rv; - bool dgram_flag, stream_flag; - - ipc_msg.buf_size = IPC_MSG_SIZE_DEF; - ipc_msg.msg_num = IPC_MSG_NUM_DEF; - dgram_flag = stream_flag = false; - while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1) - switch (opt) { - case 'd': - debug = true; - break; - case 'h': - usage(true); - return (EXIT_SUCCESS); - case 'n': - ipc_msg.msg_num = strtonum(optarg, 1, - IPC_MSG_NUM_MAX, &errstr); - if (errstr != NULL) - errx(EXIT_FAILURE, "option -n: number is %s", - errstr); - break; - case 's': - ipc_msg.buf_size = strtonum(optarg, 0, - IPC_MSG_SIZE_MAX, &errstr); - if (errstr != NULL) - errx(EXIT_FAILURE, "option -s: number is %s", - errstr); - break; - case 't': - if (strcmp(optarg, "stream") == 0) - stream_flag = true; - else if (strcmp(optarg, "dgram") == 0) - dgram_flag = true; - else - errx(EXIT_FAILURE, "option -t: " - "wrong socket type"); - break; - case 'z': - zvalue = strtonum(optarg, 0, 3, &errstr); - if (errstr != NULL) - errx(EXIT_FAILURE, "option -z: number is %s", - errstr); - if (zvalue & 0x1) - send_data_flag = false; - if (zvalue & 0x2) - send_array_flag = false; - break; - default: - usage(false); - return (EXIT_FAILURE); - } - - if (optind < argc) { - if (optind + 1 != argc) - errx(EXIT_FAILURE, "too many arguments"); - testno = strtonum(argv[optind], 0, UINT_MAX, &errstr); - if (errstr != NULL) - errx(EXIT_FAILURE, "test number is %s", errstr); - if (stream_flag && testno >= TEST_STREAM_TBL_SIZE) - errx(EXIT_FAILURE, "given test %u for stream " - "sockets does not exist", testno); - if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE) - errx(EXIT_FAILURE, "given test %u for datagram " - "sockets does not exist", testno); - } else - testno = 0; - - if (!dgram_flag && !stream_flag) { - if (testno != 0) - errx(EXIT_FAILURE, "particular test number " - "can be used with the -t option only"); - dgram_flag = stream_flag = true; - } - - if (mkdtemp(work_dir) == NULL) - err(EXIT_FAILURE, "mkdtemp(%s)", work_dir); - - rv = EXIT_FAILURE; - if (init() < 0) - goto done; - - if (stream_flag) - if (run_tests(SOCK_STREAM, testno) < 0) - goto done; - if (dgram_flag) - if (run_tests(SOCK_DGRAM, testno) < 0) - goto done; - - rv = EXIT_SUCCESS; -done: - if (rmdir(work_dir) < 0) { - logmsg("rmdir(%s)", work_dir); - rv = EXIT_FAILURE; - } - return (failed_flag ? EXIT_FAILURE : rv); -} - -static int -socket_close(int fd) -{ - int rv; - - rv = 0; - if (close(fd) < 0) { - logmsg("socket_close: close"); - rv = -1; - } - if (server_flag && fd == serv_sock_fd) - if (unlink(serv_addr_sun.sun_path) < 0) { - logmsg("socket_close: unlink(%s)", - serv_addr_sun.sun_path); - rv = -1; - } - return (rv); -} - -static int -socket_create(void) -{ - struct timeval tv; - int fd; - - fd = socket(PF_LOCAL, sock_type, 0); - if (fd < 0) { - logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str); - return (-1); - } - if (server_flag) - serv_sock_fd = fd; - - tv.tv_sec = TIMEOUT; - tv.tv_usec = 0; - if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 || - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { - logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)"); - goto failed; - } - - if (server_flag) { - if (bind(fd, (struct sockaddr *)&serv_addr_sun, - serv_addr_sun.sun_len) < 0) { - logmsg("socket_create: bind(%s)", - serv_addr_sun.sun_path); - goto failed; - } - if (sock_type == SOCK_STREAM) { - int val; - - if (listen(fd, LISTENQ) < 0) { - logmsg("socket_create: listen"); - goto failed; - } - val = fcntl(fd, F_GETFL, 0); - if (val < 0) { - logmsg("socket_create: fcntl(F_GETFL)"); - goto failed; - } - if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) { - logmsg("socket_create: fcntl(F_SETFL)"); - goto failed; - } - } - } - - return (fd); - -failed: - if (close(fd) < 0) - logmsg("socket_create: close"); - if (server_flag) - if (unlink(serv_addr_sun.sun_path) < 0) - logmsg("socket_close: unlink(%s)", - serv_addr_sun.sun_path); - return (-1); -} - -static int -socket_connect(int fd) -{ - dbgmsg("connect"); - - if (connect(fd, (struct sockaddr *)&serv_addr_sun, - serv_addr_sun.sun_len) < 0) { - logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path); - return (-1); - } - return (0); -} - -static int -sync_recv(void) -{ - ssize_t ssize; - int fd; - char buf; - - dbgmsg("sync: wait"); - - fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV]; - - ssize = read(fd, &buf, 1); - if (ssize < 0) { - logmsg("sync_recv: read"); - return (-1); - } - if (ssize < 1) { - logmsgx("sync_recv: read %zd of 1 byte", ssize); - return (-1); - } - - dbgmsg("sync: received"); - - return (0); -} - -static int -sync_send(void) -{ - ssize_t ssize; - int fd; - - dbgmsg("sync: send"); - - fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND]; - - ssize = write(fd, "", 1); - if (ssize < 0) { - logmsg("sync_send: write"); - return (-1); - } - if (ssize < 1) { - logmsgx("sync_send: sent %zd of 1 byte", ssize); - return (-1); - } - - return (0); -} - -static int -message_send(int fd, const struct msghdr *msghdr) -{ - const struct cmsghdr *cmsghdr; - size_t size; - ssize_t ssize; - - size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0; - dbgmsg("send: data size %zu", size); - dbgmsg("send: msghdr.msg_controllen %u", - (u_int)msghdr->msg_controllen); - cmsghdr = CMSG_FIRSTHDR(msghdr); - if (cmsghdr != NULL) - dbgmsg("send: cmsghdr.cmsg_len %u", - (u_int)cmsghdr->cmsg_len); - - ssize = sendmsg(fd, msghdr, 0); - if (ssize < 0) { - logmsg("message_send: sendmsg"); - return (-1); - } - if ((size_t)ssize != size) { - logmsgx("message_send: sendmsg: sent %zd of %zu bytes", - ssize, size); - return (-1); - } - - if (!send_data_flag) - if (sync_send() < 0) - return (-1); - - return (0); -} - -static int -message_sendn(int fd, struct msghdr *msghdr) -{ - u_int i; - - for (i = 1; i <= ipc_msg.msg_num; ++i) { - dbgmsg("message #%u", i); - if (message_send(fd, msghdr) < 0) - return (-1); - } - return (0); -} - -static int -message_recv(int fd, struct msghdr *msghdr) -{ - const struct cmsghdr *cmsghdr; - size_t size; - ssize_t ssize; - - if (!send_data_flag) - if (sync_recv() < 0) - return (-1); - - size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0; - ssize = recvmsg(fd, msghdr, MSG_WAITALL); - if (ssize < 0) { - logmsg("message_recv: recvmsg"); - return (-1); - } - if ((size_t)ssize != size) { - logmsgx("message_recv: recvmsg: received %zd of %zu bytes", - ssize, size); - return (-1); - } - - dbgmsg("recv: data size %zd", ssize); - dbgmsg("recv: msghdr.msg_controllen %u", - (u_int)msghdr->msg_controllen); - cmsghdr = CMSG_FIRSTHDR(msghdr); - if (cmsghdr != NULL) - dbgmsg("recv: cmsghdr.cmsg_len %u", - (u_int)cmsghdr->cmsg_len); - - if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) { - logmsgx("message_recv: received message has wrong content"); - return (-1); - } - - return (0); -} - -static int -socket_accept(int listenfd) -{ - fd_set rset; - struct timeval tv; - int fd, rv, val; - - dbgmsg("accept"); - - FD_ZERO(&rset); - FD_SET(listenfd, &rset); - tv.tv_sec = TIMEOUT; - tv.tv_usec = 0; - rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv); - if (rv < 0) { - logmsg("socket_accept: select"); - return (-1); - } - if (rv == 0) { - logmsgx("socket_accept: select timeout"); - return (-1); - } - - fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); - if (fd < 0) { - logmsg("socket_accept: accept"); - return (-1); - } - - val = fcntl(fd, F_GETFL, 0); - if (val < 0) { - logmsg("socket_accept: fcntl(F_GETFL)"); - goto failed; - } - if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) { - logmsg("socket_accept: fcntl(F_SETFL)"); - goto failed; - } - - return (fd); - -failed: - if (close(fd) < 0) - logmsg("socket_accept: close"); - return (-1); -} - -static int -check_msghdr(const struct msghdr *msghdr, size_t size) -{ - if (msghdr->msg_flags & MSG_TRUNC) { - logmsgx("msghdr.msg_flags has MSG_TRUNC"); - return (-1); - } - if (msghdr->msg_flags & MSG_CTRUNC) { - logmsgx("msghdr.msg_flags has MSG_CTRUNC"); - return (-1); - } - if (msghdr->msg_controllen < size) { - logmsgx("msghdr.msg_controllen %u < %zu", - (u_int)msghdr->msg_controllen, size); - return (-1); - } - if (msghdr->msg_controllen > 0 && size == 0) { - logmsgx("msghdr.msg_controllen %u > 0", - (u_int)msghdr->msg_controllen); - return (-1); - } - return (0); -} - -static int -check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size) -{ - if (cmsghdr == NULL) { - logmsgx("cmsghdr is NULL"); - return (-1); - } - if (cmsghdr->cmsg_level != SOL_SOCKET) { - logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET", - cmsghdr->cmsg_level); - return (-1); - } - if (cmsghdr->cmsg_type != type) { - logmsgx("cmsghdr.cmsg_type %d != %d", - cmsghdr->cmsg_type, type); - return (-1); - } - if (cmsghdr->cmsg_len != CMSG_LEN(size)) { - logmsgx("cmsghdr.cmsg_len %u != %zu", - (u_int)cmsghdr->cmsg_len, CMSG_LEN(size)); - return (-1); - } - return (0); -} - -static int -check_groups(const char *gid_arr_str, const gid_t *gid_arr, - const char *gid_num_str, int gid_num, bool all_gids) -{ - int i; - - for (i = 0; i < gid_num; ++i) - dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]); - - if (all_gids) { - if (gid_num != proc_cred.gid_num) { - logmsgx("%s %d != %d", gid_num_str, gid_num, - proc_cred.gid_num); - return (-1); - } - } else { - if (gid_num > proc_cred.gid_num) { - logmsgx("%s %d > %d", gid_num_str, gid_num, - proc_cred.gid_num); - return (-1); - } - } - if (memcmp(gid_arr, proc_cred.gid_arr, - gid_num * sizeof(*gid_arr)) != 0) { - logmsgx("%s content is wrong", gid_arr_str); - for (i = 0; i < gid_num; ++i) - if (gid_arr[i] != proc_cred.gid_arr[i]) { - logmsgx("%s[%d] %lu != %lu", - gid_arr_str, i, (u_long)gid_arr[i], - (u_long)proc_cred.gid_arr[i]); - break; - } - return (-1); - } - return (0); -} - -static int -check_xucred(const struct xucred *xucred, socklen_t len) -{ - if (len != sizeof(*xucred)) { - logmsgx("option value size %zu != %zu", - (size_t)len, sizeof(*xucred)); - return (-1); - } - - dbgmsg("xucred.cr_version %u", xucred->cr_version); - dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid); - dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups); - - if (xucred->cr_version != XUCRED_VERSION) { - logmsgx("xucred.cr_version %u != %d", - xucred->cr_version, XUCRED_VERSION); - return (-1); - } - if (xucred->cr_uid != proc_cred.euid) { - logmsgx("xucred.cr_uid %lu != %lu (EUID)", - (u_long)xucred->cr_uid, (u_long)proc_cred.euid); - return (-1); - } - if (xucred->cr_ngroups == 0) { - logmsgx("xucred.cr_ngroups == 0"); - return (-1); - } - if (xucred->cr_ngroups < 0) { - logmsgx("xucred.cr_ngroups < 0"); - return (-1); - } - if (xucred->cr_ngroups > XU_NGROUPS) { - logmsgx("xucred.cr_ngroups %hu > %u (max)", - xucred->cr_ngroups, XU_NGROUPS); - return (-1); - } - if (xucred->cr_groups[0] != proc_cred.egid) { - logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)", - (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid); - return (-1); - } - if (check_groups("xucred.cr_groups", xucred->cr_groups, - "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0) - return (-1); - return (0); -} - -static int -check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) -{ - const struct cmsgcred *cmsgcred; - - if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0) - return (-1); - - cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); - - dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid); - dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid); - dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid); - dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid); - dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups); - - if (cmsgcred->cmcred_pid != client_pid) { - logmsgx("cmsgcred.cmcred_pid %ld != %ld", - (long)cmsgcred->cmcred_pid, (long)client_pid); - return (-1); - } - if (cmsgcred->cmcred_uid != proc_cred.uid) { - logmsgx("cmsgcred.cmcred_uid %lu != %lu", - (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid); - return (-1); - } - if (cmsgcred->cmcred_euid != proc_cred.euid) { - logmsgx("cmsgcred.cmcred_euid %lu != %lu", - (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid); - return (-1); - } - if (cmsgcred->cmcred_gid != proc_cred.gid) { - logmsgx("cmsgcred.cmcred_gid %lu != %lu", - (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid); - return (-1); - } - if (cmsgcred->cmcred_ngroups == 0) { - logmsgx("cmsgcred.cmcred_ngroups == 0"); - return (-1); - } - if (cmsgcred->cmcred_ngroups < 0) { - logmsgx("cmsgcred.cmcred_ngroups %d < 0", - cmsgcred->cmcred_ngroups); - return (-1); - } - if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) { - logmsgx("cmsgcred.cmcred_ngroups %d > %d", - cmsgcred->cmcred_ngroups, CMGROUP_MAX); - return (-1); - } - if (cmsgcred->cmcred_groups[0] != proc_cred.egid) { - logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", - (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid); - return (-1); - } - if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups, - "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0) - return (-1); - return (0); -} - -static int -check_scm_creds_sockcred(struct cmsghdr *cmsghdr) -{ - const struct sockcred *sockcred; - - if (check_cmsghdr(cmsghdr, SCM_CREDS, - SOCKCREDSIZE(proc_cred.gid_num)) < 0) - return (-1); - - sockcred = (struct sockcred *)CMSG_DATA(cmsghdr); - - dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid); - dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid); - dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid); - dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid); - dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups); - - if (sockcred->sc_uid != proc_cred.uid) { - logmsgx("sockcred.sc_uid %lu != %lu", - (u_long)sockcred->sc_uid, (u_long)proc_cred.uid); - return (-1); - } - if (sockcred->sc_euid != proc_cred.euid) { - logmsgx("sockcred.sc_euid %lu != %lu", - (u_long)sockcred->sc_euid, (u_long)proc_cred.euid); - return (-1); - } - if (sockcred->sc_gid != proc_cred.gid) { - logmsgx("sockcred.sc_gid %lu != %lu", - (u_long)sockcred->sc_gid, (u_long)proc_cred.gid); - return (-1); - } - if (sockcred->sc_egid != proc_cred.egid) { - logmsgx("sockcred.sc_egid %lu != %lu", - (u_long)sockcred->sc_egid, (u_long)proc_cred.egid); - return (-1); - } - if (sockcred->sc_ngroups == 0) { - logmsgx("sockcred.sc_ngroups == 0"); - return (-1); - } - if (sockcred->sc_ngroups < 0) { - logmsgx("sockcred.sc_ngroups %d < 0", - sockcred->sc_ngroups); - return (-1); - } - if (sockcred->sc_ngroups != proc_cred.gid_num) { - logmsgx("sockcred.sc_ngroups %d != %u", - sockcred->sc_ngroups, proc_cred.gid_num); - return (-1); - } - if (check_groups("sockcred.sc_groups", sockcred->sc_groups, - "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0) - return (-1); - return (0); -} - -static int -check_scm_timestamp(struct cmsghdr *cmsghdr) -{ - const struct timeval *timeval; - - if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0) - return (-1); - - timeval = (struct timeval *)CMSG_DATA(cmsghdr); - - dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX, - (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec); - - return (0); -} - -static int -check_scm_bintime(struct cmsghdr *cmsghdr) -{ - const struct bintime *bintime; - - if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0) - return (-1); - - bintime = (struct bintime *)CMSG_DATA(cmsghdr); - - dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64, - (intmax_t)bintime->sec, bintime->frac); - - return (0); -} - -static void -msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data) -{ - msghdr->msg_name = NULL; - msghdr->msg_namelen = 0; - if (send_data_flag) { - iov->iov_base = server_flag ? - ipc_msg.buf_recv : ipc_msg.buf_send; - iov->iov_len = ipc_msg.buf_size; - msghdr->msg_iov = iov; - msghdr->msg_iovlen = 1; - } else { - msghdr->msg_iov = NULL; - msghdr->msg_iovlen = 0; - } - msghdr->msg_control = cmsg_data; - msghdr->msg_flags = 0; -} - -static void -msghdr_init_server(struct msghdr *msghdr, struct iovec *iov, - void *cmsg_data, size_t cmsg_size) -{ - msghdr_init_generic(msghdr, iov, cmsg_data); - msghdr->msg_controllen = cmsg_size; - dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ? - msghdr->msg_iov->iov_len : (size_t)0); - dbgmsg("init: msghdr.msg_controllen %u", - (u_int)msghdr->msg_controllen); -} - -static void -msghdr_init_client(struct msghdr *msghdr, struct iovec *iov, - void *cmsg_data, size_t cmsg_size, int type, size_t arr_size) -{ - struct cmsghdr *cmsghdr; - - msghdr_init_generic(msghdr, iov, cmsg_data); - if (cmsg_data != NULL) { - msghdr->msg_controllen = send_array_flag ? - cmsg_size : CMSG_SPACE(0); - cmsghdr = CMSG_FIRSTHDR(msghdr); - cmsghdr->cmsg_level = SOL_SOCKET; - cmsghdr->cmsg_type = type; - cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0); - } else - msghdr->msg_controllen = 0; -} - -static int -t_generic(int (*client_func)(int), int (*server_func)(int)) -{ - int fd, rv, rv_client; - - switch (client_fork()) { - case 0: - fd = socket_create(); - if (fd < 0) - rv = -2; - else { - rv = client_func(fd); - if (socket_close(fd) < 0) - rv = -2; - } - client_exit(rv); - break; - case 1: - fd = socket_create(); - if (fd < 0) - rv = -2; - else { - rv = server_func(fd); - rv_client = client_wait(); - if (rv == 0 || (rv == -2 && rv_client != 0)) - rv = rv_client; - if (socket_close(fd) < 0) - rv = -2; - } - break; - default: - rv = -2; - } - return (rv); -} - -static int -t_cmsgcred_client(int fd) -{ - struct msghdr msghdr; - struct iovec iov[1]; - void *cmsg_data; - size_t cmsg_size; - int rv; - - if (sync_recv() < 0) - return (-2); - - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, - SCM_CREDS, sizeof(struct cmsgcred)); - - if (socket_connect(fd) < 0) - goto done; - - if (message_sendn(fd, &msghdr) < 0) - goto done; - - rv = 0; -done: - free(cmsg_data); - return (rv); -} - -static int -t_cmsgcred_server(int fd1) -{ - struct msghdr msghdr; - struct iovec iov[1]; - struct cmsghdr *cmsghdr; - void *cmsg_data; - size_t cmsg_size; - u_int i; - int fd2, rv; - - if (sync_send() < 0) - return (-2); - - fd2 = -1; - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - - if (sock_type == SOCK_STREAM) { - fd2 = socket_accept(fd1); - if (fd2 < 0) - goto done; - } else - fd2 = fd1; - - rv = -1; - for (i = 1; i <= ipc_msg.msg_num; ++i) { - dbgmsg("message #%u", i); - - msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); - if (message_recv(fd2, &msghdr) < 0) { - rv = -2; - break; - } - - if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) - break; - - cmsghdr = CMSG_FIRSTHDR(&msghdr); - if (check_scm_creds_cmsgcred(cmsghdr) < 0) - break; - } - if (i > ipc_msg.msg_num) - rv = 0; -done: - free(cmsg_data); - if (sock_type == SOCK_STREAM && fd2 >= 0) - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_cmsgcred(void) -{ - return (t_generic(t_cmsgcred_client, t_cmsgcred_server)); -} - -static int -t_sockcred_client(int type, int fd) -{ - struct msghdr msghdr; - struct iovec iov[1]; - int rv; - - if (sync_recv() < 0) - return (-2); - - rv = -2; - - msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0); - - if (socket_connect(fd) < 0) - goto done; - - if (type == 2) - if (sync_recv() < 0) - goto done; - - if (message_sendn(fd, &msghdr) < 0) - goto done; - - rv = 0; -done: - return (rv); -} - -static int -t_sockcred_server(int type, int fd1) -{ - struct msghdr msghdr; - struct iovec iov[1]; - struct cmsghdr *cmsghdr; - void *cmsg_data; - size_t cmsg_size; - u_int i; - int fd2, rv, val; - - fd2 = -1; - rv = -2; - - cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - - if (type == 1) { - dbgmsg("setting LOCAL_CREDS"); - val = 1; - if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { - logmsg("setsockopt(LOCAL_CREDS)"); - goto done; - } - } - - if (sync_send() < 0) - goto done; - - if (sock_type == SOCK_STREAM) { - fd2 = socket_accept(fd1); - if (fd2 < 0) - goto done; - } else - fd2 = fd1; - - if (type == 2) { - dbgmsg("setting LOCAL_CREDS"); - val = 1; - if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { - logmsg("setsockopt(LOCAL_CREDS)"); - goto done; - } - if (sync_send() < 0) - goto done; - } - - rv = -1; - for (i = 1; i <= ipc_msg.msg_num; ++i) { - dbgmsg("message #%u", i); - - msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); - if (message_recv(fd2, &msghdr) < 0) { - rv = -2; - break; - } - - if (i > 1 && sock_type == SOCK_STREAM) { - if (check_msghdr(&msghdr, 0) < 0) - break; - } else { - if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) - break; - - cmsghdr = CMSG_FIRSTHDR(&msghdr); - if (check_scm_creds_sockcred(cmsghdr) < 0) - break; - } - } - if (i > ipc_msg.msg_num) - rv = 0; -done: - free(cmsg_data); - if (sock_type == SOCK_STREAM && fd2 >= 0) - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_sockcred_1(void) -{ - u_int i; - int fd, rv, rv_client; - - switch (client_fork()) { - case 0: - for (i = 1; i <= 2; ++i) { - dbgmsg("client #%u", i); - fd = socket_create(); - if (fd < 0) - rv = -2; - else { - rv = t_sockcred_client(1, fd); - if (socket_close(fd) < 0) - rv = -2; - } - if (rv != 0) - break; - } - client_exit(rv); - break; - case 1: - fd = socket_create(); - if (fd < 0) - rv = -2; - else { - rv = t_sockcred_server(1, fd); - if (rv == 0) - rv = t_sockcred_server(3, fd); - rv_client = client_wait(); - if (rv == 0 || (rv == -2 && rv_client != 0)) - rv = rv_client; - if (socket_close(fd) < 0) - rv = -2; - } - break; - default: - rv = -2; - } - - return (rv); -} - -static int -t_sockcred_2_client(int fd) -{ - return (t_sockcred_client(2, fd)); -} - -static int -t_sockcred_2_server(int fd) -{ - return (t_sockcred_server(2, fd)); -} - -static int -t_sockcred_2(void) -{ - return (t_generic(t_sockcred_2_client, t_sockcred_2_server)); -} - -static int -t_cmsgcred_sockcred_server(int fd1) -{ - struct msghdr msghdr; - struct iovec iov[1]; - struct cmsghdr *cmsghdr; - void *cmsg_data, *cmsg1_data, *cmsg2_data; - size_t cmsg_size, cmsg1_size, cmsg2_size; - u_int i; - int fd2, rv, val; - - fd2 = -1; - rv = -2; - - cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); - cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred)); - cmsg1_data = malloc(cmsg1_size); - cmsg2_data = malloc(cmsg2_size); - if (cmsg1_data == NULL || cmsg2_data == NULL) { - logmsg("malloc"); - goto done; - } - - dbgmsg("setting LOCAL_CREDS"); - val = 1; - if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { - logmsg("setsockopt(LOCAL_CREDS)"); - goto done; - } - - if (sync_send() < 0) - goto done; - - if (sock_type == SOCK_STREAM) { - fd2 = socket_accept(fd1); - if (fd2 < 0) - goto done; - } else - fd2 = fd1; - - cmsg_data = cmsg1_data; - cmsg_size = cmsg1_size; - rv = -1; - for (i = 1; i <= ipc_msg.msg_num; ++i) { - dbgmsg("message #%u", i); - - msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); - if (message_recv(fd2, &msghdr) < 0) { - rv = -2; - break; - } - - if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) - break; - - cmsghdr = CMSG_FIRSTHDR(&msghdr); - if (i == 1 || sock_type == SOCK_DGRAM) { - if (check_scm_creds_sockcred(cmsghdr) < 0) - break; - } else { - if (check_scm_creds_cmsgcred(cmsghdr) < 0) - break; - } - - cmsg_data = cmsg2_data; - cmsg_size = cmsg2_size; - } - if (i > ipc_msg.msg_num) - rv = 0; -done: - free(cmsg1_data); - free(cmsg2_data); - if (sock_type == SOCK_STREAM && fd2 >= 0) - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_cmsgcred_sockcred(void) -{ - return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server)); -} - -static int -t_timeval_client(int fd) -{ - struct msghdr msghdr; - struct iovec iov[1]; - void *cmsg_data; - size_t cmsg_size; - int rv; - - if (sync_recv() < 0) - return (-2); - - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct timeval)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, - SCM_TIMESTAMP, sizeof(struct timeval)); - - if (socket_connect(fd) < 0) - goto done; - - if (message_sendn(fd, &msghdr) < 0) - goto done; - - rv = 0; -done: - free(cmsg_data); - return (rv); -} - -static int -t_timeval_server(int fd1) -{ - struct msghdr msghdr; - struct iovec iov[1]; - struct cmsghdr *cmsghdr; - void *cmsg_data; - size_t cmsg_size; - u_int i; - int fd2, rv; - - if (sync_send() < 0) - return (-2); - - fd2 = -1; - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct timeval)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - - if (sock_type == SOCK_STREAM) { - fd2 = socket_accept(fd1); - if (fd2 < 0) - goto done; - } else - fd2 = fd1; - - rv = -1; - for (i = 1; i <= ipc_msg.msg_num; ++i) { - dbgmsg("message #%u", i); - - msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); - if (message_recv(fd2, &msghdr) < 0) { - rv = -2; - break; - } - - if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) - break; - - cmsghdr = CMSG_FIRSTHDR(&msghdr); - if (check_scm_timestamp(cmsghdr) < 0) - break; - } - if (i > ipc_msg.msg_num) - rv = 0; -done: - free(cmsg_data); - if (sock_type == SOCK_STREAM && fd2 >= 0) - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_timeval(void) -{ - return (t_generic(t_timeval_client, t_timeval_server)); -} - -static int -t_bintime_client(int fd) -{ - struct msghdr msghdr; - struct iovec iov[1]; - void *cmsg_data; - size_t cmsg_size; - int rv; - - if (sync_recv() < 0) - return (-2); - - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct bintime)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, - SCM_BINTIME, sizeof(struct bintime)); - - if (socket_connect(fd) < 0) - goto done; - - if (message_sendn(fd, &msghdr) < 0) - goto done; - - rv = 0; -done: - free(cmsg_data); - return (rv); -} - -static int -t_bintime_server(int fd1) -{ - struct msghdr msghdr; - struct iovec iov[1]; - struct cmsghdr *cmsghdr; - void *cmsg_data; - size_t cmsg_size; - u_int i; - int fd2, rv; - - if (sync_send() < 0) - return (-2); - - fd2 = -1; - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct bintime)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - - if (sock_type == SOCK_STREAM) { - fd2 = socket_accept(fd1); - if (fd2 < 0) - goto done; - } else - fd2 = fd1; - - rv = -1; - for (i = 1; i <= ipc_msg.msg_num; ++i) { - dbgmsg("message #%u", i); - - msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); - if (message_recv(fd2, &msghdr) < 0) { - rv = -2; - break; - } - - if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) - break; - - cmsghdr = CMSG_FIRSTHDR(&msghdr); - if (check_scm_bintime(cmsghdr) < 0) - break; - } - if (i > ipc_msg.msg_num) - rv = 0; -done: - free(cmsg_data); - if (sock_type == SOCK_STREAM && fd2 >= 0) - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_bintime(void) -{ - return (t_generic(t_bintime_client, t_bintime_server)); -} - -static int -t_cmsg_len_client(int fd) -{ - struct msghdr msghdr; - struct iovec iov[1]; - struct cmsghdr *cmsghdr; - void *cmsg_data; - size_t size, cmsg_size; - socklen_t socklen; - int rv; - - if (sync_recv() < 0) - return (-2); - - rv = -2; - - cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); - cmsg_data = malloc(cmsg_size); - if (cmsg_data == NULL) { - logmsg("malloc"); - goto done; - } - msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, - SCM_CREDS, sizeof(struct cmsgcred)); - cmsghdr = CMSG_FIRSTHDR(&msghdr); - - if (socket_connect(fd) < 0) - goto done; - - size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0; - rv = -1; - for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) { - cmsghdr->cmsg_len = socklen; - dbgmsg("send: data size %zu", size); - dbgmsg("send: msghdr.msg_controllen %u", - (u_int)msghdr.msg_controllen); - dbgmsg("send: cmsghdr.cmsg_len %u", - (u_int)cmsghdr->cmsg_len); - if (sendmsg(fd, &msghdr, 0) < 0) - continue; - logmsgx("sent message with cmsghdr.cmsg_len %u < %u", - (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0)); - break; - } - if (socklen == CMSG_LEN(0)) - rv = 0; - - if (sync_send() < 0) { - rv = -2; - goto done; - } -done: - free(cmsg_data); - return (rv); -} - -static int -t_cmsg_len_server(int fd1) -{ - int fd2, rv; - - if (sync_send() < 0) - return (-2); - - rv = -2; - - if (sock_type == SOCK_STREAM) { - fd2 = socket_accept(fd1); - if (fd2 < 0) - goto done; - } else - fd2 = fd1; - - if (sync_recv() < 0) - goto done; - - rv = 0; -done: - if (sock_type == SOCK_STREAM && fd2 >= 0) - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_cmsg_len(void) -{ - return (t_generic(t_cmsg_len_client, t_cmsg_len_server)); -} - -static int -t_peercred_client(int fd) -{ - struct xucred xucred; - socklen_t len; - - if (sync_recv() < 0) - return (-1); - - if (socket_connect(fd) < 0) - return (-1); - - len = sizeof(xucred); - if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { - logmsg("getsockopt(LOCAL_PEERCRED)"); - return (-1); - } - - if (check_xucred(&xucred, len) < 0) - return (-1); - - return (0); -} - -static int -t_peercred_server(int fd1) -{ - struct xucred xucred; - socklen_t len; - int fd2, rv; - - if (sync_send() < 0) - return (-2); - - fd2 = socket_accept(fd1); - if (fd2 < 0) - return (-2); - - len = sizeof(xucred); - if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { - logmsg("getsockopt(LOCAL_PEERCRED)"); - rv = -2; - goto done; - } - - if (check_xucred(&xucred, len) < 0) { - rv = -1; - goto done; - } - - rv = 0; -done: - if (socket_close(fd2) < 0) - rv = -2; - return (rv); -} - -static int -t_peercred(void) -{ - return (t_generic(t_peercred_client, t_peercred_server)); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_cmsg.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/rtsocket_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/rtsocket_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/rtsocket_test.c (nonexistent) @@ -1,101 +0,0 @@ -/*- - * Copyright (c) 2006 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$ - */ - -/* - * Simple routing socket regression test: create and destroy a raw routing - * socket, and make sure that dgram and stream don't work, socketpair, etc. - */ - -#include -#include - -#include - -#include -#include -#include - -int -main(void) -{ - int sock, socks[2]; - - sock = socket(PF_ROUTE, SOCK_STREAM, 0); - if (sock >= 0) { - close(sock); - errx(-1, "socket(PF_ROUTE, SOCK_STREAM, 0) returned %d", - sock); - } - - if (errno != EPROTONOSUPPORT) - err(-1, "socket(PF_ROUTE, SOCK_STREAM, 0)"); - - sock = socket(PF_ROUTE, SOCK_DGRAM, 0); - if (sock >= 0) { - close(sock); - errx(-1, "socket(PF_ROUTE, SOCK_DGRAM, 0) returned %d", - sock); - } - - if (errno != EPROTONOSUPPORT) - err(-1, "socket(PF_ROUTE, SOCK_DGRAM, 0)"); - - sock = socket(PF_ROUTE, SOCK_RAW, 0); - if (sock < 0) - err(-1, "socket(PF_ROUTE, SOCK_RAW, 0)"); - close(sock); - - if (socketpair(PF_ROUTE, SOCK_STREAM, 0, socks) == 0) { - close(socks[0]); - close(socks[1]); - errx(-1, - "socketpair(PF_ROUTE, SOCK_STREAM, 0, socks) success"); - } - - if (errno != EPROTONOSUPPORT) - err(-1, "socketpair(PF_ROUTE, SOCK_STREAM, 0, socks)"); - - if (socketpair(PF_ROUTE, SOCK_DGRAM, 0, socks) == 0) { - close(socks[0]); - close(socks[1]); - errx(-1, - "socketpair(PF_ROUTE, SOCK_DGRAM, 0, socks) success"); - } - - if (errno != EPROTONOSUPPORT) - err(-1, "socketpair(PF_ROUTE, SOCK_DGRAM, 0, socks)"); - - if (socketpair(PF_ROUTE, SOCK_RAW, 0, socks) == 0) { - close(socks[0]); - close(socks[1]); - errx(-1, - "socketpair(PF_ROUTE, SOCK_STREAM, 0, socks) success"); - } - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/rtsocket_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_gc_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_gc_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_gc_test.c (nonexistent) @@ -1,808 +0,0 @@ -/*- - * 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[]) -{ - char cmd[sizeof(RMDIR) + PATH_MAX]; - int serrno; - pid_t pid; - - strlcpy(dpath, "/tmp/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); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_gc_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/fstat_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/fstat_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/fstat_test.c (nonexistent) @@ -1,71 +0,0 @@ -/*- - * Copyright (c) 2008 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 - -/* - * Basic test to make sure that fstat(2) returns success on various socket - * types. In the future we should also validate the fields, confirming - * expected results such as the effect of shutdown(2) on permissions, etc. - */ - -static void -dotest(int domain, int type, int protocol) -{ - struct stat sb; - int sock; - - sock = socket(domain, type, protocol); - if (sock < 0) - err(-1, "socket(%d, %d, %d)", domain, type, protocol); - - if (fstat(sock, &sb) < 0) - err(-1, "fstat on socket(%d, %d, %d)", domain, type, - protocol); - - close(sock); -} - -int -main(void) -{ - - dotest(PF_INET, SOCK_DGRAM, 0); - dotest(PF_INET, SOCK_STREAM, 0); - dotest(PF_INET6, SOCK_DGRAM, 0); - dotest(PF_INET6, SOCK_STREAM, 0); - dotest(PF_LOCAL, SOCK_DGRAM, 0); - dotest(PF_LOCAL, SOCK_STREAM, 0); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/fstat_test.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/listenclose_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/listenclose_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/listenclose_test.c (nonexistent) @@ -1,111 +0,0 @@ -/*- - * Copyright (c) 2004-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 - -/* - * The listenclose regression test is designed to catch kernel bugs that may - * trigger as a result of performing a close on a listen() socket with as-yet - * unaccepted connections in its queues. This results in the connections - * being aborted, which is a not-often-followed code path. To do this, we - * create a local TCP socket, build a non-blocking connection to it, and then - * close the accept socket. The connection must be non-blocking or the - * program will block and as such connect() will not return as accept() is - * never called. - */ - -int -main(void) -{ - int listen_sock, connect_sock; - struct sockaddr_in sin; - socklen_t len; - u_short port; - int arg; - - listen_sock = socket(PF_INET, SOCK_STREAM, 0); - if (listen_sock == -1) - errx(-1, - "socket(PF_INET, SOCK_STREAM, 0) for listen socket: %s", - strerror(errno)); - - - 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 = 0; - - if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - errx(-1, "bind(%s, %d) for listen socket: %s", - inet_ntoa(sin.sin_addr), 0, strerror(errno)); - - len = sizeof(sin); - if (getsockname(listen_sock, (struct sockaddr *)&sin, &len) < 0) - errx(-1, "getsockname() for listen socket: %s", - strerror(errno)); - port = sin.sin_port; - - if (listen(listen_sock, -1) < 0) - errx(-1, "listen() for listen socket: %s", strerror(errno)); - - connect_sock = socket(PF_INET, SOCK_STREAM, 0); - if (connect_sock == -1) - errx(-1, "socket(PF_INET, SOCK_STREAM, 0) for connect " - "socket: %s", strerror(errno)); - - arg = O_NONBLOCK; - if (fcntl(connect_sock, F_SETFL, &arg) < 0) - errx(-1, "socket(PF_INET, SOCK_STREAM, 0) for connect socket" - ": %s", strerror(errno)); - - 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 = port; - - if (connect(connect_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - errx(-1, "connect() for connect socket: %s", strerror(errno)); - close(connect_sock); - close(listen_sock); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/listenclose_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/reconnect_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/reconnect_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/reconnect_test.c (nonexistent) @@ -1,132 +0,0 @@ -/*- - * 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() -{ - 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); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/reconnect_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/socketpair_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/socketpair_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/socketpair_test.c (nonexistent) @@ -1,161 +0,0 @@ -/*- - * Copyright (c) 2004 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 - -/* - * Open, then close a set of UNIX domain socket pairs for datagram and - * stream. - * - * Confirm that we can't open INET datagram or stream socket pairs. - * - * More tests should be added, including confirming that sending on either - * endpoint results in data at the other, that the right kind of socket was - * created (stream vs. datagram), and that message boundaries fall in the - * right places. - */ -int -main(void) -{ - int fd1, fd2, fd3; - int sv[2]; - - /* - * UNIX domain socket pair, datagram. - */ - if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) != 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM): %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (close(sv[0]) != 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM) close 0: %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (close(sv[1]) != 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM) close 1: %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - - /* - * UNIX domain socket pair, stream. - */ - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) != 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_STREAM): %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (close(sv[0]) != 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_STREAM) close 0: %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (close(sv[1]) != 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_STREAM) close 1: " - "%s\n", strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - - /* - * Confirm that PF_INET datagram socket pair creation fails. - */ - if (socketpair(PF_INET, SOCK_DGRAM, 0, sv) == 0) { - fprintf(stderr, "socketpair(PF_INET, SOCK_DGRAM): opened\n"); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (errno != EOPNOTSUPP) { - fprintf(stderr, "socketpair(PF_INET, SOCK_DGRAM): %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - } - - /* - * Confirm that PF_INET stream socket pair creation fails. - */ - if (socketpair(PF_INET, SOCK_STREAM, 0, sv) == 0) { - fprintf(stderr, "socketpair(PF_INET, SOCK_STREAM): opened\n"); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (errno != EOPNOTSUPP) { - fprintf(stderr, "socketpair(PF_INET, SOCK_STREAM): %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - } - - /* - * Check for sequential fd allocation, and give up early if not. - */ - fd1 = dup(STDIN_FILENO); - fd2 = dup(STDIN_FILENO); - if (fd2 != fd1 + 1) { - fprintf(stderr, "Non-sequential fd allocation\n"); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - - /* Allocate a socketpair using a bad destination address. */ - if (socketpair(PF_UNIX, SOCK_DGRAM, 0, NULL) == 0) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM, NULL): opened\n"); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - if (errno != EFAULT) { - fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM, NULL): %s\n", - strerror(errno)); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - - /* Allocate a file descriptor and make sure it's fd2+1. */ - fd3 = dup(STDIN_FILENO); - if (fd3 != fd2 + 1) { - fprintf(stderr, "socketpair(..., NULL) allocated descriptors\n"); - fprintf(stderr, "FAIL\n"); - exit(-1); - } - - fprintf(stderr, "PASS\n"); - exit(0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/socketpair_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/unix_passfd_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_passfd_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/unix_passfd_test.c (nonexistent) @@ -1,389 +0,0 @@ -/*- - * 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 - -/* - * 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(const char *test, int *fdp) -{ - - if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) < 0) - err(-1, "%s: socketpair(PF_UNIX, SOCK_STREAM)", test); -} - -static void -closesocketpair(int *fdp) -{ - - close(fdp[0]); - close(fdp[1]); -} - -static void -devnull(const char *test, int *fdp) -{ - int fd; - - fd = open("/dev/null", O_RDONLY); - if (fd < 0) - err(-1, "%s: open(/dev/null)", test); - *fdp = fd; -} - -static void -tempfile(const char *test, int *fdp) -{ - char path[PATH_MAX]; - int fd; - - snprintf(path, PATH_MAX, "/tmp/unix_passfd.XXXXXXXXXXXXXXX"); - fd = mkstemp(path); - if (fd < 0) - err(-1, "%s: mkstemp(%s)", test, path); - (void)unlink(path); - *fdp = fd; -} - -static void -dofstat(const char *test, int fd, struct stat *sb) -{ - - if (fstat(fd, sb) < 0) - err(-1, "%s: fstat", test); -} - -static void -samefile(const char *test, struct stat *sb1, struct stat *sb2) -{ - - if (sb1->st_dev != sb2->st_dev) - errx(-1, "%s: samefile: different device", test); - if (sb1->st_ino != sb2->st_ino) - errx(-1, "%s: samefile: different inode", test); -} - -static void -sendfd_payload(const char *test, 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); - if (len < 0) - err(-1, "%s: sendmsg", test); - if ((size_t)len != paylen) - errx(-1, "%s: sendmsg: %zd bytes sent", test, len); -} - -static void -sendfd(const char *test, int sockfd, int sendfd) -{ - char ch; - - return (sendfd_payload(test, sockfd, sendfd, &ch, sizeof(ch))); -} - -static void -recvfd_payload(const char *test, 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); - if (len < 0) - err(-1, "%s: recvmsg", test); - if ((size_t)len != buflen) - errx(-1, "%s: recvmsg: %zd bytes received", test, len); - - cmsghdr = CMSG_FIRSTHDR(&msghdr); - if (cmsghdr == NULL) - errx(-1, "%s: recvmsg: did not receive control message", test); - *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); - if (*recvfd == -1) - errx(-1, "%s: recvmsg: received fd -1", test); - } - } - if (*recvfd == -1) - errx(-1, "%s: recvmsg: did not receive single-fd message", - test); -} - -static void -recvfd(const char *test, int sockfd, int *recvfd) -{ - char ch; - - return (recvfd_payload(test, sockfd, recvfd, &ch, sizeof(ch))); -} - -int -main(void) -{ - struct stat putfd_1_stat, putfd_2_stat, getfd_1_stat, getfd_2_stat; - int fd[2], putfd_1, putfd_2, getfd_1, getfd_2; - const char *test; - - /* - * 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. - */ - test = "test1-simplesendfd"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - tempfile(test, &putfd_1); - dofstat(test, putfd_1, &putfd_1_stat); - sendfd(test, fd[0], putfd_1); - recvfd(test, fd[1], &getfd_1); - dofstat(test, getfd_1, &getfd_1_stat); - samefile(test, &putfd_1_stat, &getfd_1_stat); - close(putfd_1); - close(getfd_1); - closesocketpair(fd); - - printf("%s passed\n", test); - - /* - * 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. - */ - test = "test2-sendandclose"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - tempfile(test, &putfd_1); - dofstat(test, putfd_1, &putfd_1_stat); - sendfd(test, fd[0], putfd_1); - close(putfd_1); - recvfd(test, fd[1], &getfd_1); - dofstat(test, getfd_1, &getfd_1_stat); - samefile(test, &putfd_1_stat, &getfd_1_stat); - close(getfd_1); - closesocketpair(fd); - - printf("%s passed\n", test); - - /* - * Third test: put a temporary file into a UNIX domain socket, then - * close both endpoints causing garbage collection to kick off. - */ - test = "test3-sendandcancel"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - tempfile(test, &putfd_1); - sendfd(test, fd[0], putfd_1); - close(putfd_1); - closesocketpair(fd); - - printf("%s passed\n", test); - - /* - * Send two files. Then receive them. Make sure they are returned - * in the right order, and both get there. - */ - - test = "test4-twofile"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - tempfile(test, &putfd_1); - tempfile(test, &putfd_2); - dofstat(test, putfd_1, &putfd_1_stat); - dofstat(test, putfd_2, &putfd_2_stat); - sendfd(test, fd[0], putfd_1); - sendfd(test, fd[0], putfd_2); - close(putfd_1); - close(putfd_2); - recvfd(test, fd[1], &getfd_1); - recvfd(test, fd[1], &getfd_2); - dofstat(test, getfd_1, &getfd_1_stat); - dofstat(test, getfd_2, &getfd_2_stat); - samefile(test, &putfd_1_stat, &getfd_1_stat); - samefile(test, &putfd_2_stat, &getfd_2_stat); - close(getfd_1); - close(getfd_2); - closesocketpair(fd); - - printf("%s passed\n", test); - - /* - * Big bundling test. Send an endpoint of the UNIX domain socket - * over itself, closing the door behind it. - */ - - test = "test5-bundle"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - - sendfd(test, fd[0], fd[0]); - close(fd[0]); - recvfd(test, fd[1], &getfd_1); - close(getfd_1); - close(fd[1]); - - printf("%s passed\n", test); - - /* - * 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. - */ - - test = "test6-bundlecancel"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - sendfd(test, fd[0], fd[0]); - sendfd(test, fd[1], fd[0]); - closesocketpair(fd); - - printf("%s passed\n", test); - - /* - * Test for PR 151758: Send an character device over the UNIX - * domain socket and then close both sockets to orphan the - * device. - */ - - test = "test7-devfsorphan"; - printf("beginning %s\n", test); - - domainsocketpair(test, fd); - devnull(test, &putfd_1); - sendfd(test, fd[0], putfd_1); - close(putfd_1); - closesocketpair(fd); - - printf("%s passed\n", test); - - /* - * 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. - */ - test = "test8-rights+creds+payload"; - printf("beginning %s\n", test); - - { - const int on = 1; - u_long sendspace; - size_t len; - void *buf; - - len = sizeof(sendspace); - if (sysctlbyname("net.local.stream.sendspace", &sendspace, - &len, NULL, 0) < 0) - err(-1, "%s: sysctlbyname(net.local.stream.sendspace)", - test); - - if ((buf = malloc(sendspace)) == NULL) - err(-1, "%s: malloc", test); - - domainsocketpair(test, fd); - if (setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)) < 0) - err(-1, "%s: setsockopt(LOCAL_CREDS)", test); - tempfile(test, &putfd_1); - sendfd_payload(test, fd[0], putfd_1, buf, sendspace); - recvfd_payload(test, fd[1], &getfd_1, buf, sendspace); - close(putfd_1); - close(getfd_1); - closesocketpair(fd); - } - - printf("%s passed\n", test); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/unix_passfd_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/sendfile_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/sendfile_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/sendfile_test.c (nonexistent) @@ -1,486 +0,0 @@ -/*- - * Copyright (c) 2006 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 -#include - -/* - * Simple regression test for sendfile. Creates a file sized at four pages - * and then proceeds to send it over a series of sockets, exercising a number - * of cases and performing limited validation. - */ - -#define FAIL(msg) {printf("# %s\n", msg); \ - return (-1);} - -#define FAIL_ERR(msg) {printf("# %s: %s\n", msg, strerror(errno)); \ - return (-1);} - -#define TEST_PORT 5678 -#define TEST_MAGIC 0x4440f7bb -#define TEST_PAGES 4 -#define TEST_SECONDS 30 - -struct test_header { - uint32_t th_magic; - uint32_t th_header_length; - uint32_t th_offset; - uint32_t th_length; - char th_md5[33]; -}; - -struct sendfile_test { - uint32_t hdr_length; - uint32_t offset; - uint32_t length; - uint32_t file_size; -}; - -static int file_fd; -static char path[PATH_MAX]; -static int listen_socket; -static int accept_socket; - -static int test_th(struct test_header *th, uint32_t *header_length, - uint32_t *offset, uint32_t *length); -static void signal_alarm(int signum); -static void setup_alarm(int seconds); -static void cancel_alarm(void); -static int receive_test(void); -static void run_child(void); -static int new_test_socket(int *connect_socket); -static void init_th(struct test_header *th, uint32_t header_length, - uint32_t offset, uint32_t length); -static int send_test(int connect_socket, struct sendfile_test); -static int write_test_file(size_t file_size); -static void run_parent(void); -static void cleanup(void); - - -static int -test_th(struct test_header *th, uint32_t *header_length, uint32_t *offset, - uint32_t *length) -{ - - if (th->th_magic != htonl(TEST_MAGIC)) - FAIL("magic number not found in header") - *header_length = ntohl(th->th_header_length); - *offset = ntohl(th->th_offset); - *length = ntohl(th->th_length); - return (0); -} - -static void -signal_alarm(int signum) -{ - (void)signum; - - printf("# test timeout\n"); - - if (accept_socket > 0) - close(accept_socket); - if (listen_socket > 0) - close(listen_socket); - - _exit(-1); -} - -static void -setup_alarm(int seconds) -{ - struct itimerval itv; - bzero(&itv, sizeof(itv)); - (void)seconds; - itv.it_value.tv_sec = seconds; - - signal(SIGALRM, signal_alarm); - setitimer(ITIMER_REAL, &itv, NULL); -} - -static void -cancel_alarm(void) -{ - struct itimerval itv; - bzero(&itv, sizeof(itv)); - setitimer(ITIMER_REAL, &itv, NULL); -} - -static int -receive_test(void) -{ - uint32_t header_length, offset, length, counter; - struct test_header th; - ssize_t len; - char buf[10240]; - MD5_CTX md5ctx; - char *rxmd5; - - len = read(accept_socket, &th, sizeof(th)); - if (len < 0 || (size_t)len < sizeof(th)) - FAIL_ERR("read") - - if (test_th(&th, &header_length, &offset, &length) != 0) - return (-1); - - MD5Init(&md5ctx); - - counter = 0; - while (1) { - len = read(accept_socket, buf, sizeof(buf)); - if (len < 0 || len == 0) - break; - counter += len; - MD5Update(&md5ctx, buf, len); - } - - rxmd5 = MD5End(&md5ctx, NULL); - - if ((counter != header_length+length) || - memcmp(th.th_md5, rxmd5, 33) != 0) - FAIL("receive length mismatch") - - free(rxmd5); - return (0); -} - -static void -run_child(void) -{ - struct sockaddr_in sin; - int rc = 0; - - listen_socket = socket(PF_INET, SOCK_STREAM, 0); - if (listen_socket < 0) { - printf("# socket: %s\n", strerror(errno)); - rc = -1; - } - - if (!rc) { - 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(TEST_PORT); - - if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - printf("# bind: %s\n", strerror(errno)); - rc = -1; - } - } - - if (!rc && listen(listen_socket, -1) < 0) { - printf("# listen: %s\n", strerror(errno)); - rc = -1; - } - - if (!rc) { - accept_socket = accept(listen_socket, NULL, NULL); - setup_alarm(TEST_SECONDS); - if (receive_test() != 0) - rc = -1; - } - - cancel_alarm(); - if (accept_socket > 0) - close(accept_socket); - if (listen_socket > 0) - close(listen_socket); - - _exit(rc); -} - -static int -new_test_socket(int *connect_socket) -{ - struct sockaddr_in sin; - int rc = 0; - - *connect_socket = socket(PF_INET, SOCK_STREAM, 0); - if (*connect_socket < 0) - FAIL_ERR("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(TEST_PORT); - - if (connect(*connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) - FAIL_ERR("connect") - - return (rc); -} - -static void -init_th(struct test_header *th, uint32_t header_length, uint32_t offset, - uint32_t length) -{ - bzero(th, sizeof(*th)); - th->th_magic = htonl(TEST_MAGIC); - th->th_header_length = htonl(header_length); - th->th_offset = htonl(offset); - th->th_length = htonl(length); - - MD5FileChunk(path, th->th_md5, offset, length); -} - -static int -send_test(int connect_socket, struct sendfile_test test) -{ - struct test_header th; - struct sf_hdtr hdtr, *hdtrp; - struct iovec headers; - char *header; - ssize_t len; - int length; - off_t off; - - len = lseek(file_fd, 0, SEEK_SET); - if (len != 0) - FAIL_ERR("lseek") - - struct stat st; - if (fstat(file_fd, &st) < 0) - FAIL_ERR("fstat") - length = st.st_size - test.offset; - if (test.length > 0 && test.length < (uint32_t)length) - length = test.length; - - init_th(&th, test.hdr_length, test.offset, length); - - len = write(connect_socket, &th, sizeof(th)); - if (len != sizeof(th)) - return (-1); - - if (test.hdr_length != 0) { - header = malloc(test.hdr_length); - if (header == NULL) - FAIL_ERR("malloc") - - hdtrp = &hdtr; - bzero(&headers, sizeof(headers)); - headers.iov_base = header; - headers.iov_len = test.hdr_length; - bzero(&hdtr, sizeof(hdtr)); - hdtr.headers = &headers; - hdtr.hdr_cnt = 1; - hdtr.trailers = NULL; - hdtr.trl_cnt = 0; - } else { - hdtrp = NULL; - header = NULL; - } - - if (sendfile(file_fd, connect_socket, test.offset, test.length, - hdtrp, &off, 0) < 0) { - if (header != NULL) - free(header); - FAIL_ERR("sendfile") - } - - if (length == 0) { - struct stat sb; - - if (fstat(file_fd, &sb) == 0) - length = sb.st_size - test.offset; - } - - if (header != NULL) - free(header); - - if (off != length) - FAIL("offset != length") - - return (0); -} - -static int -write_test_file(size_t file_size) -{ - char *page_buffer; - ssize_t len; - static size_t current_file_size = 0; - - if (file_size == current_file_size) - return (0); - else if (file_size < current_file_size) { - if (ftruncate(file_fd, file_size) != 0) - FAIL_ERR("ftruncate"); - current_file_size = file_size; - return (0); - } - - page_buffer = malloc(file_size); - if (page_buffer == NULL) - FAIL_ERR("malloc") - bzero(page_buffer, file_size); - - len = write(file_fd, page_buffer, file_size); - if (len < 0) - FAIL_ERR("write") - - len = lseek(file_fd, 0, SEEK_SET); - if (len < 0) - FAIL_ERR("lseek") - if (len != 0) - FAIL("len != 0") - - free(page_buffer); - current_file_size = file_size; - return (0); -} - -static void -run_parent(void) -{ - int connect_socket; - int status; - int test_num; - int test_count; - int pid; - size_t desired_file_size = 0; - - const int pagesize = getpagesize(); - - struct sendfile_test tests[] = { - { .hdr_length = 0, .offset = 0, .length = 1 }, - { .hdr_length = 0, .offset = 0, .length = pagesize }, - { .hdr_length = 0, .offset = 1, .length = 1 }, - { .hdr_length = 0, .offset = 1, .length = pagesize }, - { .hdr_length = 0, .offset = pagesize, .length = pagesize }, - { .hdr_length = 0, .offset = 0, .length = 2*pagesize }, - { .hdr_length = 0, .offset = 0, .length = 0 }, - { .hdr_length = 0, .offset = pagesize, .length = 0 }, - { .hdr_length = 0, .offset = 2*pagesize, .length = 0 }, - { .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 }, - { .hdr_length = 0, .offset = 0, .length = pagesize, - .file_size = 1 } - }; - - test_count = sizeof(tests) / sizeof(tests[0]); - printf("1..%d\n", test_count); - - for (test_num = 1; test_num <= test_count; test_num++) { - - desired_file_size = tests[test_num - 1].file_size; - if (desired_file_size == 0) - desired_file_size = TEST_PAGES * pagesize; - if (write_test_file(desired_file_size) != 0) { - printf("not ok %d\n", test_num); - continue; - } - - pid = fork(); - if (pid == -1) { - printf("not ok %d\n", test_num); - continue; - } - - if (pid == 0) - run_child(); - - usleep(250000); - - if (new_test_socket(&connect_socket) != 0) { - printf("not ok %d\n", test_num); - kill(pid, SIGALRM); - close(connect_socket); - continue; - } - - if (send_test(connect_socket, tests[test_num-1]) != 0) { - printf("not ok %d\n", test_num); - kill(pid, SIGALRM); - close(connect_socket); - continue; - } - - close(connect_socket); - if (waitpid(pid, &status, 0) == pid) { - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - printf("%s %d\n", "ok", test_num); - else - printf("%s %d\n", "not ok", test_num); - } - else { - printf("not ok %d\n", test_num); - } - } -} - -static void -cleanup(void) -{ - - unlink(path); -} - -int -main(int argc, char *argv[]) -{ - int pagesize; - - path[0] = '\0'; - - pagesize = getpagesize(); - - if (argc == 1) { - snprintf(path, sizeof(path), "sendfile.XXXXXXXXXXXX"); - file_fd = mkstemp(path); - if (file_fd == -1) - FAIL_ERR("mkstemp"); - } else if (argc == 2) { - (void)strlcpy(path, argv[1], sizeof(path)); - file_fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600); - if (file_fd == -1) - FAIL_ERR("open"); - } else { - FAIL("usage: sendfile [path]"); - } - - atexit(cleanup); - - run_parent(); - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/sendfile_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/README.unix_cmsg =================================================================== --- user/ngie/more-tests/tests/sys/sockets/README.unix_cmsg (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/README.unix_cmsg (nonexistent) @@ -1,160 +0,0 @@ -$FreeBSD$ - -About unix_cmsg -=============== - -This program is a collection of regression tests for ancillary data -(control information) for PF_LOCAL sockets (local domain or Unix domain -sockets). There are tests for stream and datagram sockets. - -Usually each test does following steps: creates Server, forks Client, -Client sends something to Server, Server verifies whether everything is -correct in received message(s). - -It is better to change the owner of unix_cmsg to some safe user -(eg. nobody:nogroup) and set SUID and SGID bits, else some tests that -check credentials can give correct results for wrong implementation. - -It is better to run this program by a user that belongs to more -than 16 groups. - -Available options -================= - -usage: unix_cmsg [-dh] [-n num] [-s size] [-t type] [-z value] [testno] - - Options are: - -d Output debugging information - -h Output the help message and exit - -n num Number of messages to send - -s size Specify size of data for IPC - -t type Specify socket type (stream, dgram) for tests - -z value Do not send data in a message (bit 0x1), do not send - data array associated with a cmsghdr structure (bit 0x2) - testno Run one test by its number (require the -t option) - -Description -=========== - -If Client sends something to Server, then it sends 5 messages by default. -Number of messages can be changed in the -n command line option. Number -of messages will be given as N in the following descriptions. - -If Client sends something to Server, then it sends some data (few bytes) -in each message by default. The size of this data can be changed by the -s -command line option. The "-s 0" command line option means, that Client will -send zero bytes represented by { NULL, 0 } value of struct iovec{}, referenced -by the msg_iov field from struct msghdr{}. The "-z 1" or "-z 3" command line -option means, that Client will send zero bytes represented by the NULL value -in the msg_iov field from struct msghdr{}. - -If Client sends some ancillary data object, then this ancillary data object -always has associated data array by default. The "-z 2" or "-z 3" option -means, that Client will not send associated data array if possible. - -For SOCK_STREAM sockets: ------------------------ - - 1: Sending, receiving cmsgcred - - Client connects to Server and sends N messages with SCM_CREDS ancillary - data object. Server should receive N messages, each message should - have SCM_CREDS ancillary data object followed by struct cmsgcred{}. - - 2: Receiving sockcred (listening socket) - - Server creates a listening stream socket and sets the LOCAL_CREDS - socket option for it. Client connects to Server two times, each time - it sends N messages. Server accepts two connections and receives N - messages from each connection. The first message from each connection - should have SCM_CREDS ancillary data object followed by struct sockcred{}, - next messages from the same connection should not have ancillary data. - - 3: Receiving sockcred (accepted socket) - - Client connects to Server. Server accepts connection and sets the - LOCAL_CREDS socket option for just accepted socket. Client sends N - messages to Server. Server should receive N messages, the first - message should have SCM_CREDS ancillary data object followed by - struct sockcred{}, next messages should not have ancillary data. - - 4: Sending cmsgcred, receiving sockcred - - Server creates a listening stream socket and sets the LOCAL_CREDS - socket option for it. Client connects to Server and sends N messages - with SCM_CREDS ancillary data object. Server should receive N messages, - the first message should have SCM_CREDS ancillary data object followed - by struct sockcred{}, each of next messages should have SCM_CREDS - ancillary data object followed by struct cmsgcred{}. - - 5: Sending, receiving timeval - - Client connects to Server and sends message with SCM_TIMESTAMP ancillary - data object. Server should receive one message with SCM_TIMESTAMP - ancillary data object followed by struct timeval{}. - - 6: Sending, receiving bintime - - Client connects to Server and sends message with SCM_BINTIME ancillary - data object. Server should receive one message with SCM_BINTIME - ancillary data object followed by struct bintime{}. - - 7: Checking cmsghdr.cmsg_len - - Client connects to Server and tries to send several messages with - SCM_CREDS ancillary data object that has wrong cmsg_len field in its - struct cmsghdr{}. All these attempts should fail, since cmsg_len - in all requests is less than CMSG_LEN(0). - - 8: Check LOCAL_PEERCRED socket option - - This test does not use ancillary data, but can be implemented here. - Client connects to Server. Both Client and Server verify that - credentials of the peer are correct using LOCAL_PEERCRED socket option. - -For SOCK_DGRAM sockets: ----------------------- - - 1: Sending, receiving cmsgcred - - Client connects to Server and sends N messages with SCM_CREDS ancillary - data object. Server should receive N messages, each message should - have SCM_CREDS ancillary data object followed by struct cmsgcred{}. - - 2: Receiving sockcred - - Server creates datagram socket and sets the LOCAL_CREDS socket option - for it. Client sends N messages to Server. Server should receive N - messages, each message should have SCM_CREDS ancillary data object - followed by struct sockcred{}. - - 3: Sending cmsgcred, receiving sockcred - - Server creates datagram socket and sets the LOCAL_CREDS socket option - for it. Client sends N messages with SCM_CREDS ancillary data object - to Server. Server should receive N messages, the first message should - have SCM_CREDS ancillary data object followed by struct sockcred{}, - each of next messages should have SCM_CREDS ancillary data object - followed by struct cmsgcred{}. - - 4: Sending, receiving timeval - - Client sends one message with SCM_TIMESTAMP ancillary data object - to Server. Server should receive one message with SCM_TIMESTAMP - ancillary data object followed by struct timeval{}. - - 5: Sending, receiving bintime - - Client sends one message with SCM_BINTIME ancillary data object - to Server. Server should receive one message with SCM_BINTIME - ancillary data object followed by struct bintime{}. - - 6: Checking cmsghdr.cmsg_len - - Client tries to send Server several messages with SCM_CREDS ancillary - data object that has wrong cmsg_len field in its struct cmsghdr{}. - All these attempts should fail, since cmsg_len in all requests is less - than CMSG_LEN(0). - -- Andrey Simonenko -andreysimonenko@users.sourceforge.net Property changes on: user/ngie/more-tests/tests/sys/sockets/README.unix_cmsg ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/sblock_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/sblock_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/sblock_test.c (nonexistent) @@ -1,207 +0,0 @@ -/*- - * 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$ - */ - -/* - * Sockets serialize I/O in each direction in order to avoid interlacing of - * I/O by multiple processes or threcvs recving or sending the socket. This - * is done using some form of kernel lock (varies by kernel version), called - * "sblock" in FreeBSD. However, to avoid unkillable processes waiting on - * I/O that may be entirely controlled by a remote network endpoint, that - * lock acquisition must be interruptible. - * - * To test this, set up a local domain stream socket pair and a set of three - * processes. Two processes block in recv(), the first on sbwait (wait for - * I/O), and the second on the sblock waiting for the first to finish. A - * third process is responsible for signalling the second process, then - * writing to the socket. Depending on the error returned in the second - * process, we can tell whether the sblock wait was interrupted, or if - * instead the process only woke up when the write was performed. - */ - -#include - -#include -#include -#include -#include -#include -#include - -static int interrupted; -static void -signal_handler(int signum __unused) -{ - - interrupted++; -} - -/* - * Process that will perform a blocking recv on a UNIX domain socket. This - * should return one byte of data. - */ -static void -blocking_recver(int fd) -{ - ssize_t len; - char ch; - - len = recv(fd, &ch, sizeof(ch), 0); - if (len < 0) - err(-1, "FAIL: blocking_recver: recv"); - if (len == 0) - errx(-1, "FAIL: blocking_recver: recv: eof"); - if (len != 1) - errx(-1, "FAIL: blocking_recver: recv: %zd bytes", len); - if (interrupted) - errx(-1, "FAIL: blocking_recver: interrupted wrong pid"); -} - -/* - * Process that will perform a locking recv on a UNIX domain socket. - * - * This is where we figure out if the test worked or not. If it has failed, - * then recv() will return EOF, as the close() arrives before the signal, - * meaning that the wait for the sblock was not interrupted; if it has - * succeeded, we get EINTR as the signal interrupts the lock request. - */ -static void -locking_recver(int fd) -{ - ssize_t len; - char ch; - - if (sleep(1) != 0) - err(-1, "FAIL: locking_recver: sleep"); - len = recv(fd, &ch, sizeof(ch), 0); - if (len < 0 && errno != EINTR) - err(-1, "FAIL: locking_recver: recv"); - if (len < 0 && errno == EINTR) { - fprintf(stderr, "PASS\n"); - exit(0); - } - if (len == 0) - errx(-1, "FAIL: locking_recver: recv: eof"); - if (!interrupted) - errx(-1, "FAIL: locking_recver: not interrupted"); -} - -static void -signaller(pid_t locking_recver_pid, int fd) -{ - ssize_t len; - char ch; - - if (sleep(2) != 0) { - warn("signaller sleep(2)"); - return; - } - if (kill(locking_recver_pid, SIGHUP) < 0) { - warn("signaller kill(%d)", locking_recver_pid); - return; - } - if (sleep(1) != 0) { - warn("signaller sleep(1)"); - return; - } - len = send(fd, &ch, sizeof(ch), 0); - if (len < 0) { - warn("signaller send"); - return; - } - if (len != sizeof(ch)) { - warnx("signaller send ret %zd", len); - return; - } - if (close(fd) < 0) { - warn("signaller close"); - return; - } - if (sleep(1) != 0) { - warn("signaller sleep(1)"); - return; - } -} - -int -main(void) -{ - int error, fds[2], recver_fd, sender_fd; - pid_t blocking_recver_pid; - pid_t locking_recver_pid; - struct sigaction sa; - - if (sigaction(SIGHUP, NULL, &sa) < 0) - err(-1, "FAIL: sigaction(SIGHUP, NULL, &sa)"); - - sa.sa_handler = signal_handler; - if (sa.sa_flags & SA_RESTART) - printf("SIGHUP restartable by default (cleared)\n"); - sa.sa_flags &= ~SA_RESTART; - - if (sigaction(SIGHUP, &sa, NULL) < 0) - err(-1, "FAIL: sigaction(SIGHUP, &sa, NULL)"); - -#if 0 - if (signal(SIGHUP, signal_handler) == SIG_ERR) - err(-1, "FAIL: signal(SIGHUP)"); -#endif - - if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) - err(-1, "FAIL: socketpair(PF_LOCAL, SOGK_STREAM, 0)"); - - sender_fd = fds[0]; - recver_fd = fds[1]; - - blocking_recver_pid = fork(); - if (blocking_recver_pid < 0) - err(-1, "FAIL: fork"); - if (blocking_recver_pid == 0) { - close(sender_fd); - blocking_recver(recver_fd); - exit(0); - } - - locking_recver_pid = fork(); - if (locking_recver_pid < 0) { - error = errno; - kill(blocking_recver_pid, SIGKILL); - errno = error; - err(-1, "FAIL: fork"); - } - if (locking_recver_pid == 0) { - close(sender_fd); - locking_recver(recver_fd); - exit(0); - } - - signaller(locking_recver_pid, sender_fd); - - kill(blocking_recver_pid, SIGKILL); - kill(locking_recver_pid, SIGKILL); - exit(0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/sblock_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/accept_fd_leak_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/accept_fd_leak_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/accept_fd_leak_test.c (nonexistent) @@ -1,215 +0,0 @@ -/*- - * Copyright (c) 2004 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 - -#define BIND_ATTEMPTS 10 -#define LOOPS 500 -#define NUM_ATTEMPTS 1000 - -static volatile int quit; - -static void -child_died(int sig __unused) -{ - - quit = 1; -} - -/* - * This test is intended to detect a leak of a file descriptor in the process - * following a failed non-blocking accept. It measures an available fd - * baseline, then performs 1000 failing accepts, then checks to see what the - * next fd is. It relies on sequential fd allocation, and will test for it - * briefly before beginning (not 100% reliable, but a good start). - */ -int -main(void) -{ - struct sockaddr_in sin; - socklen_t size; - pid_t child; - int fd1, fd2, fd3, i, listen_port, s, status; - - printf("1..2\n"); - - /* - * Check for sequential fd allocation, and give up early if not. - */ - fd1 = dup(STDIN_FILENO); - fd2 = dup(STDIN_FILENO); - if (fd2 != fd1 + 1) - errx(-1, "Non-sequential fd allocation\n"); - - s = socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) - errx(-1, "socket: %s", strerror(errno)); - - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - srandomdev(); - - for (i = 0; i < BIND_ATTEMPTS; i++) { - /* Pick a random unprivileged port 1025-65535 */ - listen_port = MAX((int)random() % 65535, 1025); - sin.sin_port = htons(listen_port); - if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0) - break; - warn("bind with %d failed", listen_port); - usleep(1000); - } - if (i >= BIND_ATTEMPTS) { - printf("Bail out!\n"); - exit(1); - } - - if (listen(s, -1) != 0) - errx(-1, "listen: %s", strerror(errno)); - - i = fcntl(s, F_GETFL); - if (i == -1) - errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); - i |= O_NONBLOCK; - if (fcntl(s, F_SETFL, i) != 0) - errx(-1, "ioctl(F_SETFL): %s", strerror(errno)); - i = fcntl(s, F_GETFL); - if (i == -1) - errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); - if ((i & O_NONBLOCK) != O_NONBLOCK) - errx(-1, "Failed to set O_NONBLOCK (i=0x%x)\n", i); - - for (i = 0; i < LOOPS; i++) { - size = sizeof(sin); - if (accept(s, (struct sockaddr *)&sin, &size) != -1) - errx(-1, "accept succeeded\n"); - if (errno != EAGAIN) - errx(-1, "accept: %s", strerror(errno)); - } - - /* - * Allocate a file descriptor and make sure it's fd2+2. 2 because - * we allocate an fd for the socket. - */ - fd3 = dup(STDIN_FILENO); - if (fd3 != fd2 + 2) - printf("not ok 1 - (%d, %d, %d)\n", fd1, fd2, fd3); - else - printf("ok 1\n"); - - /* - * Try failing accept's w/o non-blocking where the destination - * address pointer is invalid. - */ - close(fd3); - signal(SIGCHLD, child_died); - child = fork(); - if (child < 0) - errx(-1, "fork: %s", strerror(errno)); - - /* - * Child process does `NUM_ATTEMPTS` connects. - */ - if (child == 0) { - close(fd1); - close(fd2); - close(s); - - 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(listen_port); - - for (i = 0; i < NUM_ATTEMPTS; i++) { - s = socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) - errx(-1, "socket: %s", strerror(errno)); - if (connect(s, (struct sockaddr *)&sin, - sizeof(sin)) < 0) - errx(-1, "connect: %s", strerror(errno)); - close(s); - } - _exit(0); - } - - /* Reset back to a blocking socket. */ - i = fcntl(s, F_GETFL); - if (i == -1) - errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); - i &= ~O_NONBLOCK; - if (fcntl(s, F_SETFL, i) != 0) - errx(-1, "ioctl(F_SETFL): %s", strerror(errno)); - i = fcntl(s, F_GETFL); - if (i == -1) - errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); - if (i & O_NONBLOCK) - errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i); - - /* Do `NUM_ATTEMPTS` accepts with an invalid pointer. */ - for (i = 0; !quit && i < NUM_ATTEMPTS; i++) { - size = sizeof(sin); - if (accept(s, (struct sockaddr *)(uintptr_t)(0x100), - &size) != -1) - errx(-1, "accept succeeded\n"); - if (errno != EFAULT) - errx(-1, "accept: %s", strerror(errno)); - } - - if (waitpid(child, &status, 0) < 0) - errx(-1, "waitpid: %s", strerror(errno)); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - warnx("child process died"); - - /* - * Allocate a file descriptor and make sure it's fd2+2. 2 because - * we allocate an fd for the socket. - */ - fd3 = dup(STDIN_FILENO); - if (fd3 != fd2 + 2) - printf("not ok 2 - (%d, %d, %d)\n", fd1, fd2, fd3); - else - printf("ok 2\n"); - - return (0); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/accept_fd_leak_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/Makefile =================================================================== --- user/ngie/more-tests/tests/sys/sockets/Makefile (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/Makefile (nonexistent) @@ -1,54 +0,0 @@ -# $FreeBSD$ -# -# Some of these tests fail on 11.0-CURRENT @ r280355 with DEBUG bits on - -TESTSDIR= ${TESTSBASE}/sys/socket - -BINDIR= ${TESTSDIR} - -PROGS+= unix_cmsg - -TAP_TESTS_C+= accept_fd_leak_test -# accf_data_attach: not ok 9 - setsockopt() after listen() failed with 2 (No such file or directory) -TAP_TESTS_C+= accf_data_attach_test -PLAIN_TESTS_C+= fstat_test -PLAIN_TESTS_C+= kqueue_test -PLAIN_TESTS_C+= listen_backlog_test -PLAIN_TESTS_C+= listenclose_test -PLAIN_TESTS_C+= pr_atomic_test -PLAIN_TESTS_C+= reconnect_test -# rtsocket: socket(PF_ROUTE, SOCK_STREAM, 0): Protocol wrong type for socket -PLAIN_TESTS_C+= rtsocket_test -PLAIN_TESTS_C+= sblock_test -TAP_TESTS_C+= sendfile_test -PLAIN_TESTS_C+= shutdown_test -PLAIN_TESTS_C+= sigpipe_test -TAP_TESTS_C+= so_setfib_test -PLAIN_TESTS_C+= socketpair_test -PLAIN_TESTS_C+= unix_bindconnect_test -PLAIN_TESTS_C+= unix_close_race_test -# Lots of failures -TAP_TESTS_SH+= unix_cmsg_test -# unix_gc: twosome_drop1: sendfd: before 0 after 0 -PLAIN_TESTS_C+= unix_gc_test -# unix_passfd: test8-rights+creds+payload: recvmsg: 24 bytes received -PLAIN_TESTS_C+= unix_passfd_test -PLAIN_TESTS_C+= unix_sendtorace_test -# unix_socket: socket(PF_LOCAL, SOCK_RAW, 0): Protocol wrong type for socket -PLAIN_TESTS_C+= unix_socket_test -PLAIN_TESTS_C+= unix_sorflush_test -# zerosend: tcp_0write: bind(127.0.0.1, 10001): Address already in use -PLAIN_TESTS_C+= zerosend_test - -DPADD.sendfile_test+= ${LIBMD} -LDADD.sendfile_test+= -lmd - -# XXX: this doesn't work..? -#WARNS.unix_cmsg= 3 -#WARNS.unix_gc= 3 -#WARNS.unix_passfd= 3 -#WARNS.zerosend= 2 - -WARNS= 2 - -.include Property changes on: user/ngie/more-tests/tests/sys/sockets/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/sigpipe_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/sigpipe_test.c (revision 281515) +++ user/ngie/more-tests/tests/sys/sockets/sigpipe_test.c (nonexistent) @@ -1,322 +0,0 @@ -/*- - * 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 - -/* - * 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) -{ - - 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 != 2) - usage(); - - port = strtol(argv[1], &dummy, 10); - if (port < 0 || port > 65535 || *dummy != '\0') - 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); -} Property changes on: user/ngie/more-tests/tests/sys/sockets/sigpipe_test.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/Makefile =================================================================== --- user/ngie/more-tests/tests/sys/Makefile (revision 281515) +++ user/ngie/more-tests/tests/sys/Makefile (revision 281516) @@ -1,22 +1,22 @@ # $FreeBSD$ .include TESTSDIR= ${TESTSBASE}/sys TESTS_SUBDIRS+= fifo TESTS_SUBDIRS+= file TESTS_SUBDIRS+= kern TESTS_SUBDIRS+= kqueue TESTS_SUBDIRS+= mqueue TESTS_SUBDIRS+= mmap TESTS_SUBDIRS+= netinet TESTS_SUBDIRS+= opencrypto TESTS_SUBDIRS+= posixshm -TESTS_SUBDIRS+= sockets +TESTS_SUBDIRS+= socket TESTS_SUBDIRS+= vfs # Items not integrated into kyua runs by default SUBDIR+= pjdfstest .include Index: user/ngie/more-tests/tests/sys/socket/Makefile =================================================================== --- user/ngie/more-tests/tests/sys/socket/Makefile (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/Makefile (revision 281516) @@ -0,0 +1,54 @@ +# $FreeBSD$ +# +# Some of these tests fail on 11.0-CURRENT @ r280355 with DEBUG bits on + +TESTSDIR= ${TESTSBASE}/sys/socket + +BINDIR= ${TESTSDIR} + +PROGS+= unix_cmsg + +TAP_TESTS_C+= accept_fd_leak_test +# accf_data_attach: not ok 9 - setsockopt() after listen() failed with 2 (No such file or directory) +TAP_TESTS_C+= accf_data_attach_test +PLAIN_TESTS_C+= fstat_test +PLAIN_TESTS_C+= kqueue_test +PLAIN_TESTS_C+= listen_backlog_test +PLAIN_TESTS_C+= listenclose_test +PLAIN_TESTS_C+= pr_atomic_test +PLAIN_TESTS_C+= reconnect_test +# rtsocket: socket(PF_ROUTE, SOCK_STREAM, 0): Protocol wrong type for socket +PLAIN_TESTS_C+= rtsocket_test +PLAIN_TESTS_C+= sblock_test +TAP_TESTS_C+= sendfile_test +PLAIN_TESTS_C+= shutdown_test +PLAIN_TESTS_C+= sigpipe_test +TAP_TESTS_C+= so_setfib_test +PLAIN_TESTS_C+= socketpair_test +PLAIN_TESTS_C+= unix_bindconnect_test +PLAIN_TESTS_C+= unix_close_race_test +# Lots of failures +TAP_TESTS_SH+= unix_cmsg_test +# unix_gc: twosome_drop1: sendfd: before 0 after 0 +PLAIN_TESTS_C+= unix_gc_test +# unix_passfd: test8-rights+creds+payload: recvmsg: 24 bytes received +PLAIN_TESTS_C+= unix_passfd_test +PLAIN_TESTS_C+= unix_sendtorace_test +# unix_socket: socket(PF_LOCAL, SOCK_RAW, 0): Protocol wrong type for socket +PLAIN_TESTS_C+= unix_socket_test +PLAIN_TESTS_C+= unix_sorflush_test +# zerosend: tcp_0write: bind(127.0.0.1, 10001): Address already in use +PLAIN_TESTS_C+= zerosend_test + +DPADD.sendfile_test+= ${LIBMD} +LDADD.sendfile_test+= -lmd + +# XXX: this doesn't work..? +#WARNS.unix_cmsg= 3 +#WARNS.unix_gc= 3 +#WARNS.unix_passfd= 3 +#WARNS.zerosend= 2 + +WARNS= 2 + +.include Property changes on: user/ngie/more-tests/tests/sys/socket/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/README.unix_cmsg =================================================================== --- user/ngie/more-tests/tests/sys/socket/README.unix_cmsg (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/README.unix_cmsg (revision 281516) @@ -0,0 +1,160 @@ +$FreeBSD$ + +About unix_cmsg +=============== + +This program is a collection of regression tests for ancillary data +(control information) for PF_LOCAL sockets (local domain or Unix domain +sockets). There are tests for stream and datagram sockets. + +Usually each test does following steps: creates Server, forks Client, +Client sends something to Server, Server verifies whether everything is +correct in received message(s). + +It is better to change the owner of unix_cmsg to some safe user +(eg. nobody:nogroup) and set SUID and SGID bits, else some tests that +check credentials can give correct results for wrong implementation. + +It is better to run this program by a user that belongs to more +than 16 groups. + +Available options +================= + +usage: unix_cmsg [-dh] [-n num] [-s size] [-t type] [-z value] [testno] + + Options are: + -d Output debugging information + -h Output the help message and exit + -n num Number of messages to send + -s size Specify size of data for IPC + -t type Specify socket type (stream, dgram) for tests + -z value Do not send data in a message (bit 0x1), do not send + data array associated with a cmsghdr structure (bit 0x2) + testno Run one test by its number (require the -t option) + +Description +=========== + +If Client sends something to Server, then it sends 5 messages by default. +Number of messages can be changed in the -n command line option. Number +of messages will be given as N in the following descriptions. + +If Client sends something to Server, then it sends some data (few bytes) +in each message by default. The size of this data can be changed by the -s +command line option. The "-s 0" command line option means, that Client will +send zero bytes represented by { NULL, 0 } value of struct iovec{}, referenced +by the msg_iov field from struct msghdr{}. The "-z 1" or "-z 3" command line +option means, that Client will send zero bytes represented by the NULL value +in the msg_iov field from struct msghdr{}. + +If Client sends some ancillary data object, then this ancillary data object +always has associated data array by default. The "-z 2" or "-z 3" option +means, that Client will not send associated data array if possible. + +For SOCK_STREAM sockets: +----------------------- + + 1: Sending, receiving cmsgcred + + Client connects to Server and sends N messages with SCM_CREDS ancillary + data object. Server should receive N messages, each message should + have SCM_CREDS ancillary data object followed by struct cmsgcred{}. + + 2: Receiving sockcred (listening socket) + + Server creates a listening stream socket and sets the LOCAL_CREDS + socket option for it. Client connects to Server two times, each time + it sends N messages. Server accepts two connections and receives N + messages from each connection. The first message from each connection + should have SCM_CREDS ancillary data object followed by struct sockcred{}, + next messages from the same connection should not have ancillary data. + + 3: Receiving sockcred (accepted socket) + + Client connects to Server. Server accepts connection and sets the + LOCAL_CREDS socket option for just accepted socket. Client sends N + messages to Server. Server should receive N messages, the first + message should have SCM_CREDS ancillary data object followed by + struct sockcred{}, next messages should not have ancillary data. + + 4: Sending cmsgcred, receiving sockcred + + Server creates a listening stream socket and sets the LOCAL_CREDS + socket option for it. Client connects to Server and sends N messages + with SCM_CREDS ancillary data object. Server should receive N messages, + the first message should have SCM_CREDS ancillary data object followed + by struct sockcred{}, each of next messages should have SCM_CREDS + ancillary data object followed by struct cmsgcred{}. + + 5: Sending, receiving timeval + + Client connects to Server and sends message with SCM_TIMESTAMP ancillary + data object. Server should receive one message with SCM_TIMESTAMP + ancillary data object followed by struct timeval{}. + + 6: Sending, receiving bintime + + Client connects to Server and sends message with SCM_BINTIME ancillary + data object. Server should receive one message with SCM_BINTIME + ancillary data object followed by struct bintime{}. + + 7: Checking cmsghdr.cmsg_len + + Client connects to Server and tries to send several messages with + SCM_CREDS ancillary data object that has wrong cmsg_len field in its + struct cmsghdr{}. All these attempts should fail, since cmsg_len + in all requests is less than CMSG_LEN(0). + + 8: Check LOCAL_PEERCRED socket option + + This test does not use ancillary data, but can be implemented here. + Client connects to Server. Both Client and Server verify that + credentials of the peer are correct using LOCAL_PEERCRED socket option. + +For SOCK_DGRAM sockets: +---------------------- + + 1: Sending, receiving cmsgcred + + Client connects to Server and sends N messages with SCM_CREDS ancillary + data object. Server should receive N messages, each message should + have SCM_CREDS ancillary data object followed by struct cmsgcred{}. + + 2: Receiving sockcred + + Server creates datagram socket and sets the LOCAL_CREDS socket option + for it. Client sends N messages to Server. Server should receive N + messages, each message should have SCM_CREDS ancillary data object + followed by struct sockcred{}. + + 3: Sending cmsgcred, receiving sockcred + + Server creates datagram socket and sets the LOCAL_CREDS socket option + for it. Client sends N messages with SCM_CREDS ancillary data object + to Server. Server should receive N messages, the first message should + have SCM_CREDS ancillary data object followed by struct sockcred{}, + each of next messages should have SCM_CREDS ancillary data object + followed by struct cmsgcred{}. + + 4: Sending, receiving timeval + + Client sends one message with SCM_TIMESTAMP ancillary data object + to Server. Server should receive one message with SCM_TIMESTAMP + ancillary data object followed by struct timeval{}. + + 5: Sending, receiving bintime + + Client sends one message with SCM_BINTIME ancillary data object + to Server. Server should receive one message with SCM_BINTIME + ancillary data object followed by struct bintime{}. + + 6: Checking cmsghdr.cmsg_len + + Client tries to send Server several messages with SCM_CREDS ancillary + data object that has wrong cmsg_len field in its struct cmsghdr{}. + All these attempts should fail, since cmsg_len in all requests is less + than CMSG_LEN(0). + +- Andrey Simonenko +andreysimonenko@users.sourceforge.net Property changes on: user/ngie/more-tests/tests/sys/socket/README.unix_cmsg ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/accept_fd_leak_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/accept_fd_leak_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/accept_fd_leak_test.c (revision 281516) @@ -0,0 +1,215 @@ +/*- + * Copyright (c) 2004 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 + +#define BIND_ATTEMPTS 10 +#define LOOPS 500 +#define NUM_ATTEMPTS 1000 + +static volatile int quit; + +static void +child_died(int sig __unused) +{ + + quit = 1; +} + +/* + * This test is intended to detect a leak of a file descriptor in the process + * following a failed non-blocking accept. It measures an available fd + * baseline, then performs 1000 failing accepts, then checks to see what the + * next fd is. It relies on sequential fd allocation, and will test for it + * briefly before beginning (not 100% reliable, but a good start). + */ +int +main(void) +{ + struct sockaddr_in sin; + socklen_t size; + pid_t child; + int fd1, fd2, fd3, i, listen_port, s, status; + + printf("1..2\n"); + + /* + * Check for sequential fd allocation, and give up early if not. + */ + fd1 = dup(STDIN_FILENO); + fd2 = dup(STDIN_FILENO); + if (fd2 != fd1 + 1) + errx(-1, "Non-sequential fd allocation\n"); + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) + errx(-1, "socket: %s", strerror(errno)); + + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + srandomdev(); + + for (i = 0; i < BIND_ATTEMPTS; i++) { + /* Pick a random unprivileged port 1025-65535 */ + listen_port = MAX((int)random() % 65535, 1025); + sin.sin_port = htons(listen_port); + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0) + break; + warn("bind with %d failed", listen_port); + usleep(1000); + } + if (i >= BIND_ATTEMPTS) { + printf("Bail out!\n"); + exit(1); + } + + if (listen(s, -1) != 0) + errx(-1, "listen: %s", strerror(errno)); + + i = fcntl(s, F_GETFL); + if (i == -1) + errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); + i |= O_NONBLOCK; + if (fcntl(s, F_SETFL, i) != 0) + errx(-1, "ioctl(F_SETFL): %s", strerror(errno)); + i = fcntl(s, F_GETFL); + if (i == -1) + errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); + if ((i & O_NONBLOCK) != O_NONBLOCK) + errx(-1, "Failed to set O_NONBLOCK (i=0x%x)\n", i); + + for (i = 0; i < LOOPS; i++) { + size = sizeof(sin); + if (accept(s, (struct sockaddr *)&sin, &size) != -1) + errx(-1, "accept succeeded\n"); + if (errno != EAGAIN) + errx(-1, "accept: %s", strerror(errno)); + } + + /* + * Allocate a file descriptor and make sure it's fd2+2. 2 because + * we allocate an fd for the socket. + */ + fd3 = dup(STDIN_FILENO); + if (fd3 != fd2 + 2) + printf("not ok 1 - (%d, %d, %d)\n", fd1, fd2, fd3); + else + printf("ok 1\n"); + + /* + * Try failing accept's w/o non-blocking where the destination + * address pointer is invalid. + */ + close(fd3); + signal(SIGCHLD, child_died); + child = fork(); + if (child < 0) + errx(-1, "fork: %s", strerror(errno)); + + /* + * Child process does `NUM_ATTEMPTS` connects. + */ + if (child == 0) { + close(fd1); + close(fd2); + close(s); + + 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(listen_port); + + for (i = 0; i < NUM_ATTEMPTS; i++) { + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) + errx(-1, "socket: %s", strerror(errno)); + if (connect(s, (struct sockaddr *)&sin, + sizeof(sin)) < 0) + errx(-1, "connect: %s", strerror(errno)); + close(s); + } + _exit(0); + } + + /* Reset back to a blocking socket. */ + i = fcntl(s, F_GETFL); + if (i == -1) + errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); + i &= ~O_NONBLOCK; + if (fcntl(s, F_SETFL, i) != 0) + errx(-1, "ioctl(F_SETFL): %s", strerror(errno)); + i = fcntl(s, F_GETFL); + if (i == -1) + errx(-1, "ioctl(F_GETFL): %s", strerror(errno)); + if (i & O_NONBLOCK) + errx(-1, "Failed to clear O_NONBLOCK (i=0x%x)\n", i); + + /* Do `NUM_ATTEMPTS` accepts with an invalid pointer. */ + for (i = 0; !quit && i < NUM_ATTEMPTS; i++) { + size = sizeof(sin); + if (accept(s, (struct sockaddr *)(uintptr_t)(0x100), + &size) != -1) + errx(-1, "accept succeeded\n"); + if (errno != EFAULT) + errx(-1, "accept: %s", strerror(errno)); + } + + if (waitpid(child, &status, 0) < 0) + errx(-1, "waitpid: %s", strerror(errno)); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + warnx("child process died"); + + /* + * Allocate a file descriptor and make sure it's fd2+2. 2 because + * we allocate an fd for the socket. + */ + fd3 = dup(STDIN_FILENO); + if (fd3 != fd2 + 2) + printf("not ok 2 - (%d, %d, %d)\n", fd1, fd2, fd3); + else + printf("ok 2\n"); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/accept_fd_leak_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/accf_data_attach_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/accf_data_attach_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/accf_data_attach_test.c (revision 281516) @@ -0,0 +1,216 @@ +/*- + * Copyright (c) 2004 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 + +#define ACCF_NAME "dataready" + +/* + * A number of small tests to confirm that attaching ACCF_DATA accept filters + * to inet4 ports works as expected. We test: + * + * - That no accept filter is attached on a newly created socket. + * - That bind() has no affect on the accept filter state. + * - That we can't attach an accept filter to a socket that isn't in the + * listen state. + * - That after we fail to attach the filter, querying the kernel shows no + * filter attached. + * - That we can attach an accept filter to a socket that is in the listen + * state. + * - That once an accept filter is attached, we can query to make sure it is + * attached. + * - That once an accept filter is attached, we can remove it and query to + * make sure it is removed. + */ +int +main(void) +{ + struct accept_filter_arg afa; + struct sockaddr_in sin; + socklen_t len; + int lso, ret; + + printf("1..11\n"); + + /* + * Step 0. Open socket(). + */ + lso = socket(PF_INET, SOCK_STREAM, 0); + if (lso == -1) + errx(-1, "not ok 1 - socket: %s", strerror(errno)); + printf("ok 1 - socket\n"); + + /* + * Step 1. After socket(). Should return EINVAL, since no accept + * filter should be attached. + */ + bzero(&afa, sizeof(afa)); + len = sizeof(afa); + ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); + if (ret != -1) + errx(-1, "not ok 2 - getsockopt() after socket() succeeded"); + if (errno != EINVAL) + errx(-1, "not ok 2 - getsockopt() after socket() failed with " + "%d (%s)", errno, strerror(errno)); + printf("ok 2 - getsockopt\n"); + + /* + * Step 2. Bind(). Ideally this will succeed. + */ + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(8080); + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (bind(lso, (struct sockaddr *)&sin, sizeof(sin)) < 0) + errx(-1, "not ok 3 - bind %s", strerror(errno)); + printf("ok 3 - bind\n"); + + /* + * Step 3: After bind(). getsockopt() should return EINVAL, since no + * accept filter should be attached. + */ + len = sizeof(afa); + ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); + if (ret != -1) + errx(-1, "not ok 4 - getsockopt() after bind() succeeded"); + if (errno != EINVAL) + errx(-1, "not ok 4 - getsockopt() after bind() failed with %d (%s)", + errno, strerror(errno)); + printf("ok 4 - getsockopt\n"); + + /* + * Step 4: Setsockopt() before listen(). Should fail, since it's not + * yet a listen() socket. + */ + bzero(&afa, sizeof(afa)); + strcpy(afa.af_name, ACCF_NAME); + ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); + if (ret == 0) + errx(-1, "not ok 5 - setsockopt() before listen() succeeded"); + printf("ok 5 - setsockopt\n"); + + /* + * Step 5: Getsockopt() after pre-listen() setsockopt(). Should + * fail with EINVAL, since setsockopt() should have failed. + */ + len = sizeof(afa); + ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); + if (ret == 0) + errx(-1, "not ok 6 - getsockopt() after pre-listen() setsockopt() " + "succeeded"); + if (errno != EINVAL) + errx(-1, "not ok 6 - pre-listen() getsockopt() failed with %d (%s)", + errno, strerror(errno)); + printf("ok 6 - getsockopt\n"); + + /* + * Step 6: listen(). + */ + if (listen(lso, -1) < 0) + errx(-1, "not ok 7 - listen: %s", strerror(errno)); + printf("ok 7 - listen\n"); + + /* + * Step 7: Getsockopt() after listen(). Should fail with EINVAL, + * since we have not installed accept filter yet. + */ + len = sizeof(afa); + ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); + if (ret == 0) + errx(-1, "not ok 8 - getsockopt() after listen() but before " + "setsockopt() succeeded"); + if (errno != EINVAL) + errx(-1, "not ok 8 - getsockopt() after listen() but before " + "setsockopt() failed with %d (%s)", errno, strerror(errno)); + printf("ok 8 - getsockopt\n"); + + /* + * Step 8: After listen(). This call to setsockopt() should succeed. + */ + bzero(&afa, sizeof(afa)); + strcpy(afa.af_name, ACCF_NAME); + ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)); + if (ret != 0) + errx(-1, "not ok 9 - setsockopt() after listen() failed with %d " + "(%s)", errno, strerror(errno)); + printf("ok 9 - setsockopt\n"); + + /* + * Step 9: After setsockopt(). Should succeed and identify + * ACCF_NAME. + */ + bzero(&afa, sizeof(afa)); + len = sizeof(afa); + ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); + if (ret != 0) + errx(-1, "not ok 10 - getsockopt() after listen() setsockopt() " + "failed with %d (%s)", errno, strerror(errno)); + if (len != sizeof(afa)) + errx(-1, "not ok 10 - getsockopt() after setsockopet() after " + "listen() returned wrong size (got %d expected %zd)", len, + sizeof(afa)); + if (strcmp(afa.af_name, ACCF_NAME) != 0) + errx(-1, "not ok 10 - getsockopt() after setsockopt() after " + "listen() mismatch (got %s expected %s)", afa.af_name, + ACCF_NAME); + printf("ok 10 - getsockopt\n"); + + /* + * Step 10: Remove accept filter. After removing the accept filter + * getsockopt() should fail with EINVAL. + */ + ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0); + if (ret != 0) + errx(-1, "not ok 11 - setsockopt() after listen() " + "failed with %d (%s)", errno, strerror(errno)); + bzero(&afa, sizeof(afa)); + len = sizeof(afa); + ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len); + if (ret == 0) + errx(-1, "not ok 11 - getsockopt() after removing " + "the accept filter returns valid accept filter %s", + afa.af_name); + if (errno != EINVAL) + errx(-1, "not ok 11 - getsockopt() after removing the accept" + "filter failed with %d (%s)", errno, strerror(errno)); + printf("ok 11 - setsockopt\n"); + + close(lso); + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/accf_data_attach_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/fstat_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/fstat_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/fstat_test.c (revision 281516) @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2008 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 + +/* + * Basic test to make sure that fstat(2) returns success on various socket + * types. In the future we should also validate the fields, confirming + * expected results such as the effect of shutdown(2) on permissions, etc. + */ + +static void +dotest(int domain, int type, int protocol) +{ + struct stat sb; + int sock; + + sock = socket(domain, type, protocol); + if (sock < 0) + err(-1, "socket(%d, %d, %d)", domain, type, protocol); + + if (fstat(sock, &sb) < 0) + err(-1, "fstat on socket(%d, %d, %d)", domain, type, + protocol); + + close(sock); +} + +int +main(void) +{ + + dotest(PF_INET, SOCK_DGRAM, 0); + dotest(PF_INET, SOCK_STREAM, 0); + dotest(PF_INET6, SOCK_DGRAM, 0); + dotest(PF_INET6, SOCK_STREAM, 0); + dotest(PF_LOCAL, SOCK_DGRAM, 0); + dotest(PF_LOCAL, SOCK_STREAM, 0); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/fstat_test.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/kqueue_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/kqueue_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/kqueue_test.c (revision 281516) @@ -0,0 +1,368 @@ +/*- + * Copyright (c) 2004 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 + +static int curtest = 1; + +/*- + * This test uses UNIX domain socket pairs to perform some basic exercising + * of kqueue functionality on sockets. In particular, testing that for read + * and write filters, we see the correct detection of whether reads and + * writes should actually be able to occur. + * + * TODO: + * - Test read/write filters for listen/accept sockets. + * - Handle the XXXRW below regarding datagram sockets. + * - Test that watermark/buffer size "data" fields returned by kqueue are + * correct. + * - Check that kqueue does something sensible when the remote endpoing is + * closed. + */ + +#define OK(testname) printf("ok %d - %s\n", curtest, testname); \ + curtest++; + +static void +fail(int error, const char *func, const char *socktype, const char *rest) +{ + + printf("not ok %d\n", curtest); + + if (socktype == NULL) + printf("# %s(): %s\n", func, strerror(error)); + else if (rest == NULL) + printf("# %s(%s): %s\n", func, socktype, + strerror(error)); + else + printf("# %s(%s, %s): %s\n", func, socktype, rest, + strerror(error)); + exit(-1); +} + +static void +fail_assertion(const char *func, const char *socktype, const char *rest, + const char *assertion) +{ + + printf("not ok %d - %s\n", curtest, assertion); + + if (socktype == NULL) + printf("# %s(): assertion %s failed\n", func, + assertion); + else if (rest == NULL) + printf("# %s(%s): assertion %s failed\n", func, + socktype, assertion); + else + printf("# %s(%s, %s): assertion %s failed\n", func, + socktype, rest, assertion); + exit(-1); +} + +/* + * Test read kevent on a socket pair: check to make sure endpoint 0 isn't + * readable when we start, then write to endpoint 1 and confirm that endpoint + * 0 is now readable. Drain the write, then check that it's not readable + * again. Use non-blocking kqueue operations and socket operations. + */ +static void +test_evfilt_read(int kq, int fd[2], const char *socktype) +{ + struct timespec ts; + struct kevent ke; + ssize_t len; + char ch; + int i; + + EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) + fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD"); + OK("EVFILT_READ, EV_ADD"); + + /* + * Confirm not readable to begin with, no I/O yet. + */ + ts.tv_sec = 0; + ts.tv_nsec = 0; + i = kevent(kq, NULL, 0, &ke, 1, &ts); + if (i == -1) + fail(errno, "kevent", socktype, "EVFILT_READ"); + OK("EVFILT_READ"); + if (i != 0) + fail_assertion("kevent", socktype, "EVFILT_READ", + "empty socket unreadable"); + OK("empty socket unreadable"); + + /* + * Write a byte to one end. + */ + ch = 'a'; + len = write(fd[1], &ch, sizeof(ch)); + if (len == -1) + fail(errno, "write", socktype, NULL); + OK("write one byte"); + if (len != sizeof(ch)) + fail_assertion("write", socktype, NULL, "write length"); + OK("write one byte length"); + + /* + * Other end should now be readable. + */ + ts.tv_sec = 0; + ts.tv_nsec = 0; + i = kevent(kq, NULL, 0, &ke, 1, &ts); + if (i == -1) + fail(errno, "kevent", socktype, "EVFILT_READ"); + OK("EVFILT_READ"); + if (i != 1) + fail_assertion("kevent", socktype, "EVFILT_READ", + "non-empty socket unreadable"); + OK("non-empty socket unreadable"); + + /* + * Read a byte to clear the readable state. + */ + len = read(fd[0], &ch, sizeof(ch)); + if (len == -1) + fail(errno, "read", socktype, NULL); + OK("read one byte"); + if (len != sizeof(ch)) + fail_assertion("read", socktype, NULL, "read length"); + OK("read one byte length"); + + /* + * Now re-check for readability. + */ + ts.tv_sec = 0; + ts.tv_nsec = 0; + i = kevent(kq, NULL, 0, &ke, 1, &ts); + if (i == -1) + fail(errno, "kevent", socktype, "EVFILT_READ"); + OK("EVFILT_READ"); + if (i != 0) + fail_assertion("kevent", socktype, "EVFILT_READ", + "empty socket unreadable"); + OK("empty socket unreadable"); + + EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL); + if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) + fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE"); + OK("EVFILT_READ, EV_DELETE"); +} + +static void +test_evfilt_write(int kq, int fd[2], const char *socktype) +{ + struct timespec ts; + struct kevent ke; + ssize_t len; + char ch; + int i; + + EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL); + if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) + fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD"); + OK("EVFILE_WRITE, EV_ADD"); + + /* + * Confirm writable to begin with, no I/O yet. + */ + ts.tv_sec = 0; + ts.tv_nsec = 0; + i = kevent(kq, NULL, 0, &ke, 1, &ts); + if (i == -1) + fail(errno, "kevent", socktype, "EVFILT_WRITE"); + OK("EVFILE_WRITE"); + if (i != 1) + fail_assertion("kevent", socktype, "EVFILT_WRITE", + "empty socket unwritable"); + OK("empty socket unwritable"); + + /* + * Write bytes into the socket until we can't write anymore. + */ + ch = 'a'; + while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {}; + if (len == -1 && errno != EAGAIN && errno != ENOBUFS) + fail(errno, "write", socktype, NULL); + OK("write"); + if (len != -1 && len != sizeof(ch)) + fail_assertion("write", socktype, NULL, "write length"); + OK("write length"); + + /* + * Check to make sure the socket is no longer writable. + */ + ts.tv_sec = 0; + ts.tv_nsec = 0; + i = kevent(kq, NULL, 0, &ke, 1, &ts); + if (i == -1) + fail(errno, "kevent", socktype, "EVFILT_WRITE"); + OK("EVFILT_WRITE"); + if (i != 0) + fail_assertion("kevent", socktype, "EVFILT_WRITE", + "full socket writable"); + OK("full socket writable"); + + EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1) + fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE"); + OK("EVFILT_WRITE, EV_DELETE"); +} + +/* + * Basic registration exercise for kqueue(2). Create several types/brands of + * sockets, and confirm that we can register for various events on them. + */ +int +main(void) +{ + int kq, sv[2]; + + printf("1..49\n"); + + kq = kqueue(); + if (kq == -1) + fail(errno, "kqueue", NULL, NULL); + OK("kqueue()"); + + /* + * Create a UNIX domain datagram socket, and attach/test/detach a + * read filter on it. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) + fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); + OK("socketpair() 1"); + + if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); + OK("fcntl() 1"); + if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); + OK("fnctl() 2"); + + test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM"); + + if (close(sv[0]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); + OK("close() 1"); + if (close(sv[1]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); + OK("close() 2"); + +#if 0 + /* + * XXXRW: We disable the write test in the case of datagram sockets, + * as kqueue can't tell when the remote socket receive buffer is + * full, whereas the UNIX domain socket implementation can tell and + * returns ENOBUFS. + */ + /* + * Create a UNIX domain datagram socket, and attach/test/detach a + * write filter on it. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) + fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL); + + if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); + if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK"); + + test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM"); + + if (close(sv[0]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]"); + if (close(sv[1]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]"); +#endif + + /* + * Create a UNIX domain stream socket, and attach/test/detach a + * read filter on it. + */ + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) + fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); + OK("socketpair() 2"); + + if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); + OK("fcntl() 3"); + if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); + OK("fcntl() 4"); + + test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM"); + + if (close(sv[0]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); + OK("close() 3"); + if (close(sv[1]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); + OK("close() 4"); + + /* + * Create a UNIX domain stream socket, and attach/test/detach a + * write filter on it. + */ + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) + fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL); + OK("socketpair() 3"); + + if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); + OK("fcntl() 5"); + if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0) + fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK"); + OK("fcntl() 6"); + + test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM"); + + if (close(sv[0]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]"); + OK("close() 5"); + if (close(sv[1]) == -1) + fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]"); + OK("close() 6"); + + if (close(kq) == -1) + fail(errno, "close", "kq", NULL); + OK("close() 7"); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/kqueue_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/listen_backlog_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/listen_backlog_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/listen_backlog_test.c (revision 281516) @@ -0,0 +1,383 @@ +/*- + * 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 + +/* + * This regression test is intended to validate that the backlog parameter + * set by listen() is properly set, can be retrieved using SO_LISTENQLIMIT, + * and that it can be updated by later calls to listen(). We also check that + * SO_LISTENQLIMIT cannot be set. + * + * Future things to test: + * + * - That if we change the value of kern.ipc.somaxconn, the limits really + * do change. + * + * - That limits are, approximately, enforced and implemented. + * + * - All this on multiple socket types -- i.e., PF_LOCAL. + * + * - That we also test SO_LISTENQLEN and SO_LISTENINCQLEN. + */ + +/* + * We retrieve kern.ipc.somaxconn before running the tests in order to use a + * run-time set value of SOMAXCONN, rather than compile-time set. We assume + * that no other process will be simultaneously frobbing it, and these tests + * may fail if that assumption is not held. + */ +static int somaxconn; + +/* + * Retrieve the current socket listen queue limit using SO_LISTENQLIMIT. + */ +static int +socket_get_backlog(int sock, int *backlogp, const char *testclass, + const char *test, const char *testfunc) +{ + socklen_t len; + int i; + + len = sizeof(i); + if (getsockopt(sock, SOL_SOCKET, SO_LISTENQLIMIT, &i, &len) < 0) { + warn("%s: %s: %s: socket_get_backlog: getsockopt(" + "SOL_SOCKET, SO_LISTENQLIMIT)", testclass, test, + testfunc); + return (-1); + } + + if (len != sizeof(i)) { + warnx("%s: %s: %s: socket_get_backlog: getsockopt(" + "SOL_SOCKET, SO_LISTENQLIMIT): returned size %d", + testclass, test, testfunc, len); + return (-1); + } + + *backlogp = i; + + return (0); +} + +/* + * Create a socket, check the queue limit on creation, perform a listen(), + * and make sure that the limit was set as expected by listen(). + */ +static int +socket_listen(int domain, int type, int protocol, int backlog, + int create_backlog_assertion, int listen_backlog_assertion, int *sockp, + const char *domainstring, const char *typestring, const char *testclass, + const char *test) +{ + int backlog_retrieved, sock; + + sock = socket(domain, type, protocol); + if (sock < 0) { + warn("%s: %s: socket_listen: socket(%s, %s)", testclass, + test, domainstring, typestring); + close(sock); + return (-1); + } + + if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, + "socket_listen") < 0) { + close(sock); + return (-1); + } + + if (backlog_retrieved != create_backlog_assertion) { + warnx("%s: %s: socket_listen: create backlog is %d not %d", + testclass, test, backlog_retrieved, + create_backlog_assertion); + close(sock); + return (-1); + } + + if (listen(sock, backlog) < 0) { + warn("%s: %s: socket_listen: listen(, %d)", testclass, test, + backlog); + close(sock); + return (-1); + } + + if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, + "socket_listen") < 0) { + close(sock); + return (-1); + } + + if (backlog_retrieved != listen_backlog_assertion) { + warnx("%s: %s: socket_listen: listen backlog is %d not %d", + testclass, test, backlog_retrieved, + listen_backlog_assertion); + close(sock); + return (-1); + } + + *sockp = sock; + return (0); +} + +/* + * This test creates sockets and tests default states before and after + * listen(). Specifically, we expect a queue limit of 0 before listen, and + * then various settings for after listen(). If the passed backlog was + * either < 0 or > somaxconn, it should be set to somaxconn; otherwise, the + * passed queue depth. + */ +static void +test_defaults(void) +{ + int sock; + + /* + * First pass. Confirm the default is 0. Listen with a backlog of + * 0 and confirm it gets set that way. + */ + if (socket_listen(PF_INET, SOCK_STREAM, 0, 0, 0, 0, &sock, "PF_INET", + "SOCK_STREAM", "test_defaults", "default_0_listen_0") < 0) + exit(-1); + close(sock); + + /* + * Second pass. Listen with a backlog of -1 and make sure it is set + * to somaxconn. + */ + if (socket_listen(PF_INET, SOCK_STREAM, 0, -1, 0, somaxconn, &sock, + "PF_INET", "SOCK_STREAM", "test_defaults", "default_0_listen_-1") + < 0) + exit(-1); + close(sock); + + /* + * Third pass. Listen with a backlog of 1 and make sure it is set to + * 1. + */ + if (socket_listen(PF_INET, SOCK_STREAM, 0, 1, 0, 1, &sock, "PF_INET", + "SOCK_STREAM", "test_defaults", "default_0_listen_1") < 0) + exit(-1); + close(sock); + + /* + * Fourth pass. Listen with a backlog of somaxconn and make sure it + * is set to somaxconn. + */ + if (socket_listen(PF_INET, SOCK_STREAM, 0, somaxconn, 0, somaxconn, + &sock, "PF_INET", "SOCK_STREAM", "test_defaults", + "default_0_listen_somaxconn") < 0) + exit(-1); + close(sock); + + /* + * Fifth pass. Listen with a backlog of somaxconn+1 and make sure it + * is set to somaxconn. + */ + if (socket_listen(PF_INET, SOCK_STREAM, 0, somaxconn+1, 0, somaxconn, + &sock, "PF_INET", "SOCK_STREAM", "test_defaults", + "default_0_listen_somaxconn+1") < 0) + exit(-1); + close(sock); +} + +/* + * Create a socket, set the initial listen() state, then update the queue + * depth using listen(). Check that the backlog is as expected after both + * the first and second listen(). + */ +static int +socket_listen_update(int domain __unused, int type __unused, + int protocol __unused, int backlog, + int update_backlog, int listen_backlog_assertion, + int update_backlog_assertion, int *sockp, const char *domainstring, + const char *typestring, const char *testclass, const char *test) +{ + int backlog_retrieved, sock; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + warn("%s: %s: socket_listen_update: socket(%s, %s)", + testclass, test, domainstring, typestring); + return (-1); + } + + if (listen(sock, backlog) < 0) { + warn("%s: %s: socket_listen_update: initial listen(, %d)", + testclass, test, backlog); + close(sock); + return (-1); + } + + if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, + "socket_listen_update") < 0) { + close(sock); + return (-1); + } + + if (backlog_retrieved != listen_backlog_assertion) { + warnx("%s: %s: socket_listen_update: initial backlog is %d " + "not %d", testclass, test, backlog_retrieved, + listen_backlog_assertion); + close(sock); + return (-1); + } + + if (listen(sock, update_backlog) < 0) { + warn("%s: %s: socket_listen_update: update listen(, %d)", + testclass, test, update_backlog); + close(sock); + return (-1); + } + + if (socket_get_backlog(sock, &backlog_retrieved, testclass, test, + "socket_listen_update") < 0) { + close(sock); + return (-1); + } + + if (backlog_retrieved != update_backlog_assertion) { + warnx("%s: %s: socket_listen_update: updated backlog is %d " + "not %d", testclass, test, backlog_retrieved, + update_backlog_assertion); + close(sock); + return (-1); + } + + *sockp = sock; + return (0); +} + +/* + * This test tests using listen() to update the queue depth after a socket + * has already been marked as listening. We test several cases: setting the + * socket < 0, 0, 1, somaxconn, and somaxconn + 1. + */ +static void +test_listen_update(void) +{ + int sock; + + /* + * Set to 5, update to -1, which should give somaxconn. + */ + if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, -1, 5, somaxconn, + &sock, "PF_INET", "SOCK_STREAM", "test_listen_update", + "update_5,-1") < 0) + exit(-1); + close(sock); + + /* + * Set to 5, update to 0, which should give 0. + */ + if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, 0, 5, 0, &sock, + "PF_INET", "SOCK_STREAM", "test_listen_update", "update_5,0") + < 0) + exit(-1); + close(sock); + + /* + * Set to 5, update to 1, which should give 1. + */ + if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, 1, 5, 1, &sock, + "PF_INET", "SOCK_STREAM", "test_listen_update", "update_5,1") + < 0) + exit(-1); + close(sock); + + /* + * Set to 5, update to somaxconn, which should give somaxconn. + */ + if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, somaxconn, 5, + somaxconn, &sock, "PF_INET", "SOCK_STREAM", "test_listen_update", + "update_5,somaxconn") < 0) + exit(-1); + close(sock); + + /* + * Set to 5, update to somaxconn+1, which should give somaxconn. + */ + if (socket_listen_update(PF_INET, SOCK_STREAM, 0, 5, somaxconn+1, 5, + somaxconn, &sock, "PF_INET", "SOCK_STREAM", "test_listen_update", + "update_5,somaxconn+1") < 0) + exit(-1); + close(sock); +} + +/* + * SO_LISTENQLIMIT is a read-only socket option, so make sure we get an error + * if we try to write it. + */ +static void +test_set_qlimit(void) +{ + int i, ret, sock; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) + err(-1, "test_set_qlimit: socket(PF_INET, SOCK_STREAM)"); + + i = 0; + ret = setsockopt(sock, SOL_SOCKET, SO_LISTENQLIMIT, &i, sizeof(i)); + if (ret < 0 && errno != ENOPROTOOPT) { + warn("test_set_qlimit: setsockopt(SOL_SOCKET, " + "SO_LISTENQLIMIT, 0): unexpected error"); + close(sock); + } + + if (ret == 0) { + warnx("test_set_qlimit: setsockopt(SOL_SOCKET, " + "SO_LISTENQLIMIT, 0) succeeded"); + close(sock); + exit(-1); + } + close(sock); +} + +int +main(void) +{ + size_t len; + + len = sizeof(somaxconn); + if (sysctlbyname("kern.ipc.somaxconn", &somaxconn, &len, NULL, 0) + < 0) + err(-1, "sysctlbyname(kern.ipc.somaxconn)"); + + test_defaults(); + test_listen_update(); + test_set_qlimit(); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/listen_backlog_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/listenclose_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/listenclose_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/listenclose_test.c (revision 281516) @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2004-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 + +/* + * The listenclose regression test is designed to catch kernel bugs that may + * trigger as a result of performing a close on a listen() socket with as-yet + * unaccepted connections in its queues. This results in the connections + * being aborted, which is a not-often-followed code path. To do this, we + * create a local TCP socket, build a non-blocking connection to it, and then + * close the accept socket. The connection must be non-blocking or the + * program will block and as such connect() will not return as accept() is + * never called. + */ + +int +main(void) +{ + int listen_sock, connect_sock; + struct sockaddr_in sin; + socklen_t len; + u_short port; + int arg; + + listen_sock = socket(PF_INET, SOCK_STREAM, 0); + if (listen_sock == -1) + errx(-1, + "socket(PF_INET, SOCK_STREAM, 0) for listen socket: %s", + strerror(errno)); + + + 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 = 0; + + if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + errx(-1, "bind(%s, %d) for listen socket: %s", + inet_ntoa(sin.sin_addr), 0, strerror(errno)); + + len = sizeof(sin); + if (getsockname(listen_sock, (struct sockaddr *)&sin, &len) < 0) + errx(-1, "getsockname() for listen socket: %s", + strerror(errno)); + port = sin.sin_port; + + if (listen(listen_sock, -1) < 0) + errx(-1, "listen() for listen socket: %s", strerror(errno)); + + connect_sock = socket(PF_INET, SOCK_STREAM, 0); + if (connect_sock == -1) + errx(-1, "socket(PF_INET, SOCK_STREAM, 0) for connect " + "socket: %s", strerror(errno)); + + arg = O_NONBLOCK; + if (fcntl(connect_sock, F_SETFL, &arg) < 0) + errx(-1, "socket(PF_INET, SOCK_STREAM, 0) for connect socket" + ": %s", strerror(errno)); + + 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 = port; + + if (connect(connect_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + errx(-1, "connect() for connect socket: %s", strerror(errno)); + close(connect_sock); + close(listen_sock); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/listenclose_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/pr_atomic_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/pr_atomic_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/pr_atomic_test.c (revision 281516) @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2006 Bruce M. Simpson + * 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$ + */ + +/* + * Regression test for uiomove in kernel; specifically for PR kern/38495. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static char socket_path[] = "tmp.XXXXXX"; + +static jmp_buf myjmpbuf; + +static void handle_sigalrm(int signo __unused) +{ + longjmp(myjmpbuf, 1); +} + +int +main(void) +{ + struct sockaddr_un un; + pid_t pid; + int s; + + if (mkstemp(socket_path) == -1) + err(1, "mkstemp"); + s = socket(PF_LOCAL, SOCK_DGRAM, 0); + if (s == -1) + errx(-1, "socket"); + memset(&un, 0, sizeof(un)); + un.sun_family = AF_LOCAL; + unlink(socket_path); + strcpy(un.sun_path, socket_path); + if (bind(s, (struct sockaddr *)&un, sizeof(un)) == -1) + errx(-1, "bind"); + pid = fork(); + if (pid == -1) + errx(-1, "fork"); + if (pid == 0) { + int conn; + char buf[] = "AAAAAAAAA"; + + close(s); + conn = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (conn == -1) + errx(-1,"socket"); + if (sendto(conn, buf, sizeof(buf), 0, (struct sockaddr *)&un, + sizeof(un)) != sizeof(buf)) + errx(-1,"sendto"); + close(conn); + _exit(0); + } + + sleep(5); + + /* Make sure the data is there when we try to receive it. */ + if (recvfrom(s, (void *)-1, 1, 0, NULL, NULL) != -1) + errx(-1,"recvfrom succeeded when failure expected"); + + (void)signal(SIGALRM, handle_sigalrm); + if (setjmp(myjmpbuf) == 0) { + /* + * This recvfrom will panic an unpatched system, and block + * a patched one. + */ + alarm(5); + (void)recvfrom(s, (void *)-1, 1, 0, NULL, NULL); + } + + /* We should reach here via longjmp() and all should be well. */ + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/pr_atomic_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/reconnect_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/reconnect_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/reconnect_test.c (revision 281516) @@ -0,0 +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() +{ + 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); +} Property changes on: user/ngie/more-tests/tests/sys/socket/reconnect_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/rtsocket_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/rtsocket_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/rtsocket_test.c (revision 281516) @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2006 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$ + */ + +/* + * Simple routing socket regression test: create and destroy a raw routing + * socket, and make sure that dgram and stream don't work, socketpair, etc. + */ + +#include +#include + +#include + +#include +#include +#include + +int +main(void) +{ + int sock, socks[2]; + + sock = socket(PF_ROUTE, SOCK_STREAM, 0); + if (sock >= 0) { + close(sock); + errx(-1, "socket(PF_ROUTE, SOCK_STREAM, 0) returned %d", + sock); + } + + if (errno != EPROTONOSUPPORT) + err(-1, "socket(PF_ROUTE, SOCK_STREAM, 0)"); + + sock = socket(PF_ROUTE, SOCK_DGRAM, 0); + if (sock >= 0) { + close(sock); + errx(-1, "socket(PF_ROUTE, SOCK_DGRAM, 0) returned %d", + sock); + } + + if (errno != EPROTONOSUPPORT) + err(-1, "socket(PF_ROUTE, SOCK_DGRAM, 0)"); + + sock = socket(PF_ROUTE, SOCK_RAW, 0); + if (sock < 0) + err(-1, "socket(PF_ROUTE, SOCK_RAW, 0)"); + close(sock); + + if (socketpair(PF_ROUTE, SOCK_STREAM, 0, socks) == 0) { + close(socks[0]); + close(socks[1]); + errx(-1, + "socketpair(PF_ROUTE, SOCK_STREAM, 0, socks) success"); + } + + if (errno != EPROTONOSUPPORT) + err(-1, "socketpair(PF_ROUTE, SOCK_STREAM, 0, socks)"); + + if (socketpair(PF_ROUTE, SOCK_DGRAM, 0, socks) == 0) { + close(socks[0]); + close(socks[1]); + errx(-1, + "socketpair(PF_ROUTE, SOCK_DGRAM, 0, socks) success"); + } + + if (errno != EPROTONOSUPPORT) + err(-1, "socketpair(PF_ROUTE, SOCK_DGRAM, 0, socks)"); + + if (socketpair(PF_ROUTE, SOCK_RAW, 0, socks) == 0) { + close(socks[0]); + close(socks[1]); + errx(-1, + "socketpair(PF_ROUTE, SOCK_STREAM, 0, socks) success"); + } + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/rtsocket_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/sblock_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/sblock_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/sblock_test.c (revision 281516) @@ -0,0 +1,207 @@ +/*- + * 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$ + */ + +/* + * Sockets serialize I/O in each direction in order to avoid interlacing of + * I/O by multiple processes or threcvs recving or sending the socket. This + * is done using some form of kernel lock (varies by kernel version), called + * "sblock" in FreeBSD. However, to avoid unkillable processes waiting on + * I/O that may be entirely controlled by a remote network endpoint, that + * lock acquisition must be interruptible. + * + * To test this, set up a local domain stream socket pair and a set of three + * processes. Two processes block in recv(), the first on sbwait (wait for + * I/O), and the second on the sblock waiting for the first to finish. A + * third process is responsible for signalling the second process, then + * writing to the socket. Depending on the error returned in the second + * process, we can tell whether the sblock wait was interrupted, or if + * instead the process only woke up when the write was performed. + */ + +#include + +#include +#include +#include +#include +#include +#include + +static int interrupted; +static void +signal_handler(int signum __unused) +{ + + interrupted++; +} + +/* + * Process that will perform a blocking recv on a UNIX domain socket. This + * should return one byte of data. + */ +static void +blocking_recver(int fd) +{ + ssize_t len; + char ch; + + len = recv(fd, &ch, sizeof(ch), 0); + if (len < 0) + err(-1, "FAIL: blocking_recver: recv"); + if (len == 0) + errx(-1, "FAIL: blocking_recver: recv: eof"); + if (len != 1) + errx(-1, "FAIL: blocking_recver: recv: %zd bytes", len); + if (interrupted) + errx(-1, "FAIL: blocking_recver: interrupted wrong pid"); +} + +/* + * Process that will perform a locking recv on a UNIX domain socket. + * + * This is where we figure out if the test worked or not. If it has failed, + * then recv() will return EOF, as the close() arrives before the signal, + * meaning that the wait for the sblock was not interrupted; if it has + * succeeded, we get EINTR as the signal interrupts the lock request. + */ +static void +locking_recver(int fd) +{ + ssize_t len; + char ch; + + if (sleep(1) != 0) + err(-1, "FAIL: locking_recver: sleep"); + len = recv(fd, &ch, sizeof(ch), 0); + if (len < 0 && errno != EINTR) + err(-1, "FAIL: locking_recver: recv"); + if (len < 0 && errno == EINTR) { + fprintf(stderr, "PASS\n"); + exit(0); + } + if (len == 0) + errx(-1, "FAIL: locking_recver: recv: eof"); + if (!interrupted) + errx(-1, "FAIL: locking_recver: not interrupted"); +} + +static void +signaller(pid_t locking_recver_pid, int fd) +{ + ssize_t len; + char ch; + + if (sleep(2) != 0) { + warn("signaller sleep(2)"); + return; + } + if (kill(locking_recver_pid, SIGHUP) < 0) { + warn("signaller kill(%d)", locking_recver_pid); + return; + } + if (sleep(1) != 0) { + warn("signaller sleep(1)"); + return; + } + len = send(fd, &ch, sizeof(ch), 0); + if (len < 0) { + warn("signaller send"); + return; + } + if (len != sizeof(ch)) { + warnx("signaller send ret %zd", len); + return; + } + if (close(fd) < 0) { + warn("signaller close"); + return; + } + if (sleep(1) != 0) { + warn("signaller sleep(1)"); + return; + } +} + +int +main(void) +{ + int error, fds[2], recver_fd, sender_fd; + pid_t blocking_recver_pid; + pid_t locking_recver_pid; + struct sigaction sa; + + if (sigaction(SIGHUP, NULL, &sa) < 0) + err(-1, "FAIL: sigaction(SIGHUP, NULL, &sa)"); + + sa.sa_handler = signal_handler; + if (sa.sa_flags & SA_RESTART) + printf("SIGHUP restartable by default (cleared)\n"); + sa.sa_flags &= ~SA_RESTART; + + if (sigaction(SIGHUP, &sa, NULL) < 0) + err(-1, "FAIL: sigaction(SIGHUP, &sa, NULL)"); + +#if 0 + if (signal(SIGHUP, signal_handler) == SIG_ERR) + err(-1, "FAIL: signal(SIGHUP)"); +#endif + + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) + err(-1, "FAIL: socketpair(PF_LOCAL, SOGK_STREAM, 0)"); + + sender_fd = fds[0]; + recver_fd = fds[1]; + + blocking_recver_pid = fork(); + if (blocking_recver_pid < 0) + err(-1, "FAIL: fork"); + if (blocking_recver_pid == 0) { + close(sender_fd); + blocking_recver(recver_fd); + exit(0); + } + + locking_recver_pid = fork(); + if (locking_recver_pid < 0) { + error = errno; + kill(blocking_recver_pid, SIGKILL); + errno = error; + err(-1, "FAIL: fork"); + } + if (locking_recver_pid == 0) { + close(sender_fd); + locking_recver(recver_fd); + exit(0); + } + + signaller(locking_recver_pid, sender_fd); + + kill(blocking_recver_pid, SIGKILL); + kill(locking_recver_pid, SIGKILL); + exit(0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/sblock_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/sendfile_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/sendfile_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/sendfile_test.c (revision 281516) @@ -0,0 +1,486 @@ +/*- + * Copyright (c) 2006 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 +#include + +/* + * Simple regression test for sendfile. Creates a file sized at four pages + * and then proceeds to send it over a series of sockets, exercising a number + * of cases and performing limited validation. + */ + +#define FAIL(msg) {printf("# %s\n", msg); \ + return (-1);} + +#define FAIL_ERR(msg) {printf("# %s: %s\n", msg, strerror(errno)); \ + return (-1);} + +#define TEST_PORT 5678 +#define TEST_MAGIC 0x4440f7bb +#define TEST_PAGES 4 +#define TEST_SECONDS 30 + +struct test_header { + uint32_t th_magic; + uint32_t th_header_length; + uint32_t th_offset; + uint32_t th_length; + char th_md5[33]; +}; + +struct sendfile_test { + uint32_t hdr_length; + uint32_t offset; + uint32_t length; + uint32_t file_size; +}; + +static int file_fd; +static char path[PATH_MAX]; +static int listen_socket; +static int accept_socket; + +static int test_th(struct test_header *th, uint32_t *header_length, + uint32_t *offset, uint32_t *length); +static void signal_alarm(int signum); +static void setup_alarm(int seconds); +static void cancel_alarm(void); +static int receive_test(void); +static void run_child(void); +static int new_test_socket(int *connect_socket); +static void init_th(struct test_header *th, uint32_t header_length, + uint32_t offset, uint32_t length); +static int send_test(int connect_socket, struct sendfile_test); +static int write_test_file(size_t file_size); +static void run_parent(void); +static void cleanup(void); + + +static int +test_th(struct test_header *th, uint32_t *header_length, uint32_t *offset, + uint32_t *length) +{ + + if (th->th_magic != htonl(TEST_MAGIC)) + FAIL("magic number not found in header") + *header_length = ntohl(th->th_header_length); + *offset = ntohl(th->th_offset); + *length = ntohl(th->th_length); + return (0); +} + +static void +signal_alarm(int signum) +{ + (void)signum; + + printf("# test timeout\n"); + + if (accept_socket > 0) + close(accept_socket); + if (listen_socket > 0) + close(listen_socket); + + _exit(-1); +} + +static void +setup_alarm(int seconds) +{ + struct itimerval itv; + bzero(&itv, sizeof(itv)); + (void)seconds; + itv.it_value.tv_sec = seconds; + + signal(SIGALRM, signal_alarm); + setitimer(ITIMER_REAL, &itv, NULL); +} + +static void +cancel_alarm(void) +{ + struct itimerval itv; + bzero(&itv, sizeof(itv)); + setitimer(ITIMER_REAL, &itv, NULL); +} + +static int +receive_test(void) +{ + uint32_t header_length, offset, length, counter; + struct test_header th; + ssize_t len; + char buf[10240]; + MD5_CTX md5ctx; + char *rxmd5; + + len = read(accept_socket, &th, sizeof(th)); + if (len < 0 || (size_t)len < sizeof(th)) + FAIL_ERR("read") + + if (test_th(&th, &header_length, &offset, &length) != 0) + return (-1); + + MD5Init(&md5ctx); + + counter = 0; + while (1) { + len = read(accept_socket, buf, sizeof(buf)); + if (len < 0 || len == 0) + break; + counter += len; + MD5Update(&md5ctx, buf, len); + } + + rxmd5 = MD5End(&md5ctx, NULL); + + if ((counter != header_length+length) || + memcmp(th.th_md5, rxmd5, 33) != 0) + FAIL("receive length mismatch") + + free(rxmd5); + return (0); +} + +static void +run_child(void) +{ + struct sockaddr_in sin; + int rc = 0; + + listen_socket = socket(PF_INET, SOCK_STREAM, 0); + if (listen_socket < 0) { + printf("# socket: %s\n", strerror(errno)); + rc = -1; + } + + if (!rc) { + 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(TEST_PORT); + + if (bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + printf("# bind: %s\n", strerror(errno)); + rc = -1; + } + } + + if (!rc && listen(listen_socket, -1) < 0) { + printf("# listen: %s\n", strerror(errno)); + rc = -1; + } + + if (!rc) { + accept_socket = accept(listen_socket, NULL, NULL); + setup_alarm(TEST_SECONDS); + if (receive_test() != 0) + rc = -1; + } + + cancel_alarm(); + if (accept_socket > 0) + close(accept_socket); + if (listen_socket > 0) + close(listen_socket); + + _exit(rc); +} + +static int +new_test_socket(int *connect_socket) +{ + struct sockaddr_in sin; + int rc = 0; + + *connect_socket = socket(PF_INET, SOCK_STREAM, 0); + if (*connect_socket < 0) + FAIL_ERR("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(TEST_PORT); + + if (connect(*connect_socket, (struct sockaddr *)&sin, sizeof(sin)) < 0) + FAIL_ERR("connect") + + return (rc); +} + +static void +init_th(struct test_header *th, uint32_t header_length, uint32_t offset, + uint32_t length) +{ + bzero(th, sizeof(*th)); + th->th_magic = htonl(TEST_MAGIC); + th->th_header_length = htonl(header_length); + th->th_offset = htonl(offset); + th->th_length = htonl(length); + + MD5FileChunk(path, th->th_md5, offset, length); +} + +static int +send_test(int connect_socket, struct sendfile_test test) +{ + struct test_header th; + struct sf_hdtr hdtr, *hdtrp; + struct iovec headers; + char *header; + ssize_t len; + int length; + off_t off; + + len = lseek(file_fd, 0, SEEK_SET); + if (len != 0) + FAIL_ERR("lseek") + + struct stat st; + if (fstat(file_fd, &st) < 0) + FAIL_ERR("fstat") + length = st.st_size - test.offset; + if (test.length > 0 && test.length < (uint32_t)length) + length = test.length; + + init_th(&th, test.hdr_length, test.offset, length); + + len = write(connect_socket, &th, sizeof(th)); + if (len != sizeof(th)) + return (-1); + + if (test.hdr_length != 0) { + header = malloc(test.hdr_length); + if (header == NULL) + FAIL_ERR("malloc") + + hdtrp = &hdtr; + bzero(&headers, sizeof(headers)); + headers.iov_base = header; + headers.iov_len = test.hdr_length; + bzero(&hdtr, sizeof(hdtr)); + hdtr.headers = &headers; + hdtr.hdr_cnt = 1; + hdtr.trailers = NULL; + hdtr.trl_cnt = 0; + } else { + hdtrp = NULL; + header = NULL; + } + + if (sendfile(file_fd, connect_socket, test.offset, test.length, + hdtrp, &off, 0) < 0) { + if (header != NULL) + free(header); + FAIL_ERR("sendfile") + } + + if (length == 0) { + struct stat sb; + + if (fstat(file_fd, &sb) == 0) + length = sb.st_size - test.offset; + } + + if (header != NULL) + free(header); + + if (off != length) + FAIL("offset != length") + + return (0); +} + +static int +write_test_file(size_t file_size) +{ + char *page_buffer; + ssize_t len; + static size_t current_file_size = 0; + + if (file_size == current_file_size) + return (0); + else if (file_size < current_file_size) { + if (ftruncate(file_fd, file_size) != 0) + FAIL_ERR("ftruncate"); + current_file_size = file_size; + return (0); + } + + page_buffer = malloc(file_size); + if (page_buffer == NULL) + FAIL_ERR("malloc") + bzero(page_buffer, file_size); + + len = write(file_fd, page_buffer, file_size); + if (len < 0) + FAIL_ERR("write") + + len = lseek(file_fd, 0, SEEK_SET); + if (len < 0) + FAIL_ERR("lseek") + if (len != 0) + FAIL("len != 0") + + free(page_buffer); + current_file_size = file_size; + return (0); +} + +static void +run_parent(void) +{ + int connect_socket; + int status; + int test_num; + int test_count; + int pid; + size_t desired_file_size = 0; + + const int pagesize = getpagesize(); + + struct sendfile_test tests[] = { + { .hdr_length = 0, .offset = 0, .length = 1 }, + { .hdr_length = 0, .offset = 0, .length = pagesize }, + { .hdr_length = 0, .offset = 1, .length = 1 }, + { .hdr_length = 0, .offset = 1, .length = pagesize }, + { .hdr_length = 0, .offset = pagesize, .length = pagesize }, + { .hdr_length = 0, .offset = 0, .length = 2*pagesize }, + { .hdr_length = 0, .offset = 0, .length = 0 }, + { .hdr_length = 0, .offset = pagesize, .length = 0 }, + { .hdr_length = 0, .offset = 2*pagesize, .length = 0 }, + { .hdr_length = 0, .offset = TEST_PAGES*pagesize, .length = 0 }, + { .hdr_length = 0, .offset = 0, .length = pagesize, + .file_size = 1 } + }; + + test_count = sizeof(tests) / sizeof(tests[0]); + printf("1..%d\n", test_count); + + for (test_num = 1; test_num <= test_count; test_num++) { + + desired_file_size = tests[test_num - 1].file_size; + if (desired_file_size == 0) + desired_file_size = TEST_PAGES * pagesize; + if (write_test_file(desired_file_size) != 0) { + printf("not ok %d\n", test_num); + continue; + } + + pid = fork(); + if (pid == -1) { + printf("not ok %d\n", test_num); + continue; + } + + if (pid == 0) + run_child(); + + usleep(250000); + + if (new_test_socket(&connect_socket) != 0) { + printf("not ok %d\n", test_num); + kill(pid, SIGALRM); + close(connect_socket); + continue; + } + + if (send_test(connect_socket, tests[test_num-1]) != 0) { + printf("not ok %d\n", test_num); + kill(pid, SIGALRM); + close(connect_socket); + continue; + } + + close(connect_socket); + if (waitpid(pid, &status, 0) == pid) { + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + printf("%s %d\n", "ok", test_num); + else + printf("%s %d\n", "not ok", test_num); + } + else { + printf("not ok %d\n", test_num); + } + } +} + +static void +cleanup(void) +{ + + unlink(path); +} + +int +main(int argc, char *argv[]) +{ + int pagesize; + + path[0] = '\0'; + + pagesize = getpagesize(); + + if (argc == 1) { + snprintf(path, sizeof(path), "sendfile.XXXXXXXXXXXX"); + file_fd = mkstemp(path); + if (file_fd == -1) + FAIL_ERR("mkstemp"); + } else if (argc == 2) { + (void)strlcpy(path, argv[1], sizeof(path)); + file_fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600); + if (file_fd == -1) + FAIL_ERR("open"); + } else { + FAIL("usage: sendfile [path]"); + } + + atexit(cleanup); + + run_parent(); + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/sendfile_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/shutdown_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/shutdown_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/shutdown_test.c (revision 281516) @@ -0,0 +1,110 @@ +/*- + * Copyright (C) 2005 The FreeBSD Project. 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 + +int +main(void) +{ + struct sockaddr_in sock; + socklen_t len; + int listen_sock, connect_sock; + u_short port; + + listen_sock = -1; + + /* Shutdown(2) on an invalid file descriptor has to return EBADF. */ + if ((shutdown(listen_sock, SHUT_RDWR) != -1) && (errno != EBADF)) + errx(-1, "shutdown() for invalid file descriptor does not " + "return EBADF"); + + listen_sock = socket(PF_INET, SOCK_STREAM, 0); + if (listen_sock == -1) + errx(-1, + "socket(PF_INET, SOCK_STREAM, 0) for listen socket: %s", + strerror(errno)); + + bzero(&sock, sizeof(sock)); + sock.sin_len = sizeof(sock); + sock.sin_family = AF_INET; + sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sock.sin_port = 0; + + if (bind(listen_sock, (struct sockaddr *)&sock, sizeof(sock)) < 0) + errx(-1, "bind(%s, %d) for listen socket: %s", + inet_ntoa(sock.sin_addr), sock.sin_port, strerror(errno)); + + len = sizeof(sock); + if (getsockname(listen_sock, (struct sockaddr *)&sock, &len) < 0) + errx(-1, "getsockname() for listen socket: %s", + strerror(errno)); + port = sock.sin_port; + + if (listen(listen_sock, -1) < 0) + errx(-1, "listen() for listen socket: %s", strerror(errno)); + + connect_sock = socket(PF_INET, SOCK_STREAM, 0); + if (connect_sock == -1) + errx(-1, "socket(PF_INET, SOCK_STREAM, 0) for connect " + "socket: %s", strerror(errno)); + + bzero(&sock, sizeof(sock)); + sock.sin_len = sizeof(sock); + sock.sin_family = AF_INET; + sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sock.sin_port = port; + + if (connect(connect_sock, (struct sockaddr *)&sock, sizeof(sock)) < 0) + errx(-1, "connect() for connect socket: %s", strerror(errno)); + /* Try to pass an invalid flags. */ + if ((shutdown(connect_sock, SHUT_RD - 1) != -1) && (errno != EINVAL)) + errx(-1, "shutdown(SHUT_RD - 1) does not return EINVAL"); + if ((shutdown(connect_sock, SHUT_RDWR + 1) != -1) && (errno != EINVAL)) + errx(-1, "shutdown(SHUT_RDWR + 1) does not return EINVAL"); + + if (shutdown(connect_sock, SHUT_RD) < 0) + errx(-1, "shutdown(SHUT_RD) for connect socket: %s", + strerror(errno)); + if (shutdown(connect_sock, SHUT_WR) < 0) + errx(-1, "shutdown(SHUT_WR) for connect socket: %s", + strerror(errno)); + + close(connect_sock); + close(listen_sock); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/shutdown_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/sigpipe_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/sigpipe_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/sigpipe_test.c (revision 281516) @@ -0,0 +1,322 @@ +/*- + * 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 + +/* + * 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) +{ + + 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 != 2) + usage(); + + port = strtol(argv[1], &dummy, 10); + if (port < 0 || port > 65535 || *dummy != '\0') + 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); +} Property changes on: user/ngie/more-tests/tests/sys/socket/sigpipe_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/so_setfib_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/so_setfib_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/so_setfib_test.c (revision 281516) @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 2012 Cisco Systems, Inc. + * All rights reserved. + * + * This software was developed by Bjoern Zeeb under contract to + * Cisco Systems, Inc.. + * + * 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$ + */ + +/* + * Regression test on SO_SETFIB setsockopt(2). + * + * Check that the expected domain(9) families all handle the socket option + * correctly and do proper bounds checks. + * + * Test plan: + * 1. Get system wide number of FIBs from sysctl and convert to index (-= 1). + * 2. For each protocol family (INET, INET6, ROUTE and LOCAL) open socketes of + * type (STREAM, DGRAM and RAW) as supported. + * 3. Do a sequence of -2, -1, 0, .. n, n+1, n+2 SO_SETFIB sockopt calls, + * expecting the first two and last two to fail (valid 0 ... n). + * 4. Try 3 random numbers. Calculate result based on valid range. + * 5. Repeat for next domain family and type from (2) on. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static struct t_dom { + int domain; + const char *name; +} t_dom[] = { +#ifdef INET6 + { .domain = PF_INET6, .name = "PF_INET6" }, +#endif +#ifdef INET + { .domain = PF_INET, .name = "PF_INET" }, +#endif + { .domain = PF_ROUTE, .name = "PF_ROUTE" }, + { .domain = PF_LOCAL, .name = "PF_LOCAL" }, +}; + +static struct t_type { + int type; + const char *name; +} t_type[] = { + { .type = SOCK_STREAM, .name = "SOCK_STREAM" }, + { .type = SOCK_DGRAM, .name = "SOCK_DGRAM" }, + { .type = SOCK_RAW, .name = "SOCK_RAW" }, +}; + +/* + * Number of FIBs as read from net.fibs sysctl - 1. Initialize to clear out of + * bounds value to not accidentally run on a limited range. + */ +static int rt_numfibs = -42; + +/* Number of test case. */ +static int testno = 1; + + +/* + * Try the setsockopt with given FIB number i on socket s. + * Handle result given on error and valid range and errno. + */ +static void +so_setfib(int s, int i, u_int dom, u_int type) +{ + int error; + + error = setsockopt(s, SOL_SOCKET, SO_SETFIB, &i, sizeof(i)); + /* For out of bounds we expect an error. */ + if (error == -1 && (i < 0 || i > rt_numfibs)) + printf("ok %d %s_%s_%d\n", testno, t_dom[dom].name, + t_type[type].name, i); + else if (error != -1 && (i < 0 || i > rt_numfibs)) + printf("not ok %d %s_%s_%d # setsockopt(%d, SOL_SOCKET, " + "SO_SETFIB, %d, ..) unexpectedly succeeded\n", testno, + t_dom[dom].name, t_type[type].name, i, s, i); + else if (error == 0) + printf("ok %d %s_%s_%d\n", testno, t_dom[dom].name, + t_type[type].name, i); + else if (errno != EINVAL) + printf("not ok %d %s_%s_%d # setsockopt(%d, SOL_SOCKET, " + "SO_SETFIB, %d, ..) unexpected error: %s\n", testno, + t_dom[dom].name, t_type[type].name, i, s, i, + strerror(errno)); + else + printf("not ok %d %s_%s_%d\n", testno, t_dom[dom].name, + t_type[type].name, i); + + /* Test run done, next please. */ + testno++; +} + +/* + * Main test. Open socket given domain family and type. For each FIB, out of + * bounds FIB numbers and 3 random FIB numbers set the socket option. + */ +static void +t(u_int dom, u_int type) +{ + int i, s; + + /* PF_ROUTE only supports RAW socket types, while PF_LOCAL does not. */ + if (t_dom[dom].domain == PF_ROUTE && t_type[type].type != SOCK_RAW) + return; + if (t_dom[dom].domain == PF_LOCAL && t_type[type].type == SOCK_RAW) + return; + + /* Open socket for given combination. */ + s = socket(t_dom[dom].domain, t_type[type].type, 0); + if (s == -1) { + printf("not ok %d %s_%s # socket(): %s\n", testno, + t_dom[dom].name, t_type[type].name, strerror(errno)); + testno++; + return; + } + + /* Test FIBs -2, -1, 0, .. n, n + 1, n + 2. */ + for (i = -2; i <= (rt_numfibs + 2); i++) + so_setfib(s, i, dom, type); + + /* Test 3 random FIB numbers. */ + for (i = 0; i < 3; i++) + so_setfib(s, (int)random(), dom, type); + + /* Close socket. */ + close(s); +} + +/* + * Returns 0 if no program error, 1 on sysctlbyname error. + * Test results are communicated by printf("[not ]ok .."). + */ +int +main(int argc __unused, char *argv[] __unused) +{ + u_int i, j; + size_t s; + + if (geteuid() != 0) { + printf("1..0 # SKIP: must be root"); + return (0); + } + + /* Initalize randomness. */ + srandomdev(); + + /* Get number of FIBs supported by kernel. */ + s = sizeof(rt_numfibs); + if (sysctlbyname("net.fibs", &rt_numfibs, &s, NULL, 0) == -1) + err(1, "sysctlbyname(net.fibs, ..)"); + + printf("1..%lu\n", + (nitems(t_dom) - 1) * nitems(t_type) * (2 + rt_numfibs + 2 + 3)); + + /* Adjust from number to index. */ + rt_numfibs -= 1; + + /* Run tests. */ + for (i = 0; i < sizeof(t_dom) / sizeof(struct t_dom); i++) + for (j = 0; j < sizeof(t_type) / sizeof(struct t_type); j++) + t(i, j); + + return (0); +} + +/* end */ Property changes on: user/ngie/more-tests/tests/sys/socket/so_setfib_test.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/socketpair_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/socketpair_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/socketpair_test.c (revision 281516) @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 2004 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 + +/* + * Open, then close a set of UNIX domain socket pairs for datagram and + * stream. + * + * Confirm that we can't open INET datagram or stream socket pairs. + * + * More tests should be added, including confirming that sending on either + * endpoint results in data at the other, that the right kind of socket was + * created (stream vs. datagram), and that message boundaries fall in the + * right places. + */ +int +main(void) +{ + int fd1, fd2, fd3; + int sv[2]; + + /* + * UNIX domain socket pair, datagram. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) != 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM): %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (close(sv[0]) != 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM) close 0: %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (close(sv[1]) != 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM) close 1: %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + + /* + * UNIX domain socket pair, stream. + */ + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) != 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_STREAM): %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (close(sv[0]) != 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_STREAM) close 0: %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (close(sv[1]) != 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_STREAM) close 1: " + "%s\n", strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + + /* + * Confirm that PF_INET datagram socket pair creation fails. + */ + if (socketpair(PF_INET, SOCK_DGRAM, 0, sv) == 0) { + fprintf(stderr, "socketpair(PF_INET, SOCK_DGRAM): opened\n"); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (errno != EOPNOTSUPP) { + fprintf(stderr, "socketpair(PF_INET, SOCK_DGRAM): %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + } + + /* + * Confirm that PF_INET stream socket pair creation fails. + */ + if (socketpair(PF_INET, SOCK_STREAM, 0, sv) == 0) { + fprintf(stderr, "socketpair(PF_INET, SOCK_STREAM): opened\n"); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (errno != EOPNOTSUPP) { + fprintf(stderr, "socketpair(PF_INET, SOCK_STREAM): %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + } + + /* + * Check for sequential fd allocation, and give up early if not. + */ + fd1 = dup(STDIN_FILENO); + fd2 = dup(STDIN_FILENO); + if (fd2 != fd1 + 1) { + fprintf(stderr, "Non-sequential fd allocation\n"); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + + /* Allocate a socketpair using a bad destination address. */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, NULL) == 0) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM, NULL): opened\n"); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + if (errno != EFAULT) { + fprintf(stderr, "socketpair(PF_UNIX, SOCK_DGRAM, NULL): %s\n", + strerror(errno)); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + + /* Allocate a file descriptor and make sure it's fd2+1. */ + fd3 = dup(STDIN_FILENO); + if (fd3 != fd2 + 1) { + fprintf(stderr, "socketpair(..., NULL) allocated descriptors\n"); + fprintf(stderr, "FAIL\n"); + exit(-1); + } + + fprintf(stderr, "PASS\n"); + exit(0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/socketpair_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_bindconnect_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_bindconnect_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_bindconnect_test.c (revision 281516) @@ -0,0 +1,318 @@ +/*- + * 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 + +/* + * Simple regression test to exercise some error cases relating to the use of + * bind() and connect() on UNIX domain sockets. In particular, make sure + * that when two sockets rendezvous using the file system name space, they + * get the expected success/failure cases. + * + * TODO: + * - Check that the resulting file mode/owner are right. + * - Do the same tests with UNIX domain sockets. + * - Check the results of getsockaddr() and getpeeraddr(). + */ + +#define SOCK_NAME_ONE "socket.1" +#define SOCK_NAME_TWO "socket.2" + +#define UNWIND_MAX 1024 + +static int unwind_len; +static struct unwind { + char u_path[PATH_MAX]; +} unwind_list[UNWIND_MAX]; + +static void +push_path(const char *path) +{ + + if (unwind_len >= UNWIND_MAX) + err(-1, "push_path: one path too many (%s)", path); + + strlcpy(unwind_list[unwind_len].u_path, path, PATH_MAX); + unwind_len++; +} + +static void +unwind(void) +{ + int i; + + for (i = unwind_len - 1; i >= 0; i--) { + unlink(unwind_list[i].u_path); + rmdir(unwind_list[i].u_path); + } +} + +static int +bind_test(const char *directory_path) +{ + char socket_path[PATH_MAX]; + struct sockaddr_un sun; + int sock1, sock2; + + sock1 = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock1 < 0) { + warn("bind_test: socket(PF_UNIX, SOCK_STREAM, 0)"); + return (-1); + } + + if (snprintf(socket_path, sizeof(socket_path), "%s/%s", + directory_path, SOCK_NAME_ONE) >= PATH_MAX) { + warn("bind_test: snprintf(socket_path)"); + close(sock1); + return (-1); + } + + bzero(&sun, sizeof(sun)); + sun.sun_len = sizeof(sun); + sun.sun_family = AF_UNIX; + if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path) + >= (int)sizeof(sun.sun_path)) { + warn("bind_test: snprintf(sun.sun_path)"); + close(sock1); + return (-1); + } + + if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + warn("bind_test: bind(sun) #1"); + close(sock1); + return (-1); + } + + push_path(socket_path); + + /* + * Once a STREAM UNIX domain socket has been bound, it can't be + * rebound. Expected error is EINVAL. + */ + if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) == 0) { + warnx("bind_test: bind(sun) #2 succeeded"); + close(sock1); + return (-1); + } + if (errno != EINVAL) { + warn("bind_test: bind(sun) #2"); + close(sock1); + return (-1); + } + + sock2 = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock2 < 0) { + warn("bind_test: socket(PF_UNIX, SOCK_STREAM, 0)"); + close(sock1); + return (-1); + } + + /* + * Since a socket is already bound to the pathname, it can't be bound + * to a second socket. Expected error is EADDRINUSE. + */ + if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { + warnx("bind_test: bind(sun) #3 succeeded"); + close(sock1); + close(sock2); + return (-1); + } + if (errno != EADDRINUSE) { + warn("bind_test: bind(sun) #2"); + close(sock1); + close(sock2); + return (-1); + } + + close(sock1); + + /* + * The socket bound to the pathname has been closed, but the pathname + * can't be reused without first being unlinked. Expected error is + * EADDRINUSE. + */ + if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { + warnx("bind_test: bind(sun) #4 succeeded"); + close(sock2); + return (-1); + } + if (errno != EADDRINUSE) { + warn("bind_test: bind(sun) #4"); + close(sock2); + return (-1); + } + + unlink(socket_path); + + /* + * The pathname is now free, so the socket should be able to bind to + * it. + */ + if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + warn("bind_test: bind(sun) #5"); + close(sock2); + return (-1); + } + + close(sock2); + return (0); +} + +static int +connect_test(const char *directory_path) +{ + char socket_path[PATH_MAX]; + struct sockaddr_un sun; + int sock1, sock2; + + sock1 = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock1 < 0) { + warn("connect_test: socket(PF_UNIX, SOCK_STREAM, 0)"); + return (-1); + } + + if (snprintf(socket_path, sizeof(socket_path), "%s/%s", + directory_path, SOCK_NAME_TWO) >= PATH_MAX) { + warn("connect_test: snprintf(socket_path)"); + close(sock1); + return (-1); + } + + bzero(&sun, sizeof(sun)); + sun.sun_len = sizeof(sun); + sun.sun_family = AF_UNIX; + if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path) + >= (int)sizeof(sun.sun_path)) { + warn("connect_test: snprintf(sun.sun_path)"); + close(sock1); + return (-1); + } + + /* + * Try connecting to a path that doesn't yet exist. Should fail with + * ENOENT. + */ + if (connect(sock1, (struct sockaddr *)&sun, sizeof(sun)) == 0) { + warnx("connect_test: connect(sun) #1 succeeded"); + close(sock1); + return (-1); + } + if (errno != ENOENT) { + warn("connect_test: connect(sun) #1"); + close(sock1); + return (-1); + } + + if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + warn("connect_test: bind(sun) #1"); + close(sock1); + return (-1); + } + + if (listen(sock1, 3) < 0) { + warn("connect_test: listen(sock1)"); + close(sock1); + return (-1); + } + + push_path(socket_path); + + sock2 = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock2 < 0) { + warn("socket(PF_UNIX, SOCK_STREAM, 0)"); + close(sock1); + return (-1); + } + + /* + * Do a simple connect and make sure that works. + */ + if (connect(sock2, (struct sockaddr *)&sun, sizeof(sun)) < 0) { + warn("connect(sun) #2"); + close(sock1); + return (-1); + } + + close(sock2); + + close(sock1); + + sock2 = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock2 < 0) { + warn("socket(PF_UNIX, SOCK_STREAM, 0)"); + return (-1); + } + + /* + * Confirm that once the listen socket is closed, we get a + * connection refused (ECONNREFUSED) when attempting to connect to + * the pathname. + */ + if (connect(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { + warnx("connect(sun) #3 succeeded"); + close(sock2); + return (-1); + } + if (errno != ECONNREFUSED) { + warn("connect(sun) #3"); + close(sock2); + return (-1); + } + + close(sock2); + unlink(socket_path); + return (0); +} +int +main(void) +{ + char directory_path[PATH_MAX]; + int error; + + strlcpy(directory_path, "/tmp/unix_bind.XXXXXXX", PATH_MAX); + if (mkdtemp(directory_path) == NULL) + err(-1, "mkdtemp"); + push_path(directory_path); + + error = bind_test(directory_path); + + if (error == 0) + error = connect_test(directory_path); + + unwind(); + return (error); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_bindconnect_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_close_race_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_close_race_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_close_race_test.c (revision 281516) @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2010 Mikolaj Golub + * 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$ + */ + +/* + * This regression test attempts to trigger a race that occurs when both + * endpoints of a connected UNIX domain socket are closed at once. The two + * close paths may run concurrently leading to a call to sodisconnect() on an + * already-closed socket in kernel. Before it was fixed, this might lead to + * ENOTCONN being returned improperly from close(). + * + * This race is fairly timing-dependent, so it effectively requires SMP, and + * may not even trigger then. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char socket_path[] = "tmp.XXXXXXXX"; + +#define USLEEP 100 +#define LOOPS 100000 + +int +main(void) +{ + struct sockaddr_un servaddr; + int listenfd, connfd, pid; + u_int counter, ncpus; + size_t len; + + len = sizeof(ncpus); + if (sysctlbyname("kern.smp.cpus", &ncpus, &len, NULL, 0) < 0) + err(1, "kern.smp.cpus"); + if (len != sizeof(ncpus)) + errx(1, "kern.smp.cpus: invalid length"); + if (ncpus < 2) + warnx("SMP not present, test may be unable to trigger race"); + + if (mkstemp(socket_path) == -1) + err(1, "mkstemp failed"); + unlink(socket_path); + + /* + * Create a UNIX domain socket that the child will repeatedly + * accept() from, and that the parent will repeatedly connect() to. + */ + if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) + err(1, "parent: socket error"); + (void)unlink(socket_path); + bzero(&servaddr, sizeof(servaddr)); + servaddr.sun_family = AF_LOCAL; + strcpy(servaddr.sun_path, socket_path); + if (bind(listenfd, (struct sockaddr *) &servaddr, + sizeof(servaddr)) < 0) + err(1, "parent: bind error"); + if (listen(listenfd, 1024) < 0) + err(1, "parent: listen error"); + + pid = fork(); + if (pid == -1) + err(1, "fork()"); + if (pid != 0) { + /* + * In the parent, repeatedly connect and disconnect from the + * socket, attempting to induce the race. + */ + close(listenfd); + sleep(1); + bzero(&servaddr, sizeof(servaddr)); + servaddr.sun_family = AF_LOCAL; + strcpy(servaddr.sun_path, socket_path); + for (counter = 0; counter < LOOPS; counter++) { + if ((connfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { + (void)kill(pid, SIGTERM); + err(1, "parent: socket error"); + } + if (connect(connfd, (struct sockaddr *)&servaddr, + sizeof(servaddr)) < 0) { + (void)kill(pid, SIGTERM); + err(1, "parent: connect error"); + } + if (close(connfd) < 0) { + (void)kill(pid, SIGTERM); + err(1, "parent: close error"); + } + usleep(USLEEP); + } + (void)kill(pid, SIGTERM); + } else { + /* + * In the child, loop accepting and closing. We may pick up + * the race here so report errors from close(). + */ + for ( ; ; ) { + if ((connfd = accept(listenfd, + (struct sockaddr *)NULL, NULL)) < 0) + err(1, "child: accept error"); + if (close(connfd) < 0) + err(1, "child: close error"); + } + } + printf("OK\n"); + exit(0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_close_race_test.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_cmsg.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_cmsg.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_cmsg.c (revision 281516) @@ -0,0 +1,1969 @@ +/*- + * Copyright (c) 2005 Andrey Simonenko + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * There are tables with tests descriptions and pointers to test + * functions. Each t_*() function returns 0 if its test passed, + * -1 if its test failed, -2 if some system error occurred. + * If a test function returns -2, then a program exits. + * + * If a test function forks a client process, then it waits for its + * termination. If a return code of a client process is not equal + * to zero, or if a client process was terminated by a signal, then + * a test function returns -1 or -2 depending on exit status of + * a client process. + * + * Each function which can block, is run under TIMEOUT. If timeout + * occurs, then a test function returns -2 or a client process exits + * with a non-zero return code. + */ + +#ifndef LISTENQ +# define LISTENQ 1 +#endif + +#ifndef TIMEOUT +# define TIMEOUT 2 +#endif + +static int t_cmsgcred(void); +static int t_sockcred_1(void); +static int t_sockcred_2(void); +static int t_cmsgcred_sockcred(void); +static int t_timeval(void); +static int t_bintime(void); +static int t_cmsg_len(void); +static int t_peercred(void); + +struct test_func { + int (*func)(void); + const char *desc; +}; + +static const struct test_func test_stream_tbl[] = { + { + .func = NULL, + .desc = "All tests" + }, + { + .func = t_cmsgcred, + .desc = "Sending, receiving cmsgcred" + }, + { + .func = t_sockcred_1, + .desc = "Receiving sockcred (listening socket)" + }, + { + .func = t_sockcred_2, + .desc = "Receiving sockcred (accepted socket)" + }, + { + .func = t_cmsgcred_sockcred, + .desc = "Sending cmsgcred, receiving sockcred" + }, + { + .func = t_timeval, + .desc = "Sending, receiving timeval" + }, + { + .func = t_bintime, + .desc = "Sending, receiving bintime" + }, + { + .func = t_cmsg_len, + .desc = "Check cmsghdr.cmsg_len" + }, + { + .func = t_peercred, + .desc = "Check LOCAL_PEERCRED socket option" + } +}; + +#define TEST_STREAM_TBL_SIZE \ + (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0])) + +static const struct test_func test_dgram_tbl[] = { + { + .func = NULL, + .desc = "All tests" + }, + { + .func = t_cmsgcred, + .desc = "Sending, receiving cmsgcred" + }, + { + .func = t_sockcred_2, + .desc = "Receiving sockcred" + }, + { + .func = t_cmsgcred_sockcred, + .desc = "Sending cmsgcred, receiving sockcred" + }, + { + .func = t_timeval, + .desc = "Sending, receiving timeval" + }, + { + .func = t_bintime, + .desc = "Sending, receiving bintime" + }, + { + .func = t_cmsg_len, + .desc = "Check cmsghdr.cmsg_len" + } +}; + +#define TEST_DGRAM_TBL_SIZE \ + (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0])) + +static bool debug = false; +static bool server_flag = true; +static bool send_data_flag = true; +static bool send_array_flag = true; +static bool failed_flag = false; + +static int sock_type; +static const char *sock_type_str; + +static const char *proc_name; + +static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX"; +static int serv_sock_fd; +static struct sockaddr_un serv_addr_sun; + +static struct { + char *buf_send; + char *buf_recv; + size_t buf_size; + u_int msg_num; +} ipc_msg; + +#define IPC_MSG_NUM_DEF 5 +#define IPC_MSG_NUM_MAX 10 +#define IPC_MSG_SIZE_DEF 7 +#define IPC_MSG_SIZE_MAX 128 + +static struct { + uid_t uid; + uid_t euid; + gid_t gid; + gid_t egid; + gid_t *gid_arr; + int gid_num; +} proc_cred; + +static pid_t client_pid; + +#define SYNC_SERVER 0 +#define SYNC_CLIENT 1 +#define SYNC_RECV 0 +#define SYNC_SEND 1 + +static int sync_fd[2][2]; + +#define LOGMSG_SIZE 128 + +static void logmsg(const char *, ...) __printflike(1, 2); +static void logmsgx(const char *, ...) __printflike(1, 2); +static void dbgmsg(const char *, ...) __printflike(1, 2); +static void output(const char *, ...) __printflike(1, 2); + +static void +usage(bool verbose) +{ + u_int i; + + printf("usage: %s [-dh] [-n num] [-s size] [-t type] " + "[-z value] [testno]\n", getprogname()); + if (!verbose) + return; + printf("\n Options are:\n\ + -d Output debugging information\n\ + -h Output the help message and exit\n\ + -n num Number of messages to send\n\ + -s size Specify size of data for IPC\n\ + -t type Specify socket type (stream, dgram) for tests\n\ + -z value Do not send data in a message (bit 0x1), do not send\n\ + data array associated with a cmsghdr structure (bit 0x2)\n\ + testno Run one test by its number (require the -t option)\n\n"); + printf(" Available tests for stream sockets:\n"); + for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i) + printf(" %u: %s\n", i, test_stream_tbl[i].desc); + printf("\n Available tests for datagram sockets:\n"); + for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i) + printf(" %u: %s\n", i, test_dgram_tbl[i].desc); +} + +static void +output(const char *format, ...) +{ + char buf[LOGMSG_SIZE]; + va_list ap; + + va_start(ap, format); + if (vsnprintf(buf, sizeof(buf), format, ap) < 0) + err(EXIT_FAILURE, "output: vsnprintf failed"); + write(STDOUT_FILENO, buf, strlen(buf)); + va_end(ap); +} + +static void +logmsg(const char *format, ...) +{ + char buf[LOGMSG_SIZE]; + va_list ap; + int errno_save; + + errno_save = errno; + va_start(ap, format); + if (vsnprintf(buf, sizeof(buf), format, ap) < 0) + err(EXIT_FAILURE, "logmsg: vsnprintf failed"); + if (errno_save == 0) + output("%s: %s\n", proc_name, buf); + else + output("%s: %s: %s\n", proc_name, buf, strerror(errno_save)); + va_end(ap); + errno = errno_save; +} + +static void +vlogmsgx(const char *format, va_list ap) +{ + char buf[LOGMSG_SIZE]; + + if (vsnprintf(buf, sizeof(buf), format, ap) < 0) + err(EXIT_FAILURE, "logmsgx: vsnprintf failed"); + output("%s: %s\n", proc_name, buf); + +} + +static void +logmsgx(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vlogmsgx(format, ap); + va_end(ap); +} + +static void +dbgmsg(const char *format, ...) +{ + va_list ap; + + if (debug) { + va_start(ap, format); + vlogmsgx(format, ap); + va_end(ap); + } +} + +static int +run_tests(int type, u_int testno1) +{ + const struct test_func *tf; + u_int i, testno2, failed_num; + + sock_type = type; + if (type == SOCK_STREAM) { + sock_type_str = "SOCK_STREAM"; + tf = test_stream_tbl; + i = TEST_STREAM_TBL_SIZE - 1; + } else { + sock_type_str = "SOCK_DGRAM"; + tf = test_dgram_tbl; + i = TEST_DGRAM_TBL_SIZE - 1; + } + if (testno1 == 0) { + testno1 = 1; + testno2 = i; + } else + testno2 = testno1; + + output("Running tests for %s sockets:\n", sock_type_str); + failed_num = 0; + for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) { + output(" %u: %s\n", i, tf->desc); + switch (tf->func()) { + case -1: + ++failed_num; + break; + case -2: + logmsgx("some system error or timeout occurred"); + return (-1); + } + } + + if (failed_num != 0) + failed_flag = true; + + if (testno1 != testno2) { + if (failed_num == 0) + output("-- all tests passed!\n"); + else + output("-- %u test%s failed!\n", + failed_num, failed_num == 1 ? "" : "s"); + } else { + if (failed_num == 0) + output("-- test passed!\n"); + else + output("-- test failed!\n"); + } + + return (0); +} + +static int +init(void) +{ + struct sigaction sigact; + size_t idx; + int rv; + + proc_name = "SERVER"; + + sigact.sa_handler = SIG_IGN; + sigact.sa_flags = 0; + sigemptyset(&sigact.sa_mask); + if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) { + logmsg("init: sigaction"); + return (-1); + } + + if (ipc_msg.buf_size == 0) + ipc_msg.buf_send = ipc_msg.buf_recv = NULL; + else { + ipc_msg.buf_send = malloc(ipc_msg.buf_size); + ipc_msg.buf_recv = malloc(ipc_msg.buf_size); + if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) { + logmsg("init: malloc"); + return (-1); + } + for (idx = 0; idx < ipc_msg.buf_size; ++idx) + ipc_msg.buf_send[idx] = (char)idx; + } + + proc_cred.uid = getuid(); + proc_cred.euid = geteuid(); + proc_cred.gid = getgid(); + proc_cred.egid = getegid(); + proc_cred.gid_num = getgroups(0, (gid_t *)NULL); + if (proc_cred.gid_num < 0) { + logmsg("init: getgroups"); + return (-1); + } + proc_cred.gid_arr = malloc(proc_cred.gid_num * + sizeof(*proc_cred.gid_arr)); + if (proc_cred.gid_arr == NULL) { + logmsg("init: malloc"); + return (-1); + } + if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) { + logmsg("init: getgroups"); + return (-1); + } + + memset(&serv_addr_sun, 0, sizeof(serv_addr_sun)); + rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path), + "%s/%s", work_dir, proc_name); + if (rv < 0) { + logmsg("init: snprintf"); + return (-1); + } + if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) { + logmsgx("init: not enough space for socket pathname"); + return (-1); + } + serv_addr_sun.sun_family = PF_LOCAL; + serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun); + + return (0); +} + +static int +client_fork(void) +{ + int fd1, fd2; + + if (pipe(sync_fd[SYNC_SERVER]) < 0 || + pipe(sync_fd[SYNC_CLIENT]) < 0) { + logmsg("client_fork: pipe"); + return (-1); + } + client_pid = fork(); + if (client_pid == (pid_t)-1) { + logmsg("client_fork: fork"); + return (-1); + } + if (client_pid == 0) { + proc_name = "CLIENT"; + server_flag = false; + fd1 = sync_fd[SYNC_SERVER][SYNC_RECV]; + fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND]; + } else { + fd1 = sync_fd[SYNC_SERVER][SYNC_SEND]; + fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV]; + } + if (close(fd1) < 0 || close(fd2) < 0) { + logmsg("client_fork: close"); + return (-1); + } + return (client_pid != 0); +} + +static void +client_exit(int rv) +{ + if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 || + close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) { + logmsg("client_exit: close"); + rv = -1; + } + rv = rv == 0 ? EXIT_SUCCESS : -rv; + dbgmsg("exit: code %d", rv); + _exit(rv); +} + +static int +client_wait(void) +{ + int status; + pid_t pid; + + dbgmsg("waiting for client"); + + if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 || + close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) { + logmsg("client_wait: close"); + return (-1); + } + + pid = waitpid(client_pid, &status, 0); + if (pid == (pid_t)-1) { + logmsg("client_wait: waitpid"); + return (-1); + } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != EXIT_SUCCESS) { + logmsgx("client exit status is %d", + WEXITSTATUS(status)); + return (-WEXITSTATUS(status)); + } + } else { + if (WIFSIGNALED(status)) + logmsgx("abnormal termination of client, signal %d%s", + WTERMSIG(status), WCOREDUMP(status) ? + " (core file generated)" : ""); + else + logmsgx("termination of client, unknown status"); + return (-1); + } + + return (0); +} + +int +main(int argc, char *argv[]) +{ + const char *errstr; + u_int testno, zvalue; + int opt, rv; + bool dgram_flag, stream_flag; + + ipc_msg.buf_size = IPC_MSG_SIZE_DEF; + ipc_msg.msg_num = IPC_MSG_NUM_DEF; + dgram_flag = stream_flag = false; + while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1) + switch (opt) { + case 'd': + debug = true; + break; + case 'h': + usage(true); + return (EXIT_SUCCESS); + case 'n': + ipc_msg.msg_num = strtonum(optarg, 1, + IPC_MSG_NUM_MAX, &errstr); + if (errstr != NULL) + errx(EXIT_FAILURE, "option -n: number is %s", + errstr); + break; + case 's': + ipc_msg.buf_size = strtonum(optarg, 0, + IPC_MSG_SIZE_MAX, &errstr); + if (errstr != NULL) + errx(EXIT_FAILURE, "option -s: number is %s", + errstr); + break; + case 't': + if (strcmp(optarg, "stream") == 0) + stream_flag = true; + else if (strcmp(optarg, "dgram") == 0) + dgram_flag = true; + else + errx(EXIT_FAILURE, "option -t: " + "wrong socket type"); + break; + case 'z': + zvalue = strtonum(optarg, 0, 3, &errstr); + if (errstr != NULL) + errx(EXIT_FAILURE, "option -z: number is %s", + errstr); + if (zvalue & 0x1) + send_data_flag = false; + if (zvalue & 0x2) + send_array_flag = false; + break; + default: + usage(false); + return (EXIT_FAILURE); + } + + if (optind < argc) { + if (optind + 1 != argc) + errx(EXIT_FAILURE, "too many arguments"); + testno = strtonum(argv[optind], 0, UINT_MAX, &errstr); + if (errstr != NULL) + errx(EXIT_FAILURE, "test number is %s", errstr); + if (stream_flag && testno >= TEST_STREAM_TBL_SIZE) + errx(EXIT_FAILURE, "given test %u for stream " + "sockets does not exist", testno); + if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE) + errx(EXIT_FAILURE, "given test %u for datagram " + "sockets does not exist", testno); + } else + testno = 0; + + if (!dgram_flag && !stream_flag) { + if (testno != 0) + errx(EXIT_FAILURE, "particular test number " + "can be used with the -t option only"); + dgram_flag = stream_flag = true; + } + + if (mkdtemp(work_dir) == NULL) + err(EXIT_FAILURE, "mkdtemp(%s)", work_dir); + + rv = EXIT_FAILURE; + if (init() < 0) + goto done; + + if (stream_flag) + if (run_tests(SOCK_STREAM, testno) < 0) + goto done; + if (dgram_flag) + if (run_tests(SOCK_DGRAM, testno) < 0) + goto done; + + rv = EXIT_SUCCESS; +done: + if (rmdir(work_dir) < 0) { + logmsg("rmdir(%s)", work_dir); + rv = EXIT_FAILURE; + } + return (failed_flag ? EXIT_FAILURE : rv); +} + +static int +socket_close(int fd) +{ + int rv; + + rv = 0; + if (close(fd) < 0) { + logmsg("socket_close: close"); + rv = -1; + } + if (server_flag && fd == serv_sock_fd) + if (unlink(serv_addr_sun.sun_path) < 0) { + logmsg("socket_close: unlink(%s)", + serv_addr_sun.sun_path); + rv = -1; + } + return (rv); +} + +static int +socket_create(void) +{ + struct timeval tv; + int fd; + + fd = socket(PF_LOCAL, sock_type, 0); + if (fd < 0) { + logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str); + return (-1); + } + if (server_flag) + serv_sock_fd = fd; + + tv.tv_sec = TIMEOUT; + tv.tv_usec = 0; + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 || + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { + logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)"); + goto failed; + } + + if (server_flag) { + if (bind(fd, (struct sockaddr *)&serv_addr_sun, + serv_addr_sun.sun_len) < 0) { + logmsg("socket_create: bind(%s)", + serv_addr_sun.sun_path); + goto failed; + } + if (sock_type == SOCK_STREAM) { + int val; + + if (listen(fd, LISTENQ) < 0) { + logmsg("socket_create: listen"); + goto failed; + } + val = fcntl(fd, F_GETFL, 0); + if (val < 0) { + logmsg("socket_create: fcntl(F_GETFL)"); + goto failed; + } + if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) { + logmsg("socket_create: fcntl(F_SETFL)"); + goto failed; + } + } + } + + return (fd); + +failed: + if (close(fd) < 0) + logmsg("socket_create: close"); + if (server_flag) + if (unlink(serv_addr_sun.sun_path) < 0) + logmsg("socket_close: unlink(%s)", + serv_addr_sun.sun_path); + return (-1); +} + +static int +socket_connect(int fd) +{ + dbgmsg("connect"); + + if (connect(fd, (struct sockaddr *)&serv_addr_sun, + serv_addr_sun.sun_len) < 0) { + logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path); + return (-1); + } + return (0); +} + +static int +sync_recv(void) +{ + ssize_t ssize; + int fd; + char buf; + + dbgmsg("sync: wait"); + + fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV]; + + ssize = read(fd, &buf, 1); + if (ssize < 0) { + logmsg("sync_recv: read"); + return (-1); + } + if (ssize < 1) { + logmsgx("sync_recv: read %zd of 1 byte", ssize); + return (-1); + } + + dbgmsg("sync: received"); + + return (0); +} + +static int +sync_send(void) +{ + ssize_t ssize; + int fd; + + dbgmsg("sync: send"); + + fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND]; + + ssize = write(fd, "", 1); + if (ssize < 0) { + logmsg("sync_send: write"); + return (-1); + } + if (ssize < 1) { + logmsgx("sync_send: sent %zd of 1 byte", ssize); + return (-1); + } + + return (0); +} + +static int +message_send(int fd, const struct msghdr *msghdr) +{ + const struct cmsghdr *cmsghdr; + size_t size; + ssize_t ssize; + + size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0; + dbgmsg("send: data size %zu", size); + dbgmsg("send: msghdr.msg_controllen %u", + (u_int)msghdr->msg_controllen); + cmsghdr = CMSG_FIRSTHDR(msghdr); + if (cmsghdr != NULL) + dbgmsg("send: cmsghdr.cmsg_len %u", + (u_int)cmsghdr->cmsg_len); + + ssize = sendmsg(fd, msghdr, 0); + if (ssize < 0) { + logmsg("message_send: sendmsg"); + return (-1); + } + if ((size_t)ssize != size) { + logmsgx("message_send: sendmsg: sent %zd of %zu bytes", + ssize, size); + return (-1); + } + + if (!send_data_flag) + if (sync_send() < 0) + return (-1); + + return (0); +} + +static int +message_sendn(int fd, struct msghdr *msghdr) +{ + u_int i; + + for (i = 1; i <= ipc_msg.msg_num; ++i) { + dbgmsg("message #%u", i); + if (message_send(fd, msghdr) < 0) + return (-1); + } + return (0); +} + +static int +message_recv(int fd, struct msghdr *msghdr) +{ + const struct cmsghdr *cmsghdr; + size_t size; + ssize_t ssize; + + if (!send_data_flag) + if (sync_recv() < 0) + return (-1); + + size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0; + ssize = recvmsg(fd, msghdr, MSG_WAITALL); + if (ssize < 0) { + logmsg("message_recv: recvmsg"); + return (-1); + } + if ((size_t)ssize != size) { + logmsgx("message_recv: recvmsg: received %zd of %zu bytes", + ssize, size); + return (-1); + } + + dbgmsg("recv: data size %zd", ssize); + dbgmsg("recv: msghdr.msg_controllen %u", + (u_int)msghdr->msg_controllen); + cmsghdr = CMSG_FIRSTHDR(msghdr); + if (cmsghdr != NULL) + dbgmsg("recv: cmsghdr.cmsg_len %u", + (u_int)cmsghdr->cmsg_len); + + if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) { + logmsgx("message_recv: received message has wrong content"); + return (-1); + } + + return (0); +} + +static int +socket_accept(int listenfd) +{ + fd_set rset; + struct timeval tv; + int fd, rv, val; + + dbgmsg("accept"); + + FD_ZERO(&rset); + FD_SET(listenfd, &rset); + tv.tv_sec = TIMEOUT; + tv.tv_usec = 0; + rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv); + if (rv < 0) { + logmsg("socket_accept: select"); + return (-1); + } + if (rv == 0) { + logmsgx("socket_accept: select timeout"); + return (-1); + } + + fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); + if (fd < 0) { + logmsg("socket_accept: accept"); + return (-1); + } + + val = fcntl(fd, F_GETFL, 0); + if (val < 0) { + logmsg("socket_accept: fcntl(F_GETFL)"); + goto failed; + } + if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) { + logmsg("socket_accept: fcntl(F_SETFL)"); + goto failed; + } + + return (fd); + +failed: + if (close(fd) < 0) + logmsg("socket_accept: close"); + return (-1); +} + +static int +check_msghdr(const struct msghdr *msghdr, size_t size) +{ + if (msghdr->msg_flags & MSG_TRUNC) { + logmsgx("msghdr.msg_flags has MSG_TRUNC"); + return (-1); + } + if (msghdr->msg_flags & MSG_CTRUNC) { + logmsgx("msghdr.msg_flags has MSG_CTRUNC"); + return (-1); + } + if (msghdr->msg_controllen < size) { + logmsgx("msghdr.msg_controllen %u < %zu", + (u_int)msghdr->msg_controllen, size); + return (-1); + } + if (msghdr->msg_controllen > 0 && size == 0) { + logmsgx("msghdr.msg_controllen %u > 0", + (u_int)msghdr->msg_controllen); + return (-1); + } + return (0); +} + +static int +check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size) +{ + if (cmsghdr == NULL) { + logmsgx("cmsghdr is NULL"); + return (-1); + } + if (cmsghdr->cmsg_level != SOL_SOCKET) { + logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET", + cmsghdr->cmsg_level); + return (-1); + } + if (cmsghdr->cmsg_type != type) { + logmsgx("cmsghdr.cmsg_type %d != %d", + cmsghdr->cmsg_type, type); + return (-1); + } + if (cmsghdr->cmsg_len != CMSG_LEN(size)) { + logmsgx("cmsghdr.cmsg_len %u != %zu", + (u_int)cmsghdr->cmsg_len, CMSG_LEN(size)); + return (-1); + } + return (0); +} + +static int +check_groups(const char *gid_arr_str, const gid_t *gid_arr, + const char *gid_num_str, int gid_num, bool all_gids) +{ + int i; + + for (i = 0; i < gid_num; ++i) + dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]); + + if (all_gids) { + if (gid_num != proc_cred.gid_num) { + logmsgx("%s %d != %d", gid_num_str, gid_num, + proc_cred.gid_num); + return (-1); + } + } else { + if (gid_num > proc_cred.gid_num) { + logmsgx("%s %d > %d", gid_num_str, gid_num, + proc_cred.gid_num); + return (-1); + } + } + if (memcmp(gid_arr, proc_cred.gid_arr, + gid_num * sizeof(*gid_arr)) != 0) { + logmsgx("%s content is wrong", gid_arr_str); + for (i = 0; i < gid_num; ++i) + if (gid_arr[i] != proc_cred.gid_arr[i]) { + logmsgx("%s[%d] %lu != %lu", + gid_arr_str, i, (u_long)gid_arr[i], + (u_long)proc_cred.gid_arr[i]); + break; + } + return (-1); + } + return (0); +} + +static int +check_xucred(const struct xucred *xucred, socklen_t len) +{ + if (len != sizeof(*xucred)) { + logmsgx("option value size %zu != %zu", + (size_t)len, sizeof(*xucred)); + return (-1); + } + + dbgmsg("xucred.cr_version %u", xucred->cr_version); + dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid); + dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups); + + if (xucred->cr_version != XUCRED_VERSION) { + logmsgx("xucred.cr_version %u != %d", + xucred->cr_version, XUCRED_VERSION); + return (-1); + } + if (xucred->cr_uid != proc_cred.euid) { + logmsgx("xucred.cr_uid %lu != %lu (EUID)", + (u_long)xucred->cr_uid, (u_long)proc_cred.euid); + return (-1); + } + if (xucred->cr_ngroups == 0) { + logmsgx("xucred.cr_ngroups == 0"); + return (-1); + } + if (xucred->cr_ngroups < 0) { + logmsgx("xucred.cr_ngroups < 0"); + return (-1); + } + if (xucred->cr_ngroups > XU_NGROUPS) { + logmsgx("xucred.cr_ngroups %hu > %u (max)", + xucred->cr_ngroups, XU_NGROUPS); + return (-1); + } + if (xucred->cr_groups[0] != proc_cred.egid) { + logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)", + (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid); + return (-1); + } + if (check_groups("xucred.cr_groups", xucred->cr_groups, + "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0) + return (-1); + return (0); +} + +static int +check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) +{ + const struct cmsgcred *cmsgcred; + + if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0) + return (-1); + + cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); + + dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid); + dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid); + dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid); + dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid); + dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups); + + if (cmsgcred->cmcred_pid != client_pid) { + logmsgx("cmsgcred.cmcred_pid %ld != %ld", + (long)cmsgcred->cmcred_pid, (long)client_pid); + return (-1); + } + if (cmsgcred->cmcred_uid != proc_cred.uid) { + logmsgx("cmsgcred.cmcred_uid %lu != %lu", + (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid); + return (-1); + } + if (cmsgcred->cmcred_euid != proc_cred.euid) { + logmsgx("cmsgcred.cmcred_euid %lu != %lu", + (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid); + return (-1); + } + if (cmsgcred->cmcred_gid != proc_cred.gid) { + logmsgx("cmsgcred.cmcred_gid %lu != %lu", + (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid); + return (-1); + } + if (cmsgcred->cmcred_ngroups == 0) { + logmsgx("cmsgcred.cmcred_ngroups == 0"); + return (-1); + } + if (cmsgcred->cmcred_ngroups < 0) { + logmsgx("cmsgcred.cmcred_ngroups %d < 0", + cmsgcred->cmcred_ngroups); + return (-1); + } + if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) { + logmsgx("cmsgcred.cmcred_ngroups %d > %d", + cmsgcred->cmcred_ngroups, CMGROUP_MAX); + return (-1); + } + if (cmsgcred->cmcred_groups[0] != proc_cred.egid) { + logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", + (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid); + return (-1); + } + if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups, + "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0) + return (-1); + return (0); +} + +static int +check_scm_creds_sockcred(struct cmsghdr *cmsghdr) +{ + const struct sockcred *sockcred; + + if (check_cmsghdr(cmsghdr, SCM_CREDS, + SOCKCREDSIZE(proc_cred.gid_num)) < 0) + return (-1); + + sockcred = (struct sockcred *)CMSG_DATA(cmsghdr); + + dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid); + dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid); + dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid); + dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid); + dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups); + + if (sockcred->sc_uid != proc_cred.uid) { + logmsgx("sockcred.sc_uid %lu != %lu", + (u_long)sockcred->sc_uid, (u_long)proc_cred.uid); + return (-1); + } + if (sockcred->sc_euid != proc_cred.euid) { + logmsgx("sockcred.sc_euid %lu != %lu", + (u_long)sockcred->sc_euid, (u_long)proc_cred.euid); + return (-1); + } + if (sockcred->sc_gid != proc_cred.gid) { + logmsgx("sockcred.sc_gid %lu != %lu", + (u_long)sockcred->sc_gid, (u_long)proc_cred.gid); + return (-1); + } + if (sockcred->sc_egid != proc_cred.egid) { + logmsgx("sockcred.sc_egid %lu != %lu", + (u_long)sockcred->sc_egid, (u_long)proc_cred.egid); + return (-1); + } + if (sockcred->sc_ngroups == 0) { + logmsgx("sockcred.sc_ngroups == 0"); + return (-1); + } + if (sockcred->sc_ngroups < 0) { + logmsgx("sockcred.sc_ngroups %d < 0", + sockcred->sc_ngroups); + return (-1); + } + if (sockcred->sc_ngroups != proc_cred.gid_num) { + logmsgx("sockcred.sc_ngroups %d != %u", + sockcred->sc_ngroups, proc_cred.gid_num); + return (-1); + } + if (check_groups("sockcred.sc_groups", sockcred->sc_groups, + "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0) + return (-1); + return (0); +} + +static int +check_scm_timestamp(struct cmsghdr *cmsghdr) +{ + const struct timeval *timeval; + + if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0) + return (-1); + + timeval = (struct timeval *)CMSG_DATA(cmsghdr); + + dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX, + (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec); + + return (0); +} + +static int +check_scm_bintime(struct cmsghdr *cmsghdr) +{ + const struct bintime *bintime; + + if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0) + return (-1); + + bintime = (struct bintime *)CMSG_DATA(cmsghdr); + + dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64, + (intmax_t)bintime->sec, bintime->frac); + + return (0); +} + +static void +msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data) +{ + msghdr->msg_name = NULL; + msghdr->msg_namelen = 0; + if (send_data_flag) { + iov->iov_base = server_flag ? + ipc_msg.buf_recv : ipc_msg.buf_send; + iov->iov_len = ipc_msg.buf_size; + msghdr->msg_iov = iov; + msghdr->msg_iovlen = 1; + } else { + msghdr->msg_iov = NULL; + msghdr->msg_iovlen = 0; + } + msghdr->msg_control = cmsg_data; + msghdr->msg_flags = 0; +} + +static void +msghdr_init_server(struct msghdr *msghdr, struct iovec *iov, + void *cmsg_data, size_t cmsg_size) +{ + msghdr_init_generic(msghdr, iov, cmsg_data); + msghdr->msg_controllen = cmsg_size; + dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ? + msghdr->msg_iov->iov_len : (size_t)0); + dbgmsg("init: msghdr.msg_controllen %u", + (u_int)msghdr->msg_controllen); +} + +static void +msghdr_init_client(struct msghdr *msghdr, struct iovec *iov, + void *cmsg_data, size_t cmsg_size, int type, size_t arr_size) +{ + struct cmsghdr *cmsghdr; + + msghdr_init_generic(msghdr, iov, cmsg_data); + if (cmsg_data != NULL) { + msghdr->msg_controllen = send_array_flag ? + cmsg_size : CMSG_SPACE(0); + cmsghdr = CMSG_FIRSTHDR(msghdr); + cmsghdr->cmsg_level = SOL_SOCKET; + cmsghdr->cmsg_type = type; + cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0); + } else + msghdr->msg_controllen = 0; +} + +static int +t_generic(int (*client_func)(int), int (*server_func)(int)) +{ + int fd, rv, rv_client; + + switch (client_fork()) { + case 0: + fd = socket_create(); + if (fd < 0) + rv = -2; + else { + rv = client_func(fd); + if (socket_close(fd) < 0) + rv = -2; + } + client_exit(rv); + break; + case 1: + fd = socket_create(); + if (fd < 0) + rv = -2; + else { + rv = server_func(fd); + rv_client = client_wait(); + if (rv == 0 || (rv == -2 && rv_client != 0)) + rv = rv_client; + if (socket_close(fd) < 0) + rv = -2; + } + break; + default: + rv = -2; + } + return (rv); +} + +static int +t_cmsgcred_client(int fd) +{ + struct msghdr msghdr; + struct iovec iov[1]; + void *cmsg_data; + size_t cmsg_size; + int rv; + + if (sync_recv() < 0) + return (-2); + + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, + SCM_CREDS, sizeof(struct cmsgcred)); + + if (socket_connect(fd) < 0) + goto done; + + if (message_sendn(fd, &msghdr) < 0) + goto done; + + rv = 0; +done: + free(cmsg_data); + return (rv); +} + +static int +t_cmsgcred_server(int fd1) +{ + struct msghdr msghdr; + struct iovec iov[1]; + struct cmsghdr *cmsghdr; + void *cmsg_data; + size_t cmsg_size; + u_int i; + int fd2, rv; + + if (sync_send() < 0) + return (-2); + + fd2 = -1; + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + + if (sock_type == SOCK_STREAM) { + fd2 = socket_accept(fd1); + if (fd2 < 0) + goto done; + } else + fd2 = fd1; + + rv = -1; + for (i = 1; i <= ipc_msg.msg_num; ++i) { + dbgmsg("message #%u", i); + + msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); + if (message_recv(fd2, &msghdr) < 0) { + rv = -2; + break; + } + + if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) + break; + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (check_scm_creds_cmsgcred(cmsghdr) < 0) + break; + } + if (i > ipc_msg.msg_num) + rv = 0; +done: + free(cmsg_data); + if (sock_type == SOCK_STREAM && fd2 >= 0) + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_cmsgcred(void) +{ + return (t_generic(t_cmsgcred_client, t_cmsgcred_server)); +} + +static int +t_sockcred_client(int type, int fd) +{ + struct msghdr msghdr; + struct iovec iov[1]; + int rv; + + if (sync_recv() < 0) + return (-2); + + rv = -2; + + msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0); + + if (socket_connect(fd) < 0) + goto done; + + if (type == 2) + if (sync_recv() < 0) + goto done; + + if (message_sendn(fd, &msghdr) < 0) + goto done; + + rv = 0; +done: + return (rv); +} + +static int +t_sockcred_server(int type, int fd1) +{ + struct msghdr msghdr; + struct iovec iov[1]; + struct cmsghdr *cmsghdr; + void *cmsg_data; + size_t cmsg_size; + u_int i; + int fd2, rv, val; + + fd2 = -1; + rv = -2; + + cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + + if (type == 1) { + dbgmsg("setting LOCAL_CREDS"); + val = 1; + if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { + logmsg("setsockopt(LOCAL_CREDS)"); + goto done; + } + } + + if (sync_send() < 0) + goto done; + + if (sock_type == SOCK_STREAM) { + fd2 = socket_accept(fd1); + if (fd2 < 0) + goto done; + } else + fd2 = fd1; + + if (type == 2) { + dbgmsg("setting LOCAL_CREDS"); + val = 1; + if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { + logmsg("setsockopt(LOCAL_CREDS)"); + goto done; + } + if (sync_send() < 0) + goto done; + } + + rv = -1; + for (i = 1; i <= ipc_msg.msg_num; ++i) { + dbgmsg("message #%u", i); + + msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); + if (message_recv(fd2, &msghdr) < 0) { + rv = -2; + break; + } + + if (i > 1 && sock_type == SOCK_STREAM) { + if (check_msghdr(&msghdr, 0) < 0) + break; + } else { + if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) + break; + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (check_scm_creds_sockcred(cmsghdr) < 0) + break; + } + } + if (i > ipc_msg.msg_num) + rv = 0; +done: + free(cmsg_data); + if (sock_type == SOCK_STREAM && fd2 >= 0) + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_sockcred_1(void) +{ + u_int i; + int fd, rv, rv_client; + + switch (client_fork()) { + case 0: + for (i = 1; i <= 2; ++i) { + dbgmsg("client #%u", i); + fd = socket_create(); + if (fd < 0) + rv = -2; + else { + rv = t_sockcred_client(1, fd); + if (socket_close(fd) < 0) + rv = -2; + } + if (rv != 0) + break; + } + client_exit(rv); + break; + case 1: + fd = socket_create(); + if (fd < 0) + rv = -2; + else { + rv = t_sockcred_server(1, fd); + if (rv == 0) + rv = t_sockcred_server(3, fd); + rv_client = client_wait(); + if (rv == 0 || (rv == -2 && rv_client != 0)) + rv = rv_client; + if (socket_close(fd) < 0) + rv = -2; + } + break; + default: + rv = -2; + } + + return (rv); +} + +static int +t_sockcred_2_client(int fd) +{ + return (t_sockcred_client(2, fd)); +} + +static int +t_sockcred_2_server(int fd) +{ + return (t_sockcred_server(2, fd)); +} + +static int +t_sockcred_2(void) +{ + return (t_generic(t_sockcred_2_client, t_sockcred_2_server)); +} + +static int +t_cmsgcred_sockcred_server(int fd1) +{ + struct msghdr msghdr; + struct iovec iov[1]; + struct cmsghdr *cmsghdr; + void *cmsg_data, *cmsg1_data, *cmsg2_data; + size_t cmsg_size, cmsg1_size, cmsg2_size; + u_int i; + int fd2, rv, val; + + fd2 = -1; + rv = -2; + + cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); + cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred)); + cmsg1_data = malloc(cmsg1_size); + cmsg2_data = malloc(cmsg2_size); + if (cmsg1_data == NULL || cmsg2_data == NULL) { + logmsg("malloc"); + goto done; + } + + dbgmsg("setting LOCAL_CREDS"); + val = 1; + if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { + logmsg("setsockopt(LOCAL_CREDS)"); + goto done; + } + + if (sync_send() < 0) + goto done; + + if (sock_type == SOCK_STREAM) { + fd2 = socket_accept(fd1); + if (fd2 < 0) + goto done; + } else + fd2 = fd1; + + cmsg_data = cmsg1_data; + cmsg_size = cmsg1_size; + rv = -1; + for (i = 1; i <= ipc_msg.msg_num; ++i) { + dbgmsg("message #%u", i); + + msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); + if (message_recv(fd2, &msghdr) < 0) { + rv = -2; + break; + } + + if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) + break; + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (i == 1 || sock_type == SOCK_DGRAM) { + if (check_scm_creds_sockcred(cmsghdr) < 0) + break; + } else { + if (check_scm_creds_cmsgcred(cmsghdr) < 0) + break; + } + + cmsg_data = cmsg2_data; + cmsg_size = cmsg2_size; + } + if (i > ipc_msg.msg_num) + rv = 0; +done: + free(cmsg1_data); + free(cmsg2_data); + if (sock_type == SOCK_STREAM && fd2 >= 0) + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_cmsgcred_sockcred(void) +{ + return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server)); +} + +static int +t_timeval_client(int fd) +{ + struct msghdr msghdr; + struct iovec iov[1]; + void *cmsg_data; + size_t cmsg_size; + int rv; + + if (sync_recv() < 0) + return (-2); + + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct timeval)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, + SCM_TIMESTAMP, sizeof(struct timeval)); + + if (socket_connect(fd) < 0) + goto done; + + if (message_sendn(fd, &msghdr) < 0) + goto done; + + rv = 0; +done: + free(cmsg_data); + return (rv); +} + +static int +t_timeval_server(int fd1) +{ + struct msghdr msghdr; + struct iovec iov[1]; + struct cmsghdr *cmsghdr; + void *cmsg_data; + size_t cmsg_size; + u_int i; + int fd2, rv; + + if (sync_send() < 0) + return (-2); + + fd2 = -1; + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct timeval)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + + if (sock_type == SOCK_STREAM) { + fd2 = socket_accept(fd1); + if (fd2 < 0) + goto done; + } else + fd2 = fd1; + + rv = -1; + for (i = 1; i <= ipc_msg.msg_num; ++i) { + dbgmsg("message #%u", i); + + msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); + if (message_recv(fd2, &msghdr) < 0) { + rv = -2; + break; + } + + if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) + break; + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (check_scm_timestamp(cmsghdr) < 0) + break; + } + if (i > ipc_msg.msg_num) + rv = 0; +done: + free(cmsg_data); + if (sock_type == SOCK_STREAM && fd2 >= 0) + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_timeval(void) +{ + return (t_generic(t_timeval_client, t_timeval_server)); +} + +static int +t_bintime_client(int fd) +{ + struct msghdr msghdr; + struct iovec iov[1]; + void *cmsg_data; + size_t cmsg_size; + int rv; + + if (sync_recv() < 0) + return (-2); + + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct bintime)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, + SCM_BINTIME, sizeof(struct bintime)); + + if (socket_connect(fd) < 0) + goto done; + + if (message_sendn(fd, &msghdr) < 0) + goto done; + + rv = 0; +done: + free(cmsg_data); + return (rv); +} + +static int +t_bintime_server(int fd1) +{ + struct msghdr msghdr; + struct iovec iov[1]; + struct cmsghdr *cmsghdr; + void *cmsg_data; + size_t cmsg_size; + u_int i; + int fd2, rv; + + if (sync_send() < 0) + return (-2); + + fd2 = -1; + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct bintime)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + + if (sock_type == SOCK_STREAM) { + fd2 = socket_accept(fd1); + if (fd2 < 0) + goto done; + } else + fd2 = fd1; + + rv = -1; + for (i = 1; i <= ipc_msg.msg_num; ++i) { + dbgmsg("message #%u", i); + + msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); + if (message_recv(fd2, &msghdr) < 0) { + rv = -2; + break; + } + + if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) + break; + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (check_scm_bintime(cmsghdr) < 0) + break; + } + if (i > ipc_msg.msg_num) + rv = 0; +done: + free(cmsg_data); + if (sock_type == SOCK_STREAM && fd2 >= 0) + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_bintime(void) +{ + return (t_generic(t_bintime_client, t_bintime_server)); +} + +static int +t_cmsg_len_client(int fd) +{ + struct msghdr msghdr; + struct iovec iov[1]; + struct cmsghdr *cmsghdr; + void *cmsg_data; + size_t size, cmsg_size; + socklen_t socklen; + int rv; + + if (sync_recv() < 0) + return (-2); + + rv = -2; + + cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); + cmsg_data = malloc(cmsg_size); + if (cmsg_data == NULL) { + logmsg("malloc"); + goto done; + } + msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, + SCM_CREDS, sizeof(struct cmsgcred)); + cmsghdr = CMSG_FIRSTHDR(&msghdr); + + if (socket_connect(fd) < 0) + goto done; + + size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0; + rv = -1; + for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) { + cmsghdr->cmsg_len = socklen; + dbgmsg("send: data size %zu", size); + dbgmsg("send: msghdr.msg_controllen %u", + (u_int)msghdr.msg_controllen); + dbgmsg("send: cmsghdr.cmsg_len %u", + (u_int)cmsghdr->cmsg_len); + if (sendmsg(fd, &msghdr, 0) < 0) + continue; + logmsgx("sent message with cmsghdr.cmsg_len %u < %u", + (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0)); + break; + } + if (socklen == CMSG_LEN(0)) + rv = 0; + + if (sync_send() < 0) { + rv = -2; + goto done; + } +done: + free(cmsg_data); + return (rv); +} + +static int +t_cmsg_len_server(int fd1) +{ + int fd2, rv; + + if (sync_send() < 0) + return (-2); + + rv = -2; + + if (sock_type == SOCK_STREAM) { + fd2 = socket_accept(fd1); + if (fd2 < 0) + goto done; + } else + fd2 = fd1; + + if (sync_recv() < 0) + goto done; + + rv = 0; +done: + if (sock_type == SOCK_STREAM && fd2 >= 0) + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_cmsg_len(void) +{ + return (t_generic(t_cmsg_len_client, t_cmsg_len_server)); +} + +static int +t_peercred_client(int fd) +{ + struct xucred xucred; + socklen_t len; + + if (sync_recv() < 0) + return (-1); + + if (socket_connect(fd) < 0) + return (-1); + + len = sizeof(xucred); + if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { + logmsg("getsockopt(LOCAL_PEERCRED)"); + return (-1); + } + + if (check_xucred(&xucred, len) < 0) + return (-1); + + return (0); +} + +static int +t_peercred_server(int fd1) +{ + struct xucred xucred; + socklen_t len; + int fd2, rv; + + if (sync_send() < 0) + return (-2); + + fd2 = socket_accept(fd1); + if (fd2 < 0) + return (-2); + + len = sizeof(xucred); + if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { + logmsg("getsockopt(LOCAL_PEERCRED)"); + rv = -2; + goto done; + } + + if (check_xucred(&xucred, len) < 0) { + rv = -1; + goto done; + } + + rv = 0; +done: + if (socket_close(fd2) < 0) + rv = -2; + return (rv); +} + +static int +t_peercred(void) +{ + return (t_generic(t_peercred_client, t_peercred_server)); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_cmsg.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_cmsg_test.sh =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_cmsg_test.sh (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_cmsg_test.sh (revision 281516) @@ -0,0 +1,85 @@ +#!/bin/sh +# $FreeBSD$ + +cmd=`echo $0 | sed -e 's,_test$,,'` + +IFS= +n=0 + +run() +{ + result=`${cmd} -t $2 $3 ${5%% *} 2>&1` + if [ $? -ne 0 ]; then + echo -n "not " + fi + echo "ok $1 - $4 ${5#* }" + echo ${result} | grep -E "SERVER|CLIENT" | while read line; do + echo "# ${line}" + done +} + +echo "1..47" + +for t1 in \ + "1 Sending, receiving cmsgcred" \ + "4 Sending cmsgcred, receiving sockcred" \ + "5 Sending, receiving timeval" \ + "6 Sending, receiving bintime" \ + "7 Check cmsghdr.cmsg_len" +do + for t2 in \ + "0 " \ + "1 (no data)" \ + "2 (no array)" \ + "3 (no data, array)" + do + n=$((n + 1)) + run ${n} stream "-z ${t2%% *}" STREAM "${t1} ${t2#* }" + done +done + +for t1 in \ + "2 Receiving sockcred (listening socket)" \ + "3 Receiving sockcred (accepted socket)" +do + for t2 in \ + "0 " \ + "1 (no data)" + do + n=$((n + 1)) + run ${n} stream "-z ${t2%% *}" STREAM "${t1} ${t2#* }" + done +done + +n=$((n + 1)) +run ${n} stream "-z 0" STREAM "8 Check LOCAL_PEERCRED socket option" + +for t1 in \ + "1 Sending, receiving cmsgcred" \ + "3 Sending cmsgcred, receiving sockcred" \ + "4 Sending, receiving timeval" \ + "5 Sending, receiving bintime" \ + "6 Check cmsghdr.cmsg_len" +do + for t2 in \ + "0 " \ + "1 (no data)" \ + "2 (no array)" \ + "3 (no data, array)" + do + n=$((n + 1)) + run ${n} dgram "-z ${t2%% *}" DGRAM "${t1} ${t2#* }" + done +done + +for t1 in \ + "2 Receiving sockcred" +do + for t2 in \ + "0 " \ + "1 (no data)" + do + n=$((n + 1)) + run ${n} dgram "-z ${t2%% *}" DGRAM "${t1} ${t2#* }" + done +done Property changes on: user/ngie/more-tests/tests/sys/socket/unix_cmsg_test.sh ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_gc_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_gc_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_gc_test.c (revision 281516) @@ -0,0 +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[]) +{ + char cmd[sizeof(RMDIR) + PATH_MAX]; + int serrno; + pid_t pid; + + strlcpy(dpath, "/tmp/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); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_gc_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c (revision 281516) @@ -0,0 +1,389 @@ +/*- + * 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 + +/* + * 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(const char *test, int *fdp) +{ + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) < 0) + err(-1, "%s: socketpair(PF_UNIX, SOCK_STREAM)", test); +} + +static void +closesocketpair(int *fdp) +{ + + close(fdp[0]); + close(fdp[1]); +} + +static void +devnull(const char *test, int *fdp) +{ + int fd; + + fd = open("/dev/null", O_RDONLY); + if (fd < 0) + err(-1, "%s: open(/dev/null)", test); + *fdp = fd; +} + +static void +tempfile(const char *test, int *fdp) +{ + char path[PATH_MAX]; + int fd; + + snprintf(path, PATH_MAX, "/tmp/unix_passfd.XXXXXXXXXXXXXXX"); + fd = mkstemp(path); + if (fd < 0) + err(-1, "%s: mkstemp(%s)", test, path); + (void)unlink(path); + *fdp = fd; +} + +static void +dofstat(const char *test, int fd, struct stat *sb) +{ + + if (fstat(fd, sb) < 0) + err(-1, "%s: fstat", test); +} + +static void +samefile(const char *test, struct stat *sb1, struct stat *sb2) +{ + + if (sb1->st_dev != sb2->st_dev) + errx(-1, "%s: samefile: different device", test); + if (sb1->st_ino != sb2->st_ino) + errx(-1, "%s: samefile: different inode", test); +} + +static void +sendfd_payload(const char *test, 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); + if (len < 0) + err(-1, "%s: sendmsg", test); + if ((size_t)len != paylen) + errx(-1, "%s: sendmsg: %zd bytes sent", test, len); +} + +static void +sendfd(const char *test, int sockfd, int sendfd) +{ + char ch; + + return (sendfd_payload(test, sockfd, sendfd, &ch, sizeof(ch))); +} + +static void +recvfd_payload(const char *test, 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); + if (len < 0) + err(-1, "%s: recvmsg", test); + if ((size_t)len != buflen) + errx(-1, "%s: recvmsg: %zd bytes received", test, len); + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + if (cmsghdr == NULL) + errx(-1, "%s: recvmsg: did not receive control message", test); + *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); + if (*recvfd == -1) + errx(-1, "%s: recvmsg: received fd -1", test); + } + } + if (*recvfd == -1) + errx(-1, "%s: recvmsg: did not receive single-fd message", + test); +} + +static void +recvfd(const char *test, int sockfd, int *recvfd) +{ + char ch; + + return (recvfd_payload(test, sockfd, recvfd, &ch, sizeof(ch))); +} + +int +main(void) +{ + struct stat putfd_1_stat, putfd_2_stat, getfd_1_stat, getfd_2_stat; + int fd[2], putfd_1, putfd_2, getfd_1, getfd_2; + const char *test; + + /* + * 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. + */ + test = "test1-simplesendfd"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + tempfile(test, &putfd_1); + dofstat(test, putfd_1, &putfd_1_stat); + sendfd(test, fd[0], putfd_1); + recvfd(test, fd[1], &getfd_1); + dofstat(test, getfd_1, &getfd_1_stat); + samefile(test, &putfd_1_stat, &getfd_1_stat); + close(putfd_1); + close(getfd_1); + closesocketpair(fd); + + printf("%s passed\n", test); + + /* + * 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. + */ + test = "test2-sendandclose"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + tempfile(test, &putfd_1); + dofstat(test, putfd_1, &putfd_1_stat); + sendfd(test, fd[0], putfd_1); + close(putfd_1); + recvfd(test, fd[1], &getfd_1); + dofstat(test, getfd_1, &getfd_1_stat); + samefile(test, &putfd_1_stat, &getfd_1_stat); + close(getfd_1); + closesocketpair(fd); + + printf("%s passed\n", test); + + /* + * Third test: put a temporary file into a UNIX domain socket, then + * close both endpoints causing garbage collection to kick off. + */ + test = "test3-sendandcancel"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + tempfile(test, &putfd_1); + sendfd(test, fd[0], putfd_1); + close(putfd_1); + closesocketpair(fd); + + printf("%s passed\n", test); + + /* + * Send two files. Then receive them. Make sure they are returned + * in the right order, and both get there. + */ + + test = "test4-twofile"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + tempfile(test, &putfd_1); + tempfile(test, &putfd_2); + dofstat(test, putfd_1, &putfd_1_stat); + dofstat(test, putfd_2, &putfd_2_stat); + sendfd(test, fd[0], putfd_1); + sendfd(test, fd[0], putfd_2); + close(putfd_1); + close(putfd_2); + recvfd(test, fd[1], &getfd_1); + recvfd(test, fd[1], &getfd_2); + dofstat(test, getfd_1, &getfd_1_stat); + dofstat(test, getfd_2, &getfd_2_stat); + samefile(test, &putfd_1_stat, &getfd_1_stat); + samefile(test, &putfd_2_stat, &getfd_2_stat); + close(getfd_1); + close(getfd_2); + closesocketpair(fd); + + printf("%s passed\n", test); + + /* + * Big bundling test. Send an endpoint of the UNIX domain socket + * over itself, closing the door behind it. + */ + + test = "test5-bundle"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + + sendfd(test, fd[0], fd[0]); + close(fd[0]); + recvfd(test, fd[1], &getfd_1); + close(getfd_1); + close(fd[1]); + + printf("%s passed\n", test); + + /* + * 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. + */ + + test = "test6-bundlecancel"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + sendfd(test, fd[0], fd[0]); + sendfd(test, fd[1], fd[0]); + closesocketpair(fd); + + printf("%s passed\n", test); + + /* + * Test for PR 151758: Send an character device over the UNIX + * domain socket and then close both sockets to orphan the + * device. + */ + + test = "test7-devfsorphan"; + printf("beginning %s\n", test); + + domainsocketpair(test, fd); + devnull(test, &putfd_1); + sendfd(test, fd[0], putfd_1); + close(putfd_1); + closesocketpair(fd); + + printf("%s passed\n", test); + + /* + * 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. + */ + test = "test8-rights+creds+payload"; + printf("beginning %s\n", test); + + { + const int on = 1; + u_long sendspace; + size_t len; + void *buf; + + len = sizeof(sendspace); + if (sysctlbyname("net.local.stream.sendspace", &sendspace, + &len, NULL, 0) < 0) + err(-1, "%s: sysctlbyname(net.local.stream.sendspace)", + test); + + if ((buf = malloc(sendspace)) == NULL) + err(-1, "%s: malloc", test); + + domainsocketpair(test, fd); + if (setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)) < 0) + err(-1, "%s: setsockopt(LOCAL_CREDS)", test); + tempfile(test, &putfd_1); + sendfd_payload(test, fd[0], putfd_1, buf, sendspace); + recvfd_payload(test, fd[1], &getfd_1, buf, sendspace); + close(putfd_1); + close(getfd_1); + closesocketpair(fd); + } + + printf("%s passed\n", test); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_sendtorace_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_sendtorace_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_sendtorace_test.c (revision 281516) @@ -0,0 +1,215 @@ +/*- + * Copyright (c) 2006 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$ + */ + +/* + * Attempts to exercise UNIX domain socket races relating to the non-atomic + * connect-and-send properties of sendto(). As the result of such a race is + * a kernel panic, this test simply completes or doesn't. + * + * XXX: Despite implementing support for sendto() on stream sockets with + * implied connect, the appropriate flag isn't set in the FreeBSD kernel so + * it does not work. For now, don't call the stream test. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define ITERATIONS 1000000 + +static char socket_path[] = "tmp.XXXXXX"; + +static void +stream_server(int listenfd) +{ + int acceptfd; + + while (1) { + acceptfd = accept(listenfd, NULL, NULL); + if (acceptfd < 0) { + warn("stream_server: accept"); + continue; + } + sleep(1); + close(acceptfd); + } +} + +static void +stream_client(void) +{ + struct sockaddr_un sun; + ssize_t len; + char c = 0; + int fd, i; + + bzero(&sun, sizeof(sun)); + sun.sun_len = sizeof(sun); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, socket_path); + for (i = 0; i < ITERATIONS; i++) { + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + warn("stream_client: socket"); + return; + } + len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun, + sizeof(sun)); + if (len < 0) + warn("stream_client: sendto"); + close(fd); + } +} + +static void +stream_test(void) +{ + struct sockaddr_un sun; + pid_t childpid; + int listenfd; + + listenfd = socket(PF_UNIX, SOCK_STREAM, 0); + if (listenfd < 0) + err(-1, "stream_test: socket"); + + bzero(&sun, sizeof(sun)); + sun.sun_len = sizeof(sun); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, socket_path); + + if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) + err(-1, "stream_test: bind"); + + if (listen(listenfd, -1) < 0) + err(-1, "stream_test: listen"); + + childpid = fork(); + if (childpid < 0) + err(-1, "stream_test: fork"); + + if (childpid != 0) { + sleep(1); + stream_client(); + kill(childpid, SIGTERM); + sleep(1); + } else + stream_server(listenfd); + + (void)unlink(socket_path); +} + +static void +datagram_server(int serverfd) +{ + ssize_t len; + char c; + + while (1) { + len = recv(serverfd, &c, sizeof(c), 0); + if (len < 0) + warn("datagram_server: recv"); + } +} + +static void +datagram_client(void) +{ + struct sockaddr_un sun; + ssize_t len; + char c = 0; + int fd, i; + + bzero(&sun, sizeof(sun)); + sun.sun_len = sizeof(sun); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, socket_path); + for (i = 0; i < ITERATIONS; i++) { + fd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) { + warn("datagram_client: socket"); + return; + } + len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun, + sizeof(sun)); + if (len < 0) + warn("datagram_client: sendto"); + close(fd); + } +} + +static void +datagram_test(void) +{ + struct sockaddr_un sun; + pid_t childpid; + int serverfd; + + serverfd = socket(PF_UNIX, SOCK_DGRAM, 0); + if (serverfd < 0) + err(-1, "datagram_test: socket"); + + bzero(&sun, sizeof(sun)); + sun.sun_len = sizeof(sun); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, socket_path); + + if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) + err(-1, "datagram_test: bind"); + + childpid = fork(); + if (childpid < 0) + err(-1, "datagram_test: fork"); + + if (childpid != 0) { + sleep(1); + datagram_client(); + kill(childpid, SIGTERM); + sleep(1); + } else + datagram_server(serverfd); + + (void)unlink(socket_path); +} + +int +main(void) +{ + + if (mkstemp(socket_path) == -1) + err(1, "mkstemp failed"); + (void)unlink(socket_path); + datagram_test(); + if (0) + stream_test(); + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_sendtorace_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_socket_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_socket_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_socket_test.c (revision 281516) @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2006 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$ + */ + +/* + * Simple UNIX domain socket regression test: create and tear down various + * supported and unsupported socket types. + */ + +#include +#include +#include + +#include +#include +#include + +int +main(void) +{ + int sock, socks[2]; + + sock = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + err(-1, "socket(PF_LOCAL, SOCK_STREAM, 0)"); + close(sock); + + sock = socket(PF_LOCAL, SOCK_DGRAM, 0); + if (sock < 0) + err(-1, "socket(PF_LOCAL, SOCK_DGRAM, 0)"); + close(sock); + + sock = socket(PF_LOCAL, SOCK_RAW, 0); + if (sock >= 0) { + close(sock); + errx(-1, "socket(PF_LOCAL, SOCK_RAW, 0) returned %d", sock); + } + if (errno != EPROTONOSUPPORT) + err(-1, "socket(PF_LOCAL, SOCK_RAW, 0)"); + + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, socks) < 0) + err(-1, "socketpair(PF_LOCAL, SOCK_STREAM, 0, socks)"); + if (socks[0] < 0) + errx(-1, "socketpair(PF_LOCAL, SOCK_STREAM, 0, socks) [0] < 0"); + if (socks[1] < 0) + errx(-1, "socketpair(PF_LOCAL, SOCK_STREAM, 0, socks) [1] < 1"); + close(socks[0]); + close(socks[1]); + + if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks) < 0) + err(-1, "socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks)"); + if (socks[0] < 0) + errx(-1, "socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks) [0] < 0"); + if (socks[1] < 0) + errx(-1, "socketpair(PF_LOCAL, SOCK_DGRAM, 0, socks) [1] < 1"); + close(socks[0]); + close(socks[1]); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_socket_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/unix_sorflush_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_sorflush_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/unix_sorflush_test.c (revision 281516) @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2008 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. + */ + +/* + * Reproduce a race in which: + * + * - Process (a) is blocked in read on a socket waiting on data. + * - Process (b) is blocked in shutdown() on a socket waiting on (a). + * - Process (c) delivers a signal to (b) interrupting its wait. + * + * This race is premised on shutdown() not interrupting (a) properly, and the + * signal to (b) causing problems in the kernel. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include + +static void +receive_and_exit(int s) +{ + ssize_t ssize; + char ch; + + ssize = recv(s, &ch, sizeof(ch), 0); + if (ssize < 0) + err(-1, "receive_and_exit: recv"); + exit(0); +} + +static void +shutdown_and_exit(int s) +{ + + if (shutdown(s, SHUT_RD) < 0) + err(-1, "shutdown_and_exit: shutdown"); + exit(0); +} + +int +main(void) +{ + pid_t pida, pidb; + int sv[2]; + + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) < 0) + err(-1, "socketpair"); + + pida = fork(); + if (pida < 0) + err(-1, "fork"); + if (pida == 0) + receive_and_exit(sv[1]); + sleep(1); + pidb = fork(); + if (pidb < 0) { + warn("fork"); + (void)kill(pida, SIGKILL); + exit(-1); + } + if (pidb == 0) + shutdown_and_exit(sv[1]); + sleep(1); + if (kill(pidb, SIGKILL) < 0) + err(-1, "kill"); + sleep(1); + printf("ok 1 - unix_sorflush\n"); + exit(0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/unix_sorflush_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/socket/zerosend_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/zerosend_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/socket/zerosend_test.c (revision 281516) @@ -0,0 +1,290 @@ +/*- + * 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 + +#define PORT1 10001 +#define PORT2 10002 + +static void +try_0send(const char *test, int fd) +{ + ssize_t len; + char ch; + + ch = 0; + len = send(fd, &ch, 0, 0); + if (len < 0) + err(-1, "%s: try_0send", test); + if (len != 0) + errx(-1, "%s: try_0send: returned %zd", test, len); +} + +static void +try_0write(const char *test, int fd) +{ + ssize_t len; + char ch; + + ch = 0; + len = write(fd, &ch, 0); + if (len < 0) + err(-1, "%s: try_0write", test); + if (len != 0) + errx(-1, "%s: try_0write: returned %zd", test, len); +} + +static void +setup_udp(const char *test, int *fdp) +{ + struct sockaddr_in sin; + int sock1, sock2; + + 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(PORT1); + sock1 = socket(PF_INET, SOCK_DGRAM, 0); + if (sock1 < 0) + err(-1, "%s: setup_udp: socket", test); + if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) + err(-1, "%s: setup_udp: bind(%s, %d)", test, + inet_ntoa(sin.sin_addr), PORT1); + sin.sin_port = htons(PORT2); + if (connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) + err(-1, "%s: setup_udp: connect(%s, %d)", test, + inet_ntoa(sin.sin_addr), PORT2); + + sock2 = socket(PF_INET, SOCK_DGRAM, 0); + if (sock2 < 0) + err(-1, "%s: setup_udp: socket", test); + if (bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) + err(-1, "%s: setup_udp: bind(%s, %d)", test, + inet_ntoa(sin.sin_addr), PORT2); + sin.sin_port = htons(PORT1); + if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0) + err(-1, "%s: setup_udp: connect(%s, %d)", test, + inet_ntoa(sin.sin_addr), PORT1); + + fdp[0] = sock1; + fdp[1] = sock2; +} + +static void +setup_tcp(const char *test, int *fdp) +{ + fd_set writefds, exceptfds; + struct sockaddr_in sin; + int 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); + + /* + * First set up the listen socket. + */ + sin.sin_port = htons(PORT1); + sock1 = socket(PF_INET, SOCK_STREAM, 0); + if (sock1 < 0) + err(-1, "%s: setup_tcp: socket", test); + if (bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) < 0) + err(-1, "%s: bind(%s, %d)", test, inet_ntoa(sin.sin_addr), + PORT1); + if (listen(sock1, -1) < 0) + err(-1, "%s: listen", test); + + /* + * Now connect to it, non-blocking so that we don't deadlock against + * ourselves. + */ + sock2 = socket(PF_INET, SOCK_STREAM, 0); + if (sock2 < 0) + err(-1, "%s: setup_tcp: socket", test); + if (fcntl(sock2, F_SETFL, O_NONBLOCK) < 0) + err(-1, "%s: setup_tcp: fcntl(O_NONBLOCK)", test); + if (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) < 0 && + errno != EINPROGRESS) + err(-1, "%s: setup_tcp: connect(%s, %d)", test, + inet_ntoa(sin.sin_addr), PORT1); + + /* + * Now pick up the connection after sleeping a moment to make sure + * there's been time for some packets to go back and forth. + */ + if (sleep(1) < 0) + err(-1, "%s: sleep(1)", test); + sock3 = accept(sock1, NULL, NULL); + if (sock3 < 0) + err(-1, "%s: accept", test); + if (sleep(1) < 0) + err(-1, "%s: sleep(1)", test); + + 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); + if (ret < 0) + err(-1, "%s: setup_tcp: select", test); + if (FD_ISSET(sock2, &exceptfds)) + errx(-1, "%s: setup_tcp: select: exception", test); + if (!FD_ISSET(sock2, &writefds)) + errx(-1, "%s: setup_tcp: select: not writable", test); + + close(sock1); + fdp[0] = sock2; + fdp[1] = sock3; +} + +static void +setup_udsstream(const char *test, int *fdp) +{ + + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) < 0) + err(-1, "%s: setup_udsstream: socketpair", test); +} + +static void +setup_udsdgram(const char *test, int *fdp) +{ + + if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) < 0) + err(-1, "%s: setup_udsdgram: socketpair", test); +} + +static void +setup_pipe(const char *test, int *fdp) +{ + + if (pipe(fdp) < 0) + err(-1, "%s: setup_pipe: pipe", test); +} + +static void +setup_fifo(const char *test, int *fdp) +{ + char path[] = "0send_fifo.XXXXXXX"; + int fd1, fd2; + + if (mkstemp(path) == -1) + err(-1, "%s: setup_fifo: mktemp", test); + unlink(path); + + if (mkfifo(path, 0600) < 0) + err(-1, "%s: setup_fifo: mkfifo(%s)", test, path); + + fd1 = open(path, O_RDONLY | O_NONBLOCK); + if (fd1 < 0) + err(-1, "%s: setup_fifo: open(%s, O_RDONLY)", test, path); + + fd2 = open(path, O_WRONLY | O_NONBLOCK); + if (fd2 < 0) + err(-1, "%s: setup_fifo: open(%s, O_WRONLY)", test, path); + + fdp[0] = fd2; + fdp[1] = fd1; +} + +static void +close_both(int *fdp) +{ + + close(fdp[0]); + fdp[0] = -1; + close(fdp[1]); + fdp[1] = -1; +} + +int +main(int argc, char *argv[]) +{ + int fd[2]; + + setup_udp("udp_0send", fd); + try_0send("udp_0send", fd[0]); + close_both(fd); + + setup_udp("udp_0write", fd); + try_0write("udp_0write", fd[0]); + close_both(fd); + + setup_tcp("tcp_0send", fd); + try_0send("tcp_0send", fd[0]); + close_both(fd); + + setup_tcp("tcp_0write", fd); + try_0write("tcp_0write", fd[0]); + close_both(fd); + + setup_udsstream("udsstream_0send", fd); + try_0send("udsstream_0send", fd[0]); + close_both(fd); + + setup_udsstream("udsstream_0write", fd); + try_0write("udsstream_0write", fd[0]); + close_both(fd); + + setup_udsdgram("udsdgram_0send", fd); + try_0send("udsdgram_0send", fd[0]); + close_both(fd); + + setup_udsdgram("udsdgram_0write", fd); + try_0write("udsdgram_0write", fd[0]); + close_both(fd); + + setup_pipe("pipe_0write", fd); + try_0write("pipd_0write", fd[0]); + close_both(fd); + + setup_fifo("fifo_0write", fd); + try_0write("fifo_0write", fd[0]); + close_both(fd); + + return (0); +} Property changes on: user/ngie/more-tests/tests/sys/socket/zerosend_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property