summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile26
-rw-r--r--Makefile.arc4random3
-rw-r--r--Makefile.gzip4
-rw-r--r--Makefile.zstd3
-rw-r--r--man1/opentracker.1130
-rw-r--r--man4/opentracker.conf.486
-rw-r--r--opentracker.c5
-rw-r--r--opentracker.conf.sample5
-rw-r--r--ot_accesslist.c2
-rw-r--r--ot_clean.c2
-rw-r--r--ot_fullscrape.c151
-rw-r--r--ot_http.c63
-rw-r--r--ot_http.h5
-rw-r--r--ot_iovec.c2
-rw-r--r--ot_livesync.c1
-rw-r--r--ot_mutex.c2
-rw-r--r--ot_mutex.h3
-rw-r--r--ot_rijndael.c2
-rw-r--r--ot_stats.c50
-rw-r--r--ot_stats.h4
-rw-r--r--ot_sync.c2
-rw-r--r--ot_udp.c2
-rw-r--r--ot_vector.c11
-rw-r--r--scan_urlencoded_query.c2
-rw-r--r--trackerlogic.c2
25 files changed, 478 insertions, 90 deletions
diff --git a/Makefile b/Makefile
index 6f9a82b..706b742 100644
--- a/Makefile
+++ b/Makefile
@@ -18,15 +18,24 @@ LIBOWFAT_LIBRARY=$(PREFIX)/libowfat
18BINDIR?=$(PREFIX)/bin 18BINDIR?=$(PREFIX)/bin
19STRIP?=strip 19STRIP?=strip
20 20
21#FEATURES+=-DWAND_V4_ONLY 21#FEATURES+=-DWANT_V4_ONLY
22#FEATURES+=-DWANT_ACCESSLIST_BLACK 22#FEATURES+=-DWANT_ACCESSLIST_BLACK
23#FEATURES+=-DWANT_ACCESSLIST_WHITE 23#FEATURES+=-DWANT_ACCESSLIST_WHITE
24#FEATURES+=-DWANT_DYNAMIC_ACCESSLIST 24#FEATURES+=-DWANT_DYNAMIC_ACCESSLIST
25 25
26#FEATURES+=-DWANT_SYNC_LIVE 26#FEATURES+=-DWANT_SYNC_LIVE
27#FEATURES+=-DWANT_IP_FROM_QUERY_STRING 27#FEATURES+=-DWANT_IP_FROM_QUERY_STRING
28FEATURES+=-DWANT_COMPRESSION_GZIP 28
29FEATURES+=-DWANT_COMPRESSION_GZIP_ALWAYS 29# If you want gzip support to be compiled in, uncomment the next include.
30# You can further modify the behaviour by setting DWANT_COMPRESSION_GZIP_ALWAYS
31# in Makefile.gzip
32include Makefile.gzip
33
34# If you want zstd support to be compiled in, uncomment the next include.
35# You can further modify the behaviour by setting DWANT_COMPRESSION_ZSTD_ALWAYS
36# in Makefile.zstd
37#include Makefile.zstd
38
30#FEATURES+=-DWANT_LOG_NETWORKS 39#FEATURES+=-DWANT_LOG_NETWORKS
31#FEATURES+=-DWANT_RESTRICT_STATS 40#FEATURES+=-DWANT_RESTRICT_STATS
32#FEATURES+=-DWANT_IP_FROM_PROXY 41#FEATURES+=-DWANT_IP_FROM_PROXY
@@ -43,18 +52,19 @@ FEATURES+=-DWANT_FULLSCRAPE
43#FEATURES+=-DWANT_NO_AUTO_FREE 52#FEATURES+=-DWANT_NO_AUTO_FREE
44 53
45# Is enabled on BSD systems by default in trackerlogic.h 54# Is enabled on BSD systems by default in trackerlogic.h
46# on Linux systems you will need -lbds 55# on Linux systems the include Makefile adds -lbsd
47#FEATURES+=-DWANT_ARC4RANDOM 56#include Makefile.arc4random
48 57
49#FEATURES+=-D_DEBUG_HTTPERROR 58#FEATURES+=-D_DEBUG_HTTPERROR
50#FEATURES+=-D_DEBUG_RANDOMTORRENTS 59#FEATURES+=-D_DEBUG_RANDOMTORRENTS
51 60
61GIT_VERSION=$(shell sh -c 'command -v git >/dev/null && test -d .git && git rev-parse HEAD || echo _git_or_commit_not_found_')
62
52OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage 63OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage
53OPTS_production=-O3 64OPTS_production=-O3
54 65
55CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -pthread -Wextra #-ansi -pedantic 66CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra #-ansi -pedantic
56LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz 67LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread
57#LDFLAGS+=-lbsd
58 68
59BINARY =opentracker 69BINARY =opentracker
60HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.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 70HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.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
diff --git a/Makefile.arc4random b/Makefile.arc4random
new file mode 100644
index 0000000..1488408
--- /dev/null
+++ b/Makefile.arc4random
@@ -0,0 +1,3 @@
1FEATURES+=-DWANT_ARC4RANDOM
2LDFLAGS+=-lbsd
3
diff --git a/Makefile.gzip b/Makefile.gzip
new file mode 100644
index 0000000..70d6d62
--- /dev/null
+++ b/Makefile.gzip
@@ -0,0 +1,4 @@
1FEATURES+=-DWANT_COMPRESSION_GZIP
2#FEATURES+=-DWANT_COMPRESSION_GZIP_ALWAYS
3
4LDFLAGS+=-lz
diff --git a/Makefile.zstd b/Makefile.zstd
new file mode 100644
index 0000000..2bb56be
--- /dev/null
+++ b/Makefile.zstd
@@ -0,0 +1,3 @@
1FEATURES+=-DWANT_COMPRESSION_ZSTD
2#FEATURES+=-DWANT_COMPRESSION_ZSTD_ALWAYS
3LDFLAGS+=-lzstd
diff --git a/man1/opentracker.1 b/man1/opentracker.1
new file mode 100644
index 0000000..0103ebe
--- /dev/null
+++ b/man1/opentracker.1
@@ -0,0 +1,130 @@
1.Dd 15/4/2024
2.Dt opentracker 1
3.Os Unix
4.Sh opentracker
5.Nm opentracker
6.Nd a free and open bittorrent tracker
7.Sh SYNOPSIS
8.Nm
9.Op Fl f Ar config
10.Op Fl i Ar ip-select
11.Op Fl p Ar port-bind-tcp
12.Op Fl P Ar port-bind-udp
13.Op Fl A Ar blessed-ip
14.Op Fl r Ar redirect-url
15.Op Fl d Ar chdir
16.Op Fl u Ar user
17.Op Fl w| Fl b accesslist
18.Sh DESCRIPTION
19.Nm
20is a bittorrent tracker that implements announce and scrape actions over the
21UDP and the plain http protocol, aiming for minimal resource usage.
22.Pp
23When invoked with parameters, it binds to TCP and UDP port 6969 on all
24interfaces. The recommended way to configure opentracker is by providing a
25config file using the
26.Op Fl f Ar config
27option. See
28.Xr opentracker.conf 4
29for details.
30.Pp
31.Sh OPTIONS
32The following options are available:
33.Bl -tag -width -indent=8
34.It Fl f Ar config
35Parse a config file with a list of options. Consecutive command options
36will override options from the config file. See
37.Xr opentracker.conf 4
38for details.
39.It Fl i Ar ip-select
40Select an ip address that will be used with the next
41.Op Fl p
42or
43.Op Fl P
44command to actually bind to this address. Setting this option without any bind
45options in the config file or
46.Op Fl p
47or
48.Op Fl P
49commands will limit opentracker to only bind to this address.
50.It Fl p Ar port-bind-tcp
51Bind to the TCP port on the last preceding ip address set with the
52.Op Fl i ip-select
53option or to all available addresses if none has been set. Can be given multiple
54times.
55.It Fl P Ar port-bind-udp
56Bind to the UDP port on the last preceding ip address set with the
57.Op Fl i ip-select
58option or to all available addresses if none has been set. Can be given multiple
59times.
60.It Fl A Ar blessed-ip
61Set an ip address in IPv4 or IPv6 or a net in CIDR notation to bless the network
62for access to restricted resources.
63.It Fl r Ar redirect-url
64Set the URL that
65.Nm
66will redirect users to when the / address is requested via HTTP.
67.It Fl d Ar chdir
68Sets the directory
69.Nm
70will
71.Xr chroot 2
72to if ran as root or
73.Xr chdir 2
74to if ran as unprivileged user. Note that any accesslist files need to be
75relative to and within that directory.
76.It Fl u Ar user
77User to run
78.Nm
79under after all operations that need privileges have finished.
80.It Fl w Ar accesslist | Fl b Ar accesslist
81If
82.Nm
83has been compiled with the
84.B WANT_ACCESSLIST_BLACK
85or
86.Br WANT_ACCESSLIST_WHITE
87options, this option sets the location of the accesslist.
88.El
89.Sh EXAMPLES
90Start
91.Nm
92bound on UDP and TCP ports 6969 on IPv6 localhost.
93.Dl # ./opentracker -i ::1 -p 6969 -P 6969
94.Pp
95Start
96.Nm
97bound on UDP port 6868 and TCP port 6868 on IPv4 localhost and allow
98privileged access from the network 192.168/16 while redirecting
99HTTP clients accessing the root directory, which is not covered by the
100bittorrent tracker protocol, to https://my-trackersite.com/.
101.Dl # ./opentracker -i 192.168.0.4 -p 6868 -P 6969 -A 192.168/16 -r https://my-trackersite.com/
102The announce URLs are http://192.168.0.4:6868/announce and
103udp://192.168.0.4:6868/announce respectively.
104.Sh FILES
105.Bl -tag -width indent
106.It Pa opentracker.conf
107The
108.Nm
109config file.
110.El
111.Sh SEE ALSO
112.Xr opentracker.conf 4
113.Pp
114opentracker documentation
115.Lk https://erdgeist.org/arts/software/opentracker
116.Pp
117Bittorrent tracker protocol
118.Lk http://www.bittorrent.org/beps/bep_0015.html
119.Sh AUTHOR
120.An Dirk Engling
121.Aq Mt erdgeist@erdgeist.org .
122.Sh LICENSE
123This software is released under the Beerware License:
124.Pp
125Permission is hereby granted, free of charge, to any person obtaining a copy of this software
126and associated documentation files (the "Software"), to deal in the Software with the following
127terms and conditions:
128.Pp
129If you meet the author(s) someday, and you think this software is worth it, you can buy them
130a beer in return.
diff --git a/man4/opentracker.conf.4 b/man4/opentracker.conf.4
new file mode 100644
index 0000000..2bc1389
--- /dev/null
+++ b/man4/opentracker.conf.4
@@ -0,0 +1,86 @@
1.Dd 2024-04-18
2.Dt opentracker.conf 5
3.Os Unix
4.Sh NAME
5.Nm opentracker.conf
6.Nd configuration file for opentracker
7.Sh SYNOPSIS
8.Nm
9.Sh DESCRIPTION
10The
11.Nm
12configuration file specifies various options for configuring the behavior of the opentracker program.
13.Pp
14Lines starting with '#' are comments and are ignored. Options are specified as 'keyword value' pairs.
15.Pp
16The following options are available:
17.Pp
18.Bl -tag -width ".It access.proxy" -compact
19.It listen.tcp_udp Ar address
20Specifies an address opentracker will listen on for both TCP and UDP connections. If none are specified, opentracker listens on 0.0.0.0:6969 by default. Can be added more than once.
21.Pp
22.It listen.tcp Ar address
23Specifies the address opentracker will listen on for TCP connections. Can be added more than once.
24.Pp
25.It listen.udp Ar address
26Specifies the address opentracker will listen on for UDP connections. Can be added more than once.
27.Pp
28.It listen.udp.workers Ar threads
29Specifies how many threads will be spawned to handle UDP connections. Defaults to 4.
30.Pp
31.It access.whitelist Ar path/to/whitelist
32Specifies the path to the whitelist file containing all torrent hashes that opentracker will serve. Use this option if opentracker runs in a non-open mode.
33.Pp
34.It access.blacklist Ar path/to/blacklist
35Specifies the path to the blacklist file containing all torrent hashes that opentracker will not serve. Use this option if opentracker was compiled to allow blacklisting.
36.Pp
37.It access.fifo_add Ar path/to/adder.fifo
38Specifies the path to the FIFO (named pipe) used for dynamic changesets to accesslists. Info hashes written to this FIFO will be added to the main accesslist file.
39.Pp
40.It access.fifo_delete Ar path/to/deleter.fifo
41Specifies the path to the FIFO (named pipe) used for dynamic changesets to accesslists. Info hashes written to this FIFO will be removed from the main accesslist file.
42.Pp
43.It access.stats Ar ip_address_or_network
44Specifies the IP address or network in CIDR notation allowed to fetch stats from opentracker.
45.Pp
46.It access.stats_path Ar path
47Specifies the path to the stats location. You can configure opentracker to appear anywhere on your tracker. Defaults to /stats.
48.Pp
49.It access.proxy Ar ip_address_or_network
50Specifies the IP address or network of the reverse proxies. Opentracker will take the X-Forwarded-For address instead of the source IP address. Can be added more than once.
51.Pp
52.It livesync.cluster.listen Ar ip_address:port
53Specifies the IP address and port opentracker will listen on for incoming live sync packets to keep a cluster of opentrackers synchronized.
54.Pp
55.It livesync.cluster.node_ip Ar ip_address
56Specifies one trusted IP address for sync between trackers running in a cluster. Can be added more than once.
57.Pp
58.It batchsync.cluster.admin_ip Ar ip_address
59Specifies the admin IP address for old-style (HTTP-based) asynchronous tracker syncing.
60.Pp
61.It tracker.rootdir Ar path
62Specifies the directory opentracker will chroot/chdir to. All black/white list files must be located in this directory.
63.Pp
64.It tracker.user Ar username
65Specifies the user opentracker will setuid to after binding to potentially privileged ports.
66.Pp
67.It tracker.redirect_url Ar URL
68Specifies the URL opentracker will redirect to in response to a "GET / HTTP" request.
69.El
70.Sh EXAMPLES
71To specify the address opentracker will listen on for both TCP and UDP connections:
72.Dl listen.tcp_udp 0.0.0.0:6969
73.Pp
74To specify the address opentracker will listen on for TCP connections:
75.Dl listen.tcp 0.0.0.0
76.Pp
77To specify the address opentracker will listen on for UDP connections:
78.Dl listen.udp 0.0.0.0:6969
79.Pp
80.Sh SEE ALSO
81.Xr opentracker 1
82.Pp
83.Sh AUTHOR
84.An Dirk Engling
85.Aq Mt erdgeist@erdgeist.org
86.Pp
diff --git a/opentracker.c b/opentracker.c
index 01cb501..14e9989 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -761,6 +761,8 @@ int main(int argc, char **argv) {
761 ot_try_bind(serverip, 6969, FLAG_UDP); 761 ot_try_bind(serverip, 6969, FLAG_UDP);
762 } 762 }
763 763
764 defaul_signal_handlers();
765
764#ifdef WANT_SYSLOGS 766#ifdef WANT_SYSLOGS
765 openlog("opentracker", 0, LOG_USER); 767 openlog("opentracker", 0, LOG_USER);
766 setlogmask(LOG_UPTO(LOG_INFO)); 768 setlogmask(LOG_UPTO(LOG_INFO));
@@ -783,7 +785,6 @@ int main(int argc, char **argv) {
783 io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE); 785 io_setcookie(g_self_pipe[0], (void *)FLAG_SELFPIPE);
784 io_wantread(g_self_pipe[0]); 786 io_wantread(g_self_pipe[0]);
785 787
786 defaul_signal_handlers();
787 /* Init all sub systems. This call may fail with an exit() */ 788 /* Init all sub systems. This call may fail with an exit() */
788 trackerlogic_init(); 789 trackerlogic_init();
789 790
@@ -805,5 +806,3 @@ int main(int argc, char **argv) {
805 806
806 return 0; 807 return 0;
807} 808}
808
809const char *g_version_opentracker_c = "$Source$: $Revision$\n";
diff --git a/opentracker.conf.sample b/opentracker.conf.sample
index f8bef43..054e405 100644
--- a/opentracker.conf.sample
+++ b/opentracker.conf.sample
@@ -2,7 +2,7 @@
2# 2#
3 3
4# I) Address opentracker will listen on, using both, tcp AND udp family 4# I) Address opentracker will listen on, using both, tcp AND udp family
5# (note, that port 6969 is implicite if ommitted). 5# (note, that port 6969 is implicit if omitted).
6# 6#
7# If no listen option is given (here or on the command line), opentracker 7# If no listen option is given (here or on the command line), opentracker
8# listens on 0.0.0.0:6969 tcp and udp. 8# listens on 0.0.0.0:6969 tcp and udp.
@@ -83,9 +83,10 @@
83# IIb) 83# IIb)
84# If you do not want to grant anyone access to your stats, enable the 84# If you do not want to grant anyone access to your stats, enable the
85# WANT_RESTRICT_STATS option in Makefile and bless the ip addresses 85# WANT_RESTRICT_STATS option in Makefile and bless the ip addresses
86# allowed to fetch stats here. 86# or network allowed to fetch stats here.
87# 87#
88# access.stats 192.168.0.23 88# access.stats 192.168.0.23
89# access.stats 10.1.1.23
89# 90#
90# There is another way of hiding your stats. You can obfuscate the path 91# There is another way of hiding your stats. You can obfuscate the path
91# to them. Normally it is located at /stats but you can configure it to 92# to them. Normally it is located at /stats but you can configure it to
diff --git a/ot_accesslist.c b/ot_accesslist.c
index c26e14a..4b88c40 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -559,5 +559,3 @@ int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) {
559 return 1; 559 return 1;
560 return 0; 560 return 0;
561} 561}
562
563const char *g_version_accesslist_c = "$Source$: $Revision$\n";
diff --git a/ot_clean.c b/ot_clean.c
index 2506cc1..291b847 100644
--- a/ot_clean.c
+++ b/ot_clean.c
@@ -142,5 +142,3 @@ static pthread_t thread_id;
142void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); } 142void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); }
143 143
144void clean_deinit(void) { pthread_cancel(thread_id); } 144void clean_deinit(void) { pthread_cancel(thread_id); }
145
146const char *g_version_clean_c = "$Source$: $Revision$\n";
diff --git a/ot_fullscrape.c b/ot_fullscrape.c
index d299ed9..6fd6d1c 100644
--- a/ot_fullscrape.c
+++ b/ot_fullscrape.c
@@ -14,6 +14,10 @@
14#ifdef WANT_COMPRESSION_GZIP 14#ifdef WANT_COMPRESSION_GZIP
15#include <zlib.h> 15#include <zlib.h>
16#endif 16#endif
17#ifdef WANT_COMPRESSION_ZSTD
18#include <zstd.h>
19#endif
20
17 21
18/* Libowfat */ 22/* Libowfat */
19#include "byte.h" 23#include "byte.h"
@@ -40,6 +44,9 @@ static void fullscrape_make(int taskid, ot_tasktype mode);
40#ifdef WANT_COMPRESSION_GZIP 44#ifdef WANT_COMPRESSION_GZIP
41static void fullscrape_make_gzip(int taskid, ot_tasktype mode); 45static void fullscrape_make_gzip(int taskid, ot_tasktype mode);
42#endif 46#endif
47#ifdef WANT_COMPRESSION_ZSTD
48static void fullscrape_make_zstd(int taskid, ot_tasktype mode);
49#endif
43 50
44/* Converter function from memory to human readable hex strings 51/* Converter function from memory to human readable hex strings
45 XXX - Duplicated from ot_stats. Needs fix. */ 52 XXX - Duplicated from ot_stats. Needs fix. */
@@ -64,6 +71,11 @@ static void *fullscrape_worker(void *args) {
64 while (g_opentracker_running) { 71 while (g_opentracker_running) {
65 ot_tasktype tasktype = TASK_FULLSCRAPE; 72 ot_tasktype tasktype = TASK_FULLSCRAPE;
66 ot_taskid taskid = mutex_workqueue_poptask(&tasktype); 73 ot_taskid taskid = mutex_workqueue_poptask(&tasktype);
74#ifdef WANT_COMPRESSION_ZSTD
75 if (tasktype & TASK_FLAG_ZSTD)
76 fullscrape_make_zstd(taskid, tasktype);
77 else
78#endif
67#ifdef WANT_COMPRESSION_GZIP 79#ifdef WANT_COMPRESSION_GZIP
68 if (tasktype & TASK_FLAG_GZIP) 80 if (tasktype & TASK_FLAG_GZIP)
69 fullscrape_make_gzip(taskid, tasktype); 81 fullscrape_make_gzip(taskid, tasktype);
@@ -205,7 +217,6 @@ static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
205 struct iovec iovector = {NULL, 0}; 217 struct iovec iovector = {NULL, 0};
206 int zres; 218 int zres;
207 z_stream strm; 219 z_stream strm;
208 fprintf(stderr, "GZIP path\n");
209 /* Setup return vector... */ 220 /* Setup return vector... */
210 iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE); 221 iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
211 if (!iovector.iov_base) 222 if (!iovector.iov_base)
@@ -267,8 +278,10 @@ static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
267 mutex_bucket_unlock(bucket, 0); 278 mutex_bucket_unlock(bucket, 0);
268 279
269 /* Parent thread died? */ 280 /* Parent thread died? */
270 if (!g_opentracker_running) 281 if (!g_opentracker_running) {
282 deflateEnd(&strm);
271 return; 283 return;
284 }
272 } 285 }
273 286
274 if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) { 287 if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
@@ -282,7 +295,8 @@ static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
282 iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base; 295 iovector.iov_len = (char *)strm.next_out - (char *)iovector.iov_base;
283 if (mutex_workqueue_pushchunked(taskid, &iovector)) { 296 if (mutex_workqueue_pushchunked(taskid, &iovector)) {
284 free(iovector.iov_base); 297 free(iovector.iov_base);
285 return mutex_bucket_unlock(bucket, 0); 298 deflateEnd(&strm);
299 return;
286 } 300 }
287 301
288 /* Check if there's a last batch of data in the zlib buffer */ 302 /* Check if there's a last batch of data in the zlib buffer */
@@ -293,7 +307,7 @@ static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
293 if (!iovector.iov_base) { 307 if (!iovector.iov_base) {
294 fprintf(stderr, "Problem with iovec_fix_increase_or_free\n"); 308 fprintf(stderr, "Problem with iovec_fix_increase_or_free\n");
295 deflateEnd(&strm); 309 deflateEnd(&strm);
296 return mutex_bucket_unlock(bucket, 0); 310 return;
297 } 311 }
298 strm.next_out = iovector.iov_base; 312 strm.next_out = iovector.iov_base;
299 strm.avail_out = OT_SCRAPE_CHUNK_SIZE; 313 strm.avail_out = OT_SCRAPE_CHUNK_SIZE;
@@ -311,6 +325,133 @@ static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
311/* WANT_COMPRESSION_GZIP */ 325/* WANT_COMPRESSION_GZIP */
312#endif 326#endif
313 327
328#ifdef WANT_COMPRESSION_ZSTD
329
330static void fullscrape_make_zstd(int taskid, ot_tasktype mode) {
331 int bucket;
332 char *r;
333 struct iovec iovector = {NULL, 0};
334 ZSTD_CCtx *zstream = ZSTD_createCCtx();
335 ZSTD_inBuffer inbuf;
336 ZSTD_outBuffer outbuf;
337 size_t more_bytes;
338
339 if (!zstream)
340 return;
341
342 /* Setup return vector... */
343 iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
344 if (!iovector.iov_base) {
345 ZSTD_freeCCtx(zstream);
346 return;
347 }
348
349 /* Working with a compression level 6 is half as fast as level 3, but
350 seems to be the last reasonable bump that's worth extra cpu */
351 ZSTD_CCtx_setParameter(zstream, ZSTD_c_compressionLevel, 6);
352
353 outbuf.dst = iovector.iov_base;
354 outbuf.size = OT_SCRAPE_CHUNK_SIZE;
355 outbuf.pos = 0;
356
357 if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
358 inbuf.src = (const void *)"d5:filesd";
359 inbuf.size = strlen("d5:filesd");
360 inbuf.pos = 0;
361 ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_continue);
362 }
363
364 /* For each bucket... */
365 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
366 /* Get exclusive access to that bucket */
367 ot_vector *torrents_list = mutex_bucket_lock(bucket);
368 ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
369 size_t i;
370
371 /* For each torrent in this bucket.. */
372 for (i = 0; i < torrents_list->size; ++i) {
373 char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
374 r = fullscrape_write_one(mode, compress_buffer, torrents + i, &torrents[i].hash);
375 inbuf.src = compress_buffer;
376 inbuf.size = r - compress_buffer;
377 inbuf.pos = 0;
378 ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_continue);
379
380 /* Check if there still is enough buffer left */
381 while (outbuf.pos + OT_SCRAPE_MAXENTRYLEN > outbuf.size) {
382 iovector.iov_len = outbuf.size;
383
384 if (mutex_workqueue_pushchunked(taskid, &iovector)) {
385 free(iovector.iov_base);
386 ZSTD_freeCCtx(zstream);
387 return mutex_bucket_unlock(bucket, 0);
388 }
389 /* Allocate a fresh output buffer */
390 iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
391 if (!iovector.iov_base) {
392 fprintf(stderr, "Out of memory trying to claim ouput buffer\n");
393 ZSTD_freeCCtx(zstream);
394 return mutex_bucket_unlock(bucket, 0);
395 }
396
397 outbuf.dst = iovector.iov_base;
398 outbuf.size = OT_SCRAPE_CHUNK_SIZE;
399 outbuf.pos = 0;
400
401 ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_continue);
402 }
403 }
404
405 /* All torrents done: release lock on current bucket */
406 mutex_bucket_unlock(bucket, 0);
407
408 /* Parent thread died? */
409 if (!g_opentracker_running)
410 return;
411 }
412
413 if ((mode & TASK_TASK_MASK) == TASK_FULLSCRAPE) {
414 inbuf.src = (const void *)"ee";
415 inbuf.size = strlen("ee");
416 inbuf.pos = 0;
417 }
418
419 more_bytes = ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_end);
420
421 iovector.iov_len = outbuf.pos;
422 if (mutex_workqueue_pushchunked(taskid, &iovector)) {
423 free(iovector.iov_base);
424 ZSTD_freeCCtx(zstream);
425 return;
426 }
427
428 /* Check if there's a last batch of data in the zlib buffer */
429 if (more_bytes) {
430 /* Allocate a fresh output buffer */
431 iovector.iov_base = malloc(OT_SCRAPE_CHUNK_SIZE);
432
433 if (!iovector.iov_base) {
434 fprintf(stderr, "Problem with iovec_fix_increase_or_free\n");
435 ZSTD_freeCCtx(zstream);
436 return;
437 }
438
439 outbuf.dst = iovector.iov_base;
440 outbuf.size = OT_SCRAPE_CHUNK_SIZE;
441 outbuf.pos = 0;
442
443 ZSTD_compressStream2(zstream, &outbuf, &inbuf, ZSTD_e_end);
444
445 /* Only pass the new buffer if there actually was some data left in the buffer */
446 iovector.iov_len = outbuf.pos;
447 if (!iovector.iov_len || mutex_workqueue_pushchunked(taskid, &iovector))
448 free(iovector.iov_base);
449 }
450
451 ZSTD_freeCCtx(zstream);
452}
453/* WANT_COMPRESSION_ZSTD */
454#endif
455
314/* WANT_FULLSCRAPE */ 456/* WANT_FULLSCRAPE */
315#endif 457#endif
316const char *g_version_fullscrape_c = "$Source$: $Revision$\n";
diff --git a/ot_http.c b/ot_http.c
index d825426..a87a02e 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -4,9 +4,9 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#define _GNU_SOURCE
7#include <arpa/inet.h> 8#include <arpa/inet.h>
8#include <pthread.h> 9#include <pthread.h>
9#define _GNU_SOURCE
10#include <stdio.h> 10#include <stdio.h>
11#include <stdlib.h> 11#include <stdlib.h>
12#include <string.h> 12#include <string.h>
@@ -32,7 +32,7 @@
32#include "trackerlogic.h" 32#include "trackerlogic.h"
33 33
34#ifdef WANT_NO_AUTO_FREE 34#ifdef WANT_NO_AUTO_FREE
35#define OT_IOB_INIT(B) bzero(B, sizeof(io_batch)) 35#define OT_IOB_INIT(B) (bzero(B, sizeof(io_batch)), 0)
36#else 36#else
37#define OT_IOB_INIT(B) iob_init_autofree(B, 0) 37#define OT_IOB_INIT(B) iob_init_autofree(B, 0)
38#endif 38#endif
@@ -88,7 +88,15 @@ static void http_senddata(const int64 sock, struct ot_workstruct *ws) {
88 memcpy(outbuf, ws->reply + written_size, ws->reply_size - written_size); 88 memcpy(outbuf, ws->reply + written_size, ws->reply_size - written_size);
89 if (!cookie->batch) { 89 if (!cookie->batch) {
90 cookie->batch = malloc(sizeof(io_batch)); 90 cookie->batch = malloc(sizeof(io_batch));
91 OT_IOB_INIT(cookie->batch); 91 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) {
92 free(cookie->batch);
93 free(outbuf);
94 array_reset(&cookie->request);
95 free(cookie);
96 io_close(sock);
97 return;
98 }
99
92 cookie->batches = 1; 100 cookie->batches = 1;
93 } 101 }
94 102
@@ -159,17 +167,19 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, int iovec
159 167
160 if (iovec_entries) { 168 if (iovec_entries) {
161 169
162 if (cookie->flag & STRUCT_HTTP_FLAG_GZIP) 170 if (cookie->flag & STRUCT_HTTP_FLAG_ZSTD)
171 encoding = "Content-Encoding: zstd\r\n";
172 else if (cookie->flag & STRUCT_HTTP_FLAG_GZIP)
163 encoding = "Content-Encoding: gzip\r\n"; 173 encoding = "Content-Encoding: gzip\r\n";
164 else if (cookie->flag & STRUCT_HTTP_FLAG_BZIP2) 174 else if (cookie->flag & STRUCT_HTTP_FLAG_BZIP2)
165 encoding = "Content-Encoding: bzip2\r\n"; 175 encoding = "Content-Encoding: bzip2\r\n";
166 176
167 if (!(cookie->flag & STRUCT_HTTP_FLAG_CHUNKED)) 177 if (!(cookie->flag & STRUCT_HTTP_FLAG_CHUNKED))
168 header_size = asprintf(&header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n%sContent-Length: %zd\r\n\r\n", encoding, size); 178 header_size = asprintf(&header, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n%sContent-Length: %zd\r\n\r\n", encoding, size);
169 else { 179 else {
170 if (!(cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) { 180 if (!(cookie->flag & STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) {
171 header_size = 181 header_size =
172 asprintf(&header, "HTTP/1.0 200 OK\r\nContent-Type: application/octet-stream\r\n%sTransfer-Encoding: chunked\r\n\r\n%zx\r\n", encoding, size); 182 asprintf(&header, "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\n%sTransfer-Encoding: chunked\r\n\r\n%zx\r\n", encoding, size);
173 cookie->flag |= STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER; 183 cookie->flag |= STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER;
174 } else 184 } else
175 header_size = asprintf(&header, "%zx\r\n", size); 185 header_size = asprintf(&header, "%zx\r\n", size);
@@ -181,12 +191,12 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, int iovec
181 191
182 if (!cookie->batch) { 192 if (!cookie->batch) {
183 cookie->batch = malloc(sizeof(io_batch)); 193 cookie->batch = malloc(sizeof(io_batch));
184 if (!cookie->batch) { 194 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) {
195 free(cookie->batch);
185 free(header); 196 free(header);
186 iovec_free(&iovec_entries, &iovector); 197 iovec_free(&iovec_entries, &iovector);
187 HTTPERROR_500; 198 HTTPERROR_500;
188 } 199 }
189 OT_IOB_INIT(cookie->batch);
190 cookie->batches = 1; 200 cookie->batches = 1;
191 } 201 }
192 current = cookie->batch + cookie->batches - 1; 202 current = cookie->batch + cookie->batches - 1;
@@ -199,8 +209,8 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, int iovec
199 io_batch *new_batch = realloc(cookie->batch, (cookie->batches + 1) * sizeof(io_batch)); 209 io_batch *new_batch = realloc(cookie->batch, (cookie->batches + 1) * sizeof(io_batch));
200 if (new_batch) { 210 if (new_batch) {
201 cookie->batch = new_batch; 211 cookie->batch = new_batch;
202 current = cookie->batch + cookie->batches++; 212 if (OT_IOB_INIT(current) != -1)
203 OT_IOB_INIT(current); 213 current = cookie->batch + cookie->batches++;
204 } 214 }
205 } 215 }
206 iob_addbuf_free(current, iovector[i].iov_base, iovector[i].iov_len); 216 iob_addbuf_free(current, iovector[i].iov_base, iovector[i].iov_len);
@@ -369,19 +379,34 @@ static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws
369 } 379 }
370#endif 380#endif
371 381
372#ifdef WANT_COMPRESSION_GZIP 382
383#if defined(WANT_COMPRESSION_GZIP) || defined(WANT_COMPRESSION_ZSTD)
373 ws->request[ws->request_size - 1] = 0; 384 ws->request[ws->request_size - 1] = 0;
374#ifndef WANT_COMPRESSION_GZIP_ALWAYS 385#ifdef WANT_COMPRESSION_GZIP
375 if (strstr(ws->request, "gzip")) { 386 if (strstr(ws->request, "gzip")) {
376#endif
377 cookie->flag |= STRUCT_HTTP_FLAG_GZIP; 387 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
378 format = TASK_FLAG_GZIP; 388 format |= TASK_FLAG_GZIP;
379 stats_issue_event(EVENT_FULLSCRAPE_REQUEST_GZIP, 0, (uintptr_t)cookie->ip); 389 }
380#ifndef WANT_COMPRESSION_GZIP_ALWAYS 390#endif
381 } else 391#ifdef WANT_COMPRESSION_ZSTD
392 if (strstr(ws->request, "zstd")) {
393 cookie->flag |= STRUCT_HTTP_FLAG_ZSTD;
394 format |= TASK_FLAG_ZSTD;
395 }
396#endif
397
398#if defined(WANT_COMPRESSION_ZSTD) && defined(WANT_COMPRESSION_ZSTD_ALWAYS)
399 cookie->flag |= STRUCT_HTTP_FLAG_ZSTD;
400 format |= TASK_FLAG_ZSTD;
401#endif
402
403#if defined(WANT_COMPRESSION_GZIP) && defined(WANT_COMPRESSION_GZIP_ALWAYS)
404 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
405 format |= TASK_FLAG_GZIP;
382#endif 406#endif
383#endif 407#endif
384 stats_issue_event(EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip); 408
409 stats_issue_event(EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip);
385 410
386#ifdef _DEBUG_HTTPERROR 411#ifdef _DEBUG_HTTPERROR
387 fprintf(stderr, "%s", ws->debugbuf); 412 fprintf(stderr, "%s", ws->debugbuf);
@@ -760,5 +785,3 @@ ssize_t http_handle_request(const int64 sock, struct ot_workstruct *ws) {
760 http_senddata(sock, ws); 785 http_senddata(sock, ws);
761 return ws->reply_size; 786 return ws->reply_size;
762} 787}
763
764const char *g_version_http_c = "$Source$: $Revision$\n";
diff --git a/ot_http.h b/ot_http.h
index fecb4eb..b5ae9ff 100644
--- a/ot_http.h
+++ b/ot_http.h
@@ -10,8 +10,9 @@ typedef enum {
10 STRUCT_HTTP_FLAG_WAITINGFORTASK = 1, 10 STRUCT_HTTP_FLAG_WAITINGFORTASK = 1,
11 STRUCT_HTTP_FLAG_GZIP = 2, 11 STRUCT_HTTP_FLAG_GZIP = 2,
12 STRUCT_HTTP_FLAG_BZIP2 = 4, 12 STRUCT_HTTP_FLAG_BZIP2 = 4,
13 STRUCT_HTTP_FLAG_CHUNKED = 8, 13 STRUCT_HTTP_FLAG_ZSTD = 8,
14 STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER = 16 14 STRUCT_HTTP_FLAG_CHUNKED = 16,
15 STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER = 32
15} STRUCT_HTTP_FLAG; 16} STRUCT_HTTP_FLAG;
16 17
17struct http_data { 18struct http_data {
diff --git a/ot_iovec.c b/ot_iovec.c
index 9fb30cc..8e94c52 100644
--- a/ot_iovec.c
+++ b/ot_iovec.c
@@ -90,5 +90,3 @@ size_t iovec_length(const int *iovec_entries, const struct iovec **iovector) {
90 length += ((*iovector)[i]).iov_len; 90 length += ((*iovector)[i]).iov_len;
91 return length; 91 return length;
92} 92}
93
94const char *g_version_iovec_c = "$Source$: $Revision$\n";
diff --git a/ot_livesync.c b/ot_livesync.c
index 246317b..269b8d8 100644
--- a/ot_livesync.c
+++ b/ot_livesync.c
@@ -237,4 +237,3 @@ static void *livesync_worker(void *args) {
237} 237}
238 238
239#endif 239#endif
240const char *g_version_livesync_c = "$Source$: $Revision$\n";
diff --git a/ot_mutex.c b/ot_mutex.c
index 1aa2783..3011987 100644
--- a/ot_mutex.c
+++ b/ot_mutex.c
@@ -270,5 +270,3 @@ void mutex_deinit() {
270 pthread_cond_destroy(&tasklist_being_filled); 270 pthread_cond_destroy(&tasklist_being_filled);
271 byte_zero(all_torrents, sizeof(all_torrents)); 271 byte_zero(all_torrents, sizeof(all_torrents));
272} 272}
273
274const char *g_version_mutex_c = "$Source$: $Revision$\n";
diff --git a/ot_mutex.h b/ot_mutex.h
index 66b627f..cdfabc9 100644
--- a/ot_mutex.h
+++ b/ot_mutex.h
@@ -59,7 +59,8 @@ typedef enum {
59 59
60 TASK_FLAG_GZIP = 0x1000, 60 TASK_FLAG_GZIP = 0x1000,
61 TASK_FLAG_BZIP2 = 0x2000, 61 TASK_FLAG_BZIP2 = 0x2000,
62 TASK_FLAG_CHUNKED = 0x4000, 62 TASK_FLAG_ZSTD = 0x4000,
63 TASK_FLAG_CHUNKED = 0x8000,
63 64
64 TASK_TASK_MASK = 0x0fff, 65 TASK_TASK_MASK = 0x0fff,
65 TASK_CLASS_MASK = 0x0f00, 66 TASK_CLASS_MASK = 0x0f00,
diff --git a/ot_rijndael.c b/ot_rijndael.c
index f468e2f..3f36bde 100644
--- a/ot_rijndael.c
+++ b/ot_rijndael.c
@@ -486,5 +486,3 @@ void rijndaelEncrypt128(const uint32_t rk[44], const uint8_t pt[16], uint8_t ct[
486 rk[43]; 486 rk[43];
487 PUTU32(ct + 12, s3); 487 PUTU32(ct + 12, s3);
488} 488}
489
490const char *g_version_rijndael_c = "$Source$: $Revision$\n";
diff --git a/ot_stats.c b/ot_stats.c
index fa456c3..b2eaec9 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -320,7 +320,7 @@ typedef struct {
320/* Fetches stats from tracker */ 320/* Fetches stats from tracker */
321size_t stats_top_txt(char *reply, int amount) { 321size_t stats_top_txt(char *reply, int amount) {
322 size_t j; 322 size_t j;
323 ot_record top100s[100], top100c[100]; 323 ot_record top100s[100], top100c[100], top100l[100];
324 char *r = reply, hex_out[42]; 324 char *r = reply, hex_out[42];
325 int idx, bucket; 325 int idx, bucket;
326 326
@@ -329,14 +329,16 @@ size_t stats_top_txt(char *reply, int amount) {
329 329
330 byte_zero(top100s, sizeof(top100s)); 330 byte_zero(top100s, sizeof(top100s));
331 byte_zero(top100c, sizeof(top100c)); 331 byte_zero(top100c, sizeof(top100c));
332 byte_zero(top100l, sizeof(top100l));
332 333
333 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 334 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
334 ot_vector *torrents_list = mutex_bucket_lock(bucket); 335 ot_vector *torrents_list = mutex_bucket_lock(bucket);
335 for (j = 0; j < torrents_list->size; ++j) { 336 for (j = 0; j < torrents_list->size; ++j) {
336 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j; 337 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j;
337 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; 338 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
338 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; 339 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
339 idx = amount - 1; 340 size_t leech_count = peer_count - seed_count;
341 idx = amount - 1;
340 while ((idx >= 0) && (peer_count > top100c[idx].val)) 342 while ((idx >= 0) && (peer_count > top100c[idx].val))
341 --idx; 343 --idx;
342 if (idx++ != amount - 1) { 344 if (idx++ != amount - 1) {
@@ -352,6 +354,14 @@ size_t stats_top_txt(char *reply, int amount) {
352 memcpy(&top100s[idx].hash, &torrent->hash, sizeof(ot_hash)); 354 memcpy(&top100s[idx].hash, &torrent->hash, sizeof(ot_hash));
353 top100s[idx].val = seed_count; 355 top100s[idx].val = seed_count;
354 } 356 }
357 idx = amount - 1;
358 while ((idx >= 0) && (leech_count > top100l[idx].val))
359 --idx;
360 if (idx++ != amount - 1) {
361 memmove(top100l + idx + 1, top100l + idx, (amount - 1 - idx) * sizeof(ot_record));
362 memcpy(&top100l[idx].hash, &torrent->hash, sizeof(ot_hash));
363 top100l[idx].val = leech_count;
364 }
355 } 365 }
356 mutex_bucket_unlock(bucket, 0); 366 mutex_bucket_unlock(bucket, 0);
357 if (!g_opentracker_running) 367 if (!g_opentracker_running)
@@ -366,6 +376,10 @@ size_t stats_top_txt(char *reply, int amount) {
366 for (idx = 0; idx < amount; ++idx) 376 for (idx = 0; idx < amount; ++idx)
367 if (top100s[idx].val) 377 if (top100s[idx].val)
368 r += sprintf(r, "\t%zd\t%s\n", top100s[idx].val, to_hex(hex_out, top100s[idx].hash)); 378 r += sprintf(r, "\t%zd\t%s\n", top100s[idx].val, to_hex(hex_out, top100s[idx].hash));
379 r += sprintf(r, "Top %d torrents by leechers:\n", amount);
380 for (idx = 0; idx < amount; ++idx)
381 if (top100l[idx].val)
382 r += sprintf(r, "\t%zd\t%s\n", top100l[idx].val, to_hex(hex_out, top100l[idx].hash));
369 383
370 return r - reply; 384 return r - reply;
371} 385}
@@ -476,9 +490,9 @@ static void stats_return_fulllog(int *iovec_entries, struct iovec **iovector, ch
476 return; 490 return;
477 re = r + 32 * OT_STATS_TMPSIZE; 491 re = r + 32 * OT_STATS_TMPSIZE;
478 } 492 }
479 r += sprintf(r, "%08ld: ", loglist->time); 493 r += sprintf(r, "%08ld: ", loglist->time);
480 r += fmt_ip6c(r, loglist->ip); 494 r += fmt_ip6c(r, loglist->ip);
481 *r++ = '\n'; 495 *r++ = '\n';
482 memcpy(r, loglist->data, loglist->size); 496 memcpy(r, loglist->data, loglist->size);
483 r += loglist->size; 497 r += loglist->size;
484 *r++ = '\n'; 498 *r++ = '\n';
@@ -518,10 +532,8 @@ static size_t stats_return_everything(char *reply) {
518 r += sprintf(r, " <completed>\n <count>%llu</count>\n </completed>\n", ot_overall_completed); 532 r += sprintf(r, " <completed>\n <count>%llu</count>\n </completed>\n", ot_overall_completed);
519 r += sprintf(r, " <connections>\n"); 533 r += sprintf(r, " <connections>\n");
520 r += sprintf(r, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n", 534 r += sprintf(r, " <tcp>\n <accept>%llu</accept>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n </tcp>\n",
521 ot_overall_tcp_connections, ot_overall_tcp_successfulannounces, ot_overall_tcp_successfulscrapes); 535 ot_overall_tcp_connections, ot_overall_tcp_successfulannounces, ot_overall_tcp_successfulscrapes);
522 r += sprintf( 536 r += sprintf(r, " <udp>\n <overall>%llu</overall>\n <connect>%llu</connect>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n <missmatch>%llu</missmatch>\n </udp>\n",
523 r,
524 " <udp>\n <overall>%llu</overall>\n <connect>%llu</connect>\n <announce>%llu</announce>\n <scrape>%llu</scrape>\n <missmatch>%llu</missmatch>\n </udp>\n",
525 ot_overall_udp_connections, ot_overall_udp_connects, ot_overall_udp_successfulannounces, ot_overall_udp_successfulscrapes, 537 ot_overall_udp_connections, ot_overall_udp_connects, ot_overall_udp_successfulannounces, ot_overall_udp_successfulscrapes,
526 ot_overall_udp_connectionidmissmatches); 538 ot_overall_udp_connectionidmissmatches);
527 r += sprintf(r, " <livesync>\n <count>%llu</count>\n </livesync>\n", ot_overall_sync_count); 539 r += sprintf(r, " <livesync>\n <count>%llu</count>\n </livesync>\n", ot_overall_sync_count);
@@ -541,14 +553,10 @@ static size_t stats_return_everything(char *reply) {
541 return r - reply; 553 return r - reply;
542} 554}
543 555
544extern const char *g_version_opentracker_c, *g_version_accesslist_c, *g_version_clean_c, *g_version_fullscrape_c, *g_version_http_c, *g_version_iovec_c,
545 *g_version_mutex_c, *g_version_stats_c, *g_version_udp_c, *g_version_vector_c, *g_version_scan_urlencoded_query_c, *g_version_trackerlogic_c,
546 *g_version_livesync_c, *g_version_rijndael_c;
547
548size_t stats_return_tracker_version(char *reply) { 556size_t stats_return_tracker_version(char *reply) {
549 return sprintf(reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", g_version_opentracker_c, g_version_accesslist_c, g_version_clean_c, g_version_fullscrape_c, 557#define QUOTE(name) #name
550 g_version_http_c, g_version_iovec_c, g_version_mutex_c, g_version_stats_c, g_version_udp_c, g_version_vector_c, 558#define SQUOTE(name) QUOTE(name)
551 g_version_scan_urlencoded_query_c, g_version_trackerlogic_c, g_version_livesync_c, g_version_rijndael_c); 559 return sprintf(reply, "https://erdgeist.org/gitweb/opentracker/commit/?id=" SQUOTE(GIT_VERSION) "\n");
552} 560}
553 561
554size_t return_stats_for_tracker(char *reply, int mode, int format) { 562size_t return_stats_for_tracker(char *reply, int mode, int format) {
@@ -775,5 +783,3 @@ void stats_init() {
775void stats_deinit() { 783void stats_deinit() {
776 pthread_cancel(thread_id); 784 pthread_cancel(thread_id);
777} 785}
778
779const char *g_version_stats_c = "$Source$: $Revision$\n";
diff --git a/ot_stats.h b/ot_stats.h
index a354c19..8ed2b1e 100644
--- a/ot_stats.h
+++ b/ot_stats.h
@@ -19,6 +19,7 @@ typedef enum {
19 EVENT_SCRAPE, 19 EVENT_SCRAPE,
20 EVENT_FULLSCRAPE_REQUEST, 20 EVENT_FULLSCRAPE_REQUEST,
21 EVENT_FULLSCRAPE_REQUEST_GZIP, 21 EVENT_FULLSCRAPE_REQUEST_GZIP,
22 EVENT_FULLSCRAPE_REQUEST_ZSTD,
22 EVENT_FULLSCRAPE, /* TCP only */ 23 EVENT_FULLSCRAPE, /* TCP only */
23 EVENT_FAILED, 24 EVENT_FAILED,
24 EVENT_BUCKET_LOCKED, 25 EVENT_BUCKET_LOCKED,
@@ -48,7 +49,4 @@ size_t stats_return_tracker_version(char *reply);
48void stats_init(void); 49void stats_init(void);
49void stats_deinit(void); 50void stats_deinit(void);
50 51
51extern const char *g_version_rijndael_c;
52extern const char *g_version_livesync_c;
53
54#endif 52#endif
diff --git a/ot_sync.c b/ot_sync.c
index 259d4de..293acf3 100644
--- a/ot_sync.c
+++ b/ot_sync.c
@@ -170,5 +170,3 @@ void sync_deliver( int64 socket ) {
170} 170}
171 171
172#endif 172#endif
173
174const char *g_version_sync_c = "$Source$: $Revision$\n";
diff --git a/ot_udp.c b/ot_udp.c
index 912c7e4..97ccd38 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -234,5 +234,3 @@ void udp_init(int64 sock, unsigned int worker_count) {
234 while (worker_count--) 234 while (worker_count--)
235 pthread_create(&thread_id, NULL, udp_worker, (void *)sock); 235 pthread_create(&thread_id, NULL, udp_worker, (void *)sock);
236} 236}
237
238const char *g_version_udp_c = "$Source$: $Revision$\n";
diff --git a/ot_vector.c b/ot_vector.c
index 744306f..2acfbef 100644
--- a/ot_vector.c
+++ b/ot_vector.c
@@ -67,12 +67,15 @@ void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, si
67 return match; 67 return match;
68 68
69 if (vector->size + 1 > vector->space) { 69 if (vector->size + 1 > vector->space) {
70 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 70 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
71 uint8_t *new_data = realloc(vector->data, new_space * member_size); 71 ptrdiff_t match_off = match - (uint8_t *)vector->data;
72 uint8_t *new_data = realloc(vector->data, new_space * member_size);
73
72 if (!new_data) 74 if (!new_data)
73 return NULL; 75 return NULL;
76
74 /* Adjust pointer if it moved by realloc */ 77 /* Adjust pointer if it moved by realloc */
75 match = new_data + (match - (uint8_t *)vector->data); 78 match = new_data + match_off;
76 79
77 vector->data = new_data; 80 vector->data = new_data;
78 vector->space = new_space; 81 vector->space = new_space;
@@ -282,5 +285,3 @@ void vector_fixup_peers(ot_vector *vector, size_t peer_size) {
282 if (need_fix) 285 if (need_fix)
283 vector->data = realloc(vector->data, vector->space * peer_size); 286 vector->data = realloc(vector->data, vector->space * peer_size);
284} 287}
285
286const char *g_version_vector_c = "$Source$: $Revision$\n";
diff --git a/scan_urlencoded_query.c b/scan_urlencoded_query.c
index 2d3599d..38d544a 100644
--- a/scan_urlencoded_query.c
+++ b/scan_urlencoded_query.c
@@ -162,5 +162,3 @@ ssize_t scan_fixed_int(char *data, size_t len, int *tmp) {
162 *tmp = -*tmp; 162 *tmp = -*tmp;
163 return len; 163 return len;
164} 164}
165
166const char *g_version_scan_urlencoded_query_c = "$Source$: $Revision$\n";
diff --git a/trackerlogic.c b/trackerlogic.c
index 6cc239e..04df544 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -596,5 +596,3 @@ void trackerlogic_deinit(void) {
596 /* Release mutexes */ 596 /* Release mutexes */
597 mutex_deinit(); 597 mutex_deinit();
598} 598}
599
600const char *g_version_trackerlogic_c = "$Source$: $Revision$\n";