summaryrefslogtreecommitdiff
path: root/trackerlogic.c
diff options
context:
space:
mode:
Diffstat (limited to 'trackerlogic.c')
-rw-r--r--trackerlogic.c97
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
23static ot_vector all_torrents[OT_BUCKET_COUNT]; 28static ot_vector all_torrents[OT_BUCKET_COUNT];
24static ot_time all_torrents_clean[OT_BUCKET_COUNT]; 29static 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
30static int clean_single_torrent( ot_torrent *torrent ); 35static 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 */
39static 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
49static 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*/
252size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) { 284size_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 */
387size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { 428size_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
806size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { 850size_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
835exit_loop: 881exit_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
847int init_logic( const char * const serverdir ) { 898int 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
861void deinit_logic( void ) { 914void 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