diff options
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 213 |
1 files changed, 143 insertions, 70 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index c8576f6..d2d279e 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -25,6 +25,10 @@ | |||
25 | 25 | ||
26 | /* GLOBAL VARIABLES */ | 26 | /* GLOBAL VARIABLES */ |
27 | static ot_vector all_torrents[256]; | 27 | static ot_vector all_torrents[256]; |
28 | static ot_vector changeset; | ||
29 | size_t changeset_size = 0; | ||
30 | time_t last_clean_time = 0; | ||
31 | |||
28 | #ifdef WANT_CLOSED_TRACKER | 32 | #ifdef WANT_CLOSED_TRACKER |
29 | int g_closedtracker = 1; | 33 | int g_closedtracker = 1; |
30 | static ot_torrent* const OT_TORRENT_NOT_ON_WHITELIST = (ot_torrent*)1; | 34 | static ot_torrent* const OT_TORRENT_NOT_ON_WHITELIST = (ot_torrent*)1; |
@@ -158,33 +162,6 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { | |||
158 | return 1; | 162 | return 1; |
159 | } | 163 | } |
160 | 164 | ||
161 | /* This function deallocates all timedouted pools and shifts all other pools | ||
162 | it Returns 1 if torrent itself has not seen an announce for more than OT_TORRENT_TIMEOUT time units | ||
163 | 0 if torrent is not yet timed out | ||
164 | Note: We expect NOW as a parameter since calling time() may be expensive | ||
165 | */ | ||
166 | static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) { | ||
167 | int i, timedout = (int)( time_now - peer_list->base ); | ||
168 | |||
169 | if( !timedout ) return 0; | ||
170 | if( timedout > OT_POOLS_COUNT ) timedout = OT_POOLS_COUNT; | ||
171 | |||
172 | for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i ) | ||
173 | free( peer_list->peers[i].data); | ||
174 | |||
175 | memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * (OT_POOLS_COUNT-timedout) ); | ||
176 | byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); | ||
177 | |||
178 | memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) ); | ||
179 | byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout ); | ||
180 | |||
181 | if( timedout == OT_POOLS_COUNT ) | ||
182 | return time_now - peer_list->base > OT_TORRENT_TIMEOUT; | ||
183 | |||
184 | peer_list->base = time_now; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | 165 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { |
189 | int exactmatch; | 166 | int exactmatch; |
190 | ot_torrent *torrent; | 167 | ot_torrent *torrent; |
@@ -219,8 +196,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | |||
219 | 196 | ||
220 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 197 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); |
221 | torrent->peer_list->base = NOW; | 198 | torrent->peer_list->base = NOW; |
222 | } else | 199 | } |
223 | clean_peerlist( NOW, torrent->peer_list ); | ||
224 | 200 | ||
225 | /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ | 201 | /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ |
226 | if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) | 202 | if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) |
@@ -294,7 +270,9 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply | |||
294 | peer_count += torrent->peer_list->peers[index].size; | 270 | peer_count += torrent->peer_list->peers[index].size; |
295 | seed_count += torrent->peer_list->seed_count[index]; | 271 | seed_count += torrent->peer_list->seed_count[index]; |
296 | } | 272 | } |
297 | if( peer_count < amount ) amount = peer_count; | 273 | |
274 | if( peer_count < amount ) | ||
275 | amount = peer_count; | ||
298 | 276 | ||
299 | if( is_tcp ) | 277 | if( is_tcp ) |
300 | 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 ); | 278 | 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 ); |
@@ -348,10 +326,8 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
348 | int i, k; | 326 | int i, k; |
349 | char *r; | 327 | char *r; |
350 | 328 | ||
351 | for( i=0; i<256; ++i ) { | 329 | for( i=0; i<256; ++i ) |
352 | ot_vector *torrents_list = &all_torrents[i]; | 330 | torrent_count += all_torrents[i].size; |
353 | torrent_count += torrents_list->size; | ||
354 | } | ||
355 | 331 | ||
356 | if( !( r = *reply = malloc( 128*torrent_count ) ) ) return 0; | 332 | if( !( r = *reply = malloc( 128*torrent_count ) ) ) return 0; |
357 | 333 | ||
@@ -380,7 +356,6 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
380 | size_t torrent_count = 0, j; | 356 | size_t torrent_count = 0, j; |
381 | int i, k; | 357 | int i, k; |
382 | char *r; | 358 | char *r; |
383 | time_t time_now = NOW; | ||
384 | 359 | ||
385 | for( i=0; i<256; ++i ) { | 360 | for( i=0; i<256; ++i ) { |
386 | ot_vector *torrents_list = &all_torrents[i]; | 361 | ot_vector *torrents_list = &all_torrents[i]; |
@@ -398,7 +373,6 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
398 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 373 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
399 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | 374 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
400 | r += sprintf( r, "\n%s:\n", to_hex( (ot_byte*)hash ) ); | 375 | r += sprintf( r, "\n%s:\n", to_hex( (ot_byte*)hash ) ); |
401 | clean_peerlist( time_now, peer_list ); | ||
402 | for( k=0; k<OT_POOLS_COUNT; ++k ) | 376 | for( k=0; k<OT_POOLS_COUNT; ++k ) |
403 | r += sprintf( r, "\t%04X %04X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space ); | 377 | r += sprintf( r, "\t%04X %04X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space ); |
404 | } | 378 | } |
@@ -418,7 +392,6 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
418 | memset( reply, 0, 12); | 392 | memset( reply, 0, 12); |
419 | } else { | 393 | } else { |
420 | unsigned long *r = (unsigned long*) reply; | 394 | unsigned long *r = (unsigned long*) reply; |
421 | clean_peerlist( NOW, torrent->peer_list ); | ||
422 | 395 | ||
423 | for( i=0; i<OT_POOLS_COUNT; ++i ) { | 396 | for( i=0; i<OT_POOLS_COUNT; ++i ) { |
424 | peers += torrent->peer_list->peers[i].size; | 397 | peers += torrent->peer_list->peers[i].size; |
@@ -440,7 +413,6 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
440 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 413 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
441 | 414 | ||
442 | if( !exactmatch ) return sprintf( r, "d5:filesdee" ); | 415 | if( !exactmatch ) return sprintf( r, "d5:filesdee" ); |
443 | clean_peerlist( NOW, torrent->peer_list ); | ||
444 | 416 | ||
445 | for( i=0; i<OT_POOLS_COUNT; ++i ) { | 417 | for( i=0; i<OT_POOLS_COUNT; ++i ) { |
446 | peers += torrent->peer_list->peers[i].size; | 418 | peers += torrent->peer_list->peers[i].size; |
@@ -453,36 +425,145 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
453 | return r - reply; | 425 | return r - reply; |
454 | } | 426 | } |
455 | 427 | ||
456 | size_t return_sync_for_torrent( ot_hash *hash, char **reply ) { | 428 | /* Throw away old changeset */ |
457 | int exactmatch; | 429 | static void release_changeset( void ) { |
458 | size_t peers = 0; | 430 | ot_byte **changeset_ptrs = (ot_byte**)(changeset.data); |
459 | char *r; | 431 | int i; |
460 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | 432 | |
461 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 433 | for( i = 0; i < changeset.size; ++i ) |
434 | free( changeset_ptrs[i] ); | ||
435 | |||
436 | free( changeset_ptrs ); | ||
437 | byte_zero( &changeset, sizeof( changeset ) ); | ||
438 | |||
439 | changeset_size = 0; | ||
440 | } | ||
441 | |||
442 | static void add_pool_to_changeset( ot_hash *hash, ot_peer *peers, size_t peer_count ) { | ||
443 | ot_byte *pool_copy = (ot_byte *)malloc( sizeof( size_t ) + sizeof( ot_hash ) + sizeof( ot_peer ) * peer_count + 13 ); | ||
444 | size_t r = 0; | ||
445 | |||
446 | if( !pool_copy ) | ||
447 | return; | ||
448 | |||
449 | memmove( pool_copy + sizeof( size_t ), "20:", 3 ); | ||
450 | memmove( pool_copy + sizeof( size_t ) + 3, hash, sizeof( ot_hash ) ); | ||
451 | r = sizeof( size_t ) + 3 + sizeof( ot_hash ); | ||
452 | r += sprintf( (char*)pool_copy + r, "%zd:", sizeof( ot_peer ) * peer_count ); | ||
453 | memmove( pool_copy + r, peers, sizeof( ot_peer ) * peer_count ); | ||
454 | r += sizeof( ot_peer ) * peer_count; | ||
455 | |||
456 | /* Without the length field */ | ||
457 | *(size_t*)pool_copy = r - sizeof( size_t ); | ||
458 | |||
459 | if( changeset.size + 1 >= changeset.space ) { | ||
460 | size_t new_space = changeset.space ? OT_VECTOR_GROW_RATIO * changeset.space : OT_VECTOR_MIN_MEMBERS; | ||
461 | ot_byte *new_data = realloc( changeset.data, new_space * sizeof( ot_byte *) ); | ||
462 | |||
463 | if( !new_data ) | ||
464 | return free( pool_copy ); | ||
465 | |||
466 | changeset.data = new_data; | ||
467 | changeset.space = new_space; | ||
468 | } | ||
469 | |||
470 | ((ot_byte**)changeset.data)[changeset.size++] = pool_copy; | ||
471 | |||
472 | /* Without the length field */ | ||
473 | changeset_size += r - sizeof( size_t ); | ||
474 | } | ||
475 | |||
476 | /* Proposed output format | ||
477 | d4:syncd20:<info_hash>8*N:(xxxxyy)*Nee | ||
478 | */ | ||
479 | size_t return_changeset_for_tracker( char **reply ) { | ||
480 | size_t i, r = 8; | ||
481 | |||
482 | clean_all_torrents(); | ||
483 | |||
484 | *reply = malloc( 8 + changeset_size + 2 ); | ||
485 | if( !*reply ) | ||
486 | return 0; | ||
462 | 487 | ||
463 | if( exactmatch ) { | 488 | memmove( *reply, "d4:syncd", 8 ); |
464 | clean_peerlist( NOW, torrent->peer_list ); | 489 | for( i = 0; i < changeset.size; ++i ) { |
465 | peers = torrent->peer_list->peers[0].size; | 490 | ot_byte *data = ((ot_byte**)changeset.data)[i]; |
491 | memmove( *reply + r, data + sizeof( size_t ), *(size_t*)data ); | ||
492 | r += *(size_t*)data; | ||
466 | } | 493 | } |
467 | 494 | ||
468 | if( !( r = *reply = malloc( 10 + peers * sizeof( ot_peer ) ) ) ) return 0; | 495 | (*reply)[r++] = 'e'; |
496 | (*reply)[r++] = 'e'; | ||
497 | |||
498 | return r; | ||
499 | } | ||
500 | |||
501 | /* Clean up all torrents, remove timedout pools and | ||
502 | torrents, also prepare new changeset */ | ||
503 | void clean_all_torrents( void ) { | ||
504 | int i, j, k; | ||
505 | time_t time_now = NOW; | ||
506 | size_t peers_count; | ||
507 | |||
508 | if( time_now <= last_clean_time ) | ||
509 | return; | ||
510 | last_clean_time = time_now; | ||
511 | |||
512 | release_changeset(); | ||
469 | 513 | ||
470 | memmove( r, "d4:sync", 7 ); | 514 | for( i=0; i<256; ++i ) { |
471 | r += 7; | 515 | ot_vector *torrents_list = &all_torrents[i]; |
472 | r += sprintf( r, "%zd:", peers * sizeof( ot_peer ) ); | 516 | for( j=0; j<torrents_list->size; ++j ) { |
473 | if( peers ) { | 517 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
474 | memmove( r, torrent->peer_list->peers[0].data, peers * sizeof( ot_peer ) ); | 518 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
475 | r += peers * sizeof( ot_peer ); | 519 | |
520 | time_t timedout = (int)( time_now - peer_list->base ); | ||
521 | |||
522 | /* Torrent has idled out */ | ||
523 | if( timedout > OT_TORRENT_TIMEOUT ) { | ||
524 | vector_remove_torrent( torrents_list, hash ); | ||
525 | --j; | ||
526 | } | ||
527 | |||
528 | /* If nothing to be cleaned here, handle next torrent */ | ||
529 | if( timedout > OT_POOLS_COUNT ) | ||
530 | continue; | ||
531 | |||
532 | /* Release vectors that have timed out */ | ||
533 | for( k = OT_POOLS_COUNT - timedout; k < OT_POOLS_COUNT; ++k ) | ||
534 | free( peer_list->peers[k].data); | ||
535 | |||
536 | /* Shift vectors back by the amount of pools that were shifted out */ | ||
537 | memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) ); | ||
538 | byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); | ||
539 | |||
540 | /* Shift back seed counts as well */ | ||
541 | memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) ); | ||
542 | byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout ); | ||
543 | |||
544 | /* Save the block modified within last OT_POOLS_TIMEOUT */ | ||
545 | if( peer_list->peers[1].size ) | ||
546 | add_pool_to_changeset( hash, peer_list->peers[1].data, peer_list->peers[1].size ); | ||
547 | |||
548 | peers_count = 0; | ||
549 | for( k = 0; k < OT_POOLS_COUNT; ++k ) | ||
550 | peers_count += peer_list->peers[k].size; | ||
551 | |||
552 | if( peers_count ) { | ||
553 | peer_list->base = time_now; | ||
554 | } else { | ||
555 | /* When we got here, the last time that torrent | ||
556 | has been touched is OT_POOLS_COUNT units before */ | ||
557 | peer_list->base = time_now - OT_POOLS_COUNT; | ||
558 | } | ||
559 | } | ||
476 | } | 560 | } |
477 | *r++ = 'e'; | ||
478 | return r - *reply; | ||
479 | } | 561 | } |
480 | 562 | ||
481 | typedef struct { int val; ot_torrent * torrent; } ot_record; | 563 | typedef struct { int val; ot_torrent * torrent; } ot_record; |
482 | 564 | ||
483 | /* Fetches stats from tracker */ | 565 | /* Fetches stats from tracker */ |
484 | size_t return_stats_for_tracker( char *reply, int mode ) { | 566 | size_t return_stats_for_tracker( char *reply, int mode ) { |
485 | time_t time_now = NOW; | ||
486 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; | 567 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; |
487 | ot_record top5s[5], top5c[5]; | 568 | ot_record top5s[5], top5c[5]; |
488 | char *r = reply; | 569 | char *r = reply; |
@@ -498,12 +579,6 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
498 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 579 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
499 | size_t local_peers = 0, local_seeds = 0; | 580 | size_t local_peers = 0, local_seeds = 0; |
500 | 581 | ||
501 | if( clean_peerlist( time_now, peer_list ) ) { | ||
502 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | ||
503 | vector_remove_torrent( torrents_list, hash ); | ||
504 | --j; | ||
505 | continue; | ||
506 | } | ||
507 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 582 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
508 | local_peers += peer_list->peers[k].size; | 583 | local_peers += peer_list->peers[k].size; |
509 | local_seeds += peer_list->seed_count[k]; | 584 | local_seeds += peer_list->seed_count[k]; |
@@ -549,12 +624,6 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) { | |||
549 | 624 | ||
550 | if( !exactmatch ) return; | 625 | if( !exactmatch ) return; |
551 | 626 | ||
552 | /* Maybe this does the job */ | ||
553 | if( clean_peerlist( NOW, torrent->peer_list ) ) { | ||
554 | vector_remove_torrent( torrents_list, hash ); | ||
555 | return; | ||
556 | } | ||
557 | |||
558 | for( i=0; i<OT_POOLS_COUNT; ++i ) | 627 | for( i=0; i<OT_POOLS_COUNT; ++i ) |
559 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, i == 0 ) ) { | 628 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, i == 0 ) ) { |
560 | case 0: continue; | 629 | case 0: continue; |
@@ -572,7 +641,9 @@ int init_logic( const char * const serverdir ) { | |||
572 | srandom( time(NULL) ); | 641 | srandom( time(NULL) ); |
573 | 642 | ||
574 | /* Initialize control structures */ | 643 | /* Initialize control structures */ |
575 | byte_zero( all_torrents, sizeof (all_torrents) ); | 644 | byte_zero( all_torrents, sizeof( all_torrents ) ); |
645 | byte_zero( &changeset, sizeof( changeset ) ); | ||
646 | changeset_size = 0; | ||
576 | 647 | ||
577 | return 0; | 648 | return 0; |
578 | } | 649 | } |
@@ -591,4 +662,6 @@ void deinit_logic( void ) { | |||
591 | } | 662 | } |
592 | } | 663 | } |
593 | byte_zero( all_torrents, sizeof (all_torrents)); | 664 | byte_zero( all_torrents, sizeof (all_torrents)); |
665 | byte_zero( &changeset, sizeof( changeset ) ); | ||
666 | changeset_size = 0; | ||
594 | } | 667 | } |