diff options
| -rw-r--r-- | Makefile | 46 | ||||
| -rw-r--r-- | opentracker.c | 43 | ||||
| -rw-r--r-- | ot_clean.h | 2 | ||||
| -rw-r--r-- | ot_fullscrape.c | 2 | ||||
| -rw-r--r-- | ot_fullscrape.h | 2 | ||||
| -rw-r--r-- | ot_http.c | 16 | ||||
| -rw-r--r-- | ot_http.h | 14 | ||||
| -rw-r--r-- | ot_iovec.c | 3 | ||||
| -rw-r--r-- | ot_livesync.c | 42 | ||||
| -rw-r--r-- | ot_livesync.h | 4 | ||||
| -rw-r--r-- | ot_mutex.c | 10 | ||||
| -rw-r--r-- | ot_mutex.h | 14 | ||||
| -rw-r--r-- | ot_socket.c | 256 | ||||
| -rw-r--r-- | ot_socket.h | 45 | ||||
| -rw-r--r-- | ot_stats.c | 10 | ||||
| -rw-r--r-- | ot_stats.h | 2 | ||||
| -rw-r--r-- | ot_sync.c | 2 | ||||
| -rw-r--r-- | ot_sync.h | 4 | ||||
| -rw-r--r-- | ot_udp.c | 26 | ||||
| -rw-r--r-- | ot_udp.h | 8 | ||||
| -rw-r--r-- | ot_vector.h | 5 | ||||
| -rw-r--r-- | proxy.c | 81 | ||||
| -rw-r--r-- | scan_urlencoded_query.c | 14 | ||||
| -rw-r--r-- | scan_urlencoded_query.h | 4 | ||||
| -rw-r--r-- | tests/runner.c | 1 | ||||
| -rw-r--r-- | tests/t_scan_urlencoded_query.c | 9 | ||||
| -rw-r--r-- | tests/t_socket.c | 307 | ||||
| -rw-r--r-- | tests/test.h | 1 |
28 files changed, 775 insertions, 198 deletions
| @@ -68,36 +68,50 @@ CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread | |||
| 68 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread | 68 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread |
| 69 | 69 | ||
| 70 | BINARY =opentracker | 70 | BINARY =opentracker |
| 71 | HEADERS=trackerlogic.h scan_urlencoded_query.h ot_buf.h ot_hex.h ot_ip.h ot_scan.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h | 71 | HEADERS=trackerlogic.h scan_urlencoded_query.h ot_buf.h ot_hex.h ot_ip.h ot_scan.h ot_socket.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h |
| 72 | SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_buf.c ot_hex.c ot_ip.c ot_scan.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c | 72 | SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_buf.c ot_hex.c ot_ip.c ot_scan.c ot_socket.c ot_mutex.c ot_random.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c ot_rijndael.c |
| 73 | SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c ot_ip.c | 73 | SOURCES_proxy=proxy.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c ot_ip.c ot_socket.c |
| 74 | 74 | ||
| 75 | OBJECTS = $(SOURCES:%.c=%.o) | 75 | OBJECTS = $(SOURCES:%.c=%.o) |
| 76 | OBJECTS_debug = $(SOURCES:%.c=%.debug.o) | 76 | OBJECTS_debug = $(SOURCES:%.c=%.debug.o) |
| 77 | OBJECTS_proxy = $(SOURCES_proxy:%.c=%.o) | 77 | OBJECTS_proxy = $(SOURCES_proxy:%.c=%.proxy.o) |
| 78 | OBJECTS_proxy_debug = $(SOURCES_proxy:%.c=%.debug.o) | 78 | OBJECTS_proxy_debug = $(SOURCES_proxy:%.c=%.proxy.debug.o) |
| 79 | 79 | ||
| 80 | .SUFFIXES: .debug.o .o .c | 80 | .SUFFIXES: .proxy.debug.o .proxy.o .debug.o .o .c |
| 81 | 81 | ||
| 82 | all: $(BINARY) $(BINARY).debug | 82 | all: $(BINARY) $(BINARY).debug |
| 83 | 83 | ||
| 84 | CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES) | 84 | CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES) |
| 85 | CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES) | 85 | CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES) |
| 86 | 86 | ||
| 87 | $(BINARY): $(OBJECTS) $(HEADERS) | 87 | CFLAGS_proxy = $(CFLAGS_production) -DWANT_SYNC_LIVE |
| 88 | CFLAGS_proxy_debug = $(CFLAGS_debug) -DWANT_SYNC_LIVE | ||
| 89 | |||
| 90 | $(BINARY): $(OBJECTS) | ||
| 88 | $(CC) -o $@ $(OBJECTS) $(LDFLAGS) | 91 | $(CC) -o $@ $(OBJECTS) $(LDFLAGS) |
| 89 | $(STRIP) $@ | 92 | $(STRIP) $@ |
| 90 | $(BINARY).debug: $(OBJECTS_debug) $(HEADERS) | 93 | $(BINARY).debug: $(OBJECTS_debug) |
| 91 | $(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS) | 94 | $(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS) |
| 92 | proxy: $(OBJECTS_proxy) $(HEADERS) | 95 | proxy: $(OBJECTS_proxy) |
| 93 | $(CC) -o $@ $(OBJECTS_proxy) $(CFLAGS_production) $(LDFLAGS) | 96 | $(CC) -o $@ $(OBJECTS_proxy) $(CFLAGS_production) $(LDFLAGS) |
| 94 | proxy.debug: $(OBJECTS_proxy_debug) $(HEADERS) | 97 | proxy.debug: $(OBJECTS_proxy_debug) |
| 95 | $(CC) -o $@ $(OBJECTS_proxy_debug) $(LDFLAGS) | 98 | $(CC) -o $@ $(OBJECTS_proxy_debug) $(LDFLAGS) |
| 96 | 99 | ||
| 97 | .c.debug.o : $(HEADERS) | 100 | $(OBJECTS): $(HEADERS) |
| 101 | $(OBJECTS_debug): $(HEADERS) | ||
| 102 | $(OBJECTS_proxy): $(HEADERS) | ||
| 103 | $(OBJECTS_proxy_debug): $(HEADERS) | ||
| 104 | |||
| 105 | .c.proxy.debug.o : | ||
| 106 | $(CC) -c -o $@ $(CFLAGS_proxy_debug) $(<:.proxy.debug.o=.c) | ||
| 107 | |||
| 108 | .c.proxy.o : | ||
| 109 | $(CC) -c -o $@ $(CFLAGS_proxy) $(<:.proxy.o=.c) | ||
| 110 | |||
| 111 | .c.debug.o : | ||
| 98 | $(CC) -c -o $@ $(CFLAGS_debug) $(<:.debug.o=.c) | 112 | $(CC) -c -o $@ $(CFLAGS_debug) $(<:.debug.o=.c) |
| 99 | 113 | ||
| 100 | .c.o : $(HEADERS) | 114 | .c.o : |
| 101 | $(CC) -c -o $@ $(CFLAGS_production) $< | 115 | $(CC) -c -o $@ $(CFLAGS_production) $< |
| 102 | 116 | ||
| 103 | # Unit tests. The modules under test are compiled straight into the test | 117 | # Unit tests. The modules under test are compiled straight into the test |
| @@ -105,12 +119,12 @@ proxy.debug: $(OBJECTS_proxy_debug) $(HEADERS) | |||
| 105 | # has to. tests/stubs.c supplies the few symbols those modules reference but | 119 | # has to. tests/stubs.c supplies the few symbols those modules reference but |
| 106 | # the tests never reach. | 120 | # the tests never reach. |
| 107 | TESTBIN=tests/runner | 121 | TESTBIN=tests/runner |
| 108 | TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_scan_urlencoded_query.c tests/t_iovec.c tests/t_vector.c tests/t_random.c tests/t_hex.c tests/t_accesslist.c tests/t_scan.c tests/t_buf.c tests/t_ip.c | 122 | TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_scan_urlencoded_query.c tests/t_iovec.c tests/t_vector.c tests/t_random.c tests/t_hex.c tests/t_accesslist.c tests/t_scan.c tests/t_buf.c tests/t_ip.c tests/t_socket.c |
| 109 | TEST_UNITS=scan_urlencoded_query.c ot_buf.c ot_ip.c ot_iovec.c ot_vector.c ot_random.c ot_hex.c ot_scan.c ot_accesslist.c | 123 | TEST_UNITS=scan_urlencoded_query.c ot_buf.c ot_ip.c ot_socket.c ot_iovec.c ot_vector.c ot_random.c ot_hex.c ot_scan.c ot_accesslist.c |
| 110 | TEST_HEADERS=tests/test.h $(HEADERS) | 124 | TEST_HEADERS=tests/test.h $(HEADERS) |
| 111 | # Tests reach code that sits behind feature flags, so the units under test are | 125 | # Tests reach code that sits behind feature flags, so the units under test are |
| 112 | # built with those features enabled. A test binary is not a production binary. | 126 | # built with those features enabled. A test binary is not a production binary. |
| 113 | FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK | 127 | FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE |
| 114 | CFLAGS_test = $(CFLAGS) -I. -g -O1 $(FEATURES_test) | 128 | CFLAGS_test = $(CFLAGS) -I. -g -O1 $(FEATURES_test) |
| 115 | 129 | ||
| 116 | $(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) | 130 | $(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) |
| @@ -122,7 +136,7 @@ check: $(TESTBIN) | |||
| 122 | .PHONY: all check clean install | 136 | .PHONY: all check clean install |
| 123 | 137 | ||
| 124 | clean: | 138 | clean: |
| 125 | rm -rf opentracker opentracker.debug $(TESTBIN) *.o *~ | 139 | rm -rf opentracker opentracker.debug proxy proxy.debug $(TESTBIN) *.o *~ |
| 126 | 140 | ||
| 127 | install: | 141 | install: |
| 128 | install -m 755 opentracker $(DESTDIR)$(BINDIR) | 142 | install -m 755 opentracker $(DESTDIR)$(BINDIR) |
diff --git a/opentracker.c b/opentracker.c index 8a39bde..5b197d1 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | /* Libowfat */ | 24 | /* Libowfat */ |
| 25 | #include "io.h" | 25 | #include "io.h" |
| 26 | #include "iob.h" | 26 | #include "iob.h" |
| 27 | #include "socket.h" | ||
| 28 | 27 | ||
| 29 | /* Opentracker */ | 28 | /* Opentracker */ |
| 30 | #include "ot_accesslist.h" | 29 | #include "ot_accesslist.h" |
| @@ -35,6 +34,7 @@ | |||
| 35 | #include "ot_mutex.h" | 34 | #include "ot_mutex.h" |
| 36 | #include "ot_random.h" | 35 | #include "ot_random.h" |
| 37 | #include "ot_scan.h" | 36 | #include "ot_scan.h" |
| 37 | #include "ot_socket.h" | ||
| 38 | #include "ot_stats.h" | 38 | #include "ot_stats.h" |
| 39 | #include "ot_udp.h" | 39 | #include "ot_udp.h" |
| 40 | #include "trackerlogic.h" | 40 | #include "trackerlogic.h" |
| @@ -156,7 +156,7 @@ static ssize_t header_complete(char *request, ssize_t byte_count) { | |||
| 156 | return 0; | 156 | return 0; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | static void handle_dead(const int64 sock) { | 159 | static void handle_dead(const int64_t sock) { |
| 160 | struct http_data *cookie = io_getcookie(sock); | 160 | struct http_data *cookie = io_getcookie(sock); |
| 161 | if (cookie) { | 161 | if (cookie) { |
| 162 | size_t i; | 162 | size_t i; |
| @@ -171,7 +171,7 @@ static void handle_dead(const int64 sock) { | |||
| 171 | io_close(sock); | 171 | io_close(sock); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static void handle_read(const int64 sock, struct ot_workstruct *ws) { | 174 | static void handle_read(const int64_t sock, struct ot_workstruct *ws) { |
| 175 | struct http_data *cookie = io_getcookie(sock); | 175 | struct http_data *cookie = io_getcookie(sock); |
| 176 | ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); | 176 | ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); |
| 177 | 177 | ||
| @@ -215,7 +215,7 @@ static void handle_read(const int64 sock, struct ot_workstruct *ws) { | |||
| 215 | } | 215 | } |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | static void handle_write(const int64 sock) { | 218 | static void handle_write(const int64_t sock) { |
| 219 | struct http_data *cookie = io_getcookie(sock); | 219 | struct http_data *cookie = io_getcookie(sock); |
| 220 | size_t i; | 220 | size_t i; |
| 221 | int chunked = 0; | 221 | int chunked = 0; |
| @@ -227,7 +227,7 @@ static void handle_write(const int64 sock) { | |||
| 227 | 227 | ||
| 228 | for (i = 0; i < cookie->batches; ++i) { | 228 | for (i = 0; i < cookie->batches; ++i) { |
| 229 | if (cookie->batch[i].bytesleft) { | 229 | if (cookie->batch[i].bytesleft) { |
| 230 | int64 res = iob_send(sock, cookie->batch + i); | 230 | int64_t res = iob_send(sock, cookie->batch + i); |
| 231 | 231 | ||
| 232 | if (res == -3) { | 232 | if (res == -3) { |
| 233 | handle_dead(sock); | 233 | handle_dead(sock); |
| @@ -250,14 +250,14 @@ static void handle_write(const int64 sock) { | |||
| 250 | handle_dead(sock); | 250 | handle_dead(sock); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static void handle_accept(const int64 serversocket) { | 253 | static void handle_accept(const int64_t serversocket) { |
| 254 | struct http_data *cookie; | 254 | struct http_data *cookie; |
| 255 | int64 sock; | 255 | int64_t sock; |
| 256 | ot_ip6 ip; | 256 | ot_ip6 ip; |
| 257 | uint16 port; | 257 | uint16_t port; |
| 258 | tai6464 t; | 258 | tai6464 t; |
| 259 | 259 | ||
| 260 | while ((sock = socket_accept6(serversocket, ip, &port, NULL)) != -1) { | 260 | while ((sock = socket_accept(serversocket, ip, &port)) != -1) { |
| 261 | 261 | ||
| 262 | /* Put fd into a non-blocking mode */ | 262 | /* Put fd into a non-blocking mode */ |
| 263 | io_nonblock(sock); | 263 | io_nonblock(sock); |
| @@ -305,7 +305,7 @@ static void *server_mainloop(void *args) { | |||
| 305 | random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); | 305 | random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); |
| 306 | 306 | ||
| 307 | for (;;) { | 307 | for (;;) { |
| 308 | int64 sock; | 308 | int64_t sock; |
| 309 | 309 | ||
| 310 | io_wait(); | 310 | io_wait(); |
| 311 | 311 | ||
| @@ -339,7 +339,7 @@ static void *server_mainloop(void *args) { | |||
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) { | 341 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) { |
| 342 | int64 sock = proto == FLAG_TCP ? socket_tcp6() : socket_udp6(); | 342 | int64_t sock; |
| 343 | 343 | ||
| 344 | #ifdef _DEBUG | 344 | #ifdef _DEBUG |
| 345 | { | 345 | { |
| @@ -352,11 +352,13 @@ static int64_t ot_try_bind(ot_ip6 ip, uint16_t port, PROTO_FLAG proto) { | |||
| 352 | } | 352 | } |
| 353 | #endif | 353 | #endif |
| 354 | 354 | ||
| 355 | if (socket_bind6_reuse(sock, ip, port, 0) == -1) | 355 | if (proto == FLAG_TCP) { |
| 356 | panic("socket_bind6_reuse"); | 356 | if ((sock = socket_tcp_listen(ip, port)) == -1) |
| 357 | 357 | panic("socket_tcp_listen"); | |
| 358 | if ((proto == FLAG_TCP) && (socket_listen(sock, SOMAXCONN) == -1)) | 358 | } else { |
| 359 | panic("socket_listen"); | 359 | if ((sock = socket_udp_bind(ip, port)) == -1) |
| 360 | panic("socket_udp_bind"); | ||
| 361 | } | ||
| 360 | 362 | ||
| 361 | if (!io_fd(sock)) | 363 | if (!io_fd(sock)) |
| 362 | panic("io_fd"); | 364 | panic("io_fd"); |
| @@ -450,6 +452,7 @@ typedef enum { | |||
| 450 | CONFIG_LISTEN_TCP, | 452 | CONFIG_LISTEN_TCP, |
| 451 | CONFIG_LISTEN_UDP, | 453 | CONFIG_LISTEN_UDP, |
| 452 | CONFIG_LISTEN_UDP_WORKERS, | 454 | CONFIG_LISTEN_UDP_WORKERS, |
| 455 | CONFIG_LISTEN_REUSEPORT, | ||
| 453 | CONFIG_ACCESS_WHITELIST, | 456 | CONFIG_ACCESS_WHITELIST, |
| 454 | CONFIG_ACCESS_BLACKLIST, | 457 | CONFIG_ACCESS_BLACKLIST, |
| 455 | CONFIG_ACCESS_FIFO_ADD, | 458 | CONFIG_ACCESS_FIFO_ADD, |
| @@ -477,6 +480,7 @@ static const config_key config_keys[] = { | |||
| 477 | CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP), | 480 | CONFIG_KEY("listen.tcp", CONFIG_LISTEN_TCP), |
| 478 | CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP), | 481 | CONFIG_KEY("listen.udp", CONFIG_LISTEN_UDP), |
| 479 | CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS), | 482 | CONFIG_KEY("listen.udp.workers", CONFIG_LISTEN_UDP_WORKERS), |
| 483 | CONFIG_KEY("listen.reuseport", CONFIG_LISTEN_REUSEPORT), | ||
| 480 | #ifdef WANT_ACCESSLIST_WHITE | 484 | #ifdef WANT_ACCESSLIST_WHITE |
| 481 | CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST), | 485 | CONFIG_KEY("access.whitelist", CONFIG_ACCESS_WHITELIST), |
| 482 | #elif defined(WANT_ACCESSLIST_BLACK) | 486 | #elif defined(WANT_ACCESSLIST_BLACK) |
| @@ -582,6 +586,13 @@ int parse_configfile(char *config_filename) { | |||
| 582 | if (scan_udec(p, &value, UINT_MAX)) | 586 | if (scan_udec(p, &value, UINT_MAX)) |
| 583 | g_udp_workers = (unsigned int)value; | 587 | g_udp_workers = (unsigned int)value; |
| 584 | break; | 588 | break; |
| 589 | case CONFIG_LISTEN_REUSEPORT: | ||
| 590 | /* Like listen.udp.workers this is read when a socket is bound, so it | ||
| 591 | has to come before the listen lines it should apply to. */ | ||
| 592 | if (!scan_udec(p, &value, 1)) | ||
| 593 | goto parse_error; | ||
| 594 | g_socket_reuseport = (int)value; | ||
| 595 | break; | ||
| 585 | #ifdef WANT_ACCESSLIST_WHITE | 596 | #ifdef WANT_ACCESSLIST_WHITE |
| 586 | case CONFIG_ACCESS_WHITELIST: | 597 | case CONFIG_ACCESS_WHITELIST: |
| 587 | set_config_option(&g_accesslist_filename, p); | 598 | set_config_option(&g_accesslist_filename, p); |
| @@ -6,6 +6,8 @@ | |||
| 6 | #ifndef OT_CLEAN_H__ | 6 | #ifndef OT_CLEAN_H__ |
| 7 | #define OT_CLEAN_H__ | 7 | #define OT_CLEAN_H__ |
| 8 | 8 | ||
| 9 | #include "trackerlogic.h" | ||
| 10 | |||
| 9 | /* The amount of time a clean cycle should take */ | 11 | /* The amount of time a clean cycle should take */ |
| 10 | #define OT_CLEAN_INTERVAL_MINUTES 2 | 12 | #define OT_CLEAN_INTERVAL_MINUTES 2 |
| 11 | 13 | ||
diff --git a/ot_fullscrape.c b/ot_fullscrape.c index 3d0e2f1..9dcbe68 100644 --- a/ot_fullscrape.c +++ b/ot_fullscrape.c | |||
| @@ -82,7 +82,7 @@ void fullscrape_deinit(void) { | |||
| 82 | pthread_cancel( thread_id ); | 82 | pthread_cancel( thread_id ); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | void fullscrape_deliver( int64 sock, ot_tasktype tasktype ) { | 85 | void fullscrape_deliver( int64_t sock, ot_tasktype tasktype ) { |
| 86 | mutex_workqueue_pushtask( sock, tasktype ); | 86 | mutex_workqueue_pushtask( sock, tasktype ); |
| 87 | } | 87 | } |
| 88 | 88 | ||
diff --git a/ot_fullscrape.h b/ot_fullscrape.h index 843e039..0e7690c 100644 --- a/ot_fullscrape.h +++ b/ot_fullscrape.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | void fullscrape_init(void); | 13 | void fullscrape_init(void); |
| 14 | void fullscrape_deinit(void); | 14 | void fullscrape_deinit(void); |
| 15 | void fullscrape_deliver(int64 sock, ot_tasktype tasktype); | 15 | void fullscrape_deliver(int64_t sock, ot_tasktype tasktype); |
| 16 | 16 | ||
| 17 | #else | 17 | #else |
| 18 | 18 | ||
| @@ -44,7 +44,7 @@ ssize_t g_stats_path_len; | |||
| 44 | 44 | ||
| 45 | enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; | 45 | enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; |
| 46 | 46 | ||
| 47 | static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | 47 | static void http_senddata(const int64_t sock, struct ot_workstruct *ws) { |
| 48 | struct http_data *cookie = io_getcookie(sock); | 48 | struct http_data *cookie = io_getcookie(sock); |
| 49 | ssize_t written_size; | 49 | ssize_t written_size; |
| 50 | 50 | ||
| @@ -124,7 +124,7 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) { | |||
| 124 | #define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) | 124 | #define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) |
| 125 | #define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) | 125 | #define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) |
| 126 | #define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) | 126 | #define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) |
| 127 | ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) { | 127 | ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) { |
| 128 | char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", | 128 | char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", |
| 129 | "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; | 129 | "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; |
| 130 | char *title = error_code[code]; | 130 | char *title = error_code[code]; |
| @@ -144,7 +144,7 @@ ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) { | |||
| 144 | return ws->reply_size = -2; | 144 | return ws->reply_size = -2; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) { | 147 | ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) { |
| 148 | struct http_data *cookie = io_getcookie(sock); | 148 | struct http_data *cookie = io_getcookie(sock); |
| 149 | io_batch *current; | 149 | io_batch *current; |
| 150 | char *header; | 150 | char *header; |
| @@ -243,7 +243,7 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t io | |||
| 243 | return 0; | 243 | return 0; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | static ssize_t http_handle_stats(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { | 246 | static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 247 | static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}}; | 247 | static const ot_keywords keywords_main[] = {{"mode", 1}, {"format", 2}, {"info_hash", 3}, {NULL, -3}}; |
| 248 | static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS}, | 248 | static const ot_keywords keywords_mode[] = {{"peer", TASK_STATS_PEERS}, |
| 249 | {"conn", TASK_STATS_CONNS}, | 249 | {"conn", TASK_STATS_CONNS}, |
| @@ -368,7 +368,7 @@ typedef struct { | |||
| 368 | #endif | 368 | #endif |
| 369 | 369 | ||
| 370 | #ifdef WANT_FULLSCRAPE | 370 | #ifdef WANT_FULLSCRAPE |
| 371 | static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws) { | 371 | static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *ws) { |
| 372 | struct http_data *cookie = io_getcookie(sock); | 372 | struct http_data *cookie = io_getcookie(sock); |
| 373 | int format = 0; | 373 | int format = 0; |
| 374 | tai6464 t; | 374 | tai6464 t; |
| @@ -438,7 +438,7 @@ static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws | |||
| 438 | } | 438 | } |
| 439 | #endif | 439 | #endif |
| 440 | 440 | ||
| 441 | static ssize_t http_handle_scrape(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { | 441 | static ssize_t http_handle_scrape(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 442 | static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; | 442 | static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; |
| 443 | 443 | ||
| 444 | ot_hash *multiscrape_buf = (ot_hash *)ws->request; | 444 | ot_hash *multiscrape_buf = (ot_hash *)ws->request; |
| @@ -517,7 +517,7 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event", | |||
| 517 | #endif | 517 | #endif |
| 518 | {"peer_id", 9}, {NULL, -3}}; | 518 | {"peer_id", 9}, {NULL, -3}}; |
| 519 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; | 519 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; |
| 520 | static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { | 520 | static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct *ws, char *read_ptr) { |
| 521 | size_t numwant; | 521 | size_t numwant; |
| 522 | int tmp, scanon; | 522 | int tmp, scanon; |
| 523 | unsigned short port = 0; | 523 | unsigned short port = 0; |
| @@ -695,7 +695,7 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct * | |||
| 695 | return ws->reply_size; | 695 | return ws->reply_size; |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | ssize_t http_handle_request(const int64 sock, struct ot_workstruct *ws) { | 698 | ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) { |
| 699 | ssize_t reply_off, len; | 699 | ssize_t reply_off, len; |
| 700 | char *read_ptr = ws->request, *write_ptr; | 700 | char *read_ptr = ws->request, *write_ptr; |
| 701 | 701 | ||
| @@ -6,7 +6,15 @@ | |||
| 6 | #ifndef OT_HTTP_H__ | 6 | #ifndef OT_HTTP_H__ |
| 7 | #define OT_HTTP_H__ | 7 | #define OT_HTTP_H__ |
| 8 | 8 | ||
| 9 | #include <stdint.h> | ||
| 10 | #include <sys/types.h> | ||
| 11 | #include <sys/uio.h> | ||
| 12 | |||
| 13 | /* Libowfat */ | ||
| 14 | #include "iob.h" | ||
| 15 | |||
| 9 | #include "ot_buf.h" | 16 | #include "ot_buf.h" |
| 17 | #include "trackerlogic.h" | ||
| 10 | 18 | ||
| 11 | typedef enum { | 19 | typedef enum { |
| 12 | STRUCT_HTTP_FLAG_WAITINGFORTASK = 1, | 20 | STRUCT_HTTP_FLAG_WAITINGFORTASK = 1, |
| @@ -25,9 +33,9 @@ struct http_data { | |||
| 25 | STRUCT_HTTP_FLAG flag; | 33 | STRUCT_HTTP_FLAG flag; |
| 26 | }; | 34 | }; |
| 27 | 35 | ||
| 28 | ssize_t http_handle_request(const int64 s, struct ot_workstruct *ws); | 36 | ssize_t http_handle_request(const int64_t s, struct ot_workstruct *ws); |
| 29 | ssize_t http_sendiovecdata(const int64 s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial); | 37 | ssize_t http_sendiovecdata(const int64_t s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial); |
| 30 | ssize_t http_issue_error(const int64 s, struct ot_workstruct *ws, int code); | 38 | ssize_t http_issue_error(const int64_t s, struct ot_workstruct *ws, int code); |
| 31 | 39 | ||
| 32 | extern char *g_stats_path; | 40 | extern char *g_stats_path; |
| 33 | extern ssize_t g_stats_path_len; | 41 | extern ssize_t g_stats_path_len; |
| @@ -20,6 +20,8 @@ void *iovec_increase(size_t *iovec_entries, struct iovec **iovector, size_t new_ | |||
| 20 | if (!new_vec) | 20 | if (!new_vec) |
| 21 | return NULL; | 21 | return NULL; |
| 22 | 22 | ||
| 23 | *iovector = new_vec; | ||
| 24 | |||
| 23 | /* Only allocate after we have a place to store the pointer */ | 25 | /* Only allocate after we have a place to store the pointer */ |
| 24 | new_data = malloc(new_alloc); | 26 | new_data = malloc(new_alloc); |
| 25 | if (!new_data) | 27 | if (!new_data) |
| @@ -28,7 +30,6 @@ void *iovec_increase(size_t *iovec_entries, struct iovec **iovector, size_t new_ | |||
| 28 | new_vec[new_entries - 1].iov_base = new_data; | 30 | new_vec[new_entries - 1].iov_base = new_data; |
| 29 | new_vec[new_entries - 1].iov_len = new_alloc; | 31 | new_vec[new_entries - 1].iov_len = new_alloc; |
| 30 | 32 | ||
| 31 | *iovector = new_vec; | ||
| 32 | ++*iovec_entries; | 33 | ++*iovec_entries; |
| 33 | return new_data; | 34 | return new_data; |
| 34 | } | 35 | } |
diff --git a/ot_livesync.c b/ot_livesync.c index f6bb28b..5a63f3c 100644 --- a/ot_livesync.c +++ b/ot_livesync.c | |||
| @@ -5,19 +5,16 @@ | |||
| 5 | 5 | ||
| 6 | /* System */ | 6 | /* System */ |
| 7 | #include <arpa/inet.h> | 7 | #include <arpa/inet.h> |
| 8 | #include <fcntl.h> | ||
| 9 | #include <pthread.h> | 8 | #include <pthread.h> |
| 10 | #include <stdlib.h> | 9 | #include <stdlib.h> |
| 11 | #include <string.h> | 10 | #include <string.h> |
| 12 | #include <sys/types.h> | 11 | #include <sys/types.h> |
| 13 | #include <unistd.h> | 12 | #include <unistd.h> |
| 14 | 13 | ||
| 15 | /* Libowfat */ | ||
| 16 | #include "socket.h" | ||
| 17 | |||
| 18 | /* Opentracker */ | 14 | /* Opentracker */ |
| 19 | #include "ot_accesslist.h" | 15 | #include "ot_accesslist.h" |
| 20 | #include "ot_ip.h" | 16 | #include "ot_ip.h" |
| 17 | #include "ot_socket.h" | ||
| 21 | #include "ot_livesync.h" | 18 | #include "ot_livesync.h" |
| 22 | #include "ot_mutex.h" | 19 | #include "ot_mutex.h" |
| 23 | #include "ot_stats.h" | 20 | #include "ot_stats.h" |
| @@ -25,7 +22,7 @@ | |||
| 25 | 22 | ||
| 26 | #ifdef WANT_SYNC_LIVE | 23 | #ifdef WANT_SYNC_LIVE |
| 27 | 24 | ||
| 28 | char groupip_1[4] = {224, 0, 23, 5}; | 25 | ot_ip6 groupip_1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 224, 0, 23, 5}; |
| 29 | 26 | ||
| 30 | #define LIVESYNC_INCOMING_BUFFSIZE (256 * 256) | 27 | #define LIVESYNC_INCOMING_BUFFSIZE (256 * 256) |
| 31 | 28 | ||
| @@ -39,11 +36,11 @@ enum { OT_SYNC_PEER4, OT_SYNC_PEER6 }; | |||
| 39 | /* Forward declaration */ | 36 | /* Forward declaration */ |
| 40 | static void *livesync_worker(void *args); | 37 | static void *livesync_worker(void *args); |
| 41 | 38 | ||
| 42 | /* For outgoing packets */ | ||
| 43 | static int64 g_socket_in = -1; | ||
| 44 | |||
| 45 | /* For incoming packets */ | 39 | /* For incoming packets */ |
| 46 | static int64 g_socket_out = -1; | 40 | static int g_socket_in = -1; |
| 41 | |||
| 42 | /* For outgoing packets */ | ||
| 43 | static int g_socket_out = -1; | ||
| 47 | 44 | ||
| 48 | static pthread_mutex_t g_outbuf_mutex = PTHREAD_MUTEX_INITIALIZER; | 45 | static pthread_mutex_t g_outbuf_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 49 | typedef struct { | 46 | typedef struct { |
| @@ -89,34 +86,17 @@ void livesync_deinit(void) { | |||
| 89 | } | 86 | } |
| 90 | 87 | ||
| 91 | void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { | 88 | void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { |
| 92 | char tmpip[4] = {0, 0, 0, 0}; | ||
| 93 | char *v4ip; | ||
| 94 | |||
| 95 | if (!ip_is_v4mapped(ip)) | 89 | if (!ip_is_v4mapped(ip)) |
| 96 | exerr("v6 mcast support not yet available."); | 90 | exerr("v6 mcast support not yet available."); |
| 97 | v4ip = ip + 12; | ||
| 98 | 91 | ||
| 99 | if (g_socket_in != -1) | 92 | if (g_socket_in != -1) |
| 100 | exerr("Error: Livesync listen ip specified twice."); | 93 | exerr("Error: Livesync listen ip specified twice."); |
| 101 | 94 | ||
| 102 | if ((g_socket_in = socket_udp4()) < 0) | 95 | if ((g_socket_in = socket_mcast_join(groupip_1, ip, port)) == -1) |
| 103 | exerr("Error: Cant create live sync incoming socket."); | ||
| 104 | |||
| 105 | fcntl(g_socket_in, F_SETFL, fcntl(g_socket_in, F_GETFL, 0) & ~O_NONBLOCK); | ||
| 106 | |||
| 107 | if (socket_bind4_reuse(g_socket_in, tmpip, port) == -1) | ||
| 108 | exerr("Error: Cant bind live sync incoming socket."); | 96 | exerr("Error: Cant bind live sync incoming socket."); |
| 109 | 97 | ||
| 110 | if (socket_mcjoin4(g_socket_in, groupip_1, v4ip)) | 98 | if ((g_socket_out = socket_mcast_bind(ip, port, 0)) == -1) |
| 111 | exerr("Error: Cant make live sync incoming socket join mcast group."); | ||
| 112 | |||
| 113 | if ((g_socket_out = socket_udp4()) < 0) | ||
| 114 | exerr("Error: Cant create live sync outgoing socket."); | ||
| 115 | if (socket_bind4_reuse(g_socket_out, v4ip, port) == -1) | ||
| 116 | exerr("Error: Cant bind live sync outgoing socket."); | 99 | exerr("Error: Cant bind live sync outgoing socket."); |
| 117 | |||
| 118 | socket_mcttl4(g_socket_out, 1); | ||
| 119 | socket_mcloop4(g_socket_out, 0); | ||
| 120 | } | 100 | } |
| 121 | 101 | ||
| 122 | /* Caller MUST hold g_outbuf_mutex. Returns with g_outbuf_mutex unlocked */ | 102 | /* Caller MUST hold g_outbuf_mutex. Returns with g_outbuf_mutex unlocked */ |
| @@ -132,7 +112,7 @@ static void livesync_issue_peersync(sync_buffer *buf) { | |||
| 132 | has modified the protected element */ | 112 | has modified the protected element */ |
| 133 | pthread_mutex_unlock(&g_outbuf_mutex); | 113 | pthread_mutex_unlock(&g_outbuf_mutex); |
| 134 | 114 | ||
| 135 | socket_send4(g_socket_out, mycopy, fill, groupip_1, LIVESYNC_PORT); | 115 | socket_mcast_send(g_socket_out, mycopy, fill, groupip_1, LIVESYNC_PORT); |
| 136 | } | 116 | } |
| 137 | 117 | ||
| 138 | static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) { | 118 | static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) { |
| @@ -215,12 +195,10 @@ static void *livesync_worker(void *args) { | |||
| 215 | ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE); | 195 | ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE); |
| 216 | ws.outbuf = ws.reply = 0; | 196 | ws.outbuf = ws.reply = 0; |
| 217 | 197 | ||
| 218 | memcpy(in_ip, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); | ||
| 219 | |||
| 220 | while (1) { | 198 | while (1) { |
| 221 | uint32_t packet_type; | 199 | uint32_t packet_type; |
| 222 | 200 | ||
| 223 | ws.request_size = socket_recv4(g_socket_in, (char *)ws.inbuf, LIVESYNC_INCOMING_BUFFSIZE, 12 + (char *)in_ip, &in_port); | 201 | ws.request_size = socket_recv(g_socket_in, ws.inbuf, LIVESYNC_INCOMING_BUFFSIZE, in_ip, &in_port); |
| 224 | 202 | ||
| 225 | /* Expect at least tracker id and packet type */ | 203 | /* Expect at least tracker id and packet type */ |
| 226 | if (ws.request_size <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t))) | 204 | if (ws.request_size <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t))) |
diff --git a/ot_livesync.h b/ot_livesync.h index ed710f0..5b9fa0e 100644 --- a/ot_livesync.h +++ b/ot_livesync.h | |||
| @@ -51,7 +51,7 @@ void livesync_init(void); | |||
| 51 | void livesync_deinit(void); | 51 | void livesync_deinit(void); |
| 52 | 52 | ||
| 53 | /* Join multicast group for listening and create sending socket */ | 53 | /* Join multicast group for listening and create sending socket */ |
| 54 | void livesync_bind_mcast(char *ip, uint16_t port); | 54 | void livesync_bind_mcast(ot_ip6 ip, uint16_t port); |
| 55 | 55 | ||
| 56 | /* Inform live sync about whats going on. */ | 56 | /* Inform live sync about whats going on. */ |
| 57 | void livesync_tell(struct ot_workstruct *ws); | 57 | void livesync_tell(struct ot_workstruct *ws); |
| @@ -62,7 +62,7 @@ void livesync_tell(struct ot_workstruct *ws); | |||
| 62 | void livesync_ticker(void); | 62 | void livesync_ticker(void); |
| 63 | 63 | ||
| 64 | /* Handle an incoming live sync packet */ | 64 | /* Handle an incoming live sync packet */ |
| 65 | void handle_livesync(const int64 sock); | 65 | void handle_livesync(const int64_t sock); |
| 66 | 66 | ||
| 67 | #else | 67 | #else |
| 68 | 68 | ||
| @@ -62,7 +62,7 @@ size_t mutex_get_torrent_count(void) { return g_torrent_count; } | |||
| 62 | struct ot_task { | 62 | struct ot_task { |
| 63 | ot_taskid taskid; | 63 | ot_taskid taskid; |
| 64 | ot_tasktype tasktype; | 64 | ot_tasktype tasktype; |
| 65 | int64 sock; | 65 | int64_t sock; |
| 66 | size_t iovec_entries; | 66 | size_t iovec_entries; |
| 67 | struct iovec *iovec; | 67 | struct iovec *iovec; |
| 68 | struct ot_task *next; | 68 | struct ot_task *next; |
| @@ -73,7 +73,7 @@ static struct ot_task *tasklist; | |||
| 73 | static pthread_mutex_t tasklist_mutex; | 73 | static pthread_mutex_t tasklist_mutex; |
| 74 | static pthread_cond_t tasklist_being_filled; | 74 | static pthread_cond_t tasklist_being_filled; |
| 75 | 75 | ||
| 76 | int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) { | 76 | int mutex_workqueue_pushtask(int64_t sock, ot_tasktype tasktype) { |
| 77 | struct ot_task **tmptask, *task; | 77 | struct ot_task **tmptask, *task; |
| 78 | 78 | ||
| 79 | task = malloc(sizeof(struct ot_task)); | 79 | task = malloc(sizeof(struct ot_task)); |
| @@ -102,7 +102,7 @@ int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype) { | |||
| 102 | return 0; | 102 | return 0; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | void mutex_workqueue_canceltask(int64 sock) { | 105 | void mutex_workqueue_canceltask(int64_t sock) { |
| 106 | struct ot_task **task; | 106 | struct ot_task **task; |
| 107 | 107 | ||
| 108 | /* Want exclusive access to tasklist */ | 108 | /* Want exclusive access to tasklist */ |
| @@ -227,9 +227,9 @@ int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) { | |||
| 227 | return task ? 0 : -1; | 227 | return task ? 0 : -1; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | int64 mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovec, int *is_partial) { | 230 | int64_t mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovec, int *is_partial) { |
| 231 | struct ot_task **task; | 231 | struct ot_task **task; |
| 232 | int64 sock = -1; | 232 | int64_t sock = -1; |
| 233 | 233 | ||
| 234 | *is_partial = 0; | 234 | *is_partial = 0; |
| 235 | 235 | ||
| @@ -69,12 +69,12 @@ typedef enum { | |||
| 69 | 69 | ||
| 70 | typedef unsigned long ot_taskid; | 70 | typedef unsigned long ot_taskid; |
| 71 | 71 | ||
| 72 | int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype); | 72 | int mutex_workqueue_pushtask(int64_t sock, ot_tasktype tasktype); |
| 73 | void mutex_workqueue_canceltask(int64 sock); | 73 | void mutex_workqueue_canceltask(int64_t sock); |
| 74 | void mutex_workqueue_pushsuccess(ot_taskid taskid); | 74 | void mutex_workqueue_pushsuccess(ot_taskid taskid); |
| 75 | ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype); | 75 | ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype); |
| 76 | int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct iovec *iovector); | 76 | int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct iovec *iovector); |
| 77 | int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec); | 77 | int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec); |
| 78 | int64 mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovector, int *is_partial); | 78 | int64_t mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovector, int *is_partial); |
| 79 | 79 | ||
| 80 | #endif | 80 | #endif |
diff --git a/ot_socket.c b/ot_socket.c new file mode 100644 index 0000000..e26ad52 --- /dev/null +++ b/ot_socket.c | |||
| @@ -0,0 +1,256 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | /* System */ | ||
| 7 | #include <errno.h> | ||
| 8 | #include <fcntl.h> | ||
| 9 | #include <netinet/in.h> | ||
| 10 | #include <string.h> | ||
| 11 | #include <sys/socket.h> | ||
| 12 | #include <unistd.h> | ||
| 13 | |||
| 14 | /* Opentracker */ | ||
| 15 | #include "ot_ip.h" | ||
| 16 | #include "ot_socket.h" | ||
| 17 | |||
| 18 | int g_socket_reuseport; | ||
| 19 | |||
| 20 | static void sockaddr_from_ip(struct sockaddr_in6 *sa, const ot_ip6 ip, uint16_t port) { | ||
| 21 | memset(sa, 0, sizeof(*sa)); | ||
| 22 | sa->sin6_family = AF_INET6; | ||
| 23 | sa->sin6_port = htons(port); | ||
| 24 | memcpy(&sa->sin6_addr, ip, sizeof(ot_ip6)); | ||
| 25 | } | ||
| 26 | |||
| 27 | /* Linux reports an IPv4 peer on a dual stack socket as a v4 mapped | ||
| 28 | sockaddr_in6, the BSDs and macOS hand back a plain sockaddr_in instead, so | ||
| 29 | both forms have to be read. */ | ||
| 30 | static void ip_from_sockaddr(ot_ip6 ip, uint16_t *port, const struct sockaddr_storage *ss) { | ||
| 31 | if (ss->ss_family == AF_INET) { | ||
| 32 | const struct sockaddr_in *sa = (const struct sockaddr_in *)ss; | ||
| 33 | |||
| 34 | memcpy(ip, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); | ||
| 35 | memcpy(ip + sizeof(ip_v4mapped_prefix), &sa->sin_addr, 4); | ||
| 36 | *port = ntohs(sa->sin_port); | ||
| 37 | } else { | ||
| 38 | const struct sockaddr_in6 *sa = (const struct sockaddr_in6 *)ss; | ||
| 39 | |||
| 40 | memcpy(ip, &sa->sin6_addr, sizeof(ot_ip6)); | ||
| 41 | *port = ntohs(sa->sin6_port); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | static int set_nonblocking(int s) { | ||
| 46 | int flags = fcntl(s, F_GETFL, 0); | ||
| 47 | |||
| 48 | if (flags == -1) | ||
| 49 | return -1; | ||
| 50 | return fcntl(s, F_SETFL, flags | O_NONBLOCK); | ||
| 51 | } | ||
| 52 | |||
| 53 | /* Close without letting the failure we are about to report be overwritten */ | ||
| 54 | static int close_and_fail(int s) { | ||
| 55 | int saved = errno; | ||
| 56 | close(s); | ||
| 57 | errno = saved; | ||
| 58 | return -1; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int socket_v6(int type) { | ||
| 62 | int s = socket(PF_INET6, type, 0); | ||
| 63 | int zero = 0; | ||
| 64 | |||
| 65 | if (s == -1) | ||
| 66 | return -1; | ||
| 67 | |||
| 68 | /* A tracker that answered only one family would be half a tracker */ | ||
| 69 | if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) == -1) | ||
| 70 | return close_and_fail(s); | ||
| 71 | |||
| 72 | if (set_nonblocking(s) == -1) | ||
| 73 | return close_and_fail(s); | ||
| 74 | |||
| 75 | return s; | ||
| 76 | } | ||
| 77 | |||
| 78 | static int socket_bind_v6(int s, const ot_ip6 ip, uint16_t port) { | ||
| 79 | struct sockaddr_in6 sa; | ||
| 80 | int one = 1; | ||
| 81 | |||
| 82 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); | ||
| 83 | #ifdef SO_REUSEPORT | ||
| 84 | if (g_socket_reuseport) | ||
| 85 | setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); | ||
| 86 | #endif | ||
| 87 | |||
| 88 | sockaddr_from_ip(&sa, ip, port); | ||
| 89 | return bind(s, (struct sockaddr *)&sa, sizeof(sa)); | ||
| 90 | } | ||
| 91 | |||
| 92 | int socket_tcp_listen(const ot_ip6 ip, uint16_t port) { | ||
| 93 | int s = socket_v6(SOCK_STREAM); | ||
| 94 | |||
| 95 | if (s == -1) | ||
| 96 | return -1; | ||
| 97 | if (socket_bind_v6(s, ip, port) == -1 || listen(s, SOMAXCONN) == -1) | ||
| 98 | return close_and_fail(s); | ||
| 99 | |||
| 100 | return s; | ||
| 101 | } | ||
| 102 | |||
| 103 | int socket_udp_bind(const ot_ip6 ip, uint16_t port) { | ||
| 104 | int s = socket_v6(SOCK_DGRAM); | ||
| 105 | |||
| 106 | if (s == -1) | ||
| 107 | return -1; | ||
| 108 | if (socket_bind_v6(s, ip, port) == -1) | ||
| 109 | return close_and_fail(s); | ||
| 110 | |||
| 111 | return s; | ||
| 112 | } | ||
| 113 | |||
| 114 | int socket_tcp_connect(const ot_ip6 srcip, uint16_t srcport, const ot_ip6 dstip, uint16_t dstport) { | ||
| 115 | struct sockaddr_in6 sa; | ||
| 116 | int s = socket_v6(SOCK_STREAM); | ||
| 117 | |||
| 118 | if (s == -1) | ||
| 119 | return -1; | ||
| 120 | if (socket_bind_v6(s, srcip, srcport) == -1) | ||
| 121 | return close_and_fail(s); | ||
| 122 | |||
| 123 | sockaddr_from_ip(&sa, dstip, dstport); | ||
| 124 | if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1 && errno != EINPROGRESS && errno != EWOULDBLOCK) | ||
| 125 | return close_and_fail(s); | ||
| 126 | |||
| 127 | return s; | ||
| 128 | } | ||
| 129 | |||
| 130 | int socket_is_connected(int s) { | ||
| 131 | int error = 0; | ||
| 132 | socklen_t len = sizeof(error); | ||
| 133 | |||
| 134 | if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) | ||
| 135 | return 0; | ||
| 136 | if (error) { | ||
| 137 | errno = error; | ||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | |||
| 143 | int socket_accept(int s, ot_ip6 ip, uint16_t *port) { | ||
| 144 | struct sockaddr_storage ss; | ||
| 145 | socklen_t len = sizeof(ss); | ||
| 146 | int fd; | ||
| 147 | |||
| 148 | memset(&ss, 0, sizeof(ss)); | ||
| 149 | if ((fd = accept(s, (struct sockaddr *)&ss, &len)) == -1) | ||
| 150 | return -1; | ||
| 151 | |||
| 152 | /* Linux hands over a blocking socket whatever the listening socket was, the | ||
| 153 | BSDs and macOS inherit the listener's flags, so say which one we want. */ | ||
| 154 | if (set_nonblocking(fd) == -1) | ||
| 155 | return close_and_fail(fd); | ||
| 156 | |||
| 157 | ip_from_sockaddr(ip, port, &ss); | ||
| 158 | return fd; | ||
| 159 | } | ||
| 160 | |||
| 161 | ssize_t socket_recv(int s, void *buf, size_t len, ot_ip6 ip, uint16_t *port) { | ||
| 162 | struct sockaddr_storage ss; | ||
| 163 | socklen_t sslen = sizeof(ss); | ||
| 164 | ssize_t received; | ||
| 165 | |||
| 166 | memset(&ss, 0, sizeof(ss)); | ||
| 167 | received = recvfrom(s, buf, len, 0, (struct sockaddr *)&ss, &sslen); | ||
| 168 | if (received == -1) | ||
| 169 | return -1; | ||
| 170 | |||
| 171 | ip_from_sockaddr(ip, port, &ss); | ||
| 172 | return received; | ||
| 173 | } | ||
| 174 | |||
| 175 | ssize_t socket_send(int s, const void *buf, size_t len, const ot_ip6 ip, uint16_t port) { | ||
| 176 | struct sockaddr_in6 sa; | ||
| 177 | |||
| 178 | sockaddr_from_ip(&sa, ip, port); | ||
| 179 | return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa)); | ||
| 180 | } | ||
| 181 | |||
| 182 | #ifdef WANT_SYNC_LIVE | ||
| 183 | static void sockaddr4_from_ip(struct sockaddr_in *sa, const ot_ip6 ip, uint16_t port) { | ||
| 184 | memset(sa, 0, sizeof(*sa)); | ||
| 185 | sa->sin_family = AF_INET; | ||
| 186 | sa->sin_port = htons(port); | ||
| 187 | memcpy(&sa->sin_addr, ip + sizeof(ip_v4mapped_prefix), 4); | ||
| 188 | } | ||
| 189 | |||
| 190 | static int socket_v4_bind(const ot_ip6 ip, uint16_t port) { | ||
| 191 | struct sockaddr_in sa; | ||
| 192 | int s, one = 1; | ||
| 193 | |||
| 194 | if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1) | ||
| 195 | return -1; | ||
| 196 | |||
| 197 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); | ||
| 198 | #ifdef SO_REUSEPORT | ||
| 199 | if (g_socket_reuseport) | ||
| 200 | setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); | ||
| 201 | #endif | ||
| 202 | |||
| 203 | sockaddr4_from_ip(&sa, ip, port); | ||
| 204 | if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) | ||
| 205 | return close_and_fail(s); | ||
| 206 | |||
| 207 | return s; | ||
| 208 | } | ||
| 209 | |||
| 210 | int socket_mcast_join(const ot_ip6 group, const ot_ip6 interface, uint16_t port) { | ||
| 211 | struct ip_mreq mreq; | ||
| 212 | ot_ip6 any; | ||
| 213 | int s; | ||
| 214 | |||
| 215 | /* The group is what is listened to, so the socket takes the wildcard and | ||
| 216 | the join names the interface to receive it on */ | ||
| 217 | memcpy(any, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); | ||
| 218 | memset(any + sizeof(ip_v4mapped_prefix), 0, 4); | ||
| 219 | |||
| 220 | if ((s = socket_v4_bind(any, port)) == -1) | ||
| 221 | return -1; | ||
| 222 | |||
| 223 | memset(&mreq, 0, sizeof(mreq)); | ||
| 224 | memcpy(&mreq.imr_multiaddr, group + sizeof(ip_v4mapped_prefix), 4); | ||
| 225 | memcpy(&mreq.imr_interface, interface + sizeof(ip_v4mapped_prefix), 4); | ||
| 226 | if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) | ||
| 227 | return close_and_fail(s); | ||
| 228 | |||
| 229 | return s; | ||
| 230 | } | ||
| 231 | |||
| 232 | int socket_mcast_bind(const ot_ip6 interface, uint16_t port, int loopback) { | ||
| 233 | /* The BSDs and macOS want a byte for the IPv4 multicast options, Linux | ||
| 234 | accepts either that or an int. */ | ||
| 235 | unsigned char ttl = 1, loop = (unsigned char)(loopback != 0); | ||
| 236 | int s = socket_v4_bind(interface, port); | ||
| 237 | |||
| 238 | if (s == -1) | ||
| 239 | return -1; | ||
| 240 | if (set_nonblocking(s) == -1) | ||
| 241 | return close_and_fail(s); | ||
| 242 | |||
| 243 | if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1 || | ||
| 244 | setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) == -1) | ||
| 245 | return close_and_fail(s); | ||
| 246 | |||
| 247 | return s; | ||
| 248 | } | ||
| 249 | |||
| 250 | ssize_t socket_mcast_send(int s, const void *buf, size_t len, const ot_ip6 group, uint16_t port) { | ||
| 251 | struct sockaddr_in sa; | ||
| 252 | |||
| 253 | sockaddr4_from_ip(&sa, group, port); | ||
| 254 | return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa)); | ||
| 255 | } | ||
| 256 | #endif | ||
diff --git a/ot_socket.h b/ot_socket.h new file mode 100644 index 0000000..20fd839 --- /dev/null +++ b/ot_socket.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | #ifndef OT_SOCKET_H__ | ||
| 7 | #define OT_SOCKET_H__ | ||
| 8 | |||
| 9 | #include <stdint.h> | ||
| 10 | #include <sys/types.h> | ||
| 11 | |||
| 12 | #include "trackerlogic.h" | ||
| 13 | |||
| 14 | /* Every socket opentracker opens is an AF_INET6 socket with IPV6_V6ONLY | ||
| 15 | cleared, so one descriptor serves both families and an IPv4 peer arrives | ||
| 16 | as the v4 mapped address */ | ||
| 17 | |||
| 18 | /* Ask the kernel to let several processes bind the same address */ | ||
| 19 | extern int g_socket_reuseport; | ||
| 20 | |||
| 21 | /* Create, bind and, for TCP, listen. The returned socket is non blocking | ||
| 22 | Returns -1 on failure with errno set */ | ||
| 23 | int socket_tcp_listen(const ot_ip6 ip, uint16_t port); | ||
| 24 | int socket_udp_bind(const ot_ip6 ip, uint16_t port); | ||
| 25 | |||
| 26 | int socket_tcp_connect(const ot_ip6 srcip, uint16_t srcport, const ot_ip6 dstip, uint16_t dstport); | ||
| 27 | int socket_is_connected(int s); | ||
| 28 | int socket_accept(int s, ot_ip6 ip, uint16_t *port); | ||
| 29 | |||
| 30 | ssize_t socket_recv(int s, void *buf, size_t len, ot_ip6 ip, uint16_t *port); | ||
| 31 | ssize_t socket_send(int s, const void *buf, size_t len, const ot_ip6 ip, uint16_t port); | ||
| 32 | |||
| 33 | #ifdef WANT_SYNC_LIVE | ||
| 34 | /* | ||
| 35 | socket_mcast_join takes the wildcard address and names the interface in the | ||
| 36 | join, and hands back a blocking socket, since the thread that reads it does | ||
| 37 | nothing else. socket_mcast_bind hands back a non blocking one, because the | ||
| 38 | thread that sends from it is also serving clients. Incoming datagrams are | ||
| 39 | read with socket_recv */ | ||
| 40 | int socket_mcast_join(const ot_ip6 group, const ot_ip6 interface, uint16_t port); | ||
| 41 | int socket_mcast_bind(const ot_ip6 interface, uint16_t port, int loopback); | ||
| 42 | ssize_t socket_mcast_send(int s, const void *buf, size_t len, const ot_ip6 group, uint16_t port); | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #endif | ||
| @@ -206,10 +206,6 @@ static size_t stats_return_busy_networks(char *reply, stats_network_node *tree, | |||
| 206 | r += sprintf(r, "%08zd: ", scores[i - 1]); | 206 | r += sprintf(r, "%08zd: ", scores[i - 1]); |
| 207 | // #ifdef WANT_V6 | 207 | // #ifdef WANT_V6 |
| 208 | r += ip_format(r, networks[i - 1]); | 208 | r += ip_format(r, networks[i - 1]); |
| 209 | #if 0 | ||
| 210 | // XXX | ||
| 211 | r += fmt_ip4( r, networks[i - 1]); | ||
| 212 | #endif | ||
| 213 | *r++ = '\n'; | 209 | *r++ = '\n'; |
| 214 | } | 210 | } |
| 215 | } | 211 | } |
| @@ -663,10 +659,6 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_ | |||
| 663 | } | 659 | } |
| 664 | 660 | ||
| 665 | ip_readable[ip_format(ip_readable, (char *)&ws->peer)] = 0; | 661 | ip_readable[ip_format(ip_readable, (char *)&ws->peer)] = 0; |
| 666 | #if 0 | ||
| 667 | /* XXX */ | ||
| 668 | ip_readable[ fmt_ip4( ip_readable, (char*)&ws->peer ) ] = 0; | ||
| 669 | #endif | ||
| 670 | syslog(LOG_INFO, "time=%s event=completed info_hash=%s peer_id=%s ip=%s", timestring, hash_hex, peerid_hex, ip_readable); | 662 | syslog(LOG_INFO, "time=%s event=completed info_hash=%s peer_id=%s ip=%s", timestring, hash_hex, peerid_hex, ip_readable); |
| 671 | } | 663 | } |
| 672 | #endif | 664 | #endif |
| @@ -750,7 +742,7 @@ static void *stats_worker(void *args) { | |||
| 750 | return NULL; | 742 | return NULL; |
| 751 | } | 743 | } |
| 752 | 744 | ||
| 753 | void stats_deliver(int64 sock, int tasktype) { mutex_workqueue_pushtask(sock, tasktype); } | 745 | void stats_deliver(int64_t sock, int tasktype) { mutex_workqueue_pushtask(sock, tasktype); } |
| 754 | 746 | ||
| 755 | static pthread_t thread_id; | 747 | static pthread_t thread_id; |
| 756 | void stats_init(void) { | 748 | void stats_init(void) { |
| @@ -42,7 +42,7 @@ enum { | |||
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data); | 44 | void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_data); |
| 45 | void stats_deliver(int64 sock, int tasktype); | 45 | void stats_deliver(int64_t sock, int tasktype); |
| 46 | void stats_cleanup(void); | 46 | void stats_cleanup(void); |
| 47 | size_t return_stats_for_tracker(char *reply, int mode, int format); | 47 | size_t return_stats_for_tracker(char *reply, int mode, int format); |
| 48 | size_t stats_return_tracker_version(char *reply); | 48 | size_t stats_return_tracker_version(char *reply); |
| @@ -163,7 +163,7 @@ void sync_deinit( ) { | |||
| 163 | pthread_cancel( thread_id ); | 163 | pthread_cancel( thread_id ); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | void sync_deliver( int64 socket ) { | 166 | void sync_deliver( int64_t socket ) { |
| 167 | mutex_workqueue_pushtask( socket, TASK_SYNC_OUT ); | 167 | mutex_workqueue_pushtask( socket, TASK_SYNC_OUT ); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| @@ -6,12 +6,14 @@ | |||
| 6 | #ifndef OT_SYNC_H__ | 6 | #ifndef OT_SYNC_H__ |
| 7 | #define OT_SYNC_H__ | 7 | #define OT_SYNC_H__ |
| 8 | 8 | ||
| 9 | #include <stdint.h> | ||
| 10 | |||
| 9 | #ifdef WANT_SYNC_BATCH | 11 | #ifdef WANT_SYNC_BATCH |
| 10 | enum { SYNC_IN, SYNC_OUT }; | 12 | enum { SYNC_IN, SYNC_OUT }; |
| 11 | 13 | ||
| 12 | void sync_init(); | 14 | void sync_init(); |
| 13 | void sync_deinit(); | 15 | void sync_deinit(); |
| 14 | void sync_deliver(int64 socket); | 16 | void sync_deliver(int64_t socket); |
| 15 | 17 | ||
| 16 | int add_changeset_to_tracker(uint8_t *data, size_t len); | 18 | int add_changeset_to_tracker(uint8_t *data, size_t len); |
| 17 | #else | 19 | #else |
| @@ -12,19 +12,16 @@ | |||
| 12 | 12 | ||
| 13 | /* Libowfat */ | 13 | /* Libowfat */ |
| 14 | #include "io.h" | 14 | #include "io.h" |
| 15 | #include "socket.h" | ||
| 16 | 15 | ||
| 17 | /* Opentracker */ | 16 | /* Opentracker */ |
| 18 | #include "ot_ip.h" | 17 | #include "ot_ip.h" |
| 19 | #include "ot_random.h" | 18 | #include "ot_random.h" |
| 20 | #include "ot_rijndael.h" | 19 | #include "ot_rijndael.h" |
| 20 | #include "ot_socket.h" | ||
| 21 | #include "ot_stats.h" | 21 | #include "ot_stats.h" |
| 22 | #include "ot_udp.h" | 22 | #include "ot_udp.h" |
| 23 | #include "trackerlogic.h" | 23 | #include "trackerlogic.h" |
| 24 | 24 | ||
| 25 | #if 0 | ||
| 26 | static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; | ||
| 27 | #endif | ||
| 28 | static uint32_t g_rijndael_round_key[44] = {0}; | 25 | static uint32_t g_rijndael_round_key[44] = {0}; |
| 29 | static volatile uint32_t g_key_of_the_hour[2] = {0}; | 26 | static volatile uint32_t g_key_of_the_hour[2] = {0}; |
| 30 | static volatile ot_time g_hour_of_the_key; | 27 | static volatile ot_time g_hour_of_the_key; |
| @@ -71,19 +68,20 @@ static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int | |||
| 71 | } | 68 | } |
| 72 | 69 | ||
| 73 | /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ | 70 | /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ |
| 74 | int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | 71 | int handle_udp6(int64_t serversocket, struct ot_workstruct *ws) { |
| 75 | ot_ip6 remoteip; | 72 | ot_ip6 remoteip; |
| 76 | uint32_t *inpacket = (uint32_t *)ws->inbuf; | 73 | uint32_t *inpacket = (uint32_t *)ws->inbuf; |
| 77 | uint32_t *outpacket = (uint32_t *)ws->outbuf; | 74 | uint32_t *outpacket = (uint32_t *)ws->outbuf; |
| 78 | uint32_t left, event, scopeid; | 75 | uint32_t left, event; |
| 79 | uint32_t connid[2]; | 76 | uint32_t connid[2]; |
| 80 | uint32_t action; | 77 | uint32_t action; |
| 81 | uint16_t port, remoteport; | 78 | uint16_t port, remoteport; |
| 82 | size_t byte_count, scrape_count; | 79 | size_t byte_count, scrape_count; |
| 83 | 80 | ||
| 84 | byte_count = socket_recv6(serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport, &scopeid); | 81 | ssize_t result = socket_recv(serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport); |
| 85 | if (!byte_count) | 82 | if (result <= 0) |
| 86 | return 0; | 83 | return 0; |
| 84 | byte_count = (size_t)result; | ||
| 87 | 85 | ||
| 88 | stats_issue_event(EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip); | 86 | stats_issue_event(EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip); |
| 89 | stats_issue_event(EVENT_READ, FLAG_UDP, byte_count); | 87 | stats_issue_event(EVENT_READ, FLAG_UDP, byte_count); |
| @@ -117,7 +115,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 117 | outpacket[0] = htonl(3); | 115 | outpacket[0] = htonl(3); |
| 118 | outpacket[1] = inpacket[3]; | 116 | outpacket[1] = inpacket[3]; |
| 119 | memcpy(&outpacket[2], "Connection ID missmatch.", s); | 117 | memcpy(&outpacket[2], "Connection ID missmatch.", s); |
| 120 | socket_send6(serversocket, ws->outbuf, 8 + s, remoteip, remoteport, 0); | 118 | socket_send(serversocket, ws->outbuf, 8 + s, remoteip, remoteport); |
| 121 | stats_issue_event(EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s); | 119 | stats_issue_event(EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s); |
| 122 | return 1; | 120 | return 1; |
| 123 | } | 121 | } |
| @@ -134,7 +132,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 134 | outpacket[2] = connid[0]; | 132 | outpacket[2] = connid[0]; |
| 135 | outpacket[3] = connid[1]; | 133 | outpacket[3] = connid[1]; |
| 136 | 134 | ||
| 137 | socket_send6(serversocket, ws->outbuf, 16, remoteip, remoteport, 0); | 135 | socket_send(serversocket, ws->outbuf, 16, remoteip, remoteport); |
| 138 | stats_issue_event(EVENT_CONNECT, FLAG_UDP, 16); | 136 | stats_issue_event(EVENT_CONNECT, FLAG_UDP, 16); |
| 139 | break; | 137 | break; |
| 140 | case 1: /* This is an announce action */ | 138 | case 1: /* This is an announce action */ |
| @@ -184,7 +182,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 184 | ws->reply_size = 8 + add_peer_to_torrent_and_return_peers(FLAG_UDP, ws, numwant); | 182 | ws->reply_size = 8 + add_peer_to_torrent_and_return_peers(FLAG_UDP, ws, numwant); |
| 185 | } | 183 | } |
| 186 | 184 | ||
| 187 | socket_send6(serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport, 0); | 185 | socket_send(serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport); |
| 188 | stats_issue_event(EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size); | 186 | stats_issue_event(EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size); |
| 189 | break; | 187 | break; |
| 190 | 188 | ||
| @@ -195,7 +193,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 195 | for (scrape_count = 0; (scrape_count * 20 < byte_count - 16) && (scrape_count <= 74); scrape_count++) | 193 | for (scrape_count = 0; (scrape_count * 20 < byte_count - 16) && (scrape_count <= 74); scrape_count++) |
| 196 | return_udp_scrape_for_torrent(*(ot_hash *)(((char *)inpacket) + 16 + 20 * scrape_count), ((char *)outpacket) + 8 + 12 * scrape_count); | 194 | return_udp_scrape_for_torrent(*(ot_hash *)(((char *)inpacket) + 16 + 20 * scrape_count), ((char *)outpacket) + 8 + 12 * scrape_count); |
| 197 | 195 | ||
| 198 | socket_send6(serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport, 0); | 196 | socket_send(serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport); |
| 199 | stats_issue_event(EVENT_SCRAPE, FLAG_UDP, scrape_count); | 197 | stats_issue_event(EVENT_SCRAPE, FLAG_UDP, scrape_count); |
| 200 | break; | 198 | break; |
| 201 | } | 199 | } |
| @@ -203,7 +201,7 @@ int handle_udp6(int64 serversocket, struct ot_workstruct *ws) { | |||
| 203 | } | 201 | } |
| 204 | 202 | ||
| 205 | static void *udp_worker(void *args) { | 203 | static void *udp_worker(void *args) { |
| 206 | int64 sock = (int64)args; | 204 | int64_t sock = (int64_t)args; |
| 207 | struct ot_workstruct ws; | 205 | struct ot_workstruct ws; |
| 208 | memset(&ws, 0, sizeof(ws)); | 206 | memset(&ws, 0, sizeof(ws)); |
| 209 | 207 | ||
| @@ -229,7 +227,7 @@ static void *udp_worker(void *args) { | |||
| 229 | return NULL; | 227 | return NULL; |
| 230 | } | 228 | } |
| 231 | 229 | ||
| 232 | void udp_init(int64 sock, unsigned int worker_count) { | 230 | void udp_init(int64_t sock, unsigned int worker_count) { |
| 233 | pthread_t thread_id; | 231 | pthread_t thread_id; |
| 234 | if (!g_rijndael_round_key[0]) | 232 | if (!g_rijndael_round_key[0]) |
| 235 | udp_generate_rijndael_round_key(); | 233 | udp_generate_rijndael_round_key(); |
| @@ -6,8 +6,12 @@ | |||
| 6 | #ifndef OT_UDP_H__ | 6 | #ifndef OT_UDP_H__ |
| 7 | #define OT_UDP_H__ | 7 | #define OT_UDP_H__ |
| 8 | 8 | ||
| 9 | void udp_init(int64 sock, unsigned int worker_count); | 9 | #include <stdint.h> |
| 10 | |||
| 11 | #include "trackerlogic.h" | ||
| 12 | |||
| 13 | void udp_init(int64_t sock, unsigned int worker_count); | ||
| 10 | void udp_kickoff(void); | 14 | void udp_kickoff(void); |
| 11 | int handle_udp6(int64 serversocket, struct ot_workstruct *ws); | 15 | int handle_udp6(int64_t serversocket, struct ot_workstruct *ws); |
| 12 | 16 | ||
| 13 | #endif | 17 | #endif |
diff --git a/ot_vector.h b/ot_vector.h index 2618363..fbc75f4 100644 --- a/ot_vector.h +++ b/ot_vector.h | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | #ifndef OT_VECTOR_H__ | 6 | #ifndef OT_VECTOR_H__ |
| 7 | #define OT_VECTOR_H__ | 7 | #define OT_VECTOR_H__ |
| 8 | 8 | ||
| 9 | #include <stddef.h> | ||
| 10 | |||
| 9 | /* These defines control vectors behaviour */ | 11 | /* These defines control vectors behaviour */ |
| 10 | #define OT_VECTOR_MIN_MEMBERS 2 | 12 | #define OT_VECTOR_MIN_MEMBERS 2 |
| 11 | #define OT_VECTOR_GROW_RATIO 2 | 13 | #define OT_VECTOR_GROW_RATIO 2 |
| @@ -21,6 +23,9 @@ typedef struct { | |||
| 21 | size_t space; | 23 | size_t space; |
| 22 | } ot_vector; | 24 | } ot_vector; |
| 23 | 25 | ||
| 26 | /* trackerlogic.h needs ot_vector, break circular dependency here */ | ||
| 27 | #include "trackerlogic.h" | ||
| 28 | |||
| 24 | void *binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch); | 29 | void *binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch); |
| 25 | void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch); | 30 | void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch); |
| 26 | ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch); | 31 | ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch); |
| @@ -7,38 +7,33 @@ | |||
| 7 | #include <arpa/inet.h> | 7 | #include <arpa/inet.h> |
| 8 | #include <ctype.h> | 8 | #include <ctype.h> |
| 9 | #include <errno.h> | 9 | #include <errno.h> |
| 10 | #include <fcntl.h> | ||
| 11 | #include <pthread.h> | 10 | #include <pthread.h> |
| 12 | #include <stdint.h> | 11 | #include <stdint.h> |
| 13 | #include <stdio.h> | 12 | #include <stdio.h> |
| 14 | #include <stdlib.h> | 13 | #include <stdlib.h> |
| 15 | #include <string.h> | 14 | #include <string.h> |
| 16 | #include <sys/socket.h> | ||
| 17 | #include <unistd.h> | 15 | #include <unistd.h> |
| 18 | 16 | ||
| 19 | /* Libowfat */ | 17 | /* Libowfat */ |
| 20 | #include "io.h" | 18 | #include "io.h" |
| 21 | #include "iob.h" | 19 | #include "iob.h" |
| 22 | #include "socket.h" | ||
| 23 | 20 | ||
| 24 | /* Opentracker */ | 21 | /* Opentracker */ |
| 25 | #include "ot_ip.h" | 22 | #include "ot_ip.h" |
| 26 | #include "ot_mutex.h" | 23 | #include "ot_mutex.h" |
| 27 | #include "ot_random.h" | 24 | #include "ot_random.h" |
| 28 | #include "ot_scan.h" | 25 | #include "ot_scan.h" |
| 26 | #include "ot_socket.h" | ||
| 29 | #include "ot_stats.h" | 27 | #include "ot_stats.h" |
| 30 | #include "ot_vector.h" | 28 | #include "ot_vector.h" |
| 31 | #include "trackerlogic.h" | 29 | #include "trackerlogic.h" |
| 32 | 30 | ||
| 33 | #ifndef WANT_SYNC_LIVE | ||
| 34 | #define WANT_SYNC_LIVE | ||
| 35 | #endif | ||
| 36 | #include "ot_livesync.h" | 31 | #include "ot_livesync.h" |
| 37 | 32 | ||
| 38 | ot_ip6 g_serverip; | 33 | ot_ip6 g_serverip; |
| 39 | uint16_t g_serverport = 9009; | 34 | uint16_t g_serverport = 9009; |
| 40 | uint32_t g_tracker_id; | 35 | uint32_t g_tracker_id; |
| 41 | char groupip_1[4] = {224, 0, 23, 5}; | 36 | ot_ip6 groupip_1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 224, 0, 23, 5}; |
| 42 | int g_self_pipe[2]; | 37 | int g_self_pipe[2]; |
| 43 | 38 | ||
| 44 | /* If you have more than 10 peers, don't use this proxy | 39 | /* If you have more than 10 peers, don't use this proxy |
| @@ -63,11 +58,11 @@ enum { OT_SYNC_PEER4, OT_SYNC_PEER6 }; | |||
| 63 | enum { FLAG_SERVERSOCKET = 1 }; | 58 | enum { FLAG_SERVERSOCKET = 1 }; |
| 64 | 59 | ||
| 65 | /* For incoming packets */ | 60 | /* For incoming packets */ |
| 66 | static int64 g_socket_in = -1; | 61 | static int g_socket_in = -1; |
| 67 | static uint8_t g_inbuffer[LIVESYNC_INCOMING_BUFFSIZE]; | 62 | static uint8_t g_inbuffer[LIVESYNC_INCOMING_BUFFSIZE]; |
| 68 | 63 | ||
| 69 | /* For outgoing packets */ | 64 | /* For outgoing packets */ |
| 70 | static int64 g_socket_out = -1; | 65 | static int g_socket_out = -1; |
| 71 | static uint8_t g_peerbuffer_start[LIVESYNC_OUTGOING_BUFFSIZE_PEERS]; | 66 | static uint8_t g_peerbuffer_start[LIVESYNC_OUTGOING_BUFFSIZE_PEERS]; |
| 72 | static uint8_t *g_peerbuffer_pos; | 67 | static uint8_t *g_peerbuffer_pos; |
| 73 | static uint8_t *g_peerbuffer_highwater = g_peerbuffer_start + LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS; | 68 | static uint8_t *g_peerbuffer_highwater = g_peerbuffer_start + LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS; |
| @@ -89,34 +84,17 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_ | |||
| 89 | } | 84 | } |
| 90 | 85 | ||
| 91 | void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { | 86 | void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { |
| 92 | char tmpip[4] = {0, 0, 0, 0}; | ||
| 93 | char *v4ip; | ||
| 94 | |||
| 95 | if (!ip_is_v4mapped(ip)) | 87 | if (!ip_is_v4mapped(ip)) |
| 96 | exerr("v6 mcast support not yet available."); | 88 | exerr("v6 mcast support not yet available."); |
| 97 | v4ip = ip + 12; | ||
| 98 | 89 | ||
| 99 | if (g_socket_in != -1) | 90 | if (g_socket_in != -1) |
| 100 | exerr("Error: Livesync listen ip specified twice."); | 91 | exerr("Error: Livesync listen ip specified twice."); |
| 101 | 92 | ||
| 102 | if ((g_socket_in = socket_udp4()) < 0) | 93 | if ((g_socket_in = socket_mcast_join(groupip_1, ip, port)) == -1) |
| 103 | exerr("Error: Cant create live sync incoming socket."); | ||
| 104 | |||
| 105 | fcntl(g_socket_in, F_SETFL, fcntl(g_socket_in, F_GETFL, 0) & ~O_NONBLOCK); | ||
| 106 | |||
| 107 | if (socket_bind4_reuse(g_socket_in, tmpip, port) == -1) | ||
| 108 | exerr("Error: Cant bind live sync incoming socket."); | 94 | exerr("Error: Cant bind live sync incoming socket."); |
| 109 | 95 | ||
| 110 | if (socket_mcjoin4(g_socket_in, groupip_1, v4ip)) | 96 | if ((g_socket_out = socket_mcast_bind(ip, port, 1)) == -1) |
| 111 | exerr("Error: Cant make live sync incoming socket join mcast group."); | ||
| 112 | |||
| 113 | if ((g_socket_out = socket_udp4()) < 0) | ||
| 114 | exerr("Error: Cant create live sync outgoing socket."); | ||
| 115 | if (socket_bind4_reuse(g_socket_out, v4ip, port) == -1) | ||
| 116 | exerr("Error: Cant bind live sync outgoing socket."); | 97 | exerr("Error: Cant bind live sync outgoing socket."); |
| 117 | |||
| 118 | socket_mcttl4(g_socket_out, 1); | ||
| 119 | socket_mcloop4(g_socket_out, 1); | ||
| 120 | } | 98 | } |
| 121 | 99 | ||
| 122 | size_t add_peer_to_torrent_proxy(ot_hash hash, ot_peer *peer, size_t peer_size) { | 100 | size_t add_peer_to_torrent_proxy(ot_hash hash, ot_peer *peer, size_t peer_size) { |
| @@ -249,7 +227,7 @@ typedef struct { | |||
| 249 | uint8_t indata[8192 * 16]; /* Any data not processed yet */ | 227 | uint8_t indata[8192 * 16]; /* Any data not processed yet */ |
| 250 | size_t indata_length; /* Length of unprocessed data */ | 228 | size_t indata_length; /* Length of unprocessed data */ |
| 251 | uint32_t tracker_id; /* How the other end greeted */ | 229 | uint32_t tracker_id; /* How the other end greeted */ |
| 252 | int64 fd; /* A file handle, if connected, <= 0 is disconnected (0 initially, -1 else) */ | 230 | int64_t fd; /* A file handle, if connected, <= 0 is disconnected (0 initially, -1 else) */ |
| 253 | io_batch outdata; /* The iobatch containing our sync data */ | 231 | io_batch outdata; /* The iobatch containing our sync data */ |
| 254 | 232 | ||
| 255 | size_t packet_tcount; /* Number of unprocessed torrents in packet we currently receive */ | 233 | size_t packet_tcount; /* Number of unprocessed torrents in packet we currently receive */ |
| @@ -283,19 +261,11 @@ static void handle_reconnects(void) { | |||
| 283 | size_t i; | 261 | size_t i; |
| 284 | for (i = 0; i < g_connection_count; ++i) | 262 | for (i = 0; i < g_connection_count; ++i) |
| 285 | if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) { | 263 | if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) { |
| 286 | int64 newfd = socket_tcp6(); | 264 | int64_t newfd = socket_tcp_connect(g_serverip, g_serverport, g_connections[i].ip, g_connections[i].port); |
| 287 | fprintf(stderr, "(Re)connecting to peer..."); | 265 | fprintf(stderr, "(Re)connecting to peer..."); |
| 288 | if (newfd < 0) | 266 | if (newfd == -1) |
| 289 | continue; /* No socket for you */ | 267 | continue; /* No socket for you */ |
| 290 | io_fd(newfd); | 268 | io_fd(newfd); |
| 291 | if (socket_bind6_reuse(newfd, g_serverip, g_serverport, 0)) { | ||
| 292 | io_close(newfd); | ||
| 293 | continue; | ||
| 294 | } | ||
| 295 | if (socket_connect6(newfd, g_connections[i].ip, g_connections[i].port, 0) == -1 && errno != EINPROGRESS && errno != EWOULDBLOCK) { | ||
| 296 | close(newfd); | ||
| 297 | continue; | ||
| 298 | } | ||
| 299 | io_wantwrite(newfd); /* So we will be informed when it is connected */ | 269 | io_wantwrite(newfd); /* So we will be informed when it is connected */ |
| 300 | io_setcookie(newfd, g_connections + i); | 270 | io_setcookie(newfd, g_connections + i); |
| 301 | 271 | ||
| @@ -308,12 +278,12 @@ static void handle_reconnects(void) { | |||
| 308 | } | 278 | } |
| 309 | 279 | ||
| 310 | /* Handle incoming connection requests, check against whitelist */ | 280 | /* Handle incoming connection requests, check against whitelist */ |
| 311 | static void handle_accept(int64 serversocket) { | 281 | static void handle_accept(int64_t serversocket) { |
| 312 | int64 newfd; | 282 | int64_t newfd; |
| 313 | ot_ip6 ip; | 283 | ot_ip6 ip; |
| 314 | uint16 port; | 284 | uint16_t port; |
| 315 | 285 | ||
| 316 | while ((newfd = socket_accept6(serversocket, ip, &port, NULL)) != -1) { | 286 | while ((newfd = socket_accept(serversocket, ip, &port)) != -1) { |
| 317 | 287 | ||
| 318 | /* XXX some access control */ | 288 | /* XXX some access control */ |
| 319 | 289 | ||
| @@ -351,9 +321,9 @@ static void handle_accept(int64 serversocket) { | |||
| 351 | } | 321 | } |
| 352 | 322 | ||
| 353 | /* New sync data on the stream */ | 323 | /* New sync data on the stream */ |
| 354 | static void handle_read(int64 peersocket) { | 324 | static void handle_read(int64_t peersocket) { |
| 355 | int i; | 325 | int i; |
| 356 | int64 datalen; | 326 | int64_t datalen; |
| 357 | uint32_t tracker_id; | 327 | uint32_t tracker_id; |
| 358 | proxy_peer *peer = io_getcookie(peersocket); | 328 | proxy_peer *peer = io_getcookie(peersocket); |
| 359 | 329 | ||
| @@ -420,7 +390,7 @@ static void handle_read(int64 peersocket) { | |||
| 420 | } | 390 | } |
| 421 | 391 | ||
| 422 | /* Can write new sync data to the stream */ | 392 | /* Can write new sync data to the stream */ |
| 423 | static void handle_write(int64 peersocket) { | 393 | static void handle_write(int64_t peersocket) { |
| 424 | proxy_peer *peer = io_getcookie(peersocket); | 394 | proxy_peer *peer = io_getcookie(peersocket); |
| 425 | 395 | ||
| 426 | if (!peer) { | 396 | if (!peer) { |
| @@ -436,7 +406,7 @@ static void handle_write(int64 peersocket) { | |||
| 436 | break; | 406 | break; |
| 437 | case FLAG_CONNECTING: | 407 | case FLAG_CONNECTING: |
| 438 | /* Ensure that the connection is established and handle connection error */ | 408 | /* Ensure that the connection is established and handle connection error */ |
| 439 | if (peer->state & FLAG_OUTGOING && !socket_connected(peersocket)) { | 409 | if (peer->state & FLAG_OUTGOING && !socket_is_connected(peersocket)) { |
| 440 | fprintf(stderr, "failed\n"); | 410 | fprintf(stderr, "failed\n"); |
| 441 | reset_info_block(peer); | 411 | reset_info_block(peer); |
| 442 | io_close(peersocket); | 412 | io_close(peersocket); |
| @@ -472,7 +442,7 @@ static void handle_write(int64 peersocket) { | |||
| 472 | } | 442 | } |
| 473 | 443 | ||
| 474 | static void server_mainloop() { | 444 | static void server_mainloop() { |
| 475 | int64 sock; | 445 | int64_t sock; |
| 476 | uint32_t packet_type; | 446 | uint32_t packet_type; |
| 477 | 447 | ||
| 478 | /* inlined livesync_init() */ | 448 | /* inlined livesync_init() */ |
| @@ -515,13 +485,10 @@ static void panic(const char *routine) { | |||
| 515 | } | 485 | } |
| 516 | 486 | ||
| 517 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port) { | 487 | static int64_t ot_try_bind(ot_ip6 ip, uint16_t port) { |
| 518 | int64 sock = socket_tcp6(); | 488 | int64_t sock = socket_tcp_listen(ip, port); |
| 519 | |||
| 520 | if (socket_bind6_reuse(sock, ip, port, 0) == -1) | ||
| 521 | panic("socket_bind6_reuse"); | ||
| 522 | 489 | ||
| 523 | if (socket_listen(sock, SOMAXCONN) == -1) | 490 | if (sock == -1) |
| 524 | panic("socket_listen"); | 491 | panic("socket_tcp_listen"); |
| 525 | 492 | ||
| 526 | if (!io_fd(sock)) | 493 | if (!io_fd(sock)) |
| 527 | panic("io_fd"); | 494 | panic("io_fd"); |
| @@ -776,7 +743,7 @@ static void *streamsync_worker(void *args) { | |||
| 776 | } | 743 | } |
| 777 | 744 | ||
| 778 | static void livesync_issue_peersync() { | 745 | static void livesync_issue_peersync() { |
| 779 | socket_send4(g_socket_out, (char *)g_peerbuffer_start, g_peerbuffer_pos - g_peerbuffer_start, groupip_1, LIVESYNC_PORT); | 746 | socket_mcast_send(g_socket_out, g_peerbuffer_start, (size_t)(g_peerbuffer_pos - g_peerbuffer_start), groupip_1, LIVESYNC_PORT); |
| 780 | g_peerbuffer_pos = g_peerbuffer_start + sizeof(g_tracker_id) + sizeof(uint32_t); | 747 | g_peerbuffer_pos = g_peerbuffer_start + sizeof(g_tracker_id) + sizeof(uint32_t); |
| 781 | g_next_packet_time = time(NULL) + LIVESYNC_MAXDELAY; | 748 | g_next_packet_time = time(NULL) + LIVESYNC_MAXDELAY; |
| 782 | } | 749 | } |
| @@ -871,7 +838,7 @@ static void *livesync_worker(void *args) { | |||
| 871 | ot_ip6 in_ip; | 838 | ot_ip6 in_ip; |
| 872 | uint16_t in_port; | 839 | uint16_t in_port; |
| 873 | uint32_t packet_type; | 840 | uint32_t packet_type; |
| 874 | size_t datalen = socket_recv4(g_socket_in, (char *)g_inbuffer, LIVESYNC_INCOMING_BUFFSIZE, 12 + (char *)in_ip, &in_port); | 841 | ssize_t datalen = socket_recv(g_socket_in, g_inbuffer, LIVESYNC_INCOMING_BUFFSIZE, in_ip, &in_port); |
| 875 | 842 | ||
| 876 | /* Expect at least tracker id and packet type */ | 843 | /* Expect at least tracker id and packet type */ |
| 877 | if (datalen <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t))) | 844 | if (datalen <= (ssize_t)(sizeof(g_tracker_id) + sizeof(uint32_t))) |
diff --git a/scan_urlencoded_query.c b/scan_urlencoded_query.c index cf0c5b1..4825a4a 100644 --- a/scan_urlencoded_query.c +++ b/scan_urlencoded_query.c | |||
| @@ -170,16 +170,12 @@ size_t fmt_urlencoded(char *dest, const uint8_t *src, size_t len) { | |||
| 170 | 170 | ||
| 171 | /* strchr would find the terminator, so a zero byte never counts as safe */ | 171 | /* strchr would find the terminator, so a zero byte never counts as safe */ |
| 172 | if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c && strchr(safe, c))) { | 172 | if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c && strchr(safe, c))) { |
| 173 | if (dest) | 173 | dest[written++] = (char)c; |
| 174 | dest[written] = (char)c; | ||
| 175 | ++written; | ||
| 176 | } else { | 174 | } else { |
| 177 | if (dest) { | 175 | dest[written] = '%'; |
| 178 | dest[written] = '%'; | 176 | dest[written + 1] = hexdigit[c >> 4]; |
| 179 | dest[written + 1] = hexdigit[c >> 4]; | 177 | dest[written + 2] = hexdigit[c & 15]; |
| 180 | dest[written + 2] = hexdigit[c & 15]; | 178 | written += 3; |
| 181 | } | ||
| 182 | written += 3; | ||
| 183 | } | 179 | } |
| 184 | } | 180 | } |
| 185 | 181 | ||
diff --git a/scan_urlencoded_query.h b/scan_urlencoded_query.h index 6f12c03..d0929cf 100644 --- a/scan_urlencoded_query.h +++ b/scan_urlencoded_query.h | |||
| @@ -55,9 +55,7 @@ void scan_urlencoded_skipvalue(char **string); | |||
| 55 | ssize_t scan_fixed_int(char *data, size_t len, int *number); | 55 | ssize_t scan_fixed_int(char *data, size_t len, int *number); |
| 56 | 56 | ||
| 57 | /* The other direction: percent encode len bytes from src into dest and return | 57 | /* The other direction: percent encode len bytes from src into dest and return |
| 58 | how many characters were written, or how many would be needed when dest is | 58 | how many characters were written. dest needs room for three times len. */ |
| 59 | NULL. dest needs room for three times len. | ||
| 60 | */ | ||
| 61 | size_t fmt_urlencoded(char *dest, const uint8_t *src, size_t len); | 59 | size_t fmt_urlencoded(char *dest, const uint8_t *src, size_t len); |
| 62 | 60 | ||
| 63 | #endif | 61 | #endif |
diff --git a/tests/runner.c b/tests/runner.c index 10b6625..db62246 100644 --- a/tests/runner.c +++ b/tests/runner.c | |||
| @@ -22,6 +22,7 @@ static const struct module modules[] = {{"scan_urlencoded_query", test_scan_urle | |||
| 22 | {"ot_scan", test_scan}, | 22 | {"ot_scan", test_scan}, |
| 23 | {"ot_buf", test_buf}, | 23 | {"ot_buf", test_buf}, |
| 24 | {"ot_ip", test_ip}, | 24 | {"ot_ip", test_ip}, |
| 25 | {"ot_socket", test_socket}, | ||
| 25 | {"ot_accesslist", test_accesslist}, | 26 | {"ot_accesslist", test_accesslist}, |
| 26 | {NULL, NULL}}; | 27 | {NULL, NULL}}; |
| 27 | 28 | ||
diff --git a/tests/t_scan_urlencoded_query.c b/tests/t_scan_urlencoded_query.c index 6fa34e0..f660ea3 100644 --- a/tests/t_scan_urlencoded_query.c +++ b/tests/t_scan_urlencoded_query.c | |||
| @@ -295,14 +295,6 @@ static void case_fmt_hex_is_lower_case(void) { | |||
| 295 | CHECK_STR(dest, "%00%ab%ff"); | 295 | CHECK_STR(dest, "%00%ab%ff"); |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static void case_fmt_length_only(void) { | ||
| 299 | const uint8_t src[] = {'a', 0xff, 'b'}; | ||
| 300 | |||
| 301 | test_case("a null destination reports the length without writing"); | ||
| 302 | CHECK_INT(fmt_urlencoded(NULL, src, sizeof(src)), 5); | ||
| 303 | CHECK_INT(fmt_urlencoded(NULL, src, 0), 0); | ||
| 304 | } | ||
| 305 | |||
| 306 | static void case_fmt_zero_length(void) { | 298 | static void case_fmt_zero_length(void) { |
| 307 | char dest[4]; | 299 | char dest[4]; |
| 308 | 300 | ||
| @@ -374,7 +366,6 @@ void test_scan_urlencoded_query(void) { | |||
| 374 | case_fmt_passes_safe_bytes(); | 366 | case_fmt_passes_safe_bytes(); |
| 375 | case_fmt_escapes_the_rest(); | 367 | case_fmt_escapes_the_rest(); |
| 376 | case_fmt_hex_is_lower_case(); | 368 | case_fmt_hex_is_lower_case(); |
| 377 | case_fmt_length_only(); | ||
| 378 | case_fmt_zero_length(); | 369 | case_fmt_zero_length(); |
| 379 | case_fmt_worst_case_fits(); | 370 | case_fmt_worst_case_fits(); |
| 380 | case_fmt_decoder_disagrees_on_dollar(); | 371 | case_fmt_decoder_disagrees_on_dollar(); |
diff --git a/tests/t_socket.c b/tests/t_socket.c new file mode 100644 index 0000000..bbc9e5e --- /dev/null +++ b/tests/t_socket.c | |||
| @@ -0,0 +1,307 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | ||
| 3 | |||
| 4 | $id$ */ | ||
| 5 | |||
| 6 | /* System */ | ||
| 7 | #include <errno.h> | ||
| 8 | #include <fcntl.h> | ||
| 9 | #include <netinet/in.h> | ||
| 10 | #include <poll.h> | ||
| 11 | #include <string.h> | ||
| 12 | #include <sys/socket.h> | ||
| 13 | #include <unistd.h> | ||
| 14 | |||
| 15 | /* Opentracker */ | ||
| 16 | #include "ot_ip.h" | ||
| 17 | #include "ot_socket.h" | ||
| 18 | #include "test.h" | ||
| 19 | |||
| 20 | /* These cases talk to the loopback interface rather than to a mock, because | ||
| 21 | what is worth pinning down here is the behaviour of the socket options the | ||
| 22 | rest of the tracker relies on, and only the kernel can report that. */ | ||
| 23 | |||
| 24 | static const char ip_any[16] = {0}; | ||
| 25 | static const char ip_loopback[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; | ||
| 26 | static const char ip_v4_loopback[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1}; | ||
| 27 | /* RFC 3849 reserves 2001:db8::/32 for documentation, so no host carries it */ | ||
| 28 | static const char ip_unassigned[16] = {0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; | ||
| 29 | |||
| 30 | /* What a socket ended up bound to, which is not always what was asked for: a | ||
| 31 | FreeBSD jail, for one, rewrites a loopback bind to the address it was given. | ||
| 32 | A datagram a socket sends to itself must come back carrying this, so the | ||
| 33 | cases below compare against it rather than against the address they passed | ||
| 34 | to the bind. */ | ||
| 35 | static void bound_address(int s, char ip[16], uint16_t *port) { | ||
| 36 | struct sockaddr_storage ss; | ||
| 37 | socklen_t len = sizeof(ss); | ||
| 38 | |||
| 39 | memset(&ss, 0, sizeof(ss)); | ||
| 40 | memset(ip, 0, 16); | ||
| 41 | *port = 0; | ||
| 42 | if (getsockname(s, (struct sockaddr *)&ss, &len) == -1) | ||
| 43 | return; | ||
| 44 | |||
| 45 | /* Spelled out here rather than borrowed from ot_socket.c, so that a wrong | ||
| 46 | idea about how a kernel reports an address cannot hide in both at once */ | ||
| 47 | if (ss.ss_family == AF_INET) { | ||
| 48 | const struct sockaddr_in *sa = (const struct sockaddr_in *)&ss; | ||
| 49 | |||
| 50 | memcpy(ip, ip_v4mapped_prefix, sizeof(ip_v4mapped_prefix)); | ||
| 51 | memcpy(ip + sizeof(ip_v4mapped_prefix), &sa->sin_addr, 4); | ||
| 52 | *port = ntohs(sa->sin_port); | ||
| 53 | } else { | ||
| 54 | const struct sockaddr_in6 *sa = (const struct sockaddr_in6 *)&ss; | ||
| 55 | |||
| 56 | memcpy(ip, &sa->sin6_addr, 16); | ||
| 57 | *port = ntohs(sa->sin6_port); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | static int is_nonblocking(int s) { | ||
| 62 | int flags = fcntl(s, F_GETFL, 0); | ||
| 63 | return flags != -1 && (flags & O_NONBLOCK) != 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int sock_flag(int s, int level, int option) { | ||
| 67 | int value = -1; | ||
| 68 | socklen_t len = sizeof(value); | ||
| 69 | |||
| 70 | if (getsockopt(s, level, option, &value, &len) == -1) | ||
| 71 | return -1; | ||
| 72 | return value != 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | /* Wait for one event, so a test never blocks forever on a lost packet */ | ||
| 76 | static int wait_for(int s, short events) { | ||
| 77 | struct pollfd pfd; | ||
| 78 | |||
| 79 | pfd.fd = s; | ||
| 80 | pfd.events = events; | ||
| 81 | pfd.revents = 0; | ||
| 82 | return poll(&pfd, 1, 2000) == 1; | ||
| 83 | } | ||
| 84 | |||
| 85 | /* ------------------------------------------------------------ invariants */ | ||
| 86 | |||
| 87 | /* Asked for the wildcard address, because a socket bound to one specific | ||
| 88 | IPv6 address cannot carry IPv4 traffic anyway and Linux turns IPV6_V6ONLY | ||
| 89 | back on in that case. The tracker's own default is the wildcard. */ | ||
| 90 | static void case_socket_options(void) { | ||
| 91 | int udp, tcp; | ||
| 92 | |||
| 93 | test_case("a bound udp socket is non blocking and serves both families"); | ||
| 94 | udp = socket_udp_bind(ip_any, 0); | ||
| 95 | CHECK(udp != -1); | ||
| 96 | CHECK_INT(is_nonblocking(udp), 1); | ||
| 97 | CHECK_INT(sock_flag(udp, IPPROTO_IPV6, IPV6_V6ONLY), 0); | ||
| 98 | close(udp); | ||
| 99 | |||
| 100 | test_case("a listening tcp socket is non blocking and serves both families"); | ||
| 101 | tcp = socket_tcp_listen(ip_any, 0); | ||
| 102 | CHECK(tcp != -1); | ||
| 103 | CHECK_INT(is_nonblocking(tcp), 1); | ||
| 104 | CHECK_INT(sock_flag(tcp, IPPROTO_IPV6, IPV6_V6ONLY), 0); | ||
| 105 | close(tcp); | ||
| 106 | } | ||
| 107 | |||
| 108 | #ifdef SO_REUSEPORT | ||
| 109 | static void case_reuseport_is_opt_in(void) { | ||
| 110 | int s; | ||
| 111 | |||
| 112 | test_case("reuseport stays off unless the operator asks for it"); | ||
| 113 | g_socket_reuseport = 0; | ||
| 114 | s = socket_udp_bind(ip_loopback, 0); | ||
| 115 | CHECK(s != -1); | ||
| 116 | CHECK_INT(sock_flag(s, SOL_SOCKET, SO_REUSEPORT), 0); | ||
| 117 | close(s); | ||
| 118 | |||
| 119 | test_case("reuseport reaches the socket when it is asked for"); | ||
| 120 | g_socket_reuseport = 1; | ||
| 121 | s = socket_udp_bind(ip_loopback, 0); | ||
| 122 | CHECK(s != -1); | ||
| 123 | CHECK_INT(sock_flag(s, SOL_SOCKET, SO_REUSEPORT), 1); | ||
| 124 | close(s); | ||
| 125 | |||
| 126 | g_socket_reuseport = 0; | ||
| 127 | } | ||
| 128 | #endif | ||
| 129 | |||
| 130 | /* ------------------------------------------------------------------- udp */ | ||
| 131 | |||
| 132 | static void case_udp_roundtrip(void) { | ||
| 133 | char buf[32], ip[16], own_ip[16]; | ||
| 134 | uint16_t port = 0, own_port = 0; | ||
| 135 | int s; | ||
| 136 | |||
| 137 | test_case("a datagram comes back with the sender's address and port"); | ||
| 138 | s = socket_udp_bind(ip_loopback, 0); | ||
| 139 | CHECK(s != -1); | ||
| 140 | bound_address(s, own_ip, &own_port); | ||
| 141 | CHECK(own_port != 0); | ||
| 142 | CHECK_INT(socket_send(s, "opentracker", 11, own_ip, own_port), 11); | ||
| 143 | CHECK_INT(wait_for(s, POLLIN), 1); | ||
| 144 | CHECK_INT(socket_recv(s, buf, sizeof(buf), ip, &port), 11); | ||
| 145 | CHECK_MEM(buf, "opentracker", 11); | ||
| 146 | CHECK_MEM(ip, own_ip, 16); | ||
| 147 | CHECK_INT(port, own_port); | ||
| 148 | close(s); | ||
| 149 | } | ||
| 150 | |||
| 151 | /* An IPv4 peer must arrive in the v4 mapped form opentracker stores, however | ||
| 152 | the kernel chose to report it. Linux fills a v4 mapped sockaddr_in6 here | ||
| 153 | and the BSDs fill a plain sockaddr_in, so this is the case that tells the | ||
| 154 | two apart. */ | ||
| 155 | static void case_udp_v4mapped(void) { | ||
| 156 | char buf[32], ip[16], receiver_ip[16], sender_ip[16]; | ||
| 157 | uint16_t port = 0, receiver_port = 0, sender_port = 0; | ||
| 158 | int receiver, sender; | ||
| 159 | |||
| 160 | test_case("an IPv4 sender is reported in its v4 mapped form"); | ||
| 161 | receiver = socket_udp_bind(ip_v4_loopback, 0); | ||
| 162 | CHECK(receiver != -1); | ||
| 163 | sender = socket_udp_bind(ip_v4_loopback, 0); | ||
| 164 | CHECK(sender != -1); | ||
| 165 | bound_address(receiver, receiver_ip, &receiver_port); | ||
| 166 | bound_address(sender, sender_ip, &sender_port); | ||
| 167 | CHECK_INT(ip_is_v4mapped(sender_ip), 1); | ||
| 168 | |||
| 169 | CHECK_INT(socket_send(sender, "v4", 2, receiver_ip, receiver_port), 2); | ||
| 170 | CHECK_INT(wait_for(receiver, POLLIN), 1); | ||
| 171 | CHECK_INT(socket_recv(receiver, buf, sizeof(buf), ip, &port), 2); | ||
| 172 | CHECK_INT(ip_is_v4mapped(ip), 1); | ||
| 173 | CHECK_MEM(ip, sender_ip, 16); | ||
| 174 | CHECK_INT(port, sender_port); | ||
| 175 | close(sender); | ||
| 176 | close(receiver); | ||
| 177 | } | ||
| 178 | |||
| 179 | /* ------------------------------------------------------------------- tcp */ | ||
| 180 | |||
| 181 | static void case_tcp_roundtrip(void) { | ||
| 182 | char ip[16], listener_ip[16], client_ip[16]; | ||
| 183 | uint16_t port = 0, listener_port = 0, client_port = 0; | ||
| 184 | int listener, client, accepted; | ||
| 185 | |||
| 186 | test_case("a connection is accepted and carries the caller's address"); | ||
| 187 | listener = socket_tcp_listen(ip_loopback, 0); | ||
| 188 | CHECK(listener != -1); | ||
| 189 | bound_address(listener, listener_ip, &listener_port); | ||
| 190 | CHECK(listener_port != 0); | ||
| 191 | |||
| 192 | client = socket_tcp_connect(ip_loopback, 0, listener_ip, listener_port); | ||
| 193 | CHECK(client != -1); | ||
| 194 | CHECK_INT(wait_for(client, POLLOUT), 1); | ||
| 195 | CHECK_INT(socket_is_connected(client), 1); | ||
| 196 | bound_address(client, client_ip, &client_port); | ||
| 197 | |||
| 198 | CHECK_INT(wait_for(listener, POLLIN), 1); | ||
| 199 | accepted = socket_accept(listener, ip, &port); | ||
| 200 | CHECK(accepted != -1); | ||
| 201 | CHECK_MEM(ip, client_ip, 16); | ||
| 202 | CHECK_INT(port, client_port); | ||
| 203 | |||
| 204 | test_case("the accepted socket is handed over non blocking"); | ||
| 205 | CHECK_INT(is_nonblocking(accepted), 1); | ||
| 206 | |||
| 207 | close(accepted); | ||
| 208 | close(client); | ||
| 209 | close(listener); | ||
| 210 | } | ||
| 211 | |||
| 212 | static void case_connect_refused(void) { | ||
| 213 | char listener_ip[16]; | ||
| 214 | int listener, client; | ||
| 215 | uint16_t port; | ||
| 216 | |||
| 217 | test_case("a refused connection is reported by socket_is_connected"); | ||
| 218 | /* Take a port, then drop it, so nothing is listening on it any more */ | ||
| 219 | listener = socket_tcp_listen(ip_loopback, 0); | ||
| 220 | CHECK(listener != -1); | ||
| 221 | bound_address(listener, listener_ip, &port); | ||
| 222 | close(listener); | ||
| 223 | |||
| 224 | client = socket_tcp_connect(ip_loopback, 0, listener_ip, port); | ||
| 225 | CHECK(client != -1); | ||
| 226 | CHECK_INT(wait_for(client, POLLOUT), 1); | ||
| 227 | CHECK_INT(socket_is_connected(client), 0); | ||
| 228 | CHECK_INT(errno, ECONNREFUSED); | ||
| 229 | close(client); | ||
| 230 | } | ||
| 231 | |||
| 232 | /* --------------------------------------------------------- failed binds */ | ||
| 233 | |||
| 234 | /* The lowest free descriptor is handed out first, so a number that stays put | ||
| 235 | across a failing call shows the call did not keep a socket behind. */ | ||
| 236 | static int next_descriptor(void) { | ||
| 237 | int fd = dup(0); | ||
| 238 | |||
| 239 | if (fd != -1) | ||
| 240 | close(fd); | ||
| 241 | return fd; | ||
| 242 | } | ||
| 243 | |||
| 244 | static void case_bind_failure(void) { | ||
| 245 | int before; | ||
| 246 | |||
| 247 | test_case("binding an address no interface carries fails"); | ||
| 248 | before = next_descriptor(); | ||
| 249 | CHECK(before != -1); | ||
| 250 | CHECK_INT(socket_tcp_listen(ip_unassigned, 0), -1); | ||
| 251 | CHECK_INT(socket_udp_bind(ip_unassigned, 0), -1); | ||
| 252 | |||
| 253 | test_case("a failed bind leaves no socket behind"); | ||
| 254 | CHECK_INT(next_descriptor(), before); | ||
| 255 | } | ||
| 256 | |||
| 257 | #ifdef WANT_SYNC_LIVE | ||
| 258 | /* Reading an IPv4 multicast option back: Linux answers with an int, the BSDs | ||
| 259 | with a single byte, so ask how much was written. */ | ||
| 260 | static int mcast_option(int s, int option) { | ||
| 261 | int value = 0; | ||
| 262 | socklen_t len = sizeof(value); | ||
| 263 | |||
| 264 | if (getsockopt(s, IPPROTO_IP, option, &value, &len) == -1) | ||
| 265 | return -1; | ||
| 266 | if (len == 1) | ||
| 267 | return *(unsigned char *)&value; | ||
| 268 | return value; | ||
| 269 | } | ||
| 270 | |||
| 271 | static void case_mcast_sender(void) { | ||
| 272 | int s; | ||
| 273 | |||
| 274 | test_case("the sending socket keeps its traffic on the local network"); | ||
| 275 | s = socket_mcast_bind(ip_v4_loopback, 0, 0); | ||
| 276 | CHECK(s != -1); | ||
| 277 | CHECK_INT(mcast_option(s, IP_MULTICAST_TTL), 1); | ||
| 278 | |||
| 279 | test_case("and does not hear itself unless it is asked to"); | ||
| 280 | CHECK_INT(mcast_option(s, IP_MULTICAST_LOOP), 0); | ||
| 281 | |||
| 282 | test_case("whoever sends from it is serving clients too, so it cannot block"); | ||
| 283 | CHECK_INT(is_nonblocking(s), 1); | ||
| 284 | close(s); | ||
| 285 | |||
| 286 | test_case("the proxy asks to hear itself and gets it"); | ||
| 287 | s = socket_mcast_bind(ip_v4_loopback, 0, 1); | ||
| 288 | CHECK(s != -1); | ||
| 289 | CHECK_INT(mcast_option(s, IP_MULTICAST_LOOP), 1); | ||
| 290 | close(s); | ||
| 291 | } | ||
| 292 | #endif | ||
| 293 | |||
| 294 | void test_socket(void) { | ||
| 295 | case_socket_options(); | ||
| 296 | #ifdef SO_REUSEPORT | ||
| 297 | case_reuseport_is_opt_in(); | ||
| 298 | #endif | ||
| 299 | case_udp_roundtrip(); | ||
| 300 | case_udp_v4mapped(); | ||
| 301 | case_tcp_roundtrip(); | ||
| 302 | case_connect_refused(); | ||
| 303 | case_bind_failure(); | ||
| 304 | #ifdef WANT_SYNC_LIVE | ||
| 305 | case_mcast_sender(); | ||
| 306 | #endif | ||
| 307 | } | ||
diff --git a/tests/test.h b/tests/test.h index 7449b73..d79c4d2 100644 --- a/tests/test.h +++ b/tests/test.h | |||
| @@ -85,5 +85,6 @@ void test_accesslist(void); | |||
| 85 | void test_scan(void); | 85 | void test_scan(void); |
| 86 | void test_buf(void); | 86 | void test_buf(void); |
| 87 | void test_ip(void); | 87 | void test_ip(void); |
| 88 | void test_socket(void); | ||
| 88 | 89 | ||
| 89 | #endif | 90 | #endif |
