-
-
Save asomers/5f98656d574e68314029 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: Makefile.inc1 | |
=================================================================== | |
--- Makefile.inc1 (revision 260986) | |
+++ Makefile.inc1 (working copy) | |
@@ -87,6 +87,7 @@ | |
SUBDIR+=sys usr.bin usr.sbin | |
.if ${MK_TESTS} != "no" | |
SUBDIR+= tests | |
+SUBDIR+= sys/tests | |
.endif | |
.if ${MK_OFED} != "no" | |
SUBDIR+=contrib/ofed | |
Index: etc/mtree/BSD.tests.dist | |
=================================================================== | |
--- etc/mtree/BSD.tests.dist (revision 260986) | |
+++ etc/mtree/BSD.tests.dist (working copy) | |
@@ -78,6 +78,10 @@ | |
.. | |
.. | |
.. | |
+ sys | |
+ kern | |
+ .. | |
+ .. | |
usr.bin | |
atf | |
atf-sh | |
Index: sys/kern/tests/Makefile | |
=================================================================== | |
--- sys/kern/tests/Makefile (revision 0) | |
+++ sys/kern/tests/Makefile (working copy) | |
@@ -0,0 +1,10 @@ | |
+# $FreeBSD$ | |
+ | |
+TESTSDIR= ${TESTSBASE}/sys/kern | |
+ | |
+ATF_TESTS_C= unix_seqpacket | |
+TEST_METADATA.unix_seqpacket+= timeout="15" | |
+ | |
+LDADD+= -lpthread | |
+ | |
+.include <atf.test.mk> | |
Index: sys/kern/tests/unix_seqpacket.c | |
=================================================================== | |
--- sys/kern/tests/unix_seqpacket.c (revision 0) | |
+++ sys/kern/tests/unix_seqpacket.c (working copy) | |
@@ -0,0 +1,1114 @@ | |
+/*- | |
+ * 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) | |
+{ | |
+ 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 | |
+ */ | |
+ 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(); | |
+} | |
Index: sys/tests/Makefile | |
=================================================================== | |
--- sys/tests/Makefile (revision 0) | |
+++ sys/tests/Makefile (working copy) | |
@@ -0,0 +1,11 @@ | |
+# $FreeBSD$ | |
+ | |
+.include <bsd.own.mk> | |
+ | |
+TESTSDIR= ${TESTSBASE}/sys | |
+ | |
+TESTS_SUBDIRS+= ../kern/tests | |
+.PATH: ${.CURDIR:H:H}/tests | |
+KYUAFILE= yes | |
+ | |
+.include <atf.test.mk> | |
Index: tools/regression/sockets/unix_seqpacket/Makefile | |
=================================================================== | |
--- tools/regression/sockets/unix_seqpacket/Makefile (revision 260986) | |
+++ tools/regression/sockets/unix_seqpacket/Makefile (working copy) | |
@@ -1,9 +0,0 @@ | |
-# | |
-# $FreeBSD$ | |
-# | |
- | |
-PROG= unix_seqpacket | |
-CFLAGS+= -Wall -Werror | |
-NO_MAN= | |
- | |
-.include <bsd.prog.mk> | |
Index: tools/regression/sockets/unix_seqpacket/unix_seqpacket.c | |
=================================================================== | |
--- tools/regression/sockets/unix_seqpacket/unix_seqpacket.c (revision 260986) | |
+++ tools/regression/sockets/unix_seqpacket/unix_seqpacket.c (working copy) | |
@@ -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(); | |
-} | |
Index: tools/regression/sockets/unix_seqpacket_exercise/Makefile | |
=================================================================== | |
--- tools/regression/sockets/unix_seqpacket_exercise/Makefile (revision 260986) | |
+++ tools/regression/sockets/unix_seqpacket_exercise/Makefile (working copy) | |
@@ -1,9 +0,0 @@ | |
-# | |
-# $FreeBSD$ | |
-# | |
- | |
-PROG=unix_seqpacket_exercise | |
-CFLAGS+=-Wall -Werror | |
-NO_MAN= | |
- | |
-.include <bsd.prog.mk> | |
Index: tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c | |
=================================================================== | |
--- tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c (revision 260986) | |
+++ tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c (working copy) | |
@@ -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); | |
-} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment