diff options
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 97 |
1 files changed, 76 insertions, 21 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 |