diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | opentracker.c | 42 | ||||
-rw-r--r-- | opentracker.xcodeproj/project.pbxproj | 11 | ||||
-rw-r--r-- | ot_accesslist.c | 2 | ||||
-rw-r--r-- | ot_accesslist.h | 7 | ||||
-rw-r--r-- | ot_clean.c | 148 | ||||
-rw-r--r-- | ot_clean.h | 8 | ||||
-rw-r--r-- | ot_fullscrape.c | 1 | ||||
-rw-r--r-- | ot_http.c | 62 | ||||
-rw-r--r-- | ot_iovec.h | 2 | ||||
-rw-r--r-- | ot_livesync.c | 19 | ||||
-rw-r--r-- | ot_livesync.h | 4 | ||||
-rw-r--r-- | ot_mutex.c | 2 | ||||
-rw-r--r-- | ot_mutex.h | 13 | ||||
-rw-r--r-- | ot_stats.c | 71 | ||||
-rw-r--r-- | ot_stats.h | 4 | ||||
-rw-r--r-- | ot_udp.c | 2 | ||||
-rw-r--r-- | ot_vector.c | 239 | ||||
-rw-r--r-- | ot_vector.h | 20 | ||||
-rw-r--r-- | tests/testsuite.sh | 12 | ||||
-rw-r--r-- | tests/testsuite2.sh | 2 | ||||
-rw-r--r-- | trackerlogic.c | 291 | ||||
-rw-r--r-- | trackerlogic.h | 32 |
23 files changed, 463 insertions, 538 deletions
@@ -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 | ||
36 | FEATURES+=-DWANT_FULLSCRAPE | 33 | FEATURES+=-DWANT_FULLSCRAPE |
37 | 34 | ||
@@ -42,8 +39,8 @@ CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-pedantic -ansi | |||
42 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz | 39 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz |
43 | 40 | ||
44 | BINARY =opentracker | 41 | BINARY =opentracker |
45 | HEADERS=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 | 42 | HEADERS=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 |
46 | SOURCES=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 | 43 | SOURCES=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 | ||
48 | OBJECTS = $(SOURCES:%.c=%.o) | 45 | OBJECTS = $(SOURCES:%.c=%.o) |
49 | OBJECTS_debug = $(SOURCES:%.c=%.debug.o) | 46 | OBJECTS_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 */ |
43 | time_t g_now; | 37 | time_t g_now_seconds; |
44 | char * g_redirecturl = NULL; | 38 | char * g_redirecturl = NULL; |
45 | uint32_t g_tracker_id; | 39 | uint32_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 | ||
189 | static void server_mainloop( ) { | 183 | static 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 | ||
25 | typedef enum { | 25 | typedef 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 | ||
32 | int accesslist_blessip( char * ip, ot_permissions permissions ); | 31 | int accesslist_blessip( char * ip, ot_permissions permissions ); |
@@ -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 */ | ||
23 | static 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 | */ |
24 | int clean_single_torrent( ot_torrent *torrent ) { | 50 | int 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 | |||
92 | static 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 */ |
117 | static void * clean_worker( void * args ) { | 104 | static 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 | ||
128 | void clean_all_torrents( ) { | ||
129 | mutex_workqueue_pushtask( 0, TASK_CLEAN ); | ||
130 | } | ||
131 | |||
132 | static pthread_t thread_id; | 126 | static pthread_t thread_id; |
133 | void clean_init( void ) { | 127 | void clean_init( void ) { |
134 | pthread_create( &thread_id, NULL, clean_worker, NULL ); | 128 | pthread_create( &thread_id, NULL, clean_worker, NULL ); |
@@ -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 | |||
9 | void clean_init( void ); | 15 | void clean_init( void ); |
10 | void clean_deinit( void ); | 16 | void clean_deinit( void ); |
11 | |||
12 | void clean_all_torrents( void ); | ||
13 | int clean_single_torrent( ot_torrent *torrent ); | 17 | int 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> |
@@ -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 |
32 | static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT]; | 30 | static 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 | ||
169 | static 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 | |||
214 | static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) { | 166 | static 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 ); |
@@ -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 | |||
9 | void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ); | 11 | void *iovec_increase( int *iovec_entries, struct iovec **iovector, size_t new_alloc ); |
10 | void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ); | 12 | void iovec_fixlast( int *iovec_entries, struct iovec **iovector, void *last_ptr ); |
11 | void iovec_free( int *iovec_entries, struct iovec **iovector ); | 13 | void 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. */ |
95 | void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const uint8_t peerflag ) { | 95 | void 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 */ |
108 | void livesync_ticker( ) { | 107 | void 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(); | |||
49 | void livesync_bind_mcast( char *ip, uint16_t port ); | 48 | void 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. */ |
52 | void livesync_tell( ot_hash * const info_hash, const ot_peer * const peer, const uint8_t peerflag ); | 51 | void 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) |
@@ -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 ); |
@@ -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 | |||
9 | void mutex_init( ); | 11 | void mutex_init( ); |
10 | void mutex_deinit( ); | 12 | void 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 | ||
@@ -46,7 +46,7 @@ static unsigned long long ot_full_scrape_count = 0; | |||
46 | static unsigned long long ot_full_scrape_request_count = 0; | 46 | static unsigned long long ot_full_scrape_request_count = 0; |
47 | static unsigned long long ot_full_scrape_size = 0; | 47 | static unsigned long long ot_full_scrape_size = 0; |
48 | static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT]; | 48 | static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT]; |
49 | static unsigned long long ot_renewed[OT_POOLS_COUNT]; | 49 | static unsigned long long ot_renewed[OT_PEER_TIMEOUT]; |
50 | 50 | ||
51 | static time_t ot_start_time; | 51 | static 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 | ||
286 | bailout_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 | ||
302 | static 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 | |||
340 | static unsigned long events_per_time( unsigned long long events, time_t t ) { | 303 | static 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 | ||
505 | extern const char | 468 | extern 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 | ||
510 | size_t stats_return_tracker_version( char *reply ) { | 473 | size_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 | ||
644 | static pthread_t thread_id; | 597 | static pthread_t thread_id; |
645 | void stats_init( ) { | 598 | void 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 | ||
@@ -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 | ||
@@ -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 | |||
17 | static uint64_t vector_debug_inc[32]; | ||
18 | static uint64_t vector_debug_noinc[32]; | ||
19 | static uint64_t vector_debug_dec[32]; | ||
20 | static uint64_t vector_debug_nodec[32]; | ||
21 | static 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 | ||
33 | size_t vector_info( char * reply ) { | 19 | static 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 | */ |
52 | void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, | 32 | void *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 | ||
61 | static 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 | */ |
79 | void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { | 75 | void *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 */ | ||
98 | ot_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 | */ |
113 | int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) { | 110 | int 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 | ||
145 | void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { | 132 | void 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 | 148 | void 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 | |||
155 | void 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 | |||
241 | void 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 | ||
167 | const char *g_version_vector_c = "$Source$: $Revision$\n"; | 260 | const 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 | |||
15 | typedef struct { | 18 | typedef 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 | ||
21 | void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, | 24 | void *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 ); |
23 | void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); | 26 | void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); |
24 | 27 | ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ); | |
25 | int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ); | ||
26 | void vector_remove_torrent( ot_vector *vector, ot_torrent *match ); | ||
27 | 28 | ||
28 | #ifdef _DEBUG_VECTOR | 29 | int vector_remove_peer( ot_vector *vector, ot_peer *peer ); |
29 | size_t vector_info( char * reply ); | 30 | void vector_remove_torrent( ot_vector *vector, ot_torrent *match ); |
30 | #endif | 31 | void vector_redistribute_buckets( ot_peerlist * peer_list ); |
32 | void 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 | ||
3 | while true; do | 3 | while 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" |
7 | 2345678901234567\ | ||
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 | 8 | echo $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 | ||
14 | done | 14 | done |
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 | ||
34 | void free_peerlist( ot_peerlist *peer_list ) { | 28 | void 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 | ||
45 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_changeset ) ) { | 41 | ot_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 | ||
128 | static 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 | |||
148 | static 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 | */ |
162 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto ) { | 195 | size_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 | ||
277 | static ot_peerlist dummy_list; | ||
277 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ) { | 278 | size_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 | ||
318 | exit_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 | ||
337 | void exerr( char * message ) { | 316 | void 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 */ |
44 | extern time_t g_now; | 40 | extern time_t g_now_seconds; |
45 | #define NOW (g_now/OT_POOLS_TIMEOUT) | 41 | #define g_now_minutes (g_now_seconds/60) |
42 | |||
46 | extern uint32_t g_tracker_id; | 43 | extern uint32_t g_tracker_id; |
47 | typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA } PROTO_FLAG; | 44 | typedef 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 ); | |||
100 | void trackerlogic_deinit( void ); | 98 | void trackerlogic_deinit( void ); |
101 | void exerr( char * message ); | 99 | void exerr( char * message ); |
102 | 100 | ||
103 | ot_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 */ | ||
103 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ); | ||
104 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_sync ) ); | ||
104 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ); | 105 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROTO_FLAG proto ); |
105 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, PROTO_FLAG proto ); | ||
106 | size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); | 106 | size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); |
107 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); | 107 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); |
108 | 108 | ||