Thanks. I am very happy you added these tests :-) Only some minor comments below.
On Tue, Aug 7, 2018 at 5:49 AM, Charles Myers <[email protected]> wrote: > Signed-off-by: Charles Myers <[email protected]> > --- > modules/tests/Makefile | 16 ++- > tests/tst-pktinfo.cc | 245 ++++++++++++++++++++++++++++++ > ++++++++++++ > tests/tst-socket-timestamp.cc | 162 ++++++++++++++++++++++++++++ > tests/tst-tcp-v6.cc | 240 ++++++++++++++++++++++++++++++ > +++++++---- > 4 files changed, 641 insertions(+), 22 deletions(-) > create mode 100644 tests/tst-pktinfo.cc > create mode 100644 tests/tst-socket-timestamp.cc > > diff --git a/modules/tests/Makefile b/modules/tests/Makefile > index cec4feb..60fc1eb 100644 > --- a/modules/tests/Makefile > +++ b/modules/tests/Makefile > @@ -22,6 +22,13 @@ makedir = $(call very-quiet, mkdir -p $(dir $@)) > > autodepend = -MD -MT $@ -MP > > +include $(OSV_BASE)/conf/base.mk > + > +configuration-defines = conf-preempt conf-debug_memory conf-logger_debug > conf-INET6 > +configuration = $(foreach cf,$(configuration-defines), \ > + -D$(cf:conf-%=CONF_%)=$($(cf))) > + > + > INCLUDES = -I$(src)/arch/$(ARCH) -I$(src) -I$(src)/include \ > -I$(src)/arch/common -isystem $(src)/include/glibc-compat \ > $(shell $(CXX) -E -xc++ - -v </dev/null 2>&1 | awk '/^End/ {exit} > /^ .*c\+\+/ {print "-isystem" $$0}') \ > @@ -29,7 +36,7 @@ INCLUDES = -I$(src)/arch/$(ARCH) -I$(src) > -I$(src)/include \ > -isystem $(out)/gen/include > > COMMON = $(autodepend) $(INCLUDES) -g -O2 -fPIC -DBOOST_TEST_DYN_LINK \ > - -U _FORTIFY_SOURCE -D_KERNEL -D__OSV__ -DCONF_debug_memory=0 \ > + -U _FORTIFY_SOURCE -D_KERNEL -D__OSV__ $(configuration) \ > -Wall -Wno-pointer-arith -Wformat=0 -Wno-format-security > > LIBS = > @@ -113,8 +120,9 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so > tst-bsd-evh.so \ > tst-pthread-setcancelstate.so tst-syscall.so tst-pin.so tst-run.so > \ > tst-ifaddrs.so tst-pthread-affinity-inherit.so > tst-sem-timed-wait.so \ > tst-ttyname.so tst-pthread-barrier.so tst-feexcept.so tst-math.so \ > - tst-sigaltstack.so tst-fread.so tst-tcp-cork.so tst-tcp-v6.so \ > - tst-calloc.so tst-crypt.so > + tst-sigaltstack.so tst-fread.so tst-tcp-cork.so \ > + tst-calloc.so tst-crypt.so \ > + tst-socket-timestamp.so tst-pktinfo.so > > # libstatic-thread-variable.so tst-static-thread-variable.so \ > > @@ -145,7 +153,7 @@ boost-tests := tst-vfs.so tst-libc-locking.so > misc-fs-stress.so \ > tst-bsd-tcp1-zsndrcv.so tst-async.so tst-rcu-list.so > tst-tcp-listen.so \ > tst-poll.so tst-bitset-iter.so tst-timer-set.so tst-clock.so \ > tst-rcu-hashtable.so tst-unordered-ring-mpsc.so \ > - tst-seek.so > + tst-seek.so tst-tcp-v6.so > > rofs-only-boost-tests := > > diff --git a/tests/tst-pktinfo.cc b/tests/tst-pktinfo.cc > new file mode 100644 > index 0000000..41022ac > --- /dev/null > +++ b/tests/tst-pktinfo.cc > @@ -0,0 +1,245 @@ > +/* > + * Copyright (C) 2014 Cloudius Systems, Ltd. > You can use your own copyright statement (and current year) instead. > + * > + * This work is open source software, licensed under the terms of the > + * BSD license as described in the LICENSE file in the top-level > directory. > + */ > +// To compile on Linux, use: g++ -g -pthread -std=c++11 tests/tst-uio.cc > Change tst-uio.cc on this command line to tst-pktinfo.cc > + > +// This test tests the SO_TIMESTMAP socket option. > Is this really what this test tests? Looks more like testing IP_PKTINFO (I'm not familiar with this option, so I don't know if it tests anything else). > + > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <assert.h> > +#include <sys/uio.h> > +#include <string.h> > +#include <sys/socket.h> > +#include <sys/time.h> > +#include <arpa/inet.h> > + > +#include <iostream> > +#include <thread> > +#include <vector> > +#include <mutex> > + > +#ifdef __OSV__ > +#include <bsd/porting/netport.h> // Get INET6 > +#else > +#define INET6 > +#endif > + > + > +// Multiple threads can call expect functions at the same time > +// so need to protect against concurrent writes to cout. > +std::mutex test_mutex; > + > +static int tests = 0, fails = 0; > + > +template<typename T> > +bool do_expect(T actual, T expected, const char *actuals, const char > *expecteds, const char *file, int line) > +{ > + std::lock_guard<std::mutex> lock(test_mutex); > + > + ++tests; > + if (actual != expected) { > + fails++; > + std::cout << "FAIL: " << file << ":" << line << ": For " << > actuals > + << " expected " << expecteds << "(" << expected << "), > saw " > + << actual << ".\n"; > + return false; > + } > + std::cout << "OK: " << file << ":" << line << ".\n"; > + return true; > +} > +template<typename T> > +bool do_expectge(T actual, T expected, const char *actuals, const char > *expecteds, const char *file, int line) > +{ > + std::lock_guard<std::mutex> lock(test_mutex); > + > + ++tests; > + if (actual < expected) { > + fails++; > + std::cout << "FAIL: " << file << ":" << line << ": For " << > actuals > + << " expected >=" << expecteds << ", saw " << actual << > ".\n"; > + return false; > + } > + std::cout << "OK: " << file << ":" << line << ".\n"; > + return true; > +} > +#define expect(actual, expected) do_expect(actual, expected, #actual, > #expected, __FILE__, __LINE__) > +#define expectge(actual, expected) do_expectge(actual, expected, #actual, > #expected, __FILE__, __LINE__) > +#define expect_errno(call, experrno) ( \ > + do_expect((long)(call), (long)-1, #call, "-1", __FILE__, > __LINE__) && \ > + do_expect(errno, experrno, #call " errno", #experrno, __FILE__, > __LINE__) ) > +#define expect_success(var, call) \ > + errno = 0; \ > + var = call; \ > + do_expectge(var, 0, #call, "0", __FILE__, __LINE__); \ > + do_expect(errno, 0, #call " errno", "0", __FILE__, __LINE__); > + > +void test_ipv4() > +{ > + int sockfd; > + int optval = 1; > + struct sockaddr_in serveraddr; > + socklen_t serveraddr_len = sizeof(serveraddr); > + const int npacket = 5; > + int ret; > + > + expect_success(sockfd, socket(AF_INET, SOCK_DGRAM, 0)); > + expect_success(ret, setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, > &optval, sizeof(optval))); > + expect_success(ret, setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, > &optval, sizeof(optval))); > + > + bzero(&serveraddr, sizeof(serveraddr)); > + serveraddr.sin_family = AF_INET; > + serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); > + serveraddr.sin_port = 0; // Find next available port > + expect_success(ret, bind(sockfd, (struct sockaddr*) &serveraddr, > serveraddr_len)); > + > + expect_success(ret, getsockname(sockfd, (struct sockaddr*) > &serveraddr, &serveraddr_len)); > + expect(serveraddr.sin_family, (in_port_t)AF_INET); > + std::cout << "Server bound to UDP port " << > ntohs(serveraddr.sin_port) << std::endl; > + > + std::thread t([sockfd, npacket] { > + struct msghdr msg; > + struct iovec iov; > + uint8_t buf[64]; > + uint8_t controlbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; > + > + bzero(&msg, sizeof(msg)); > + bzero(&iov, sizeof(iov)); > + for (int ipacket = 0; ipacket < npacket; ++ipacket) { > + iov.iov_base = buf; > + iov.iov_len = sizeof(buf); > + msg.msg_iov = &iov; > + msg.msg_iovlen = 1; > + msg.msg_control = controlbuf; > + msg.msg_controllen = sizeof(controlbuf); > + > + int n; > + expect_success(n, recvmsg(sockfd, &msg, 0)); > + expect(n, 6); > + > + struct in_pktinfo pktinfo; > + bool pktinfo_valid = false; > + > + for (auto cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = > CMSG_NXTHDR(&msg, cmptr)) { > + if ((cmptr->cmsg_level == IPPROTO_IP) && > (cmptr->cmsg_type == IP_PKTINFO)) { > + memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(pktinfo)); > + pktinfo_valid = true; > + break; > + } > + } > + > + expect(pktinfo_valid, true); > + > + char ipaddr[INET_ADDRSTRLEN]; > + inet_ntop(AF_INET, &pktinfo.ipi_addr, ipaddr, sizeof(ipaddr)); > + std::cout << "ifindex " << pktinfo.ipi_ifindex << " ipaddr " > << ipaddr << std::endl; > + expect(pktinfo.ipi_addr.s_addr, htonl(INADDR_LOOPBACK)); > + } > + }); > + > + int sendsock; > + > + expect_success(sendsock, socket(AF_INET, SOCK_DGRAM, 0)); > + for (int ipacket = 0; ipacket < npacket; ++ipacket) { > + expect_success(ret, sendto(sendsock, "Hello!", 6, 0, (const > sockaddr*) &serveraddr, sizeof(serveraddr))); > + } > + t.join(); > + close(sockfd); > + close(sendsock); > +} > + > +#ifdef INET6 > + > +void test_ipv6() > +{ > + int sockfd; > + int optval = 1; > + struct sockaddr_in6 serveraddr; > + socklen_t serveraddr_len = sizeof(serveraddr); > + const int npacket = 5; > + int ret; > + > + expect_success(sockfd, socket(AF_INET6, SOCK_DGRAM, 0)); > + expect_success(ret, setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, > &optval, sizeof(optval))); > + expect_success(ret, setsockopt(sockfd, IPPROTO_IPV6, > IPV6_RECVPKTINFO, &optval, sizeof(optval))); > + > + bzero(&serveraddr, sizeof(serveraddr)); > + serveraddr.sin6_family = AF_INET6; > + serveraddr.sin6_addr = in6addr_loopback; > + serveraddr.sin6_port = 0; // Find next available port > + expect_success(ret, bind(sockfd, (struct sockaddr*) &serveraddr, > serveraddr_len)); > + > + expect_success(ret, getsockname(sockfd, (struct sockaddr*) > &serveraddr, &serveraddr_len)); > + expect(serveraddr.sin6_family, (in_port_t)AF_INET6); > + std::cout << "Server bound to UDP port " << > ntohs(serveraddr.sin6_port) << std::endl; > + > + std::thread t([sockfd, npacket] { > + struct msghdr msg; > + struct iovec iov; > + uint8_t buf[64]; > + uint8_t controlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; > + > + bzero(&msg, sizeof(msg)); > + bzero(&iov, sizeof(iov)); > + for (int ipacket = 0; ipacket < npacket; ++ipacket) { > + iov.iov_base = buf; > + iov.iov_len = sizeof(buf); > + msg.msg_iov = &iov; > + msg.msg_iovlen = 1; > + msg.msg_control = controlbuf; > + msg.msg_controllen = sizeof(controlbuf); > + > + int n; > + expect_success(n, recvmsg(sockfd, &msg, 0)); > + expect(n, 6); > + > + struct in6_pktinfo pktinfo; > + bool pktinfo_valid = false; > + > + for (auto cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = > CMSG_NXTHDR(&msg, cmptr)) { > + if ((cmptr->cmsg_level == IPPROTO_IPV6) && > (cmptr->cmsg_type == IPV6_PKTINFO)) { > + memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(pktinfo)); > + pktinfo_valid = true; > + break; > + } > + } > + > + expect(pktinfo_valid, true); > + > + char ipaddr[INET6_ADDRSTRLEN]; > + inet_ntop(AF_INET6, &pktinfo.ipi6_addr, ipaddr, > sizeof(ipaddr)); > + std::cout << "ifindex " << pktinfo.ipi6_ifindex << " ipaddr " > << ipaddr << std::endl; > + expect(std::string(ipaddr), std::string("::1")); > + } > + }); > + > + int sendsock; > + > + expect_success(sendsock, socket(AF_INET6, SOCK_DGRAM, 0)); > + for (int ipacket = 0; ipacket < npacket; ++ipacket) { > + expect_success(ret, sendto(sendsock, "Hello!", 6, 0, (const > sockaddr*) &serveraddr, sizeof(serveraddr))); > + } > + t.join(); > + close(sockfd); > + close(sendsock); > +} > + > +#endif > + > +int main() > +{ > + test_ipv4(); > +#ifdef INET6 > + test_ipv6(); > +#endif > + std::cout << "SUMMARY: " << tests << " tests, " << fails << " > failures\n"; > + return fails == 0 ? 0 : 1; > +} > + > diff --git a/tests/tst-socket-timestamp.cc b/tests/tst-socket-timestamp.cc > new file mode 100644 > index 0000000..1ad1792 > --- /dev/null > +++ b/tests/tst-socket-timestamp.cc > @@ -0,0 +1,162 @@ > +/* > + * Copyright (C) 2014 Cloudius Systems, Ltd. > Again, probably update year and copyright. + * > + * This work is open source software, licensed under the terms of the > + * BSD license as described in the LICENSE file in the top-level > directory. > + */ > +// To compile on Linux, use: g++ -g -pthread -std=c++11 tests/tst-uio.cc > again tst-uio.cc :-) > + > +// This test tests the SO_TIMESTMAP socket option. > Oh, so this comment came from here :-) + > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <assert.h> > +#include <sys/uio.h> > +#include <string.h> > +#include <sys/socket.h> > +#include <sys/time.h> > +#include <arpa/inet.h> > + > +#include <iostream> > +#include <thread> > +#include <vector> > +#include <mutex> > + > +// Multiple threads can call expect functions at the same time > +// so need to protect against concurrent writes to cout. > +std::mutex test_mutex; > + > +static int tests = 0, fails = 0; > + > +template<typename T> > +bool do_expect(T actual, T expected, const char *actuals, const char > *expecteds, const char *file, int line) > +{ > + std::lock_guard<std::mutex> lock(test_mutex); > + > + ++tests; > + if (actual != expected) { > + fails++; > + std::cout << "FAIL: " << file << ":" << line << ": For " << > actuals > + << " expected " << expecteds << "(" << expected << "), > saw " > + << actual << ".\n"; > + return false; > + } > + std::cout << "OK: " << file << ":" << line << ".\n"; > + return true; > +} > +template<typename T> > +bool do_expectge(T actual, T expected, const char *actuals, const char > *expecteds, const char *file, int line) > +{ > + std::lock_guard<std::mutex> lock(test_mutex); > + > + ++tests; > + if (actual < expected) { > + fails++; > + std::cout << "FAIL: " << file << ":" << line << ": For " << > actuals > + << " expected >=" << expecteds << ", saw " << actual << > ".\n"; > + return false; > + } > + std::cout << "OK: " << file << ":" << line << ".\n"; > + return true; > +} > +#define expect(actual, expected) do_expect(actual, expected, #actual, > #expected, __FILE__, __LINE__) > +#define expectge(actual, expected) do_expectge(actual, expected, #actual, > #expected, __FILE__, __LINE__) > +#define expect_errno(call, experrno) ( \ > + do_expect((long)(call), (long)-1, #call, "-1", __FILE__, > __LINE__) && \ > + do_expect(errno, experrno, #call " errno", #experrno, __FILE__, > __LINE__) ) > +#define expect_success(var, call) \ > + errno = 0; \ > + var = call; \ > + do_expectge(var, 0, #call, "0", __FILE__, __LINE__); \ > + do_expect(errno, 0, #call " errno", "0", __FILE__, __LINE__); > + > +int main() > +{ > + int sockfd; > + int optval = 1; > + struct sockaddr_in serveraddr; > + socklen_t serveraddr_len = sizeof(serveraddr); > + const int npacket = 5; > + int ret; > + > + expect_success(sockfd, socket(AF_INET, SOCK_DGRAM, 0)); > + expect(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, > sizeof(optval)), 0); > + expect(setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMP, &optval, > sizeof(optval)), 0); > + > + bzero(&serveraddr, sizeof(serveraddr)); > + serveraddr.sin_family = AF_INET; > + serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); > + serveraddr.sin_port = 0; // Find next available port > + expect_success(ret, bind(sockfd, (struct sockaddr*) &serveraddr, > serveraddr_len)); > + > + expect_success(ret, getsockname(sockfd, (struct sockaddr*) > &serveraddr, &serveraddr_len)); > + expect(serveraddr.sin_family, (in_port_t)AF_INET); > + std::cout << "Server bound to UDP port " << > ntohs(serveraddr.sin_port) << std::endl; > + > + std::thread t([sockfd, npacket] { > + struct msghdr msg; > + struct iovec iov; > + uint8_t buf[64]; > + uint8_t controlbuf[CMSG_SPACE(sizeof(struct timeval))]; > + struct timeval start, end; > + std::vector<struct timeval> timestamps; > + > + gettimeofday(&start, NULL); > + > + bzero(&msg, sizeof(msg)); > + bzero(&iov, sizeof(iov)); > + for (int ipacket = 0; ipacket < npacket; ++ipacket) { > + iov.iov_base = buf; > + iov.iov_len = sizeof(buf); > + msg.msg_iov = &iov; > + msg.msg_iovlen = 1; > + msg.msg_control = controlbuf; > + msg.msg_controllen = sizeof(controlbuf); > + > + int n; > + expect_success(n, recvmsg(sockfd, &msg, 0)); > + expect(n, 6); > + > + // Extract receive timestamp from cmsg data > + for (auto cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = > CMSG_NXTHDR(&msg, cmptr)) { > + if ((cmptr->cmsg_level == SOL_SOCKET) && > (cmptr->cmsg_type == SCM_TIMESTAMP)) { > + struct timeval tv; > + memcpy(&tv, CMSG_DATA(cmptr), sizeof(tv)); > + timestamps.push_back(tv); > + } > + } > + } > + > + gettimeofday(&end, NULL); > + > + // Validate received timestamps > + expect(timestamps.size(), (std::size_t)5); > + const struct timeval *prev_tv = NULL; > + for (auto const & tv : timestamps) { > + expect(timercmp(&tv, &start, >=), true); > + expect(timercmp(&tv, &end, <=), true); > + if (prev_tv) { > + expect(timercmp(&tv, prev_tv, >=), true); > + } > + prev_tv = &tv; > + } > + }); > + > + int sendsock; > + > + expect_success(sendsock, socket(AF_INET, SOCK_DGRAM, 0)); > + for (int ipacket = 0; ipacket < npacket; ++ipacket) { > + expect_success(ret, sendto(sendsock, "Hello!", 6, 0, (const > sockaddr*) &serveraddr, sizeof(serveraddr))); > + } > + t.join(); > + close(sockfd); > + close(sendsock); > + > + std::cout << "SUMMARY: " << tests << " tests, " << fails << " > failures\n"; > + return fails == 0 ? 0 : 1; > +} > + > diff --git a/tests/tst-tcp-v6.cc b/tests/tst-tcp-v6.cc > index 6858c1d..49268d3 100644 > --- a/tests/tst-tcp-v6.cc > +++ b/tests/tst-tcp-v6.cc > @@ -5,38 +5,242 @@ > * BSD license as described in the LICENSE file in the top-level > directory. > */ > > +#define BOOST_TEST_MODULE tst-tcp-v6 > + > +#include <stdio.h> > +#include <unistd.h> > +#include <errno.h> > +#include <vector> > +#include <thread> > +#include <chrono> > +#include <sys/types.h> > +#include <sys/socket.h> > +#include <arpa/inet.h> > +#include <osv/latch.hh> > +#include <boost/test/unit_test.hpp> > +#include <boost/interprocess/sync/interprocess_semaphore.hpp> > + > +#ifdef __OSV__ > +#include <bsd/porting/netport.h> // Get INET6 > +#else > +#define INET6 > +#endif > + > +#ifndef INET6 > + > /* > * This is a test for OSv's IPv6 non-support :-) Although we do not > support > * IPv6, we should return the errors which applications expect - see issue > * #865 on how us returning the wrong error from socket() confused redis. > */ > > -#include <stdio.h> > -#include <strings.h> > -#include <unistd.h> > -#include <netinet/in.h> > -#include <netinet/tcp.h> > -#include <errno.h> > - > > -static int tests = 0, fails = 0; > -static void report(bool ok, const char* msg) > +BOOST_AUTO_TEST_CASE(test_no_ipv6) > { > - ++tests; > - fails += !ok; > - printf("%s: %s\n", (ok ? "PASS" : "FAIL"), msg); > + int sock = socket(AF_INET, SOCK_STREAM, 0); > + BOOST_REQUIRE_MESSAGE(sock>=0, "open AF_INET socket succeeds"); > + close(sock); > + sock = socket(AF_INET6, SOCK_STREAM, 0); > + BOOST_REQUIRE_MESSAGE(sock<0, "open AF_INET6 socket fails"); > + BOOST_REQUIRE_MESSAGE(errno==EAFNOSUPPORT, "failure should be > EAFNOSUPPORT"); > } > > +#else > > -int main(int argc, char **argv) > +/* > + * OSv compiled with IP6 support. > + */ > + > +BOOST_AUTO_TEST_CASE(test_has_ipv6) > { > int sock = socket(AF_INET, SOCK_STREAM, 0); > - report(sock>=0, "open AF_INET socket succeeds"); > + BOOST_REQUIRE_MESSAGE(sock>=0, "open AF_INET socket succeeds"); > close(sock); > sock = socket(AF_INET6, SOCK_STREAM, 0); > - report(sock<0, "open AF_INET6 socket fails"); > - report(errno==EAFNOSUPPORT, "failure should be EAFNOSUPPORT"); > + BOOST_REQUIRE_MESSAGE(sock>=0, "open AF_INET6 socket succeeds"); > close(sock); > - printf("SUMMARY: %d tests, %d failures\n", tests, fails); > - return fails; > } > + > +#define LISTEN_PORT 7777 > + > +using _clock = std::chrono::high_resolution_clock; > + > +static int accept_with_timeout(int listening_socket, int > timeout_in_seconds) > +{ > + fd_set rfds; > + FD_ZERO(&rfds); > + FD_SET(listening_socket, &rfds); > + > + struct timeval tv = { .tv_sec = timeout_in_seconds, .tv_usec = 0 }; > + int retval = select(listening_socket + 1, &rfds, NULL, NULL, &tv); > + BOOST_REQUIRE_EQUAL(1, retval); > + > + int client_socket = accept(listening_socket, NULL, NULL); > + BOOST_REQUIRE(client_socket > 0); > + return client_socket; > +} > + > +BOOST_AUTO_TEST_CASE(test_ipv6_connections_get_accepted_ > even_when_backlog_gets_overflowed) > +{ > + std::vector<int> sockets_to_close; > + > + constexpr int n_connections = 7; > + constexpr int backlog_size = 2; > + > + static_assert(n_connections < SOMAXCONN, > + "The number of connections should not exceed maximum backlog > size"); > + > + static_assert(backlog_size < n_connections, > + "The test makes sense only when number of connections is greater > than backlog size"); > + > + auto listen_s = socket(AF_INET6, SOCK_STREAM, 0); > + BOOST_REQUIRE(listen_s > 0); > + > + sockets_to_close.push_back(listen_s); > + > + int reuse = 1; > + BOOST_REQUIRE(setsockopt(listen_s, SOL_SOCKET, SO_REUSEADDR, (const > char*)&reuse, sizeof(reuse)) == 0); > + > + struct sockaddr_in6 laddr = {}; > + laddr.sin6_family = AF_INET6; > + laddr.sin6_addr = in6addr_any; > + laddr.sin6_port = htons(LISTEN_PORT); > + > + BOOST_REQUIRE(bind(listen_s, (struct sockaddr *) &laddr, > sizeof(laddr)) == 0); > + BOOST_REQUIRE(listen(listen_s, backlog_size) == 0); > + > + BOOST_MESSAGE("listening..."); > + > + for (int i = 0; i < n_connections; i++) { > + int s = socket(AF_INET6, SOCK_STREAM, 0); > + BOOST_REQUIRE(s > 0); > + > + struct sockaddr_in6 raddr = {}; > + raddr.sin6_family = AF_INET6; > + inet_pton(AF_INET6, "::1", &raddr.sin6_addr); > + raddr.sin6_port = htons(LISTEN_PORT); > + > + BOOST_MESSAGE("connecting..."); > + > + BOOST_REQUIRE(connect(s, (struct sockaddr *)&raddr, > sizeof(raddr)) == 0); > + sockets_to_close.push_back(s); > + } > + > + BOOST_MESSAGE("starting to accept..."); > + > + for (int i = 0; i < n_connections; i++) { > + int client_s = accept_with_timeout(listen_s, 3); > + BOOST_REQUIRE(client_s >= 0); > + BOOST_MESSAGE("accepted"); > + > + sockets_to_close.push_back(client_s); > + } > + > + BOOST_MESSAGE("closing..."); > + > + for (auto& fd : sockets_to_close) { > + close(fd); > + } > +} > + > +BOOST_AUTO_TEST_CASE(test_ipv6_clients_are_not_reset_ > when_backlog_is_full_and_they_write) > +{ > + constexpr int backlog_size = 5; > + constexpr int n_connections = backlog_size * 3; > + > + auto listen_s = socket(AF_INET6, SOCK_STREAM, 0); > + if (listen_s < 0) { > + perror("socket"); > + BOOST_REQUIRE(false); > + exit(1); > + } > + > + int reuse = 1; > + BOOST_REQUIRE(setsockopt(listen_s, SOL_SOCKET, SO_REUSEADDR, (const > char*)&reuse, sizeof(reuse)) == 0); > + > + struct sockaddr_in6 laddr = {}; > + laddr.sin6_family = AF_INET6; > + laddr.sin6_addr = in6addr_any; > + laddr.sin6_port = htons(LISTEN_PORT); > + > + if (bind(listen_s, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) { > + perror("bind"); > + BOOST_REQUIRE(false); > + exit(1); > + } > + > + BOOST_REQUIRE(listen(listen_s, backlog_size) == 0); > + > + BOOST_MESSAGE("listening..."); > + > + std::vector<std::thread*> threads; > + > + latch _latch(n_connections); > + > + for (int i = 0; i < n_connections; i++) { > + threads.push_back(new std::thread([i, &_latch] { > + int s = socket(AF_INET6, SOCK_STREAM, 0); > + if (s < 0) { > + perror("socket"); > + BOOST_REQUIRE(false); > + exit(1); > + } > + > + struct sockaddr_in6 raddr = {}; > + raddr.sin6_family = AF_INET6; > + inet_pton(AF_INET6, "::1", &raddr.sin6_addr); > + raddr.sin6_port = htons(LISTEN_PORT); > + > + _latch.count_down(); > + > + if (connect(s, (struct sockaddr *)&raddr, sizeof(raddr))) { > + perror("connect"); > + BOOST_REQUIRE(false); > + exit(1); > + } > + > + while (true) { > + const char* msg = "hello"; > + int bytes = write(s, msg, strlen(msg) + 1); > + if (bytes < 0) { > + break; > + } > + } > + close(s); > + })); > + } > + > + // Start accepting after all clients are lined up > + // to create a thundering storm effect. > + _latch.await(); > + > + for (int i = 0; i < n_connections; i++) { > + int client_s = accept_with_timeout(listen_s, 3); > + BOOST_MESSAGE("accepted"); > + > + threads.push_back(new std::thread([client_s] { > + auto close_at = _clock::now() + std::chrono::milliseconds(50); > + while (_clock::now() < close_at) { > + char buf[1]; > + int bytes = read(client_s, &buf, sizeof(buf)); > + if (bytes < 0) { > + perror("read"); > + BOOST_REQUIRE(false); > + exit(1); > + } > + } > + > + close(client_s); > + })); > + } > + > + for (auto& thread : threads) { > + thread->join(); > + delete thread; > + } > + > + close(listen_s); > +} > + > +#endif /* INET6 */ > + > -- > 2.7.4 > > -- > You received this message because you are subscribed to the Google Groups > "OSv Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
