summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <>2007-10-27 14:06:07 +0000
committererdgeist <>2007-10-27 14:06:07 +0000
commitb19bbd6a850ecd51180dfea6e025a032fb2f1fe1 (patch)
tree84b17f4b10344fcb7addf653c8fdc10a4980fdb5
parent72c72bb3a18655925b6a6d3d1df5af3600da3b58 (diff)
Number of buckets is 1024 now
Clean all torrents now only cleans one bucket at a time All torrents that are being worked upon in an announce are being cleaned on demoand torrent's peer lists now keep extra counts for seeds and peers to speed up scrape and announce Sync has gone for now. I will think up a new way to implement. The old one was way to slow.
-rw-r--r--Makefile2
-rw-r--r--opentracker.c3
-rw-r--r--trackerlogic.c348
-rw-r--r--trackerlogic.h38
4 files changed, 195 insertions, 196 deletions
diff --git a/Makefile b/Makefile
index 11e4c50..2e2cfb8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1CC?=gcc 1CC?=gcc
2FEATURES=#-DWANT_CLOSED_TRACKER -DWANT_IP_FROM_QUERY_STRING -D_DEBUG_HTTPERROR 2FEATURES=#-DWANT_CLOSED_TRACKER -DWANT_UTORRENT1600_WORKAROUND #-DWANT_IP_FROM_QUERY_STRING -D_DEBUG_HTTPERROR -DWANT_TRACKER_SYNC
3OPTS_debug=-g -ggdb #-pg # -fprofile-arcs -ftest-coverage 3OPTS_debug=-g -ggdb #-pg # -fprofile-arcs -ftest-coverage
4OPTS_production=-s -Os 4OPTS_production=-s -Os
5CFLAGS+=-I../libowfat -Wall -pipe -Wextra #-pedantic #-ansi 5CFLAGS+=-I../libowfat -Wall -pipe -Wextra #-pedantic #-ansi
diff --git a/opentracker.c b/opentracker.c
index cfa051a..d9336da 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -243,7 +243,7 @@ static void httpresponse( const int64 s, char *data, size_t l ) {
243 for( c = data+4; *c == '/'; ++c); 243 for( c = data+4; *c == '/'; ++c);
244 244
245 switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { 245 switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) {
246 246#ifdef WANT_TRACKER_SYNC
247/****************************** 247/******************************
248 * S Y N C * 248 * S Y N C *
249 ******************************/ 249 ******************************/
@@ -286,6 +286,7 @@ LOG_TO_STDERR( "sync: %d.%d.%d.%d\n", h->ip[0], h->ip[1], h->ip[2], h->ip[3] );
286 reply_size = 2; 286 reply_size = 2;
287 287
288 break; 288 break;
289#endif
289/****************************** 290/******************************
290 * S T A T S * 291 * S T A T S *
291 ******************************/ 292 ******************************/
diff --git a/trackerlogic.c b/trackerlogic.c
index 3560834..3aa3752 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -20,7 +20,8 @@
20#include "byte.h" 20#include "byte.h"
21 21
22/* GLOBAL VARIABLES */ 22/* GLOBAL VARIABLES */
23static ot_vector all_torrents[256]; 23static ot_vector all_torrents[OT_BUCKET_COUNT];
24static ot_time all_torrents_clean[OT_BUCKET_COUNT];
24static ot_vector changeset; 25static ot_vector changeset;
25#if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) 26#if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER )
26static ot_vector accesslist; 27static ot_vector accesslist;
@@ -28,7 +29,8 @@ static ot_vector accesslist;
28#endif 29#endif
29 30
30static size_t changeset_size = 0; 31static size_t changeset_size = 0;
31static time_t last_clean_time = 0; 32
33static int clean_single_torrent( ot_torrent *torrent );
32 34
33/* Converter function from memory to human readable hex strings 35/* Converter function from memory to human readable hex strings
34 - definitely not thread safe!!! 36 - definitely not thread safe!!!
@@ -127,19 +129,10 @@ static void free_peerlist( ot_peerlist *peer_list ) {
127 free( peer_list ); 129 free( peer_list );
128} 130}
129 131
130/* This is the non-generic delete from vector-operation specialized for torrents in buckets. 132static void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
131 it returns 0 if the hash wasn't found in vector
132 1 if the torrent was removed from vector
133*/
134static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
135 int exactmatch;
136 ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; 133 ot_torrent *end = ((ot_torrent*)vector->data) + vector->size;
137 ot_torrent *match;
138 134
139 if( !vector->size ) return 0; 135 if( !vector->size ) return;
140
141 match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
142 if( !exactmatch ) return 0;
143 136
144 /* If this is being called after a unsuccessful malloc() for peer_list 137 /* If this is being called after a unsuccessful malloc() for peer_list
145 in add_peer_to_torrent, match->peer_list actually might be NULL */ 138 in add_peer_to_torrent, match->peer_list actually might be NULL */
@@ -150,14 +143,13 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
150 vector->space /= OT_VECTOR_SHRINK_RATIO; 143 vector->space /= OT_VECTOR_SHRINK_RATIO;
151 vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); 144 vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) );
152 } 145 }
153 return 1;
154} 146}
155 147
156ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) { 148ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) {
157 int exactmatch; 149 int exactmatch;
158 ot_torrent *torrent; 150 ot_torrent *torrent;
159 ot_peer *peer_dest; 151 ot_peer *peer_dest;
160 ot_vector *torrents_list = &all_torrents[*hash[0]], *peer_pool; 152 ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ), *peer_pool;
161 int base_pool = 0; 153 int base_pool = 0;
162 154
163#ifdef WANT_ACCESS_CONTROL 155#ifdef WANT_ACCESS_CONTROL
@@ -179,13 +171,14 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changese
179 memmove( &torrent->hash, hash, sizeof( ot_hash ) ); 171 memmove( &torrent->hash, hash, sizeof( ot_hash ) );
180 172
181 if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { 173 if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
182 vector_remove_torrent( torrents_list, hash ); 174 vector_remove_torrent( torrents_list, torrent );
183 return NULL; 175 return NULL;
184 } 176 }
185 177
186 byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); 178 byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
187 torrent->peer_list->base = NOW; 179 torrent->peer_list->base = NOW;
188 } 180 } else
181 clean_single_torrent( torrent );
189 182
190 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ 183 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
191 if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) 184 if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
@@ -208,27 +201,37 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changese
208 if( !exactmatch ) { 201 if( !exactmatch ) {
209 int i; 202 int i;
210 memmove( peer_dest, peer, sizeof( ot_peer ) ); 203 memmove( peer_dest, peer, sizeof( ot_peer ) );
204 torrent->peer_list->peer_count++;
211 205
212 if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) 206 if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED )
213 torrent->peer_list->downloaded++; 207 torrent->peer_list->down_count++;
214 208
215 if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) 209 if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) {
216 torrent->peer_list->seed_count[ base_pool ]++; 210 torrent->peer_list->seed_counts[ base_pool ]++;
211 torrent->peer_list->seed_count++;
212 }
217 213
218 for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) { 214 for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) {
219 switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) { 215 switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) {
220 case 0: continue; 216 case 0: continue;
221 case 2: torrent->peer_list->seed_count[i]--; 217 case 2: torrent->peer_list->seed_counts[i]--;
222 case 1: default: return torrent; 218 torrent->peer_list->seed_count--;
219 case 1: default:
220 torrent->peer_list->peer_count--;
221 return torrent;
223 } 222 }
224 } 223 }
225 } else { 224 } else {
226 if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) 225 if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) {
227 torrent->peer_list->seed_count[ base_pool ]--; 226 torrent->peer_list->seed_counts[ base_pool ]--;
228 if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) 227 torrent->peer_list->seed_count--;
229 torrent->peer_list->seed_count[ base_pool ]++; 228 }
229 if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) {
230 torrent->peer_list->seed_counts[ base_pool ]++;
231 torrent->peer_list->seed_count++;
232 }
230 if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) ) 233 if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) )
231 torrent->peer_list->downloaded++; 234 torrent->peer_list->down_count++;
232 if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) 235 if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED )
233 OT_FLAG( peer ) |= PEER_FLAG_COMPLETED; 236 OT_FLAG( peer ) |= PEER_FLAG_COMPLETED;
234 237
@@ -245,29 +248,25 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changese
245 * does not yet check not to return self 248 * does not yet check not to return self
246*/ 249*/
247size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) { 250size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) {
248 char *r = reply; 251 char *r = reply;
249 size_t peer_count, seed_count, index; 252 ot_peerlist *peer_list = torrent->peer_list;
250 253 size_t index;
251 for( peer_count = seed_count = index = 0; index < OT_POOLS_COUNT; ++index ) {
252 peer_count += torrent->peer_list->peers[index].size;
253 seed_count += torrent->peer_list->seed_count[index];
254 }
255 254
256 if( peer_count < amount ) 255 if( peer_list->peer_count < amount )
257 amount = peer_count; 256 amount = peer_list->peer_count;
258 257
259 if( is_tcp ) 258 if( is_tcp )
260 r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); 259 r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount );
261 else { 260 else {
262 *(ot_dword*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); 261 *(ot_dword*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
263 *(ot_dword*)(r+4) = htonl( peer_count ); 262 *(ot_dword*)(r+4) = htonl( peer_list->peer_count );
264 *(ot_dword*)(r+8) = htonl( seed_count ); 263 *(ot_dword*)(r+8) = htonl( peer_list->seed_count );
265 r += 12; 264 r += 12;
266 } 265 }
267 266
268 if( amount ) { 267 if( amount ) {
269 unsigned int pool_offset, pool_index = 0;; 268 unsigned int pool_offset, pool_index = 0;;
270 unsigned int shifted_pc = peer_count; 269 unsigned int shifted_pc = peer_list->peer_count;
271 unsigned int shifted_step = 0; 270 unsigned int shifted_step = 0;
272 unsigned int shift = 0; 271 unsigned int shift = 0;
273 272
@@ -279,7 +278,7 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply
279 278
280 /* Initialize somewhere in the middle of peers so that 279 /* Initialize somewhere in the middle of peers so that
281 fixpoint's aliasing doesn't alway miss the same peers */ 280 fixpoint's aliasing doesn't alway miss the same peers */
282 pool_offset = random() % peer_count; 281 pool_offset = random() % peer_list->peer_count;
283 282
284 for( index = 0; index < amount; ++index ) { 283 for( index = 0; index < amount; ++index ) {
285 /* This is the aliased, non shifted range, next value may fall into */ 284 /* This is the aliased, non shifted range, next value may fall into */
@@ -287,12 +286,12 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply
287 ( ( index * shifted_step ) >> shift ); 286 ( ( index * shifted_step ) >> shift );
288 pool_offset += 1 + random() % diff; 287 pool_offset += 1 + random() % diff;
289 288
290 while( pool_offset >= torrent->peer_list->peers[pool_index].size ) { 289 while( pool_offset >= peer_list->peers[pool_index].size ) {
291 pool_offset -= torrent->peer_list->peers[pool_index].size; 290 pool_offset -= peer_list->peers[pool_index].size;
292 pool_index = ( pool_index + 1 ) % OT_POOLS_COUNT; 291 pool_index = ( pool_index + 1 ) % OT_POOLS_COUNT;
293 } 292 }
294 293
295 memmove( r, ((ot_peer*)torrent->peer_list->peers[pool_index].data) + pool_offset, 6 ); 294 memmove( r, ((ot_peer*)peer_list->peers[pool_index].data) + pool_offset, 6 );
296 r += 6; 295 r += 6;
297 } 296 }
298 } 297 }
@@ -316,10 +315,10 @@ static void fix_mmapallocation( void *buf, size_t old_alloc, size_t new_alloc )
316size_t return_fullscrape_for_tracker( char **reply ) { 315size_t return_fullscrape_for_tracker( char **reply ) {
317 size_t torrent_count = 0, j; 316 size_t torrent_count = 0, j;
318 size_t allocated, replysize; 317 size_t allocated, replysize;
319 int i, k; 318 int i;
320 char *r; 319 char *r;
321 320
322 for( i=0; i<256; ++i ) 321 for( i=0; i<OT_BUCKET_COUNT; ++i )
323 torrent_count += all_torrents[i].size; 322 torrent_count += all_torrents[i].size;
324 323
325 /* one extra for pro- and epilogue */ 324 /* one extra for pro- and epilogue */
@@ -327,20 +326,15 @@ size_t return_fullscrape_for_tracker( char **reply ) {
327 if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; 326 if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0;
328 327
329 memmove( r, "d5:filesd", 9 ); r += 9; 328 memmove( r, "d5:filesd", 9 ); r += 9;
330 for( i=0; i<256; ++i ) { 329 for( i=0; i<OT_BUCKET_COUNT; ++i ) {
331 ot_vector *torrents_list = &all_torrents[i]; 330 ot_vector *torrents_list = all_torrents + i;
332 for( j=0; j<torrents_list->size; ++j ) { 331 for( j=0; j<torrents_list->size; ++j ) {
333 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 332 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
334 ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; 333 ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
335 size_t peers = 0, seeds = 0; 334 if( peer_list->peer_count || peer_list->down_count ) {
336 for( k=0; k<OT_POOLS_COUNT; ++k ) {
337 peers += peer_list->peers[k].size;
338 seeds += peer_list->seed_count[k];
339 }
340 if( peers || peer_list->downloaded ) {
341 *r++='2'; *r++='0'; *r++=':'; 335 *r++='2'; *r++='0'; *r++=':';
342 memmove( r, hash, 20 ); r+=20; 336 memmove( r, hash, 20 ); r+=20;
343 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seeds, peer_list->downloaded, peers-seeds ); 337 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count );
344 } 338 }
345 } 339 }
346 } 340 }
@@ -359,19 +353,19 @@ size_t return_memstat_for_tracker( char **reply ) {
359 int i, k; 353 int i, k;
360 char *r; 354 char *r;
361 355
362 for( i=0; i<256; ++i ) { 356 for( i=0; i<OT_BUCKET_COUNT; ++i ) {
363 ot_vector *torrents_list = &all_torrents[i]; 357 ot_vector *torrents_list = all_torrents + i;
364 torrent_count += torrents_list->size; 358 torrent_count += torrents_list->size;
365 } 359 }
366 360
367 allocated = 256*32 + (43+OT_POOLS_COUNT*32)*torrent_count; 361 allocated = OT_BUCKET_COUNT*32 + (43+OT_POOLS_COUNT*32)*torrent_count;
368 if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; 362 if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0;
369 363
370 for( i=0; i<256; ++i ) 364 for( i=0; i<OT_BUCKET_COUNT; ++i )
371 r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space ); 365 r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space );
372 366
373 for( i=0; i<256; ++i ) { 367 for( i=0; i<OT_BUCKET_COUNT; ++i ) {
374 ot_vector *torrents_list = &all_torrents[i]; 368 ot_vector *torrents_list = all_torrents + i;
375 for( j=0; j<torrents_list->size; ++j ) { 369 for( j=0; j<torrents_list->size; ++j ) {
376 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 370 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
377 ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; 371 ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
@@ -389,9 +383,8 @@ size_t return_memstat_for_tracker( char **reply ) {
389 383
390/* Fetches scrape info for a specific torrent */ 384/* Fetches scrape info for a specific torrent */
391size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { 385size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) {
392 int exactmatch, i; 386 int exactmatch ;
393 size_t peers = 0, seeds = 0; 387 ot_vector *torrents_list = hash_to_bucket( all_torrents, hash );
394 ot_vector *torrents_list = &all_torrents[*hash[0]];
395 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); 388 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
396 389
397 if( !exactmatch ) { 390 if( !exactmatch ) {
@@ -399,13 +392,14 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) {
399 } else { 392 } else {
400 ot_dword *r = (ot_dword*) reply; 393 ot_dword *r = (ot_dword*) reply;
401 394
402 for( i=0; i<OT_POOLS_COUNT; ++i ) { 395 if( clean_single_torrent( torrent ) ) {
403 peers += torrent->peer_list->peers[i].size; 396 vector_remove_torrent( torrents_list, torrent );
404 seeds += torrent->peer_list->seed_count[i]; 397 memset( reply, 0, 12);
398 } else {
399 r[0] = htonl( torrent->peer_list->seed_count );
400 r[1] = htonl( torrent->peer_list->down_count );
401 r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count );
405 } 402 }
406 r[0] = htonl( seeds );
407 r[1] = htonl( torrent->peer_list->downloaded );
408 r[2] = htonl( peers-seeds );
409 } 403 }
410 return 12; 404 return 12;
411} 405}
@@ -413,31 +407,30 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) {
413/* Fetches scrape info for a specific torrent */ 407/* Fetches scrape info for a specific torrent */
414size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { 408size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) {
415 char *r = reply; 409 char *r = reply;
416 int exactmatch, i, j; 410 int exactmatch, i;
417 411
418 r += sprintf( r, "d5:filesd" ); 412 r += sprintf( r, "d5:filesd" );
419 413
420 for( i=0; i<amount; ++i ) { 414 for( i=0; i<amount; ++i ) {
421 ot_hash *hash = hash_list + i; 415 ot_hash *hash = hash_list + i;
422 ot_vector *torrents_list = &all_torrents[*hash[0]]; 416 ot_vector *torrents_list = hash_to_bucket( all_torrents, hash );
423 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); 417 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
424 size_t peers = 0, seeds = 0;
425 418
426 if( !exactmatch ) continue; 419 if( !exactmatch ) continue;
427 420 if( clean_single_torrent( torrent ) ) {
428 for( j=0; j<OT_POOLS_COUNT; ++j ) { 421 vector_remove_torrent( torrents_list, torrent );
429 peers += torrent->peer_list->peers[j].size; 422 } else {
430 seeds += torrent->peer_list->seed_count[j]; 423 memmove( r, "20:", 3 ); memmove( r+3, hash, 20 );
424 r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
425 torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23;
431 } 426 }
432
433 memmove( r, "20:", 3 ); memmove( r+3, hash, 20 );
434 r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 23;
435 } 427 }
436 428
437 *r++ = 'e'; *r++ = 'e'; 429 *r++ = 'e'; *r++ = 'e';
438 return r - reply; 430 return r - reply;
439} 431}
440 432
433#ifdef WANT_TRACKER_SYNC
441/* Throw away old changeset */ 434/* Throw away old changeset */
442static void release_changeset( void ) { 435static void release_changeset( void ) {
443 ot_byte **changeset_ptrs = (ot_byte**)(changeset.data); 436 ot_byte **changeset_ptrs = (ot_byte**)(changeset.data);
@@ -548,86 +541,91 @@ size_t return_changeset_for_tracker( char **reply ) {
548 541
549 return r; 542 return r;
550} 543}
544#endif
551 545
552/* Clean up all torrents, remove timedout pools and 546/* Clean a single torrent
553 torrents, also prepare new changeset */ 547 return 1 if torrent timed out
554void clean_all_torrents( void ) { 548*/
555 int i, k; 549static int clean_single_torrent( ot_torrent *torrent ) {
556 size_t j; 550 ot_peerlist *peer_list = torrent->peer_list;
557 time_t time_now = NOW; 551 size_t peers_count = 0, seeds_count;
558 size_t peers_count; 552 time_t timedout = (int)( NOW - peer_list->base );
559 ot_dword diff; struct timeval tv1, tv2; gettimeofday( &tv1, NULL ); 553 int i;
560
561 if( time_now <= last_clean_time )
562 return;
563 last_clean_time = time_now;
564
565 release_changeset();
566 554
567 for( i=0; i<256; ++i ) { 555 /* Torrent has idled out */
568 ot_vector *torrents_list = &all_torrents[i]; 556 if( timedout > OT_TORRENT_TIMEOUT )
569 for( j=0; j<torrents_list->size; ++j ) { 557 return 1;
570 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
571 ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
572 558
573 time_t timedout = (int)( time_now - peer_list->base ); 559 /* Nothing to be cleaned here? Test if torrent is worth keeping */
560 if( timedout > OT_POOLS_COUNT ) {
561 if( !peer_list->peer_count )
562 return peer_list->down_count ? 0 : 1;
563 timedout = OT_POOLS_COUNT;
564 }
574 565
575 /* Torrent has idled out */ 566 /* Release vectors that have timed out */
576 if( timedout > OT_TORRENT_TIMEOUT ) { 567 for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i )
577 vector_remove_torrent( torrents_list, hash ); 568 free( peer_list->peers[i].data);
578 --j; continue;
579 }
580 569
581 /* If nothing to be cleaned here, handle next torrent */ 570 /* Shift vectors back by the amount of pools that were shifted out */
582 if( timedout > OT_POOLS_COUNT ) { 571 memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) );
572 byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
583 573
584 peers_count = 0; 574 /* Shift back seed counts as well */
585 for( k = 0; k < OT_POOLS_COUNT; ++k ) 575 memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) );
586 peers_count += peer_list->peers[k].size; 576 byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout );
587 577
588 if( !peers_count ) { 578 /* Save the block modified within last OT_POOLS_TIMEOUT --- XXX no sync for now
589 if( !peer_list->downloaded ) { 579 if( peer_list->peers[1].size )
590 vector_remove_torrent( torrents_list, hash ); 580 add_pool_to_changeset( hash, peer_list->peers[1].data, peer_list->peers[1].size );
591 --j; 581 */
592 }
593 continue;
594 }
595 582
596 timedout = OT_POOLS_COUNT; 583 peers_count = seeds_count = 0;
597 } 584 for( i = 0; i < OT_POOLS_COUNT; ++i ) {
585 peers_count += peer_list->peers[i].size;
586 seeds_count += peer_list->seed_counts[i];
587 }
588 peer_list->seed_count = seeds_count;
589 peer_list->peer_count = peers_count;
598 590
599 /* Release vectors that have timed out */ 591 if( peers_count )
600 for( k = OT_POOLS_COUNT - timedout; k < OT_POOLS_COUNT; ++k ) 592 peer_list->base = NOW;
601 free( peer_list->peers[k].data); 593 else {
594 /* When we got here, the last time that torrent
595 has been touched is OT_POOLS_COUNT units before */
596 peer_list->base = NOW - OT_POOLS_COUNT;
597 }
598 return 0;
599}
602 600
603 /* Shift vectors back by the amount of pools that were shifted out */ 601/* Clean up all peers in current bucket, remove timedout pools and
604 memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) ); 602 torrents */
605 byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); 603void clean_all_torrents( void ) {
604 ot_vector *torrents_list;
605 size_t i;
606 static int bucket;
607 ot_time time_now = NOW;
606 608
607 /* Shift back seed counts as well */ 609/* No sync for now
608 memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) ); 610 release_changeset();
609 byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout ); 611*/
610 612
611 /* Save the block modified within last OT_POOLS_TIMEOUT */ 613 /* Search for an uncleaned bucked */
612 if( peer_list->peers[1].size ) 614 while( ( all_torrents_clean[bucket] == time_now ) && ( ++bucket < OT_BUCKET_COUNT ) );
613 add_pool_to_changeset( hash, peer_list->peers[1].data, peer_list->peers[1].size ); 615 if( bucket >= OT_BUCKET_COUNT ) {
616 bucket = 0; return;
617 }
614 618
615 peers_count = 0; 619 all_torrents_clean[bucket] = time_now;
616 for( k = 0; k < OT_POOLS_COUNT; ++k )
617 peers_count += peer_list->peers[k].size;
618 620
619 if( peers_count ) { 621 torrents_list = all_torrents + bucket;
620 peer_list->base = time_now; 622 for( i=0; i<torrents_list->size; ++i ) {
621 } else { 623 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i;
622 /* When we got here, the last time that torrent 624 if( clean_single_torrent( torrent ) ) {
623 has been touched is OT_POOLS_COUNT units before */ 625 vector_remove_torrent( torrents_list, torrent );
624 peer_list->base = time_now - OT_POOLS_COUNT; 626 --i; continue;
625 }
626 } 627 }
627 } 628 }
628
629 gettimeofday( &tv2, NULL ); diff = ( tv2.tv_sec - tv1.tv_sec ) * 1000000 + tv2.tv_usec - tv1.tv_usec;
630 fprintf( stderr, "Cleanup time taken: %u\n", diff );
631} 629}
632 630
633typedef struct { size_t val; ot_torrent * torrent; } ot_record; 631typedef struct { size_t val; ot_torrent * torrent; } ot_record;
@@ -637,37 +635,31 @@ size_t return_stats_for_tracker( char *reply, int mode ) {
637 size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; 635 size_t torrent_count = 0, peer_count = 0, seed_count = 0, j;
638 ot_record top5s[5], top5c[5]; 636 ot_record top5s[5], top5c[5];
639 char *r = reply; 637 char *r = reply;
640 int i,k; 638 int i;
641 639
642 byte_zero( top5s, sizeof( top5s ) ); 640 byte_zero( top5s, sizeof( top5s ) );
643 byte_zero( top5c, sizeof( top5c ) ); 641 byte_zero( top5c, sizeof( top5c ) );
644 642
645 for( i=0; i<256; ++i ) { 643 for( i=0; i<OT_BUCKET_COUNT; ++i ) {
646 ot_vector *torrents_list = &all_torrents[i]; 644 ot_vector *torrents_list = all_torrents + i;
647 torrent_count += torrents_list->size; 645 torrent_count += torrents_list->size;
648 for( j=0; j<torrents_list->size; ++j ) { 646 for( j=0; j<torrents_list->size; ++j ) {
649 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 647 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
650 size_t local_peers = 0, local_seeds = 0;
651
652 for( k=0; k<OT_POOLS_COUNT; ++k ) {
653 local_peers += peer_list->peers[k].size;
654 local_seeds += peer_list->seed_count[k];
655 }
656 if( mode == STATS_TOP5 ) { 648 if( mode == STATS_TOP5 ) {
657 int idx = 4; while( (idx >= 0) && ( local_peers > top5c[idx].val ) ) --idx; 649 int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx;
658 if ( idx++ != 4 ) { 650 if ( idx++ != 4 ) {
659 memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); 651 memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) );
660 top5c[idx].val = local_peers; 652 top5c[idx].val = peer_list->peer_count;
661 top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; 653 top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
662 } 654 }
663 idx = 4; while( (idx >= 0) && ( local_seeds > top5s[idx].val ) ) --idx; 655 idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx;
664 if ( idx++ != 4 ) { 656 if ( idx++ != 4 ) {
665 memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); 657 memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) );
666 top5s[idx].val = local_seeds; 658 top5s[idx].val = peer_list->seed_count;
667 top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; 659 top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
668 } 660 }
669 } 661 }
670 peer_count += local_peers; seed_count += local_seeds; 662 peer_count += peer_list->peer_count; seed_count += peer_list->seed_count;
671 } 663 }
672 } 664 }
673 if( mode == STATS_TOP5 ) { 665 if( mode == STATS_TOP5 ) {
@@ -708,8 +700,8 @@ size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh )
708 700
709 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); 701 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh );
710 702
711 for( i=0; i<256; ++i ) { 703 for( i=0; i<OT_BUCKET_COUNT; ++i ) {
712 ot_vector *torrents_list = &all_torrents[i]; 704 ot_vector *torrents_list = all_torrents + i;
713 for( j=0; j<torrents_list->size; ++j ) { 705 for( j=0; j<torrents_list->size; ++j ) {
714 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 706 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
715 for( k=0; k<OT_POOLS_COUNT; ++k ) { 707 for( k=0; k<OT_POOLS_COUNT; ++k ) {
@@ -787,8 +779,8 @@ size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thres
787 779
788 r += sprintf( r, "Stats for all /24s with more than %d announced torrents:\n\n", ((int)thresh) ); 780 r += sprintf( r, "Stats for all /24s with more than %d announced torrents:\n\n", ((int)thresh) );
789 781
790 for( i=0; i<256; ++i ) { 782 for( i=0; i<OT_BUCKET_COUNT; ++i ) {
791 ot_vector *torrents_list = &all_torrents[i]; 783 ot_vector *torrents_list = all_torrents + i;
792 for( j=0; j<torrents_list->size; ++j ) { 784 for( j=0; j<torrents_list->size; ++j ) {
793 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 785 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
794 for( k=0; k<OT_POOLS_COUNT; ++k ) { 786 for( k=0; k<OT_POOLS_COUNT; ++k ) {
@@ -828,9 +820,10 @@ size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thres
828 820
829size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { 821size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) {
830 int exactmatch; 822 int exactmatch;
831 size_t peer_count, seed_count, index; 823 size_t index;
832 ot_vector *torrents_list = &all_torrents[*hash[0]]; 824 ot_vector *torrents_list = hash_to_bucket( all_torrents, hash );
833 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); 825 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
826 ot_peerlist *peer_list;
834 827
835 if( !exactmatch ) { 828 if( !exactmatch ) {
836 if( is_tcp ) 829 if( is_tcp )
@@ -842,33 +835,27 @@ size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int
842 return (size_t)20; 835 return (size_t)20;
843 } 836 }
844 837
845 for( peer_count = seed_count = index = 0; index<OT_POOLS_COUNT; ++index ) { 838 peer_list = torrent->peer_list;
846 peer_count += torrent->peer_list->peers[index].size; 839 for( index = 0; index<OT_POOLS_COUNT; ++index ) {
847 seed_count += torrent->peer_list->seed_count[index]; 840 switch( vector_remove_peer( &peer_list->peers[index], peer, index == 0 ) ) {
848
849 switch( vector_remove_peer( &torrent->peer_list->peers[index], peer, index == 0 ) ) {
850 case 0: continue; 841 case 0: continue;
851 case 2: torrent->peer_list->seed_count[index]--; 842 case 2: peer_list->seed_counts[index]--;
852 seed_count--; 843 peer_list->seed_count--;
853 case 1: default: 844 case 1: default:
854 peer_count--; 845 peer_list->peer_count--;
855 goto exit_loop; 846 goto exit_loop;
856 } 847 }
857 } 848 }
858 849
859exit_loop: 850exit_loop:
860 for( ++index; index < OT_POOLS_COUNT; ++index ) {
861 peer_count += torrent->peer_list->peers[index].size;
862 seed_count += torrent->peer_list->seed_count[index];
863 }
864 851
865 if( is_tcp ) 852 if( is_tcp )
866 return sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", seed_count, peer_count - seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM ); 853 return 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 );
867 854
868 /* else { Handle UDP reply */ 855 /* else { Handle UDP reply */
869 ((ot_dword*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); 856 ((ot_dword*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
870 ((ot_dword*)reply)[3] = peer_count - seed_count; 857 ((ot_dword*)reply)[3] = peer_list->peer_count - peer_list->seed_count;
871 ((ot_dword*)reply)[4] = seed_count; 858 ((ot_dword*)reply)[4] = peer_list->seed_count;
872 return (size_t)20; 859 return (size_t)20;
873} 860}
874 861
@@ -893,7 +880,7 @@ void deinit_logic( void ) {
893 size_t j; 880 size_t j;
894 881
895 /* Free all torrents... */ 882 /* Free all torrents... */
896 for(i=0; i<256; ++i ) { 883 for(i=0; i<OT_BUCKET_COUNT; ++i ) {
897 if( all_torrents[i].size ) { 884 if( all_torrents[i].size ) {
898 ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data; 885 ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data;
899 for( j=0; j<all_torrents[i].size; ++j ) 886 for( j=0; j<all_torrents[i].size; ++j )
@@ -902,6 +889,7 @@ void deinit_logic( void ) {
902 } 889 }
903 } 890 }
904 byte_zero( all_torrents, sizeof (all_torrents)); 891 byte_zero( all_torrents, sizeof (all_torrents));
892 byte_zero( all_torrents_clean, sizeof (all_torrents_clean));
905 byte_zero( &changeset, sizeof( changeset ) ); 893 byte_zero( &changeset, sizeof( changeset ) );
906 changeset_size = 0; 894 changeset_size = 0;
907} 895}
diff --git a/trackerlogic.h b/trackerlogic.h
index 96b59f3..fd8f48a 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -20,6 +20,16 @@ typedef ot_byte ot_hash[20];
20typedef ot_dword ot_ip; 20typedef ot_dword ot_ip;
21typedef time_t ot_time; 21typedef time_t ot_time;
22 22
23#define OT_VECTOR_MIN_MEMBERS 4
24#define OT_VECTOR_GROW_RATIO 8
25#define OT_VECTOR_SHRINK_THRESH 6
26#define OT_VECTOR_SHRINK_RATIO 4
27typedef struct {
28 void *data;
29 size_t size;
30 size_t space;
31} ot_vector;
32
23/* Some tracker behaviour tunable */ 33/* Some tracker behaviour tunable */
24#define OT_CLIENT_TIMEOUT 30 34#define OT_CLIENT_TIMEOUT 30
25#define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10 35#define OT_CLIENT_TIMEOUT_CHECKINTERVAL 10
@@ -32,8 +42,13 @@ typedef time_t ot_time;
32 42
33#define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) ) 43#define OT_CLIENT_REQUEST_INTERVAL_RANDOM ( OT_CLIENT_REQUEST_INTERVAL - OT_CLIENT_REQUEST_VARIATION/2 + (int)( random( ) % OT_CLIENT_REQUEST_VARIATION ) )
34 44
35/* We maintain a list of 256 pointers to sorted list of ot_torrent structs 45/* We maintain a list of 4096 pointers to sorted list of ot_torrent structs
36 Sort key is, of course, its hash */ 46 Sort key is, of course, its hash */
47#define OT_BUCKET_COUNT 1024
48static inline ot_vector *hash_to_bucket( ot_vector *vectors, ot_hash *hash ) {
49 unsigned char *local_hash = hash[0];
50 return vectors + ( ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ) );
51}
37 52
38/* This list points to 9 pools of peers each grouped in five-minute-intervals 53/* This list points to 9 pools of peers each grouped in five-minute-intervals
39 thus achieving a timeout of 2700s or 45 minutes 54 thus achieving a timeout of 2700s or 45 minutes
@@ -45,16 +60,6 @@ typedef time_t ot_time;
45extern time_t g_now; 60extern time_t g_now;
46#define NOW (g_now/OT_POOLS_TIMEOUT) 61#define NOW (g_now/OT_POOLS_TIMEOUT)
47 62
48#define OT_VECTOR_MIN_MEMBERS 4
49#define OT_VECTOR_GROW_RATIO 8
50#define OT_VECTOR_SHRINK_THRESH 6
51#define OT_VECTOR_SHRINK_RATIO 4
52typedef struct {
53 void *data;
54 size_t size;
55 size_t space;
56} ot_vector;
57
58typedef struct { 63typedef struct {
59 ot_byte data[8]; 64 ot_byte data[8];
60} ot_peer; 65} ot_peer;
@@ -71,8 +76,10 @@ static const ot_byte PEER_FLAG_STOPPED = 0x20;
71 76
72typedef struct { 77typedef struct {
73 ot_time base; 78 ot_time base;
74 size_t seed_count[ OT_POOLS_COUNT ]; 79 size_t seed_count;
75 size_t downloaded; 80 size_t peer_count;
81 size_t down_count;
82 size_t seed_counts[ OT_POOLS_COUNT ];
76 ot_vector peers[ OT_POOLS_COUNT ]; 83 ot_vector peers[ OT_POOLS_COUNT ];
77} ot_peerlist; 84} ot_peerlist;
78 85
@@ -100,9 +107,12 @@ size_t return_stats_for_tracker( char *reply, int mode );
100size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ); 107size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh );
101size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thresh ); 108size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thresh );
102size_t return_memstat_for_tracker( char **reply ); 109size_t return_memstat_for_tracker( char **reply );
110void clean_all_torrents( void );
111
112#ifdef WANT_TRACKER_SYNC
103size_t return_changeset_for_tracker( char **reply ); 113size_t return_changeset_for_tracker( char **reply );
104int add_changeset_to_tracker( ot_byte *data, size_t len ); 114int add_changeset_to_tracker( ot_byte *data, size_t len );
105void clean_all_torrents( void ); 115#endif
106 116
107#if defined ( WANT_BLACKLISTING ) || defined ( WANT_CLOSED_TRACKER ) 117#if defined ( WANT_BLACKLISTING ) || defined ( WANT_CLOSED_TRACKER )
108int accesslist_addentry( ot_hash *hash ); 118int accesslist_addentry( ot_hash *hash );