From 0f95c7d1056cab5bd8c6334cf601349ac4631457 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Thu, 29 Oct 2026 00:53:50 +0100 Subject: Revert last wake-up experiment. Having each udp worker wake up once a second to check if the tracker stops is wasteful --- tests/t_socket.c | 91 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 37 deletions(-) (limited to 'tests/t_socket.c') diff --git a/tests/t_socket.c b/tests/t_socket.c index ede8ae0..ab4b785 100644 --- a/tests/t_socket.c +++ b/tests/t_socket.c @@ -8,14 +8,18 @@ #include #include #include +#include +#include +#include #include #include -#include +#include #include /* Opentracker */ #include "ot_ip.h" #include "ot_socket.h" +#include "trackerlogic.h" #include "test.h" /* These cases talk to the loopback interface rather than to a mock, because @@ -145,42 +149,55 @@ static void case_udp_roundtrip(void) { close(s); } -/* udp_workers_deinit relies on a worker parked in a read coming back. The - receive timeout is what guarantees that; shutting the socket down is what - makes it prompt where the platform allows it. Neither is uniform across the - systems opentracker runs on, so both are checked rather than assumed. */ -static void case_blocking_read_comes_back(void) { - char buf[32], ip[16], own_ip[16]; - uint16_t port = 0, own_port = 0; - time_t started; - int s; - - test_case("a receive timeout does not delay a datagram that is already there"); - s = socket_udp_bind(ip_loopback, 0, SOCKET_EXCLUSIVE); - CHECK(s != -1); - CHECK_INT(socket_set_blocking(s, 1), 0); - CHECK_INT(socket_set_timeout(s, 1), 0); - bound_address(s, own_ip, &own_port); - CHECK_INT(socket_send(s, "opentracker", 11, own_ip, own_port), 11); - CHECK_INT(socket_recv(s, buf, sizeof(buf), ip, &port), 11); - - test_case("and ends a read that would otherwise never return"); - started = time(NULL); - CHECK_INT(socket_recv(s, buf, sizeof(buf), ip, &port), -1); - CHECK(errno == EAGAIN || errno == EWOULDBLOCK); - CHECK(time(NULL) - started <= 3); - close(s); +/* udp_workers_deinit and livesync_deinit end a read another thread is parked + in by signalling that thread. Which mechanisms wake a blocked reader + differs between kernels -- shutting the socket down does so on Linux and + FreeBSD but not on Darwin, closing it does so on Darwin but not on Linux -- + so the one the tracker relies on is checked rather than assumed. The + watchdog is the test's own: where a reader is not woken this fails with a + figure to look at instead of hanging the suite. */ +static _Atomic int reader_returned; +static int reader_socket; + +static void reader_wake(int s) { (void)s; } + +static void *blocked_reader(void *args) { + char buf[32], ip[16]; + uint16_t port = 0; + + (void)args; + socket_recv(reader_socket, buf, sizeof(buf), ip, &port); + atomic_store(&reader_returned, 1); + return NULL; +} - test_case("shutting the socket down ends one too"); - s = socket_udp_bind(ip_loopback, 0, SOCKET_EXCLUSIVE); - CHECK(s != -1); - CHECK_INT(socket_set_blocking(s, 1), 0); - CHECK_INT(socket_set_timeout(s, 1), 0); - shutdown(s, SHUT_RD); - started = time(NULL); - CHECK(socket_recv(s, buf, sizeof(buf), ip, &port) <= 0); - CHECK(time(NULL) - started <= 3); - close(s); +static void case_a_signal_ends_a_blocking_read(void) { + struct sigaction sa; + struct timeval watchdog = {2, 0}; + pthread_t thread; + int waited; + + test_case("a signal ends a read another thread is parked in"); + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = reader_wake; + sa.sa_flags = 0; /* SA_RESTART would resume the read instead of ending it */ + CHECK_INT(sigaction(OT_SIGNAL_WAKE, &sa, NULL), 0); + + atomic_store(&reader_returned, 0); + reader_socket = socket_udp_bind(ip_loopback, 0, SOCKET_EXCLUSIVE); + CHECK(reader_socket != -1); + CHECK_INT(socket_set_blocking(reader_socket, 1), 0); + CHECK_INT(setsockopt(reader_socket, SOL_SOCKET, SO_RCVTIMEO, &watchdog, sizeof(watchdog)), 0); + + CHECK_INT(pthread_create(&thread, NULL, blocked_reader, NULL), 0); + usleep(100000); /* long enough to be sure it reached the read */ + CHECK_INT(pthread_kill(thread, OT_SIGNAL_WAKE), 0); + + for (waited = 0; waited < 1000 && !atomic_load(&reader_returned); ++waited) + usleep(1000); + CHECK(waited < 1000); + pthread_join(thread, NULL); + close(reader_socket); } /* An IPv4 peer must arrive in the v4 mapped form opentracker stores, however @@ -332,7 +349,7 @@ void test_socket(void) { case_sharing_is_opt_in(); #endif case_udp_roundtrip(); - case_blocking_read_comes_back(); + case_a_signal_ends_a_blocking_read(); case_udp_v4mapped(); case_tcp_roundtrip(); case_connect_refused(); -- cgit v1.3