summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile22
-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.c11
-rw-r--r--opentracker.conf.sample5
-rw-r--r--ot_accesslist.c18
-rw-r--r--ot_accesslist.h2
-rw-r--r--ot_clean.c6
-rw-r--r--ot_fullscrape.c160
-rw-r--r--ot_fullscrape.h4
-rw-r--r--ot_http.c83
-rw-r--r--ot_http.h7
-rw-r--r--ot_iovec.c21
-rw-r--r--ot_iovec.h12
-rw-r--r--ot_livesync.c10
-rw-r--r--ot_mutex.c18
-rw-r--r--ot_mutex.h7
-rw-r--r--ot_stats.c97
-rw-r--r--ot_stats.h1
-rw-r--r--ot_sync.c8
-rw-r--r--ot_udp.c30
-rw-r--r--ot_vector.c17
-rw-r--r--ot_vector.h2
-rw-r--r--proxy.c6
-rw-r--r--trackerlogic.c20
-rw-r--r--trackerlogic.h2
29 files changed, 615 insertions, 180 deletions
diff --git a/Makefile b/Makefile
index a224845..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,8 +52,8 @@ 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
@@ -55,8 +64,7 @@ OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage
55OPTS_production=-O3 64OPTS_production=-O3
56 65
57CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra #-ansi -pedantic 66CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra #-ansi -pedantic
58LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz 67LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread
59#LDFLAGS+=-lbsd
60 68
61BINARY =opentracker 69BINARY =opentracker
62HEADERS=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 14e9989..f63db72 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -281,7 +281,8 @@ static void *server_mainloop(void *args) {
281 struct ot_workstruct ws; 281 struct ot_workstruct ws;
282 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 282 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
283 struct iovec *iovector; 283 struct iovec *iovector;
284 int iovec_entries, is_partial; 284 size_t iovec_entries;
285 int is_partial;
285 286
286 (void)args; 287 (void)args;
287 288
@@ -444,7 +445,7 @@ int parse_configfile(char *config_filename) {
444#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE) 445#if defined(WANT_RESTRICT_STATS) || defined(WANT_IP_FROM_PROXY) || defined(WANT_SYNC_LIVE)
445 ot_net tmpnet; 446 ot_net tmpnet;
446#endif 447#endif
447 int bound = 0; 448 int bound = 0;
448 449
449 accesslist_filehandle = fopen(config_filename, "r"); 450 accesslist_filehandle = fopen(config_filename, "r");
450 451
@@ -566,15 +567,15 @@ void load_state(const char *const state_filename) {
566 567
567 /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */ 568 /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */
568 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) { 569 while (fgets(inbuf, sizeof(inbuf), state_filehandle)) {
569 int i; 570 size_t i;
570 for (i = 0; i < (int)sizeof(ot_hash); ++i) { 571 for (i = 0; i < sizeof(ot_hash); ++i) {
571 int eger = 16 * scan_fromhex(inbuf[2 * i]) + scan_fromhex(inbuf[1 + 2 * i]); 572 int eger = 16 * scan_fromhex(inbuf[2 * i]) + scan_fromhex(inbuf[1 + 2 * i]);
572 if (eger < 0) 573 if (eger < 0)
573 continue; 574 continue;
574 infohash[i] = eger; 575 infohash[i] = eger;
575 } 576 }
576 577
577 if (i != (int)sizeof(ot_hash)) 578 if (i != sizeof(ot_hash))
578 continue; 579 continue;
579 i *= 2; 580 i *= 2;
580 581
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 4b88c40..8e9afdc 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -129,8 +129,8 @@ static void accesslist_readfile(void) {
129 129
130 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */ 130 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" */
131 while (read_offs <= map_end) { 131 while (read_offs <= map_end) {
132 int i; 132 size_t i;
133 for (i = 0; i < (int)sizeof(ot_hash); ++i) { 133 for (i = 0; i < sizeof(ot_hash); ++i) {
134 int eger1 = scan_fromhex((unsigned char)read_offs[2 * i]); 134 int eger1 = scan_fromhex((unsigned char)read_offs[2 * i]);
135 int eger2 = scan_fromhex((unsigned char)read_offs[1 + 2 * i]); 135 int eger2 = scan_fromhex((unsigned char)read_offs[1 + 2 * i]);
136 if (eger1 < 0 || eger2 < 0) 136 if (eger1 < 0 || eger2 < 0)
@@ -197,7 +197,7 @@ int accesslist_hashisvalid(ot_hash hash) {
197 197
198 /* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */ 198 /* If we found a matching hash on the main list, scan the list of dynamically deleted hashes */
199 accesslist_delete = g_accesslist_delete; 199 accesslist_delete = g_accesslist_delete;
200 if ((exactmatch != NULL) && accesslist_delete && bsearch(hash, accesslist_add->list, accesslist_add->size, OT_HASH_COMPARE_SIZE, vector_compare_hash)) 200 if ((exactmatch != NULL) && accesslist_delete && bsearch(hash, accesslist_delete->list, accesslist_delete->size, OT_HASH_COMPARE_SIZE, vector_compare_hash))
201 exactmatch = NULL; 201 exactmatch = NULL;
202#endif 202#endif
203 203
@@ -262,7 +262,7 @@ static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic
262 262
263 while ((linelen = getline(&line, &linecap, fifo)) > 0) { 263 while ((linelen = getline(&line, &linecap, fifo)) > 0) {
264 ot_hash info_hash; 264 ot_hash info_hash;
265 int i; 265 size_t i;
266 266
267 printf("Got line %*s", (int)linelen, line); 267 printf("Got line %*s", (int)linelen, line);
268 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*" 268 /* We do ignore anything that is not of the form "^[:xdigit:]{40}[^:xdigit:].*"
@@ -270,7 +270,7 @@ static void *accesslist_adddel_worker(char *fifoname, ot_accesslist *_Atomic
270 if (linelen < 41) 270 if (linelen < 41)
271 continue; 271 continue;
272 272
273 for (i = 0; i < (int)sizeof(ot_hash); ++i) { 273 for (i = 0; i < sizeof(ot_hash); ++i) {
274 int eger1 = scan_fromhex((unsigned char)line[2 * i]); 274 int eger1 = scan_fromhex((unsigned char)line[2 * i]);
275 int eger2 = scan_fromhex((unsigned char)line[1 + 2 * i]); 275 int eger2 = scan_fromhex((unsigned char)line[1 + 2 * i]);
276 if (eger1 < 0 || eger2 < 0) 276 if (eger1 < 0 || eger2 < 0)
@@ -342,7 +342,7 @@ static void *accesslist_deleter_worker(void *args) {
342#endif 342#endif
343 343
344static pthread_t thread_id; 344static pthread_t thread_id;
345void accesslist_init() { 345void accesslist_init(void) {
346 pthread_mutex_init(&g_accesslist_mutex, NULL); 346 pthread_mutex_init(&g_accesslist_mutex, NULL);
347 pthread_create(&thread_id, NULL, accesslist_worker, NULL); 347 pthread_create(&thread_id, NULL, accesslist_worker, NULL);
348#ifdef WANT_DYNAMIC_ACCESSLIST 348#ifdef WANT_DYNAMIC_ACCESSLIST
@@ -444,7 +444,7 @@ void loglist_add_network(const ot_net *net) {
444 pthread_mutex_unlock(&g_lognets_list_mutex); 444 pthread_mutex_unlock(&g_lognets_list_mutex);
445} 445}
446 446
447void loglist_reset() { 447void loglist_reset(void) {
448 pthread_mutex_lock(&g_lognets_list_mutex); 448 pthread_mutex_lock(&g_lognets_list_mutex);
449 free(g_lognets_list.data); 449 free(g_lognets_list.data);
450 g_lognets_list.data = 0; 450 g_lognets_list.data = 0;
@@ -511,7 +511,7 @@ int proxylist_check_proxy(const ot_ip6 proxy, const ot_ip6 address) {
511 511
512static ot_net g_admin_nets[OT_ADMINIP_MAX]; 512static ot_net g_admin_nets[OT_ADMINIP_MAX];
513static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX]; 513static ot_permissions g_admin_nets_permissions[OT_ADMINIP_MAX];
514static unsigned int g_admin_nets_count = 0; 514static size_t g_admin_nets_count = 0;
515 515
516int accesslist_bless_net(ot_net *net, ot_permissions permissions) { 516int accesslist_bless_net(ot_net *net, ot_permissions permissions) {
517 if (g_admin_nets_count >= OT_ADMINIP_MAX) 517 if (g_admin_nets_count >= OT_ADMINIP_MAX)
@@ -553,7 +553,7 @@ int accesslist_bless_net(ot_net *net, ot_permissions permissions) {
553} 553}
554 554
555int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) { 555int accesslist_is_blessed(ot_ip6 ip, ot_permissions permissions) {
556 unsigned int i; 556 size_t i;
557 for (i = 0; i < g_admin_nets_count; ++i) 557 for (i = 0; i < g_admin_nets_count; ++i)
558 if (address_in_net(ip, g_admin_nets + i) && (g_admin_nets_permissions[i] & permissions)) 558 if (address_in_net(ip, g_admin_nets + i) && (g_admin_nets_permissions[i] & permissions))
559 return 1; 559 return 1;
diff --git a/ot_accesslist.h b/ot_accesslist.h
index 0a7488e..d05e1f7 100644
--- a/ot_accesslist.h
+++ b/ot_accesslist.h
@@ -72,7 +72,7 @@ struct ot_log {
72extern ot_log *g_logchain_first, *g_logchain_last; 72extern ot_log *g_logchain_first, *g_logchain_last;
73 73
74void loglist_add_network(const ot_net *net); 74void loglist_add_network(const ot_net *net);
75void loglist_reset(); 75void loglist_reset(void);
76int loglist_check_address(const ot_ip6 address); 76int loglist_check_address(const ot_ip6 address);
77#endif 77#endif
78 78
diff --git a/ot_clean.c b/ot_clean.c
index 291b847..825290d 100644
--- a/ot_clean.c
+++ b/ot_clean.c
@@ -20,7 +20,7 @@
20#include "trackerlogic.h" 20#include "trackerlogic.h"
21 21
22/* Returns amount of removed peers */ 22/* Returns amount of removed peers */
23static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders) { 23static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, size_t *removed_seeders) {
24 ot_peer *last_peer = peers + peer_count * peer_size, *insert_point; 24 ot_peer *last_peer = peers + peer_count * peer_size, *insert_point;
25 25
26 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */ 26 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
@@ -50,7 +50,7 @@ static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t pee
50int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { 50int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) {
51 ot_vector *peer_vector = &peer_list->peers; 51 ot_vector *peer_vector = &peer_list->peers;
52 time_t timedout = (time_t)(g_now_minutes - peer_list->base); 52 time_t timedout = (time_t)(g_now_minutes - peer_list->base);
53 int num_buckets = 1, removed_seeders = 0; 53 size_t num_buckets = 1, removed_seeders = 0;
54 54
55 /* No need to clean empty torrent */ 55 /* No need to clean empty torrent */
56 if (!timedout) 56 if (!timedout)
@@ -111,7 +111,7 @@ int clean_single_torrent(ot_torrent *torrent) {
111static void *clean_worker(void *args) { 111static void *clean_worker(void *args) {
112 (void)args; 112 (void)args;
113 while (1) { 113 while (1) {
114 int bucket = OT_BUCKET_COUNT; 114 size_t bucket = OT_BUCKET_COUNT;
115 while (bucket--) { 115 while (bucket--) {
116 ot_vector *torrents_list = mutex_bucket_lock(bucket); 116 ot_vector *torrents_list = mutex_bucket_lock(bucket);
117 size_t toffs; 117 size_t toffs;
diff --git a/ot_fullscrape.c b/ot_fullscrape.c
index aed2ad9..b800431 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);
@@ -76,11 +88,11 @@ static void *fullscrape_worker(void *args) {
76} 88}
77 89
78static pthread_t thread_id; 90static pthread_t thread_id;
79void fullscrape_init( ) { 91void fullscrape_init(void) {
80 pthread_create( &thread_id, NULL, fullscrape_worker, NULL ); 92 pthread_create( &thread_id, NULL, fullscrape_worker, NULL );
81} 93}
82 94
83void fullscrape_deinit( ) { 95void fullscrape_deinit(void) {
84 pthread_cancel( thread_id ); 96 pthread_cancel( thread_id );
85} 97}
86 98
@@ -137,8 +149,8 @@ static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torre
137} 149}
138 150
139static void fullscrape_make(int taskid, ot_tasktype mode) { 151static void fullscrape_make(int taskid, ot_tasktype mode) {
140 int bucket; 152 size_t bucket;
141 char *r, *re; 153 char *r, *re;
142 struct iovec iovector = {NULL, 0}; 154 struct iovec iovector = {NULL, 0};
143 155
144 /* Setup return vector... */ 156 /* Setup return vector... */
@@ -200,12 +212,11 @@ static void fullscrape_make(int taskid, ot_tasktype mode) {
200#ifdef WANT_COMPRESSION_GZIP 212#ifdef WANT_COMPRESSION_GZIP
201 213
202static void fullscrape_make_gzip(int taskid, ot_tasktype mode) { 214static void fullscrape_make_gzip(int taskid, ot_tasktype mode) {
203 int bucket; 215 size_t bucket;
204 char *r; 216 char *r;
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,5 +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
diff --git a/ot_fullscrape.h b/ot_fullscrape.h
index bbb2a3f..843e039 100644
--- a/ot_fullscrape.h
+++ b/ot_fullscrape.h
@@ -10,8 +10,8 @@
10 10
11#include "ot_mutex.h" 11#include "ot_mutex.h"
12 12
13void fullscrape_init(); 13void fullscrape_init(void);
14void fullscrape_deinit(); 14void fullscrape_deinit(void);
15void fullscrape_deliver(int64 sock, ot_tasktype tasktype); 15void fullscrape_deliver(int64 sock, ot_tasktype tasktype);
16 16
17#else 17#else
diff --git a/ot_http.c b/ot_http.c
index cd2dfc1..e4486fc 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
@@ -133,13 +141,12 @@ ssize_t http_issue_error(const int64 sock, struct ot_workstruct *ws, int code) {
133 return ws->reply_size = -2; 141 return ws->reply_size = -2;
134} 142}
135 143
136ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector, int is_partial) { 144ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial) {
137 struct http_data *cookie = io_getcookie(sock); 145 struct http_data *cookie = io_getcookie(sock);
138 io_batch *current; 146 io_batch *current;
139 char *header; 147 char *header;
140 const char *encoding = ""; 148 const char *encoding = "";
141 int i; 149 size_t i, header_size, size = iovec_length(&iovec_entries, (const struct iovec **)&iovector);
142 size_t header_size, size = iovec_length(&iovec_entries, (const struct iovec **)&iovector);
143 tai6464 t; 150 tai6464 t;
144 151
145 /* No cookie? Bad socket. Leave. */ 152 /* No cookie? Bad socket. Leave. */
@@ -159,7 +166,9 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, int iovec
159 166
160 if (iovec_entries) { 167 if (iovec_entries) {
161 168
162 if (cookie->flag & STRUCT_HTTP_FLAG_GZIP) 169 if (cookie->flag & STRUCT_HTTP_FLAG_ZSTD)
170 encoding = "Content-Encoding: zstd\r\n";
171 else if (cookie->flag & STRUCT_HTTP_FLAG_GZIP)
163 encoding = "Content-Encoding: gzip\r\n"; 172 encoding = "Content-Encoding: gzip\r\n";
164 else if (cookie->flag & STRUCT_HTTP_FLAG_BZIP2) 173 else if (cookie->flag & STRUCT_HTTP_FLAG_BZIP2)
165 encoding = "Content-Encoding: bzip2\r\n"; 174 encoding = "Content-Encoding: bzip2\r\n";
@@ -181,26 +190,26 @@ ssize_t http_sendiovecdata(const int64 sock, struct ot_workstruct *ws, int iovec
181 190
182 if (!cookie->batch) { 191 if (!cookie->batch) {
183 cookie->batch = malloc(sizeof(io_batch)); 192 cookie->batch = malloc(sizeof(io_batch));
184 if (!cookie->batch) { 193 if (!cookie->batch || OT_IOB_INIT(cookie->batch) == -1) {
194 free(cookie->batch);
185 free(header); 195 free(header);
186 iovec_free(&iovec_entries, &iovector); 196 iovec_free(&iovec_entries, &iovector);
187 HTTPERROR_500; 197 HTTPERROR_500;
188 } 198 }
189 OT_IOB_INIT(cookie->batch);
190 cookie->batches = 1; 199 cookie->batches = 1;
191 } 200 }
192 current = cookie->batch + cookie->batches - 1; 201 current = cookie->batch + cookie->batches - 1;
193 iob_addbuf_free(current, header, header_size); 202 iob_addbuf_free(current, header, header_size);
194 203
195 /* Split huge iovectors into separate io_batches */ 204 /* Split huge iovectors into separate io_batches */
196 for (i = 0; i < iovec_entries; ++i) { 205 for (i = 0; i < (size_t)iovec_entries; ++i) {
197 /* If the current batch's limit is reached, try to reallocate a new batch to work on */ 206 /* If the current batch's limit is reached, try to reallocate a new batch to work on */
198 if (current->bytesleft > OT_BATCH_LIMIT) { 207 if (current->bytesleft > OT_BATCH_LIMIT) {
199 io_batch *new_batch = realloc(cookie->batch, (cookie->batches + 1) * sizeof(io_batch)); 208 io_batch *new_batch = realloc(cookie->batch, (cookie->batches + 1) * sizeof(io_batch));
200 if (new_batch) { 209 if (new_batch) {
201 cookie->batch = new_batch; 210 cookie->batch = new_batch;
202 current = cookie->batch + cookie->batches++; 211 if (OT_IOB_INIT(current) != -1)
203 OT_IOB_INIT(current); 212 current = cookie->batch + cookie->batches++;
204 } 213 }
205 } 214 }
206 iob_addbuf_free(current, iovector[i].iov_base, iovector[i].iov_len); 215 iob_addbuf_free(current, iovector[i].iov_base, iovector[i].iov_len);
@@ -369,19 +378,34 @@ static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws
369 } 378 }
370#endif 379#endif
371 380
372#ifdef WANT_COMPRESSION_GZIP 381
382#if defined(WANT_COMPRESSION_GZIP) || defined(WANT_COMPRESSION_ZSTD)
373 ws->request[ws->request_size - 1] = 0; 383 ws->request[ws->request_size - 1] = 0;
374#ifndef WANT_COMPRESSION_GZIP_ALWAYS 384#ifdef WANT_COMPRESSION_GZIP
375 if (strstr(ws->request, "gzip")) { 385 if (strstr(ws->request, "gzip")) {
376#endif
377 cookie->flag |= STRUCT_HTTP_FLAG_GZIP; 386 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
378 format = TASK_FLAG_GZIP; 387 format |= TASK_FLAG_GZIP;
379 stats_issue_event(EVENT_FULLSCRAPE_REQUEST_GZIP, 0, (uintptr_t)cookie->ip); 388 }
380#ifndef WANT_COMPRESSION_GZIP_ALWAYS 389#endif
381 } else 390#ifdef WANT_COMPRESSION_ZSTD
391 if (strstr(ws->request, "zstd")) {
392 cookie->flag |= STRUCT_HTTP_FLAG_ZSTD;
393 format |= TASK_FLAG_ZSTD;
394 }
395#endif
396
397#if defined(WANT_COMPRESSION_ZSTD) && defined(WANT_COMPRESSION_ZSTD_ALWAYS)
398 cookie->flag |= STRUCT_HTTP_FLAG_ZSTD;
399 format |= TASK_FLAG_ZSTD;
400#endif
401
402#if defined(WANT_COMPRESSION_GZIP) && defined(WANT_COMPRESSION_GZIP_ALWAYS)
403 cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
404 format |= TASK_FLAG_GZIP;
382#endif 405#endif
383#endif 406#endif
384 stats_issue_event(EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip); 407
408 stats_issue_event(EVENT_FULLSCRAPE_REQUEST, 0, (uintptr_t)cookie->ip);
385 409
386#ifdef _DEBUG_HTTPERROR 410#ifdef _DEBUG_HTTPERROR
387 fprintf(stderr, "%s", ws->debugbuf); 411 fprintf(stderr, "%s", ws->debugbuf);
@@ -401,8 +425,9 @@ static ssize_t http_handle_fullscrape(const int64 sock, struct ot_workstruct *ws
401static ssize_t http_handle_scrape(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { 425static ssize_t http_handle_scrape(const int64 sock, struct ot_workstruct *ws, char *read_ptr) {
402 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}}; 426 static const ot_keywords keywords_scrape[] = {{"info_hash", 1}, {NULL, -3}};
403 427
404 ot_hash *multiscrape_buf = (ot_hash *)ws->request; 428 ot_hash *multiscrape_buf = (ot_hash *)ws->request;
405 int scanon = 1, numwant = 0; 429 int scanon = 1;
430 size_t numwant = 0;
406 431
407 /* This is to hack around stupid clients that send "scrape ?info_hash" */ 432 /* This is to hack around stupid clients that send "scrape ?info_hash" */
408 if (read_ptr[-1] != '?') { 433 if (read_ptr[-1] != '?') {
@@ -477,7 +502,8 @@ static ot_keywords keywords_announce[] = {{"port", 1}, {"left", 2}, {"event",
477 {"peer_id", 9}, {NULL, -3}}; 502 {"peer_id", 9}, {NULL, -3}};
478static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}}; 503static ot_keywords keywords_announce_event[] = {{"completed", 1}, {"stopped", 2}, {NULL, -3}};
479static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *ws, char *read_ptr) { 504static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *ws, char *read_ptr) {
480 int numwant, tmp, scanon; 505 size_t numwant;
506 int tmp, scanon;
481 unsigned short port = 0; 507 unsigned short port = 0;
482 char *write_ptr; 508 char *write_ptr;
483 ssize_t len; 509 ssize_t len;
@@ -553,12 +579,13 @@ static ssize_t http_handle_announce(const int64 sock, struct ot_workstruct *
553 break; 579 break;
554 case 4: /* matched "numwant" */ 580 case 4: /* matched "numwant" */
555 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); 581 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
556 if ((len <= 0) || scan_fixed_int(write_ptr, len, &numwant)) 582 if ((len <= 0) || scan_fixed_int(write_ptr, len, &tmp))
557 HTTPERROR_400_PARAM; 583 HTTPERROR_400_PARAM;
558 if (numwant < 0) 584 if (tmp < 0)
559 numwant = 50; 585 tmp = 50;
560 if (numwant > 200) 586 if (tmp > 200)
561 numwant = 200; 587 tmp = 200;
588 numwant = tmp;
562 break; 589 break;
563 case 5: /* matched "compact" */ 590 case 5: /* matched "compact" */
564 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE); 591 len = scan_urlencoded_query(&read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE);
diff --git a/ot_http.h b/ot_http.h
index fecb4eb..8980682 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 {
@@ -23,7 +24,7 @@ struct http_data {
23}; 24};
24 25
25ssize_t http_handle_request(const int64 s, struct ot_workstruct *ws); 26ssize_t http_handle_request(const int64 s, struct ot_workstruct *ws);
26ssize_t http_sendiovecdata(const int64 s, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector, int is_partial); 27ssize_t http_sendiovecdata(const int64 s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial);
27ssize_t http_issue_error(const int64 s, struct ot_workstruct *ws, int code); 28ssize_t http_issue_error(const int64 s, struct ot_workstruct *ws, int code);
28 29
29extern char *g_stats_path; 30extern char *g_stats_path;
diff --git a/ot_iovec.c b/ot_iovec.c
index 8e94c52..e2cdd4b 100644
--- a/ot_iovec.c
+++ b/ot_iovec.c
@@ -14,9 +14,9 @@
14/* Opentracker */ 14/* Opentracker */
15#include "ot_iovec.h" 15#include "ot_iovec.h"
16 16
17void *iovec_increase(int *iovec_entries, struct iovec **iovector, size_t new_alloc) { 17void *iovec_increase(size_t *iovec_entries, struct iovec **iovector, size_t new_alloc) {
18 void *new_data; 18 void *new_data;
19 int new_entries = 1 + *iovec_entries; 19 size_t new_entries = 1 + *iovec_entries;
20 struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec)); 20 struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec));
21 21
22 if (!new_vec) 22 if (!new_vec)
@@ -35,8 +35,8 @@ void *iovec_increase(int *iovec_entries, struct iovec **iovector, size_t new_all
35 return new_data; 35 return new_data;
36} 36}
37 37
38void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector) { 38void *iovec_append(size_t *iovec_entries, struct iovec **iovector, struct iovec *append_iovector) {
39 int new_entries = *iovec_entries + 1; 39 size_t new_entries = *iovec_entries + 1;
40 struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec)); 40 struct iovec *new_vec = realloc(*iovector, new_entries * sizeof(struct iovec));
41 if (!new_vec) 41 if (!new_vec)
42 return NULL; 42 return NULL;
@@ -54,15 +54,15 @@ void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *ap
54 return new_vec; 54 return new_vec;
55} 55}
56 56
57void iovec_free(int *iovec_entries, struct iovec **iovector) { 57void iovec_free(size_t *iovec_entries, struct iovec **iovector) {
58 int i; 58 size_t i;
59 for (i = 0; i < *iovec_entries; ++i) 59 for (i = 0; i < *iovec_entries; ++i)
60 free(((*iovector)[i]).iov_base); 60 free(((*iovector)[i]).iov_base);
61 *iovector = NULL; 61 *iovector = NULL;
62 *iovec_entries = 0; 62 *iovec_entries = 0;
63} 63}
64 64
65void iovec_fixlast(int *iovec_entries, struct iovec **iovector, void *last_ptr) { 65void iovec_fixlast(size_t *iovec_entries, struct iovec **iovector, void *last_ptr) {
66 if (*iovec_entries) { 66 if (*iovec_entries) {
67 char *base = (char *)((*iovector)[*iovec_entries - 1]).iov_base; 67 char *base = (char *)((*iovector)[*iovec_entries - 1]).iov_base;
68 size_t new_alloc = ((char *)last_ptr) - base; 68 size_t new_alloc = ((char *)last_ptr) - base;
@@ -72,7 +72,7 @@ void iovec_fixlast(int *iovec_entries, struct iovec **iovector, void *last_ptr)
72 } 72 }
73} 73}
74 74
75void *iovec_fix_increase_or_free(int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc) { 75void *iovec_fix_increase_or_free(size_t *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc) {
76 void *new_data; 76 void *new_data;
77 77
78 iovec_fixlast(iovec_entries, iovector, last_ptr); 78 iovec_fixlast(iovec_entries, iovector, last_ptr);
@@ -83,9 +83,8 @@ void *iovec_fix_increase_or_free(int *iovec_entries, struct iovec **iovector, vo
83 return new_data; 83 return new_data;
84} 84}
85 85
86size_t iovec_length(const int *iovec_entries, const struct iovec **iovector) { 86size_t iovec_length(const size_t *iovec_entries, const struct iovec **iovector) {
87 size_t length = 0; 87 size_t i, length = 0;
88 int i;
89 for (i = 0; i < *iovec_entries; ++i) 88 for (i = 0; i < *iovec_entries; ++i)
90 length += ((*iovector)[i]).iov_len; 89 length += ((*iovector)[i]).iov_len;
91 return length; 90 return length;
diff --git a/ot_iovec.h b/ot_iovec.h
index 4317ab7..eb4365b 100644
--- a/ot_iovec.h
+++ b/ot_iovec.h
@@ -8,13 +8,13 @@
8 8
9#include <sys/uio.h> 9#include <sys/uio.h>
10 10
11void *iovec_increase(int *iovec_entries, struct iovec **iovector, size_t new_alloc); 11void *iovec_increase(size_t *iovec_entries, struct iovec **iovector, size_t new_alloc);
12void *iovec_append(int *iovec_entries, struct iovec **iovector, struct iovec *append_iovector); 12void *iovec_append(size_t *iovec_entries, struct iovec **iovector, struct iovec *append_iovector);
13void iovec_fixlast(int *iovec_entries, struct iovec **iovector, void *last_ptr); 13void iovec_fixlast(size_t *iovec_entries, struct iovec **iovector, void *last_ptr);
14void iovec_free(int *iovec_entries, struct iovec **iovector); 14void iovec_free(size_t *iovec_entries, struct iovec **iovector);
15 15
16size_t iovec_length(const int *iovec_entries, const struct iovec **iovector); 16size_t iovec_length(const size_t *iovec_entries, const struct iovec **iovector);
17 17
18void *iovec_fix_increase_or_free(int *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc); 18void *iovec_fix_increase_or_free(size_t *iovec_entries, struct iovec **iovector, void *last_ptr, size_t new_alloc);
19 19
20#endif 20#endif
diff --git a/ot_livesync.c b/ot_livesync.c
index 269b8d8..f620592 100644
--- a/ot_livesync.c
+++ b/ot_livesync.c
@@ -136,10 +136,18 @@ static void livesync_issue_peersync(sync_buffer *buf) {
136static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) { 136static void livesync_handle_peersync(struct ot_workstruct *ws, size_t peer_size) {
137 size_t off = sizeof(g_tracker_id) + sizeof(uint32_t); 137 size_t off = sizeof(g_tracker_id) + sizeof(uint32_t);
138 138
139 /* Prepare peer record for v4mapped expansion */
140 if (peer_size == OT_PEER_SIZE4)
141 memcpy(&ws->peer, V4mappedprefix, sizeof(V4mappedprefix));
142
139 /* Now basic sanity checks have been done on the live sync packet 143 /* Now basic sanity checks have been done on the live sync packet
140 We might add more testing and logging. */ 144 We might add more testing and logging. */
141 while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= ws->request_size) { 145 while ((ssize_t)(off + sizeof(ot_hash) + peer_size) <= ws->request_size) {
142 memcpy(&ws->peer, ws->request + off + sizeof(ot_hash), peer_size); 146 char *peer_ip = ws->request + off + sizeof(ot_hash);
147 if (peer_size == OT_PEER_SIZE4)
148 memcpy(&ws->peer[0] + sizeof(V4mappedprefix), peer_ip, peer_size);
149 else
150 memcpy(&ws->peer, peer_ip, peer_size);
143 ws->hash = (ot_hash *)(ws->request + off); 151 ws->hash = (ot_hash *)(ws->request + off);
144 152
145 if (!g_opentracker_running) 153 if (!g_opentracker_running)
diff --git a/ot_mutex.c b/ot_mutex.c
index 3011987..be3ddf9 100644
--- a/ot_mutex.c
+++ b/ot_mutex.c
@@ -48,7 +48,7 @@ void mutex_bucket_unlock_by_hash(ot_hash const hash, int delta_torrentcount) {
48 mutex_bucket_unlock(uint32_read_big((char *)hash) >> OT_BUCKET_COUNT_SHIFT, delta_torrentcount); 48 mutex_bucket_unlock(uint32_read_big((char *)hash) >> OT_BUCKET_COUNT_SHIFT, delta_torrentcount);
49} 49}
50 50
51size_t mutex_get_torrent_count() { return g_torrent_count; } 51size_t mutex_get_torrent_count(void) { return g_torrent_count; }
52 52
53/* TaskQueue Magic */ 53/* TaskQueue Magic */
54 54
@@ -56,7 +56,7 @@ struct ot_task {
56 ot_taskid taskid; 56 ot_taskid taskid;
57 ot_tasktype tasktype; 57 ot_tasktype tasktype;
58 int64 sock; 58 int64 sock;
59 int iovec_entries; 59 size_t iovec_entries;
60 struct iovec *iovec; 60 struct iovec *iovec;
61 struct ot_task *next; 61 struct ot_task *next;
62}; 62};
@@ -105,7 +105,7 @@ void mutex_workqueue_canceltask(int64 sock) {
105 if ((*task)->sock == sock) { 105 if ((*task)->sock == sock) {
106 struct iovec *iovec = (*task)->iovec; 106 struct iovec *iovec = (*task)->iovec;
107 struct ot_task *ptask = *task; 107 struct ot_task *ptask = *task;
108 int i; 108 size_t i;
109 109
110 /* Free task's iovec */ 110 /* Free task's iovec */
111 for (i = 0; i < (*task)->iovec_entries; ++i) 111 for (i = 0; i < (*task)->iovec_entries; ++i)
@@ -167,7 +167,7 @@ void mutex_workqueue_pushsuccess(ot_taskid taskid) {
167 pthread_mutex_unlock(&tasklist_mutex); 167 pthread_mutex_unlock(&tasklist_mutex);
168} 168}
169 169
170int mutex_workqueue_pushresult(ot_taskid taskid, int iovec_entries, struct iovec *iovec) { 170int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct iovec *iovec) {
171 struct ot_task *task; 171 struct ot_task *task;
172 const char byte = 'o'; 172 const char byte = 'o';
173 173
@@ -219,7 +219,7 @@ int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) {
219 return task ? 0 : -1; 219 return task ? 0 : -1;
220} 220}
221 221
222int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovec, int *is_partial) { 222int64 mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovec, int *is_partial) {
223 struct ot_task **task; 223 struct ot_task **task;
224 int64 sock = -1; 224 int64 sock = -1;
225 225
@@ -253,8 +253,8 @@ int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovec, int *i
253 return sock; 253 return sock;
254} 254}
255 255
256void mutex_init() { 256void mutex_init(void) {
257 int i; 257 size_t i;
258 pthread_mutex_init(&tasklist_mutex, NULL); 258 pthread_mutex_init(&tasklist_mutex, NULL);
259 pthread_cond_init(&tasklist_being_filled, NULL); 259 pthread_cond_init(&tasklist_being_filled, NULL);
260 for (i = 0; i < OT_BUCKET_COUNT; ++i) 260 for (i = 0; i < OT_BUCKET_COUNT; ++i)
@@ -262,8 +262,8 @@ void mutex_init() {
262 byte_zero(all_torrents, sizeof(all_torrents)); 262 byte_zero(all_torrents, sizeof(all_torrents));
263} 263}
264 264
265void mutex_deinit() { 265void mutex_deinit(void) {
266 int i; 266 size_t i;
267 for (i = 0; i < OT_BUCKET_COUNT; ++i) 267 for (i = 0; i < OT_BUCKET_COUNT; ++i)
268 pthread_mutex_destroy(bucket_mutex + i); 268 pthread_mutex_destroy(bucket_mutex + i);
269 pthread_mutex_destroy(&tasklist_mutex); 269 pthread_mutex_destroy(&tasklist_mutex);
diff --git a/ot_mutex.h b/ot_mutex.h
index 66b627f..ab1cf59 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,
@@ -72,8 +73,8 @@ int mutex_workqueue_pushtask(int64 sock, ot_tasktype tasktype)
72void mutex_workqueue_canceltask(int64 sock); 73void mutex_workqueue_canceltask(int64 sock);
73void mutex_workqueue_pushsuccess(ot_taskid taskid); 74void mutex_workqueue_pushsuccess(ot_taskid taskid);
74ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype); 75ot_taskid mutex_workqueue_poptask(ot_tasktype *tasktype);
75int mutex_workqueue_pushresult(ot_taskid taskid, int iovec_entries, struct iovec *iovector); 76int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct iovec *iovector);
76int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec); 77int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec);
77int64 mutex_workqueue_popresult(int *iovec_entries, struct iovec **iovector, int *is_partial); 78int64 mutex_workqueue_popresult(size_t *iovec_entries, struct iovec **iovector, int *is_partial);
78 79
79#endif 80#endif
diff --git a/ot_stats.c b/ot_stats.c
index 158884f..58ac4b8 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -38,7 +38,7 @@
38#endif 38#endif
39 39
40/* Forward declaration */ 40/* Forward declaration */
41static void stats_make(int *iovec_entries, struct iovec **iovector, ot_tasktype mode); 41static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode);
42#define OT_STATS_TMPSIZE 8192 42#define OT_STATS_TMPSIZE 8192
43 43
44/* Clumsy counters... to be rethought */ 44/* Clumsy counters... to be rethought */
@@ -113,7 +113,7 @@ static int stat_increase_network_count(stats_network_node **pnode, int depth, ui
113} 113}
114 114
115static int stats_shift_down_network_count(stats_network_node **node, int depth, int shift) { 115static int stats_shift_down_network_count(stats_network_node **node, int depth, int shift) {
116 int i, rest = 0; 116 size_t i, rest = 0;
117 117
118 if (!*node) 118 if (!*node)
119 return 0; 119 return 0;
@@ -134,8 +134,7 @@ static int stats_shift_down_network_count(stats_network_node **node, int depth,
134 134
135static size_t stats_get_highscore_networks(stats_network_node *node, int depth, ot_ip6 node_value, size_t *scores, ot_ip6 *networks, int network_count, 135static size_t stats_get_highscore_networks(stats_network_node *node, int depth, ot_ip6 node_value, size_t *scores, ot_ip6 *networks, int network_count,
136 int limit) { 136 int limit) {
137 size_t score = 0; 137 size_t i, score = 0;
138 int i;
139 138
140 if (!node) 139 if (!node)
141 return 0; 140 return 0;
@@ -191,11 +190,11 @@ static size_t stats_get_highscore_networks(stats_network_node *node, int depth,
191 return score; 190 return score;
192} 191}
193 192
194static size_t stats_return_busy_networks(char *reply, stats_network_node *tree, int amount, int limit) { 193static size_t stats_return_busy_networks(char *reply, stats_network_node *tree, size_t amount, int limit) {
195 ot_ip6 networks[amount]; 194 ot_ip6 networks[amount];
196 ot_ip6 node_value; 195 ot_ip6 node_value;
197 size_t scores[amount]; 196 size_t scores[amount];
198 int i; 197 size_t i;
199 char *r = reply; 198 char *r = reply;
200 199
201 memset(scores, 0, sizeof(scores)); 200 memset(scores, 0, sizeof(scores));
@@ -205,14 +204,14 @@ static size_t stats_return_busy_networks(char *reply, stats_network_node *tree,
205 stats_get_highscore_networks(tree, 0, node_value, scores, networks, amount, limit); 204 stats_get_highscore_networks(tree, 0, node_value, scores, networks, amount, limit);
206 205
207 r += sprintf(r, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH); 206 r += sprintf(r, "Networks, limit /%d:\n", limit + STATS_NETWORK_NODE_BITWIDTH);
208 for (i = amount - 1; i >= 0; --i) { 207 for (i = amount; i > 0; --i) {
209 if (scores[i]) { 208 if (scores[i - 1]) {
210 r += sprintf(r, "%08zd: ", scores[i]); 209 r += sprintf(r, "%08zd: ", scores[i - 1]);
211 // #ifdef WANT_V6 210 // #ifdef WANT_V6
212 r += fmt_ip6c(r, networks[i]); 211 r += fmt_ip6c(r, networks[i - 1]);
213#if 0 212#if 0
214 // XXX 213 // XXX
215 r += fmt_ip4( r, networks[i]); 214 r += fmt_ip4( r, networks[i - 1]);
216#endif 215#endif
217 *r++ = '\n'; 216 *r++ = '\n';
218 } 217 }
@@ -225,8 +224,7 @@ static size_t stats_return_busy_networks(char *reply, stats_network_node *tree,
225static size_t stats_slash24s_txt(char *reply, size_t amount) { 224static size_t stats_slash24s_txt(char *reply, size_t amount) {
226 stats_network_node *slash24s_network_counters_root = NULL; 225 stats_network_node *slash24s_network_counters_root = NULL;
227 char *r = reply; 226 char *r = reply;
228 int bucket; 227 size_t i, bucket, peer_size = OT_PEER_SIZE4;
229 size_t i, peer_size = OT_PEER_SIZE4;
230 228
231 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 229 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
232 ot_vector *torrents_list = mutex_bucket_lock(bucket); 230 ot_vector *torrents_list = mutex_bucket_lock(bucket);
@@ -317,55 +315,64 @@ typedef struct {
317 ot_hash hash; 315 ot_hash hash;
318} ot_record; 316} ot_record;
319 317
318static inline void stats_insert_into_highscore(size_t val, ot_record* list, size_t amount, ot_hash* hash) {
319 size_t i;
320 for (i = 0; (i < amount) && (list[i].val > val); ++i)
321 {}
322 /* if we score better than a record in the list, we need to make room in the high
323 score array by moving lower scoring entries up */
324 if (i < amount) {
325 memmove(list + i + 1, list + i, (amount - i - 1) * sizeof(ot_record));
326
327 memcpy(&list[i].hash, hash, sizeof(ot_hash));
328 list[i].val = val;
329 }
330}
331
332
320/* Fetches stats from tracker */ 333/* Fetches stats from tracker */
321size_t stats_top_txt(char *reply, int amount) { 334size_t stats_top_txt(char *reply, size_t amount) {
322 size_t j; 335 size_t j, idx, bucket;
323 ot_record top100s[100], top100c[100]; 336 ot_record top100s[100], top100c[100], top100l[100];
324 char *r = reply, hex_out[42]; 337 char *r = reply, hex_out[42];
325 int idx, bucket;
326 338
327 if (amount > 100) 339 if (amount > 100)
328 amount = 100; 340 amount = 100;
329 341
330 byte_zero(top100s, sizeof(top100s)); 342 byte_zero(top100s, sizeof(top100s));
331 byte_zero(top100c, sizeof(top100c)); 343 byte_zero(top100c, sizeof(top100c));
344 byte_zero(top100l, sizeof(top100l));
332 345
346 /* Iterate over complete torrent list */
333 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 347 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
334 ot_vector *torrents_list = mutex_bucket_lock(bucket); 348 ot_vector *torrents_list = mutex_bucket_lock(bucket);
335 for (j = 0; j < torrents_list->size; ++j) { 349 for (j = 0; j < torrents_list->size; ++j) {
336 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j; 350 ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j;
337 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; 351 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; 352 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
339 idx = amount - 1; 353 size_t leech_count = peer_count - seed_count;
340 while ((idx >= 0) && (peer_count > top100c[idx].val)) 354
341 --idx; 355 stats_insert_into_highscore(peer_count, top100c, amount, &torrent->hash);
342 if (idx++ != amount - 1) { 356 stats_insert_into_highscore(seed_count, top100s, amount, &torrent->hash);
343 memmove(top100c + idx + 1, top100c + idx, (amount - 1 - idx) * sizeof(ot_record)); 357 stats_insert_into_highscore(leech_count, top100l, amount, &torrent->hash);
344 memcpy(&top100c[idx].hash, &torrent->hash, sizeof(ot_hash));
345 top100c[idx].val = peer_count;
346 }
347 idx = amount - 1;
348 while ((idx >= 0) && (seed_count > top100s[idx].val))
349 --idx;
350 if (idx++ != amount - 1) {
351 memmove(top100s + idx + 1, top100s + idx, (amount - 1 - idx) * sizeof(ot_record));
352 memcpy(&top100s[idx].hash, &torrent->hash, sizeof(ot_hash));
353 top100s[idx].val = seed_count;
354 }
355 } 358 }
356 mutex_bucket_unlock(bucket, 0); 359 mutex_bucket_unlock(bucket, 0);
357 if (!g_opentracker_running) 360 if (!g_opentracker_running)
358 return 0; 361 return 0;
359 } 362 }
360 363
361 r += sprintf(r, "Top %d torrents by peers:\n", amount); 364 r += sprintf(r, "Top %zd torrents by peers:\n", amount);
362 for (idx = 0; idx < amount; ++idx) 365 for (idx = 0; idx < amount; ++idx)
363 if (top100c[idx].val) 366 if (top100c[idx].val)
364 r += sprintf(r, "\t%zd\t%s\n", top100c[idx].val, to_hex(hex_out, top100c[idx].hash)); 367 r += sprintf(r, "\t%zd\t%s\n", top100c[idx].val, to_hex(hex_out, top100c[idx].hash));
365 r += sprintf(r, "Top %d torrents by seeds:\n", amount); 368 r += sprintf(r, "Top %zd torrents by seeds:\n", amount);
366 for (idx = 0; idx < amount; ++idx) 369 for (idx = 0; idx < amount; ++idx)
367 if (top100s[idx].val) 370 if (top100s[idx].val)
368 r += sprintf(r, "\t%zd\t%s\n", top100s[idx].val, to_hex(hex_out, top100s[idx].hash)); 371 r += sprintf(r, "\t%zd\t%s\n", top100s[idx].val, to_hex(hex_out, top100s[idx].hash));
372 r += sprintf(r, "Top %zd torrents by leechers:\n", amount);
373 for (idx = 0; idx < amount; ++idx)
374 if (top100l[idx].val)
375 r += sprintf(r, "\t%zd\t%s\n", top100l[idx].val, to_hex(hex_out, top100l[idx].hash));
369 376
370 return r - reply; 377 return r - reply;
371} 378}
@@ -463,7 +470,7 @@ static size_t stats_return_numwants(char *reply) {
463#endif 470#endif
464 471
465#ifdef WANT_FULLLOG_NETWORKS 472#ifdef WANT_FULLLOG_NETWORKS
466static void stats_return_fulllog(int *iovec_entries, struct iovec **iovector, char *r) { 473static void stats_return_fulllog(size_t *iovec_entries, struct iovec **iovector, char *r) {
467 ot_log *loglist = g_logchain_first, *llnext; 474 ot_log *loglist = g_logchain_first, *llnext;
468 char *re = r + OT_STATS_TMPSIZE; 475 char *re = r + OT_STATS_TMPSIZE;
469 476
@@ -577,7 +584,7 @@ size_t return_stats_for_tracker(char *reply, int mode, int format) {
577 } 584 }
578} 585}
579 586
580static void stats_make(int *iovec_entries, struct iovec **iovector, ot_tasktype mode) { 587static void stats_make(size_t *iovec_entries, struct iovec **iovector, ot_tasktype mode) {
581 char *r; 588 char *r;
582 589
583 *iovec_entries = 0; 590 *iovec_entries = 0;
@@ -734,7 +741,7 @@ void stats_issue_event(ot_status_event event, PROTO_FLAG proto, uintptr_t event_
734 } 741 }
735} 742}
736 743
737void stats_cleanup() { 744void stats_cleanup(void) {
738#ifdef WANT_SPOT_WOODPECKER 745#ifdef WANT_SPOT_WOODPECKER
739 pthread_mutex_lock(&g_woodpeckers_mutex); 746 pthread_mutex_lock(&g_woodpeckers_mutex);
740 stats_shift_down_network_count(&stats_woodpeckers_tree, 0, 1); 747 stats_shift_down_network_count(&stats_woodpeckers_tree, 0, 1);
@@ -743,7 +750,7 @@ void stats_cleanup() {
743} 750}
744 751
745static void *stats_worker(void *args) { 752static void *stats_worker(void *args) {
746 int iovec_entries; 753 size_t iovec_entries;
747 struct iovec *iovector; 754 struct iovec *iovector;
748 755
749 (void)args; 756 (void)args;
@@ -761,11 +768,11 @@ static void *stats_worker(void *args) {
761void stats_deliver(int64 sock, int tasktype) { mutex_workqueue_pushtask(sock, tasktype); } 768void stats_deliver(int64 sock, int tasktype) { mutex_workqueue_pushtask(sock, tasktype); }
762 769
763static pthread_t thread_id; 770static pthread_t thread_id;
764void stats_init() { 771void stats_init(void) {
765 ot_start_time = g_now_seconds; 772 ot_start_time = g_now_seconds;
766 pthread_create(&thread_id, NULL, stats_worker, NULL); 773 pthread_create(&thread_id, NULL, stats_worker, NULL);
767} 774}
768 775
769void stats_deinit() { 776void stats_deinit(void) {
770 pthread_cancel(thread_id); 777 pthread_cancel(thread_id);
771} 778}
diff --git a/ot_stats.h b/ot_stats.h
index 4f75049..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,
diff --git a/ot_sync.c b/ot_sync.c
index 293acf3..65a8170 100644
--- a/ot_sync.c
+++ b/ot_sync.c
@@ -72,9 +72,9 @@ int add_changeset_to_tracker(uint8_t *data, size_t len) {
72/* Proposed output format 72/* Proposed output format
73 d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee 73 d4:syncd20:<info_hash>8*N:(xxxxyyyy)*Nee
74*/ 74*/
75static void sync_make(int *iovec_entries, struct iovec **iovector) { 75static void sync_make(size_t *iovec_entries, struct iovec **iovector) {
76 int bucket; 76 size_t bucket;
77 char *r, *re; 77 char *r, *re;
78 78
79 /* Setup return vector... */ 79 /* Setup return vector... */
80 *iovec_entries = 0; 80 *iovec_entries = 0;
@@ -140,7 +140,7 @@ static void sync_make(int *iovec_entries, struct iovec **iovector) {
140 It grabs tasks from mutex_tasklist and delivers results back 140 It grabs tasks from mutex_tasklist and delivers results back
141*/ 141*/
142static void *sync_worker(void *args) { 142static void *sync_worker(void *args) {
143 int iovec_entries; 143 size_t iovec_entries;
144 struct iovec *iovector; 144 struct iovec *iovector;
145 145
146 args = args; 146 args = args;
diff --git a/ot_udp.c b/ot_udp.c
index 97ccd38..26fb979 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -25,10 +25,10 @@
25static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; 25static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
26#endif 26#endif
27static uint32_t g_rijndael_round_key[44] = {0}; 27static uint32_t g_rijndael_round_key[44] = {0};
28static uint32_t g_key_of_the_hour[2] = {0}; 28static volatile uint32_t g_key_of_the_hour[2] = {0};
29static ot_time g_hour_of_the_key; 29static volatile ot_time g_hour_of_the_key;
30 30
31static void udp_generate_rijndael_round_key() { 31static void udp_generate_rijndael_round_key(void) {
32 uint32_t key[16]; 32 uint32_t key[16];
33#ifdef WANT_ARC4RANDOM 33#ifdef WANT_ARC4RANDOM
34 arc4random_buf(&key[0], sizeof(key)); 34 arc4random_buf(&key[0], sizeof(key));
@@ -52,20 +52,30 @@ static void udp_generate_rijndael_round_key() {
52static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int age) { 52static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int age) {
53 uint32_t plain[4], crypt[4]; 53 uint32_t plain[4], crypt[4];
54 int i; 54 int i;
55 if (g_now_minutes + 60 > g_hour_of_the_key) { 55 uint32_t current_key_of_the_hour;
56 g_hour_of_the_key = g_now_minutes; 56
57 g_key_of_the_hour[1] = g_key_of_the_hour[0]; 57 if (g_now_minutes - g_hour_of_the_key >= 60) {
58 uint32_t old_key_of_the_hour = g_key_of_the_hour[0];
58#ifdef WANT_ARC4RANDOM 59#ifdef WANT_ARC4RANDOM
59 g_key_of_the_hour[0] = arc4random(); 60 uint32_t new_key_of_the_hour = arc4random();
60#else 61#else
61 g_key_of_the_hour[0] = random(); 62 uint32_t new_key_of_the_hour = random();
62#endif 63#endif
64 /* If in the meantime another thread has performed
65 key rotation, do not overwrite their results */
66 if (g_now_minutes - g_hour_of_the_key >= 60) {
67 /* Upgrade en bloc */
68 g_hour_of_the_key = g_now_minutes;
69 g_key_of_the_hour[0] = new_key_of_the_hour;
70 g_key_of_the_hour[1] = old_key_of_the_hour;
71 }
63 } 72 }
64 73
65 memcpy(plain, remoteip, sizeof(plain)); 74 memcpy(plain, remoteip, sizeof(plain));
75 current_key_of_the_hour = g_key_of_the_hour[age];
66 for (i = 0; i < 4; ++i) 76 for (i = 0; i < 4; ++i)
67 plain[i] ^= g_key_of_the_hour[age]; 77 plain[i] ^= current_key_of_the_hour;
68 rijndaelEncrypt128(g_rijndael_round_key, (uint8_t *)remoteip, (uint8_t *)crypt); 78 rijndaelEncrypt128(g_rijndael_round_key, (uint8_t *)plain, (uint8_t *)crypt);
69 connid[0] = crypt[0] ^ crypt[1]; 79 connid[0] = crypt[0] ^ crypt[1];
70 connid[1] = crypt[2] ^ crypt[3]; 80 connid[1] = crypt[2] ^ crypt[3];
71} 81}
diff --git a/ot_vector.c b/ot_vector.c
index 2bc07b5..d068999 100644
--- a/ot_vector.c
+++ b/ot_vector.c
@@ -45,7 +45,7 @@ void *binary_search(const void *const key, const void *base, const size_t member
45 return (void *)base; 45 return (void *)base;
46} 46}
47 47
48static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, int bucket_count) { 48static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, size_t bucket_count) {
49 unsigned int hash = 5381; 49 unsigned int hash = 5381;
50 uint8_t *p = (uint8_t *)peer; 50 uint8_t *p = (uint8_t *)peer;
51 while (compare_size--) 51 while (compare_size--)
@@ -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;
@@ -169,7 +172,7 @@ void vector_remove_torrent(ot_vector *vector, ot_torrent *match) {
169 } 172 }
170} 173}
171 174
172void vector_clean_list(ot_vector *vector, int num_buckets) { 175void vector_clean_list(ot_vector *vector, size_t num_buckets) {
173 while (num_buckets--) 176 while (num_buckets--)
174 free(vector[num_buckets].data); 177 free(vector[num_buckets].data);
175 free(vector); 178 free(vector);
@@ -177,7 +180,7 @@ void vector_clean_list(ot_vector *vector, int num_buckets) {
177} 180}
178 181
179void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) { 182void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) {
180 int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; 183 size_t tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
181 ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers; 184 ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers;
182 int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4; 185 int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
183 186
@@ -226,7 +229,7 @@ void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) {
226 /* Now sort them into the correct bucket */ 229 /* Now sort them into the correct bucket */
227 for (bucket = 0; bucket < num_buckets_old; ++bucket) { 230 for (bucket = 0; bucket < num_buckets_old; ++bucket) {
228 ot_peer *peers_old = bucket_list_old[bucket].data; 231 ot_peer *peers_old = bucket_list_old[bucket].data;
229 int peer_count_old = bucket_list_old[bucket].size; 232 size_t peer_count_old = bucket_list_old[bucket].size;
230 while (peer_count_old--) { 233 while (peer_count_old--) {
231 ot_vector *bucket_dest = bucket_list_new; 234 ot_vector *bucket_dest = bucket_list_new;
232 if (num_buckets_new > 1) 235 if (num_buckets_new > 1)
diff --git a/ot_vector.h b/ot_vector.h
index 8d41452..2618363 100644
--- a/ot_vector.h
+++ b/ot_vector.h
@@ -31,6 +31,6 @@ void vector_remove_torrent(ot_vector *vector, ot_torrent *match);
31/* For ot_clean.c */ 31/* For ot_clean.c */
32void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size); 32void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size);
33void vector_fixup_peers(ot_vector *vector, size_t peer_size); 33void vector_fixup_peers(ot_vector *vector, size_t peer_size);
34void vector_clean_list(ot_vector *vector, int num_buckets); 34void vector_clean_list(ot_vector *vector, size_t num_buckets);
35 35
36#endif 36#endif
diff --git a/proxy.c b/proxy.c
index 9946240..6bf45df 100644
--- a/proxy.c
+++ b/proxy.c
@@ -276,12 +276,12 @@ void reset_info_block(proxy_peer *peer) {
276 * Multiple connections to/from the same ip are okay, if tracker_id doesn't match 276 * Multiple connections to/from the same ip are okay, if tracker_id doesn't match
277 * Reconnect attempts occur only twice a minute 277 * Reconnect attempts occur only twice a minute
278 */ 278 */
279static int g_connection_count; 279static size_t g_connection_count;
280static ot_time g_connection_reconn; 280static ot_time g_connection_reconn;
281static proxy_peer g_connections[MAX_PEERS]; 281static proxy_peer g_connections[MAX_PEERS];
282 282
283static void handle_reconnects(void) { 283static void handle_reconnects(void) {
284 int i; 284 size_t i;
285 for (i = 0; i < g_connection_count; ++i) 285 for (i = 0; i < g_connection_count; ++i)
286 if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) { 286 if (PROXYPEER_NEEDSCONNECT(g_connections[i].state)) {
287 int64 newfd = socket_tcp6(); 287 int64 newfd = socket_tcp6();
@@ -625,7 +625,7 @@ int main(int argc, char **argv) {
625static void *streamsync_worker(void *args) { 625static void *streamsync_worker(void *args) {
626 (void)args; 626 (void)args;
627 while (1) { 627 while (1) {
628 int bucket; 628 size_t bucket;
629 /* For each bucket... */ 629 /* For each bucket... */
630 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 630 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
631 /* Get exclusive access to that bucket */ 631 /* Get exclusive access to that bucket */
diff --git a/trackerlogic.c b/trackerlogic.c
index 04df544..cacb12b 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -195,7 +195,7 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
195} 195}
196 196
197static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) { 197static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) {
198 unsigned int bucket, num_buckets = 1; 198 size_t bucket, num_buckets = 1;
199 ot_vector *bucket_list = &peer_list->peers; 199 ot_vector *bucket_list = &peer_list->peers;
200 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); 200 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
201 size_t result = compare_size * peer_list->peer_count; 201 size_t result = compare_size * peer_list->peer_count;
@@ -224,7 +224,7 @@ static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *r
224} 224}
225 225
226static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) { 226static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) {
227 unsigned int bucket_offset, bucket_index = 0, num_buckets = 1; 227 size_t bucket_offset, bucket_index = 0, num_buckets = 1;
228 ot_vector *bucket_list = &peer_list->peers; 228 ot_vector *bucket_list = &peer_list->peers;
229 unsigned int shifted_pc = peer_list->peer_count; 229 unsigned int shifted_pc = peer_list->peer_count;
230 unsigned int shifted_step = 0; 230 unsigned int shifted_step = 0;
@@ -262,7 +262,7 @@ static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer
262 bucket_offset -= bucket_list[bucket_index].size; 262 bucket_offset -= bucket_list[bucket_index].size;
263 bucket_index = (bucket_index + 1) % num_buckets; 263 bucket_index = (bucket_index + 1) % num_buckets;
264 } 264 }
265 peer = bucket_list[bucket_index].data + peer_size * bucket_offset; 265 peer = (ot_peer*)bucket_list[bucket_index].data + peer_size * bucket_offset;
266 if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING) { 266 if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING) {
267 r_end -= compare_size; 267 r_end -= compare_size;
268 memcpy(r_end, peer, compare_size); 268 memcpy(r_end, peer, compare_size);
@@ -403,9 +403,10 @@ size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
403} 403}
404 404
405/* Fetches scrape info for a specific torrent */ 405/* Fetches scrape info for a specific torrent */
406size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply) { 406size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, size_t amount, char *reply) {
407 char *r = reply; 407 char *r = reply;
408 int exactmatch, i; 408 int exactmatch;
409 size_t i;
409 410
410 r += sprintf(r, "d5:filesd"); 411 r += sprintf(r, "d5:filesd");
411 412
@@ -489,8 +490,7 @@ size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
489} 490}
490 491
491void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data) { 492void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data) {
492 int bucket; 493 size_t bucket, j;
493 size_t j;
494 494
495 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 495 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
496 ot_vector *torrents_list = mutex_bucket_lock(bucket); 496 ot_vector *torrents_list = mutex_bucket_lock(bucket);
@@ -552,7 +552,7 @@ void exerr(char *message) {
552 exit(111); 552 exit(111);
553} 553}
554 554
555void trackerlogic_init() { 555void trackerlogic_init(void) {
556 g_tracker_id = random(); 556 g_tracker_id = random();
557 557
558 if (!g_stats_path) 558 if (!g_stats_path)
@@ -569,8 +569,8 @@ void trackerlogic_init() {
569} 569}
570 570
571void trackerlogic_deinit(void) { 571void trackerlogic_deinit(void) {
572 int bucket, delta_torrentcount = 0; 572 int delta_torrentcount = 0;
573 size_t j; 573 size_t bucket, j;
574 574
575 /* Free all torrents... */ 575 /* Free all torrents... */
576 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { 576 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
diff --git a/trackerlogic.h b/trackerlogic.h
index 022184d..88d9a11 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -194,7 +194,7 @@ void exerr(char *message);
194 otherwise it is released in return_peers_for_torrent */ 194 otherwise it is released in return_peers_for_torrent */
195size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount); 195size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount);
196size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws); 196size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws);
197size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply); 197size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, size_t amount, char *reply);
198size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply); 198size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply);
199void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count); 199void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count);
200#ifdef _DEBUG_RANDOMTORRENTS 200#ifdef _DEBUG_RANDOMTORRENTS