summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/mtree/BSD.tests.dist4
-rw-r--r--tests/Makefile2
-rw-r--r--tests/sys/Makefile12
-rw-r--r--tests/sys/kern/Makefile10
-rw-r--r--tests/sys/kern/unix_seqpacket_test.c1117
-rw-r--r--tools/regression/sockets/unix_seqpacket/Makefile9
-rw-r--r--tools/regression/sockets/unix_seqpacket/unix_seqpacket.c140
-rw-r--r--tools/regression/sockets/unix_seqpacket_exercise/Makefile9
-rw-r--r--tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c435
9 files changed, 1144 insertions, 594 deletions
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index 65f9090..b4afeee 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -48,6 +48,10 @@
..
..
..
+ sys
+ kern
+ ..
+ ..
usr.bin
atf
atf-sh
diff --git a/tests/Makefile b/tests/Makefile
index 88386eb..ba81cac 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,7 +2,7 @@
.include <bsd.own.mk>
-SUBDIR= # still empty
+SUBDIR= sys
TESTSDIR= ${TESTSBASE}
KYUAFILE= yes
diff --git a/tests/sys/Makefile b/tests/sys/Makefile
new file mode 100644
index 0000000..ea8b3c4
--- /dev/null
+++ b/tests/sys/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}/..
+
+TESTS_SUBDIRS+= kern
+TESTSDIR= ${TESTSBASE}/sys
+
+KYUAFILE= yes
+
+.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);
-}
OpenPOWER on IntegriCloud