diff options
Diffstat (limited to 'opentracker.c')
| -rw-r--r-- | opentracker.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/opentracker.c b/opentracker.c index 34b8fd5..e0f16d7 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -49,7 +49,9 @@ static void panic(const char *routine) { | |||
| 49 | exit(111); | 49 | exit(111); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /* Say we are stopping, wake the loop, and let main do the work on its own stack. */ | 52 | /* Say we are stopping, wake the loop, and let main do the work on its own |
| 53 | stack. Everything other than SIGINT falls through and does nothing, which | ||
| 54 | is what OT_SIGNAL_WAKE wants: returning from the read is all it is for. */ | ||
| 53 | static void signal_handler(int s) { | 55 | static void signal_handler(int s) { |
| 54 | if (s == SIGINT) { | 56 | if (s == SIGINT) { |
| 55 | const char byte = 0; | 57 | const char byte = 0; |
| @@ -84,8 +86,9 @@ static void install_signal_handlers(void) { | |||
| 84 | 86 | ||
| 85 | sa.sa_handler = signal_handler; | 87 | sa.sa_handler = signal_handler; |
| 86 | sigemptyset(&sa.sa_mask); | 88 | sigemptyset(&sa.sa_mask); |
| 87 | sa.sa_flags = SA_RESTART; | 89 | sa.sa_flags = 0; |
| 88 | if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1)) | 90 | if ((sigaction(SIGINT, &sa, NULL) == -1) || (sigaction(SIGALRM, &sa, NULL) == -1) || |
| 91 | (sigaction(OT_SIGNAL_WAKE, &sa, NULL) == -1)) | ||
| 89 | panic("install_signal_handlers"); | 92 | panic("install_signal_handlers"); |
| 90 | 93 | ||
| 91 | sigaddset(&signal_mask, SIGINT); | 94 | sigaddset(&signal_mask, SIGINT); |
| @@ -320,8 +323,17 @@ static void *server_mainloop(void *args) { | |||
| 320 | } | 323 | } |
| 321 | 324 | ||
| 322 | 325 | ||
| 326 | /* A group of sockets sharing one address only spreads datagrams if every | ||
| 327 | member asked for it before binding, the first one included, so whether | ||
| 328 | this entry will have workers has to be known here. */ | ||
| 329 | static socket_sharing listen_sharing_for(const ot_listen *entry) { | ||
| 330 | if (entry->proto == FLAG_UDP && entry->workers > 1 && socket_can_balance()) | ||
| 331 | return SOCKET_BALANCED; | ||
| 332 | return entry->shared ? SOCKET_SHARED : SOCKET_EXCLUSIVE; | ||
| 333 | } | ||
| 334 | |||
| 323 | static void listen_bind_one(ot_listen *entry) { | 335 | static void listen_bind_one(ot_listen *entry) { |
| 324 | socket_sharing sharing = entry->shared ? SOCKET_SHARED : SOCKET_EXCLUSIVE; | 336 | socket_sharing sharing = listen_sharing_for(entry); |
| 325 | 337 | ||
| 326 | #ifdef _DEBUG | 338 | #ifdef _DEBUG |
| 327 | { | 339 | { |
| @@ -370,6 +382,10 @@ static void listen_bind_all(void) { | |||
| 370 | listen_bind_one(entries + i); | 382 | listen_bind_one(entries + i); |
| 371 | } | 383 | } |
| 372 | 384 | ||
| 385 | /* The socket the event loop was using becomes the first worker's. Where the | ||
| 386 | kernel spreads datagrams, every further worker binds one of its own, so | ||
| 387 | none of them share a receive queue. | ||
| 388 | All others read from the first */ | ||
| 373 | static void listen_start_udp_workers(void) { | 389 | static void listen_start_udp_workers(void) { |
| 374 | size_t count, i; | 390 | size_t count, i; |
| 375 | ot_listen *entries = config_listen_entries(&count); | 391 | ot_listen *entries = config_listen_entries(&count); |
| @@ -377,14 +393,28 @@ static void listen_start_udp_workers(void) { | |||
| 377 | udp_init(); | 393 | udp_init(); |
| 378 | 394 | ||
| 379 | for (i = 0; i < count; ++i) { | 395 | for (i = 0; i < count; ++i) { |
| 380 | ot_listen *entry = entries + i; | 396 | ot_listen *entry = entries + i; |
| 397 | int balance = listen_sharing_for(entry) == SOCKET_BALANCED; | ||
| 398 | int worker; | ||
| 381 | 399 | ||
| 382 | if (entry->proto != FLAG_UDP || entry->workers <= 0) | 400 | if (entry->proto != FLAG_UDP || entry->workers <= 0) |
| 383 | continue; | 401 | continue; |
| 384 | 402 | ||
| 385 | socket_set_blocking((int)entry->sock, 1); | ||
| 386 | event_del((int)entry->sock); | 403 | event_del((int)entry->sock); |
| 387 | udp_workers_install(entry->sock, (unsigned int)entry->workers); | 404 | udp_worker_install(entry->sock); |
| 405 | |||
| 406 | for (worker = 1; worker < entry->workers; ++worker) { | ||
| 407 | int64_t sock = entry->sock; | ||
| 408 | |||
| 409 | if (balance) { | ||
| 410 | sock = socket_udp_bind(entry->ip, entry->port, SOCKET_BALANCED); | ||
| 411 | if (sock == -1) { | ||
| 412 | fprintf(stderr, "Warning: could not bind another socket for udp worker %d: %s. Sharing the first instead.\n", worker, strerror(errno)); | ||
| 413 | sock = entry->sock; | ||
| 414 | } | ||
| 415 | } | ||
| 416 | udp_worker_install(sock); | ||
| 417 | } | ||
| 388 | } | 418 | } |
| 389 | } | 419 | } |
| 390 | 420 | ||
| @@ -519,9 +549,10 @@ int main(int argc, char **argv) { | |||
| 519 | listen_start_udp_workers(); | 549 | listen_start_udp_workers(); |
| 520 | 550 | ||
| 521 | server_mainloop(0); | 551 | server_mainloop(0); |
| 552 | udp_workers_deinit(); | ||
| 522 | 553 | ||
| 523 | /* The loop has left, so no thread is serving any more and the teardown | 554 | /* No thread is serving any more, so the teardown can run where a debugger |
| 524 | can run where a debugger and the sanitizers can follow it */ | 555 | and the sanitizers can follow it */ |
| 525 | trackerlogic_deinit(); | 556 | trackerlogic_deinit(); |
| 526 | #ifdef WANT_SYSLOGS | 557 | #ifdef WANT_SYSLOGS |
| 527 | closelog(); | 558 | closelog(); |
