summaryrefslogtreecommitdiff
path: root/ot_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_udp.c')
-rw-r--r--ot_udp.c58
1 files changed, 35 insertions, 23 deletions
diff --git a/ot_udp.c b/ot_udp.c
index 7aa0e61..1ec5148 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -9,7 +9,7 @@
9#include <stdio.h> 9#include <stdio.h>
10#include <stdlib.h> 10#include <stdlib.h>
11#include <string.h> 11#include <string.h>
12#include <sys/socket.h> 12#include <unistd.h>
13 13
14/* Opentracker */ 14/* Opentracker */
15#include "ot_ip.h" 15#include "ot_ip.h"
@@ -20,16 +20,16 @@
20#include "ot_udp.h" 20#include "ot_udp.h"
21#include "trackerlogic.h" 21#include "trackerlogic.h"
22 22
23/* How long a worker may sit in a read before it looks at the running flag */ 23/* One of these per worker, each allocated on its own so that growing the
24#define OT_UDP_WORKER_PATIENCE 1 24 array below never moves the one a running worker holds. */
25
26struct udp_worker { 25struct udp_worker {
27 pthread_t thread; 26 pthread_t thread;
28 int64_t sock; 27 int64_t sock;
28 _Atomic int left;
29}; 29};
30 30
31static struct udp_worker *g_workers; 31static struct udp_worker **g_workers;
32static size_t g_worker_count; 32static size_t g_worker_count;
33 33
34static uint32_t g_rijndael_round_key[44] = {0}; 34static uint32_t g_rijndael_round_key[44] = {0};
35static volatile uint32_t g_key_of_the_hour[2] = {0}; 35static volatile uint32_t g_key_of_the_hour[2] = {0};
@@ -218,7 +218,7 @@ int handle_udp6(int64_t serversocket, struct ot_workstruct *ws) {
218} 218}
219 219
220static void *udp_worker(void *args) { 220static void *udp_worker(void *args) {
221 int64_t sock = (int64_t)args; 221 struct udp_worker *me = args;
222 struct ot_workstruct ws; 222 struct ot_workstruct ws;
223 memset(&ws, 0, sizeof(ws)); 223 memset(&ws, 0, sizeof(ws));
224 224
@@ -230,7 +230,7 @@ static void *udp_worker(void *args) {
230#endif 230#endif
231 231
232 while (g_opentracker_running) 232 while (g_opentracker_running)
233 handle_udp6(sock, &ws); 233 handle_udp6(me->sock, &ws);
234 234
235 stats_counters_retire(&ws); 235 stats_counters_retire(&ws);
236 236
@@ -239,6 +239,8 @@ static void *udp_worker(void *args) {
239#ifdef _DEBUG_HTTPERROR 239#ifdef _DEBUG_HTTPERROR
240 free(ws.debugbuf); 240 free(ws.debugbuf);
241#endif 241#endif
242
243 atomic_store(&me->left, 1);
242 return NULL; 244 return NULL;
243} 245}
244 246
@@ -248,34 +250,44 @@ void udp_init(void) {
248} 250}
249 251
250void udp_worker_install(int64_t sock) { 252void udp_worker_install(int64_t sock) {
251 struct udp_worker *grown = realloc(g_workers, (g_worker_count + 1) * sizeof(*g_workers)); 253 struct udp_worker **grown = realloc(g_workers, (g_worker_count + 1) * sizeof(*g_workers));
254 struct udp_worker *worker;
252 255
253 if (!grown) { 256 if (!grown || !(worker = calloc(1, sizeof(*worker)))) {
254 fprintf(stderr, "Warning: out of memory installing a udp worker, this socket stays with the workers already running.\n"); 257 fprintf(stderr, "Warning: out of memory installing a udp worker, this socket stays with the workers already running.\n");
258 g_workers = grown ? grown : g_workers;
255 return; 259 return;
256 } 260 }
257 g_workers = grown; 261 g_workers = grown;
262 worker->sock = sock;
258 263
259#ifdef _DEBUG 264#ifdef _DEBUG
260 fprintf(stderr, "Installing a worker on udp socket %ld\n", (unsigned long)sock); 265 fprintf(stderr, "Installing a worker on udp socket %ld\n", (unsigned long)sock);
261#endif 266#endif
262 socket_set_blocking((int)sock, 1); 267 socket_set_blocking((int)sock, 1);
263 socket_set_timeout((int)sock, OT_UDP_WORKER_PATIENCE);
264 268
265 g_workers[g_worker_count].sock = sock; 269 if (pthread_create(&worker->thread, NULL, udp_worker, worker))
266 if (!pthread_create(&g_workers[g_worker_count].thread, NULL, udp_worker, (void *)sock)) 270 free(worker);
267 ++g_worker_count; 271 else
272 g_workers[g_worker_count++] = worker;
268} 273}
269 274
270void udp_workers_deinit(void) { 275void udp_workers_deinit(void) {
271 size_t i; 276 size_t i;
272 277
273 /* The receive timeout bounds this on its own, shutting the socket down 278 for (i = 0; i < g_worker_count; ++i) {
274 cuts it short wherever the platform wakes a blocked reader */ 279 struct udp_worker *worker = g_workers[i];
275 for (i = 0; i < g_worker_count; ++i) 280
276 shutdown((int)g_workers[i].sock, SHUT_RD); 281 /* Repeated because a signal only interrupts a read already under way: a
277 for (i = 0; i < g_worker_count; ++i) 282 worker that was between two reads when the first one arrived is inside
278 pthread_join(g_workers[i].thread, NULL); 283 the next one by now. */
284 while (!atomic_load(&worker->left)) {
285 pthread_kill(worker->thread, OT_SIGNAL_WAKE);
286 usleep(1000);
287 }
288 pthread_join(worker->thread, NULL);
289 free(worker);
290 }
279 291
280 free(g_workers); 292 free(g_workers);
281 g_workers = NULL; 293 g_workers = NULL;