summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile90
-rw-r--r--man1/opentracker.14
-rw-r--r--man4/opentracker.conf.43
-rw-r--r--opentracker.conf.sample6
-rw-r--r--ot_accesslist.c28
-rw-r--r--ot_accesslist.h16
-rw-r--r--ot_config.c2
-rw-r--r--ot_http.c69
-rw-r--r--ot_stats.c146
-rw-r--r--ot_stats.h1
-rw-r--r--ot_sync.c165
-rw-r--r--ot_sync.h26
-rw-r--r--ot_workqueue.h2
-rw-r--r--proxy.c4
-rw-r--r--tests/integration/test_stats.py25
-rw-r--r--tests/integration/test_version.py36
-rw-r--r--trackerlogic.h4
18 files changed, 214 insertions, 416 deletions
diff --git a/.gitignore b/.gitignore
index 3e469ff..df288e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,6 @@ proxy.debug
9tests/runner 9tests/runner
10tests/runner.poll 10tests/runner.poll
11tests/runner.sanitize 11tests/runner.sanitize
12.buildstamp
13.tarball-version
14opentracker-*.tar.gz
diff --git a/Makefile b/Makefile
index 6a5a270..a665890 100644
--- a/Makefile
+++ b/Makefile
@@ -1,20 +1,6 @@
1# $Id$ 1# $Id$
2 2
3# Linux flavour
4# PREFIX?=/opt/diet
5# LIBOWFAT_HEADERS=$(PREFIX)/include
6# LIBOWFAT_LIBRARY=$(PREFIX)/lib
7
8# BSD flavour
9# PREFIX?=/usr/local
10# LIBOWFAT_HEADERS=$(PREFIX)/include/libowfat
11# LIBOWFAT_LIBRARY=$(PREFIX)/lib
12
13# Debug flavour
14PREFIX?=.. 3PREFIX?=..
15LIBOWFAT_HEADERS=$(PREFIX)/libowfat
16LIBOWFAT_LIBRARY=$(PREFIX)/libowfat
17
18BINDIR?=$(PREFIX)/bin 4BINDIR?=$(PREFIX)/bin
19STRIP?=strip 5STRIP?=strip
20 6
@@ -36,10 +22,8 @@ include Makefile.gzip
36# in Makefile.zstd 22# in Makefile.zstd
37#include Makefile.zstd 23#include Makefile.zstd
38 24
39#FEATURES+=-DWANT_LOG_NETWORKS
40#FEATURES+=-DWANT_RESTRICT_STATS 25#FEATURES+=-DWANT_RESTRICT_STATS
41#FEATURES+=-DWANT_IP_FROM_PROXY 26#FEATURES+=-DWANT_IP_FROM_PROXY
42#FEATURES+=-DWANT_FULLLOG_NETWORKS
43#FEATURES+=-DWANT_LOG_NUMWANT 27#FEATURES+=-DWANT_LOG_NUMWANT
44#FEATURES+=-DWANT_MODEST_FULLSCRAPES 28#FEATURES+=-DWANT_MODEST_FULLSCRAPES
45#FEATURES+=-DWANT_SPOT_WOODPECKER 29#FEATURES+=-DWANT_SPOT_WOODPECKER
@@ -55,41 +39,52 @@ FEATURES+=-DWANT_FULLSCRAPE
55#FEATURES+=-D_DEBUG_HTTPERROR 39#FEATURES+=-D_DEBUG_HTTPERROR
56#FEATURES+=-D_DEBUG_RANDOMTORRENTS 40#FEATURES+=-D_DEBUG_RANDOMTORRENTS
57 41
58GIT_VERSION=`sh -c 'command -v git >/dev/null && test -d .git && git rev-parse HEAD || echo _git_or_commit_not_found_'` 42VERSION=1.0.0
43TARBALL_VERSION=test -r .tarball-version && read v < .tarball-version && echo "$$v"
44HAVE_GIT=command -v git >/dev/null && test -d .git
45GIT_VERSION=`sh -c '$(TARBALL_VERSION) || { $(HAVE_GIT) && git describe --tags --match "v*" --always --dirty 2>/dev/null; }'`
46OT_TAG=`sh -c '$(TARBALL_VERSION) || { $(HAVE_GIT) && git describe --tags --match "v*" --exact-match 2>/dev/null; }'`
59 47
60OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage 48OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage
61OPTS_production=-O3 49OPTS_production=-O3
62 50
63CFLAGS+=-DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra -Wwrite-strings #-ansi -pedantic 51CFLAGS+=-DOT_VERSION=\"$(VERSION)\" -DGIT_VERSION=\"$(GIT_VERSION)\" -DOT_TAG=\"$(OT_TAG)\" -Wall -pipe -pthread -Wextra -Wwrite-strings #-ansi -pedantic
64LDFLAGS+=-pthread 52LDFLAGS+=-pthread
65 53
66# Only the proxy, which has not been ported since the tracker went dual stack, 54# Record feature flags as a dep to allow rebuild when they change
67# still wants libowfat. 55BUILDSTAMP=.buildstamp
68CFLAGS_libowfat=-I$(LIBOWFAT_HEADERS) 56BUILDDEPS=Makefile $(BUILDSTAMP)
69LDFLAGS_libowfat=-L$(LIBOWFAT_LIBRARY) -lowfat 57
58$(BUILDSTAMP): FORCE
59 @echo "$(CFLAGS) $(FEATURES) $(LDFLAGS)" | cmp -s - $@ 2>/dev/null || echo "$(CFLAGS) $(FEATURES) $(LDFLAGS)" > $@
60
61FORCE:
70 62
71BINARY =opentracker 63BINARY =opentracker
72HEADERS=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 64HEADERS=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
73SOURCES=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 65SOURCES=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
74SOURCES_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
75 66
76all: $(BINARY) $(BINARY).debug 67all: $(BINARY) $(BINARY).debug
77 68
78CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES) 69CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES)
79CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES) 70CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES)
80 71
81CFLAGS_proxy = $(CFLAGS_production) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE 72$(BINARY): $(SOURCES) $(HEADERS) $(BUILDDEPS)
82CFLAGS_proxy_debug = $(CFLAGS_debug) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE
83
84$(BINARY): $(SOURCES) $(HEADERS)
85 $(CC) -o $@ $(CFLAGS_production) $(SOURCES) $(LDFLAGS) 73 $(CC) -o $@ $(CFLAGS_production) $(SOURCES) $(LDFLAGS)
86 $(STRIP) $@ 74 $(STRIP) $@
87$(BINARY).debug: $(SOURCES) $(HEADERS) 75$(BINARY).debug: $(SOURCES) $(HEADERS) $(BUILDDEPS)
88 $(CC) -o $@ $(CFLAGS_debug) $(SOURCES) $(LDFLAGS) 76 $(CC) -o $@ $(CFLAGS_debug) $(SOURCES) $(LDFLAGS)
89proxy: $(SOURCES_proxy) $(HEADERS) 77
90 $(CC) -o $@ $(CFLAGS_proxy) $(SOURCES_proxy) $(LDFLAGS) $(LDFLAGS_libowfat) 78# The proxy is out of service
91proxy.debug: $(SOURCES_proxy) $(HEADERS) 79#
92 $(CC) -o $@ $(CFLAGS_proxy_debug) $(SOURCES_proxy) $(LDFLAGS) $(LDFLAGS_libowfat) 80# 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
81# CFLAGS_proxy = $(CFLAGS_production) -DWANT_SYNC_LIVE
82# CFLAGS_proxy_debug = $(CFLAGS_debug) -DWANT_SYNC_LIVE
83#
84# proxy: $(SOURCES_proxy) $(HEADERS) $(BUILDDEPS)
85# $(CC) -o $@ $(CFLAGS_proxy) $(SOURCES_proxy) $(LDFLAGS)
86# proxy.debug: $(SOURCES_proxy) $(HEADERS) $(BUILDDEPS)
87# $(CC) -o $@ $(CFLAGS_proxy_debug) $(SOURCES_proxy) $(LDFLAGS)
93 88
94# Unit tests. The modules under test are compiled straight into the test 89# Unit tests. The modules under test are compiled straight into the test
95# binary, so a test may reach a static function by including the source if it 90# binary, so a test may reach a static function by including the source if it
@@ -104,13 +99,13 @@ TEST_HEADERS=tests/test.h $(HEADERS)
104FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE 99FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE
105CFLAGS_test = $(CFLAGS) -I. -g -O1 $(FEATURES_test) 100CFLAGS_test = $(CFLAGS) -I. -g -O1 $(FEATURES_test)
106 101
107$(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) 102$(TESTBIN): $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) $(BUILDDEPS)
108 $(CC) -o $@ $(CFLAGS_test) $(TEST_SOURCES) $(TEST_UNITS) 103 $(CC) -o $@ $(CFLAGS_test) $(TEST_SOURCES) $(TEST_UNITS)
109 104
110check: $(TESTBIN) $(BINARY) 105check: $(TESTBIN) $(BINARY)
111 ./$(TESTBIN) 106 ./$(TESTBIN)
112 107
113$(TESTBIN).poll: $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) 108$(TESTBIN).poll: $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) $(BUILDDEPS)
114 $(CC) -o $@ $(CFLAGS_test) -DOT_EVENT_FORCE_POLL $(TEST_SOURCES) $(TEST_UNITS) 109 $(CC) -o $@ $(CFLAGS_test) -DOT_EVENT_FORCE_POLL $(TEST_SOURCES) $(TEST_UNITS)
115 110
116check-poll: $(TESTBIN).poll 111check-poll: $(TESTBIN).poll
@@ -123,7 +118,7 @@ CC_sanitize?=clang
123CFLAGS_sanitize=$(CFLAGS_test) -fsanitize=address,undefined -fno-omit-frame-pointer 118CFLAGS_sanitize=$(CFLAGS_test) -fsanitize=address,undefined -fno-omit-frame-pointer
124LDFLAGS_sanitize=$(LDFLAGS) -fsanitize=address,undefined 119LDFLAGS_sanitize=$(LDFLAGS) -fsanitize=address,undefined
125 120
126$(TESTBIN).sanitize: $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) 121$(TESTBIN).sanitize: $(TEST_SOURCES) $(TEST_UNITS) $(TEST_HEADERS) $(BUILDDEPS)
127 $(CC_sanitize) -o $@ $(CFLAGS_sanitize) $(TEST_SOURCES) $(TEST_UNITS) $(LDFLAGS_sanitize) 122 $(CC_sanitize) -o $@ $(CFLAGS_sanitize) $(TEST_SOURCES) $(TEST_UNITS) $(LDFLAGS_sanitize)
128 123
129check-sanitize: $(TESTBIN).sanitize 124check-sanitize: $(TESTBIN).sanitize
@@ -140,7 +135,7 @@ FEATURES_integration=$(FEATURES) -DWANT_IP_FROM_QUERY_STRING -DWANT_ACCESSLIST_B
140CFLAGS_integration=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=address,undefined -fno-omit-frame-pointer 135CFLAGS_integration=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=address,undefined -fno-omit-frame-pointer
141LDFLAGS_integration=$(LDFLAGS) -fsanitize=address,undefined 136LDFLAGS_integration=$(LDFLAGS) -fsanitize=address,undefined
142 137
143opentracker.integration: $(SOURCES) $(HEADERS) 138opentracker.integration: $(SOURCES) $(HEADERS) $(BUILDDEPS)
144 $(CC) -o $@ $(CFLAGS_integration) $(SOURCES) $(LDFLAGS_integration) 139 $(CC) -o $@ $(CFLAGS_integration) $(SOURCES) $(LDFLAGS_integration)
145 140
146check-integration: opentracker.integration 141check-integration: opentracker.integration
@@ -150,7 +145,7 @@ check-integration: opentracker.integration
150CFLAGS_tsan=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=thread -fno-omit-frame-pointer 145CFLAGS_tsan=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=thread -fno-omit-frame-pointer
151LDFLAGS_tsan=$(LDFLAGS) -fsanitize=thread 146LDFLAGS_tsan=$(LDFLAGS) -fsanitize=thread
152 147
153opentracker.tsan: $(SOURCES) $(HEADERS) 148opentracker.tsan: $(SOURCES) $(HEADERS) $(BUILDDEPS)
154 $(CC) -o $@ $(CFLAGS_tsan) $(SOURCES) $(LDFLAGS_tsan) 149 $(CC) -o $@ $(CFLAGS_tsan) $(SOURCES) $(LDFLAGS_tsan)
155 150
156check-tsan: opentracker.tsan 151check-tsan: opentracker.tsan
@@ -164,12 +159,27 @@ check-all:
164 $(MAKE) check-integration 159 $(MAKE) check-integration
165 $(MAKE) check-tsan 160 $(MAKE) check-tsan
166 161
167.PHONY: all check check-poll check-sanitize check-integration check-tsan check-all clean install 162.PHONY: all FORCE dist check check-poll check-sanitize check-integration check-tsan check-all clean install
168 163
169BINARIES=opentracker opentracker.debug opentracker.integration opentracker.tsan proxy proxy.debug $(TESTBIN) $(TESTBIN).sanitize $(TESTBIN).poll 164BINARIES=opentracker opentracker.debug opentracker.integration opentracker.tsan $(TESTBIN) $(TESTBIN).sanitize $(TESTBIN).poll
170 165
171clean: 166clean:
172 rm -rf $(BINARIES) $(BINARIES:=.dSYM) *.o *~ 167 rm -rf $(BINARIES) $(BINARIES:=.dSYM) $(BUILDSTAMP) *.o *~
173 168
174install: 169install:
175 install -m 755 opentracker $(DESTDIR)$(BINDIR) 170 install -m 755 opentracker $(DESTDIR)$(BINDIR)
171
172# Roll a release: tag it v<something>, then make dist. The commit is written
173# into the tarball, so a build from it reports the same version this checkout
174# would, without a git to ask. The tarball is HEAD by construction, so the
175# working tree it was rolled from does not enter into the version.
176DISTNAME=opentracker-$(VERSION)
177
178dist:
179 @test "`git describe --tags --match 'v*' --exact-match 2>/dev/null`" = "v$(VERSION)" || \
180 { echo "HEAD must carry the tag v$(VERSION). Tag the release, or correct VERSION."; exit 1; }
181 rm -rf $(DISTNAME) $(DISTNAME).tar.gz
182 git archive --format=tar --prefix=$(DISTNAME)/ HEAD | tar -xf -
183 git describe --tags --match "v*" --always > $(DISTNAME)/.tarball-version
184 tar -czf $(DISTNAME).tar.gz $(DISTNAME)
185 rm -rf $(DISTNAME)
diff --git a/man1/opentracker.1 b/man1/opentracker.1
index 0103ebe..489a54c 100644
--- a/man1/opentracker.1
+++ b/man1/opentracker.1
@@ -15,6 +15,7 @@
15.Op Fl d Ar chdir 15.Op Fl d Ar chdir
16.Op Fl u Ar user 16.Op Fl u Ar user
17.Op Fl w| Fl b accesslist 17.Op Fl w| Fl b accesslist
18.Op Fl v
18.Sh DESCRIPTION 19.Sh DESCRIPTION
19.Nm 20.Nm
20is a bittorrent tracker that implements announce and scrape actions over the 21is a bittorrent tracker that implements announce and scrape actions over the
@@ -85,6 +86,9 @@ has been compiled with the
85or 86or
86.Br WANT_ACCESSLIST_WHITE 87.Br WANT_ACCESSLIST_WHITE
87options, this option sets the location of the accesslist. 88options, this option sets the location of the accesslist.
89.It Fl v
90Report the version, the event mechanism in use and the feature flags this
91binary was built with.
88.El 92.El
89.Sh EXAMPLES 93.Sh EXAMPLES
90Start 94Start
diff --git a/man4/opentracker.conf.4 b/man4/opentracker.conf.4
index 1bd1c7a..239ab88 100644
--- a/man4/opentracker.conf.4
+++ b/man4/opentracker.conf.4
@@ -84,9 +84,6 @@ Specifies the IP address and port opentracker will listen on for incoming live s
84.It livesync.cluster.node_ip Ar ip_address 84.It livesync.cluster.node_ip Ar ip_address
85Specifies one trusted IP address for sync between trackers running in a cluster. Can be added more than once. 85Specifies one trusted IP address for sync between trackers running in a cluster. Can be added more than once.
86.Pp 86.Pp
87.It batchsync.cluster.admin_ip Ar ip_address
88Specifies the admin IP address for old-style (HTTP-based) asynchronous tracker syncing.
89.Pp
90.It tracker.rootdir Ar path 87.It tracker.rootdir Ar path
91Specifies the directory opentracker will chroot/chdir to. All black/white list files must be located in this directory. 88Specifies the directory opentracker will chroot/chdir to. All black/white list files must be located in this directory.
92.Pp 89.Pp
diff --git a/opentracker.conf.sample b/opentracker.conf.sample
index f075703..491c88a 100644
--- a/opentracker.conf.sample
+++ b/opentracker.conf.sample
@@ -154,12 +154,6 @@
154# livesync.cluster.node_ip 192.168.0.4 154# livesync.cluster.node_ip 192.168.0.4
155# livesync.cluster.node_ip 192.168.0.5 155# livesync.cluster.node_ip 192.168.0.5
156# livesync.cluster.node_ip 192.168.0.6 156# livesync.cluster.node_ip 192.168.0.6
157#
158# This is the admin ip address for old style (HTTP based) asynchronus
159# tracker syncing.
160#
161# batchsync.cluster.admin_ip 10.1.1.1
162#
163 157
164# V) Control privilege drop behaviour. 158# V) Control privilege drop behaviour.
165# Put in the directory opentracker will chroot/chdir to. All black/white 159# Put in the directory opentracker will chroot/chdir to. All black/white
diff --git a/ot_accesslist.c b/ot_accesslist.c
index df084b8..945ddcf 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -503,34 +503,6 @@ void *accesslist_get_value_for_net(const ot_ip6 address, const ot_vector *vector
503 return (void *)net; 503 return (void *)net;
504} 504}
505 505
506#ifdef WANT_FULLLOG_NETWORKS
507static ot_vector g_lognets_list;
508ot_log *g_logchain_first, *g_logchain_last;
509static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER;
510
511void loglist_add_network(const ot_net *net) {
512 pthread_mutex_lock(&g_lognets_list_mutex);
513 accesslist_set_value_for_net(net, &g_lognets_list, NULL, sizeof(ot_net));
514 pthread_mutex_unlock(&g_lognets_list_mutex);
515}
516
517void loglist_reset(void) {
518 pthread_mutex_lock(&g_lognets_list_mutex);
519 free(g_lognets_list.data);
520 g_lognets_list.data = 0;
521 g_lognets_list.size = g_lognets_list.space = 0;
522 pthread_mutex_unlock(&g_lognets_list_mutex);
523}
524
525int loglist_check_address(const ot_ip6 address) {
526 int result;
527 pthread_mutex_lock(&g_lognets_list_mutex);
528 result = (NULL != accesslist_get_value_for_net(address, &g_lognets_list, sizeof(ot_net)));
529 pthread_mutex_unlock(&g_lognets_list_mutex);
530 return result;
531}
532#endif
533
534#ifdef WANT_IP_FROM_PROXY 506#ifdef WANT_IP_FROM_PROXY
535typedef struct { 507typedef struct {
536 ot_net *proxy; 508 ot_net *proxy;
diff --git a/ot_accesslist.h b/ot_accesslist.h
index 9c39a7a..ca0e126 100644
--- a/ot_accesslist.h
+++ b/ot_accesslist.h
@@ -66,22 +66,6 @@ int proxylist_add_network(const ot_net *proxy, const ot_net *net);
66int proxylist_check_network(const ot_ip6 *proxy, const ot_ip6 address /* can be NULL to only check proxy */); 66int proxylist_check_network(const ot_ip6 *proxy, const ot_ip6 address /* can be NULL to only check proxy */);
67#endif 67#endif
68 68
69#ifdef WANT_FULLLOG_NETWORKS
70typedef struct ot_log ot_log;
71struct ot_log {
72 ot_ip6 ip;
73 uint8_t *data;
74 size_t size;
75 ot_time time;
76 ot_log *next;
77};
78extern ot_log *g_logchain_first, *g_logchain_last;
79
80void loglist_add_network(const ot_net *net);
81void loglist_reset(void);
82int loglist_check_address(const ot_ip6 address);
83#endif
84
85typedef enum { 69typedef enum {
86 OT_PERMISSION_MAY_FULLSCRAPE = 0x1, 70 OT_PERMISSION_MAY_FULLSCRAPE = 0x1,
87 OT_PERMISSION_MAY_STAT = 0x2, 71 OT_PERMISSION_MAY_STAT = 0x2,
diff --git a/ot_config.c b/ot_config.c
index 272acf1..5da6642 100644
--- a/ot_config.c
+++ b/ot_config.c
@@ -432,6 +432,7 @@ static void help(char *name) {
432 HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")"); 432 HELPLINE("-d dir", "specify directory to try to chroot to (default: \".\")");
433 HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")"); 433 HELPLINE("-u user", "specify user under whose privileges opentracker should run (default: \"nobody\")");
434 HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)"); 434 HELPLINE("-A ip[/bits]", "bless an ip address or net as admin address (e.g. to allow syncs from this address)");
435 HELPLINE("-v", "report version, event mechanism and the feature flags opentracker was built with");
435#ifdef WANT_ACCESSLIST_BLACK 436#ifdef WANT_ACCESSLIST_BLACK
436 HELPLINE("-b file", "specify blacklist file."); 437 HELPLINE("-b file", "specify blacklist file.");
437#elif defined(WANT_ACCESSLIST_WHITE) 438#elif defined(WANT_ACCESSLIST_WHITE)
@@ -566,6 +567,7 @@ void config_parse(int argc, char **argv) {
566 char *cursor = buffer; 567 char *cursor = buffer;
567 568
568 stats_return_tracker_version(&cursor, buffer + sizeof(buffer) - 1); 569 stats_return_tracker_version(&cursor, buffer + sizeof(buffer) - 1);
570 stats_return_tracker_features(&cursor, buffer + sizeof(buffer) - 1);
569 *cursor = 0; 571 *cursor = 0;
570 fputs(buffer, stderr); 572 fputs(buffer, stderr);
571 exit(0); 573 exit(0);
diff --git a/ot_http.c b/ot_http.c
index b0e1de3..b243ff6 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -289,10 +289,8 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
289 {"top10", TASK_STATS_TOP10}, 289 {"top10", TASK_STATS_TOP10},
290 {"renew", TASK_STATS_RENEW}, 290 {"renew", TASK_STATS_RENEW},
291 {"syncs", TASK_STATS_SYNCS}, 291 {"syncs", TASK_STATS_SYNCS},
292 {"version", TASK_STATS_VERSION},
293 {"everything", TASK_STATS_EVERYTHING}, 292 {"everything", TASK_STATS_EVERYTHING},
294 {"statedump", TASK_FULLSCRAPE_TRACKERSTATE}, 293 {"statedump", TASK_FULLSCRAPE_TRACKERSTATE},
295 {"fulllog", TASK_STATS_FULLLOG},
296 {"woodpeckers", TASK_STATS_WOODPECKERS}, 294 {"woodpeckers", TASK_STATS_WOODPECKERS},
297#ifdef WANT_LOG_NUMWANT 295#ifdef WANT_LOG_NUMWANT
298 {"numwants", TASK_STATS_NUMWANTS}, 296 {"numwants", TASK_STATS_NUMWANTS},
@@ -559,10 +557,7 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event",
559#ifdef WANT_IP_FROM_QUERY_STRING 557#ifdef WANT_IP_FROM_QUERY_STRING
560 {"ip", 7}, 558 {"ip", 7},
561#endif 559#endif
562#ifdef WANT_FULLLOG_NETWORKS 560 {"peer_id", 8}, {NULL, -3}};
563 {"lognet", 8},
564#endif
565 {"peer_id", 9}, {NULL, -3}};
566static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; 561static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}};
567 562
568/* For the replies that are one fixed string and nothing else, where the only 563/* For the replies that are one fixed string and nothing else, where the only
@@ -687,43 +682,7 @@ static ssize_t http_handle_announce(const int64_t sock, struct ot_workstruct
687 OT_SETIP(&ws->peer, tmp_buf1); 682 OT_SETIP(&ws->peer, tmp_buf1);
688 } break; 683 } break;
689#endif 684#endif
690#ifdef WANT_FULLLOG_NETWORKS 685 case 8: /* matched "peer_id" */
691 case 8: /* matched "lognet" */
692 {
693 // if( accesslist_is_blessed( cookie->ip, OT_PERMISSION_MAY_STAT ) ) {
694 char *tmp_buf = ws->reply;
695 ot_net net;
696 uint64_t value;
697 signed short parsed, bits;
698
699 len = urlencoded_parse(&read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE);
700 tmp_buf[len] = 0;
701 if (len <= 0)
702 HTTPERROR_400_PARAM;
703 if (*tmp_buf == '-') {
704 loglist_reset();
705 return ws->reply_size = reply_literal(ws, "Successfully removed.\n");
706 }
707 parsed = ip_parse(tmp_buf, net.address);
708 if (!parsed)
709 HTTPERROR_400_PARAM;
710 if (tmp_buf[parsed++] != '/')
711 bits = 128;
712 else {
713 parsed = scan_uint(tmp_buf + parsed, &value, 128);
714 if (!parsed)
715 HTTPERROR_400_PARAM;
716 bits = (signed short)value;
717 if (ip_is_v4mapped(net.address))
718 bits += 96;
719 }
720 net.bits = bits;
721 loglist_add_network(&net);
722 return ws->reply_size = reply_literal(ws, "Successfully added.\n");
723 //}
724 } break;
725#endif
726 case 9: /* matched "peer_id" */
727 /* ignore this, when we have less than 20 bytes */ 686 /* ignore this, when we have less than 20 bytes */
728 if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20) 687 if (urlencoded_parse(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE) != 20)
729 HTTPERROR_400_PARAM; 688 HTTPERROR_400_PARAM;
@@ -757,30 +716,6 @@ ssize_t http_handle_request(const int64_t sock, struct ot_workstruct *ws) {
757 ssize_t reply_off, len; 716 ssize_t reply_off, len;
758 char *read_ptr = ws->request, *write_ptr; 717 char *read_ptr = ws->request, *write_ptr;
759 718
760#ifdef WANT_FULLLOG_NETWORKS
761 struct http_data *cookie = fdstate_cookie(sock);
762 if (loglist_check_address(cookie->ip)) {
763 ot_log *log = malloc(sizeof(ot_log));
764 if (log) {
765 log->size = ws->request_size;
766 log->data = malloc(ws->request_size);
767 log->next = 0;
768 log->time = time_now_seconds();
769 memcpy(log->ip, cookie->ip, sizeof(ot_ip6));
770 if (log->data) {
771 memcpy(log->data, ws->request, ws->request_size);
772 if (!g_logchain_first)
773 g_logchain_first = g_logchain_last = log;
774 else {
775 g_logchain_last->next = log;
776 g_logchain_last = log;
777 }
778 } else
779 free(log);
780 }
781 }
782#endif
783
784#ifdef _DEBUG_HTTPERROR 719#ifdef _DEBUG_HTTPERROR
785 reply_off = ws->request_size; 720 reply_off = ws->request_size;
786 if (ws->request_size >= G_DEBUGBUF_SIZE) 721 if (ws->request_size >= G_DEBUGBUF_SIZE)
diff --git a/ot_stats.c b/ot_stats.c
index d38355a..a2eb084 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -4,7 +4,6 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#include <inttypes.h>
8#include <pthread.h> 7#include <pthread.h>
9#include <stdatomic.h> 8#include <stdatomic.h>
10#include <stdio.h> 9#include <stdio.h>
@@ -19,6 +18,7 @@
19 18
20/* Opentracker */ 19/* Opentracker */
21#include "ot_accesslist.h" 20#include "ot_accesslist.h"
21#include "ot_event.h"
22#include "ot_hex.h" 22#include "ot_hex.h"
23#include "ot_iovec.h" 23#include "ot_iovec.h"
24#include "ot_ip.h" 24#include "ot_ip.h"
@@ -117,10 +117,6 @@ union stats_network_node {
117 stats_network_node *children[STATS_NETWORK_NODE_COUNT]; 117 stats_network_node *children[STATS_NETWORK_NODE_COUNT];
118}; 118};
119 119
120#ifdef WANT_LOG_NETWORKS
121static stats_network_node *stats_network_counters_root;
122#endif
123
124static int stat_increase_network_count(stats_network_node **pnode, int depth, uintptr_t ip) { 120static int stat_increase_network_count(stats_network_node **pnode, int depth, uintptr_t ip) {
125 int foo = __LDR(ip, depth); 121 int foo = __LDR(ip, depth);
126 stats_network_node *node; 122 stats_network_node *node;
@@ -504,36 +500,6 @@ static void stats_return_numwants(char **reply, const char *reply_en
504} 500}
505#endif 501#endif
506 502
507#ifdef WANT_FULLLOG_NETWORKS
508static void stats_return_fulllog(size_t *iovec_entries, struct iovec **iovector, char *r) {
509 ot_log *loglist = g_logchain_first, *llnext;
510 char *re = r + OT_STATS_TMPSIZE;
511
512 g_logchain_first = g_logchain_last = 0;
513
514 while (loglist) {
515 if (r + (loglist->size + 64) >= re) {
516 r = iovec_next_chunk(iovec_entries, iovector, r, 32 * OT_STATS_TMPSIZE);
517 if (!r)
518 return;
519 re = r + 32 * OT_STATS_TMPSIZE;
520 }
521 char ip_readable[64];
522
523 ip_readable[ip_format(ip_readable, loglist->ip)] = 0;
524 fmt_append(&r, re, "%08ld: %s\n", loglist->time, ip_readable);
525 fmt_bytes(&r, re, loglist->data, loglist->size);
526 fmt_append(&r, re, "\n*\n\n");
527
528 llnext = loglist->next;
529 free(loglist->data);
530 free(loglist);
531 loglist = llnext;
532 }
533 iovec_trim_last(iovec_entries, iovector, r);
534}
535#endif
536
537static void stats_return_everything(char **reply, const char *reply_end) { 503static void stats_return_everything(char **reply, const char *reply_end) {
538 unsigned long long total[OT_COUNTER_COUNT]; 504 unsigned long long total[OT_COUNTER_COUNT];
539 505
@@ -546,10 +512,6 @@ static void stats_return_everything(char **reply, const char *reply_end) {
546 512
547 fmt_append(reply, reply_end, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 513 fmt_append(reply, reply_end, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
548 fmt_append(reply, reply_end, "<stats>\n"); 514 fmt_append(reply, reply_end, "<stats>\n");
549 fmt_append(reply, reply_end, " <tracker_id>%" PRIu32 "</tracker_id>\n", g_tracker_id);
550 fmt_append(reply, reply_end, " <version>\n");
551 stats_return_tracker_version(reply, reply_end);
552 fmt_append(reply, reply_end, " </version>\n");
553 fmt_append(reply, reply_end, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL) - ot_start_time)); 515 fmt_append(reply, reply_end, " <uptime>%llu</uptime>\n", (unsigned long long)(time(NULL) - ot_start_time));
554 fmt_append(reply, reply_end, " <torrents>\n"); 516 fmt_append(reply, reply_end, " <torrents>\n");
555 fmt_append(reply, reply_end, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count()); 517 fmt_append(reply, reply_end, " <count_mutex>%zd</count_mutex>\n", mutex_get_torrent_count());
@@ -580,10 +542,99 @@ static void stats_return_everything(char **reply, const char *reply_end) {
580 fmt_append(reply, reply_end, "</stats>"); 542 fmt_append(reply, reply_end, "</stats>");
581} 543}
582 544
545/* The names as the Makefile spells them, so that what a binary reports maps
546 straight back onto the FEATURES lines it was built from */
547static const char *const build_features[] = {
548#ifdef WANT_V4_ONLY
549 "WANT_V4_ONLY",
550#endif
551#ifdef WANT_ACCESSLIST_BLACK
552 "WANT_ACCESSLIST_BLACK",
553#endif
554#ifdef WANT_ACCESSLIST_WHITE
555 "WANT_ACCESSLIST_WHITE",
556#endif
557#ifdef WANT_DYNAMIC_ACCESSLIST
558 "WANT_DYNAMIC_ACCESSLIST",
559#endif
560#ifdef WANT_SYNC_LIVE
561 "WANT_SYNC_LIVE",
562#endif
563#ifdef WANT_IP_FROM_QUERY_STRING
564 "WANT_IP_FROM_QUERY_STRING",
565#endif
566#ifdef WANT_IP_FROM_PROXY
567 "WANT_IP_FROM_PROXY",
568#endif
569#ifdef WANT_COMPRESSION_GZIP
570 "WANT_COMPRESSION_GZIP",
571#endif
572#ifdef WANT_COMPRESSION_GZIP_ALWAYS
573 "WANT_COMPRESSION_GZIP_ALWAYS",
574#endif
575#ifdef WANT_COMPRESSION_ZSTD
576 "WANT_COMPRESSION_ZSTD",
577#endif
578#ifdef WANT_COMPRESSION_ZSTD_ALWAYS
579 "WANT_COMPRESSION_ZSTD_ALWAYS",
580#endif
581#ifdef WANT_FULLSCRAPE
582 "WANT_FULLSCRAPE",
583#endif
584#ifdef WANT_MODEST_FULLSCRAPES
585 "WANT_MODEST_FULLSCRAPES",
586#endif
587#ifdef WANT_KEEPALIVE
588 "WANT_KEEPALIVE",
589#endif
590#ifdef WANT_RESTRICT_STATS
591 "WANT_RESTRICT_STATS",
592#endif
593#ifdef WANT_LOG_NUMWANT
594 "WANT_LOG_NUMWANT",
595#endif
596#ifdef WANT_SPOT_WOODPECKER
597 "WANT_SPOT_WOODPECKER",
598#endif
599#ifdef WANT_SYSLOGS
600 "WANT_SYSLOGS",
601#endif
602#ifdef WANT_DEV_RANDOM
603 "WANT_DEV_RANDOM",
604#endif
605#ifdef WANT_INSECURE_RANDOM_FALLBACK
606 "WANT_INSECURE_RANDOM_FALLBACK",
607#endif
608#ifdef _DEBUG
609 "_DEBUG",
610#endif
611#ifdef _DEBUG_HTTPERROR
612 "_DEBUG_HTTPERROR",
613#endif
614#ifdef _DEBUG_RANDOMTORRENTS
615 "_DEBUG_RANDOMTORRENTS",
616#endif
617 NULL};
618
619void stats_return_tracker_features(char **reply, const char *reply_end) {
620 size_t i;
621
622 fmt_append(reply, reply_end, "events: %s\n", event_mechanism());
623 fmt_append(reply, reply_end, "features:");
624 for (i = 0; build_features[i]; ++i)
625 fmt_append(reply, reply_end, " %s", build_features[i]);
626 if (!build_features[0])
627 fmt_append(reply, reply_end, " none");
628 fmt_append(reply, reply_end, "\n");
629}
630
583void stats_return_tracker_version(char **reply, const char *reply_end) { 631void stats_return_tracker_version(char **reply, const char *reply_end) {
584#define QUOTE(name) #name 632 fmt_append(reply, reply_end, "opentracker %s", OT_VERSION);
585#define SQUOTE(name) QUOTE(name) 633 if (*GIT_VERSION && strcmp(GIT_VERSION, OT_TAG))
586 fmt_append(reply, reply_end, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION) "\n"); 634 fmt_append(reply, reply_end, " (%s)", GIT_VERSION);
635 fmt_append(reply, reply_end, "\n");
636 if (*OT_TAG)
637 fmt_append(reply, reply_end, "https://erdgeist.org/gitweb/opentracker/tag/?h=%s\n", OT_TAG);
587} 638}
588 639
589void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format) { 640void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format) {
@@ -610,9 +661,6 @@ void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int
610 case TASK_STATS_HTTPERRORS: 661 case TASK_STATS_HTTPERRORS:
611 stats_httperrors_txt(reply, reply_end); 662 stats_httperrors_txt(reply, reply_end);
612 break; 663 break;
613 case TASK_STATS_VERSION:
614 stats_return_tracker_version(reply, reply_end);
615 break;
616 case TASK_STATS_RENEW: 664 case TASK_STATS_RENEW:
617 stats_return_renew_bucket(reply, reply_end); 665 stats_return_renew_bucket(reply, reply_end);
618 break; 666 break;
@@ -671,11 +719,6 @@ static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_taskty
671 stats_return_woodpeckers(&r, r_end, 128); 719 stats_return_woodpeckers(&r, r_end, 128);
672 break; 720 break;
673#endif 721#endif
674#ifdef WANT_FULLLOG_NETWORKS
675 case TASK_STATS_FULLLOG:
676 stats_return_fulllog(iovec_entries, iovector, r);
677 return;
678#endif
679 default: 722 default:
680 iovec_free(iovec_entries, iovector); 723 iovec_free(iovec_entries, iovector);
681 return; 724 return;
@@ -693,9 +736,6 @@ void stats_issue_event(struct ot_workstruct *ws, ot_status_event event, PROTO_FL
693 COUNT(OT_COUNTER_TCP_CONNECTIONS, 1); 736 COUNT(OT_COUNTER_TCP_CONNECTIONS, 1);
694 else 737 else
695 COUNT(OT_COUNTER_UDP_CONNECTIONS, 1); 738 COUNT(OT_COUNTER_UDP_CONNECTIONS, 1);
696#ifdef WANT_LOG_NETWORKS
697 stat_increase_network_count(&stats_network_counters_root, 0, event_data);
698#endif
699 break; 739 break;
700 case EVENT_ANNOUNCE: 740 case EVENT_ANNOUNCE:
701 if (proto == FLAG_TCP) 741 if (proto == FLAG_TCP)
diff --git a/ot_stats.h b/ot_stats.h
index f484765..f9a9d87 100644
--- a/ot_stats.h
+++ b/ot_stats.h
@@ -35,6 +35,7 @@ void stats_deliver(int64_t sock, int tasktype);
35void stats_cleanup(void); 35void stats_cleanup(void);
36void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format); 36void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format);
37void stats_return_tracker_version(char **reply, const char *reply_end); 37void stats_return_tracker_version(char **reply, const char *reply_end);
38void stats_return_tracker_features(char **reply, const char *reply_end);
38void stats_init(void); 39void stats_init(void);
39void stats_deinit(void); 40void stats_deinit(void);
40 41
diff --git a/ot_sync.c b/ot_sync.c
deleted file mode 100644
index c19cf36..0000000
--- a/ot_sync.c
+++ /dev/null
@@ -1,165 +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 $id$ */
5
6/* System */
7#include <pthread.h>
8#include <stdio.h>
9#include <string.h>
10#include <sys/types.h>
11#include <sys/uio.h>
12
13/* Opentracker */
14#include "ot_fmt.h"
15#include "ot_iovec.h"
16#include "ot_mutex.h"
17#include "ot_workqueue.h"
18#include "ot_scan.h"
19#include "ot_stats.h"
20#include "ot_sync.h"
21#include "trackerlogic.h"
22
23#ifdef WANT_SYNC_BATCH
24
25#define OT_SYNC_CHUNK_SIZE (512 * 1024)
26
27/* Import Changeset from an external authority
28 format: d4:syncd[..]ee
29 [..]: ( 20:01234567890abcdefghij16:XXXXYYYY )+
30*/
31int add_changeset_to_tracker(uint8_t *data, size_t len) {
32 ot_hash *hash;
33 uint8_t *end = data + len;
34 uint64_t peer_count;
35
36 /* We do know, that the string is \n terminated, so it can't
37 overflow */
38 if (!memcmp(data, "d4:syncd", 8))
39 return -1;
40 data += 8;
41
42 while (1) {
43 if (!memcmp(data, "20:", 3)) {
44 if (!memcmp(data, "ee", 2))
45 return -1;
46 return 0;
47 }
48 data += 3;
49 hash = (ot_hash *)data;
50 data += sizeof(ot_hash);
51
52 /* Scan string length indicator, strictly: bencode writes no leading zeros */
53 data += (len = scan_uint_bencode((char *)data, &peer_count, (uint64_t)(end - data)));
54
55 /* If no long was scanned, it is not divisible by 8, it is not
56 followed by a colon or claims to need to much memory, we fail */
57 if (!len || !peer_count || (peer_count & 7) || (*data++ != ':') || (data + peer_count > end))
58 return -1;
59
60 while (peer_count > 0) {
61 add_peer_to_torrent(hash, (ot_peer *)data, 1);
62 data += 8;
63 peer_count -= 8;
64 }
65 }
66 return 0;
67}
68
69/* Proposed output format
70 d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee
71*/
72static void sync_make(size_t *iovec_entries, struct iovec **iovector) {
73 size_t bucket;
74 char *r, *re;
75
76 /* Setup return vector... */
77 *iovec_entries = 0;
78 *iovector = NULL;
79 if (!(r = iovec_new_chunk(iovec_entries, iovector, OT_SYNC_CHUNK_SIZE)))
80 return;
81
82 /* ... and pointer to end of current output buffer.
83 This works as a low watermark */
84 re = r + OT_SYNC_CHUNK_SIZE;
85
86 memmove(r, "d4:syncd", 8);
87 r += 8;
88
89 /* For each bucket... */
90 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
91 /* Get exclusive access to that bucket */
92 ot_vector *torrents_list = mutex_bucket_lock(bucket);
93 size_t tor_offset;
94
95 /* For each torrent in this bucket.. */
96 for (tor_offset = 0; tor_offset < torrents_list->size; ++tor_offset) {
97 /* Address torrents members */
98 ot_peerlist *peer_list = (((ot_torrent *)(torrents_list->data))[tor_offset]).peer_list;
99 ot_hash *hash = &(((ot_torrent *)(torrents_list->data))[tor_offset]).hash;
100 const size_t byte_count = sizeof(ot_peer) * peer_list->changeset.size;
101
102 /* If we reached our low watermark in buffer... */
103 if (re - r <= (ssize_t)(/* strlen( "20:" ) == */ 3 + sizeof(ot_hash) + /* strlen_max( "%zd" ) == */ 12 + byte_count)) {
104
105 /* Allocate a fresh output buffer at the end of our buffers list
106 release bucket and return, if that fails */
107 if (!(r = iovec_next_chunk(iovec_entries, iovector, r, OT_SYNC_CHUNK_SIZE)))
108 return mutex_bucket_unlock(bucket);
109
110 /* Adjust new end of output buffer */
111 re = r + OT_SYNC_CHUNK_SIZE;
112 }
113
114 fmt_append(&r, re, "20:");
115 fmt_bytes(&r, re, hash, sizeof(ot_hash));
116 fmt_append(&r, re, "%zd:", byte_count);
117 fmt_bytes(&r, re, peer_list->changeset.data, byte_count);
118 }
119
120 /* All torrents done: release lock on currenct bucket */
121 mutex_bucket_unlock(bucket);
122 }
123
124 /* Close bencoded sync dictionary */
125 *r++ = 'e';
126 *r++ = 'e';
127
128 /* Release unused memory in current output buffer */
129 iovec_trim_last(iovec_entries, iovector, r);
130}
131
132/* This is the entry point into this worker thread
133 It grabs tasks from mutex_tasklist and delivers results back
134*/
135static void *sync_worker(void *args) {
136 size_t iovec_entries;
137 struct iovec *iovector;
138
139 args = args;
140
141 while (1) {
142 ot_tasktype tasktype = TASK_SYNC_OUT;
143 ot_taskid taskid = workqueue_poptask(&tasktype);
144 sync_make(&iovec_entries, &iovector);
145 stats_issue_event(ws, EVENT_SYNC_OUT, FLAG_TCP, iovec_length(&iovec_entries, &iovector));
146 if (workqueue_pushresult(taskid, iovec_entries, iovector))
147 iovec_free(&iovec_entries, &iovector);
148 }
149 return NULL;
150}
151
152static pthread_t thread_id;
153void sync_init( ) {
154 pthread_create( &thread_id, NULL, sync_worker, NULL );
155}
156
157void sync_deinit( ) {
158 pthread_cancel( thread_id );
159}
160
161void sync_deliver( int64_t socket ) {
162 workqueue_pushtask( socket, TASK_SYNC_OUT );
163}
164
165#endif
diff --git a/ot_sync.h b/ot_sync.h
deleted file mode 100644
index b6964fa..0000000
--- a/ot_sync.h
+++ /dev/null
@@ -1,26 +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 $id$ */
5
6#ifndef OT_SYNC_H__
7#define OT_SYNC_H__
8
9#include <stdint.h>
10
11#ifdef WANT_SYNC_BATCH
12enum { SYNC_IN, SYNC_OUT };
13
14void sync_init();
15void sync_deinit();
16void sync_deliver(int64_t socket);
17
18int add_changeset_to_tracker(uint8_t *data, size_t len);
19#else
20
21#define sync_init()
22#define sync_deinit()
23
24#endif
25
26#endif
diff --git a/ot_workqueue.h b/ot_workqueue.h
index f99a7b5..4acd6fd 100644
--- a/ot_workqueue.h
+++ b/ot_workqueue.h
@@ -23,7 +23,6 @@ typedef enum {
23 TASK_STATS_FULLSCRAPE = 0x0005, 23 TASK_STATS_FULLSCRAPE = 0x0005,
24 TASK_STATS_TPB = 0x0006, 24 TASK_STATS_TPB = 0x0006,
25 TASK_STATS_HTTPERRORS = 0x0007, 25 TASK_STATS_HTTPERRORS = 0x0007,
26 TASK_STATS_VERSION = 0x0008,
27 TASK_STATS_RENEW = 0x000a, 26 TASK_STATS_RENEW = 0x000a,
28 TASK_STATS_SYNCS = 0x000b, 27 TASK_STATS_SYNCS = 0x000b,
29 TASK_STATS_COMPLETED = 0x000c, 28 TASK_STATS_COMPLETED = 0x000c,
@@ -36,7 +35,6 @@ typedef enum {
36 TASK_STATS_TOP10 = 0x0104, 35 TASK_STATS_TOP10 = 0x0104,
37 TASK_STATS_TOP100 = 0x0105, 36 TASK_STATS_TOP100 = 0x0105,
38 TASK_STATS_EVERYTHING = 0x0106, 37 TASK_STATS_EVERYTHING = 0x0106,
39 TASK_STATS_FULLLOG = 0x0107,
40 TASK_STATS_WOODPECKERS = 0x0108, 38 TASK_STATS_WOODPECKERS = 0x0108,
41 39
42 TASK_FULLSCRAPE = 0x0200, /* Default mode */ 40 TASK_FULLSCRAPE = 0x0200, /* Default mode */
diff --git a/proxy.c b/proxy.c
index b06e256..f6e90a3 100644
--- a/proxy.c
+++ b/proxy.c
@@ -3,6 +3,10 @@
3 3
4 $Id$ */ 4 $Id$ */
5 5
6/* This relays sync traffic between trackers, and between multicast domains
7 that have no route to each other, so that no tracker has to reach out to
8 the outside world by itself. Defunc. */
9
6/* System */ 10/* System */
7#include <arpa/inet.h> 11#include <arpa/inet.h>
8#include <ctype.h> 12#include <ctype.h>
diff --git a/tests/integration/test_stats.py b/tests/integration/test_stats.py
index 820b917..088d8a1 100644
--- a/tests/integration/test_stats.py
+++ b/tests/integration/test_stats.py
@@ -15,10 +15,10 @@ import xml.etree.ElementTree
15from harness import TrackerTestCase 15from harness import TrackerTestCase
16 16
17# The modes a default build answers. "tpbs" and "statedump" are full scrapes 17# The modes a default build answers. "tpbs" and "statedump" are full scrapes
18# and belong to test_fullscrape; "fulllog" and "woodpeckers" sit behind 18# and belong to test_fullscrape; "woodpeckers" sits behind a
19# feature flags this build does not set. 19# feature flag this build does not set.
20MRTG_MODES = ["peer", "conn", "scrp", "udp4", "tcp4", "torr", "fscr", "completed", "syncs"] 20MRTG_MODES = ["peer", "conn", "scrp", "udp4", "tcp4", "torr", "fscr", "completed", "syncs"]
21TEXT_MODES = ["herr", "s24s", "top10", "top100", "renew", "version"] 21TEXT_MODES = ["herr", "s24s", "top10", "top100", "renew"]
22 22
23 23
24class StatsShape(TrackerTestCase): 24class StatsShape(TrackerTestCase):
@@ -55,9 +55,22 @@ class StatsShape(TrackerTestCase):
55 self.assertIsNotNone(root.find("torrents/count_mutex")) 55 self.assertIsNotNone(root.find("torrents/count_mutex"))
56 self.assertIsNotNone(root.find("connections/tcp/announce")) 56 self.assertIsNotNone(root.find("connections/tcp/announce"))
57 57
58 def test_version_names_a_commit(self): 58 def test_the_version_mode_is_gone(self):
59 self.assertIn(b"opentracker", self.tracker.stats("version").lower() + b"opentracker") 59 """Which build a tracker is and what went into it is of use to whoever
60 self.assertRegex(self.tracker.stats("version"), rb"https?://") 60 attacks it and to nobody else on the far end of a socket. It is
61 reported by -v, to whoever already has the binary."""
62 with self.assertRaises(urllib.error.HTTPError) as caught:
63 self.tracker.stats("version")
64 self.assertEqual(caught.exception.code, 400, "an unknown mode, like any other")
65
66 def test_everything_does_not_name_the_build(self):
67 self.assertNotIn(b"opentracker 1", self.tracker.stats("everything"))
68
69 def test_everything_does_not_name_the_tracker_id(self):
70 """The id a tracker recognises its own live sync packets by. Knowing
71 it is of no use to a client and of some use to whoever would like a
72 tracker to discard what it is told."""
73 self.assertNotIn(b"tracker_id", self.tracker.stats("everything"))
61 74
62 75
63class StatsCount(TrackerTestCase): 76class StatsCount(TrackerTestCase):
diff --git a/tests/integration/test_version.py b/tests/integration/test_version.py
new file mode 100644
index 0000000..66f570d
--- /dev/null
+++ b/tests/integration/test_version.py
@@ -0,0 +1,36 @@
1"""The -v report, which is where a build says what went into it.
2
3Driving the binary is the only way to see this: the feature list is a table
4of #ifdefs, so it is only true for the flags the binary itself was built with.
5"""
6
7import subprocess
8import unittest
9
10from harness import TRACKER
11
12
13class VersionFlag(unittest.TestCase):
14 def report(self):
15 # -v writes to stderr and exits before it binds anything
16 done = subprocess.run([TRACKER, "-v"], capture_output=True, timeout=30)
17 self.assertEqual(done.returncode, 0, done.stderr)
18 return done.stderr.decode()
19
20 def test_first_line_names_the_release(self):
21 # The commit in brackets is there in a checkout and in a release
22 # tarball, and absent in a build that had neither to ask.
23 first = self.report().splitlines()[0]
24 self.assertRegex(first, r"^opentracker \d+\.\d+\.\d+( \(\S+\))?$")
25
26 def test_names_the_event_mechanism(self):
27 self.assertRegex(self.report(), r"(?m)^events: (epoll|kqueue|poll)$")
28
29 def test_lists_the_features_this_build_has(self):
30 # The Makefile builds this binary with these and not with those, so a
31 # feature table that stops following the build fails here.
32 report = self.report()
33 for want in ("WANT_KEEPALIVE", "WANT_ACCESSLIST_BLACK", "WANT_DYNAMIC_ACCESSLIST"):
34 self.assertIn(want, report)
35 for unwanted in ("WANT_SPOT_WOODPECKER", "WANT_V4_ONLY", "WANT_RESTRICT_STATS"):
36 self.assertNotIn(unwanted, report)
diff --git a/trackerlogic.h b/trackerlogic.h
index 53edabd..39afece 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -256,10 +256,6 @@ void workstruct_deinit(struct ot_workstruct *ws);
256#define WANT_SYNC_PARAM(param) 256#define WANT_SYNC_PARAM(param)
257#endif 257#endif
258 258
259#ifdef WANT_LOG_NETWORKS
260#error Live logging networks disabled at the moment.
261#endif
262
263void trackerlogic_init(void); 259void trackerlogic_init(void);
264void trackerlogic_deinit(void); 260void trackerlogic_deinit(void);
265void exerr(const char *message); 261void exerr(const char *message);