diff options
-rw-r--r-- | Makefile.inc1 | 2 | ||||
-rw-r--r-- | etc/mtree/BSD.tests.dist | 4 | ||||
-rw-r--r-- | tests/sys/Makefile | 13 | ||||
-rw-r--r-- | tests/sys/kern/Makefile | 10 | ||||
-rw-r--r-- | tests/sys/kern/unix_seqpacket_test.c | 1117 | ||||
-rw-r--r-- | tools/regression/sockets/unix_seqpacket/Makefile | 9 | ||||
-rw-r--r-- | tools/regression/sockets/unix_seqpacket/unix_seqpacket.c | 140 | ||||
-rw-r--r-- | tools/regression/sockets/unix_seqpacket_exercise/Makefile | 9 | ||||
-rw-r--r-- | tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c | 435 |
9 files changed, 1145 insertions, 594 deletions
diff --git a/Makefile.inc1 b/Makefile.inc1 index a06c34a..e4ef1e5 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -417,7 +417,7 @@ LIB32WMAKEFLAGS+= \ -DNO_LINT LIB32WMAKE= ${LIB32WMAKEENV} ${MAKE} ${LIB32WMAKEFLAGS} \ - -DWITHOUT_MAN -DWITHOUT_INFO -DWITHOUT_HTML + -DWITHOUT_MAN -DWITHOUT_INFO -DWITHOUT_HTML -DNO_TESTS LIB32IMAKE= ${LIB32WMAKE:NINSTALL=*:NDESTDIR=*:N_LDSCRIPTROOT=*} -DNO_INCS \ ${IMAKE_INSTALL} .endif diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 2d5d8a9..037c997 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -78,6 +78,10 @@ .. .. .. + sys + kern + .. + .. usr.bin atf atf-sh diff --git a/tests/sys/Makefile b/tests/sys/Makefile new file mode 100644 index 0000000..cb41472 --- /dev/null +++ b/tests/sys/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/sys + +KYUAFILE= yes + +CLEANFILES+= Kyuafile +Kyuafile: ${.CURDIR}/../Kyuafile + cp -f ${.CURDIR}/../Kyuafile . + +.include <bsd.test.mk> diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile new file mode 100644 index 0000000..576e7d2 --- /dev/null +++ b/tests/sys/kern/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/sys/kern + +ATF_TESTS_C= unix_seqpacket_test +TEST_METADATA.unix_seqpacket_test+= timeout="15" + +LDADD+= -lpthread + +.include <atf.test.mk> diff --git a/tests/sys/kern/unix_seqpacket_test.c b/tests/sys/kern/unix_seqpacket_test.c new file mode 100644 index 0000000..5b8632d --- /dev/null +++ b/tests/sys/kern/unix_seqpacket_test.c @@ -0,0 +1,1117 @@ +/*- + * Copyright (c) 2014 Spectra Logic Corporation. 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 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 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <stdio.h> + +#include <atf-c.h> + +/* + * Helper functions + */ + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +void +do_socketpair(int *sv) +{ + int s; + + s = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv); + ATF_REQUIRE_EQ(0, s); + ATF_REQUIRE(sv[0] >= 0); + ATF_REQUIRE(sv[1] >= 0); + ATF_REQUIRE(sv[0] != sv[1]); +} + +void +do_socketpair_nonblocking(int *sv) +{ + int s; + + s = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv); + ATF_REQUIRE_EQ(0, s); + ATF_REQUIRE(sv[0] >= 0); + ATF_REQUIRE(sv[1] >= 0); + ATF_REQUIRE(sv[0] != sv[1]); + ATF_REQUIRE(-1 != fcntl(sv[0], F_SETFL, O_NONBLOCK)); + ATF_REQUIRE(-1 != fcntl(sv[1], F_SETFL, O_NONBLOCK)); +} + +/* + * Returns a pair of sockets made the hard way: bind, listen, connect & accept + * @return const char* The path to the socket + */ +const char* +mk_pair_of_sockets(int *sv) +{ + struct sockaddr_un sun; + /* ATF's isolation mechanisms will guarantee uniqueness of this file */ + const char *path = "sock"; + int s, err, s2, s1; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s >= 0); + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_LOCAL; + sun.sun_len = sizeof(sun); + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + err = bind(s, (struct sockaddr *)&sun, sizeof(sun)); + err = listen(s, -1); + ATF_CHECK_EQ(0, err); + ATF_CHECK_EQ(0, err); + + /* Create the other socket */ + s2 = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s2 >= 0); + err = connect(s2, (struct sockaddr*)&sun, sizeof(sun)); + if (err != 0) { + perror("connect"); + atf_tc_fail("connect(2) failed"); + } + + /* Accept it */ + s1 = accept(s, NULL, NULL); + if (s1 == -1) { + perror("accept"); + atf_tc_fail("accept(2) failed"); + } + + sv[0] = s1; + sv[1] = s2; + return (path); +} + +static volatile sig_atomic_t got_sigpipe = 0; +static void +shutdown_send_sigpipe_handler(int x) +{ + got_sigpipe = 1; +} + +/* + * Parameterized test function bodies + */ +void +test_eagain(size_t sndbufsize, size_t rcvbufsize) +{ + int i; + int sv[2]; + const size_t totalsize = (sndbufsize + rcvbufsize) * 2; + const size_t pktsize = MIN(sndbufsize, rcvbufsize) / 4; + char sndbuf[pktsize]; + char recv_buf[pktsize]; + ssize_t ssize, rsize; + + /* setup the socket pair */ + do_socketpair(sv); + /* Setup the buffers */ + ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize, + sizeof(sndbufsize))); + ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize))); + + bzero(sndbuf, pktsize); + /* Send data until we get EAGAIN */ + for(i=0; i < totalsize / pktsize; i++) { + ssize = send(sv[0], sndbuf, pktsize, MSG_EOR); + if (ssize == -1) { + if (errno == EAGAIN) + atf_tc_pass(); + else { + perror("send"); + atf_tc_fail("send returned < 0 but not EAGAIN"); + } + } + } + atf_tc_fail("Never got EAGAIN"); +} + +void +test_sendrecv_symmetric_buffers(size_t bufsize, int blocking) { + int s; + int sv[2]; + const size_t pktsize = bufsize / 2; + char sndbuf[pktsize]; + char recv_buf[pktsize]; + ssize_t ssize, rsize; + + /* setup the socket pair */ + if (blocking) + do_socketpair(sv); + else + do_socketpair_nonblocking(sv); + + /* Setup the buffers */ + s = setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); + ATF_REQUIRE_EQ(0, s); + s = setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)); + ATF_REQUIRE_EQ(0, s); + + /* Fill the send buffer */ + bzero(sndbuf, pktsize); + + /* send and receive the packet */ + ssize = send(sv[0], sndbuf, pktsize, MSG_EOR); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(pktsize, ssize, "expected %zd=send(...) but got %zd", + pktsize, ssize); + + rsize = recv(sv[1], recv_buf, pktsize, MSG_WAITALL); + if (rsize < 0) { + perror("recv"); + atf_tc_fail("recv returned < 0"); + } + ATF_CHECK_EQ_MSG(pktsize, rsize, "expected %zd=send(...) but got %zd", + pktsize, rsize); +} + +void +test_pipe_simulator(size_t sndbufsize, size_t rcvbufsize) +{ + int s, num_sent, num_received; + int sv[2]; + const size_t pktsize = MIN(sndbufsize, rcvbufsize) / 4; + int numpkts; + char sndbuf[pktsize]; + char rcvbuf[pktsize]; + char comparebuf[pktsize]; + ssize_t ssize, rsize; + bool currently_sending = true; + + /* setup the socket pair */ + do_socketpair_nonblocking(sv); + /* Setup the buffers */ + ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize, + sizeof(sndbufsize))); + ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize))); + + /* Send a total amount of data comfortably greater than the buffers */ + numpkts = MAX(sndbufsize, rcvbufsize) * 8 / pktsize; + for (num_sent=0, num_received=0; + num_sent < numpkts || num_received < numpkts; ) { + if (currently_sending && num_sent < numpkts) { + /* The simulated sending process */ + /* fill the buffer */ + memset(sndbuf, num_sent, pktsize); + ssize = send(sv[0], sndbuf, pktsize, MSG_EOR); + if (ssize < 0) { + /* + * XXX: This is bug-compatible with the kernel. + * The kernel returns EMSGSIZE when it should + * return EAGAIN + */ + if (errno == EAGAIN || errno == EMSGSIZE) + currently_sending = false; + else { + perror("send"); + atf_tc_fail("send failed"); + } + } else { + ATF_CHECK_EQ_MSG(pktsize, ssize, + "expected %zd=send(...) but got %zd", + pktsize, ssize); + num_sent++; + } + } else { + /* The simulated receiving process */ + rsize = recv(sv[1], rcvbuf, pktsize, MSG_WAITALL); + if (rsize < 0) { + if (errno == EAGAIN) { + currently_sending = true; + ATF_REQUIRE_MSG(num_sent < numpkts, + "Packets were lost!"); + } + else { + perror("recv"); + atf_tc_fail("recv failed"); + } + } else { + ATF_CHECK_EQ_MSG(pktsize, rsize, + "expected %zd=recv(...) but got %zd", + pktsize, rsize); + memset(comparebuf, num_received, pktsize); + ATF_CHECK_EQ_MSG(0, memcmp(comparebuf, rcvbuf, + pktsize), + "Received data miscompare"); + num_received++; + } + } + } +} + +typedef struct { + ssize_t pktsize; + int numpkts; + int so; +} test_pipe_thread_data_t; + +static void* +test_pipe_writer(void* args) +{ + test_pipe_thread_data_t* td = args; + char sndbuf[td->pktsize]; + ssize_t ssize; + int i; + + for(i=0; i < td->numpkts; i++) { + memset(sndbuf, i, td->pktsize); + ssize = send(td->so, sndbuf, td->pktsize, MSG_EOR); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(td->pktsize, ssize, + "expected %zd=send(...) but got %zd", + td->pktsize, ssize); + } + return (0); +} + +static void* +test_pipe_reader(void* args) +{ + test_pipe_thread_data_t* td = args; + char rcvbuf[td->pktsize]; + char comparebuf[td->pktsize]; + ssize_t rsize; + int i, d; + + for(i=0; i < td->numpkts; i++) { + memset(comparebuf, i, td->pktsize); + rsize = recv(td->so, rcvbuf, td->pktsize, MSG_WAITALL); + if (rsize < 0) { + perror("recv"); + atf_tc_fail("recv returned < 0"); + } + ATF_CHECK_EQ_MSG(td->pktsize, rsize, + "expected %zd=send(...) but got %zd", + td->pktsize, rsize); + d = memcmp(comparebuf, rcvbuf, td->pktsize); + ATF_CHECK_EQ_MSG(0, d, + "Received data miscompare on packet %d", i); + } + return (0); +} + + +void +test_pipe(size_t sndbufsize, size_t rcvbufsize) +{ + test_pipe_thread_data_t writer_data, reader_data; + pthread_t writer, reader; + int num_sent, num_received; + int sv[2]; + const size_t pktsize = MIN(sndbufsize, rcvbufsize) / 4; + int numpkts; + + /* setup the socket pair */ + do_socketpair(sv); + /* Setup the buffers */ + ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize, + sizeof(sndbufsize))); + ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize))); + + /* Send a total amount of data comfortably greater than the buffers */ + numpkts = MAX(sndbufsize, rcvbufsize) * 8 / pktsize; + + /* Start the child threads */ + writer_data.pktsize = pktsize; + writer_data.numpkts = numpkts; + writer_data.so = sv[0]; + reader_data.pktsize = pktsize; + reader_data.numpkts = numpkts; + reader_data.so = sv[1]; + ATF_REQUIRE_EQ(0, pthread_create(&writer, NULL, test_pipe_writer, + (void*)&writer_data)); + ATF_REQUIRE_EQ(0, pthread_create(&reader, NULL, test_pipe_reader, + (void*)&reader_data)); + + /* Join the children */ + ATF_REQUIRE_EQ(0, pthread_join(writer, NULL)); + ATF_REQUIRE_EQ(0, pthread_join(reader, NULL)); +} + + +/* + * Test Cases + */ + +/* Create a SEQPACKET socket */ +ATF_TC_WITHOUT_HEAD(create_socket); +ATF_TC_BODY(create_socket, tc) +{ + int s; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_CHECK(s >= 0); +} + +/* Create SEQPACKET sockets using socketpair(2) */ +ATF_TC_WITHOUT_HEAD(create_socketpair); +ATF_TC_BODY(create_socketpair, tc) +{ + int sv[2]; + int s; + + s = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv); + ATF_CHECK_EQ(0, s); + ATF_CHECK(sv[0] >= 0); + ATF_CHECK(sv[1] >= 0); + ATF_CHECK(sv[0] != sv[1]); +} + +/* Call listen(2) without first calling bind(2). It should fail */ +ATF_TC_WITHOUT_HEAD(listen_unbound); +ATF_TC_BODY(listen_unbound, tc) +{ + int s, r; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s > 0); + r = listen(s, -1); + /* expect listen to fail since we haven't called bind(2) */ + ATF_CHECK(r != 0); +} + +/* Bind the socket to a file */ +ATF_TC_WITHOUT_HEAD(bind); +ATF_TC_BODY(bind, tc) +{ + struct sockaddr_un sun; + /* ATF's isolation mechanisms will guarantee uniqueness of this file */ + const char *path = "sock"; + int s, r; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s >= 0); + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_LOCAL; + sun.sun_len = sizeof(sun); + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + r = bind(s, (struct sockaddr *)&sun, sizeof(sun)); + ATF_CHECK_EQ(0, r); +} + +/* listen(2) a socket that is already bound(2) should succeed */ +ATF_TC_WITHOUT_HEAD(listen_bound); +ATF_TC_BODY(listen_bound, tc) +{ + struct sockaddr_un sun; + /* ATF's isolation mechanisms will guarantee uniqueness of this file */ + const char *path = "sock"; + int s, r, l; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s >= 0); + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_LOCAL; + sun.sun_len = sizeof(sun); + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + r = bind(s, (struct sockaddr *)&sun, sizeof(sun)); + l = listen(s, -1); + ATF_CHECK_EQ(0, r); + ATF_CHECK_EQ(0, l); +} + +/* connect(2) can make a connection */ +ATF_TC_WITHOUT_HEAD(connect); +ATF_TC_BODY(connect, tc) +{ + struct sockaddr_un sun; + /* ATF's isolation mechanisms will guarantee uniqueness of this file */ + const char *path = "sock"; + int s, r, err, l, s2; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s >= 0); + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_LOCAL; + sun.sun_len = sizeof(sun); + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + r = bind(s, (struct sockaddr *)&sun, sizeof(sun)); + l = listen(s, -1); + ATF_CHECK_EQ(0, r); + ATF_CHECK_EQ(0, l); + + /* Create the other socket */ + s2 = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s2 >= 0); + err = connect(s2, (struct sockaddr*)&sun, sizeof(sun)); + if (err != 0) { + perror("connect"); + atf_tc_fail("connect(2) failed"); + } +} + +/* accept(2) can receive a connection */ +ATF_TC_WITHOUT_HEAD(accept); +ATF_TC_BODY(accept, tc) +{ + int sv[2]; + + mk_pair_of_sockets(sv); +} + + +/* Set O_NONBLOCK on the socket */ +ATF_TC_WITHOUT_HEAD(fcntl_nonblock); +ATF_TC_BODY(fcntl_nonblock, tc) +{ + int s; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s >= 0); + if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { + perror("fcntl"); + atf_tc_fail("fcntl failed"); + } +} + +/* Resize the send and receive buffers */ +ATF_TC_WITHOUT_HEAD(resize_buffers); +ATF_TC_BODY(resize_buffers, tc) +{ + int s; + int sndbuf = 12345; + int rcvbuf = 23456; + int xs, xr; + socklen_t sl = sizeof(xs); + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_REQUIRE(s >= 0); + + printf(" Socket Buffer Sizes\n"); + printf(" | SNDBUF | RCVBUF |\n"); + ATF_CHECK_EQ(0, getsockopt(s, SOL_SOCKET, SO_SNDBUF, &xs, &sl)); + ATF_CHECK_EQ(0, getsockopt(s, SOL_SOCKET, SO_RCVBUF, &xr, &sl)); + printf("Default | %7d | %7d |\n", xs, xr); + + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) != 0){ + perror("setsockopt"); + atf_tc_fail("setsockopt(SO_SNDBUF) failed"); + } + ATF_CHECK_EQ(0, getsockopt(s, SOL_SOCKET, SO_SNDBUF, &xs, &sl)); + ATF_CHECK_EQ(0, getsockopt(s, SOL_SOCKET, SO_RCVBUF, &xr, &sl)); + printf("After changing SNDBUF | %7d | %7d |\n", xs, xr); + + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) != 0){ + perror("setsockopt"); + atf_tc_fail("setsockopt(SO_RCVBUF) failed"); + } + ATF_CHECK_EQ(0, getsockopt(s, SOL_SOCKET, SO_SNDBUF, &xs, &sl)); + ATF_CHECK_EQ(0, getsockopt(s, SOL_SOCKET, SO_RCVBUF, &xr, &sl)); + printf("After changing RCVBUF | %7d | %7d |\n", xs, xr); +} + +/* + * Resize the send and receive buffers of a connected socketpair + * Print some useful debugging info too + */ +ATF_TC_WITHOUT_HEAD(resize_connected_buffers); +ATF_TC_BODY(resize_connected_buffers, tc) +{ + int sv[2]; + int sndbuf = 12345; + int rcvbuf = 23456; + int err; + int ls, lr, rs, rr; + socklen_t sl = sizeof(ls); + + /* setup the socket pair */ + do_socketpair(sv); + + printf(" Socket Buffer Sizes\n"); + printf(" | Left Socket | Right Socket |\n"); + printf(" | SNDBUF | RCVBUF | SNDBUF | RCVBUF |\n"); + ATF_CHECK_EQ(0, getsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &ls, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &lr, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &rs, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rr, &sl)); + printf("Default | %7d | %7d | %7d | %7d |\n", + ls, lr, rs, rr); + + /* Update one side's send buffer */ + err = setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); + if (err != 0){ + perror("setsockopt"); + atf_tc_fail("setsockopt(SO_SNDBUF) failed"); + } + + ATF_CHECK_EQ(0, getsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &ls, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &lr, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &rs, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rr, &sl)); + printf("After changing Left's SNDBUF | %7d | %7d | %7d | %7d |\n", + ls, lr, rs, rr); + + /* Update the same side's receive buffer */ + err = setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); + if (err != 0){ + perror("setsockopt"); + atf_tc_fail("setsockopt(SO_RCVBUF) failed"); + } + + ATF_CHECK_EQ(0, getsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &ls, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &lr, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &rs, &sl)); + ATF_CHECK_EQ(0, getsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rr, &sl)); + printf("After changing Left's RCVBUF | %7d | %7d | %7d | %7d |\n", + ls, lr, rs, rr); +} + + +/* send(2) and recv(2) a single short record */ +ATF_TC_WITHOUT_HEAD(send_recv); +ATF_TC_BODY(send_recv, tc) +{ + int s; + int sv[2]; + const int bufsize = 64; + const char *data = "data"; + char recv_buf[bufsize]; + size_t datalen; + ssize_t ssize, rsize; + + /* setup the socket pair */ + do_socketpair(sv); + + /* send and receive a small packet */ + datalen = strlen(data) + 1; /* +1 for the null */ + ssize = send(sv[0], data, datalen, MSG_EOR); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(datalen, ssize, "expected %zd=send(...) but got %zd", + datalen, ssize); + + rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL); + ATF_CHECK_EQ(datalen, rsize); +} + +/* sendto(2) and recvfrom(2) a single short record + * According to The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 + * Edition, sendto(2) is exactly the same as send(2) on a connection-mode socket + * + * According to the same spec, not all protocols are required to provide the + * source addres in recvfrom(2). + */ +ATF_TC_WITHOUT_HEAD(sendto_recvfrom); +ATF_TC_BODY(sendto_recvfrom, tc) +{ + const char* path; + struct sockaddr_storage from; + int s; + int sv[2]; + const int bufsize = 64; + const char *data = "data"; + char recv_buf[bufsize]; + size_t datalen; + ssize_t ssize, rsize; + socklen_t fromlen; + + /* setup the socket pair */ + path = mk_pair_of_sockets(sv); + + /* send and receive a small packet */ + datalen = strlen(data) + 1; /* +1 for the null */ + ssize = sendto(sv[0], data, datalen, MSG_EOR, NULL, 0); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(datalen, ssize, "expected %zd=send(...) but got %zd", + datalen, ssize); + + fromlen = sizeof(from); + rsize = recvfrom(sv[1], recv_buf, bufsize, MSG_WAITALL, + (struct sockaddr*)&from, &fromlen); + if (ssize < 0) { + perror("recvfrom"); + atf_tc_fail("recvfrom returned < 0"); + } + ATF_CHECK_EQ(datalen, rsize); + + /* + * FreeBSD does not currently provide the source address for SEQ_PACKET + * AF_UNIX sockets, and POSIX does not require it, so these two checks + * are disabled. If FreeBSD gains that feature in the future, then + * these checks may be reenabled + */ + /* ATF_CHECK_EQ(PF_LOCAL, from.ss_family); */ + /* ATF_CHECK_STREQ(path, ((struct sockaddr_un*)&from)->sun_path); */ +} + +/* + * send(2) and recv(2) a single short record with sockets created the + * traditional way, involving bind, listen, connect, and accept + */ +ATF_TC_WITHOUT_HEAD(send_recv_with_connect); +ATF_TC_BODY(send_recv_with_connect, tc) +{ + const char* path; + int sv[2]; + const int bufsize = 64; + const char *data = "data"; + char recv_buf[bufsize]; + size_t datalen; + ssize_t ssize, rsize; + + mk_pair_of_sockets(sv); + + /* send and receive a small packet */ + datalen = strlen(data) + 1; /* +1 for the null */ + ssize = send(sv[0], data, datalen, MSG_EOR); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(datalen, ssize, "expected %zd=send(...) but got %zd", + datalen, ssize); + + rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL); + ATF_CHECK_EQ(datalen, rsize); +} + +/* send(2) should fail on a shutdown socket */ +ATF_TC_WITHOUT_HEAD(shutdown_send); +ATF_TC_BODY(shutdown_send, tc) +{ + int s; + const char *data = "data"; + ssize_t ssize; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_CHECK(s >= 0); + ATF_CHECK_EQ(0, shutdown(s, SHUT_RDWR)); + /* USE MSG_NOSIGNAL so we don't get SIGPIPE */ + ssize = send(s, data, sizeof(data), MSG_EOR | MSG_NOSIGNAL); + ATF_CHECK_EQ(EPIPE, errno); + ATF_CHECK_EQ(-1, ssize); +} + +/* send(2) should cause SIGPIPE on a shutdown socket */ +ATF_TC_WITHOUT_HEAD(shutdown_send_sigpipe); +ATF_TC_BODY(shutdown_send_sigpipe, tc) +{ + int s; + const char *data = "data"; + ssize_t ssize; + + s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); + ATF_CHECK(s >= 0); + ATF_CHECK_EQ(0, shutdown(s, SHUT_RDWR)); + ATF_REQUIRE(SIG_ERR != signal(SIGPIPE, shutdown_send_sigpipe_handler)); + ssize = send(s, data, sizeof(data), MSG_EOR); + ATF_CHECK_EQ(1, got_sigpipe); +} + +/* nonblocking send(2) and recv(2) a single short record */ +ATF_TC_WITHOUT_HEAD(send_recv_nonblocking); +ATF_TC_BODY(send_recv_nonblocking, tc) +{ + int s; + int sv[2]; + const int bufsize = 64; + const char *data = "data"; + char recv_buf[bufsize]; + size_t datalen; + ssize_t ssize, rsize; + + /* setup the socket pair */ + do_socketpair_nonblocking(sv); + + /* Verify that there is nothing to receive */ + rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL); + ATF_CHECK_EQ(EAGAIN, errno); + ATF_CHECK_EQ(-1, rsize); + + /* send and receive a small packet */ + datalen = strlen(data) + 1; /* +1 for the null */ + ssize = send(sv[0], data, datalen, MSG_EOR); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(datalen, ssize, "expected %zd=send(...) but got %zd", + datalen, ssize); + + rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL); + ATF_CHECK_EQ(datalen, rsize); +} + +/* + * We should get EMSGSIZE if we try to send a message larger than the socket + * buffer, with blocking sockets + */ +ATF_TC_WITHOUT_HEAD(emsgsize); +ATF_TC_BODY(emsgsize, tc) +{ + int s; + int sv[2]; + const size_t sndbufsize = 8192; + const size_t rcvbufsize = 8192; + const size_t pktsize = (sndbufsize + rcvbufsize) * 2; + char sndbuf[pktsize]; + char recv_buf[pktsize]; + ssize_t ssize, rsize; + + /* setup the socket pair */ + do_socketpair(sv); + /* Setup the buffers */ + ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize, + sizeof(sndbufsize))); + ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize))); + + ssize = send(sv[0], sndbuf, pktsize, MSG_EOR); + ATF_CHECK_EQ(EMSGSIZE, errno); + ATF_CHECK_EQ(-1, ssize); +} + +/* + * We should get EMSGSIZE if we try to send a message larger than the socket + * buffer, with nonblocking sockets + */ +ATF_TC_WITHOUT_HEAD(emsgsize_nonblocking); +ATF_TC_BODY(emsgsize_nonblocking, tc) +{ + int s; + int sv[2]; + const size_t sndbufsize = 8192; + const size_t rcvbufsize = 8192; + const size_t pktsize = (sndbufsize + rcvbufsize) * 2; + char sndbuf[pktsize]; + char recv_buf[pktsize]; + ssize_t ssize, rsize; + + /* setup the socket pair */ + do_socketpair_nonblocking(sv); + /* Setup the buffers */ + ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize, + sizeof(sndbufsize))); + ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize, + sizeof(rcvbufsize))); + + ssize = send(sv[0], sndbuf, pktsize, MSG_EOR); + ATF_CHECK_EQ(EMSGSIZE, errno); + ATF_CHECK_EQ(-1, ssize); +} + + +/* + * We should get EAGAIN if we try to send a message larger than the socket + * buffer, with nonblocking sockets. Test with several different sockbuf sizes + */ +ATF_TC_WITHOUT_HEAD(eagain_8k_8k); +ATF_TC_BODY(eagain_8k_8k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_eagain(8192, 8192); +} +ATF_TC_WITHOUT_HEAD(eagain_8k_128k); +ATF_TC_BODY(eagain_8k_128k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_eagain(8192, 131072); +} +ATF_TC_WITHOUT_HEAD(eagain_128k_8k); +ATF_TC_BODY(eagain_128k_8k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_eagain(131072, 8192); +} +ATF_TC_WITHOUT_HEAD(eagain_128k_128k); +ATF_TC_BODY(eagain_128k_128k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_eagain(131072, 131072); +} + + +/* + * nonblocking send(2) and recv(2) of several records, which should collectively + * fill up the send buffer but not the receive buffer + */ +ATF_TC_WITHOUT_HEAD(rcvbuf_oversized); +ATF_TC_BODY(rcvbuf_oversized, tc) +{ + int s, i, j; + int sv[2]; + const size_t sndbufsize = 8192; + const size_t rcvbufsize = 131072; + const size_t geom_mean_bufsize = 32768; + const int pktsize = 1024; + char sndbuf[pktsize]; + char recv_buf[pktsize]; + size_t datalen; + ssize_t ssize, rsize; + + /* setup the socket pair */ + do_socketpair_nonblocking(sv); + + /* + * Send and receive packets that are collectively greater than the send + * buffer, but less than the receive buffer + */ + for (i=0; i < geom_mean_bufsize / pktsize; i++) { + /* Fill the buffer */ + memset(sndbuf, i, pktsize); + + /* send the packet */ + ssize = send(sv[0], sndbuf, pktsize, MSG_EOR); + if (ssize < 0) { + perror("send"); + atf_tc_fail("send returned < 0"); + } + ATF_CHECK_EQ_MSG(pktsize, ssize, + "expected %zd=send(...) but got %zd", pktsize, ssize); + + /* Receive it */ + + rsize = recv(sv[1], recv_buf, pktsize, MSG_WAITALL); + if (rsize < 0) { + perror("recv"); + atf_tc_fail("recv returned < 0"); + } + ATF_CHECK_EQ_MSG(pktsize, rsize, + "expected %zd=send(...) but got %zd", pktsize, rsize); + + /* Verify the contents */ + ATF_CHECK_EQ_MSG(0, memcmp(sndbuf, recv_buf, pktsize), + "Received data miscompare"); + } + + /* Trying to receive again should return EAGAIN */ + rsize = recv(sv[1], recv_buf, pktsize, MSG_WAITALL); + ATF_CHECK_EQ(EAGAIN, errno); + ATF_CHECK_EQ(-1, rsize); +} + +/* + * Simulate the behavior of a blocking pipe. The sender will send until his + * buffer fills up, then we'll simulate a scheduler switch that will allow the + * receiver to read until his buffer empties. Repeat the process until the + * transfer is complete. + * Repeat the test with multiple send and receive buffer sizes + */ +ATF_TC_WITHOUT_HEAD(pipe_simulator_8k_8k); +ATF_TC_BODY(pipe_simulator_8k_8k, tc) +{ + test_pipe_simulator(8192, 8192); +} + +ATF_TC_WITHOUT_HEAD(pipe_simulator_8k_128k); +ATF_TC_BODY(pipe_simulator_8k_128k, tc) +{ + test_pipe_simulator(8192, 131072); +} + +ATF_TC_WITHOUT_HEAD(pipe_simulator_128k_8k); +ATF_TC_BODY(pipe_simulator_128k_8k, tc) +{ + atf_tc_expect_fail("PR kern/185812 SOCK_SEQPACKET AF_UNIX sockets with asymmetrical buffers drop packets"); + test_pipe_simulator(131072, 8192); +} + +ATF_TC_WITHOUT_HEAD(pipe_simulator_128k_128k); +ATF_TC_BODY(pipe_simulator_128k_128k, tc) +{ + test_pipe_simulator(131072, 131072); +} + +/* + * Test blocking I/O by passing data between two threads. The total amount of + * data will be >> buffer size to force blocking. Repeat the test with multiple + * send and receive buffer sizes + */ +ATF_TC_WITHOUT_HEAD(pipe_8k_8k); +ATF_TC_BODY(pipe_8k_8k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_pipe(8192, 8192); +} + +ATF_TC_WITHOUT_HEAD(pipe_8k_128k); +ATF_TC_BODY(pipe_8k_128k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_pipe(8192, 131072); +} + +ATF_TC_WITHOUT_HEAD(pipe_128k_8k); +ATF_TC_BODY(pipe_128k_8k, tc) +{ + /* + * kern/185812 causes this test case to both fail and timeout. The + * atf-c-api(3) doesn't have a way to set such an expectation. + * If you use atf_tc_expect_fail, then it will timeout. If you use + * atf_tc_expect_timeout, then it will fail. If you use both, then it + * will show up as an unexpected pass, which is much worse + * + * https://code.google.com/p/kyua/issues/detail?id=76 + */ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_pipe(131072, 8192); +} + +ATF_TC_WITHOUT_HEAD(pipe_128k_128k); +ATF_TC_BODY(pipe_128k_128k, tc) +{ + atf_tc_expect_fail("PR kern/185812 send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN"); + test_pipe(131072, 131072); +} + + +/* + * Test single-packet I/O with and without blocking, with symmetric buffers of + * various sizes + */ +ATF_TC_WITHOUT_HEAD(sendrecv_8k); +ATF_TC_BODY(sendrecv_8k, tc) +{ + test_sendrecv_symmetric_buffers(8 * 1024, true); +} +ATF_TC_WITHOUT_HEAD(sendrecv_16k); +ATF_TC_BODY(sendrecv_16k, tc) +{ + test_sendrecv_symmetric_buffers(16 * 1024, true); +} +ATF_TC_WITHOUT_HEAD(sendrecv_32k); +ATF_TC_BODY(sendrecv_32k, tc) +{ + test_sendrecv_symmetric_buffers(32 * 1024, true); +} +ATF_TC_WITHOUT_HEAD(sendrecv_64k); +ATF_TC_BODY(sendrecv_64k, tc) +{ + test_sendrecv_symmetric_buffers(64 * 1024, true); +} +ATF_TC_WITHOUT_HEAD(sendrecv_128k); +ATF_TC_BODY(sendrecv_128k, tc) +{ + test_sendrecv_symmetric_buffers(128 * 1024, true); +} +ATF_TC_WITHOUT_HEAD(sendrecv_8k_nonblocking); +ATF_TC_BODY(sendrecv_8k_nonblocking, tc) +{ + test_sendrecv_symmetric_buffers(8 * 1024, false); +} +ATF_TC_WITHOUT_HEAD(sendrecv_16k_nonblocking); +ATF_TC_BODY(sendrecv_16k_nonblocking, tc) +{ + test_sendrecv_symmetric_buffers(16 * 1024, false); +} +ATF_TC_WITHOUT_HEAD(sendrecv_32k_nonblocking); +ATF_TC_BODY(sendrecv_32k_nonblocking, tc) +{ + test_sendrecv_symmetric_buffers(32 * 1024, false); +} +ATF_TC_WITHOUT_HEAD(sendrecv_64k_nonblocking); +ATF_TC_BODY(sendrecv_64k_nonblocking, tc) +{ + test_sendrecv_symmetric_buffers(64 * 1024, false); +} +ATF_TC_WITHOUT_HEAD(sendrecv_128k_nonblocking); +ATF_TC_BODY(sendrecv_128k_nonblocking, tc) +{ + test_sendrecv_symmetric_buffers(128 * 1024, false); +} + + +/* + * Main. + */ + +ATF_TP_ADD_TCS(tp) +{ + /* Basic creation and connection tests */ + ATF_TP_ADD_TC(tp, create_socket); + ATF_TP_ADD_TC(tp, create_socketpair); + ATF_TP_ADD_TC(tp, listen_unbound); + ATF_TP_ADD_TC(tp, bind); + ATF_TP_ADD_TC(tp, listen_bound); + ATF_TP_ADD_TC(tp, connect); + ATF_TP_ADD_TC(tp, accept); + ATF_TP_ADD_TC(tp, fcntl_nonblock); + ATF_TP_ADD_TC(tp, resize_buffers); + ATF_TP_ADD_TC(tp, resize_connected_buffers); + + /* Unthreaded I/O tests */ + ATF_TP_ADD_TC(tp, send_recv); + ATF_TP_ADD_TC(tp, send_recv_nonblocking); + ATF_TP_ADD_TC(tp, send_recv_with_connect); + ATF_TP_ADD_TC(tp, sendto_recvfrom); + ATF_TP_ADD_TC(tp, shutdown_send); + ATF_TP_ADD_TC(tp, shutdown_send_sigpipe); + ATF_TP_ADD_TC(tp, emsgsize); + ATF_TP_ADD_TC(tp, emsgsize_nonblocking); + ATF_TP_ADD_TC(tp, eagain_8k_8k); + ATF_TP_ADD_TC(tp, eagain_8k_128k); + ATF_TP_ADD_TC(tp, eagain_128k_8k); + ATF_TP_ADD_TC(tp, eagain_128k_128k); + ATF_TP_ADD_TC(tp, sendrecv_8k); + ATF_TP_ADD_TC(tp, sendrecv_16k); + ATF_TP_ADD_TC(tp, sendrecv_32k); + ATF_TP_ADD_TC(tp, sendrecv_64k); + ATF_TP_ADD_TC(tp, sendrecv_128k); + ATF_TP_ADD_TC(tp, sendrecv_8k_nonblocking); + ATF_TP_ADD_TC(tp, sendrecv_16k_nonblocking); + ATF_TP_ADD_TC(tp, sendrecv_32k_nonblocking); + ATF_TP_ADD_TC(tp, sendrecv_64k_nonblocking); + ATF_TP_ADD_TC(tp, sendrecv_128k_nonblocking); + ATF_TP_ADD_TC(tp, rcvbuf_oversized); + ATF_TP_ADD_TC(tp, pipe_simulator_8k_8k); + ATF_TP_ADD_TC(tp, pipe_simulator_8k_128k); + ATF_TP_ADD_TC(tp, pipe_simulator_128k_8k); + ATF_TP_ADD_TC(tp, pipe_simulator_128k_128k); + + /* Threaded I/O tests with blocking sockets */ + ATF_TP_ADD_TC(tp, pipe_8k_8k); + ATF_TP_ADD_TC(tp, pipe_8k_128k); + ATF_TP_ADD_TC(tp, pipe_128k_8k); + ATF_TP_ADD_TC(tp, pipe_128k_128k); + + return atf_no_error(); +} diff --git a/tools/regression/sockets/unix_seqpacket/Makefile b/tools/regression/sockets/unix_seqpacket/Makefile deleted file mode 100644 index 3045065..0000000 --- a/tools/regression/sockets/unix_seqpacket/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG= unix_seqpacket -CFLAGS+= -Wall -Werror -NO_MAN= - -.include <bsd.prog.mk> diff --git a/tools/regression/sockets/unix_seqpacket/unix_seqpacket.c b/tools/regression/sockets/unix_seqpacket/unix_seqpacket.c deleted file mode 100644 index 40baa64..0000000 --- a/tools/regression/sockets/unix_seqpacket/unix_seqpacket.c +++ /dev/null @@ -1,140 +0,0 @@ -/*- - * Copyright (c) 2009 Robert N. M. Watson - * All rights reserved. - * - * This software was developed at the University of Cambridge Computer - * Laboratory with support from a grant from Google, 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. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/socket.h> -#include <sys/un.h> - -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#define FAILERR(str) err(-1, "%s: %s", __func__, str) -#define FAILERRX(str) errx(-1, "%s: %s", __func__, str) - -static void -test_socket(void) -{ - int s; - - s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - if (s < 0) - FAILERR("socket"); - (void)close(s); -} - -static void -test_socketpair(void) -{ - int sv[2]; - - if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv) < 0) - FAILERR("socketpair"); - (void)close(sv[0]); - (void)close(sv[1]); -} - -static void -test_listen_unbound(void) -{ - int s; - - s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - if (s < 0) - FAILERR("socket"); - if (listen(s, -1) == 0) - FAILERRX("listen"); - (void)close(s); -} - -static void -test_bind(void) -{ - struct sockaddr_un sun; - char path[PATH_MAX]; - int s; - - snprintf(path, sizeof(path), "/tmp/lds.XXXXXXXXX"); - if (mktemp(path) == NULL) - FAILERR("mktemp"); - s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - if (s < 0) - FAILERR("socket"); - bzero(&sun, sizeof(sun)); - sun.sun_family = AF_LOCAL; - sun.sun_len = sizeof(sun); - strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); - if (bind(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) - FAILERR("bind"); - close(s); - (void)unlink(path); -} - -static void -test_listen_bound(void) -{ - struct sockaddr_un sun; - char path[PATH_MAX]; - int s; - - snprintf(path, sizeof(path), "/tmp/lds.XXXXXXXXX"); - if (mktemp(path) == NULL) - FAILERR("mktemp"); - s = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - if (s < 0) - FAILERR("socket"); - bzero(&sun, sizeof(sun)); - sun.sun_family = AF_LOCAL; - sun.sun_len = sizeof(sun); - strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); - if (bind(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) - FAILERR("bind"); - if (listen(s, -1)) { - (void)unlink(path); - FAILERR("bind"); - } - close(s); - (void)unlink(path); -} - -int -main(int argc, char *argv[]) -{ - - test_socket(); - test_socketpair(); - test_listen_unbound(); - test_bind(); - test_listen_bound(); -} diff --git a/tools/regression/sockets/unix_seqpacket_exercise/Makefile b/tools/regression/sockets/unix_seqpacket_exercise/Makefile deleted file mode 100644 index 494575b..0000000 --- a/tools/regression/sockets/unix_seqpacket_exercise/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# $FreeBSD$ -# - -PROG=unix_seqpacket_exercise -CFLAGS+=-Wall -Werror -NO_MAN= - -.include <bsd.prog.mk> diff --git a/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c b/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c deleted file mode 100644 index a16c384..0000000 --- a/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c +++ /dev/null @@ -1,435 +0,0 @@ -/*- - * Copyright (c) 2009 Robert N. M. Watson - * All rights reserved. - * - * This software was developed at the University of Cambridge Computer - * Laboratory with support from a grant from Google, 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. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/socket.h> -#include <sys/wait.h> -#include <sys/un.h> - -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <signal.h> -#include <string.h> -#include <unistd.h> - -#define min(x, y) (x < y ? x : y) - -#define BUFLEN 32768 - -#define SEQPACKET_RCVBUF (131072-16) -#define SEQPACKET_SNDBUF (131072-16) - -#define FAILERR(str) err(-1, "%s: %s", __func__, str) -#define FAILNERR(str, n) err(-1, "%s %zd: %s", __func__, n, str) -#define FAILNMERR(str, n, m) err(-1, "%s %zd %d: %s", __func__, n, m, str) -#define FAILERRX(str) errx(-1, "%s: %s", __func__, str) -#define FAILNERRX(str, n) errx(-1, "%s %zd: %s", __func__, n, str) -#define FAILNMERRX(str, n, m) errx(-1, "%s %zd %d: %s", __func__, n, m, str) - -static int ann = 0; - -#define ANN() (ann ? warnx("%s: start", __func__) : 0) -#define ANNN(n) (ann ? warnx("%s %zd: start", __func__, (n)) : 0) -#define ANNNM(n, m) (ann ? warnx("%s %zd %d: start", __func__, (n), (m)):0) - -#define OK() warnx("%s: ok", __func__) -#define OKN(n) warnx("%s %zd: ok", __func__, (n)) -#define OKNM(n, m) warnx("%s %zd %d: ok", __func__, (n), (m)) - -#ifdef SO_NOSIGPIPE -#define NEW_SOCKET(s) do { \ - int i; \ - \ - (s) = socket(PF_LOCAL, SOCK_SEQPACKET, 0); \ - if ((s) < 0) \ - FAILERR("socket"); \ - \ - i = 1; \ - if (setsockopt((s), SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) \ - FAILERR("setsockopt SO_NOSIGPIPE"); \ - \ - i = SEQPACKET_RCVBUF; \ - if (setsockopt((s), SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) \ - FAILERR("setsockopt SO_RCVBUF"); \ - \ - i = SEQPACKET_SNDBUF; \ - if (setsockopt((s), SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) \ - FAILERR("setsockopt SO_SNDBUF"); \ -} while (0) -#else -#define NEW_SOCKET(s) do { \ - int i; \ - \ - (s) = socket(PF_LOCAL, SOCK_SEQPACKET, 0); \ - if ((s) < 0) \ - FAILERR("socket"); \ - \ - i = SEQPACKET_RCVBUF; \ - if (setsockopt((s), SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) \ - FAILERR("setsockopt SO_RCVBUF"); \ - \ - i = SEQPACKET_SNDBUF; \ - if (setsockopt((s), SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) \ - FAILERR("setsockopt SO_SNDBUF"); \ -} while (0) -#endif - -static void -server(int s_listen) -{ - char buffer[BUFLEN]; - ssize_t ssize_recv, ssize_send; - socklen_t socklen; - int i, s_accept; - - while (1) { - s_accept = accept(s_listen, NULL, 0); - if (s_accept >= 0) { - i = SEQPACKET_RCVBUF; - if (setsockopt(s_accept, SOL_SOCKET, SO_RCVBUF, &i, - sizeof(i)) < 0) { - warn("server: setsockopt SO_RCVBUF"); - close(s_accept); - continue; - } - - if (getsockopt(s_accept, SOL_SOCKET, SO_RCVBUF, &i, - &socklen) < 0) { - warn("server: getsockopt SO_RCVBUF"); - close(s_accept); - continue; - } - if (i != SEQPACKET_RCVBUF) { - warnx("server: getsockopt SO_RCVBUF wrong %d", - i); - close(s_accept); - continue; - } - - socklen = sizeof(i); - if (getsockopt(s_accept, SOL_SOCKET, SO_SNDBUF, &i, - &socklen) < 0) { - warn("server: getsockopt SO_SNDBUF"); - close(s_accept); - continue; - } - if (i != SEQPACKET_SNDBUF) { - warnx("server: getsockopt SO_SNDBUF wrong %d", - i); - close(s_accept); - continue; - } - - do { - ssize_recv = recv(s_accept, buffer, - sizeof(buffer), 0); - if (ssize_recv == 0) - break; - if (ssize_recv < 0) { - warn("server: recv"); - break; - } - ssize_send = send(s_accept, buffer, - ssize_recv, 0); - if (ssize_send == 0) - break; - if (ssize_send < 0) { - warn("server: send"); - break; - } - if (ssize_send != ssize_recv) - warnx("server: recv %zd sent %zd", - ssize_recv, ssize_send); - } while (1); - close(s_accept); - } else - warn("server: accept"); - } -} - -static void -test_connect(struct sockaddr_un *sun) -{ - int s; - - ANN(); - NEW_SOCKET(s); - if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) - FAILERR("connect"); - (void)close(s); - OK(); -} - -static void -test_connect_send(struct sockaddr_un *sun) -{ - ssize_t ssize; - char ch; - int s; - - ANN(); - NEW_SOCKET(s); - if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) - FAILERR("connect"); - ssize = send(s, &ch, sizeof(ch), 0); - if (ssize < 0) - FAILERR("send"); - if (ssize != sizeof(ch)) - FAILERRX("send wrong size"); - (void)close(s); - OK(); -} - -static void -test_connect_shutdown_send(struct sockaddr_un *sun) -{ - ssize_t ssize; - char ch; - int s; - - ANN(); - NEW_SOCKET(s); - if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) - FAILERR("connect"); - if (shutdown(s, SHUT_RDWR) < 0) - FAILERR("shutdown SHUT_RDWR"); - ssize = send(s, &ch, sizeof(ch), 0); - if (ssize >= 0) - FAILERRX("send"); - if (errno != EPIPE) - FAILERR("send unexpected error"); - (void)close(s); - OK(); -} - -static void -test_connect_send_recv(struct sockaddr_un *sun, size_t size) -{ - char buf[size + 4]; /* Detect extra bytes. */ - size_t truncsize; - ssize_t ssize; - int s; - - ANNN(size); - NEW_SOCKET(s); - if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) - FAILNERR("connect", size); - ssize = send(s, buf, size, 0); - if (ssize < 0 && size >= SEQPACKET_RCVBUF) - goto out; - if (ssize < 0) - FAILNERR("send", size); - if (ssize == 0) - FAILNERR("send eof", size); - if (ssize != size) - FAILNERRX("send size", size); - - truncsize = min(size, BUFLEN); - ssize = recv(s, buf, sizeof(buf), 0); - if (ssize < 0) - FAILNERR("recv", size); - if (ssize == 0) - FAILNERRX("recv eof", size); - if (ssize < truncsize) - FAILNERRX("recv too few bytes", size); - if (ssize > truncsize) - FAILNERRX("recv too many bytes", size); -out: - (void)close(s); - OKN(size); -} - -static void -test_connect_send_recv_count(struct sockaddr_un *sun, int count, size_t size) -{ - char buf[size + 4]; /* Detect extra bytes and coalescing. */ - size_t truncsize; - ssize_t ssize; - int i, s; - - ANNNM(size, count); - NEW_SOCKET(s); - if (connect(s, (struct sockaddr *)sun, sizeof(*sun)) < 0) - FAILNMERR("connect", size, count); - for (i = 0; i < count; i++) { - usleep(5000); - ssize = send(s, buf, size, 0); - if (ssize < 0 && size >= SEQPACKET_RCVBUF) - goto out; - if (ssize < 0) - FAILNMERR("send", size, count); - if (ssize == 0) - FAILNMERRX("send eof", size, count); - if (ssize != size) - FAILNMERRX("send size", size, count); - } - - truncsize = min(size, BUFLEN); - for (i = 0; i < count; i++) { - ssize = recv(s, buf, sizeof(buf), 0); - if (ssize < 0) - FAILNMERR("recv", size, count); - if (ssize == 0) - FAILNMERRX("recv eof", size, count); - if (ssize < truncsize) - FAILNMERRX("recv too few bytes", size, count); - if (ssize > truncsize) - FAILNMERRX("recv too many bytes", size, count); - } -out: - (void)close(s); - OKNM(size, count); -} - -static void -test_sendto(struct sockaddr_un *sun) -{ - ssize_t ssize; - char ch; - int s; - - ANN(); - NEW_SOCKET(s); - ssize = sendto(s, &ch, sizeof(ch), 0, (struct sockaddr *)sun, - sizeof(*sun)); - if (ssize < 0) - FAILERR("sendto"); - (void)close(s); - OK(); -} - -static void -client(struct sockaddr_un *sun) -{ - size_t sizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, - 4096, 8192, 16384, 32768, 65536 /*, 131072 */}; - int c, i; - - test_connect(sun); - test_connect_send(sun); - test_connect_shutdown_send(sun); - - /* - * Try a range of sizes and packet counts. - */ - for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) - test_connect_send_recv(sun, sizes[i]); - for (c = 1; c <= 8; c++) { - for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) - test_connect_send_recv_count(sun, c, sizes[i]); - } - test_sendto(sun); - printf("client done\n"); -} - -int -main(int argc, char *argv[]) -{ - struct sockaddr_un sun; - char path[PATH_MAX]; - pid_t pid_client, pid_server; - int i, s_listen; - - snprintf(path, sizeof(path), "/tmp/lds_exercise.XXXXXXXXX"); - if (mktemp(path) == NULL) - FAILERR("mktemp"); - - s_listen = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - if (s_listen < 0) { - (void)unlink(path); - FAILERR("socket"); - } - - i = SEQPACKET_RCVBUF; - if (setsockopt(s_listen, SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0) { - (void)unlink(path); - FAILERR("setsockopt SO_RCVBUF"); - } - - i = SEQPACKET_SNDBUF; - if (setsockopt(s_listen, SOL_SOCKET, SO_SNDBUF, &i, sizeof(i)) < 0) { - (void)unlink(path); - FAILERR("setsockopt SO_SNDBUF"); - } - - i = 1; - if (setsockopt(s_listen, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) - < 0) { - (void)unlink(path); - FAILERR("setsockopt SO_NOSIGPIPE"); - } - - bzero(&sun, sizeof(sun)); - sun.sun_len = sizeof(sun); - sun.sun_family = AF_LOCAL; - strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); - - if (bind(s_listen, (struct sockaddr *)&sun, sizeof(sun)) < 0) { - (void)unlink(path); - FAILERR("bind"); - } - - if (listen(s_listen, -1) < 0) { - (void)unlink(path); - FAILERR("listen"); - } - - pid_server = fork(); - if (pid_server < 0) { - (void)unlink(path); - FAILERR("fork"); - } - if (pid_server == 0) { - server(s_listen); - return (0); - } - - pid_client = fork(); - if (pid_client < 0) { - (void)kill(pid_server, SIGKILL); - (void)unlink(path); - FAILERR("fork"); - } - if (pid_client == 0) { - client(&sun); - return (0); - } - - /* - * When the client is done, kill the server and clean up. - */ - (void)waitpid(pid_client, NULL, 0); - (void)kill(pid_server, SIGKILL); - (void)unlink(path); - return (0); -} |