summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--opentracker.c42
-rw-r--r--opentracker.xcodeproj/project.pbxproj11
-rw-r--r--ot_accesslist.c2
-rw-r--r--ot_accesslist.h7
-rw-r--r--ot_clean.c148
-rw-r--r--ot_clean.h8
-rw-r--r--ot_fullscrape.c1
-rw-r--r--ot_http.c62
-rw-r--r--ot_iovec.h2
-rw-r--r--ot_livesync.c19
-rw-r--r--ot_livesync.h4
-rw-r--r--ot_mutex.c2
-rw-r--r--ot_mutex.h13
-rw-r--r--ot_stats.c71
-rw-r--r--ot_stats.h4
-rw-r--r--ot_udp.c2
-rw-r--r--ot_vector.c239
-rw-r--r--ot_vector.h20
-rw-r--r--tests/testsuite.sh12
-rw-r--r--tests/testsuite2.sh2
-rw-r--r--trackerlogic.c291
-rw-r--r--trackerlogic.h32
23 files changed, 463 insertions, 538 deletions
diff --git a/Makefile b/Makefile
index 35d2618..16b027c 100644
--- a/Makefile
+++ b/Makefile
@@ -22,16 +22,13 @@ BINDIR?=$(PREFIX)/bin
22#FEATURES+=-DWANT_ACCESSLIST_BLACK 22#FEATURES+=-DWANT_ACCESSLIST_BLACK
23#FEATURES+=-DWANT_ACCESSLIST_WHITE 23#FEATURES+=-DWANT_ACCESSLIST_WHITE
24 24
25#FEATURES+=-DWANT_SYNC_BATCH
26#FEATURES+=-DWANT_SYNC_LIVE 25#FEATURES+=-DWANT_SYNC_LIVE
27
28#FEATURES+=-DWANT_UTORRENT1600_WORKAROUND 26#FEATURES+=-DWANT_UTORRENT1600_WORKAROUND
29#FEATURES+=-DWANT_IP_FROM_QUERY_STRING 27#FEATURES+=-DWANT_IP_FROM_QUERY_STRING
30#FEATURES+=-DWANT_COMPRESSION_GZIP 28#FEATURES+=-DWANT_COMPRESSION_GZIP
31#FEATURES+=-DWANT_LOG_NETWORKS 29#FEATURES+=-DWANT_LOG_NETWORKS
32#FEATURES+=-DWANT_RESTRICT_STATS 30#FEATURES+=-DWANT_RESTRICT_STATS
33#FEATURES+=-D_DEBUG_HTTPERROR 31#FEATURES+=-D_DEBUG_HTTPERROR
34#FEATURES+=-D_DEBUG_VECTOR
35 32
36FEATURES+=-DWANT_FULLSCRAPE 33FEATURES+=-DWANT_FULLSCRAPE
37 34
@@ -42,8 +39,8 @@ CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-pedantic -ansi
42LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz 39LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz
43 40
44BINARY =opentracker 41BINARY =opentracker
45HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.h ot_stats.h ot_sync.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 42HEADERS=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
46SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_sync.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c 43SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_vector.c ot_clean.c ot_udp.c ot_iovec.c ot_fullscrape.c ot_accesslist.c ot_http.c ot_livesync.c
47 44
48OBJECTS = $(SOURCES:%.c=%.o) 45OBJECTS = $(SOURCES:%.c=%.o)
49OBJECTS_debug = $(SOURCES:%.c=%.debug.o) 46OBJECTS_debug = $(SOURCES:%.c=%.debug.o)
diff --git a/opentracker.c b/opentracker.c
index f76c042..f8587c9 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -5,42 +5,36 @@
5 $Id$ */ 5 $Id$ */
6 6
7/* System */ 7/* System */
8#include <stdlib.h>
8#include <string.h> 9#include <string.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <arpa/inet.h> 10#include <arpa/inet.h>
11#include <sys/socket.h>
12#include <unistd.h> 12#include <unistd.h>
13#include <stdlib.h>
14#include <errno.h> 13#include <errno.h>
15#include <signal.h> 14#include <signal.h>
16#include <stdio.h> 15#include <stdio.h>
17#include <pwd.h> 16#include <pwd.h>
18#include <ctype.h> 17#include <ctype.h>
19#include <arpa/inet.h>
20 18
21/* Libowfat */ 19/* Libowfat */
22#include "socket.h" 20#include "socket.h"
23#include "io.h" 21#include "io.h"
24#include "iob.h" 22#include "iob.h"
25#include "array.h"
26#include "byte.h" 23#include "byte.h"
27#include "fmt.h"
28#include "scan.h" 24#include "scan.h"
29#include "ip4.h" 25#include "ip4.h"
30 26
31/* Opentracker */ 27/* Opentracker */
32#include "trackerlogic.h" 28#include "trackerlogic.h"
33#include "ot_iovec.h"
34#include "ot_mutex.h" 29#include "ot_mutex.h"
35#include "ot_http.h" 30#include "ot_http.h"
36#include "ot_udp.h" 31#include "ot_udp.h"
37#include "ot_clean.h"
38#include "ot_accesslist.h" 32#include "ot_accesslist.h"
39#include "ot_stats.h" 33#include "ot_stats.h"
40#include "ot_livesync.h" 34#include "ot_livesync.h"
41 35
42/* Globals */ 36/* Globals */
43time_t g_now; 37time_t g_now_seconds;
44char * g_redirecturl = NULL; 38char * g_redirecturl = NULL;
45uint32_t g_tracker_id; 39uint32_t g_tracker_id;
46 40
@@ -61,7 +55,7 @@ static void signal_handler( int s ) {
61 trackerlogic_deinit(); 55 trackerlogic_deinit();
62 exit( 0 ); 56 exit( 0 );
63 } else if( s == SIGALRM ) { 57 } else if( s == SIGALRM ) {
64 g_now = time(NULL); 58 g_now_seconds = time(NULL);
65 alarm(5); 59 alarm(5);
66 } 60 }
67} 61}
@@ -135,7 +129,7 @@ static ssize_t handle_read( const int64 clientsocket ) {
135 if( array_failed( &h->request ) ) 129 if( array_failed( &h->request ) )
136 return http_issue_error( clientsocket, CODE_HTTPERROR_500 ); 130 return http_issue_error( clientsocket, CODE_HTTPERROR_500 );
137 131
138 if( ( array_bytes( &h->request ) > 8192 ) && !accesslist_isblessed( (char*)&h->ip, OT_PERMISSION_MAY_SYNC ) ) 132 if( array_bytes( &h->request ) > 8192 )
139 return http_issue_error( clientsocket, CODE_HTTPERROR_500 ); 133 return http_issue_error( clientsocket, CODE_HTTPERROR_500 );
140 134
141 if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) ) 135 if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) )
@@ -178,7 +172,7 @@ static void handle_accept( const int64 serversocket ) {
178 /* That breaks taia encapsulation. But there is no way to take system 172 /* That breaks taia encapsulation. But there is no way to take system
179 time this often in FreeBSD and libowfat does not allow to set unix time */ 173 time this often in FreeBSD and libowfat does not allow to set unix time */
180 taia_uint( &t, 0 ); /* Clear t */ 174 taia_uint( &t, 0 ); /* Clear t */
181 tai_unix( &(t.sec), (g_now + OT_CLIENT_TIMEOUT) ); 175 tai_unix( &(t.sec), (g_now_seconds + OT_CLIENT_TIMEOUT) );
182 io_timeout( i, t ); 176 io_timeout( i, t );
183 } 177 }
184 178
@@ -187,8 +181,7 @@ static void handle_accept( const int64 serversocket ) {
187} 181}
188 182
189static void server_mainloop( ) { 183static void server_mainloop( ) {
190 static time_t ot_last_clean_time; 184 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
191 time_t next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
192 struct iovec *iovector; 185 struct iovec *iovector;
193 int iovec_entries; 186 int iovec_entries;
194 187
@@ -213,20 +206,14 @@ static void server_mainloop( ) {
213 while( ( i = io_canwrite( ) ) != -1 ) 206 while( ( i = io_canwrite( ) ) != -1 )
214 handle_write( i ); 207 handle_write( i );
215 208
216 if( g_now > next_timeout_check ) { 209 if( g_now_seconds > next_timeout_check ) {
217 while( ( i = io_timeouted() ) != -1 ) 210 while( ( i = io_timeouted() ) != -1 )
218 handle_dead( i ); 211 handle_dead( i );
219 next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 212 next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
220 } 213 }
221 214
222 livesync_ticker(); 215 livesync_ticker();
223 216
224 /* See if we need to move our pools */
225 if( NOW != ot_last_clean_time ) {
226 ot_last_clean_time = NOW;
227 clean_all_torrents();
228 }
229
230 /* Enforce setting the clock */ 217 /* Enforce setting the clock */
231 signal_handler( SIGALRM ); 218 signal_handler( SIGALRM );
232 } 219 }
@@ -266,7 +253,7 @@ char * set_config_option( char **option, char *value ) {
266 fprintf( stderr, "Setting config option: %s\n", value ); 253 fprintf( stderr, "Setting config option: %s\n", value );
267#endif 254#endif
268 while( isspace(*value) ) ++value; 255 while( isspace(*value) ) ++value;
269 if( *option ) free( *option ); 256 free( *option );
270 return *option = strdup( value ); 257 return *option = strdup( value );
271} 258}
272 259
@@ -342,11 +329,6 @@ int parse_configfile( char * config_filename ) {
342#endif 329#endif
343 } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) { 330 } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
344 set_config_option( &g_redirecturl, p+21 ); 331 set_config_option( &g_redirecturl, p+21 );
345#ifdef WANT_SYNC_BATCH
346 } else if(!byte_diff(p, 26, "batchsync.cluster.admin_ip" ) && isspace(p[26])) {
347 if(!scan_ip4( p+27, tmpip )) goto parse_error;
348 accesslist_blessip( tmpip, OT_PERMISSION_MAY_SYNC );
349#endif
350#ifdef WANT_SYNC_LIVE 332#ifdef WANT_SYNC_LIVE
351 } else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) { 333 } else if(!byte_diff(p, 24, "livesync.cluster.node_ip" ) && isspace(p[24])) {
352 if( !scan_ip4( p+25, tmpip )) goto parse_error; 334 if( !scan_ip4( p+25, tmpip )) goto parse_error;
@@ -408,7 +390,7 @@ while( scanon ) {
408 break; 390 break;
409 case 'f': bound += parse_configfile( optarg ); break; 391 case 'f': bound += parse_configfile( optarg ); break;
410 case 'h': help( argv[0] ); exit( 0 ); 392 case 'h': help( argv[0] ); exit( 0 );
411 case 'v': write( 2, static_inbuf, stats_return_tracker_version( static_inbuf )); exit( 0 ); 393 case 'v': stats_return_tracker_version( static_inbuf ); fputs( static_inbuf, stderr ); exit( 0 );
412 default: 394 default:
413 case '?': usage( argv[0] ); exit( 1 ); 395 case '?': usage( argv[0] ); exit( 1 );
414 } 396 }
@@ -435,7 +417,7 @@ while( scanon ) {
435 signal( SIGINT, signal_handler ); 417 signal( SIGINT, signal_handler );
436 signal( SIGALRM, signal_handler ); 418 signal( SIGALRM, signal_handler );
437 419
438 g_now = time( NULL ); 420 g_now_seconds = time( NULL );
439 421
440 if( trackerlogic_init( g_serverdir ? g_serverdir : "." ) == -1 ) 422 if( trackerlogic_init( g_serverdir ? g_serverdir : "." ) == -1 )
441 panic( "Logic not started" ); 423 panic( "Logic not started" );
diff --git a/opentracker.xcodeproj/project.pbxproj b/opentracker.xcodeproj/project.pbxproj
index 895f63f..bccf44f 100644
--- a/opentracker.xcodeproj/project.pbxproj
+++ b/opentracker.xcodeproj/project.pbxproj
@@ -14,7 +14,6 @@
14 654A808A0CD832FD009035DE /* scan_urlencoded_query.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80850CD832FC009035DE /* scan_urlencoded_query.c */; }; 14 654A808A0CD832FD009035DE /* scan_urlencoded_query.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80850CD832FC009035DE /* scan_urlencoded_query.c */; };
15 654A808B0CD832FD009035DE /* trackerlogic.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80870CD832FC009035DE /* trackerlogic.c */; }; 15 654A808B0CD832FD009035DE /* trackerlogic.c in Sources */ = {isa = PBXBuildFile; fileRef = 654A80870CD832FC009035DE /* trackerlogic.c */; };
16 65542D8B0CE078E800469330 /* ot_vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8A0CE078E800469330 /* ot_vector.c */; }; 16 65542D8B0CE078E800469330 /* ot_vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8A0CE078E800469330 /* ot_vector.c */; };
17 65542D8E0CE07BA900469330 /* ot_sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8D0CE07BA900469330 /* ot_sync.c */; };
18 65542D930CE07CED00469330 /* ot_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8F0CE07CED00469330 /* ot_mutex.c */; }; 17 65542D930CE07CED00469330 /* ot_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D8F0CE07CED00469330 /* ot_mutex.c */; };
19 65542D940CE07CED00469330 /* ot_stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D910CE07CED00469330 /* ot_stats.c */; }; 18 65542D940CE07CED00469330 /* ot_stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542D910CE07CED00469330 /* ot_stats.c */; };
20 65542E750CE08B9100469330 /* ot_clean.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542E740CE08B9100469330 /* ot_clean.c */; }; 19 65542E750CE08B9100469330 /* ot_clean.c in Sources */ = {isa = PBXBuildFile; fileRef = 65542E740CE08B9100469330 /* ot_clean.c */; };
@@ -53,8 +52,6 @@
53 654A80880CD832FC009035DE /* trackerlogic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trackerlogic.h; sourceTree = "<group>"; }; 52 654A80880CD832FC009035DE /* trackerlogic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trackerlogic.h; sourceTree = "<group>"; };
54 65542D890CE078E800469330 /* ot_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_vector.h; sourceTree = "<group>"; }; 53 65542D890CE078E800469330 /* ot_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_vector.h; sourceTree = "<group>"; };
55 65542D8A0CE078E800469330 /* ot_vector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_vector.c; sourceTree = "<group>"; }; 54 65542D8A0CE078E800469330 /* ot_vector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_vector.c; sourceTree = "<group>"; };
56 65542D8C0CE07BA900469330 /* ot_sync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_sync.h; sourceTree = "<group>"; };
57 65542D8D0CE07BA900469330 /* ot_sync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_sync.c; sourceTree = "<group>"; };
58 65542D8F0CE07CED00469330 /* ot_mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_mutex.c; sourceTree = "<group>"; }; 55 65542D8F0CE07CED00469330 /* ot_mutex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_mutex.c; sourceTree = "<group>"; };
59 65542D900CE07CED00469330 /* ot_mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_mutex.h; sourceTree = "<group>"; }; 56 65542D900CE07CED00469330 /* ot_mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ot_mutex.h; sourceTree = "<group>"; };
60 65542D910CE07CED00469330 /* ot_stats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_stats.c; sourceTree = "<group>"; }; 57 65542D910CE07CED00469330 /* ot_stats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ot_stats.c; sourceTree = "<group>"; };
@@ -114,7 +111,6 @@
114 653A56B40CE28EC5000CF140 /* ot_iovec.c */, 111 653A56B40CE28EC5000CF140 /* ot_iovec.c */,
115 65542D8F0CE07CED00469330 /* ot_mutex.c */, 112 65542D8F0CE07CED00469330 /* ot_mutex.c */,
116 65542D910CE07CED00469330 /* ot_stats.c */, 113 65542D910CE07CED00469330 /* ot_stats.c */,
117 65542D8D0CE07BA900469330 /* ot_sync.c */,
118 65542EE70CE0CA6B00469330 /* ot_udp.c */, 114 65542EE70CE0CA6B00469330 /* ot_udp.c */,
119 65542D8A0CE078E800469330 /* ot_vector.c */, 115 65542D8A0CE078E800469330 /* ot_vector.c */,
120 654A80850CD832FC009035DE /* scan_urlencoded_query.c */, 116 654A80850CD832FC009035DE /* scan_urlencoded_query.c */,
@@ -144,9 +140,8 @@
144 653A56B30CE28EC5000CF140 /* ot_iovec.h */, 140 653A56B30CE28EC5000CF140 /* ot_iovec.h */,
145 65542D900CE07CED00469330 /* ot_mutex.h */, 141 65542D900CE07CED00469330 /* ot_mutex.h */,
146 65542D920CE07CED00469330 /* ot_stats.h */, 142 65542D920CE07CED00469330 /* ot_stats.h */,
147 65542D8C0CE07BA900469330 /* ot_sync.h */,
148 65542EE60CE0CA6B00469330 /* ot_udp.h */,
149 65542D890CE078E800469330 /* ot_vector.h */, 143 65542D890CE078E800469330 /* ot_vector.h */,
144 65542EE60CE0CA6B00469330 /* ot_udp.h */,
150 654A80860CD832FC009035DE /* scan_urlencoded_query.h */, 145 654A80860CD832FC009035DE /* scan_urlencoded_query.h */,
151 654A80880CD832FC009035DE /* trackerlogic.h */, 146 654A80880CD832FC009035DE /* trackerlogic.h */,
152 ); 147 );
@@ -244,7 +239,6 @@
244 654A808A0CD832FD009035DE /* scan_urlencoded_query.c in Sources */, 239 654A808A0CD832FD009035DE /* scan_urlencoded_query.c in Sources */,
245 654A808B0CD832FD009035DE /* trackerlogic.c in Sources */, 240 654A808B0CD832FD009035DE /* trackerlogic.c in Sources */,
246 65542D8B0CE078E800469330 /* ot_vector.c in Sources */, 241 65542D8B0CE078E800469330 /* ot_vector.c in Sources */,
247 65542D8E0CE07BA900469330 /* ot_sync.c in Sources */,
248 65542D930CE07CED00469330 /* ot_mutex.c in Sources */, 242 65542D930CE07CED00469330 /* ot_mutex.c in Sources */,
249 65542D940CE07CED00469330 /* ot_stats.c in Sources */, 243 65542D940CE07CED00469330 /* ot_stats.c in Sources */,
250 65542E750CE08B9100469330 /* ot_clean.c in Sources */, 244 65542E750CE08B9100469330 /* ot_clean.c in Sources */,
@@ -282,6 +276,7 @@
282 isa = XCBuildConfiguration; 276 isa = XCBuildConfiguration;
283 buildSettings = { 277 buildSettings = {
284 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 278 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
279 GCC_ENABLE_FIX_AND_CONTINUE = YES;
285 GCC_MODEL_TUNING = G5; 280 GCC_MODEL_TUNING = G5;
286 INSTALL_PATH = /usr/local/bin; 281 INSTALL_PATH = /usr/local/bin;
287 LIBRARY_SEARCH_PATHS = ( 282 LIBRARY_SEARCH_PATHS = (
@@ -295,6 +290,7 @@
295 1DEB928A08733DD80010E9CD /* Debug */ = { 290 1DEB928A08733DD80010E9CD /* Debug */ = {
296 isa = XCBuildConfiguration; 291 isa = XCBuildConfiguration;
297 buildSettings = { 292 buildSettings = {
293 GCC_PREPROCESSOR_DEFINITIONS = WANT_IP_FROM_QUERY_STRING;
298 GCC_WARN_ABOUT_RETURN_TYPE = YES; 294 GCC_WARN_ABOUT_RETURN_TYPE = YES;
299 GCC_WARN_UNUSED_VARIABLE = YES; 295 GCC_WARN_UNUSED_VARIABLE = YES;
300 HEADER_SEARCH_PATHS = ../libowfat/; 296 HEADER_SEARCH_PATHS = ../libowfat/;
@@ -309,6 +305,7 @@
309 buildSettings = { 305 buildSettings = {
310 ARCHS = ppc; 306 ARCHS = ppc;
311 DEAD_CODE_STRIPPING = NO; 307 DEAD_CODE_STRIPPING = NO;
308 GCC_PREPROCESSOR_DEFINITIONS = WANT_IP_FROM_QUERY_STRING;
312 GCC_WARN_ABOUT_RETURN_TYPE = YES; 309 GCC_WARN_ABOUT_RETURN_TYPE = YES;
313 GCC_WARN_UNUSED_VARIABLE = YES; 310 GCC_WARN_UNUSED_VARIABLE = YES;
314 HEADER_SEARCH_PATHS = ../libowfat/; 311 HEADER_SEARCH_PATHS = ../libowfat/;
diff --git a/ot_accesslist.c b/ot_accesslist.c
index 59d3659..d306aeb 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -16,6 +16,7 @@
16/* Opentracker */ 16/* Opentracker */
17#include "trackerlogic.h" 17#include "trackerlogic.h"
18#include "ot_accesslist.h" 18#include "ot_accesslist.h"
19#include "ot_vector.h"
19 20
20/* GLOBAL VARIABLES */ 21/* GLOBAL VARIABLES */
21#ifdef WANT_ACCESSLIST 22#ifdef WANT_ACCESSLIST
@@ -110,7 +111,6 @@ int accesslist_blessip( char *ip, ot_permissions permissions ) {
110 uint8_t *_ip = (uint8_t*)ip; 111 uint8_t *_ip = (uint8_t*)ip;
111 fprintf( stderr, "Blessing ip address %d.%d.%d.%d with:", _ip[0], _ip[1], _ip[2], _ip[3]); 112 fprintf( stderr, "Blessing ip address %d.%d.%d.%d with:", _ip[0], _ip[1], _ip[2], _ip[3]);
112 if( permissions & OT_PERMISSION_MAY_STAT ) fputs( " may_fetch_stats", stderr ); 113 if( permissions & OT_PERMISSION_MAY_STAT ) fputs( " may_fetch_stats", stderr );
113 if( permissions & OT_PERMISSION_MAY_SYNC ) fputs( " may_sync_batch", stderr );
114 if( permissions & OT_PERMISSION_MAY_LIVESYNC ) fputs( " may_sync_live", stderr ); 114 if( permissions & OT_PERMISSION_MAY_LIVESYNC ) fputs( " may_sync_live", stderr );
115 if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) fputs( " may_fetch_fullscrapes", stderr ); 115 if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) fputs( " may_fetch_fullscrapes", stderr );
116 if( !permissions ) fputs(" nothing.\n", stderr); else fputs(".\n", stderr ); 116 if( !permissions ) fputs(" nothing.\n", stderr); else fputs(".\n", stderr );
diff --git a/ot_accesslist.h b/ot_accesslist.h
index 8d87710..9c93187 100644
--- a/ot_accesslist.h
+++ b/ot_accesslist.h
@@ -7,7 +7,7 @@
7#define __OT_ACCESSLIST_H__ 7#define __OT_ACCESSLIST_H__
8 8
9#if defined ( WANT_ACCESSLIST_BLACK ) && defined (WANT_ACCESSLIST_WHITE ) 9#if defined ( WANT_ACCESSLIST_BLACK ) && defined (WANT_ACCESSLIST_WHITE )
10 #error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive. 10# error WANT_ACCESSLIST_BLACK and WANT_ACCESSLIST_WHITE are exclusive.
11#endif 11#endif
12 12
13#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE ) 13#if defined ( WANT_ACCESSLIST_BLACK ) || defined (WANT_ACCESSLIST_WHITE )
@@ -24,9 +24,8 @@ extern char *g_accesslist_filename;
24 24
25typedef enum { 25typedef enum {
26 OT_PERMISSION_MAY_FULLSCRAPE = 0x1, 26 OT_PERMISSION_MAY_FULLSCRAPE = 0x1,
27 OT_PERMISSION_MAY_SYNC = 0x2, 27 OT_PERMISSION_MAY_STAT = 0x2,
28 OT_PERMISSION_MAY_STAT = 0x4, 28 OT_PERMISSION_MAY_LIVESYNC = 0x4
29 OT_PERMISSION_MAY_LIVESYNC = 0x8
30} ot_permissions; 29} ot_permissions;
31 30
32int accesslist_blessip( char * ip, ot_permissions permissions ); 31int accesslist_blessip( char * ip, ot_permissions permissions );
diff --git a/ot_clean.c b/ot_clean.c
index 4f18433..e4d8ca2 100644
--- a/ot_clean.c
+++ b/ot_clean.c
@@ -7,29 +7,53 @@
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#include <pthread.h> 9#include <pthread.h>
10#include <sys/uio.h>
11#include <unistd.h> 10#include <unistd.h>
11#include <stdint.h>
12 12
13/* Libowfat */ 13/* Libowfat */
14#include "byte.h"
15#include "io.h" 14#include "io.h"
16 15
17/* Opentracker */ 16/* Opentracker */
18#include "trackerlogic.h" 17#include "trackerlogic.h"
19#include "ot_mutex.h" 18#include "ot_mutex.h"
19#include "ot_vector.h"
20#include "ot_clean.h"
21
22/* Returns amount of removed peers */
23static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) {
24 ot_peer *last_peer = peers + peer_count, *insert_point;
25 time_t timediff;
26
27 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
28 while( peers < last_peer ) {
29 if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT )
30 break;
31 OT_PEERTIME( peers++ ) = timediff;
32 }
33
34 /* If we at least remove one peer, we have to copy */
35 insert_point = peers;
36 while( peers < last_peer )
37 if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) {
38 OT_PEERTIME( peers ) = timediff;
39 *(uint64_t*)(insert_point++) = *(uint64_t*)(peers++);
40 } else
41 if( OT_FLAG( peers++ ) & PEER_FLAG_SEEDING )
42 (*removed_seeders)++;
43
44 return peers - insert_point;
45}
20 46
21/* Clean a single torrent 47/* Clean a single torrent
22 return 1 if torrent timed out 48 return 1 if torrent timed out
23*/ 49*/
24int clean_single_torrent( ot_torrent *torrent ) { 50int clean_single_torrent( ot_torrent *torrent ) {
25 ot_peerlist *peer_list = torrent->peer_list; 51 ot_peerlist *peer_list = torrent->peer_list;
26 size_t peers_count = 0, seeds_count; 52 ot_vector *bucket_list = &peer_list->peers;
27 time_t timedout = (int)( NOW - peer_list->base ); 53 time_t timedout = (time_t)( g_now_minutes - peer_list->base );
28 int i; 54 int num_buckets = 1, removed_seeders = 0;
29#ifdef WANT_SYNC_BATCH
30 char *new_peers;
31#endif
32 55
56 /* No need to clean empty torrent */
33 if( !timedout ) 57 if( !timedout )
34 return 0; 58 return 0;
35 59
@@ -38,97 +62,67 @@ int clean_single_torrent( ot_torrent *torrent ) {
38 return 1; 62 return 1;
39 63
40 /* Nothing to be cleaned here? Test if torrent is worth keeping */ 64 /* Nothing to be cleaned here? Test if torrent is worth keeping */
41 if( timedout > OT_POOLS_COUNT ) { 65 if( timedout > OT_PEER_TIMEOUT ) {
42 if( !peer_list->peer_count ) 66 if( !peer_list->peer_count )
43 return peer_list->down_count ? 0 : 1; 67 return peer_list->down_count ? 0 : 1;
44 timedout = OT_POOLS_COUNT; 68 timedout = OT_PEER_TIMEOUT;
45 } 69 }
46 70
47 /* Release vectors that have timed out */ 71 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
48 for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i ) 72 num_buckets = bucket_list->size;
49 free( peer_list->peers[i].data); 73 bucket_list = (ot_vector *)bucket_list->data;
50
51 /* Shift vectors back by the amount of pools that were shifted out */
52 memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) );
53 byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
54
55 /* Shift back seed counts as well */
56 memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) );
57 byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout );
58
59#ifdef WANT_SYNC_BATCH
60 /* Save the block modified within last OT_POOLS_TIMEOUT */
61 if( peer_list->peers[1].size &&
62 ( new_peers = realloc( peer_list->changeset.data, sizeof( ot_peer ) * peer_list->peers[1].size ) ) )
63 {
64 memmove( new_peers, peer_list->peers[1].data, peer_list->peers[1].size );
65 peer_list->changeset.data = new_peers;
66 peer_list->changeset.size = sizeof( ot_peer ) * peer_list->peers[1].size;
67 } else {
68 free( peer_list->changeset.data );
69
70 memset( &peer_list->changeset, 0, sizeof( ot_vector ) );
71 } 74 }
72#endif
73 75
74 peers_count = seeds_count = 0; 76 while( num_buckets-- ) {
75 for( i = 0; i < OT_POOLS_COUNT; ++i ) { 77 size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->size, timedout, &removed_seeders );
76 peers_count += peer_list->peers[i].size; 78 peer_list->peer_count -= removed_peers;
77 seeds_count += peer_list->seed_counts[i]; 79 bucket_list->size -= removed_peers;
80 if( bucket_list->size < removed_peers )
81 vector_fixup_peers( bucket_list );
82 ++bucket_list;
78 } 83 }
79 peer_list->seed_count = seeds_count;
80 peer_list->peer_count = peers_count;
81 84
82 if( peers_count ) 85 peer_list->seed_count -= removed_seeders;
83 peer_list->base = NOW; 86
87 /* See, if we need to convert a torrent from simple vector to bucket list */
88 if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) )
89 vector_redistribute_buckets( peer_list );
90
91 if( peer_list->peer_count )
92 peer_list->base = g_now_minutes;
84 else { 93 else {
85 /* When we got here, the last time that torrent 94 /* When we got here, the last time that torrent
86 has been touched is OT_POOLS_COUNT units before */ 95 has been touched is OT_PEER_TIMEOUT Minutes before */
87 peer_list->base = NOW - OT_POOLS_COUNT; 96 peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
88 } 97 }
89 return 0; 98 return 0;
90}
91
92static void clean_make() {
93 int bucket;
94
95 for( bucket = OT_BUCKET_COUNT - 1; bucket >= 0; --bucket ) {
96 ot_vector *torrents_list = mutex_bucket_lock( bucket );
97 size_t toffs;
98 99
99 for( toffs=0; toffs<torrents_list->size; ++toffs ) {
100 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs;
101 if( clean_single_torrent( torrent ) ) {
102 vector_remove_torrent( torrents_list, torrent );
103 --toffs; continue;
104 }
105 }
106 mutex_bucket_unlock( bucket );
107
108 /* We want the cleanup to be spread about 2 Minutes to reduce load spikes
109 during cleanup. Sleeping around two minutes was chosen to allow enough
110 time for the actual work and fluctuations in timer. */
111 usleep( ( 2 * 60 * 1000000 ) / OT_BUCKET_COUNT );
112 }
113} 100}
114 101
115/* Clean up all peers in current bucket, remove timedout pools and 102/* Clean up all peers in current bucket, remove timedout pools and
116 torrents */ 103 torrents */
117static void * clean_worker( void * args ) { 104static void * clean_worker( void * args ) {
118 args = args; 105 args=args;
119 while( 1 ) { 106 while( 1 ) {
120 ot_tasktype tasktype = TASK_CLEAN; 107 int bucket = OT_BUCKET_COUNT;
121 ot_taskid taskid = mutex_workqueue_poptask( &tasktype ); 108 while( bucket-- ) {
122 clean_make( ); 109 ot_vector *torrents_list = mutex_bucket_lock( bucket );
123 mutex_workqueue_pushsuccess( taskid ); 110 size_t toffs;
111
112 for( toffs=0; toffs<torrents_list->size; ++toffs ) {
113 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs;
114 if( clean_single_torrent( torrent ) ) {
115 vector_remove_torrent( torrents_list, torrent );
116 --toffs; continue;
117 }
118 }
119 mutex_bucket_unlock( bucket );
120 usleep( OT_CLEAN_SLEEP );
121 }
124 } 122 }
125 return NULL; 123 return NULL;
126} 124}
127 125
128void clean_all_torrents( ) {
129 mutex_workqueue_pushtask( 0, TASK_CLEAN );
130}
131
132static pthread_t thread_id; 126static pthread_t thread_id;
133void clean_init( void ) { 127void clean_init( void ) {
134 pthread_create( &thread_id, NULL, clean_worker, NULL ); 128 pthread_create( &thread_id, NULL, clean_worker, NULL );
diff --git a/ot_clean.h b/ot_clean.h
index 7fefddb..cb450c4 100644
--- a/ot_clean.h
+++ b/ot_clean.h
@@ -6,10 +6,14 @@
6#ifndef __OT_CLEAN_H__ 6#ifndef __OT_CLEAN_H__
7#define __OT_CLEAN_H__ 7#define __OT_CLEAN_H__
8 8
9/* The amount of time a clean cycle should take */
10#define OT_CLEAN_INTERVAL_MINUTES 2
11
12/* So after each bucket wait 1 / OT_BUCKET_COUNT intervals */
13#define OT_CLEAN_SLEEP ( ( ( OT_CLEAN_INTERVAL_MINUTES ) * 60 * 1000000 ) / ( OT_BUCKET_COUNT ) )
14
9void clean_init( void ); 15void clean_init( void );
10void clean_deinit( void ); 16void clean_deinit( void );
11
12void clean_all_torrents( void );
13int clean_single_torrent( ot_torrent *torrent ); 17int clean_single_torrent( ot_torrent *torrent );
14 18
15#endif 19#endif
diff --git a/ot_fullscrape.c b/ot_fullscrape.c
index fa17d61..dfad640 100644
--- a/ot_fullscrape.c
+++ b/ot_fullscrape.c
@@ -7,7 +7,6 @@
7 7
8/* System */ 8/* System */
9#include <sys/param.h> 9#include <sys/param.h>
10#include <sys/uio.h>
11#include <stdio.h> 10#include <stdio.h>
12#include <string.h> 11#include <string.h>
13#include <pthread.h> 12#include <pthread.h>
diff --git a/ot_http.c b/ot_http.c
index e0062ce..d8ab0a2 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -5,7 +5,6 @@
5 5
6/* System */ 6/* System */
7#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/uio.h>
9#include <arpa/inet.h> 8#include <arpa/inet.h>
10#include <stdlib.h> 9#include <stdlib.h>
11#include <stdio.h> 10#include <stdio.h>
@@ -26,7 +25,6 @@
26#include "ot_fullscrape.h" 25#include "ot_fullscrape.h"
27#include "ot_stats.h" 26#include "ot_stats.h"
28#include "ot_accesslist.h" 27#include "ot_accesslist.h"
29#include "ot_sync.h"
30 28
31#define OT_MAXMULTISCRAPE_COUNT 64 29#define OT_MAXMULTISCRAPE_COUNT 64
32static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT]; 30static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT];
@@ -165,52 +163,6 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct
165 return 0; 163 return 0;
166} 164}
167 165
168#ifdef WANT_SYNC_BATCH
169static ssize_t http_handle_sync( const int64 client_socket, char *data ) {
170 struct http_data* h = io_getcookie( client_socket );
171 size_t len;
172 int mode = SYNC_OUT, scanon = 1;
173 char *c = data;
174
175 if( !accesslist_isblessed( h->ip, OT_PERMISSION_MAY_SYNC ) )
176 HTTPERROR_403_IP;
177
178 while( scanon ) {
179 switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
180 case -2: scanon = 0; break; /* TERMINATOR */
181 case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
182 default: scan_urlencoded_skipvalue( &c ); break;
183 case 9:
184 if(byte_diff(data,9,"changeset")) {
185 scan_urlencoded_skipvalue( &c );
186 continue;
187 }
188 /* ignore this, when we dont at least see "d4:syncdee" */
189 if( ( len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) < 10 ) HTTPERROR_400_PARAM;
190 if( add_changeset_to_tracker( (uint8_t*)data, len ) ) HTTPERROR_400_PARAM;
191 if( mode == SYNC_OUT ) {
192 stats_issue_event( EVENT_SYNC_IN, FLAG_TCP, 0 );
193 mode = SYNC_IN;
194 }
195 break;
196 }
197 }
198
199 if( mode == SYNC_OUT ) {
200 /* Pass this task to the worker thread */
201 h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;
202 stats_issue_event( EVENT_SYNC_OUT_REQUEST, FLAG_TCP, 0 );
203 sync_deliver( client_socket );
204 io_dontwantread( client_socket );
205 return -2;
206 }
207
208 /* Simple but proof for now */
209 memmove( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, "OK", 2);
210 return 2;
211}
212#endif
213
214static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) { 166static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) {
215 char *c = data; 167 char *c = data;
216 int mode = TASK_STATS_PEERS, scanon = 1, format = 0; 168 int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
@@ -245,10 +197,6 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
245 mode = TASK_STATS_UDP; 197 mode = TASK_STATS_UDP;
246 else if( !byte_diff(data,4,"busy")) 198 else if( !byte_diff(data,4,"busy"))
247 mode = TASK_STATS_BUSY_NETWORKS; 199 mode = TASK_STATS_BUSY_NETWORKS;
248 else if( !byte_diff(data,4,"dmem"))
249 mode = TASK_STATS_MEMORY;
250 else if( !byte_diff(data,4,"vdeb"))
251 mode = TASK_STATS_VECTOR_DEBUG;
252 else if( !byte_diff(data,4,"torr")) 200 else if( !byte_diff(data,4,"torr"))
253 mode = TASK_STATS_TORRENTS; 201 mode = TASK_STATS_TORRENTS;
254 else if( !byte_diff(data,4,"fscr")) 202 else if( !byte_diff(data,4,"fscr"))
@@ -265,7 +213,7 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
265 case 5: 213 case 5:
266 if( !byte_diff(data,5,"top10")) 214 if( !byte_diff(data,5,"top10"))
267 mode = TASK_STATS_TOP10; 215 mode = TASK_STATS_TOP10;
268 if( !byte_diff(data,5,"renew")) 216 else if( !byte_diff(data,5,"renew"))
269 mode = TASK_STATS_RENEW; 217 mode = TASK_STATS_RENEW;
270 else 218 else
271 HTTPERROR_400_PARAM; 219 HTTPERROR_400_PARAM;
@@ -524,7 +472,7 @@ static ssize_t http_handle_announce( const int64 client_socket, char *data ) {
524 len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP ); 472 len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP );
525 else { 473 else {
526 torrent = add_peer_to_torrent( hash, &peer WANT_SYNC_PARAM( 0 ) ); 474 torrent = add_peer_to_torrent( hash, &peer WANT_SYNC_PARAM( 0 ) );
527 if( !torrent || !( len = return_peers_for_torrent( hash, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP ) ) ) HTTPERROR_500; 475 if( !torrent || !( len = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP ) ) ) HTTPERROR_500;
528 } 476 }
529 stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, len); 477 stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, len);
530 return len; 478 return len;
@@ -573,12 +521,6 @@ ssize_t http_handle_request( const int64 client_socket, char *data, size_t recv_
573 reply_size = http_handle_scrape( client_socket, c ); 521 reply_size = http_handle_scrape( client_socket, c );
574 /* All the rest is matched the standard way */ 522 /* All the rest is matched the standard way */
575 else switch( len ) { 523 else switch( len ) {
576#ifdef WANT_SYNC_BATCH
577 case 4: /* sync ? */
578 if( byte_diff( data, 4, "sync") ) HTTPERROR_404;
579 reply_size = http_handle_sync( client_socket, c );
580 break;
581#endif
582 case 5: /* stats ? */ 524 case 5: /* stats ? */
583 if( byte_diff( data, 5, "stats") ) HTTPERROR_404; 525 if( byte_diff( data, 5, "stats") ) HTTPERROR_404;
584 reply_size = http_handle_stats( client_socket, c, recv_header, recv_length ); 526 reply_size = http_handle_stats( client_socket, c, recv_header, recv_length );
diff --git a/ot_iovec.h b/ot_iovec.h
index d5cf158..83a1a36 100644
--- a/ot_iovec.h
+++ b/ot_iovec.h
@@ -6,6 +6,8 @@
6#ifndef __OT_IOVEC_H__ 6#ifndef __OT_IOVEC_H__
7#define __OT_IOVEC_H__ 7#define __OT_IOVEC_H__
8 8
9#include <sys/uio.h>
10
9void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ); 11void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc );
10void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ); 12void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr );
11void iovec_free( int *iovec_entries, struct iovec **iovector ); 13void iovec_free( int *iovec_entries, struct iovec **iovector );
diff --git a/ot_livesync.c b/ot_livesync.c
index 3e27c9a..f6e4e51 100644
--- a/ot_livesync.c
+++ b/ot_livesync.c
@@ -50,7 +50,7 @@ void livesync_init( ) {
50 livesync_outbuffer_pos = livesync_outbuffer_start; 50 livesync_outbuffer_pos = livesync_outbuffer_start;
51 memmove( livesync_outbuffer_pos, &g_tracker_id, sizeof( g_tracker_id ) ); 51 memmove( livesync_outbuffer_pos, &g_tracker_id, sizeof( g_tracker_id ) );
52 livesync_outbuffer_pos += sizeof( g_tracker_id ); 52 livesync_outbuffer_pos += sizeof( g_tracker_id );
53 livesync_lastpacket_time = g_now; 53 livesync_lastpacket_time = g_now_seconds;
54 54
55 pthread_create( &thread_id, NULL, livesync_worker, NULL ); 55 pthread_create( &thread_id, NULL, livesync_worker, NULL );
56} 56}
@@ -88,14 +88,13 @@ static void livesync_issuepacket( ) {
88 socket_send4(g_livesync_socket_out, (char*)livesync_outbuffer_start, livesync_outbuffer_pos - livesync_outbuffer_start, 88 socket_send4(g_livesync_socket_out, (char*)livesync_outbuffer_start, livesync_outbuffer_pos - livesync_outbuffer_start,
89 groupip_1, LIVESYNC_PORT); 89 groupip_1, LIVESYNC_PORT);
90 livesync_outbuffer_pos = livesync_outbuffer_start + sizeof( g_tracker_id ); 90 livesync_outbuffer_pos = livesync_outbuffer_start + sizeof( g_tracker_id );
91 livesync_lastpacket_time = g_now; 91 livesync_lastpacket_time = g_now_seconds;
92} 92}
93 93
94/* Inform live sync about whats going on. */ 94/* Inform live sync about whats going on. */
95void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const uint8_t peerflag ) { 95void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer ) {
96 memmove( livesync_outbuffer_pos , info_hash, sizeof(ot_hash)); 96 memmove( livesync_outbuffer_pos , info_hash, sizeof(ot_hash));
97 memmove( livesync_outbuffer_pos + sizeof(ot_hash), peer, sizeof(ot_peer)); 97 memmove( livesync_outbuffer_pos + sizeof(ot_hash), peer, sizeof(ot_peer));
98 OT_FLAG( livesync_outbuffer_pos + sizeof(ot_hash) ) |= peerflag;
99 98
100 livesync_outbuffer_pos += sizeof(ot_hash) + sizeof(ot_peer); 99 livesync_outbuffer_pos += sizeof(ot_hash) + sizeof(ot_peer);
101 if( livesync_outbuffer_pos >= livesync_outbuffer_highwater ) 100 if( livesync_outbuffer_pos >= livesync_outbuffer_highwater )
@@ -106,7 +105,7 @@ void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const
106 stuck when there's not enough traffic to fill udp packets fast 105 stuck when there's not enough traffic to fill udp packets fast
107 enough */ 106 enough */
108void livesync_ticker( ) { 107void livesync_ticker( ) {
109 if( ( g_now - livesync_lastpacket_time > LIVESYNC_MAXDELAY) && 108 if( ( g_now_seconds - livesync_lastpacket_time > LIVESYNC_MAXDELAY) &&
110 ( livesync_outbuffer_pos > livesync_outbuffer_start + sizeof( g_tracker_id ) ) ) 109 ( livesync_outbuffer_pos > livesync_outbuffer_start + sizeof( g_tracker_id ) ) )
111 livesync_issuepacket(); 110 livesync_issuepacket();
112} 111}
@@ -126,22 +125,22 @@ static void * livesync_worker( void * args ) {
126 continue; 125 continue;
127 126
128 if( datalen < (ssize_t)(sizeof( g_tracker_id ) + sizeof( ot_hash ) + sizeof( ot_peer ) ) ) { 127 if( datalen < (ssize_t)(sizeof( g_tracker_id ) + sizeof( ot_hash ) + sizeof( ot_peer ) ) ) {
129 // TODO: log invalid sync packet 128 /* TODO: log invalid sync packet */
130 continue; 129 continue;
131 } 130 }
132 131
133 if( !accesslist_isblessed((char*)in_ip, OT_PERMISSION_MAY_LIVESYNC)) { 132 if( !accesslist_isblessed((char*)in_ip, OT_PERMISSION_MAY_LIVESYNC)) {
134 // TODO: log invalid sync packet 133 /* TODO: log invalid sync packet */
135 continue; 134 continue;
136 } 135 }
137 136
138 if( !memcmp( livesync_inbuffer, &g_tracker_id, sizeof( g_tracker_id ) ) ) { 137 if( !memcmp( livesync_inbuffer, &g_tracker_id, sizeof( g_tracker_id ) ) ) {
139 // TODO: log packet coming from ourselves 138 /* TODO: log packet coming from ourselves */
140 continue; 139 continue;
141 } 140 }
142 141
143 // Now basic sanity checks have been done on the live sync packet 142 /* Now basic sanity checks have been done on the live sync packet
144 // We might add more testing and logging. 143 We might add more testing and logging. */
145 while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= datalen ) { 144 while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= datalen ) {
146 ot_peer *peer = (ot_peer*)(livesync_inbuffer + off + sizeof(ot_hash)); 145 ot_peer *peer = (ot_peer*)(livesync_inbuffer + off + sizeof(ot_hash));
147 ot_hash *hash = (ot_hash*)(livesync_inbuffer + off); 146 ot_hash *hash = (ot_hash*)(livesync_inbuffer + off);
diff --git a/ot_livesync.h b/ot_livesync.h
index 8c3c96d..c534f59 100644
--- a/ot_livesync.h
+++ b/ot_livesync.h
@@ -35,7 +35,6 @@
35 ]+ 35 ]+
36 ]* 36 ]*
37 37
38
39 */ 38 */
40 39
41#ifdef WANT_SYNC_LIVE 40#ifdef WANT_SYNC_LIVE
@@ -49,7 +48,7 @@ void livesync_deinit();
49void livesync_bind_mcast( char *ip, uint16_t port ); 48void livesync_bind_mcast( char *ip, uint16_t port );
50 49
51/* Inform live sync about whats going on. */ 50/* Inform live sync about whats going on. */
52void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const uint8_t peerflag ); 51void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer );
53 52
54/* Tickle the live sync module from time to time, so no events get 53/* Tickle the live sync module from time to time, so no events get
55 stuck when there's not enough traffic to fill udp packets fast 54 stuck when there's not enough traffic to fill udp packets fast
@@ -63,7 +62,6 @@ void handle_livesync( const int64 serversocket );
63 62
64/* If no syncing is required, save calling code from #ifdef 63/* If no syncing is required, save calling code from #ifdef
65 constructions */ 64 constructions */
66
67#define livesync_init() 65#define livesync_init()
68#define livesync_ticker() 66#define livesync_ticker()
69#define handle_livesync(a) 67#define handle_livesync(a)
diff --git a/ot_mutex.c b/ot_mutex.c
index a7b583b..b6da4be 100644
--- a/ot_mutex.c
+++ b/ot_mutex.c
@@ -174,7 +174,7 @@ void mutex_workqueue_canceltask( int64 socket ) {
174 174
175 /* Free task's iovec */ 175 /* Free task's iovec */
176 for( i=0; i<(*task)->iovec_entries; ++i ) 176 for( i=0; i<(*task)->iovec_entries; ++i )
177 munmap( iovec[i].iov_base , iovec[i].iov_len ); 177 munmap( iovec[i].iov_base, iovec[i].iov_len );
178 178
179 *task = (*task)->next; 179 *task = (*task)->next;
180 free( ptask ); 180 free( ptask );
diff --git a/ot_mutex.h b/ot_mutex.h
index e16a097..ae295be 100644
--- a/ot_mutex.h
+++ b/ot_mutex.h
@@ -6,6 +6,8 @@
6#ifndef __OT_MUTEX_H__ 6#ifndef __OT_MUTEX_H__
7#define __OT_MUTEX_H__ 7#define __OT_MUTEX_H__
8 8
9#include <sys/uio.h>
10
9void mutex_init( ); 11void mutex_init( );
10void mutex_deinit( ); 12void mutex_deinit( );
11 13
@@ -27,27 +29,20 @@ typedef enum {
27 TASK_STATS_TORADDREM = 0x0009, 29 TASK_STATS_TORADDREM = 0x0009,
28 TASK_STATS_VERSION = 0x000a, 30 TASK_STATS_VERSION = 0x000a,
29 TASK_STATS_BUSY_NETWORKS = 0x000b, 31 TASK_STATS_BUSY_NETWORKS = 0x000b,
30 TASK_STATS_VECTOR_DEBUG = 0x000c, 32 TASK_STATS_RENEW = 0x000c,
31 TASK_STATS_RENEW = 0x000d,
32 33
33 TASK_STATS = 0x0100, /* Mask */ 34 TASK_STATS = 0x0100, /* Mask */
34 TASK_STATS_TORRENTS = 0x0101, 35 TASK_STATS_TORRENTS = 0x0101,
35 TASK_STATS_PEERS = 0x0102, 36 TASK_STATS_PEERS = 0x0102,
36 TASK_STATS_SLASH24S = 0x0103, 37 TASK_STATS_SLASH24S = 0x0103,
37 TASK_STATS_TOP10 = 0x0104, 38 TASK_STATS_TOP10 = 0x0104,
38 TASK_STATS_MEMORY = 0x0105,
39 39
40 TASK_FULLSCRAPE = 0x0200, /* Default mode */ 40 TASK_FULLSCRAPE = 0x0200, /* Default mode */
41 TASK_FULLSCRAPE_TPB_BINARY = 0x0201, 41 TASK_FULLSCRAPE_TPB_BINARY = 0x0201,
42 TASK_FULLSCRAPE_TPB_ASCII = 0x0202, 42 TASK_FULLSCRAPE_TPB_ASCII = 0x0202,
43 TASK_FULLSCRAPE_TPB_URLENCODED = 0x0203, 43 TASK_FULLSCRAPE_TPB_URLENCODED = 0x0203,
44 44
45 TASK_CLEAN = 0x0300, 45 TASK_DMEM = 0x0300,
46
47 TASK_SYNC_OUT = 0x0400,
48 TASK_SYNC_IN = 0x0401,
49
50 TASK_DMEM = 0x0500,
51 46
52 TASK_DONE = 0x0f00, 47 TASK_DONE = 0x0f00,
53 48
diff --git a/ot_stats.c b/ot_stats.c
index 0751bf8..2428adf 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -46,7 +46,7 @@ static unsigned long long ot_full_scrape_count = 0;
46static unsigned long long ot_full_scrape_request_count = 0; 46static unsigned long long ot_full_scrape_request_count = 0;
47static unsigned long long ot_full_scrape_size = 0; 47static unsigned long long ot_full_scrape_size = 0;
48static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT]; 48static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT];
49static unsigned long long ot_renewed[OT_POOLS_COUNT]; 49static unsigned long long ot_renewed[OT_PEER_TIMEOUT];
50 50
51static time_t ot_start_time; 51static time_t ot_start_time;
52 52
@@ -214,7 +214,7 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
214 214
215 uint32_t *counts[ NUM_BUFS ]; 215 uint32_t *counts[ NUM_BUFS ];
216 uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */ 216 uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */
217 int bucket; 217// int bucket;
218 size_t i, j, k, l; 218 size_t i, j, k, l;
219 char *r = reply; 219 char *r = reply;
220 220
@@ -223,6 +223,8 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
223 223
224 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); 224 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh );
225 225
226#if 0
227 /* XXX: TOOD: Doesn't work yet with new peer storage model */
226 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 228 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
227 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 229 ot_vector *torrents_list = mutex_bucket_lock( bucket );
228 for( j=0; j<torrents_list->size; ++j ) { 230 for( j=0; j<torrents_list->size; ++j ) {
@@ -248,6 +250,7 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
248 } 250 }
249 mutex_bucket_unlock( bucket ); 251 mutex_bucket_unlock( bucket );
250 } 252 }
253#endif
251 254
252 k = l = 0; /* Debug: count allocated bufs */ 255 k = l = 0; /* Debug: count allocated bufs */
253 for( i=0; i < NUM_BUFS; ++i ) { 256 for( i=0; i < NUM_BUFS; ++i ) {
@@ -283,8 +286,6 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
283 286
284 return r - reply; 287 return r - reply;
285 288
286bailout_cleanup:
287
288 for( i=0; i < NUM_BUFS; ++i ) 289 for( i=0; i < NUM_BUFS; ++i )
289 free( counts[i] ); 290 free( counts[i] );
290 291
@@ -299,44 +300,6 @@ bailout_cleanup:
299 } 300 }
300 */ 301 */
301 302
302static ssize_t stats_vector_usage( char * reply ) {
303 size_t i, j, *vec_member;
304 char *r = reply;
305 int exactmatch, bucket;
306
307 ot_vector bucketsizes;
308 memset( &bucketsizes, 0, sizeof( bucketsizes ));
309
310 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
311 ot_vector *torrents_list = mutex_bucket_lock( bucket );
312 for( i=0; i<torrents_list->size; ++i ) {
313 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list;
314 for( j=0; j<OT_POOLS_COUNT; ++j ) {
315 if( ! ( vec_member = vector_find_or_insert(&bucketsizes, &peer_list->peers[j].size, 3 * sizeof( size_t ), 2 * sizeof(size_t), &exactmatch) ) ) {
316 mutex_bucket_unlock( bucket );
317 return 0;
318 }
319 if( !exactmatch ) {
320 vec_member[0] = peer_list->peers[j].size;
321 vec_member[1] = peer_list->peers[j].space;
322 vec_member[2] = 1;
323 } else
324 ++vec_member[2];
325 }
326 }
327 mutex_bucket_unlock( bucket );
328 }
329
330 for( i = 0; i<bucketsizes.size; ++i ) {
331 r += sprintf( r, "%zd\t%zd\t%zd\n", ((size_t*)bucketsizes.data)[3*i], ((size_t*)bucketsizes.data)[3*i+1], ((size_t*)bucketsizes.data)[3*i+2] );
332 /* Prevent overflow. 8k should be enough for debugging */
333 if( r - reply > OT_STATS_TMPSIZE - 3*10+3 /* 3*%zd + 2*\t + \n */ )
334 break;
335 }
336
337 return r - reply;
338}
339
340static unsigned long events_per_time( unsigned long long events, time_t t ) { 303static unsigned long events_per_time( unsigned long long events, time_t t ) {
341 return events / ( (unsigned int)t ? (unsigned int)t : 1 ); 304 return events / ( (unsigned int)t ? (unsigned int)t : 1 );
342} 305}
@@ -497,20 +460,20 @@ static size_t stats_return_renew_bucket( char * reply ) {
497 char *r = reply; 460 char *r = reply;
498 int i; 461 int i;
499 462
500 for( i=0; i<OT_POOLS_COUNT; ++i ) 463 for( i=0; i<OT_PEER_TIMEOUT; ++i )
501 r+=sprintf(r,"%02i %llu\n", i, ot_renewed[i] ); 464 r+=sprintf(r,"%02i %llu\n", i, ot_renewed[i] );
502 return r - reply; 465 return r - reply;
503} 466}
504 467
505extern const char 468extern const char
506*g_version_opentracker_c, *g_version_accesslist_c, *g_version_clean_c, *g_version_fullscrape_c, *g_version_http_c, 469*g_version_opentracker_c, *g_version_accesslist_c, *g_version_clean_c, *g_version_fullscrape_c, *g_version_http_c,
507*g_version_iovec_c, *g_version_mutex_c, *g_version_stats_c, *g_version_sync_c, *g_version_udp_c, *g_version_vector_c, 470*g_version_iovec_c, *g_version_mutex_c, *g_version_stats_c, *g_version_udp_c, *g_version_vector_c,
508*g_version_scan_urlencoded_query_c, *g_version_trackerlogic_c, *g_version_livesync_c; 471*g_version_scan_urlencoded_query_c, *g_version_trackerlogic_c, *g_version_livesync_c;
509 472
510size_t stats_return_tracker_version( char *reply ) { 473size_t stats_return_tracker_version( char *reply ) {
511 return sprintf( reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 474 return sprintf( reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
512 g_version_opentracker_c, g_version_accesslist_c, g_version_clean_c, g_version_fullscrape_c, g_version_http_c, 475 g_version_opentracker_c, g_version_accesslist_c, g_version_clean_c, g_version_fullscrape_c, g_version_http_c,
513 g_version_iovec_c, g_version_mutex_c, g_version_stats_c, g_version_sync_c, g_version_udp_c, g_version_vector_c, 476 g_version_iovec_c, g_version_mutex_c, g_version_stats_c, g_version_udp_c, g_version_vector_c,
514 g_version_scan_urlencoded_query_c, g_version_trackerlogic_c, g_version_livesync_c ); 477 g_version_scan_urlencoded_query_c, g_version_trackerlogic_c, g_version_livesync_c );
515} 478}
516 479
@@ -541,10 +504,6 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
541 case TASK_STATS_BUSY_NETWORKS: 504 case TASK_STATS_BUSY_NETWORKS:
542 return stats_return_busy_networks( reply ); 505 return stats_return_busy_networks( reply );
543#endif 506#endif
544#ifdef _DEBUG_VECTOR
545 case TASK_STATS_VECTOR_DEBUG:
546 return vector_info( reply );
547#endif
548 default: 507 default:
549 return 0; 508 return 0;
550 } 509 }
@@ -563,7 +522,6 @@ static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype
563 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break; 522 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break;
564 case TASK_STATS_SLASH24S: r += stats_slash24s_txt( r, 25, 16 ); break; 523 case TASK_STATS_SLASH24S: r += stats_slash24s_txt( r, 25, 16 ); break;
565 case TASK_STATS_TOP10: r += stats_top10_txt( r ); break; 524 case TASK_STATS_TOP10: r += stats_top10_txt( r ); break;
566 case TASK_STATS_MEMORY: r += stats_vector_usage( r ); break;
567 default: 525 default:
568 iovec_free(iovec_entries, iovector); 526 iovec_free(iovec_entries, iovector);
569 return; 527 return;
@@ -594,14 +552,14 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_
594 case EVENT_FULLSCRAPE_REQUEST: 552 case EVENT_FULLSCRAPE_REQUEST:
595 { 553 {
596 uint8_t ip[4]; *(uint32_t*)ip = (uint32_t)proto; /* ugly hack to transfer ip to stats */ 554 uint8_t ip[4]; *(uint32_t*)ip = (uint32_t)proto; /* ugly hack to transfer ip to stats */
597 LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE\n", (unsigned int)(g_now - ot_start_time), ip[0], ip[1], ip[2], ip[3] ); 555 LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE\n", (unsigned int)(g_now_seconds - ot_start_time)/60, ip[0], ip[1], ip[2], ip[3] );
598 ot_full_scrape_request_count++; 556 ot_full_scrape_request_count++;
599 } 557 }
600 break; 558 break;
601 case EVENT_FULLSCRAPE_REQUEST_GZIP: 559 case EVENT_FULLSCRAPE_REQUEST_GZIP:
602 { 560 {
603 uint8_t ip[4]; *(uint32_t*)ip = (uint32_t)proto; /* ugly hack to transfer ip to stats */ 561 uint8_t ip[4]; *(uint32_t*)ip = (uint32_t)proto; /* ugly hack to transfer ip to stats */
604 LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE GZIP\n", (unsigned int)(g_now - ot_start_time), ip[0], ip[1], ip[2], ip[3] ); 562 LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE GZIP\n", (unsigned int)(g_now_seconds - ot_start_time)/60, ip[0], ip[1], ip[2], ip[3] );
605 ot_full_scrape_request_count++; 563 ot_full_scrape_request_count++;
606 } 564 }
607 break; 565 break;
@@ -611,11 +569,6 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_
611 case EVENT_RENEW: 569 case EVENT_RENEW:
612 ot_renewed[event_data]++; 570 ot_renewed[event_data]++;
613 break; 571 break;
614 case EVENT_SYNC_IN_REQUEST:
615 case EVENT_SYNC_IN:
616 case EVENT_SYNC_OUT_REQUEST:
617 case EVENT_SYNC_OUT:
618 break;
619 default: 572 default:
620 break; 573 break;
621 } 574 }
@@ -643,7 +596,7 @@ void stats_deliver( int64 socket, int tasktype ) {
643 596
644static pthread_t thread_id; 597static pthread_t thread_id;
645void stats_init( ) { 598void stats_init( ) {
646 ot_start_time = g_now; 599 ot_start_time = g_now_seconds;
647 pthread_create( &thread_id, NULL, stats_worker, NULL ); 600 pthread_create( &thread_id, NULL, stats_worker, NULL );
648} 601}
649 602
diff --git a/ot_stats.h b/ot_stats.h
index 76fdcb5..f930a3f 100644
--- a/ot_stats.h
+++ b/ot_stats.h
@@ -16,10 +16,6 @@ typedef enum {
16 EVENT_FULLSCRAPE_REQUEST, 16 EVENT_FULLSCRAPE_REQUEST,
17 EVENT_FULLSCRAPE_REQUEST_GZIP, 17 EVENT_FULLSCRAPE_REQUEST_GZIP,
18 EVENT_FULLSCRAPE, /* TCP only */ 18 EVENT_FULLSCRAPE, /* TCP only */
19 EVENT_SYNC_IN_REQUEST,
20 EVENT_SYNC_IN,
21 EVENT_SYNC_OUT_REQUEST,
22 EVENT_SYNC_OUT,
23 EVENT_FAILED 19 EVENT_FAILED
24} ot_status_event; 20} ot_status_event;
25 21
diff --git a/ot_udp.c b/ot_udp.c
index db8dfbd..764281c 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -115,7 +115,7 @@ void handle_udp4( int64 serversocket ) {
115 if( !torrent ) 115 if( !torrent )
116 return; /* XXX maybe send error */ 116 return; /* XXX maybe send error */
117 117
118 r = 8 + return_peers_for_torrent( hash, numwant, static_outbuf + 8, FLAG_UDP ); 118 r = 8 + return_peers_for_torrent( torrent, numwant, static_outbuf + 8, FLAG_UDP );
119 } 119 }
120 120
121 socket_send4( serversocket, static_outbuf, r, remoteip, remoteport ); 121 socket_send4( serversocket, static_outbuf, r, remoteip, remoteport );
diff --git a/ot_vector.c b/ot_vector.c
index 2dcbb08..2862763 100644
--- a/ot_vector.c
+++ b/ot_vector.c
@@ -6,69 +6,65 @@
6/* System */ 6/* System */
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#include <stdint.h>
10#include <stdio.h>
9 11
10/* Opentracker */ 12/* Opentracker */
11#include "trackerlogic.h" 13#include "trackerlogic.h"
12#include "ot_vector.h" 14#include "ot_vector.h"
13 15
14#ifdef _DEBUG_VECTOR 16/* Libowfat */
15#include <stdio.h> 17#include "uint32.h"
16
17static uint64_t vector_debug_inc[32];
18static uint64_t vector_debug_noinc[32];
19static uint64_t vector_debug_dec[32];
20static uint64_t vector_debug_nodec[32];
21static void vector_debug( size_t old_size, ssize_t diff_size, size_t old_space, ssize_t diff_space ) {
22 int x = 0;
23 while( old_space ) { old_space>>=1; ++x; }
24 old_size = old_size;
25
26 if( diff_size == -1 )
27 if( diff_space ) vector_debug_dec[x]++; else vector_debug_nodec[x]++;
28 else
29 if( diff_space ) vector_debug_inc[x]++; else vector_debug_noinc[x]++;
30
31}
32 18
33size_t vector_info( char * reply ) { 19static int vector_compare_peer(const void *peer1, const void *peer2 ) {
34 char * r = reply; 20 int32_t cmp = (int32_t)uint32_read(peer1) - (int32_t)uint32_read(peer2);
35 int i; 21 if (cmp == 0) cmp = ((int8_t*)peer1)[4] - ((int8_t*)peer2)[4];
36 for( i=1; i<28; ++i ) 22 if (cmp == 0) cmp = ((int8_t*)peer1)[5] - ((int8_t*)peer2)[5];
37 r += sprintf( r, " inc % 12d -> % 12d: % 16lld\n", 1<<(i-1), 8<<(i-1), vector_debug_inc[i] ); 23 return cmp;
38 for( i=1; i<28; ++i )
39 r += sprintf( r, "noinc % 12d -> % 12d: % 16lld\n", 1<<(i-1), 1<<(i-1), vector_debug_noinc[i] );
40 for( i=1; i<28; ++i )
41 r += sprintf( r, " dec % 12d -> % 12d: % 16lld\n", 1<<(i-1), 4<<(i-1), vector_debug_dec[i] );
42 for( i=1; i<28; ++i )
43 r += sprintf( r, "nodec % 12d -> % 12d: % 16lld\n", 1<<(i-1), 1<<(i-1), vector_debug_nodec[i] );
44 return r - reply;
45} 24}
46#endif
47 25
48/* This function gives us a binary search that returns a pointer, even if 26/* This function gives us a binary search that returns a pointer, even if
49 no exact match is found. In that case it sets exactmatch 0 and gives 27 no exact match is found. In that case it sets exactmatch 0 and gives
50 calling functions the chance to insert data 28 calling functions the chance to insert data
29
30 NOTE: Minimal compare_size is 4.
51*/ 31*/
52void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, 32void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
53 size_t compare_size, int *exactmatch ) { 33 size_t compare_size, int *exactmatch ) {
54 size_t mc = member_count; 34 size_t offs, mc = member_count;
55 uint8_t *lookat = ((uint8_t*)base) + member_size * (member_count >> 1); 35 int8_t *lookat = ((int8_t*)base) + member_size * (mc >> 1);
36 int32_t key_cache = (int32_t)uint32_read(key);
56 *exactmatch = 1; 37 *exactmatch = 1;
57 38
58 while( mc ) { 39 while( mc ) {
59 int cmp = memcmp( lookat, key, compare_size); 40 int32_t cmp = key_cache - (int32_t)uint32_read(lookat);
60 if (cmp == 0) return (void *)lookat; 41 if (cmp == 0) {
42 for( offs = 4; cmp == 0 && offs < compare_size; ++offs )
43 cmp = ((int8_t*)key)[offs] - lookat[offs];
44 if( cmp == 0 )
45 return (void *)lookat;
46 }
47
61 if (cmp < 0) { 48 if (cmp < 0) {
62 base = (void*)(lookat + member_size); 49 base = (void*)(lookat + member_size);
63 --mc; 50 --mc;
64 } 51 }
52
65 mc >>= 1; 53 mc >>= 1;
66 lookat = ((uint8_t*)base) + member_size * (mc >> 1); 54 lookat = ((int8_t*)base) + member_size * (mc >> 1);
67 } 55 }
56
68 *exactmatch = 0; 57 *exactmatch = 0;
69 return (void*)lookat; 58 return (void*)lookat;
70} 59}
71 60
61static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) {
62 unsigned int hash = 5381, i = 6;
63 uint8_t *p = (uint8_t*)peer;
64 while( i-- ) hash += (hash<<5) + *(p++);
65 return hash % bucket_count;
66}
67
72/* This is the generic insert operation for our vector type. 68/* This is the generic insert operation for our vector type.
73 It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with 69 It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with
74 those of objects in vector. Our special "binary_search" function does that and either returns the match or a 70 those of objects in vector. Our special "binary_search" function does that and either returns the match or a
@@ -78,17 +74,13 @@ void *binary_search( const void * const key, const void * base, const size_t mem
78*/ 74*/
79void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { 75void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) {
80 uint8_t *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); 76 uint8_t *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch );
81#ifdef _DEBUG_VECTOR
82 size_t old_space = vector->space;
83#endif
84 77
85 if( *exactmatch ) return match; 78 if( *exactmatch ) return match;
86 79
87 if( vector->size + 1 >= vector->space ) { 80 if( vector->size + 1 > vector->space ) {
88 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 81 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
89 uint8_t *new_data = realloc( vector->data, new_space * member_size ); 82 uint8_t *new_data = realloc( vector->data, new_space * member_size );
90 if( !new_data ) return NULL; 83 if( !new_data ) return NULL;
91
92 /* Adjust pointer if it moved by realloc */ 84 /* Adjust pointer if it moved by realloc */
93 match = new_data + (match - (uint8_t*)vector->data); 85 match = new_data + (match - (uint8_t*)vector->data);
94 86
@@ -97,56 +89,48 @@ void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, s
97 } 89 }
98 memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match ); 90 memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match );
99 91
100#ifdef _DEBUG_VECTOR
101 vector_debug( vector->size, 1, old_space, vector->space - old_space );
102#endif
103 vector->size++; 92 vector->size++;
104 return match; 93 return match;
105} 94}
106 95
96/* This function checks, whether our peer vector is a real vector
97 or a list of buckets and dispatches accordingly */
98ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) {
99 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
100 if( vector->space < vector->size )
101 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size );
102 return vector_find_or_insert( vector, peer, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, exactmatch );
103}
104
107/* This is the non-generic delete from vector-operation specialized for peers in pools. 105/* This is the non-generic delete from vector-operation specialized for peers in pools.
108 Set hysteresis == 0 if you expect the vector not to ever grow again.
109 It returns 0 if no peer was found (and thus not removed) 106 It returns 0 if no peer was found (and thus not removed)
110 1 if a non-seeding peer was removed 107 1 if a non-seeding peer was removed
111 2 if a seeding peer was removed 108 2 if a seeding peer was removed
112*/ 109*/
113int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) { 110int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
114 int exactmatch; 111 int exactmatch;
115 size_t shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO; 112 ot_peer *match, *end;
116 ot_peer *end = ((ot_peer*)vector->data) + vector->size;
117 ot_peer *match;
118#ifdef _DEBUG_VECTOR
119 size_t old_space = vector->space;
120#endif
121 113
122 if( !vector->size ) return 0; 114 if( !vector->size ) return 0;
123 match = binary_search( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch ); 115
116 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
117 if( vector->space < vector->size )
118 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size );
124 119
120 end = ((ot_peer*)vector->data) + vector->size;
121 match = binary_search( peer, vector->data, vector->size, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
125 if( !exactmatch ) return 0; 122 if( !exactmatch ) return 0;
123
126 exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; 124 exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
127 memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); 125 memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
128 if( ( --vector->size * shrink_thresh < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) { 126
129 vector->space /= OT_VECTOR_SHRINK_RATIO; 127 vector->size--;
130 vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); 128 vector_fixup_peers( vector );
131 }
132 if( !vector->size ) {
133 /* for peer pools its safe to let them go,
134 in 999 of 1000 this happens in older pools, that won't ever grow again */
135 free( vector->data );
136 vector->data = NULL;
137 vector->space = 0;
138 }
139#ifdef _DEBUG_VECTOR
140 vector_debug( vector->size+1, -1, old_space, vector->space - old_space );
141#endif
142 return exactmatch; 129 return exactmatch;
143} 130}
144 131
145void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { 132void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
146 ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; 133 ot_torrent *end = ((ot_torrent*)vector->data) + vector->size;
147#ifdef _DEBUG_VECTOR
148 size_t old_space = vector->space;
149#endif
150 134
151 if( !vector->size ) return; 135 if( !vector->size ) return;
152 136
@@ -159,9 +143,118 @@ void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
159 vector->space /= OT_VECTOR_SHRINK_RATIO; 143 vector->space /= OT_VECTOR_SHRINK_RATIO;
160 vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); 144 vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
161 } 145 }
162#ifdef _DEBUG_VECTOR 146}
163 vector_debug( vector->size+1, -1, old_space, vector->space - old_space ); 147
164#endif 148void vector_clean_list( ot_vector * vector, int num_buckets ) {
149 while( num_buckets-- )
150 free( vector[num_buckets].data );
151 free( vector );
152 return;
153}
154
155void vector_redistribute_buckets( ot_peerlist * peer_list ) {
156 int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
157 ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers;
158
159 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
160 num_buckets_old = peer_list->peers.size;
161 bucket_list_old = peer_list->peers.data;
162 }
163
164 if( peer_list->peer_count < 255 )
165 num_buckets_new = 1;
166 else if( peer_list->peer_count > 8192 )
167 num_buckets_new = 64;
168 else if( peer_list->peer_count >= 512 && peer_list->peer_count < 4096 )
169 num_buckets_new = 16;
170 else if( peer_list->peer_count < 512 && num_buckets_old <= 16 )
171 num_buckets_new = num_buckets_old;
172 else if( peer_list->peer_count < 512 )
173 num_buckets_new = 1;
174 else if( peer_list->peer_count < 8192 && num_buckets_old > 1 )
175 num_buckets_new = num_buckets_old;
176 else
177 num_buckets_new = 16;
178
179 if( num_buckets_new == num_buckets_old )
180 return;
181
182 /* Assume near perfect distribution */
183 bucket_list_new = malloc( num_buckets_new * sizeof( ot_vector ) );
184 if( !bucket_list_new) return;
185 bzero( bucket_list_new, num_buckets_new * sizeof( ot_vector ) );
186
187 tmp = peer_list->peer_count / num_buckets_new;
188 bucket_size_new = OT_VECTOR_MIN_MEMBERS;
189 while( bucket_size_new < tmp)
190 bucket_size_new *= OT_VECTOR_GROW_RATIO;
191
192 /* preallocate vectors to hold all peers */
193 for( bucket=0; bucket<num_buckets_new; ++bucket ) {
194 bucket_list_new[bucket].space = bucket_size_new;
195 bucket_list_new[bucket].data = malloc( bucket_size_new * sizeof(ot_peer) );
196 if( !bucket_list_new[bucket].data )
197 return vector_clean_list( bucket_list_new, num_buckets_new );
198 }
199
200 /* Now sort them into the correct bucket */
201 for( bucket=0; bucket<num_buckets_old; ++bucket ) {
202 ot_peer * peers_old = bucket_list_old[bucket].data, * peers_new;
203 int peer_count_old = bucket_list_old[bucket].size;
204 while( peer_count_old-- ) {
205 ot_vector * bucket_dest = bucket_list_new;
206 if( num_buckets_new > 1 )
207 bucket_dest += vector_hash_peer(peers_old, num_buckets_new);
208 if( bucket_dest->size + 1 > bucket_dest->space ) {
209 void * tmp = realloc( bucket_dest->data, sizeof(ot_peer) * OT_VECTOR_GROW_RATIO * bucket_dest->space );
210 if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new );
211 bucket_dest->data = tmp;
212 bucket_dest->space *= OT_VECTOR_GROW_RATIO;
213 }
214 peers_new = (ot_peer*)bucket_dest->data;
215 *(uint64_t*)(peers_new + bucket_dest->size++) = *(uint64_t*)(peers_old++);
216 }
217 }
218
219 /* Now sort each bucket to later allow bsearch */
220 for( bucket=0; bucket<num_buckets_new; ++bucket )
221 qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, sizeof( ot_peer ), vector_compare_peer );
222
223 /* Everything worked fine. Now link new bucket_list to peer_list */
224 if( OT_PEERLIST_HASBUCKETS( peer_list) )
225 vector_clean_list( (ot_vector*)peer_list->peers.data, peer_list->peers.size );
226 else
227 free( peer_list->peers.data );
228
229 if( num_buckets_new > 1 ) {
230 peer_list->peers.data = bucket_list_new;
231 peer_list->peers.size = num_buckets_new;
232 peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */
233 } else {
234 peer_list->peers.data = bucket_list_new->data;
235 peer_list->peers.size = bucket_list_new->size;
236 peer_list->peers.space = bucket_list_new->space;
237 free( bucket_list_new );
238 }
239}
240
241void vector_fixup_peers( ot_vector * vector ) {
242 int need_fix = 0;
243
244 if( !vector->size ) {
245 free( vector->data );
246 vector->data = NULL;
247 vector->space = 0;
248 return;
249 }
250
251 while( ( vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) &&
252 ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
253 vector->space /= OT_VECTOR_SHRINK_RATIO;
254 need_fix++;
255 }
256 if( need_fix )
257 vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
165} 258}
166 259
167const char *g_version_vector_c = "$Source$: $Revision$\n"; 260const char *g_version_vector_c = "$Source$: $Revision$\n";
diff --git a/ot_vector.h b/ot_vector.h
index 1d42dd0..37135e7 100644
--- a/ot_vector.h
+++ b/ot_vector.h
@@ -12,21 +12,23 @@
12#define OT_VECTOR_SHRINK_THRESH 4 12#define OT_VECTOR_SHRINK_THRESH 4
13#define OT_VECTOR_SHRINK_RATIO 2 13#define OT_VECTOR_SHRINK_RATIO 2
14 14
15#define OT_PEER_BUCKET_MINCOUNT 512
16#define OT_PEER_BUCKET_MAXCOUNT 256
17
15typedef struct { 18typedef struct {
16 void *data; 19 void *data;
17 size_t size; 20 size_t size;
18 size_t space; 21 size_t space;
19} ot_vector; 22} ot_vector;
20 23
21void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, 24void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
22 size_t compare_size, int *exactmatch ); 25 size_t compare_size, int *exactmatch );
23void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); 26void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch );
24 27ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch );
25int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis );
26void vector_remove_torrent( ot_vector *vector, ot_torrent *match );
27 28
28#ifdef _DEBUG_VECTOR 29int vector_remove_peer( ot_vector *vector, ot_peer *peer );
29size_t vector_info( char * reply ); 30void vector_remove_torrent( ot_vector *vector, ot_torrent *match );
30#endif 31void vector_redistribute_buckets( ot_peerlist * peer_list );
32void vector_fixup_peers( ot_vector * vector );
31 33
32#endif 34#endif
diff --git a/tests/testsuite.sh b/tests/testsuite.sh
index b07546d..dace2c6 100644
--- a/tests/testsuite.sh
+++ b/tests/testsuite.sh
@@ -1,15 +1,11 @@
1#!/bin/sh 1#!/bin/sh
2 2
3while true; do 3while true; do
4 request_string="GET /announce?info_hash=\ 4 request_string="GET /announce?info_hash=0123456789012345678\
5%$(printf %02X $(( $RANDOM & 0xff )) )\ 5%$(printf %02X $(( $RANDOM & 0xf )) )\
6%$(printf %02X $(( $RANDOM & 0xff )) )\ 6&ip=$(( $RANDOM & 0xf )).$(( $RANDOM & 0xf )).13.16&port=$(( $RANDOM & 0xff )) HTTP/1.0\n"
72345678901234567\
8%$(printf %02X $(( $RANDOM & 0xff )) )\
9%$(printf %02X $(( $RANDOM & 0xff )) )\
10&ip=$(( $RANDOM & 0xff )).17.13.15&port=$(( $RANDOM & 0xff )) HTTP/1.0\n"
11 7
12# echo $request_string 8echo $request_string
13# echo 9# echo
14 echo $request_string | nc 127.0.0.1 6969 >/dev/null 10 echo $request_string | nc 127.0.0.1 6969 >/dev/null
15# echo 11# echo
diff --git a/tests/testsuite2.sh b/tests/testsuite2.sh
index 5189187..c9a5a6a 100644
--- a/tests/testsuite2.sh
+++ b/tests/testsuite2.sh
@@ -8,7 +8,7 @@ while true; do
8 8
9 echo $request_string 9 echo $request_string
10 echo 10 echo
11 echo $request_string | nc 10.0.1.3 6969 >/dev/null 11 echo $request_string | nc 23.23.23.237 6969 >/dev/null
12 echo 12 echo
13 13
14done 14done
diff --git a/trackerlogic.c b/trackerlogic.c
index 0aca287..faca19b 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -7,17 +7,12 @@
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#include <stdio.h> 9#include <stdio.h>
10#include <sys/uio.h>
11#include <arpa/inet.h> 10#include <arpa/inet.h>
12#include <sys/types.h>
13#include <sys/mman.h>
14#include <unistd.h> 11#include <unistd.h>
15#include <time.h>
16#include <math.h>
17#include <errno.h> 12#include <errno.h>
13#include <stdint.h>
18 14
19/* Libowfat */ 15/* Libowfat */
20#include "scan.h"
21#include "byte.h" 16#include "byte.h"
22#include "io.h" 17#include "io.h"
23 18
@@ -28,26 +23,26 @@
28#include "ot_clean.h" 23#include "ot_clean.h"
29#include "ot_accesslist.h" 24#include "ot_accesslist.h"
30#include "ot_fullscrape.h" 25#include "ot_fullscrape.h"
31#include "ot_sync.h"
32#include "ot_livesync.h" 26#include "ot_livesync.h"
33 27
34void free_peerlist( ot_peerlist *peer_list ) { 28void free_peerlist( ot_peerlist *peer_list ) {
35 size_t i; 29 if( peer_list->peers.data ) {
36 for( i=0; i<OT_POOLS_COUNT; ++i ) 30 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
37 if( peer_list->peers[i].data ) 31 ot_vector *bucket_list = (ot_vector*)(peer_list->peers.data);
38 free( peer_list->peers[i].data ); 32
39#ifdef WANT_SYNC_BATCH 33 while( peer_list->peers.size-- )
40 free( peer_list->changeset.data ); 34 free( bucket_list++->data );
41#endif 35 }
36 free( peer_list->peers.data );
37 }
42 free( peer_list ); 38 free( peer_list );
43} 39}
44 40
45ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) ) { 41ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_sync ) ) {
46 int exactmatch; 42 int exactmatch;
47 ot_torrent *torrent; 43 ot_torrent *torrent;
48 ot_peer *peer_dest; 44 ot_peer *peer_dest;
49 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ), *peer_pool; 45 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
50 int base_pool = 0;
51 46
52 if( !accesslist_hashisvalid( hash ) ) { 47 if( !accesslist_hashisvalid( hash ) ) {
53 mutex_bucket_unlock_by_hash( hash ); 48 mutex_bucket_unlock_by_hash( hash );
@@ -75,106 +70,135 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM(
75 clean_single_torrent( torrent ); 70 clean_single_torrent( torrent );
76 71
77 /* Timestamp our first pool */ 72 /* Timestamp our first pool */
78 torrent->peer_list->base = NOW; 73 torrent->peer_list->base = g_now_minutes;
74
75 /* Check for peer in torrent */
76 peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), peer, &exactmatch );
77 if( !peer_dest ) {
78 mutex_bucket_unlock_by_hash( hash );
79 return NULL;
80 }
81
82 /* Tell peer that it's fresh */
83 OT_PEERTIME( peer ) = 0;
79 84
80 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ 85 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
81 if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) 86 if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
82 OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED; 87 OT_FLAG( peer ) ^= PEER_FLAG_COMPLETED;
83 88
84#ifdef WANT_SYNC 89 /* If we hadn't had a match create peer there */
85 if( from_changeset ) {
86 /* Check, whether peer already is in current pool, do nothing if so */
87 peer_pool = &torrent->peer_list->peers[0];
88 binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch );
89 if( exactmatch ) {
90 mutex_bucket_unlock_by_hash( hash );
91 return torrent;
92 }
93 base_pool = 1;
94 if( torrent->peer_list->base < NOW )
95 torrent->peer_list->base = NOW;
96 }
97#endif
98
99 peer_pool = &torrent->peer_list->peers[ base_pool ];
100 peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch );
101
102 /* If we hadn't had a match in current pool, create peer there and
103 remove it from all older pools */
104 if( !exactmatch ) { 90 if( !exactmatch ) {
105 int i;
106 memmove( peer_dest, peer, sizeof( ot_peer ) );
107 torrent->peer_list->peer_count++;
108 91
109#ifdef WANT_SYNC_LIVE 92#ifdef WANT_SYNC_LIVE
110 if( !from_changeset ) 93 if( !from_sync )
111 livesync_tell( hash, peer, PEER_FLAG_LEECHING ); 94 livesync_tell( hash, peer );
112#endif 95#endif
113 96
114 if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) 97 torrent->peer_list->peer_count++;
98 if( OT_FLAG(peer) & PEER_FLAG_COMPLETED )
115 torrent->peer_list->down_count++; 99 torrent->peer_list->down_count++;
116 100 if( OT_FLAG(peer) & PEER_FLAG_SEEDING )
117 if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) {
118 torrent->peer_list->seed_counts[ base_pool ]++;
119 torrent->peer_list->seed_count++; 101 torrent->peer_list->seed_count++;
120 }
121 102
122 for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) {
123 switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) {
124 case 0: continue;
125 case 2: torrent->peer_list->seed_counts[i]--;
126 torrent->peer_list->seed_count--;
127 case 1: default:
128 torrent->peer_list->peer_count--;
129 mutex_bucket_unlock_by_hash( hash );
130 stats_issue_event( EVENT_RENEW, 0, i );
131 return torrent;
132 }
133 }
134 } else { 103 } else {
135 if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) { 104 stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) );
136 torrent->peer_list->seed_counts[ base_pool ]--; 105
106 if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) )
137 torrent->peer_list->seed_count--; 107 torrent->peer_list->seed_count--;
138 } 108 if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) )
139 if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) {
140 torrent->peer_list->seed_counts[ base_pool ]++;
141 torrent->peer_list->seed_count++; 109 torrent->peer_list->seed_count++;
142 } 110 if( !(OT_FLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_FLAG(peer) & PEER_FLAG_COMPLETED ) )
143 if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) )
144 torrent->peer_list->down_count++; 111 torrent->peer_list->down_count++;
145 if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) 112 if( OT_FLAG(peer_dest) & PEER_FLAG_COMPLETED )
146 OT_FLAG( peer ) |= PEER_FLAG_COMPLETED; 113 OT_FLAG( peer ) |= PEER_FLAG_COMPLETED;
147
148 stats_issue_event( EVENT_RENEW, 0, base_pool );
149 memmove( peer_dest, peer, sizeof( ot_peer ) );
150 } 114 }
151 115
152 mutex_bucket_unlock_by_hash( hash ); 116 *(uint64_t*)(peer_dest) = *(uint64_t*)(peer);
117#ifdef WANT_SYNC
118 /* In order to avoid an unlock/lock between add_peers and return_peers,
119 we only unlock the bucket if return_peers won't do the job: either
120 if we return NULL or if no reply is expected, i.e. when called
121 from livesync code. */
122 if( from_sync )
123 mutex_bucket_unlock_by_hash( hash );
124#endif
153 return torrent; 125 return torrent;
154} 126}
155 127
128static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
129 unsigned int bucket, num_buckets = 1;
130 ot_vector * bucket_list = &peer_list->peers;
131 char * r = reply;
132
133 if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
134 num_buckets = bucket_list->size;
135 bucket_list = (ot_vector *)bucket_list->data;
136 }
137
138 for( bucket = 0; bucket<num_buckets; ++bucket ) {
139 ot_peer * peers = (ot_peer*)bucket_list[bucket].data;
140 size_t peer_count = bucket_list[bucket].size;
141 while( peer_count-- )
142 memmove( r+=6, peers++, 6 );
143 }
144
145 return r - reply;
146}
147
148static size_t return_peers_selection( ot_peerlist *peer_list, size_t amount, char *reply ) {
149 unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
150 ot_vector * bucket_list = &peer_list->peers;
151 unsigned int shifted_pc = peer_list->peer_count;
152 unsigned int shifted_step = 0;
153 unsigned int shift = 0;
154 char * r = reply;
155
156 if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
157 num_buckets = bucket_list->size;
158 bucket_list = (ot_vector *)bucket_list->data;
159 }
160
161 /* Make fixpoint arithmetic as exact as possible */
162#define MAXPRECBIT (1<<(8*sizeof(int)-3))
163 while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; }
164 shifted_step = shifted_pc/amount;
165#undef MAXPRECBIT
166
167 /* Initialize somewhere in the middle of peers so that
168 fixpoint's aliasing doesn't alway miss the same peers */
169 bucket_offset = random() % peer_list->peer_count;
170
171 while( amount-- ) {
172 /* This is the aliased, non shifted range, next value may fall into */
173 unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) -
174 ( ( amount * shifted_step ) >> shift );
175 bucket_offset += 1 + random() % diff;
176
177 while( bucket_offset >= bucket_list[bucket_index].size ) {
178 bucket_offset -= bucket_list[bucket_index].size;
179 bucket_index = ( bucket_index + 1 ) % num_buckets;
180 }
181
182 memmove( r, ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset, 6 );
183 r += 6;
184 }
185 return r - reply;
186}
187
156/* Compiles a list of random peers for a torrent 188/* Compiles a list of random peers for a torrent
157 * reply must have enough space to hold 92+6*amount bytes 189 * reply must have enough space to hold 92+6*amount bytes
158 * Selector function can be anything, maybe test for seeds, etc.
159 * RANDOM may return huge values
160 * does not yet check not to return self 190 * does not yet check not to return self
191 * the bucket, torrent resides in has been locked by the
192 add_peer call, the ot_torrent * was gathered from, so we
193 have to unlock it here.
161*/ 194*/
162size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto ) { 195size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) {
163 char *r = reply;
164 int exactmatch;
165 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
166 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
167 ot_peerlist *peer_list = torrent->peer_list; 196 ot_peerlist *peer_list = torrent->peer_list;
168 size_t index; 197 char *r = reply;
169
170 if( !torrent ) {
171 mutex_bucket_unlock_by_hash( hash );
172 return 0;
173 }
174 198
175 if( peer_list->peer_count < amount ) 199 if( amount > peer_list->peer_count )
176 amount = peer_list->peer_count; 200 amount = peer_list->peer_count;
177 201
178 if( proto == FLAG_TCP ) 202 if( proto == FLAG_TCP )
179 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); 203 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount );
180 else { 204 else {
@@ -185,40 +209,16 @@ size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROT
185 } 209 }
186 210
187 if( amount ) { 211 if( amount ) {
188 unsigned int pool_offset, pool_index = 0;; 212 if( amount == peer_list->peer_count )
189 unsigned int shifted_pc = peer_list->peer_count; 213 r += return_peers_all( peer_list, r );
190 unsigned int shifted_step = 0; 214 else
191 unsigned int shift = 0; 215 r += return_peers_selection( peer_list, amount, r );
192
193 /* Make fixpoint arithmetic as exact as possible */
194#define MAXPRECBIT (1<<(8*sizeof(int)-3))
195 while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; }
196 shifted_step = shifted_pc/amount;
197#undef MAXPRECBIT
198
199 /* Initialize somewhere in the middle of peers so that
200 fixpoint's aliasing doesn't alway miss the same peers */
201 pool_offset = random() % peer_list->peer_count;
202
203 for( index = 0; index < amount; ++index ) {
204 /* This is the aliased, non shifted range, next value may fall into */
205 unsigned int diff = ( ( ( index + 1 ) * shifted_step ) >> shift ) -
206 ( ( index * shifted_step ) >> shift );
207 pool_offset += 1 + random() % diff;
208
209 while( pool_offset >= peer_list->peers[pool_index].size ) {
210 pool_offset -= peer_list->peers[pool_index].size;
211 pool_index = ( pool_index + 1 ) % OT_POOLS_COUNT;
212 }
213
214 memmove( r, ((ot_peer*)peer_list->peers[pool_index].data) + pool_offset, 6 );
215 r += 6;
216 }
217 } 216 }
217
218 if( proto == FLAG_TCP ) 218 if( proto == FLAG_TCP )
219 *r++ = 'e'; 219 *r++ = 'e';
220 220
221 mutex_bucket_unlock_by_hash( hash ); 221 mutex_bucket_unlock_by_hash( &torrent->hash );
222 return r - reply; 222 return r - reply;
223} 223}
224 224
@@ -274,64 +274,43 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl
274 return r - reply; 274 return r - reply;
275} 275}
276 276
277static ot_peerlist dummy_list;
277size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ) { 278size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ) {
278 int exactmatch; 279 int exactmatch;
279 size_t index; 280 size_t reply_size = 0;
280 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); 281 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
281 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); 282 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
282 ot_peerlist *peer_list; 283 ot_peerlist *peer_list = &dummy_list;
283 284
284#ifdef WANT_SYNC_LIVE 285#ifdef WANT_SYNC_LIVE
285 if( proto != FLAG_MCA ) 286 if( proto != FLAG_MCA ) {
286 livesync_tell( hash, peer, PEER_FLAG_STOPPED ); 287 OT_FLAG( peer ) |= PEER_FLAG_STOPPED;
287#endif 288 livesync_tell( hash, peer );
288
289 if( !exactmatch ) {
290 mutex_bucket_unlock_by_hash( hash );
291
292 if( proto == FLAG_TCP )
293 return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM );
294
295 /* Create fake packet to satisfy parser on the other end */
296 if( proto == FLAG_UDP ) {
297 ((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
298 ((uint32_t*)reply)[3] = ((uint32_t*)reply)[4] = 0;
299 return (size_t)20;
300 }
301
302 if( proto == FLAG_MCA )
303 return 0;
304 } 289 }
290#endif
305 291
306 peer_list = torrent->peer_list; 292 if( exactmatch ) {
307 for( index = 0; index<OT_POOLS_COUNT; ++index ) { 293 peer_list = torrent->peer_list;
308 switch( vector_remove_peer( &peer_list->peers[index], peer, index == 0 ) ) { 294 switch( vector_remove_peer( &peer_list->peers, peer ) ) {
309 case 0: continue; 295 case 2: peer_list->seed_count--; /* Fall throughs intended */
310 case 2: peer_list->seed_counts[index]--; 296 case 1: peer_list->peer_count--; /* Fall throughs intended */
311 peer_list->seed_count--; 297 default: break;
312 case 1: default:
313 peer_list->peer_count--;
314 goto exit_loop;
315 } 298 }
316 } 299 }
317 300
318exit_loop: 301 if( proto == FLAG_TCP )
319 302 reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM );
320 if( proto == FLAG_TCP ) {
321 size_t reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM );
322 mutex_bucket_unlock_by_hash( hash );
323 return reply_size;
324 }
325 303
326 /* Handle UDP reply */ 304 /* Handle UDP reply */
327 if( proto == FLAG_UDP ) { 305 if( proto == FLAG_UDP ) {
328 ((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); 306 ((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
329 ((uint32_t*)reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count ); 307 ((uint32_t*)reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count );
330 ((uint32_t*)reply)[4] = htonl( peer_list->seed_count); 308 ((uint32_t*)reply)[4] = htonl( peer_list->seed_count);
309 reply_size = 20;
331 } 310 }
332 311
333 mutex_bucket_unlock_by_hash( hash ); 312 mutex_bucket_unlock_by_hash( hash );
334 return (size_t)20; 313 return reply_size;
335} 314}
336 315
337void exerr( char * message ) { 316void exerr( char * message ) {
@@ -354,7 +333,6 @@ int trackerlogic_init( const char * const serverdir ) {
354 fullscrape_init( ); 333 fullscrape_init( );
355 accesslist_init( ); 334 accesslist_init( );
356 livesync_init( ); 335 livesync_init( );
357 sync_init( );
358 stats_init( ); 336 stats_init( );
359 337
360 return 0; 338 return 0;
@@ -366,7 +344,6 @@ void trackerlogic_deinit( void ) {
366 344
367 /* Deinitialise background worker threads */ 345 /* Deinitialise background worker threads */
368 stats_deinit( ); 346 stats_deinit( );
369 sync_deinit( );
370 livesync_init( ); 347 livesync_init( );
371 accesslist_init( ); 348 accesslist_init( );
372 fullscrape_deinit( ); 349 fullscrape_deinit( );
diff --git a/trackerlogic.h b/trackerlogic.h
index 3d7bcb5..c2d071a 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -22,7 +22,7 @@ typedef time_t ot_time;
22#define OT_CLIENT_REQUEST_VARIATION (60*6) 22#define OT_CLIENT_REQUEST_VARIATION (60*6)
23 23
24#define OT_TORRENT_TIMEOUT_HOURS 24 24#define OT_TORRENT_TIMEOUT_HOURS 24
25#define OT_TORRENT_TIMEOUT ((60*60*OT_TORRENT_TIMEOUT_HOURS)/OT_POOLS_TIMEOUT) 25#define OT_TORRENT_TIMEOUT (60*OT_TORRENT_TIMEOUT_HOURS)
26 26
27#define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) ) 27#define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) )
28 28
@@ -34,15 +34,12 @@ typedef time_t ot_time;
34#define OT_ADMINIP_MAX 64 34#define OT_ADMINIP_MAX 64
35#define OT_MAX_THREADS 16 35#define OT_MAX_THREADS 16
36 36
37/* This list points to 9 pools of peers each grouped in five-minute-intervals 37#define OT_PEER_TIMEOUT 45
38 thus achieving a timeout of 2700s or 45 minutes
39 These pools are sorted by its binary content */
40#define OT_POOLS_COUNT 9
41#define OT_POOLS_TIMEOUT (60*5)
42 38
43/* From opentracker.c */ 39/* From opentracker.c */
44extern time_t g_now; 40extern time_t g_now_seconds;
45#define NOW (g_now/OT_POOLS_TIMEOUT) 41#define g_now_minutes (g_now_seconds/60)
42
46extern uint32_t g_tracker_id; 43extern uint32_t g_tracker_id;
47typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA } PROTO_FLAG; 44typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA } PROTO_FLAG;
48 45
@@ -57,6 +54,7 @@ static const uint8_t PEER_FLAG_LEECHING = 0x00;
57#define OT_SETIP( peer, ip ) memmove((peer),(ip),4); 54#define OT_SETIP( peer, ip ) memmove((peer),(ip),4);
58#define OT_SETPORT( peer, port ) memmove(((uint8_t*)peer)+4,(port),2); 55#define OT_SETPORT( peer, port ) memmove(((uint8_t*)peer)+4,(port),2);
59#define OT_FLAG(peer) (((uint8_t*)(peer))[6]) 56#define OT_FLAG(peer) (((uint8_t*)(peer))[6])
57#define OT_PEERTIME(peer) (((uint8_t*)(peer))[7])
60 58
61#define OT_PEER_COMPARE_SIZE ((size_t)6) 59#define OT_PEER_COMPARE_SIZE ((size_t)6)
62#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash)) 60#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
@@ -75,18 +73,18 @@ struct ot_peerlist {
75 size_t seed_count; 73 size_t seed_count;
76 size_t peer_count; 74 size_t peer_count;
77 size_t down_count; 75 size_t down_count;
78 size_t seed_counts[ OT_POOLS_COUNT ]; 76/* normal peers vector or
79 ot_vector peers[ OT_POOLS_COUNT ]; 77 pointer to ot_vector[32] buckets if data != NULL and space == 0
80#ifdef WANT_SYNC_BATCH 78*/
81 ot_vector changeset; 79 ot_vector peers;
82#endif
83}; 80};
81#define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list) && ((peer_list)->peers.size > (peer_list)->peers.space))
84 82
85/* 83/*
86 Exported functions 84 Exported functions
87*/ 85*/
88 86
89#if defined( WANT_SYNC_BATCH ) || defined( WANT_SYNC_LIVE ) 87#ifdef WANT_SYNC_LIVE
90#define WANT_SYNC 88#define WANT_SYNC
91#endif 89#endif
92 90
@@ -100,9 +98,11 @@ int trackerlogic_init( const char * const serverdir );
100void trackerlogic_deinit( void ); 98void trackerlogic_deinit( void );
101void exerr( char * message ); 99void exerr( char * message );
102 100
103ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) ); 101/* add_peer_to_torrent does only release the torrent bucket if from_sync is set,
102 otherwise it is released in return_peers_for_torrent */
103size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto );
104ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_sync ) );
104size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ); 105size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto );
105size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto );
106size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); 106size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply );
107size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); 107size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply );
108 108