From owner-freebsd-bugs@FreeBSD.ORG Thu Jan 23 17:30:01 2014 Return-Path: Delivered-To: freebsd-bugs@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 3D49128E for ; Thu, 23 Jan 2014 17:30:01 +0000 (UTC) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 1D87415F4 for ; Thu, 23 Jan 2014 17:30:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.7/8.14.7) with ESMTP id s0NHU1qA070242 for ; Thu, 23 Jan 2014 17:30:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.7/8.14.7/Submit) id s0NHU1Fx070241; Thu, 23 Jan 2014 17:30:01 GMT (envelope-from gnats) Date: Thu, 23 Jan 2014 17:30:01 GMT Message-Id: <201401231730.s0NHU1Fx070241@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/185813: commit references a PR X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list Reply-To: dfilter service List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Jan 2014 17:30:01 -0000 The following reply was made to PR kern/185813; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/185813: commit references a PR Date: Thu, 23 Jan 2014 17:26:41 +0000 (UTC) Author: asomers Date: Thu Jan 23 17:26:28 2014 New Revision: 261081 URL: http://svnweb.freebsd.org/changeset/base/261081 Log: Replace the old unix_seqpacket and unix_seqpacket_exercise tests, which were a little broken and not automatable, with unix_seqpacket_test. It's coverage is a superset of the old tests and it uses ATF. It includes test cases for bugs kern/185813 and kern/185812. PR: kern/185812 PR: kern/185813 Sponsored by: Spectra Logic MFC after: 2 weeks Added: head/tests/sys/ head/tests/sys/Makefile (contents, props changed) head/tests/sys/kern/ head/tests/sys/kern/Makefile (contents, props changed) head/tests/sys/kern/unix_seqpacket_test.c (contents, props changed) Deleted: head/tools/regression/sockets/unix_seqpacket/ head/tools/regression/sockets/unix_seqpacket_exercise/ Modified: head/Makefile.inc1 head/etc/mtree/BSD.tests.dist Modified: head/Makefile.inc1 ============================================================================== --- head/Makefile.inc1 Thu Jan 23 17:24:26 2014 (r261080) +++ head/Makefile.inc1 Thu Jan 23 17:26:28 2014 (r261081) @@ -417,7 +417,7 @@ LIB32WMAKEFLAGS+= \ -DNO_LINT LIB32WMAKE= ${LIB32WMAKEENV} ${MAKE} ${LIB32WMAKEFLAGS} \ - -DWITHOUT_MAN -DWITHOUT_INFO -DWITHOUT_HTML + -DWITHOUT_MAN -DWITHOUT_INFO -DWITHOUT_HTML -DNO_TESTS LIB32IMAKE= ${LIB32WMAKE:NINSTALL=*:NDESTDIR=*:N_LDSCRIPTROOT=*} -DNO_INCS \ ${IMAKE_INSTALL} .endif Modified: head/etc/mtree/BSD.tests.dist ============================================================================== --- head/etc/mtree/BSD.tests.dist Thu Jan 23 17:24:26 2014 (r261080) +++ head/etc/mtree/BSD.tests.dist Thu Jan 23 17:26:28 2014 (r261081) @@ -78,6 +78,10 @@ .. .. .. + sys + kern + .. + .. usr.bin atf atf-sh Added: head/tests/sys/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tests/sys/Makefile Thu Jan 23 17:26:28 2014 (r261081) @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.include + +TESTSDIR= ${TESTSBASE}/sys + +KYUAFILE= yes + +CLEANFILES+= Kyuafile +Kyuafile: ${.CURDIR}/../Kyuafile + cp -f ${.CURDIR}/../Kyuafile . + +.include Added: head/tests/sys/kern/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tests/sys/kern/Makefile Thu Jan 23 17:26:28 2014 (r261081) @@ -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 Added: head/tests/sys/kern/unix_seqpacket_test.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tests/sys/kern/unix_seqpacket_test.c Thu Jan 23 17:26:28 2014 (r261081) @@ -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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + * 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); +} + *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"