diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Makefile | 90 | ||||
| -rw-r--r-- | man1/opentracker.1 | 4 | ||||
| -rw-r--r-- | man4/opentracker.conf.4 | 3 | ||||
| -rw-r--r-- | opentracker.conf.sample | 6 | ||||
| -rw-r--r-- | ot_accesslist.c | 28 | ||||
| -rw-r--r-- | ot_accesslist.h | 16 | ||||
| -rw-r--r-- | ot_config.c | 2 | ||||
| -rw-r--r-- | ot_http.c | 69 | ||||
| -rw-r--r-- | ot_stats.c | 146 | ||||
| -rw-r--r-- | ot_stats.h | 1 | ||||
| -rw-r--r-- | ot_sync.c | 165 | ||||
| -rw-r--r-- | ot_sync.h | 26 | ||||
| -rw-r--r-- | ot_workqueue.h | 2 | ||||
| -rw-r--r-- | proxy.c | 4 | ||||
| -rw-r--r-- | tests/integration/test_stats.py | 25 | ||||
| -rw-r--r-- | tests/integration/test_version.py | 36 | ||||
| -rw-r--r-- | trackerlogic.h | 4 |
18 files changed, 214 insertions, 416 deletions
| @@ -9,3 +9,6 @@ proxy.debug | |||
| 9 | tests/runner | 9 | tests/runner |
| 10 | tests/runner.poll | 10 | tests/runner.poll |
| 11 | tests/runner.sanitize | 11 | tests/runner.sanitize |
| 12 | .buildstamp | ||
| 13 | .tarball-version | ||
| 14 | opentracker-*.tar.gz | ||
| @@ -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 | ||
| 14 | PREFIX?=.. | 3 | PREFIX?=.. |
| 15 | LIBOWFAT_HEADERS=$(PREFIX)/libowfat | ||
| 16 | LIBOWFAT_LIBRARY=$(PREFIX)/libowfat | ||
| 17 | |||
| 18 | BINDIR?=$(PREFIX)/bin | 4 | BINDIR?=$(PREFIX)/bin |
| 19 | STRIP?=strip | 5 | STRIP?=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 | ||
| 58 | GIT_VERSION=`sh -c 'command -v git >/dev/null && test -d .git && git rev-parse HEAD || echo _git_or_commit_not_found_'` | 42 | VERSION=1.0.0 |
| 43 | TARBALL_VERSION=test -r .tarball-version && read v < .tarball-version && echo "$$v" | ||
| 44 | HAVE_GIT=command -v git >/dev/null && test -d .git | ||
| 45 | GIT_VERSION=`sh -c '$(TARBALL_VERSION) || { $(HAVE_GIT) && git describe --tags --match "v*" --always --dirty 2>/dev/null; }'` | ||
| 46 | OT_TAG=`sh -c '$(TARBALL_VERSION) || { $(HAVE_GIT) && git describe --tags --match "v*" --exact-match 2>/dev/null; }'` | ||
| 59 | 47 | ||
| 60 | OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage | 48 | OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage |
| 61 | OPTS_production=-O3 | 49 | OPTS_production=-O3 |
| 62 | 50 | ||
| 63 | CFLAGS+=-DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra -Wwrite-strings #-ansi -pedantic | 51 | CFLAGS+=-DOT_VERSION=\"$(VERSION)\" -DGIT_VERSION=\"$(GIT_VERSION)\" -DOT_TAG=\"$(OT_TAG)\" -Wall -pipe -pthread -Wextra -Wwrite-strings #-ansi -pedantic |
| 64 | LDFLAGS+=-pthread | 52 | LDFLAGS+=-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. | 55 | BUILDSTAMP=.buildstamp |
| 68 | CFLAGS_libowfat=-I$(LIBOWFAT_HEADERS) | 56 | BUILDDEPS=Makefile $(BUILDSTAMP) |
| 69 | LDFLAGS_libowfat=-L$(LIBOWFAT_LIBRARY) -lowfat | 57 | |
| 58 | $(BUILDSTAMP): FORCE | ||
| 59 | @echo "$(CFLAGS) $(FEATURES) $(LDFLAGS)" | cmp -s - $@ 2>/dev/null || echo "$(CFLAGS) $(FEATURES) $(LDFLAGS)" > $@ | ||
| 60 | |||
| 61 | FORCE: | ||
| 70 | 62 | ||
| 71 | BINARY =opentracker | 63 | BINARY =opentracker |
| 72 | 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 | 64 | 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 |
| 73 | 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 | 65 | 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 |
| 74 | 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 | ||
| 75 | 66 | ||
| 76 | all: $(BINARY) $(BINARY).debug | 67 | all: $(BINARY) $(BINARY).debug |
| 77 | 68 | ||
| 78 | CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES) | 69 | CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES) |
| 79 | CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES) | 70 | CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES) |
| 80 | 71 | ||
| 81 | CFLAGS_proxy = $(CFLAGS_production) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE | 72 | $(BINARY): $(SOURCES) $(HEADERS) $(BUILDDEPS) |
| 82 | CFLAGS_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) |
| 89 | proxy: $(SOURCES_proxy) $(HEADERS) | 77 | |
| 90 | $(CC) -o $@ $(CFLAGS_proxy) $(SOURCES_proxy) $(LDFLAGS) $(LDFLAGS_libowfat) | 78 | # The proxy is out of service |
| 91 | proxy.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) | |||
| 104 | FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE | 99 | FEATURES_test=$(FEATURES) -DWANT_ACCESSLIST_BLACK -DWANT_SYNC_LIVE |
| 105 | CFLAGS_test = $(CFLAGS) -I. -g -O1 $(FEATURES_test) | 100 | CFLAGS_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 | ||
| 110 | check: $(TESTBIN) $(BINARY) | 105 | check: $(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 | ||
| 116 | check-poll: $(TESTBIN).poll | 111 | check-poll: $(TESTBIN).poll |
| @@ -123,7 +118,7 @@ CC_sanitize?=clang | |||
| 123 | CFLAGS_sanitize=$(CFLAGS_test) -fsanitize=address,undefined -fno-omit-frame-pointer | 118 | CFLAGS_sanitize=$(CFLAGS_test) -fsanitize=address,undefined -fno-omit-frame-pointer |
| 124 | LDFLAGS_sanitize=$(LDFLAGS) -fsanitize=address,undefined | 119 | LDFLAGS_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 | ||
| 129 | check-sanitize: $(TESTBIN).sanitize | 124 | check-sanitize: $(TESTBIN).sanitize |
| @@ -140,7 +135,7 @@ FEATURES_integration=$(FEATURES) -DWANT_IP_FROM_QUERY_STRING -DWANT_ACCESSLIST_B | |||
| 140 | CFLAGS_integration=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=address,undefined -fno-omit-frame-pointer | 135 | CFLAGS_integration=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=address,undefined -fno-omit-frame-pointer |
| 141 | LDFLAGS_integration=$(LDFLAGS) -fsanitize=address,undefined | 136 | LDFLAGS_integration=$(LDFLAGS) -fsanitize=address,undefined |
| 142 | 137 | ||
| 143 | opentracker.integration: $(SOURCES) $(HEADERS) | 138 | opentracker.integration: $(SOURCES) $(HEADERS) $(BUILDDEPS) |
| 144 | $(CC) -o $@ $(CFLAGS_integration) $(SOURCES) $(LDFLAGS_integration) | 139 | $(CC) -o $@ $(CFLAGS_integration) $(SOURCES) $(LDFLAGS_integration) |
| 145 | 140 | ||
| 146 | check-integration: opentracker.integration | 141 | check-integration: opentracker.integration |
| @@ -150,7 +145,7 @@ check-integration: opentracker.integration | |||
| 150 | CFLAGS_tsan=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=thread -fno-omit-frame-pointer | 145 | CFLAGS_tsan=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=thread -fno-omit-frame-pointer |
| 151 | LDFLAGS_tsan=$(LDFLAGS) -fsanitize=thread | 146 | LDFLAGS_tsan=$(LDFLAGS) -fsanitize=thread |
| 152 | 147 | ||
| 153 | opentracker.tsan: $(SOURCES) $(HEADERS) | 148 | opentracker.tsan: $(SOURCES) $(HEADERS) $(BUILDDEPS) |
| 154 | $(CC) -o $@ $(CFLAGS_tsan) $(SOURCES) $(LDFLAGS_tsan) | 149 | $(CC) -o $@ $(CFLAGS_tsan) $(SOURCES) $(LDFLAGS_tsan) |
| 155 | 150 | ||
| 156 | check-tsan: opentracker.tsan | 151 | check-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 | ||
| 169 | BINARIES=opentracker opentracker.debug opentracker.integration opentracker.tsan proxy proxy.debug $(TESTBIN) $(TESTBIN).sanitize $(TESTBIN).poll | 164 | BINARIES=opentracker opentracker.debug opentracker.integration opentracker.tsan $(TESTBIN) $(TESTBIN).sanitize $(TESTBIN).poll |
| 170 | 165 | ||
| 171 | clean: | 166 | clean: |
| 172 | rm -rf $(BINARIES) $(BINARIES:=.dSYM) *.o *~ | 167 | rm -rf $(BINARIES) $(BINARIES:=.dSYM) $(BUILDSTAMP) *.o *~ |
| 173 | 168 | ||
| 174 | install: | 169 | install: |
| 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. | ||
| 176 | DISTNAME=opentracker-$(VERSION) | ||
| 177 | |||
| 178 | dist: | ||
| 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 |
| 20 | is a bittorrent tracker that implements announce and scrape actions over the | 21 | is a bittorrent tracker that implements announce and scrape actions over the |
| @@ -85,6 +86,9 @@ has been compiled with the | |||
| 85 | or | 86 | or |
| 86 | .Br WANT_ACCESSLIST_WHITE | 87 | .Br WANT_ACCESSLIST_WHITE |
| 87 | options, this option sets the location of the accesslist. | 88 | options, this option sets the location of the accesslist. |
| 89 | .It Fl v | ||
| 90 | Report the version, the event mechanism in use and the feature flags this | ||
| 91 | binary was built with. | ||
| 88 | .El | 92 | .El |
| 89 | .Sh EXAMPLES | 93 | .Sh EXAMPLES |
| 90 | Start | 94 | Start |
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 |
| 85 | Specifies one trusted IP address for sync between trackers running in a cluster. Can be added more than once. | 85 | Specifies 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 | ||
| 88 | Specifies 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 |
| 91 | Specifies the directory opentracker will chroot/chdir to. All black/white list files must be located in this directory. | 88 | Specifies 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 | ||
| 507 | static ot_vector g_lognets_list; | ||
| 508 | ot_log *g_logchain_first, *g_logchain_last; | ||
| 509 | static pthread_mutex_t g_lognets_list_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
| 510 | |||
| 511 | void 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 | |||
| 517 | void 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 | |||
| 525 | int 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 |
| 535 | typedef struct { | 507 | typedef 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); | |||
| 66 | int proxylist_check_network(const ot_ip6 *proxy, const ot_ip6 address /* can be NULL to only check proxy */); | 66 | int 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 | ||
| 70 | typedef struct ot_log ot_log; | ||
| 71 | struct ot_log { | ||
| 72 | ot_ip6 ip; | ||
| 73 | uint8_t *data; | ||
| 74 | size_t size; | ||
| 75 | ot_time time; | ||
| 76 | ot_log *next; | ||
| 77 | }; | ||
| 78 | extern ot_log *g_logchain_first, *g_logchain_last; | ||
| 79 | |||
| 80 | void loglist_add_network(const ot_net *net); | ||
| 81 | void loglist_reset(void); | ||
| 82 | int loglist_check_address(const ot_ip6 address); | ||
| 83 | #endif | ||
| 84 | |||
| 85 | typedef enum { | 69 | typedef 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); |
| @@ -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}}; | ||
| 566 | static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; | 561 | static 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) |
| @@ -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 | ||
| 121 | static stats_network_node *stats_network_counters_root; | ||
| 122 | #endif | ||
| 123 | |||
| 124 | static int stat_increase_network_count(stats_network_node **pnode, int depth, uintptr_t ip) { | 120 | static 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 | ||
| 508 | static 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 | |||
| 537 | static void stats_return_everything(char **reply, const char *reply_end) { | 503 | static 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 */ | ||
| 547 | static 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 | |||
| 619 | void 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 | |||
| 583 | void stats_return_tracker_version(char **reply, const char *reply_end) { | 631 | void 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 | ||
| 589 | void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format) { | 640 | void 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) |
| @@ -35,6 +35,7 @@ void stats_deliver(int64_t sock, int tasktype); | |||
| 35 | void stats_cleanup(void); | 35 | void stats_cleanup(void); |
| 36 | void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format); | 36 | void return_stats_for_tracker(char **reply, const char *reply_end, int mode, int format); |
| 37 | void stats_return_tracker_version(char **reply, const char *reply_end); | 37 | void stats_return_tracker_version(char **reply, const char *reply_end); |
| 38 | void stats_return_tracker_features(char **reply, const char *reply_end); | ||
| 38 | void stats_init(void); | 39 | void stats_init(void); |
| 39 | void stats_deinit(void); | 40 | void 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 | */ | ||
| 31 | int 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 | */ | ||
| 72 | static 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 | */ | ||
| 135 | static 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 | |||
| 152 | static pthread_t thread_id; | ||
| 153 | void sync_init( ) { | ||
| 154 | pthread_create( &thread_id, NULL, sync_worker, NULL ); | ||
| 155 | } | ||
| 156 | |||
| 157 | void sync_deinit( ) { | ||
| 158 | pthread_cancel( thread_id ); | ||
| 159 | } | ||
| 160 | |||
| 161 | void 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 | ||
| 12 | enum { SYNC_IN, SYNC_OUT }; | ||
| 13 | |||
| 14 | void sync_init(); | ||
| 15 | void sync_deinit(); | ||
| 16 | void sync_deliver(int64_t socket); | ||
| 17 | |||
| 18 | int 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 */ |
| @@ -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 | |||
| 15 | from harness import TrackerTestCase | 15 | from 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. |
| 20 | MRTG_MODES = ["peer", "conn", "scrp", "udp4", "tcp4", "torr", "fscr", "completed", "syncs"] | 20 | MRTG_MODES = ["peer", "conn", "scrp", "udp4", "tcp4", "torr", "fscr", "completed", "syncs"] |
| 21 | TEXT_MODES = ["herr", "s24s", "top10", "top100", "renew", "version"] | 21 | TEXT_MODES = ["herr", "s24s", "top10", "top100", "renew"] |
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | class StatsShape(TrackerTestCase): | 24 | class 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 | ||
| 63 | class StatsCount(TrackerTestCase): | 76 | class 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 | |||
| 3 | Driving the binary is the only way to see this: the feature list is a table | ||
| 4 | of #ifdefs, so it is only true for the flags the binary itself was built with. | ||
| 5 | """ | ||
| 6 | |||
| 7 | import subprocess | ||
| 8 | import unittest | ||
| 9 | |||
| 10 | from harness import TRACKER | ||
| 11 | |||
| 12 | |||
| 13 | class 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 | |||
| 263 | void trackerlogic_init(void); | 259 | void trackerlogic_init(void); |
| 264 | void trackerlogic_deinit(void); | 260 | void trackerlogic_deinit(void); |
| 265 | void exerr(const char *message); | 261 | void exerr(const char *message); |
