Index: user/ngie/more-tests/etc/mtree/BSD.tests.dist =================================================================== --- user/ngie/more-tests/etc/mtree/BSD.tests.dist (revision 281423) +++ user/ngie/more-tests/etc/mtree/BSD.tests.dist (revision 281424) @@ -1,568 +1,570 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin cat .. chown .. date .. expr .. mv .. pax .. pkill .. sh builtins .. errors .. execution .. expansion .. parameters .. parser .. set-e .. .. sleep .. test .. .. cddl lib .. sbin .. usr.bin .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. .. .. .. etc rc.d .. .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. inet .. locale .. net getaddrinfo data .. .. .. regex data .. .. ssp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcrypt .. libmp .. libnv .. libpam .. libproc .. librt .. libthr dlopen .. .. libutil .. msun .. .. libexec atf atf-check .. atf-sh .. .. rtld-elf .. .. sbin dhclient .. devd .. growfs .. ifconfig .. mdconfig .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. plain .. .. .. .. sys kern .. netinet .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. .. + socket + .. .. usr.bin apply .. basename .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. calendar .. cmp .. comm .. cut .. dirname .. file2c .. grep .. gzip .. join .. jot .. lastcomm .. m4 .. mkimg .. ncal .. opensm .. printf .. sed regress.multitest.out .. .. timeout .. tr .. truncate .. units .. uudecode .. uuencode .. xargs .. yacc yacc .. .. .. usr.sbin etcupdate .. newsyslog .. nmtree .. pw .. sa .. .. .. # vim: set expandtab ts=4 sw=4: Index: user/ngie/more-tests/tests/sys/sockets/Makefile =================================================================== --- user/ngie/more-tests/tests/sys/sockets/Makefile (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/Makefile (revision 281424) @@ -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/sockets/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/sockets/README.unix_cmsg =================================================================== --- user/ngie/more-tests/tests/sys/sockets/README.unix_cmsg (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/README.unix_cmsg (revision 281424) @@ -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/sockets/README.unix_cmsg ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/accept_fd_leak_test.c (revision 281424) @@ -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/sockets/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/sockets/accf_data_attach_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/accf_data_attach_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/accf_data_attach_test.c (revision 281424) @@ -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/sockets/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/sockets/fstat_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/fstat_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/fstat_test.c (revision 281424) @@ -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/sockets/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/sockets/kqueue_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/kqueue_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/kqueue_test.c (revision 281424) @@ -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/sockets/kqueue_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/listen_backlog_test.c (revision 281424) @@ -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/sockets/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/sockets/listenclose_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/listenclose_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/listenclose_test.c (revision 281424) @@ -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/sockets/listenclose_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/pr_atomic_test.c (revision 281424) @@ -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/sockets/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/sockets/reconnect_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/reconnect_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/reconnect_test.c (revision 281424) @@ -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/sockets/reconnect_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/rtsocket_test.c (revision 281424) @@ -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/sockets/rtsocket_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/sblock_test.c (revision 281424) @@ -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/sockets/sblock_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/sendfile_test.c (revision 281424) @@ -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/sockets/sendfile_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/shutdown_test.c (revision 281424) @@ -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/sockets/shutdown_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ 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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/sigpipe_test.c (revision 281424) @@ -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/sockets/sigpipe_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/so_setfib_test.c (revision 281424) @@ -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/sockets/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/sockets/socketpair_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/socketpair_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/socketpair_test.c (revision 281424) @@ -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/sockets/socketpair_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_bindconnect_test.c (revision 281424) @@ -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/sockets/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/sockets/unix_close_race_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_close_race_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_close_race_test.c (revision 281424) @@ -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/sockets/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/sockets/unix_cmsg.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_cmsg.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_cmsg.c (revision 281424) @@ -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/sockets/unix_cmsg.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +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 (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_cmsg_test.sh (revision 281424) @@ -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/sockets/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/sockets/unix_gc_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_gc_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_gc_test.c (revision 281424) @@ -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/sockets/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/sockets/unix_passfd_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_passfd_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_passfd_test.c (revision 281424) @@ -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/sockets/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/sockets/unix_sendtorace_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_sendtorace_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_sendtorace_test.c (revision 281424) @@ -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/sockets/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/sockets/unix_socket_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_socket_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_socket_test.c (revision 281424) @@ -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/sockets/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/sockets/unix_sorflush_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/unix_sorflush_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/unix_sorflush_test.c (revision 281424) @@ -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/sockets/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/sockets/zerosend_test.c =================================================================== --- user/ngie/more-tests/tests/sys/sockets/zerosend_test.c (nonexistent) +++ user/ngie/more-tests/tests/sys/sockets/zerosend_test.c (revision 281424) @@ -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/sockets/zerosend_test.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/rtsocket/rtsocket.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/rtsocket/rtsocket.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/rtsocket/rtsocket.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/tools/regression/sockets/rtsocket/rtsocket.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/rtsocket/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/rtsocket/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/rtsocket/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= rtsocket -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/rtsocket/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/listenclose/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/listenclose/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/listenclose/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= listenclose -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/listenclose/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/listenclose/listenclose.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/listenclose/listenclose.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/listenclose/listenclose.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/tools/regression/sockets/listenclose/listenclose.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_socket/unix_socket.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_socket/unix_socket.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_socket/unix_socket.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/tools/regression/sockets/unix_socket/unix_socket.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_socket/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_socket/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_socket/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_socket -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_socket/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/sigpipe/sigpipe.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/sigpipe/sigpipe.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/sigpipe/sigpipe.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/tools/regression/sockets/sigpipe/sigpipe.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/sigpipe/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/sigpipe/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/sigpipe/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= sigpipe -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/sigpipe/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_cmsg/README =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_cmsg/README (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_cmsg/README (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/tools/regression/sockets/unix_cmsg/README ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_cmsg/unix_cmsg.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_cmsg/unix_cmsg.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_cmsg/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/tools/regression/sockets/unix_cmsg/unix_cmsg.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_cmsg/unix_cmsg.t =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_cmsg/unix_cmsg.t (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_cmsg/unix_cmsg.t (nonexistent) @@ -1,88 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` -cmd="./`basename $0 .t`" - -make ${cmd} >/dev/null 2>&1 - -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/tools/regression/sockets/unix_cmsg/unix_cmsg.t ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_cmsg/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_cmsg/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_cmsg/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_cmsg -MAN= -WARNS?= 3 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_cmsg/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/listen_backlog/listen_backlog.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/listen_backlog/listen_backlog.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/listen_backlog/listen_backlog.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/tools/regression/sockets/listen_backlog/listen_backlog.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/listen_backlog/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/listen_backlog/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/listen_backlog/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= listen_backlog -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/listen_backlog/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/sendfile/sendfile.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/sendfile/sendfile.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/sendfile/sendfile.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/tools/regression/sockets/sendfile/sendfile.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/sendfile/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/sendfile/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/sendfile/Makefile (nonexistent) @@ -1,11 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= sendfile -MAN= -WARNS?= 6 -DPADD= ${LIBMD} -LDADD= -lmd - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/sendfile/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_sorflush/unix_sorflush.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_sorflush/unix_sorflush.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_sorflush/unix_sorflush.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/tools/regression/sockets/unix_sorflush/unix_sorflush.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_sorflush/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_sorflush/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_sorflush/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_sorflush -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_sorflush/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_close_race/unix_close_race.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_close_race/unix_close_race.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_close_race/unix_close_race.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/tools/regression/sockets/unix_close_race/unix_close_race.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/tools/regression/sockets/unix_close_race/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_close_race/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_close_race/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_close_race -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_close_race/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/tools/regression/sockets/pr_atomic/pr_atomic.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/pr_atomic/pr_atomic.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/pr_atomic/pr_atomic.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/tools/regression/sockets/pr_atomic/pr_atomic.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/pr_atomic/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/pr_atomic/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/pr_atomic/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= pr_atomic -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/pr_atomic/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/shutdown/shutdown.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/shutdown/shutdown.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/shutdown/shutdown.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/tools/regression/sockets/shutdown/shutdown.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/shutdown/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/shutdown/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/shutdown/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= shutdown -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/shutdown/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_gc/unix_gc.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_gc/unix_gc.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_gc/unix_gc.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/tools/regression/sockets/unix_gc/unix_gc.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_gc/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_gc/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_gc/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_gc -MAN= -WARNS?= 3 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_gc/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/fstat/fstat.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/fstat/fstat.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/fstat/fstat.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/tools/regression/sockets/fstat/fstat.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/tools/regression/sockets/fstat/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/fstat/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/fstat/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= fstat -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/fstat/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/tools/regression/sockets/unix_passfd/unix_passfd.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_passfd/unix_passfd.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_passfd/unix_passfd.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/tools/regression/sockets/unix_passfd/unix_passfd.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_passfd/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_passfd/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_passfd/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_passfd -MAN= -WARNS?= 3 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_passfd/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/unix_bindconnect.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/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_bindconnect -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_bindconnect/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/sblock/sblock.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/sblock/sblock.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/sblock/sblock.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/tools/regression/sockets/sblock/sblock.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/sblock/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/sblock/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/sblock/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= sblock -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/sblock/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/reconnect/reconnect.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/reconnect/reconnect.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/reconnect/reconnect.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/tools/regression/sockets/reconnect/reconnect.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/reconnect/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/reconnect/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/reconnect/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= reconnect -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/reconnect/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.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/tools/regression/sockets/accf_data_attach/accf_data_attach.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.t =================================================================== --- user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.t (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.t (nonexistent) @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable Property changes on: user/ngie/more-tests/tools/regression/sockets/accf_data_attach/accf_data_attach.t ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/accf_data_attach/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/accf_data_attach/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/accf_data_attach/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= accf_data_attach -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/accf_data_attach/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.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/tools/regression/sockets/accept_fd_leak/accept_fd_leak.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.t =================================================================== --- user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.t (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.t (nonexistent) @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable Property changes on: user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/accept_fd_leak.t ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= accept_fd_leak -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/accept_fd_leak/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/socketpair/socketpair.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/socketpair/socketpair.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/socketpair/socketpair.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/tools/regression/sockets/socketpair/socketpair.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/socketpair/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/socketpair/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/socketpair/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= socketpair -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/socketpair/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/so_setfib/so_setfib.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/so_setfib/so_setfib.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/so_setfib/so_setfib.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/tools/regression/sockets/so_setfib/so_setfib.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/tools/regression/sockets/so_setfib/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/so_setfib/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/so_setfib/Makefile (nonexistent) @@ -1,16 +0,0 @@ -# $FreeBSD$ - -.include - -PROG= so_setfib -MAN= -WARNS?= 6 - -.if ${MK_INET} != "no" -CFLAGS+= -DINET -.endif -.if ${MK_INET6} != "no" -CFLAGS+= -DINET6 -.endif - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/so_setfib/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/tools/regression/sockets/zerosend/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/zerosend/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/zerosend/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= zerosend -MAN= -WARNS?= 2 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/zerosend/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/zerosend/zerosend.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/zerosend/zerosend.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/zerosend/zerosend.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/tools/regression/sockets/zerosend/zerosend.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/unix_sendtorace.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/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/Makefile (nonexistent) @@ -1,7 +0,0 @@ -# $FreeBSD$ - -PROG= unix_sendtorace -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/unix_sendtorace/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.c =================================================================== --- user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.c (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.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/tools/regression/sockets/kqueue/kqueue.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.t =================================================================== --- user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.t (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.t (nonexistent) @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable Property changes on: user/ngie/more-tests/tools/regression/sockets/kqueue/kqueue.t ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: user/ngie/more-tests/tools/regression/sockets/kqueue/Makefile =================================================================== --- user/ngie/more-tests/tools/regression/sockets/kqueue/Makefile (revision 281423) +++ user/ngie/more-tests/tools/regression/sockets/kqueue/Makefile (nonexistent) @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= kqueue -MAN= -WARNS?= 6 - -.include Property changes on: user/ngie/more-tests/tools/regression/sockets/kqueue/Makefile ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property