diff options
| -rw-r--r-- | trackerlogic.c | 97 | ||||
| -rw-r--r-- | trackerlogic.h | 16 |
2 files changed, 80 insertions, 33 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index 134c504..80fc23e 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
| @@ -18,8 +18,13 @@ | |||
| 18 | #include <errno.h> | 18 | #include <errno.h> |
| 19 | #include "scan.h" | 19 | #include "scan.h" |
| 20 | #include "byte.h" | 20 | #include "byte.h" |
| 21 | #include "mutex.h" | ||
| 21 | 22 | ||
| 22 | /* GLOBAL VARIABLES */ | 23 | /* GLOBAL VARIABLES */ |
| 24 | |||
| 25 | /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs | ||
| 26 | Sort key is, of course, its hash */ | ||
| 27 | #define OT_BUCKET_COUNT 1024 | ||
| 23 | static ot_vector all_torrents[OT_BUCKET_COUNT]; | 28 | static ot_vector all_torrents[OT_BUCKET_COUNT]; |
| 24 | static ot_time all_torrents_clean[OT_BUCKET_COUNT]; | 29 | static ot_time all_torrents_clean[OT_BUCKET_COUNT]; |
| 25 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) | 30 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) |
| @@ -29,6 +34,28 @@ static ot_vector accesslist; | |||
| 29 | 34 | ||
| 30 | static int clean_single_torrent( ot_torrent *torrent ); | 35 | static int clean_single_torrent( ot_torrent *torrent ); |
| 31 | 36 | ||
| 37 | /* these functions protect our buckets from other threads that | ||
| 38 | try to commit announces or clean up */ | ||
| 39 | static ot_vector *lock_bucket_by_hash( ot_hash *hash ) { | ||
| 40 | unsigned char *local_hash = hash[0]; | ||
| 41 | int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ); | ||
| 42 | |||
| 43 | /* Can block */ | ||
| 44 | mutex_bucket_lock( bucket ); | ||
| 45 | |||
| 46 | return all_torrents + bucket; | ||
| 47 | } | ||
| 48 | |||
| 49 | static void *unlock_bucket_by_hash( ot_hash *hash ) { | ||
| 50 | unsigned char *local_hash = hash[0]; | ||
| 51 | int bucket = ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ); | ||
| 52 | mutex_bucket_unlock( bucket ); | ||
| 53 | |||
| 54 | /* To make caller's code look better, allow | ||
| 55 | return unlock_bucket_by_hash() */ | ||
| 56 | return NULL; | ||
| 57 | } | ||
| 58 | |||
| 32 | /* Converter function from memory to human readable hex strings | 59 | /* Converter function from memory to human readable hex strings |
| 33 | - definitely not thread safe!!! | 60 | - definitely not thread safe!!! |
| 34 | */ | 61 | */ |
| @@ -149,7 +176,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 149 | int exactmatch; | 176 | int exactmatch; |
| 150 | ot_torrent *torrent; | 177 | ot_torrent *torrent; |
| 151 | ot_peer *peer_dest; | 178 | ot_peer *peer_dest; |
| 152 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ), *peer_pool; | 179 | ot_vector *torrents_list = lock_bucket_by_hash( hash ), *peer_pool; |
| 153 | int base_pool = 0; | 180 | int base_pool = 0; |
| 154 | 181 | ||
| 155 | #ifdef WANT_ACCESS_CONTROL | 182 | #ifdef WANT_ACCESS_CONTROL |
| @@ -160,11 +187,12 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 160 | #endif | 187 | #endif |
| 161 | 188 | ||
| 162 | if( exactmatch ) | 189 | if( exactmatch ) |
| 163 | return NULL; | 190 | return unlock_bucket_by_hash( hash ); |
| 164 | #endif | 191 | #endif |
| 165 | 192 | ||
| 166 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 193 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 167 | if( !torrent ) return NULL; | 194 | if( !torrent ) |
| 195 | return unlock_bucket_by_hash( hash ); | ||
| 168 | 196 | ||
| 169 | if( !exactmatch ) { | 197 | if( !exactmatch ) { |
| 170 | /* Create a new torrent entry, then */ | 198 | /* Create a new torrent entry, then */ |
| @@ -172,7 +200,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 172 | 200 | ||
| 173 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 201 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { |
| 174 | vector_remove_torrent( torrents_list, torrent ); | 202 | vector_remove_torrent( torrents_list, torrent ); |
| 175 | return NULL; | 203 | return unlock_bucket_by_hash( hash ); |
| 176 | } | 204 | } |
| 177 | 205 | ||
| 178 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 206 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); |
| @@ -189,8 +217,10 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 189 | /* Check, whether peer already is in current pool, do nothing if so */ | 217 | /* Check, whether peer already is in current pool, do nothing if so */ |
| 190 | peer_pool = &torrent->peer_list->peers[0]; | 218 | peer_pool = &torrent->peer_list->peers[0]; |
| 191 | binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); | 219 | binary_search( peer, peer_pool->data, peer_pool->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); |
| 192 | if( exactmatch ) | 220 | if( exactmatch ) { |
| 221 | unlock_bucket_by_hash( hash ); | ||
| 193 | return torrent; | 222 | return torrent; |
| 223 | } | ||
| 194 | base_pool = 1; | 224 | base_pool = 1; |
| 195 | } | 225 | } |
| 196 | #endif | 226 | #endif |
| @@ -220,6 +250,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 220 | torrent->peer_list->seed_count--; | 250 | torrent->peer_list->seed_count--; |
| 221 | case 1: default: | 251 | case 1: default: |
| 222 | torrent->peer_list->peer_count--; | 252 | torrent->peer_list->peer_count--; |
| 253 | unlock_bucket_by_hash( hash ); | ||
| 223 | return torrent; | 254 | return torrent; |
| 224 | } | 255 | } |
| 225 | } | 256 | } |
| @@ -240,6 +271,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 240 | memmove( peer_dest, peer, sizeof( ot_peer ) ); | 271 | memmove( peer_dest, peer, sizeof( ot_peer ) ); |
| 241 | } | 272 | } |
| 242 | 273 | ||
| 274 | unlock_bucket_by_hash( hash ); | ||
| 243 | return torrent; | 275 | return torrent; |
| 244 | } | 276 | } |
| 245 | 277 | ||
| @@ -249,11 +281,19 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC | |||
| 249 | * RANDOM may return huge values | 281 | * RANDOM may return huge values |
| 250 | * does not yet check not to return self | 282 | * does not yet check not to return self |
| 251 | */ | 283 | */ |
| 252 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) { | 284 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ) { |
| 253 | char *r = reply; | 285 | char *r = reply; |
| 286 | int exactmatch; | ||
| 287 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); | ||
| 288 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
| 254 | ot_peerlist *peer_list = torrent->peer_list; | 289 | ot_peerlist *peer_list = torrent->peer_list; |
| 255 | size_t index; | 290 | size_t index; |
| 256 | 291 | ||
| 292 | if( !torrent ) { | ||
| 293 | unlock_bucket_by_hash( hash ); | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 257 | if( peer_list->peer_count < amount ) | 297 | if( peer_list->peer_count < amount ) |
| 258 | amount = peer_list->peer_count; | 298 | amount = peer_list->peer_count; |
| 259 | 299 | ||
| @@ -300,6 +340,7 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply | |||
| 300 | if( is_tcp ) | 340 | if( is_tcp ) |
| 301 | *r++ = 'e'; | 341 | *r++ = 'e'; |
| 302 | 342 | ||
| 343 | unlock_bucket_by_hash( hash ); | ||
| 303 | return r - reply; | 344 | return r - reply; |
| 304 | } | 345 | } |
| 305 | 346 | ||
| @@ -385,8 +426,8 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
| 385 | 426 | ||
| 386 | /* Fetches scrape info for a specific torrent */ | 427 | /* Fetches scrape info for a specific torrent */ |
| 387 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | 428 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { |
| 388 | int exactmatch ; | 429 | int exactmatch; |
| 389 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ); | 430 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); |
| 390 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 431 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 391 | 432 | ||
| 392 | if( !exactmatch ) { | 433 | if( !exactmatch ) { |
| @@ -403,6 +444,7 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
| 403 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); | 444 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); |
| 404 | } | 445 | } |
| 405 | } | 446 | } |
| 447 | unlock_bucket_by_hash( hash ); | ||
| 406 | return 12; | 448 | return 12; |
| 407 | } | 449 | } |
| 408 | 450 | ||
| @@ -415,17 +457,19 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl | |||
| 415 | 457 | ||
| 416 | for( i=0; i<amount; ++i ) { | 458 | for( i=0; i<amount; ++i ) { |
| 417 | ot_hash *hash = hash_list + i; | 459 | ot_hash *hash = hash_list + i; |
| 418 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ); | 460 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); |
| 419 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 461 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 420 | 462 | ||
| 421 | if( !exactmatch ) continue; | 463 | if( exactmatch ) { |
| 422 | if( clean_single_torrent( torrent ) ) { | 464 | if( clean_single_torrent( torrent ) ) { |
| 423 | vector_remove_torrent( torrents_list, torrent ); | 465 | vector_remove_torrent( torrents_list, torrent ); |
| 424 | } else { | 466 | } else { |
| 425 | memmove( r, "20:", 3 ); memmove( r+3, hash, 20 ); | 467 | memmove( r, "20:", 3 ); memmove( r+3, hash, 20 ); |
| 426 | r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", | 468 | r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", |
| 427 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23; | 469 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23; |
| 470 | } | ||
| 428 | } | 471 | } |
| 472 | unlock_bucket_by_hash( hash ); | ||
| 429 | } | 473 | } |
| 430 | 474 | ||
| 431 | *r++ = 'e'; *r++ = 'e'; | 475 | *r++ = 'e'; *r++ = 'e'; |
| @@ -806,11 +850,13 @@ size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thres | |||
| 806 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { | 850 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { |
| 807 | int exactmatch; | 851 | int exactmatch; |
| 808 | size_t index; | 852 | size_t index; |
| 809 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ); | 853 | ot_vector *torrents_list = lock_bucket_by_hash( hash ); |
| 810 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 854 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 811 | ot_peerlist *peer_list; | 855 | ot_peerlist *peer_list; |
| 812 | 856 | ||
| 813 | if( !exactmatch ) { | 857 | if( !exactmatch ) { |
| 858 | unlock_bucket_by_hash( hash ); | ||
| 859 | |||
| 814 | if( is_tcp ) | 860 | if( is_tcp ) |
| 815 | return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 861 | return sprintf( reply, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
| 816 | 862 | ||
| @@ -834,17 +880,22 @@ size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int | |||
| 834 | 880 | ||
| 835 | exit_loop: | 881 | exit_loop: |
| 836 | 882 | ||
| 837 | if( is_tcp ) | 883 | if( is_tcp ) { |
| 838 | 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 ); | 884 | size_t reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
| 885 | unlock_bucket_by_hash( hash ); | ||
| 886 | return reply_size; | ||
| 887 | } | ||
| 839 | 888 | ||
| 840 | /* else { Handle UDP reply */ | 889 | /* else { Handle UDP reply */ |
| 841 | ((ot_dword*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 890 | ((ot_dword*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
| 842 | ((ot_dword*)reply)[3] = peer_list->peer_count - peer_list->seed_count; | 891 | ((ot_dword*)reply)[3] = peer_list->peer_count - peer_list->seed_count; |
| 843 | ((ot_dword*)reply)[4] = peer_list->seed_count; | 892 | ((ot_dword*)reply)[4] = peer_list->seed_count; |
| 893 | |||
| 894 | unlock_bucket_by_hash( hash ); | ||
| 844 | return (size_t)20; | 895 | return (size_t)20; |
| 845 | } | 896 | } |
| 846 | 897 | ||
| 847 | int init_logic( const char * const serverdir ) { | 898 | int trackerlogic_init( const char * const serverdir ) { |
| 848 | if( serverdir && chdir( serverdir ) ) { | 899 | if( serverdir && chdir( serverdir ) ) { |
| 849 | fprintf( stderr, "Could not chdir() to %s\n", serverdir ); | 900 | fprintf( stderr, "Could not chdir() to %s\n", serverdir ); |
| 850 | return -1; | 901 | return -1; |
| @@ -855,10 +906,12 @@ int init_logic( const char * const serverdir ) { | |||
| 855 | /* Initialize control structures */ | 906 | /* Initialize control structures */ |
| 856 | byte_zero( all_torrents, sizeof( all_torrents ) ); | 907 | byte_zero( all_torrents, sizeof( all_torrents ) ); |
| 857 | 908 | ||
| 909 | mutex_init( ); | ||
| 910 | |||
| 858 | return 0; | 911 | return 0; |
| 859 | } | 912 | } |
| 860 | 913 | ||
| 861 | void deinit_logic( void ) { | 914 | void trackerlogic_deinit( void ) { |
| 862 | int i; | 915 | int i; |
| 863 | size_t j; | 916 | size_t j; |
| 864 | 917 | ||
| @@ -873,6 +926,8 @@ void deinit_logic( void ) { | |||
| 873 | } | 926 | } |
| 874 | byte_zero( all_torrents, sizeof (all_torrents)); | 927 | byte_zero( all_torrents, sizeof (all_torrents)); |
| 875 | byte_zero( all_torrents_clean, sizeof (all_torrents_clean)); | 928 | byte_zero( all_torrents_clean, sizeof (all_torrents_clean)); |
| 929 | |||
| 930 | mutex_deinit( ); | ||
| 876 | } | 931 | } |
| 877 | 932 | ||
| 878 | #ifdef WANT_ACCESS_CONTROL | 933 | #ifdef WANT_ACCESS_CONTROL |
diff --git a/trackerlogic.h b/trackerlogic.h index 67b14e1..86737ab 100644 --- a/trackerlogic.h +++ b/trackerlogic.h | |||
| @@ -46,14 +46,6 @@ typedef struct { | |||
| 46 | #define OT_ADMINIP_MAX 64 | 46 | #define OT_ADMINIP_MAX 64 |
| 47 | #define OT_MAX_THREADS 16 | 47 | #define OT_MAX_THREADS 16 |
| 48 | 48 | ||
| 49 | /* We maintain a list of 4096 pointers to sorted list of ot_torrent structs | ||
| 50 | Sort key is, of course, its hash */ | ||
| 51 | #define OT_BUCKET_COUNT 1024 | ||
| 52 | static inline ot_vector *hash_to_bucket( ot_vector *vectors, ot_hash *hash ) { | ||
| 53 | unsigned char *local_hash = hash[0]; | ||
| 54 | return vectors + ( ( local_hash[0] << 2 ) | ( local_hash[1] >> 6 ) ); | ||
| 55 | } | ||
| 56 | |||
| 57 | /* This list points to 9 pools of peers each grouped in five-minute-intervals | 49 | /* This list points to 9 pools of peers each grouped in five-minute-intervals |
| 58 | thus achieving a timeout of 2700s or 45 minutes | 50 | thus achieving a timeout of 2700s or 45 minutes |
| 59 | These pools are sorted by its binary content */ | 51 | These pools are sorted by its binary content */ |
| @@ -105,14 +97,14 @@ typedef struct { | |||
| 105 | #define WANT_TRACKER_SYNC_PARAM( param ) | 97 | #define WANT_TRACKER_SYNC_PARAM( param ) |
| 106 | #endif | 98 | #endif |
| 107 | 99 | ||
| 108 | int init_logic( const char * const serverdir ); | 100 | int trackerlogic_init( const char * const serverdir ); |
| 109 | void deinit_logic( void ); | 101 | void trackerlogic_deinit( void ); |
| 110 | 102 | ||
| 111 | enum { STATS_MRTG, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, STATS_SLASH24S, STATS_SLASH24S_OLD, SYNC_IN, SYNC_OUT, STATS_FULLSCRAPE }; | 103 | enum { STATS_CONNS, STATS_PEERS, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, STATS_SLASH24S, SYNC_IN, SYNC_OUT, STATS_FULLSCRAPE }; |
| 112 | 104 | ||
| 113 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ); | 105 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_TRACKER_SYNC_PARAM( int from_changeset ) ); |
| 114 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ); | 106 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ); |
| 115 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ); | 107 | size_t return_peers_for_torrent( ot_hash *hash, size_t amount, char *reply, int is_tcp ); |
| 116 | size_t return_fullscrape_for_tracker( char **reply ); | 108 | size_t return_fullscrape_for_tracker( char **reply ); |
| 117 | size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); | 109 | size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); |
| 118 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); | 110 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ); |
