diff options
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 348 |
1 files changed, 168 insertions, 180 deletions
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 */ |
23 | static ot_vector all_torrents[256]; | 23 | static ot_vector all_torrents[OT_BUCKET_COUNT]; |
24 | static ot_time all_torrents_clean[OT_BUCKET_COUNT]; | ||
24 | static ot_vector changeset; | 25 | static ot_vector changeset; |
25 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) | 26 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) |
26 | static ot_vector accesslist; | 27 | static ot_vector accesslist; |
@@ -28,7 +29,8 @@ static ot_vector accesslist; | |||
28 | #endif | 29 | #endif |
29 | 30 | ||
30 | static size_t changeset_size = 0; | 31 | static size_t changeset_size = 0; |
31 | static time_t last_clean_time = 0; | 32 | |
33 | static 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. | 132 | static 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 | */ | ||
134 | static 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 | ||
156 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) { | 148 | ot_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 | */ |
247 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) { | 250 | size_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 ) | |||
316 | size_t return_fullscrape_for_tracker( char **reply ) { | 315 | size_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 */ |
391 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | 385 | size_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 */ |
414 | size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { | 408 | size_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 */ |
442 | static void release_changeset( void ) { | 435 | static 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 |
554 | void clean_all_torrents( void ) { | 548 | */ |
555 | int i, k; | 549 | static 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 ); | 603 | void 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 | ||
633 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; | 631 | typedef 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 | ||
829 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { | 821 | size_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 | ||
859 | exit_loop: | 850 | exit_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 | } |