summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-25 19:13:36 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-10-25 19:13:36 +0100
commit7d9a0b7bb11ca99513cb48a6611d7121ecc35868 (patch)
treedd8b0df7df4ac80152406005c5a97e2b4acedcbd /opentracker.c
parent28f43d02149c96b87555e08f79e0c33c7a07e1af (diff)
Split options parsing and config code from opentracker.c, it has grown humongous
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c543
1 files changed, 15 insertions, 528 deletions
diff --git a/opentracker.c b/opentracker.c
index 1b0e119..698669c 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -27,6 +27,7 @@
27 27
28/* Opentracker */ 28/* Opentracker */
29#include "ot_accesslist.h" 29#include "ot_accesslist.h"
30#include "ot_config.h"
30#include "ot_hex.h" 31#include "ot_hex.h"
31#include "ot_http.h" 32#include "ot_http.h"
32#include "ot_ip.h" 33#include "ot_ip.h"
@@ -41,29 +42,10 @@
41 42
42/* Globals */ 43/* Globals */
43time_t g_now_seconds; 44time_t g_now_seconds;
44char *g_redirecturl;
45uint32_t g_tracker_id; 45uint32_t g_tracker_id;
46volatile int g_opentracker_running = 1; 46volatile int g_opentracker_running = 1;
47int g_self_pipe[2]; 47int g_self_pipe[2];
48 48
49static char *g_serverdir;
50static char *g_serveruser;
51
52typedef struct {
53 ot_ip6 ip;
54 uint16_t port;
55 PROTO_FLAG proto;
56 int shared;
57 int workers;
58 int64_t sock;
59} ot_listen;
60#define OT_LISTEN_INHERIT (-1)
61
62/* Config entries collected from command line and config files */
63static ot_listen *g_listen;
64static size_t g_listen_count;
65static int g_listen_shared;
66static int g_listen_workers;
67 49
68static void panic(const char *routine) __attribute__((noreturn)); 50static void panic(const char *routine) __attribute__((noreturn));
69static void panic(const char *routine) { 51static void panic(const char *routine) {
@@ -115,42 +97,6 @@ static void install_signal_handlers(void) {
115 pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL); 97 pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL);
116} 98}
117 99
118static void usage(char *name) {
119 fprintf(stderr,
120 "Usage: %s [-i ip] [-p port] [-P port] [-r redirect] [-d dir] [-u user] [-A ip[/bits]] [-f config] [-s livesyncport]"
121#ifdef WANT_ACCESSLIST_BLACK
122 " [-b blacklistfile]"
123#elif defined(WANT_ACCESSLIST_WHITE)
124 " [-w whitelistfile]"
125#endif
126 "\n",
127 name);
128}
129
130#define HELPLINE(opt, desc) fprintf(stderr, "\t%-10s%s\n", opt, desc)
131static void help(char *name) {
132 usage(name);
133
134 HELPLINE("-f config", "include and execute the config file");
135 HELPLINE("-i ip", "specify ip to bind to with next -[pP] (default: any, overrides preceeding ones)");
136 HELPLINE("-p port", "do bind to tcp port (default: 6969, you may specify more than one)");
137 HELPLINE("-P port", "do bind to udp port (default: 6969, you may specify more than one)");
138 HELPLINE("-r redirecturl", "specify url where / should be redirected to (default none)");
139 HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")");
140 HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")");
141 HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)");
142#ifdef WANT_ACCESSLIST_BLACK
143 HELPLINE("-b file", "specify blacklist file.");
144#elif defined(WANT_ACCESSLIST_WHITE)
145 HELPLINE("-w file", "specify whitelist file.");
146#endif
147
148 fprintf(stderr, "\nExample: ./opentracker -i 127.0.0.1 -p 6969 -P 6969 -f ./opentracker.conf -i 10.1.1.23 -p 2710 -p 80\n");
149 fprintf(stderr, " Here -i 127.0.0.1 selects the ip address for the next -p 6969 and -P 6969.\n");
150 fprintf(stderr, " If no port is bound from config file or command line, the last address given\n");
151 fprintf(stderr, " (or ::1 if none is set) will be used on port 6969.\n");
152}
153#undef HELPLINE
154 100
155static ssize_t header_complete(char *request, ssize_t byte_count) { 101static ssize_t header_complete(char *request, ssize_t byte_count) {
156 ssize_t i = 0, state = 0; 102 ssize_t i = 0, state = 0;
@@ -353,91 +299,9 @@ static void *server_mainloop(void *args) {
353 return 0; 299 return 0;
354} 300}
355 301
356static void listen_append(const ot_ip6 ip, uint16_t port, PROTO_FLAG proto, int shared, int workers) {
357 ot_listen *grown = realloc(g_listen, (g_listen_count + 1) * sizeof(ot_listen));
358 ot_listen *entry;
359
360 if (!grown)
361 panic("listen_append");
362 g_listen = grown;
363
364 entry = g_listen + g_listen_count++;
365 memcpy(entry->ip, ip, sizeof(ot_ip6));
366 entry->port = port;
367 entry->proto = proto;
368 entry->shared = shared;
369 entry->workers = workers;
370 entry->sock = -1;
371}
372
373typedef enum { LISTEN_OPTION_UNKNOWN, LISTEN_OPTION_SHARED, LISTEN_OPTION_WORKERS } listen_option_kind;
374
375typedef struct {
376 const char *name;
377 size_t len;
378 listen_option_kind kind;
379 int takes_value;
380} listen_option_key;
381
382#define LISTEN_OPTION_KEY(s, k, v) {s, sizeof(s) - 1, k, v}
383
384static const listen_option_key listen_option_keys[] = {
385 LISTEN_OPTION_KEY("shared", LISTEN_OPTION_SHARED, 0),
386 LISTEN_OPTION_KEY("workers", LISTEN_OPTION_WORKERS, 1),
387};
388static const size_t listen_option_count = sizeof(listen_option_keys) / sizeof(listen_option_keys[0]);
389
390static listen_option_kind parse_listen_option(char **p) {
391 size_t i;
392
393 for (i = 0; i < listen_option_count; ++i) {
394 const listen_option_key *key = &listen_option_keys[i];
395 char delimiter = (*p)[key->len];
396
397 if (strncmp(*p, key->name, key->len))
398 continue;
399 if (key->takes_value ? delimiter != '=' : (delimiter && !isspace((unsigned char)delimiter)))
400 continue;
401
402 *p += key->len + (key->takes_value ? 1 : 0);
403 return key->kind;
404 }
405 return LISTEN_OPTION_UNKNOWN;
406}
407
408/* Options trailing an address in a listen statement, in any order */
409static int listen_scan_options(char *p, int *shared, int *workers) {
410 uint64_t value;
411
412 for (;;) {
413 while (isspace((unsigned char)*p))
414 ++p;
415 if (!*p)
416 return 1;
417
418 switch (parse_listen_option(&p)) {
419 case LISTEN_OPTION_SHARED:
420 *shared = 1;
421 break;
422 case LISTEN_OPTION_WORKERS: {
423 size_t off = scan_udec(p, &value, UINT_MAX);
424
425 if (!off)
426 return 0;
427 *workers = (int)value;
428 p += off;
429 break;
430 }
431 default:
432 return 0;
433 }
434 }
435}
436
437static int listen_option(int value, int fallback) { return value == OT_LISTEN_INHERIT ? fallback : value; }
438 302
439static void listen_bind_one(ot_listen *entry) { 303static void listen_bind_one(ot_listen *entry) {
440 socket_sharing sharing = listen_option(entry->shared, g_listen_shared) ? SOCKET_SHARED : SOCKET_EXCLUSIVE; 304 socket_sharing sharing = entry->shared ? SOCKET_SHARED : SOCKET_EXCLUSIVE;
441 305
442#ifdef _DEBUG 306#ifdef _DEBUG
443 { 307 {
@@ -482,305 +346,31 @@ static void listen_bind_one(ot_listen *entry) {
482/* Bound in the order the entries were given. 346/* Bound in the order the entries were given.
483 Note: On macOS SO_REUSEPORT delivers everything to the socket that bound last. */ 347 Note: On macOS SO_REUSEPORT delivers everything to the socket that bound last. */
484static void listen_bind_all(void) { 348static void listen_bind_all(void) {
485 size_t i; 349 size_t count, i;
350 ot_listen *entries = config_listen_entries(&count);
486 351
487 for (i = 0; i < g_listen_count; ++i) 352 for (i = 0; i < count; ++i)
488 listen_bind_one(g_listen + i); 353 listen_bind_one(entries + i);
489} 354}
490 355
491static void listen_start_udp_workers(void) { 356static void listen_start_udp_workers(void) {
492 size_t i; 357 size_t count, i;
358 ot_listen *entries = config_listen_entries(&count);
493 359
494 udp_init(); 360 udp_init();
495 361
496 for (i = 0; i < g_listen_count; ++i) { 362 for (i = 0; i < count; ++i) {
497 ot_listen *entry = g_listen + i; 363 ot_listen *entry = entries + i;
498 int workers = listen_option(entry->workers, g_listen_workers);
499 364
500 if (entry->proto != FLAG_UDP || workers <= 0) 365 if (entry->proto != FLAG_UDP || entry->workers <= 0)
501 continue; 366 continue;
502 367
503 io_block(entry->sock); 368 io_block(entry->sock);
504 udp_workers_install(entry->sock, (unsigned int)workers); 369 udp_workers_install(entry->sock, (unsigned int)entry->workers);
505 }
506}
507
508char *set_config_option(char **option, char *value) {
509#ifdef _DEBUG
510 fprintf(stderr, "Setting config option: %s\n", value);
511#endif
512 while (isspace(*value))
513 ++value;
514 free(*option);
515 return *option = strdup(value);
516}
517
518static int scan_ip6_port(const char *src, ot_ip6 ip, uint16_t *port) {
519 const char *s = src;
520 uint64_t value;
521 int off, bracket = 0;
522 while (isspace(*s))
523 ++s;
524 if (*s == '[')
525 ++s, ++bracket; /* for v6 style notation */
526 if (!(off = ip_scan(s, ip)))
527 return 0;
528 s += off;
529 if (bracket && *s == ']')
530 ++s;
531 if (*s == 0 || isspace(*s))
532 return s - src;
533 if (!ip_is_v4mapped(ip)) {
534 if (*s != ':' && *s != '.')
535 return 0;
536 if (!bracket && *(s) == ':')
537 return 0;
538 s++;
539 } else {
540 if (*(s++) != ':')
541 return 0;
542 }
543 if (!(off = scan_udec(s, &value, 65535)))
544 return 0;
545 *port = (uint16_t)value;
546 return off + s - src;
547}
548
549static int scan_ip6_net(const char *src, ot_net *net) {
550 const char *s = src;
551 uint64_t value;
552 int off;
553 while (isspace(*s))
554 ++s;
555 if (!(off = ip_scan(s, net->address)))
556 return 0;
557 s += off;
558 if (*s != '/')
559 net->bits = 128;
560 else {
561 s++;
562 if (!(off = scan_udec(s, &value, 128)))
563 return 0;
564 net->bits = (int)value;
565 if (ip_is_v4mapped(net->address))
566 net->bits += 96;
567 if (net->bits > 128)
568 return 0;
569 s += off;
570 } 370 }
571 return off + s - src;
572}
573
574typedef enum {
575 CONFIG_UNKNOWN,
576 CONFIG_TRACKER_ROOTDIR,
577 CONFIG_TRACKER_USER,
578 CONFIG_LISTEN_TCP_UDP,
579 CONFIG_LISTEN_TCP,
580 CONFIG_LISTEN_UDP,
581 CONFIG_LISTEN_UDP_WORKERS,
582 CONFIG_LISTEN_SHARED,
583 CONFIG_ACCESS_WHITELIST,
584 CONFIG_ACCESS_BLACKLIST,
585 CONFIG_ACCESS_FIFO_ADD,
586 CONFIG_ACCESS_FIFO_DELETE,
587 CONFIG_ACCESS_STATS,
588 CONFIG_ACCESS_STATS_PATH,
589 CONFIG_ACCESS_PROXY,
590 CONFIG_TRACKER_REDIRECT_URL,
591 CONFIG_LIVESYNC_CLUSTER_NODE_IP,
592 CONFIG_LIVESYNC_CLUSTER_LISTEN,
593} config_kind;
594
595typedef struct {
596 const char *name;
597 size_t len;
598 config_kind kind;
599} config_key;
600
601#define CONFIG_KEY(s, k) { s, sizeof(s) - 1, k }
602
603static const config_key config_keys[] = {
604 CONFIG_KEY("tracker.rootdir", CONFIG_TRACKER_ROOTDIR),
605 CONFIG_KEY("tracker.user", CONFIG_TRACKER_USER),
606 CONFIG_KEY("listen.tcp_udp", CONFIG_LISTEN_TCP_UDP),
607 CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP),
608 CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP),
609 CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS),
610 CONFIG_KEY("listen.shared", CONFIG_LISTEN_SHARED),
611#ifdef WANT_ACCESSLIST_WHITE
612 CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST),
613#elif defined(WANT_ACCESSLIST_BLACK)
614 CONFIG_KEY("access.blacklist", CONFIG_ACCESS_BLACKLIST),
615#endif
616#ifdef WANT_DYNAMIC_ACCESSLIST
617 CONFIG_KEY("access.fifo_add", CONFIG_ACCESS_FIFO_ADD),
618 CONFIG_KEY("access.fifo_delete", CONFIG_ACCESS_FIFO_DELETE),
619#endif
620#ifdef WANT_RESTRICT_STATS
621 CONFIG_KEY("access.stats", CONFIG_ACCESS_STATS),
622#endif
623 CONFIG_KEY("access.stats_path", CONFIG_ACCESS_STATS_PATH),
624#ifdef WANT_IP_FROM_PROXY
625 CONFIG_KEY("access.proxy", CONFIG_ACCESS_PROXY),
626#endif
627 CONFIG_KEY("tracker.redirect_url", CONFIG_TRACKER_REDIRECT_URL),
628#ifdef WANT_SYNC_LIVE
629 CONFIG_KEY("livesync.cluster.node_ip", CONFIG_LIVESYNC_CLUSTER_NODE_IP),
630 CONFIG_KEY("livesync.cluster.listen", CONFIG_LIVESYNC_CLUSTER_LISTEN),
631#endif
632};
633static const size_t config_entry_count = sizeof(config_keys) / sizeof(config_keys[0]);
634
635static config_kind parse_config_key(char **p) {
636 size_t i;
637 for (i = 0; i < config_entry_count; ++i) {
638 const config_key *key = &config_keys[i];
639 if (strncmp(*p, key->name, key->len) == 0 && isspace((unsigned char)(*p)[key->len])) {
640 *p += key->len + 1;
641 /* Skip white spaces */
642 while (isspace((unsigned char)**p))
643 ++(*p);
644 return key->kind;
645 }
646 }
647 return CONFIG_UNKNOWN;
648} 371}
649 372
650int parse_configfile(char *config_filename) {
651 FILE *config_file_handle;
652 char inbuf[512];
653 ot_ip6 tmpip;
654#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE)
655 ot_net tmpnet;
656#endif
657 int bound = 0;
658 373
659 config_file_handle = fopen(config_filename, "r");
660
661 if (config_file_handle == NULL) {
662 fprintf(stderr, "Warning: Can't open config file: %s.", config_filename);
663 return 0;
664 }
665
666 while (fgets(inbuf, sizeof(inbuf), config_file_handle)) {
667 char *p = inbuf, *end;
668 uint64_t value;
669 uint16_t tmpport = 6969;
670 config_kind kind;
671
672 /* Skip white spaces */
673 while (isspace((unsigned char)*p))
674 ++p;
675
676 /* Ignore comments and empty lines */
677 if ((*p == '#') || (*p == '\n') || (*p == 0))
678 continue;
679
680 /* consume trailing new lines and spaces */
681 end = p + strlen(p);
682 while (end > p && isspace((unsigned char)end[-1]))
683 *--end = 0;
684
685 /* Scan for commands */
686 kind = parse_config_key(&p);
687 switch (kind) {
688 case CONFIG_TRACKER_ROOTDIR:
689 set_config_option(&g_serverdir, p);
690 break;
691 case CONFIG_TRACKER_USER:
692 set_config_option(&g_serveruser, p);
693 break;
694 case CONFIG_LISTEN_TCP_UDP:
695 case CONFIG_LISTEN_TCP:
696 case CONFIG_LISTEN_UDP: {
697 int shared = OT_LISTEN_INHERIT;
698 int workers = OT_LISTEN_INHERIT;
699 int off = scan_ip6_port(p, tmpip, &tmpport);
700
701 if (!off || !listen_scan_options(p + off, &shared, &workers))
702 goto parse_error;
703 if (kind != CONFIG_LISTEN_UDP)
704 listen_append(tmpip, tmpport, FLAG_TCP, shared, OT_LISTEN_INHERIT), ++bound;
705 if (kind != CONFIG_LISTEN_TCP)
706 listen_append(tmpip, tmpport, FLAG_UDP, shared, workers), ++bound;
707 break;
708 }
709 case CONFIG_LISTEN_UDP_WORKERS:
710 if (!scan_udec(p, &value, UINT_MAX))
711 goto parse_error;
712 g_listen_workers = (int)value;
713 break;
714 case CONFIG_LISTEN_SHARED:
715 if (!scan_udec(p, &value, 1))
716 goto parse_error;
717 g_listen_shared = (int)value;
718 break;
719#ifdef WANT_ACCESSLIST_WHITE
720 case CONFIG_ACCESS_WHITELIST:
721 set_config_option(&g_accesslist_filename, p);
722 break;
723#elif defined(WANT_ACCESSLIST_BLACK)
724 case CONFIG_ACCESS_BLACKLIST:
725 set_config_option(&g_accesslist_filename, p);
726 break;
727#endif
728#ifdef WANT_DYNAMIC_ACCESSLIST
729 case CONFIG_ACCESS_FIFO_ADD:
730 set_config_option(&g_accesslist_pipe_add, p);
731 break;
732 case CONFIG_ACCESS_FIFO_DELETE:
733 set_config_option(&g_accesslist_pipe_delete, p);
734 break;
735#endif
736#ifdef WANT_RESTRICT_STATS
737 case CONFIG_ACCESS_STATS:
738 if (!scan_ip6_net(p, &tmpnet))
739 goto parse_error;
740 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_STAT);
741 break;
742#endif
743 case CONFIG_ACCESS_STATS_PATH:
744 set_config_option(&g_stats_path, p);
745 break;
746#ifdef WANT_IP_FROM_PROXY
747 case CONFIG_ACCESS_PROXY:
748 if (!scan_ip6_net(p, &tmpnet))
749 goto parse_error;
750 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_PROXY);
751 break;
752#endif
753 case CONFIG_TRACKER_REDIRECT_URL:
754 set_config_option(&g_redirecturl, p);
755 break;
756#ifdef WANT_SYNC_LIVE
757 case CONFIG_LIVESYNC_CLUSTER_NODE_IP:
758 if (!scan_ip6_net(p, &tmpnet))
759 goto parse_error;
760 accesslist_bless_net(&tmpnet, OT_PERMISSION_MAY_LIVESYNC);
761 break;
762 case CONFIG_LIVESYNC_CLUSTER_LISTEN:
763 tmpport = LIVESYNC_PORT;
764 {
765 int shared = OT_LISTEN_INHERIT, dummy = OT_LISTEN_INHERIT;
766 int off = scan_ip6_port(p, tmpip, &tmpport);
767
768 if (!off || !listen_scan_options(p + off, &shared, &dummy))
769 goto parse_error;
770 listen_append(tmpip, tmpport, FLAG_MCA, shared, OT_LISTEN_INHERIT);
771 }
772 break;
773#endif
774 default:
775 fprintf(stderr, "Unhandled line in config file: %s\n", inbuf);
776 break;
777 parse_error:
778 fprintf(stderr, "Parse error in config file: %s\n", inbuf);
779 }
780 }
781 fclose(config_file_handle);
782 return bound;
783}
784 374
785void load_state(const char *const state_filename) { 375void load_state(const char *const state_filename) {
786 FILE *state_filehandle; 376 FILE *state_filehandle;
@@ -873,114 +463,11 @@ static void *time_caching_worker(void *args) {
873} 463}
874 464
875int main(int argc, char **argv) { 465int main(int argc, char **argv) {
876 ot_ip6 serverip;
877 ot_net tmpnet;
878 int bound = 0, scanon = 1;
879 uint64_t value;
880 char *statefile = 0;
881 pthread_t thread_id; /* time cacher */ 466 pthread_t thread_id; /* time cacher */
882 467
883 memset(serverip, 0, sizeof(ot_ip6));
884#ifdef WANT_V4_ONLY
885 serverip[10] = serverip[11] = -1;
886#endif
887
888 random_init(); 468 random_init();
469 config_parse(argc, argv);
889 470
890 while (scanon) {
891 switch (getopt(argc, argv,
892 ":i:p:A:P:d:u:r:s:f:l:v"
893#ifdef WANT_ACCESSLIST_BLACK
894 "b:"
895#elif defined(WANT_ACCESSLIST_WHITE)
896 "w:"
897#endif
898 "h")) {
899 case -1:
900 scanon = 0;
901 break;
902 case 'i':
903 if (!ip_scan(optarg, serverip)) {
904 usage(argv[0]);
905 exit(1);
906 }
907 break;
908#ifdef WANT_ACCESSLIST_BLACK
909 case 'b':
910 set_config_option(&g_accesslist_filename, optarg);
911 break;
912#elif defined(WANT_ACCESSLIST_WHITE)
913 case 'w':
914 set_config_option(&g_accesslist_filename, optarg);
915 break;
916#endif
917 case 'p':
918 if (!scan_udec(optarg, &value, 65535)) {
919 usage(argv[0]);
920 exit(1);
921 }
922 listen_append(serverip, (uint16_t)value, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
923 bound++;
924 break;
925 case 'P':
926 if (!scan_udec(optarg, &value, 65535)) {
927 usage(argv[0]);
928 exit(1);
929 }
930 listen_append(serverip, (uint16_t)value, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
931 bound++;
932 break;
933#ifdef WANT_SYNC_LIVE
934 case 's':
935 if (!scan_udec(optarg, &value, 65535)) {
936 usage(argv[0]);
937 exit(1);
938 }
939 listen_append(serverip, (uint16_t)value, FLAG_MCA, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
940 break;
941#endif
942 case 'd':
943 set_config_option(&g_serverdir, optarg);
944 break;
945 case 'u':
946 set_config_option(&g_serveruser, optarg);
947 break;
948 case 'r':
949 set_config_option(&g_redirecturl, optarg);
950 break;
951 case 'l':
952 statefile = optarg;
953 break;
954 case 'A':
955 if (!scan_ip6_net(optarg, &tmpnet)) {
956 usage(argv[0]);
957 exit(1);
958 }
959 accesslist_bless_net(&tmpnet, 0xffff); /* Allow everything for now */
960 break;
961 case 'f':
962 bound += parse_configfile(optarg);
963 break;
964 case 'h':
965 help(argv[0]);
966 exit(0);
967 case 'v': {
968 char buffer[8192];
969 stats_return_tracker_version(buffer);
970 fputs(buffer, stderr);
971 exit(0);
972 }
973 default:
974 case '?':
975 usage(argv[0]);
976 exit(1);
977 }
978 }
979
980 if (!bound) {
981 listen_append(serverip, 6969, FLAG_TCP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
982 listen_append(serverip, 6969, FLAG_UDP, OT_LISTEN_INHERIT, OT_LISTEN_INHERIT);
983 }
984 471
985 listen_bind_all(); 472 listen_bind_all();
986 473
@@ -1017,8 +504,8 @@ int main(int argc, char **argv) {
1017 fprintf(stderr, "... done.\n"); 504 fprintf(stderr, "... done.\n");
1018#endif 505#endif
1019 506
1020 if (statefile) 507 if (g_statefile)
1021 load_state(statefile); 508 load_state(g_statefile);
1022 509
1023 install_signal_handlers(); 510 install_signal_handlers();
1024 511