From 31d2586e3296d424e51848ada963299b0da89324 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Fri, 30 Oct 2026 13:23:39 +0100 Subject: Defer accepts until some data actually is there --- tests/t_socket.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'tests/t_socket.c') diff --git a/tests/t_socket.c b/tests/t_socket.c index ab4b785..20a0c0a 100644 --- a/tests/t_socket.c +++ b/tests/t_socket.c @@ -78,15 +78,17 @@ static int sock_flag(int s, int level, int option) { } /* Wait for one event, so a test never blocks forever on a lost packet */ -static int wait_for(int s, short events) { +static int wait_for_ms(int s, short events, int timeout_ms) { struct pollfd pfd; pfd.fd = s; pfd.events = events; pfd.revents = 0; - return poll(&pfd, 1, 2000) == 1; + return poll(&pfd, 1, timeout_ms) == 1; } +static int wait_for(int s, short events) { return wait_for_ms(s, events, 2000); } + /* ------------------------------------------------------------ invariants */ /* Asked for the wildcard address, because a socket bound to one specific @@ -200,6 +202,42 @@ static void case_a_signal_ends_a_blocking_read(void) { close(reader_socket); } +/* What a deferred accept is for is a descriptor that already has the request + in it, so what is checked is the silence before: a client that has + connected but said nothing must not make the listener readable. Kernels + that cannot do this say so, and then there is nothing to check. */ +static void case_deferred_accept(void) { + struct sockaddr_in6 address; + char ip[16]; + uint16_t port = 0; + int listener, client; + + test_case("a connection that has sent nothing is held back from accept"); + listener = socket_tcp_listen(ip_loopback, 0, SOCKET_EXCLUSIVE); + CHECK(listener != -1); + if (socket_defer_accept(listener) == -1) { + close(listener); + return; + } + bound_address(listener, ip, &port); + + client = socket(AF_INET6, SOCK_STREAM, 0); + CHECK(client != -1); + memset(&address, 0, sizeof(address)); + address.sin6_family = AF_INET6; + address.sin6_port = htons(port); + memcpy(&address.sin6_addr, ip_loopback, 16); + CHECK_INT(connect(client, (struct sockaddr *)&address, sizeof(address)), 0); + + CHECK_INT(wait_for_ms(listener, POLLIN, 300), 0); + + CHECK_INT((int)write(client, "GET / HTTP/1.0\r\n\r\n", 18), 18); + CHECK_INT(wait_for(listener, POLLIN), 1); + + close(client); + close(listener); +} + /* An IPv4 peer must arrive in the v4 mapped form opentracker stores, however the kernel chose to report it. Linux fills a v4 mapped sockaddr_in6 here and the BSDs fill a plain sockaddr_in, so this is the case that tells the @@ -352,6 +390,7 @@ void test_socket(void) { case_a_signal_ends_a_blocking_read(); case_udp_v4mapped(); case_tcp_roundtrip(); + case_deferred_accept(); case_connect_refused(); case_bind_failure(); #ifdef WANT_SYNC_LIVE -- cgit v1.3