summaryrefslogtreecommitdiff
path: root/tests/t_socket.c
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-29 00:53:50 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-10-29 00:53:50 +0100
commit0f95c7d1056cab5bd8c6334cf601349ac4631457 (patch)
treec7c27709ef3695659ab4b743d7ae359d4ece272b /tests/t_socket.c
parent2812a6795149f68226e940212c511b7c625c81d5 (diff)
Revert last wake-up experiment. Having each udp worker wake up once a second to check if the tracker stops is wasteful
Diffstat (limited to 'tests/t_socket.c')
-rw-r--r--tests/t_socket.c87
1 files changed, 52 insertions, 35 deletions
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 @@
8#include <fcntl.h> 8#include <fcntl.h>
9#include <netinet/in.h> 9#include <netinet/in.h>
10#include <poll.h> 10#include <poll.h>
11#include <pthread.h>
12#include <signal.h>
13#include <stdatomic.h>
11#include <string.h> 14#include <string.h>
12#include <sys/socket.h> 15#include <sys/socket.h>
13#include <time.h> 16#include <sys/time.h>
14#include <unistd.h> 17#include <unistd.h>
15 18
16/* Opentracker */ 19/* Opentracker */
17#include "ot_ip.h" 20#include "ot_ip.h"
18#include "ot_socket.h" 21#include "ot_socket.h"
22#include "trackerlogic.h"
19#include "test.h" 23#include "test.h"
20 24
21/* These cases talk to the loopback interface rather than to a mock, because 25/* These cases talk to the loopback interface rather than to a mock, because
@@ -145,42 +149,55 @@ static void case_udp_roundtrip(void) {
145 close(s); 149 close(s);
146} 150}
147 151
148/* udp_workers_deinit relies on a worker parked in a read coming back. The 152/* udp_workers_deinit and livesync_deinit end a read another thread is parked
149 receive timeout is what guarantees that; shutting the socket down is what 153 in by signalling that thread. Which mechanisms wake a blocked reader
150 makes it prompt where the platform allows it. Neither is uniform across the 154 differs between kernels -- shutting the socket down does so on Linux and
151 systems opentracker runs on, so both are checked rather than assumed. */ 155 FreeBSD but not on Darwin, closing it does so on Darwin but not on Linux --
152static void case_blocking_read_comes_back(void) { 156 so the one the tracker relies on is checked rather than assumed. The
153 char buf[32], ip[16], own_ip[16]; 157 watchdog is the test's own: where a reader is not woken this fails with a
154 uint16_t port = 0, own_port = 0; 158 figure to look at instead of hanging the suite. */
155 time_t started; 159static _Atomic int reader_returned;
156 int s; 160static int reader_socket;
157 161
158 test_case("a receive timeout does not delay a datagram that is already there"); 162static void reader_wake(int s) { (void)s; }
159 s = socket_udp_bind(ip_loopback, 0, SOCKET_EXCLUSIVE);
160 CHECK(s != -1);
161 CHECK_INT(socket_set_blocking(s, 1), 0);
162 CHECK_INT(socket_set_timeout(s, 1), 0);
163 bound_address(s, own_ip, &own_port);
164 CHECK_INT(socket_send(s, "opentracker", 11, own_ip, own_port), 11);
165 CHECK_INT(socket_recv(s, buf, sizeof(buf), ip, &port), 11);
166 163
167 test_case("and ends a read that would otherwise never return"); 164static void *blocked_reader(void *args) {
168 started = time(NULL); 165 char buf[32], ip[16];
169 CHECK_INT(socket_recv(s, buf, sizeof(buf), ip, &port), -1); 166 uint16_t port = 0;
170 CHECK(errno == EAGAIN || errno == EWOULDBLOCK);
171 CHECK(time(NULL) - started <= 3);
172 close(s);
173 167
174 test_case("shutting the socket down ends one too"); 168 (void)args;
175 s = socket_udp_bind(ip_loopback, 0, SOCKET_EXCLUSIVE); 169 socket_recv(reader_socket, buf, sizeof(buf), ip, &port);
176 CHECK(s != -1); 170 atomic_store(&reader_returned, 1);
177 CHECK_INT(socket_set_blocking(s, 1), 0); 171 return NULL;
178 CHECK_INT(socket_set_timeout(s, 1), 0); 172}
179 shutdown(s, SHUT_RD); 173
180 started = time(NULL); 174static void case_a_signal_ends_a_blocking_read(void) {
181 CHECK(socket_recv(s, buf, sizeof(buf), ip, &port) <= 0); 175 struct sigaction sa;
182 CHECK(time(NULL) - started <= 3); 176 struct timeval watchdog = {2, 0};
183 close(s); 177 pthread_t thread;
178 int waited;
179
180 test_case("a signal ends a read another thread is parked in");
181 memset(&sa, 0, sizeof(sa));
182 sa.sa_handler = reader_wake;
183 sa.sa_flags = 0; /* SA_RESTART would resume the read instead of ending it */
184 CHECK_INT(sigaction(OT_SIGNAL_WAKE, &sa, NULL), 0);
185
186 atomic_store(&reader_returned, 0);
187 reader_socket = socket_udp_bind(ip_loopback, 0, SOCKET_EXCLUSIVE);
188 CHECK(reader_socket != -1);
189 CHECK_INT(socket_set_blocking(reader_socket, 1), 0);
190 CHECK_INT(setsockopt(reader_socket, SOL_SOCKET, SO_RCVTIMEO, &watchdog, sizeof(watchdog)), 0);
191
192 CHECK_INT(pthread_create(&thread, NULL, blocked_reader, NULL), 0);
193 usleep(100000); /* long enough to be sure it reached the read */
194 CHECK_INT(pthread_kill(thread, OT_SIGNAL_WAKE), 0);
195
196 for (waited = 0; waited < 1000 && !atomic_load(&reader_returned); ++waited)
197 usleep(1000);
198 CHECK(waited < 1000);
199 pthread_join(thread, NULL);
200 close(reader_socket);
184} 201}
185 202
186/* An IPv4 peer must arrive in the v4 mapped form opentracker stores, however 203/* An IPv4 peer must arrive in the v4 mapped form opentracker stores, however
@@ -332,7 +349,7 @@ void test_socket(void) {
332 case_sharing_is_opt_in(); 349 case_sharing_is_opt_in();
333#endif 350#endif
334 case_udp_roundtrip(); 351 case_udp_roundtrip();
335 case_blocking_read_comes_back(); 352 case_a_signal_ends_a_blocking_read();
336 case_udp_v4mapped(); 353 case_udp_v4mapped();
337 case_tcp_roundtrip(); 354 case_tcp_roundtrip();
338 case_connect_refused(); 355 case_connect_refused();