diff options
| -rw-r--r-- | DESIGN | 39 | ||||
| -rw-r--r-- | Makefile | 21 | ||||
| -rw-r--r-- | Mk/proxy.mk | 2 | ||||
| -rw-r--r-- | Mk/tests.mk | 23 | ||||
| -rw-r--r-- | README_v6 | 1 | ||||
| -rw-r--r-- | opentracker.conf.sample | 6 | ||||
| -rw-r--r-- | ot_clean.h | 19 | ||||
| -rw-r--r-- | src/opentracker.c (renamed from opentracker.c) | 2 | ||||
| -rw-r--r-- | src/ot_accesslist.c (renamed from ot_accesslist.c) | 0 | ||||
| -rw-r--r-- | src/ot_accesslist.h (renamed from ot_accesslist.h) | 0 | ||||
| -rw-r--r-- | src/ot_batch.c (renamed from ot_batch.c) | 0 | ||||
| -rw-r--r-- | src/ot_batch.h (renamed from ot_batch.h) | 0 | ||||
| -rw-r--r-- | src/ot_buf.c (renamed from ot_buf.c) | 0 | ||||
| -rw-r--r-- | src/ot_buf.h (renamed from ot_buf.h) | 0 | ||||
| -rw-r--r-- | src/ot_clean.c (renamed from ot_clean.c) | 38 | ||||
| -rw-r--r-- | src/ot_clean.h | 28 | ||||
| -rw-r--r-- | src/ot_config.c (renamed from ot_config.c) | 0 | ||||
| -rw-r--r-- | src/ot_config.h (renamed from ot_config.h) | 0 | ||||
| -rw-r--r-- | src/ot_event.c (renamed from ot_event.c) | 0 | ||||
| -rw-r--r-- | src/ot_event.h (renamed from ot_event.h) | 0 | ||||
| -rw-r--r-- | src/ot_fdstate.c (renamed from ot_fdstate.c) | 0 | ||||
| -rw-r--r-- | src/ot_fdstate.h (renamed from ot_fdstate.h) | 0 | ||||
| -rw-r--r-- | src/ot_fmt.c (renamed from ot_fmt.c) | 0 | ||||
| -rw-r--r-- | src/ot_fmt.h (renamed from ot_fmt.h) | 0 | ||||
| -rw-r--r-- | src/ot_fullscrape.c (renamed from ot_fullscrape.c) | 0 | ||||
| -rw-r--r-- | src/ot_fullscrape.h (renamed from ot_fullscrape.h) | 0 | ||||
| -rw-r--r-- | src/ot_hex.c (renamed from ot_hex.c) | 0 | ||||
| -rw-r--r-- | src/ot_hex.h (renamed from ot_hex.h) | 0 | ||||
| -rw-r--r-- | src/ot_http.c (renamed from ot_http.c) | 0 | ||||
| -rw-r--r-- | src/ot_http.h (renamed from ot_http.h) | 0 | ||||
| -rw-r--r-- | src/ot_iovec.c (renamed from ot_iovec.c) | 0 | ||||
| -rw-r--r-- | src/ot_iovec.h (renamed from ot_iovec.h) | 0 | ||||
| -rw-r--r-- | src/ot_ip.c (renamed from ot_ip.c) | 0 | ||||
| -rw-r--r-- | src/ot_ip.h (renamed from ot_ip.h) | 0 | ||||
| -rw-r--r-- | src/ot_livesync.c (renamed from ot_livesync.c) | 32 | ||||
| -rw-r--r-- | src/ot_livesync.h (renamed from ot_livesync.h) | 3 | ||||
| -rw-r--r-- | src/ot_mutex.c (renamed from ot_mutex.c) | 0 | ||||
| -rw-r--r-- | src/ot_mutex.h (renamed from ot_mutex.h) | 0 | ||||
| -rw-r--r-- | src/ot_random.c (renamed from ot_random.c) | 0 | ||||
| -rw-r--r-- | src/ot_random.h (renamed from ot_random.h) | 0 | ||||
| -rw-r--r-- | src/ot_rijndael.c (renamed from ot_rijndael.c) | 0 | ||||
| -rw-r--r-- | src/ot_rijndael.h (renamed from ot_rijndael.h) | 0 | ||||
| -rw-r--r-- | src/ot_scan.c (renamed from ot_scan.c) | 0 | ||||
| -rw-r--r-- | src/ot_scan.h (renamed from ot_scan.h) | 0 | ||||
| -rw-r--r-- | src/ot_socket.c (renamed from ot_socket.c) | 0 | ||||
| -rw-r--r-- | src/ot_socket.h (renamed from ot_socket.h) | 0 | ||||
| -rw-r--r-- | src/ot_stats.c (renamed from ot_stats.c) | 0 | ||||
| -rw-r--r-- | src/ot_stats.h (renamed from ot_stats.h) | 0 | ||||
| -rw-r--r-- | src/ot_tcp.c (renamed from ot_tcp.c) | 0 | ||||
| -rw-r--r-- | src/ot_tcp.h (renamed from ot_tcp.h) | 0 | ||||
| -rw-r--r-- | src/ot_udp.c (renamed from ot_udp.c) | 0 | ||||
| -rw-r--r-- | src/ot_udp.h (renamed from ot_udp.h) | 0 | ||||
| -rw-r--r-- | src/ot_urlencoded.c (renamed from ot_urlencoded.c) | 0 | ||||
| -rw-r--r-- | src/ot_urlencoded.h (renamed from ot_urlencoded.h) | 0 | ||||
| -rw-r--r-- | src/ot_vector.c (renamed from ot_vector.c) | 0 | ||||
| -rw-r--r-- | src/ot_vector.h (renamed from ot_vector.h) | 0 | ||||
| -rw-r--r-- | src/ot_worker.c (renamed from ot_worker.c) | 2 | ||||
| -rw-r--r-- | src/ot_worker.h (renamed from ot_worker.h) | 0 | ||||
| -rw-r--r-- | src/ot_workqueue.c (renamed from ot_workqueue.c) | 0 | ||||
| -rw-r--r-- | src/ot_workqueue.h (renamed from ot_workqueue.h) | 0 | ||||
| -rw-r--r-- | src/proxy.c (renamed from proxy.c) | 0 | ||||
| -rw-r--r-- | src/trackerlogic.c (renamed from trackerlogic.c) | 6 | ||||
| -rw-r--r-- | src/trackerlogic.h (renamed from trackerlogic.h) | 7 | ||||
| -rw-r--r-- | tests/integration/harness.py | 34 | ||||
| -rw-r--r-- | tests/integration/test_livesync.py | 166 | ||||
| -rw-r--r-- | tests/sync_daemon.pl (renamed from sync_daemon.pl) | 0 | ||||
| -rw-r--r-- | tests/t_mutex.c | 2 | ||||
| -rw-r--r-- | tests/t_trackerlogic.c | 2 |
68 files changed, 365 insertions, 68 deletions
| @@ -16,7 +16,7 @@ A connection carries one request and closes. Keep-alive works and is rarely | |||
| 16 | asked for. | 16 | asked for. |
| 17 | 17 | ||
| 18 | Statistics are approximate on purpose. Counters are per thread and summed | 18 | Statistics are approximate on purpose. Counters are per thread and summed |
| 19 | when read, so a /stats read can under-report once. Nothing drifts. | 19 | when read, so a /stats read can under-report once. |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | Decisions | 22 | Decisions |
| @@ -60,9 +60,44 @@ connections, the filter serves more requests than no filter, not fewer, so it | |||
| 60 | is not the denial of service vector that FreeBSD-SA-02:26 once described. | 60 | is not the denial of service vector that FreeBSD-SA-02:26 once described. |
| 61 | 61 | ||
| 62 | 62 | ||
| 63 | The torrent table is split into 2^OT_BUCKET_COUNT_BITS buckets, 1024 by | ||
| 64 | default, set from the Makefile. Inserting a torrent opens a slot in a sorted | ||
| 65 | vector, so the bytes moved grow with the bucket's occupancy. Insert cost per | ||
| 66 | torrent, Linux: | ||
| 67 | |||
| 68 | 2^10 2^12 2^14 2^16 | ||
| 69 | 200k 466 ns 439 ns | ||
| 70 | 1M 834 ns 579 ns 529 ns | ||
| 71 | 4M 2348 ns 1163 ns 770 ns 674 ns | ||
| 72 | |||
| 73 | Re-announcing an existing torrent moves by under ten per cent over the same | ||
| 74 | range, so the cost is paid while the torrent population is built and not in | ||
| 75 | steady state. Below a few hundred thousand torrents there is nothing to win. | ||
| 76 | 2^14 captures most of the gain for two per cent more resident memory. | ||
| 77 | |||
| 78 | The cleaner's wake rate does not follow the bucket count. A cap of ten wakes | ||
| 79 | a second sets the sleep, and a wake cleans as many buckets as it must to | ||
| 80 | finish a sweep in OT_CLEAN_INTERVAL_MINUTES. At the default bucket count that | ||
| 81 | is one bucket every 117 ms. | ||
| 82 | |||
| 83 | |||
| 63 | Paths not taken | 84 | Paths not taken |
| 64 | --------------- | 85 | --------------- |
| 65 | 86 | ||
| 87 | A keyed hash for the bucket index. Info hashes are SHA-1 output and already | ||
| 88 | uniform, so it changes no distribution. It would buy resistance to deliberate | ||
| 89 | bucket flooding and cost the ordering a full scrape depends on: buckets are | ||
| 90 | ordered by hash prefix and sorted within, so walking them emits the sorted | ||
| 91 | dictionary bencode wants, with no sort and no copy. | ||
| 92 | |||
| 93 | Cache line padding for the per-bucket locks and vector headers. The | ||
| 94 | contention it was meant to remove is not there. On glibc, where a 48-byte | ||
| 95 | mutex straddles a line, padding gains 3 to 8 per cent, but gains as much at | ||
| 96 | one thread where no false sharing can exist, and scaling from one to eight | ||
| 97 | threads is identical either way. On FreeBSD, where eight 8-byte mutexes share | ||
| 98 | a line and the risk should be highest, padding is 15 per cent slower at one | ||
| 99 | thread and neutral to 6 per cent slower at four and eight. | ||
| 100 | |||
| 66 | accf_http, the HTTP-aware accept filter. It duplicates a parser the tracker | 101 | accf_http, the HTTP-aware accept filter. It duplicates a parser the tracker |
| 67 | has anyway, puts more kernel code in the path, and holds a connection that | 102 | has anyway, puts more kernel code in the path, and holds a connection that |
| 68 | sends "GET /" and stops, which accf_data hands straight over. | 103 | sends "GET /" and stops, which accf_data hands straight over. |
| @@ -79,8 +114,6 @@ A directory for object files. bmake has no pattern rules and the Makefile | |||
| 79 | builds under FreeBSD's make today. Building each binary in one invocation | 114 | builds under FreeBSD's make today. Building each binary in one invocation |
| 80 | clears the objects out of the tree without giving that up. | 115 | clears the objects out of the tree without giving that up. |
| 81 | 116 | ||
| 82 | A src/ directory. 52 files sharing an ot_ prefix are a module list rather | ||
| 83 | than clutter, and build output was most of what made the tree look crowded. | ||
| 84 | 117 | ||
| 85 | 118 | ||
| 86 | Platform differences that cost us code | 119 | Platform differences that cost us code |
| @@ -1,5 +1,6 @@ | |||
| 1 | PREFIX?=.. | 1 | PREFIX?=/usr/local |
| 2 | BINDIR?=$(PREFIX)/bin | 2 | BINDIR?=$(PREFIX)/bin |
| 3 | MANDIR?=$(PREFIX)/share/man | ||
| 3 | STRIP?=strip | 4 | STRIP?=strip |
| 4 | 5 | ||
| 5 | #FEATURES+=-DWANT_V4_ONLY | 6 | #FEATURES+=-DWANT_V4_ONLY |
| @@ -19,6 +20,12 @@ STRIP?=strip | |||
| 19 | #FEATURES+=-DWANT_DEV_RANDOM | 20 | #FEATURES+=-DWANT_DEV_RANDOM |
| 20 | FEATURES+=-DWANT_FULLSCRAPE | 21 | FEATURES+=-DWANT_FULLSCRAPE |
| 21 | 22 | ||
| 23 | # Buckets the torrent table is split into, as a power of two, 8 to 16. More | ||
| 24 | # buckets make inserting a new torrent cheaper and cost memory, which is worth | ||
| 25 | # it for a tracker carrying millions of torrents and not for one carrying | ||
| 26 | # thousands. DESIGN has the measurements. | ||
| 27 | FEATURES+=-DOT_BUCKET_COUNT_BITS=10 | ||
| 28 | |||
| 22 | #FEATURES+=-D_DEBUG_HTTPERROR | 29 | #FEATURES+=-D_DEBUG_HTTPERROR |
| 23 | #FEATURES+=-D_DEBUG_RANDOMTORRENTS | 30 | #FEATURES+=-D_DEBUG_RANDOMTORRENTS |
| 24 | 31 | ||
| @@ -33,7 +40,6 @@ include Mk/gzip.mk | |||
| 33 | 40 | ||
| 34 | CFLAGS?=-O3 | 41 | CFLAGS?=-O3 |
| 35 | 42 | ||
| 36 | # What the build requires, whatever you do to those. | ||
| 37 | OT_CFLAGS+=-Wall -Wextra -Wwrite-strings -pipe -pthread | 43 | OT_CFLAGS+=-Wall -Wextra -Wwrite-strings -pipe -pthread |
| 38 | OT_LDFLAGS+=-pthread | 44 | OT_LDFLAGS+=-pthread |
| 39 | 45 | ||
| @@ -43,8 +49,8 @@ COMPILE=$(CPPFLAGS) $(OT_CFLAGS) $(FEATURES) | |||
| 43 | LINK=$(LDFLAGS) $(OT_LDFLAGS) $(LDLIBS) $(OT_LDLIBS) | 49 | LINK=$(LDFLAGS) $(OT_LDFLAGS) $(LDLIBS) $(OT_LDLIBS) |
| 44 | 50 | ||
| 45 | BINARY=opentracker | 51 | BINARY=opentracker |
| 46 | HEADERS=trackerlogic.h ot_urlencoded.h ot_batch.h ot_buf.h ot_event.h ot_fdstate.h ot_fmt.h ot_hex.h ot_ip.h ot_config.h ot_scan.h ot_socket.h ot_tcp.h ot_worker.h ot_workqueue.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 | 52 | HEADERS=src/trackerlogic.h src/ot_urlencoded.h src/ot_batch.h src/ot_buf.h src/ot_event.h src/ot_fdstate.h src/ot_fmt.h src/ot_hex.h src/ot_ip.h src/ot_config.h src/ot_scan.h src/ot_socket.h src/ot_tcp.h src/ot_worker.h src/ot_workqueue.h src/ot_mutex.h src/ot_random.h src/ot_stats.h src/ot_vector.h src/ot_clean.h src/ot_udp.h src/ot_iovec.h src/ot_fullscrape.h src/ot_accesslist.h src/ot_http.h src/ot_livesync.h src/ot_rijndael.h |
| 47 | SOURCES=opentracker.c trackerlogic.c ot_urlencoded.c ot_batch.c ot_buf.c ot_event.c ot_fdstate.c ot_fmt.c ot_hex.c ot_ip.c ot_config.c ot_scan.c ot_socket.c ot_tcp.c ot_worker.c ot_workqueue.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 | 53 | SOURCES=src/opentracker.c src/trackerlogic.c src/ot_urlencoded.c src/ot_batch.c src/ot_buf.c src/ot_event.c src/ot_fdstate.c src/ot_fmt.c src/ot_hex.c src/ot_ip.c src/ot_config.c src/ot_scan.c src/ot_socket.c src/ot_tcp.c src/ot_worker.c src/ot_workqueue.c src/ot_mutex.c src/ot_random.c src/ot_stats.c src/ot_vector.c src/ot_clean.c src/ot_udp.c src/ot_iovec.c src/ot_fullscrape.c src/ot_accesslist.c src/ot_http.c src/ot_livesync.c src/ot_rijndael.c |
| 48 | BINARIES=$(BINARY) $(BINARY).debug | 54 | BINARIES=$(BINARY) $(BINARY).debug |
| 49 | 55 | ||
| 50 | # Everything is built in one go from sources, so there are no object files to | 56 | # Everything is built in one go from sources, so there are no object files to |
| @@ -67,10 +73,13 @@ $(BUILDSTAMP): FORCE | |||
| 67 | @echo "$(CFLAGS) $(COMPILE) $(LINK)" | cmp -s - $@ 2>/dev/null || echo "$(CFLAGS) $(COMPILE) $(LINK)" > $@ | 73 | @echo "$(CFLAGS) $(COMPILE) $(LINK)" | cmp -s - $@ 2>/dev/null || echo "$(CFLAGS) $(COMPILE) $(LINK)" > $@ |
| 68 | 74 | ||
| 69 | clean: | 75 | clean: |
| 70 | rm -rf $(BINARIES) $(BINARIES:=.dSYM) $(BUILDSTAMP) *.o *~ | 76 | rm -rf $(BINARIES) $(BINARIES:=.dSYM) $(BUILDSTAMP) *.o *~ src/*.o src/*~ |
| 71 | 77 | ||
| 72 | install: | 78 | install: $(BINARY) |
| 79 | install -d $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 $(DESTDIR)$(MANDIR)/man5 | ||
| 73 | install -m 755 $(BINARY) $(DESTDIR)$(BINDIR) | 80 | install -m 755 $(BINARY) $(DESTDIR)$(BINDIR) |
| 81 | install -m 644 man1/opentracker.1 $(DESTDIR)$(MANDIR)/man1 | ||
| 82 | install -m 644 man5/opentracker.conf.5 $(DESTDIR)$(MANDIR)/man5 | ||
| 74 | 83 | ||
| 75 | FORCE: | 84 | FORCE: |
| 76 | 85 | ||
diff --git a/Mk/proxy.mk b/Mk/proxy.mk index 2e876e9..64d18dc 100644 --- a/Mk/proxy.mk +++ b/Mk/proxy.mk | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | # CFLAGS_libowfat=-I$(LIBOWFAT_HEADERS) | 7 | # CFLAGS_libowfat=-I$(LIBOWFAT_HEADERS) |
| 8 | # LDFLAGS_libowfat=-L$(LIBOWFAT_LIBRARY) -lowfat | 8 | # LDFLAGS_libowfat=-L$(LIBOWFAT_LIBRARY) -lowfat |
| 9 | # | 9 | # |
| 10 | # SOURCES_proxy=proxy.c ot_batch.c ot_fdstate.c ot_vector.c ot_mutex.c ot_random.c ot_scan.c ot_ip.c ot_socket.c | 10 | # SOURCES_proxy=src/proxy.c src/ot_batch.c src/ot_fdstate.c src/ot_vector.c src/ot_mutex.c src/ot_random.c src/ot_scan.c src/ot_ip.c src/ot_socket.c |
| 11 | # CFLAGS_proxy=$(CFLAGS_production) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE | 11 | # CFLAGS_proxy=$(CFLAGS_production) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE |
| 12 | # CFLAGS_proxy_debug=$(CFLAGS_debug) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE | 12 | # CFLAGS_proxy_debug=$(CFLAGS_debug) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE |
| 13 | # | 13 | # |
diff --git a/Mk/tests.mk b/Mk/tests.mk index 8e63839..2efdd72 100644 --- a/Mk/tests.mk +++ b/Mk/tests.mk | |||
| @@ -5,13 +5,13 @@ BUILDDEPS+=Mk/tests.mk | |||
| 5 | # the few symbols those modules reference but the tests never reach. | 5 | # the few symbols those modules reference but the tests never reach. |
| 6 | TESTBIN=tests/runner | 6 | TESTBIN=tests/runner |
| 7 | TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_urlencoded.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 tests/t_mutex.c tests/t_trackerlogic.c tests/t_workqueue.c tests/t_batch.c tests/t_fdstate.c tests/t_event.c tests/t_fmt.c | 7 | TEST_SOURCES=tests/runner.c tests/test.c tests/stubs.c tests/t_urlencoded.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 tests/t_mutex.c tests/t_trackerlogic.c tests/t_workqueue.c tests/t_batch.c tests/t_fdstate.c tests/t_event.c tests/t_fmt.c |
| 8 | TEST_UNITS=ot_urlencoded.c ot_fmt.c ot_event.c ot_batch.c ot_fdstate.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 ot_mutex.c ot_workqueue.c trackerlogic.c | 8 | TEST_UNITS=src/ot_urlencoded.c src/ot_fmt.c src/ot_event.c src/ot_batch.c src/ot_fdstate.c src/ot_buf.c src/ot_ip.c src/ot_socket.c src/ot_iovec.c src/ot_vector.c src/ot_random.c src/ot_hex.c src/ot_scan.c src/ot_accesslist.c src/ot_mutex.c src/ot_workqueue.c src/trackerlogic.c |
| 9 | TEST_HEADERS=tests/test.h $(HEADERS) | 9 | TEST_HEADERS=tests/test.h $(HEADERS) |
| 10 | 10 | ||
| 11 | # A test binary is not a production binary, so it is built with the features | 11 | # A test binary is not a production binary, so it is built with the features |
| 12 | # the tests need to reach. | 12 | # the tests need to reach. |
| 13 | FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE | 13 | FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE |
| 14 | CFLAGS_test=-I. -g -O1 $(CPPFLAGS) $(OT_CFLAGS) $(FEATURES_test) | 14 | CFLAGS_test=-Isrc -g -O1 $(CPPFLAGS) $(OT_CFLAGS) $(FEATURES_test) |
| 15 | 15 | ||
| 16 | # clang over $(CC) because the two toolchains do not check the same things. | 16 | # clang over $(CC) because the two toolchains do not check the same things. |
| 17 | CC_sanitize?=clang | 17 | CC_sanitize?=clang |
| @@ -29,7 +29,13 @@ LDFLAGS_integration=$(LINK) -fsanitize=address,undefined | |||
| 29 | CFLAGS_tsan=$(OPTS_debug) $(CPPFLAGS) $(OT_CFLAGS) $(FEATURES_integration) -fsanitize=thread -fno-omit-frame-pointer | 29 | CFLAGS_tsan=$(OPTS_debug) $(CPPFLAGS) $(OT_CFLAGS) $(FEATURES_integration) -fsanitize=thread -fno-omit-frame-pointer |
| 30 | LDFLAGS_tsan=$(LINK) -fsanitize=thread | 30 | LDFLAGS_tsan=$(LINK) -fsanitize=thread |
| 31 | 31 | ||
| 32 | BINARIES+=$(TESTBIN) $(TESTBIN).poll $(TESTBIN).sanitize opentracker.integration opentracker.tsan | 32 | # Live sync is a compile time feature, so reaching it from a black box test |
| 33 | # needs a binary of its own. tests/integration/test_livesync.py skips itself | ||
| 34 | # against a build without it, which is what -v is for. | ||
| 35 | FEATURES_livesync=$(FEATURES_integration) -DWANT_SYNC_LIVE | ||
| 36 | CFLAGS_livesync=$(OPTS_debug) $(CPPFLAGS) $(OT_CFLAGS) $(FEATURES_livesync) -fsanitize=address,undefined -fno-omit-frame-pointer | ||
| 37 | |||
| 38 | BINARIES+=$(TESTBIN) $(TESTBIN).poll $(TESTBIN).sanitize opentracker.integration opentracker.tsan opentracker.livesync | ||
| 33 | 39 | ||
| 34 | $(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) $(BUILDDEPS) | 40 | $(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) $(BUILDDEPS) |
| 35 | $(CC) -o $@ $(CFLAGS_test) $(TEST_SOURCES) $(TEST_UNITS) | 41 | $(CC) -o $@ $(CFLAGS_test) $(TEST_SOURCES) $(TEST_UNITS) |
| @@ -46,6 +52,9 @@ opentracker.integration: $(SOURCES) $(HEADERS) $(BUILDDEPS) | |||
| 46 | opentracker.tsan: $(SOURCES) $(HEADERS) $(BUILDDEPS) | 52 | opentracker.tsan: $(SOURCES) $(HEADERS) $(BUILDDEPS) |
| 47 | $(CC) -o $@ $(CFLAGS_tsan) $(SOURCES) $(LDFLAGS_tsan) | 53 | $(CC) -o $@ $(CFLAGS_tsan) $(SOURCES) $(LDFLAGS_tsan) |
| 48 | 54 | ||
| 55 | opentracker.livesync: $(SOURCES) $(HEADERS) $(BUILDDEPS) | ||
| 56 | $(CC) -o $@ $(CFLAGS_livesync) $(SOURCES) $(LDFLAGS_integration) | ||
| 57 | |||
| 49 | check: $(TESTBIN) $(BINARY) | 58 | check: $(TESTBIN) $(BINARY) |
| 50 | ./$(TESTBIN) | 59 | ./$(TESTBIN) |
| 51 | 60 | ||
| @@ -61,12 +70,18 @@ check-integration: opentracker.integration | |||
| 61 | check-tsan: opentracker.tsan | 70 | check-tsan: opentracker.tsan |
| 62 | OPENTRACKER=./opentracker.tsan $(PYTHON) -m unittest discover -s tests/integration | 71 | OPENTRACKER=./opentracker.tsan $(PYTHON) -m unittest discover -s tests/integration |
| 63 | 72 | ||
| 73 | # The whole suite against a build that has live sync, which is also the only | ||
| 74 | # way the live sync tests stop skipping. | ||
| 75 | check-livesync: opentracker.livesync | ||
| 76 | OPENTRACKER=./opentracker.livesync $(PYTHON) -m unittest discover -s tests/integration | ||
| 77 | |||
| 64 | # Cheapest first, so a quick failure comes back quickly. | 78 | # Cheapest first, so a quick failure comes back quickly. |
| 65 | check-all: | 79 | check-all: |
| 66 | $(MAKE) check | 80 | $(MAKE) check |
| 67 | $(MAKE) check-poll | 81 | $(MAKE) check-poll |
| 68 | $(MAKE) check-sanitize | 82 | $(MAKE) check-sanitize |
| 69 | $(MAKE) check-integration | 83 | $(MAKE) check-integration |
| 84 | $(MAKE) check-livesync | ||
| 70 | $(MAKE) check-tsan | 85 | $(MAKE) check-tsan |
| 71 | 86 | ||
| 72 | .PHONY: check check-poll check-sanitize check-integration check-tsan check-all | 87 | .PHONY: check check-poll check-sanitize check-integration check-livesync check-tsan check-all |
diff --git a/README_v6 b/README_v6 deleted file mode 100644 index 7fac79a..0000000 --- a/README_v6 +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | IPv6 is implemented in opentracker now. You can chose whether your tracker runs in v4 or v6 mode in Makefile. YMMV. | ||
diff --git a/opentracker.conf.sample b/opentracker.conf.sample index 491c88a..3cd30dc 100644 --- a/opentracker.conf.sample +++ b/opentracker.conf.sample | |||
| @@ -138,9 +138,11 @@ | |||
| 138 | # livesync.cluster.listen 192.168.0.1:9696 | 138 | # livesync.cluster.listen 192.168.0.1:9696 |
| 139 | # | 139 | # |
| 140 | # Note that two udp sockets will be opened. One on ip address 0.0.0.0 | 140 | # Note that two udp sockets will be opened. One on ip address 0.0.0.0 |
| 141 | # port 9696, that will join the multicast group 224.0.42.23 for incoming | 141 | # port 9696, that will join the multicast group 224.0.23.5 for incoming |
| 142 | # udp packets and one on ip address 192.168.0.1 port 9696 for outgoing | 142 | # udp packets and one on ip address 192.168.0.1 port 9696 for outgoing |
| 143 | # udp packets. | 143 | # udp packets. The group is the same for every opentracker, so a cluster |
| 144 | # is kept to itself by the node_ip list below and by the ttl of 1 that | ||
| 145 | # keeps packets on the local link. | ||
| 144 | # | 146 | # |
| 145 | # As of now one and only one ip address must be given, if opentracker | 147 | # As of now one and only one ip address must be given, if opentracker |
| 146 | # was built with the WANT_SYNC_LIVE feature. | 148 | # was built with the WANT_SYNC_LIVE feature. |
diff --git a/ot_clean.h b/ot_clean.h deleted file mode 100644 index e069ee0..0000000 --- a/ot_clean.h +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
| 3 | |||
| 4 | #ifndef OT_CLEAN_H__ | ||
| 5 | #define OT_CLEAN_H__ | ||
| 6 | |||
| 7 | #include "trackerlogic.h" | ||
| 8 | |||
| 9 | /* The amount of time a clean cycle should take */ | ||
| 10 | #define OT_CLEAN_INTERVAL_MINUTES 2 | ||
| 11 | |||
| 12 | /* So after each bucket wait 1 / OT_BUCKET_COUNT intervals */ | ||
| 13 | #define OT_CLEAN_SLEEP (((OT_CLEAN_INTERVAL_MINUTES) * 60 * 1000000) / (OT_BUCKET_COUNT)) | ||
| 14 | |||
| 15 | void clean_init(void); | ||
| 16 | void clean_deinit(void); | ||
| 17 | int clean_single_torrent(ot_torrent *torrent); | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/opentracker.c b/src/opentracker.c index 14b817e..60a6d8c 100644 --- a/opentracker.c +++ b/src/opentracker.c | |||
| @@ -109,7 +109,7 @@ static void *server_mainloop(void *args) { | |||
| 109 | 109 | ||
| 110 | (void)args; | 110 | (void)args; |
| 111 | 111 | ||
| 112 | if (workstruct_init(&ws) == -1) | 112 | if (workstruct_init(&ws, G_INBUF_SIZE) == -1) |
| 113 | panic("Initializing worker failed"); | 113 | panic("Initializing worker failed"); |
| 114 | 114 | ||
| 115 | while (g_opentracker_running) { | 115 | while (g_opentracker_running) { |
diff --git a/ot_accesslist.c b/src/ot_accesslist.c index 86f9a7d..86f9a7d 100644 --- a/ot_accesslist.c +++ b/src/ot_accesslist.c | |||
diff --git a/ot_accesslist.h b/src/ot_accesslist.h index 68c88dc..68c88dc 100644 --- a/ot_accesslist.h +++ b/src/ot_accesslist.h | |||
diff --git a/ot_batch.c b/src/ot_batch.c index e4dda0b..e4dda0b 100644 --- a/ot_batch.c +++ b/src/ot_batch.c | |||
diff --git a/ot_batch.h b/src/ot_batch.h index 910bea7..910bea7 100644 --- a/ot_batch.h +++ b/src/ot_batch.h | |||
diff --git a/ot_clean.c b/src/ot_clean.c index e1d1971..f181e83 100644 --- a/ot_clean.c +++ b/src/ot_clean.c | |||
| @@ -125,26 +125,34 @@ static void clean_sleep(void) { | |||
| 125 | pthread_mutex_unlock(&g_clean_mutex); | 125 | pthread_mutex_unlock(&g_clean_mutex); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /* Clean up all peers in current bucket, remove timedout pools and | 128 | /* Clean up all peers in one bucket, remove timedout pools and torrents */ |
| 129 | torrents */ | 129 | static void clean_bucket(size_t bucket) { |
| 130 | ot_vector *torrents_list = mutex_bucket_lock((int)bucket); | ||
| 131 | size_t toffs; | ||
| 132 | int delta_torrentcount = 0; | ||
| 133 | |||
| 134 | for (toffs = 0; toffs < torrents_list->size; ++toffs) { | ||
| 135 | ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + toffs; | ||
| 136 | if (clean_single_torrent(torrent)) { | ||
| 137 | vector_remove_torrent(torrents_list, torrent); | ||
| 138 | --delta_torrentcount; | ||
| 139 | --toffs; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | mutex_bucket_unlock((int)bucket, delta_torrentcount); | ||
| 143 | } | ||
| 144 | |||
| 130 | static void *clean_worker(void *args) { | 145 | static void *clean_worker(void *args) { |
| 131 | (void)args; | 146 | (void)args; |
| 132 | while (1) { | 147 | while (1) { |
| 133 | size_t bucket = OT_BUCKET_COUNT; | 148 | size_t bucket = OT_BUCKET_COUNT; |
| 134 | while (bucket--) { | 149 | while (bucket) { |
| 135 | ot_vector *torrents_list = mutex_bucket_lock(bucket); | 150 | size_t todo = bucket < OT_CLEAN_BUCKETS_PER_WAKE ? bucket : OT_CLEAN_BUCKETS_PER_WAKE; |
| 136 | size_t toffs; | 151 | |
| 137 | int delta_torrentcount = 0; | 152 | /* One bucket is locked at a time, however many a wake gets through */ |
| 153 | while (todo--) | ||
| 154 | clean_bucket(--bucket); | ||
| 138 | 155 | ||
| 139 | for (toffs = 0; toffs < torrents_list->size; ++toffs) { | ||
| 140 | ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + toffs; | ||
| 141 | if (clean_single_torrent(torrent)) { | ||
| 142 | vector_remove_torrent(torrents_list, torrent); | ||
| 143 | --delta_torrentcount; | ||
| 144 | --toffs; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | mutex_bucket_unlock(bucket, delta_torrentcount); | ||
| 148 | if (!g_opentracker_running) | 156 | if (!g_opentracker_running) |
| 149 | return NULL; | 157 | return NULL; |
| 150 | clean_sleep(); | 158 | clean_sleep(); |
diff --git a/src/ot_clean.h b/src/ot_clean.h new file mode 100644 index 0000000..0592791 --- /dev/null +++ b/src/ot_clean.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | ||
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. */ | ||
| 3 | |||
| 4 | #ifndef OT_CLEAN_H__ | ||
| 5 | #define OT_CLEAN_H__ | ||
| 6 | |||
| 7 | #include "trackerlogic.h" | ||
| 8 | |||
| 9 | /* The amount of time a clean cycle should take */ | ||
| 10 | #define OT_CLEAN_INTERVAL_MINUTES 2 | ||
| 11 | |||
| 12 | /* How often the cleaner may wake. A full sweep takes OT_CLEAN_INTERVAL_MINUTES. | ||
| 13 | The clean operations per wake is goverend by OT_BUCKET_COUNT_BITS, | ||
| 14 | set by the Makefile. | ||
| 15 | At the default of 1024 buckets this works out at one bucket every | ||
| 16 | 117 ms. */ | ||
| 17 | #define OT_CLEAN_MAX_WAKES_PER_SECOND 10 | ||
| 18 | |||
| 19 | #define OT_CLEAN_WAKE_BUDGET ((OT_CLEAN_INTERVAL_MINUTES) * 60 * (OT_CLEAN_MAX_WAKES_PER_SECOND)) | ||
| 20 | #define OT_CLEAN_BUCKETS_PER_WAKE (((OT_BUCKET_COUNT) + (OT_CLEAN_WAKE_BUDGET) - 1) / (OT_CLEAN_WAKE_BUDGET)) | ||
| 21 | #define OT_CLEAN_WAKES ((OT_BUCKET_COUNT) / (OT_CLEAN_BUCKETS_PER_WAKE)) | ||
| 22 | #define OT_CLEAN_SLEEP (((OT_CLEAN_INTERVAL_MINUTES) * 60 * 1000000) / (OT_CLEAN_WAKES)) | ||
| 23 | |||
| 24 | void clean_init(void); | ||
| 25 | void clean_deinit(void); | ||
| 26 | int clean_single_torrent(ot_torrent *torrent); | ||
| 27 | |||
| 28 | #endif | ||
diff --git a/ot_config.c b/src/ot_config.c index 95136b5..95136b5 100644 --- a/ot_config.c +++ b/src/ot_config.c | |||
diff --git a/ot_config.h b/src/ot_config.h index 79187ee..79187ee 100644 --- a/ot_config.h +++ b/src/ot_config.h | |||
diff --git a/ot_event.c b/src/ot_event.c index 6062f70..6062f70 100644 --- a/ot_event.c +++ b/src/ot_event.c | |||
diff --git a/ot_event.h b/src/ot_event.h index cb84ca8..cb84ca8 100644 --- a/ot_event.h +++ b/src/ot_event.h | |||
diff --git a/ot_fdstate.c b/src/ot_fdstate.c index 8e4bd89..8e4bd89 100644 --- a/ot_fdstate.c +++ b/src/ot_fdstate.c | |||
diff --git a/ot_fdstate.h b/src/ot_fdstate.h index 60fe070..60fe070 100644 --- a/ot_fdstate.h +++ b/src/ot_fdstate.h | |||
diff --git a/ot_fullscrape.c b/src/ot_fullscrape.c index 9afad92..9afad92 100644 --- a/ot_fullscrape.c +++ b/src/ot_fullscrape.c | |||
diff --git a/ot_fullscrape.h b/src/ot_fullscrape.h index 8d11cd3..8d11cd3 100644 --- a/ot_fullscrape.h +++ b/src/ot_fullscrape.h | |||
diff --git a/ot_http.c b/src/ot_http.c index 96b8f4e..96b8f4e 100644 --- a/ot_http.c +++ b/src/ot_http.c | |||
diff --git a/ot_http.h b/src/ot_http.h index fb56c64..fb56c64 100644 --- a/ot_http.h +++ b/src/ot_http.h | |||
diff --git a/ot_iovec.c b/src/ot_iovec.c index 328f160..328f160 100644 --- a/ot_iovec.c +++ b/src/ot_iovec.c | |||
diff --git a/ot_iovec.h b/src/ot_iovec.h index 4a8abbb..4a8abbb 100644 --- a/ot_iovec.h +++ b/src/ot_iovec.h | |||
diff --git a/ot_livesync.c b/src/ot_livesync.c index 083fe1a..11b75d2 100644 --- a/ot_livesync.c +++ b/src/ot_livesync.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | /* System */ | 4 | /* System */ |
| 5 | #include <arpa/inet.h> | 5 | #include <arpa/inet.h> |
| 6 | #include <pthread.h> | 6 | #include <pthread.h> |
| 7 | #include <stdio.h> | ||
| 7 | #include <stdlib.h> | 8 | #include <stdlib.h> |
| 8 | #include <string.h> | 9 | #include <string.h> |
| 9 | #include <sys/socket.h> | 10 | #include <sys/socket.h> |
| @@ -22,6 +23,7 @@ | |||
| 22 | #ifdef WANT_SYNC_LIVE | 23 | #ifdef WANT_SYNC_LIVE |
| 23 | 24 | ||
| 24 | ot_ip6 groupip_1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 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}; |
| 26 | static uint16_t g_port = LIVESYNC_PORT; | ||
| 25 | 27 | ||
| 26 | #define LIVESYNC_INCOMING_BUFFSIZE (256 * 256) | 28 | #define LIVESYNC_INCOMING_BUFFSIZE (256 * 256) |
| 27 | 29 | ||
| @@ -59,7 +61,7 @@ void livesync_init(void) { | |||
| 59 | uint32_t packet_type4 = htonl(OT_SYNC_PEER4); | 61 | uint32_t packet_type4 = htonl(OT_SYNC_PEER4); |
| 60 | 62 | ||
| 61 | if (g_socket_in == -1) | 63 | if (g_socket_in == -1) |
| 62 | exerr("No socket address for live sync specified."); | 64 | return; |
| 63 | 65 | ||
| 64 | /* Prepare outgoing peers buffer */ | 66 | /* Prepare outgoing peers buffer */ |
| 65 | memcpy(g_v6_buf.data, &g_tracker_id, sizeof(g_tracker_id)); | 67 | memcpy(g_v6_buf.data, &g_tracker_id, sizeof(g_tracker_id)); |
| @@ -101,6 +103,8 @@ void livesync_bind_mcast(ot_ip6 ip, uint16_t port) { | |||
| 101 | if (g_socket_in != -1) | 103 | if (g_socket_in != -1) |
| 102 | exerr("Error: Livesync listen ip specified twice."); | 104 | exerr("Error: Livesync listen ip specified twice."); |
| 103 | 105 | ||
| 106 | g_port = port; | ||
| 107 | |||
| 104 | if ((g_socket_in = socket_mcast_join(groupip_1, ip, port)) == -1) | 108 | if ((g_socket_in = socket_mcast_join(groupip_1, ip, port)) == -1) |
| 105 | exerr("Error: Cant bind live sync incoming socket."); | 109 | exerr("Error: Cant bind live sync incoming socket."); |
| 106 | 110 | ||
| @@ -121,7 +125,7 @@ static void livesync_issue_peersync(sync_buffer *buf) { | |||
| 121 | has modified the protected element */ | 125 | has modified the protected element */ |
| 122 | pthread_mutex_unlock(&g_outbuf_mutex); | 126 | pthread_mutex_unlock(&g_outbuf_mutex); |
| 123 | 127 | ||
| 124 | socket_mcast_send(g_socket_out, mycopy, fill, groupip_1, LIVESYNC_PORT); | 128 | socket_mcast_send(g_socket_out, mycopy, fill, groupip_1, g_port); |
| 125 | } | 129 | } |
| 126 | 130 | ||
| 127 | static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) { | 131 | static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) { |
| @@ -159,6 +163,9 @@ static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) | |||
| 159 | stuck when there's not enough traffic to fill udp packets fast | 163 | stuck when there's not enough traffic to fill udp packets fast |
| 160 | enough */ | 164 | enough */ |
| 161 | void livesync_ticker(void) { | 165 | void livesync_ticker(void) { |
| 166 | if (g_socket_out == -1) | ||
| 167 | return; | ||
| 168 | |||
| 162 | /* livesync_issue_peersync sets g_next_packet_time */ | 169 | /* livesync_issue_peersync sets g_next_packet_time */ |
| 163 | pthread_mutex_lock(&g_outbuf_mutex); | 170 | pthread_mutex_lock(&g_outbuf_mutex); |
| 164 | if (time_now_seconds() > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) | 171 | if (time_now_seconds() > g_v6_buf.next_packet_time && g_v6_buf.fill > sizeof(g_tracker_id) + sizeof(uint32_t)) |
| @@ -176,8 +183,14 @@ void livesync_ticker(void) { | |||
| 176 | /* Inform live sync about whats going on. */ | 183 | /* Inform live sync about whats going on. */ |
| 177 | void livesync_tell(struct ot_workstruct *ws) { | 184 | void livesync_tell(struct ot_workstruct *ws) { |
| 178 | size_t peer_size; /* initialized in next line */ | 185 | size_t peer_size; /* initialized in next line */ |
| 179 | ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size); | 186 | ot_peer *peer_src; |
| 180 | sync_buffer *dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf; | 187 | sync_buffer *dest_buf; |
| 188 | |||
| 189 | if (g_socket_out == -1) | ||
| 190 | return; | ||
| 191 | |||
| 192 | peer_src = peer_from_peer6(&ws->peer, &peer_size); | ||
| 193 | dest_buf = peer_size == OT_PEER_SIZE6 ? &g_v6_buf : &g_v4_buf; | ||
| 181 | 194 | ||
| 182 | pthread_mutex_lock(&g_outbuf_mutex); | 195 | pthread_mutex_lock(&g_outbuf_mutex); |
| 183 | 196 | ||
| @@ -200,9 +213,12 @@ static void *livesync_worker(void *args) { | |||
| 200 | 213 | ||
| 201 | (void)args; | 214 | (void)args; |
| 202 | 215 | ||
| 203 | /* Initialize our "thread local storage" */ | 216 | if (workstruct_init(&ws, LIVESYNC_INCOMING_BUFFSIZE) == -1) { |
| 204 | ws.inbuf = ws.request = malloc(LIVESYNC_INCOMING_BUFFSIZE); | 217 | fprintf(stderr, "Warning: live sync could not get its buffers and will not run.\n"); |
| 205 | ws.outbuf = ws.reply = 0; | 218 | atomic_store(&thread_left, 1); |
| 219 | return NULL; | ||
| 220 | } | ||
| 221 | ws.request = ws.inbuf; | ||
| 206 | 222 | ||
| 207 | while (g_opentracker_running) { | 223 | while (g_opentracker_running) { |
| 208 | uint32_t packet_type; | 224 | uint32_t packet_type; |
| @@ -233,7 +249,7 @@ static void *livesync_worker(void *args) { | |||
| 233 | } | 249 | } |
| 234 | } | 250 | } |
| 235 | 251 | ||
| 236 | free(ws.inbuf); | 252 | workstruct_deinit(&ws); |
| 237 | atomic_store(&thread_left, 1); | 253 | atomic_store(&thread_left, 1); |
| 238 | return NULL; | 254 | return NULL; |
| 239 | } | 255 | } |
diff --git a/ot_livesync.h b/src/ot_livesync.h index 4bd3af0..d8d20b3 100644 --- a/ot_livesync.h +++ b/src/ot_livesync.h | |||
| @@ -7,7 +7,8 @@ | |||
| 7 | #include "trackerlogic.h" | 7 | #include "trackerlogic.h" |
| 8 | 8 | ||
| 9 | /* | 9 | /* |
| 10 | Syncing is done as udp packets in the multicast domain 224.0.42.5 port 9696 | 10 | Syncing is done as udp packets in the multicast group 224.0.23.5, on the |
| 11 | port livesync.cluster.listen names, 9696 by default | ||
| 11 | 12 | ||
| 12 | Each tracker should join the multicast group and send its live sync packets | 13 | Each tracker should join the multicast group and send its live sync packets |
| 13 | to that group, using a ttl of 1 | 14 | to that group, using a ttl of 1 |
diff --git a/ot_mutex.c b/src/ot_mutex.c index 884b74c..884b74c 100644 --- a/ot_mutex.c +++ b/src/ot_mutex.c | |||
diff --git a/ot_mutex.h b/src/ot_mutex.h index d7ded92..d7ded92 100644 --- a/ot_mutex.h +++ b/src/ot_mutex.h | |||
diff --git a/ot_random.c b/src/ot_random.c index 43f91bb..43f91bb 100644 --- a/ot_random.c +++ b/src/ot_random.c | |||
diff --git a/ot_random.h b/src/ot_random.h index c2d0387..c2d0387 100644 --- a/ot_random.h +++ b/src/ot_random.h | |||
diff --git a/ot_rijndael.c b/src/ot_rijndael.c index 3f36bde..3f36bde 100644 --- a/ot_rijndael.c +++ b/src/ot_rijndael.c | |||
diff --git a/ot_rijndael.h b/src/ot_rijndael.h index 1235215..1235215 100644 --- a/ot_rijndael.h +++ b/src/ot_rijndael.h | |||
diff --git a/ot_scan.c b/src/ot_scan.c index 3b8e87c..3b8e87c 100644 --- a/ot_scan.c +++ b/src/ot_scan.c | |||
diff --git a/ot_scan.h b/src/ot_scan.h index a79ec13..a79ec13 100644 --- a/ot_scan.h +++ b/src/ot_scan.h | |||
diff --git a/ot_socket.c b/src/ot_socket.c index 79bb01a..79bb01a 100644 --- a/ot_socket.c +++ b/src/ot_socket.c | |||
diff --git a/ot_socket.h b/src/ot_socket.h index 5c1d840..5c1d840 100644 --- a/ot_socket.h +++ b/src/ot_socket.h | |||
diff --git a/ot_stats.c b/src/ot_stats.c index 2d6335b..2d6335b 100644 --- a/ot_stats.c +++ b/src/ot_stats.c | |||
diff --git a/ot_stats.h b/src/ot_stats.h index 45a547e..45a547e 100644 --- a/ot_stats.h +++ b/src/ot_stats.h | |||
diff --git a/ot_urlencoded.c b/src/ot_urlencoded.c index 4109bb5..4109bb5 100644 --- a/ot_urlencoded.c +++ b/src/ot_urlencoded.c | |||
diff --git a/ot_urlencoded.h b/src/ot_urlencoded.h index 9882468..9882468 100644 --- a/ot_urlencoded.h +++ b/src/ot_urlencoded.h | |||
diff --git a/ot_vector.c b/src/ot_vector.c index ab0566c..ab0566c 100644 --- a/ot_vector.c +++ b/src/ot_vector.c | |||
diff --git a/ot_vector.h b/src/ot_vector.h index 8a5ba86..8a5ba86 100644 --- a/ot_vector.h +++ b/src/ot_vector.h | |||
diff --git a/ot_worker.c b/src/ot_worker.c index 432d272..ef50945 100644 --- a/ot_worker.c +++ b/src/ot_worker.c | |||
| @@ -20,7 +20,7 @@ static size_t g_worker_count; | |||
| 20 | static void *worker_trampoline(void *args) { | 20 | static void *worker_trampoline(void *args) { |
| 21 | struct ot_worker *me = args; | 21 | struct ot_worker *me = args; |
| 22 | 22 | ||
| 23 | if (workstruct_init(&me->ws) == -1) | 23 | if (workstruct_init(&me->ws, G_INBUF_SIZE) == -1) |
| 24 | fprintf(stderr, "Warning: a worker could not get its buffers and will not run.\n"); | 24 | fprintf(stderr, "Warning: a worker could not get its buffers and will not run.\n"); |
| 25 | else { | 25 | else { |
| 26 | me->run(me); | 26 | me->run(me); |
diff --git a/ot_worker.h b/src/ot_worker.h index 4954773..4954773 100644 --- a/ot_worker.h +++ b/src/ot_worker.h | |||
diff --git a/ot_workqueue.c b/src/ot_workqueue.c index 56a7cd2..56a7cd2 100644 --- a/ot_workqueue.c +++ b/src/ot_workqueue.c | |||
diff --git a/ot_workqueue.h b/src/ot_workqueue.h index 82ae29b..82ae29b 100644 --- a/ot_workqueue.h +++ b/src/ot_workqueue.h | |||
diff --git a/trackerlogic.c b/src/trackerlogic.c index 9565090..8e30a48 100644 --- a/trackerlogic.c +++ b/src/trackerlogic.c | |||
| @@ -567,9 +567,11 @@ void trackerlogic_init(void) { | |||
| 567 | stats_init(); | 567 | stats_init(); |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | int workstruct_init(struct ot_workstruct *ws) { | 570 | /* Live sync reads whole packets rather than requests and wants a larger |
| 571 | inbuf than the request path does, hence the size. */ | ||
| 572 | int workstruct_init(struct ot_workstruct *ws, size_t inbuf_size) { | ||
| 571 | memset(ws, 0, sizeof(*ws)); | 573 | memset(ws, 0, sizeof(*ws)); |
| 572 | ws->inbuf = malloc(G_INBUF_SIZE); | 574 | ws->inbuf = malloc(inbuf_size); |
| 573 | ws->outbuf = malloc(G_OUTBUF_SIZE); | 575 | ws->outbuf = malloc(G_OUTBUF_SIZE); |
| 574 | #ifdef _DEBUG_HTTPERROR | 576 | #ifdef _DEBUG_HTTPERROR |
| 575 | ws->debugbuf = malloc(G_DEBUGBUF_SIZE); | 577 | ws->debugbuf = malloc(G_DEBUGBUF_SIZE); |
diff --git a/trackerlogic.h b/src/trackerlogic.h index 338e4e6..692b6af 100644 --- a/trackerlogic.h +++ b/src/trackerlogic.h | |||
| @@ -62,7 +62,12 @@ typedef struct { | |||
| 62 | 62 | ||
| 63 | /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs | 63 | /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs |
| 64 | Sort key is, of course, its hash */ | 64 | Sort key is, of course, its hash */ |
| 65 | /* Set from the Makefile, 8 to 16. More buckets means shorter vectors and a | ||
| 66 | cheaper insert, which only pays for a tracker carrying millions of | ||
| 67 | torrents; see DESIGN. */ | ||
| 68 | #ifndef OT_BUCKET_COUNT_BITS | ||
| 65 | #define OT_BUCKET_COUNT_BITS 10 | 69 | #define OT_BUCKET_COUNT_BITS 10 |
| 70 | #endif | ||
| 66 | 71 | ||
| 67 | #define OT_BUCKET_COUNT (1 << OT_BUCKET_COUNT_BITS) | 72 | #define OT_BUCKET_COUNT (1 << OT_BUCKET_COUNT_BITS) |
| 68 | #define OT_BUCKET_COUNT_SHIFT (32 - OT_BUCKET_COUNT_BITS) | 73 | #define OT_BUCKET_COUNT_SHIFT (32 - OT_BUCKET_COUNT_BITS) |
| @@ -237,7 +242,7 @@ struct ot_workstruct { | |||
| 237 | /* Everything a thread that serves requests needs for itself. Set up and torn | 242 | /* Everything a thread that serves requests needs for itself. Set up and torn |
| 238 | down in one place so that a new kind of worker cannot miss a piece. | 243 | down in one place so that a new kind of worker cannot miss a piece. |
| 239 | Returns -1 if the buffers could not be had. */ | 244 | Returns -1 if the buffers could not be had. */ |
| 240 | int workstruct_init(struct ot_workstruct *ws); | 245 | int workstruct_init(struct ot_workstruct *ws, size_t inbuf_size); |
| 241 | void workstruct_deinit(struct ot_workstruct *ws); | 246 | void workstruct_deinit(struct ot_workstruct *ws); |
| 242 | 247 | ||
| 243 | /* | 248 | /* |
diff --git a/tests/integration/harness.py b/tests/integration/harness.py index b98ce83..a9d38ca 100644 --- a/tests/integration/harness.py +++ b/tests/integration/harness.py | |||
| @@ -20,6 +20,9 @@ import urllib.error | |||
| 20 | import urllib.parse | 20 | import urllib.parse |
| 21 | import urllib.request | 21 | import urllib.request |
| 22 | 22 | ||
| 23 | # groupip_1 in src/ot_livesync.c | ||
| 24 | LIVESYNC_GROUP = "224.0.23.5" | ||
| 25 | |||
| 23 | TRACKER = os.environ.get("OPENTRACKER", os.path.join(os.path.dirname(__file__), "..", "..", "opentracker.debug")) | 26 | TRACKER = os.environ.get("OPENTRACKER", os.path.join(os.path.dirname(__file__), "..", "..", "opentracker.debug")) |
| 24 | 27 | ||
| 25 | 28 | ||
| @@ -76,6 +79,9 @@ class Tracker: | |||
| 76 | 79 | ||
| 77 | def __init__(self, extra_config="", files=None): | 80 | def __init__(self, extra_config="", files=None): |
| 78 | self.port = free_port() | 81 | self.port = free_port() |
| 82 | # Only used by a config that asks for live sync, but allocated either | ||
| 83 | # way so {livesync_port} always resolves. | ||
| 84 | self.livesync_port = free_port() | ||
| 79 | self.dir = tempfile.mkdtemp(prefix="ot-integration-") | 85 | self.dir = tempfile.mkdtemp(prefix="ot-integration-") |
| 80 | self.log = None | 86 | self.log = None |
| 81 | self.process = None | 87 | self.process = None |
| @@ -87,7 +93,7 @@ class Tracker: | |||
| 87 | with open(self.config, "w") as handle: | 93 | with open(self.config, "w") as handle: |
| 88 | handle.write("listen.tcp 127.0.0.1:%d\n" % self.port) | 94 | handle.write("listen.tcp 127.0.0.1:%d\n" % self.port) |
| 89 | handle.write("listen.udp 127.0.0.1:%d\n" % self.port) | 95 | handle.write("listen.udp 127.0.0.1:%d\n" % self.port) |
| 90 | handle.write(extra_config.replace("{dir}", self.dir)) | 96 | handle.write(extra_config.replace("{dir}", self.dir).replace("{livesync_port}", str(self.livesync_port))) |
| 91 | self.log = open(os.path.join(self.dir, "tracker.log"), "w+b") | 97 | self.log = open(os.path.join(self.dir, "tracker.log"), "w+b") |
| 92 | # Leak detection is left at the sanitizer's own default, which is on | 98 | # Leak detection is left at the sanitizer's own default, which is on |
| 93 | # where LeakSanitizer exists and off where it does not. Asking for it | 99 | # where LeakSanitizer exists and off where it does not. Asking for it |
| @@ -186,6 +192,32 @@ class Tracker: | |||
| 186 | def torrent_count(self): | 192 | def torrent_count(self): |
| 187 | return int(self.stats("torr").split()[0]) | 193 | return int(self.stats("torr").split()[0]) |
| 188 | 194 | ||
| 195 | def livesync_send(self, payload): | ||
| 196 | """Put a packet on the live sync group. | ||
| 197 | |||
| 198 | It has to go to the group rather than straight at the port: the | ||
| 199 | tracker binds two sockets there, the reader on the wildcard address | ||
| 200 | and the writer on the configured one, and the kernel gives a unicast | ||
| 201 | datagram to the more specific of the two, which nobody reads.""" | ||
| 202 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
| 203 | try: | ||
| 204 | sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton("127.0.0.1")) | ||
| 205 | sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1) | ||
| 206 | sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1) | ||
| 207 | sock.sendto(payload, (LIVESYNC_GROUP, self.livesync_port)) | ||
| 208 | finally: | ||
| 209 | sock.close() | ||
| 210 | |||
| 211 | def wait_until(self, predicate, timeout=5): | ||
| 212 | """A live sync packet is handled by another thread, so an effect of | ||
| 213 | one arrives some time after the send.""" | ||
| 214 | deadline = time.time() + timeout | ||
| 215 | while time.time() < deadline: | ||
| 216 | if predicate(): | ||
| 217 | return True | ||
| 218 | time.sleep(0.02) | ||
| 219 | return predicate() | ||
| 220 | |||
| 189 | # ------------------------------------------------------------ over udp | 221 | # ------------------------------------------------------------ over udp |
| 190 | 222 | ||
| 191 | def udp_connect(self): | 223 | def udp_connect(self): |
diff --git a/tests/integration/test_livesync.py b/tests/integration/test_livesync.py new file mode 100644 index 0000000..3a9ee58 --- /dev/null +++ b/tests/integration/test_livesync.py | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | """Live sync, driven over the multicast group a cluster would use. | ||
| 2 | |||
| 3 | Live sync sits behind WANT_SYNC_LIVE, so these only run against a binary | ||
| 4 | built with it: make check-livesync. Against any other build they skip, which | ||
| 5 | is what the feature list in -v is for. | ||
| 6 | """ | ||
| 7 | |||
| 8 | import socket | ||
| 9 | import struct | ||
| 10 | import subprocess | ||
| 11 | import unittest | ||
| 12 | |||
| 13 | from harness import TRACKER, TrackerTestCase | ||
| 14 | |||
| 15 | # enum { OT_SYNC_PEER4, OT_SYNC_PEER6 } in src/ot_livesync.c | ||
| 16 | SYNC_PEER4 = 0 | ||
| 17 | SYNC_PEER6 = 1 | ||
| 18 | |||
| 19 | # src/trackerlogic.h | ||
| 20 | FLAG_SEEDING = 0x80 | ||
| 21 | FLAG_COMPLETED = 0x40 | ||
| 22 | FLAG_STOPPED = 0x20 | ||
| 23 | |||
| 24 | |||
| 25 | def has_livesync(): | ||
| 26 | done = subprocess.run([TRACKER, "-v"], capture_output=True, timeout=30) | ||
| 27 | return b"WANT_SYNC_LIVE" in done.stderr | ||
| 28 | |||
| 29 | |||
| 30 | def peer4(address, port, flags): | ||
| 31 | """Four bytes of address, two of port, one of flags, one the tracker | ||
| 32 | overwrites with its own idea of the time.""" | ||
| 33 | return socket.inet_aton(address) + struct.pack("!H", port) + bytes([flags, 0]) | ||
| 34 | |||
| 35 | |||
| 36 | def peer6(address, port, flags): | ||
| 37 | return socket.inet_pton(socket.AF_INET6, address) + struct.pack("!H", port) + bytes([flags, 0]) | ||
| 38 | |||
| 39 | |||
| 40 | def packet(kind, entries, tracker_id=0xDEADBEEF): | ||
| 41 | body = b"".join(info_hash + peer for info_hash, peer in entries) | ||
| 42 | return struct.pack("!I", tracker_id) + struct.pack("!I", kind) + body | ||
| 43 | |||
| 44 | |||
| 45 | @unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE") | ||
| 46 | class LiveSyncIn(TrackerTestCase): | ||
| 47 | config = "livesync.cluster.listen 127.0.0.1:{livesync_port}\nlivesync.cluster.node_ip 127.0.0.1\n" | ||
| 48 | |||
| 49 | def counts(self, info_hash): | ||
| 50 | """Seeders and leechers a scrape reports for one torrent.""" | ||
| 51 | files = self.tracker.scrape(info_hash)[b"files"] | ||
| 52 | if info_hash not in files: | ||
| 53 | return None | ||
| 54 | entry = files[info_hash] | ||
| 55 | return entry[b"complete"], entry[b"incomplete"] | ||
| 56 | |||
| 57 | def test_a_synced_seeder_arrives(self): | ||
| 58 | info_hash = self.hash_for("sync-seed") | ||
| 59 | self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.3", 6881, FLAG_SEEDING))])) | ||
| 60 | self.assertTrue(self.tracker.wait_until(lambda: self.counts(info_hash) == (1, 0)), | ||
| 61 | "scrape says %r" % (self.counts(info_hash),)) | ||
| 62 | |||
| 63 | def test_a_synced_leecher_arrives(self): | ||
| 64 | info_hash = self.hash_for("sync-leech") | ||
| 65 | self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.4", 6881, 0))])) | ||
| 66 | self.assertTrue(self.tracker.wait_until(lambda: self.counts(info_hash) == (0, 1)), | ||
| 67 | "scrape says %r" % (self.counts(info_hash),)) | ||
| 68 | |||
| 69 | def test_a_v6_peer_arrives(self): | ||
| 70 | info_hash = self.hash_for("sync-v6") | ||
| 71 | self.tracker.livesync_send(packet(SYNC_PEER6, [(info_hash, peer6("2001:db8::1", 6881, FLAG_SEEDING))])) | ||
| 72 | self.assertTrue(self.tracker.wait_until(lambda: self.counts(info_hash) == (1, 0)), | ||
| 73 | "scrape says %r" % (self.counts(info_hash),)) | ||
| 74 | |||
| 75 | def test_one_packet_carries_several_torrents(self): | ||
| 76 | hashes = [self.hash_for("sync-many-%d" % i) for i in range(4)] | ||
| 77 | self.tracker.livesync_send(packet(SYNC_PEER4, [(h, peer4("10.1.2.%d" % (5 + i), 6881, FLAG_SEEDING)) | ||
| 78 | for i, h in enumerate(hashes)])) | ||
| 79 | self.assertTrue(self.tracker.wait_until(lambda: all(self.counts(h) == (1, 0) for h in hashes))) | ||
| 80 | |||
| 81 | def test_a_stopped_peer_is_taken_away_again(self): | ||
| 82 | info_hash = self.hash_for("sync-stop") | ||
| 83 | peer = peer4("10.1.2.9", 6881, FLAG_SEEDING) | ||
| 84 | self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer)])) | ||
| 85 | self.assertTrue(self.tracker.wait_until(lambda: self.counts(info_hash) == (1, 0))) | ||
| 86 | |||
| 87 | self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.9", 6881, FLAG_STOPPED))])) | ||
| 88 | self.assertTrue(self.tracker.wait_until(lambda: self.counts(info_hash) in (None, (0, 0))), | ||
| 89 | "scrape still says %r" % (self.counts(info_hash),)) | ||
| 90 | |||
| 91 | def test_a_truncated_entry_is_dropped(self): | ||
| 92 | """The loop takes whole hash and peer pairs and leaves a short tail | ||
| 93 | where it is, so the complete entry before it still lands.""" | ||
| 94 | good, short = self.hash_for("sync-good"), self.hash_for("sync-short") | ||
| 95 | payload = packet(SYNC_PEER4, [(good, peer4("10.1.2.10", 6881, FLAG_SEEDING))]) + short + b"\x0a\x01" | ||
| 96 | self.tracker.livesync_send(payload) | ||
| 97 | self.assertTrue(self.tracker.wait_until(lambda: self.counts(good) == (1, 0))) | ||
| 98 | self.assertIsNone(self.counts(short)) | ||
| 99 | |||
| 100 | def test_an_unknown_packet_type_is_ignored(self): | ||
| 101 | info_hash = self.hash_for("sync-unknown") | ||
| 102 | self.tracker.livesync_send(packet(99, [(info_hash, peer4("10.1.2.11", 6881, FLAG_SEEDING))])) | ||
| 103 | self.assertFalse(self.tracker.wait_until(lambda: self.counts(info_hash) is not None, timeout=1)) | ||
| 104 | |||
| 105 | def test_synced_peers_are_counted(self): | ||
| 106 | """The live sync worker keeps its own tally like every other worker, | ||
| 107 | and ?mode=syncs is the sum of them.""" | ||
| 108 | before = int(self.tracker.stats("syncs").split()[0]) | ||
| 109 | hashes = [self.hash_for("sync-count-%d" % i) for i in range(3)] | ||
| 110 | self.tracker.livesync_send(packet(SYNC_PEER4, [(h, peer4("10.1.2.%d" % (20 + i), 6881, FLAG_SEEDING)) | ||
| 111 | for i, h in enumerate(hashes)])) | ||
| 112 | self.assertTrue(self.tracker.wait_until( | ||
| 113 | lambda: int(self.tracker.stats("syncs").split()[0]) == before + 3), | ||
| 114 | "syncs says %s" % self.tracker.stats("syncs").split()[0]) | ||
| 115 | |||
| 116 | def test_a_packet_with_nothing_but_a_header_is_ignored(self): | ||
| 117 | before = self.tracker.torrent_count() | ||
| 118 | self.tracker.livesync_send(struct.pack("!I", 0xDEADBEEF) + struct.pack("!I", SYNC_PEER4)) | ||
| 119 | self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != before, timeout=1)) | ||
| 120 | |||
| 121 | |||
| 122 | @unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE") | ||
| 123 | class LiveSyncAccess(TrackerTestCase): | ||
| 124 | """Nothing blesses 127.0.0.1 here, so the tracker should take nothing | ||
| 125 | from it. Source address checking is all live sync has.""" | ||
| 126 | |||
| 127 | config = "livesync.cluster.listen 127.0.0.1:{livesync_port}\nlivesync.cluster.node_ip 10.0.0.1\n" | ||
| 128 | |||
| 129 | def test_an_unblessed_sender_is_ignored(self): | ||
| 130 | info_hash = self.hash_for("sync-unblessed") | ||
| 131 | self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.12", 6881, FLAG_SEEDING))])) | ||
| 132 | self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1)) | ||
| 133 | |||
| 134 | |||
| 135 | @unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE") | ||
| 136 | class LiveSyncUnconfigured(TrackerTestCase): | ||
| 137 | """A binary that has the feature but no cluster to join. Somebody whose | ||
| 138 | packager turned WANT_SYNC_LIVE on did not ask for live sync and should | ||
| 139 | not be able to tell that it is there.""" | ||
| 140 | |||
| 141 | config = "" | ||
| 142 | |||
| 143 | def test_the_tracker_runs_anyway(self): | ||
| 144 | info_hash = self.hash_for("no-cluster") | ||
| 145 | self.tracker.announce(info_hash, port=6881, left=0) | ||
| 146 | self.assertEqual(self.tracker.torrent_count(), 1) | ||
| 147 | |||
| 148 | def test_nothing_is_said_about_the_missing_cluster(self): | ||
| 149 | self.assertNotIn("sync", self.tracker.output().lower()) | ||
| 150 | |||
| 151 | def test_no_socket_is_bound_for_it(self): | ||
| 152 | """A configured tracker holds the wildcard address on that port, so | ||
| 153 | taking it here proves nothing was started.""" | ||
| 154 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
| 155 | try: | ||
| 156 | sock.bind(("0.0.0.0", self.tracker.livesync_port)) | ||
| 157 | finally: | ||
| 158 | sock.close() | ||
| 159 | |||
| 160 | def test_announcing_stays_clean(self): | ||
| 161 | """Enough announces to pass the watermark that would flush an | ||
| 162 | outgoing buffer, if there were one to flush. The sanitizers in this | ||
| 163 | build turn anything the attempt touched into a failure.""" | ||
| 164 | for i in range(200): | ||
| 165 | self.tracker.announce(self.hash_for("no-cluster-%d" % i), port=6881 + i, left=0) | ||
| 166 | self.assertEqual(self.tracker.torrent_count(), 200) | ||
diff --git a/sync_daemon.pl b/tests/sync_daemon.pl index 9e4bdb9..9e4bdb9 100644 --- a/sync_daemon.pl +++ b/tests/sync_daemon.pl | |||
diff --git a/tests/t_mutex.c b/tests/t_mutex.c index e54e2fa..c0c41cc 100644 --- a/tests/t_mutex.c +++ b/tests/t_mutex.c | |||
| @@ -24,7 +24,7 @@ static void hash_for_bucket(ot_hash hash, int bucket) { | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | static void case_a_hash_names_its_bucket(void) { | 26 | static void case_a_hash_names_its_bucket(void) { |
| 27 | static const int buckets[] = {0, 1, 2, 17, 511, 512, OT_BUCKET_COUNT - 1}; | 27 | static const int buckets[] = {0, 1, 2, 17, OT_BUCKET_COUNT / 2 - 1, OT_BUCKET_COUNT / 2, OT_BUCKET_COUNT - 1}; |
| 28 | size_t i; | 28 | size_t i; |
| 29 | 29 | ||
| 30 | test_case("a hash is served by the bucket its leading bits name"); | 30 | test_case("a hash is served by the bucket its leading bits name"); |
diff --git a/tests/t_trackerlogic.c b/tests/t_trackerlogic.c index f64977f..1cf9141 100644 --- a/tests/t_trackerlogic.c +++ b/tests/t_trackerlogic.c | |||
| @@ -224,7 +224,7 @@ void test_trackerlogic(void) { | |||
| 224 | pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); | 224 | pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); |
| 225 | 225 | ||
| 226 | trackerlogic_init(); | 226 | trackerlogic_init(); |
| 227 | CHECK_INT(workstruct_init(&ws), 0); | 227 | CHECK_INT(workstruct_init(&ws, G_INBUF_SIZE), 0); |
| 228 | 228 | ||
| 229 | case_an_announce_makes_a_torrent(); | 229 | case_an_announce_makes_a_torrent(); |
| 230 | case_the_same_peer_twice_is_one_peer(); | 230 | case_the_same_peer_twice_is_one_peer(); |
