diff options
Diffstat (limited to 'trackerlogic.c')
| -rw-r--r-- | trackerlogic.c | 89 |
1 files changed, 44 insertions, 45 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index 34a12e7..38be9f7 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
| @@ -25,6 +25,9 @@ | |||
| 25 | #include "ot_fullscrape.h" | 25 | #include "ot_fullscrape.h" |
| 26 | #include "ot_livesync.h" | 26 | #include "ot_livesync.h" |
| 27 | 27 | ||
| 28 | /* Forward declaration */ | ||
| 29 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ); | ||
| 30 | |||
| 28 | void free_peerlist( ot_peerlist *peer_list ) { | 31 | void free_peerlist( ot_peerlist *peer_list ) { |
| 29 | if( peer_list->peers.data ) { | 32 | if( peer_list->peers.data ) { |
| 30 | if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { | 33 | if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { |
| @@ -43,34 +46,36 @@ extern size_t g_this_peerid_len; | |||
| 43 | extern char *g_this_peerid_data; | 46 | extern char *g_this_peerid_data; |
| 44 | #endif | 47 | #endif |
| 45 | 48 | ||
| 46 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( int from_sync ) ) { | 49 | size_t add_peer_to_torrent_and_return_peers( ot_hash *hash, ot_peer *peer, PROTO_FLAG proto, size_t amount, char * reply ) { |
| 47 | int exactmatch; | 50 | int exactmatch, delta_torrentcount = 0; |
| 51 | size_t reply_size; | ||
| 48 | ot_torrent *torrent; | 52 | ot_torrent *torrent; |
| 49 | ot_peer *peer_dest; | 53 | ot_peer *peer_dest; |
| 50 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); | 54 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); |
| 51 | 55 | ||
| 52 | if( !accesslist_hashisvalid( hash ) ) { | 56 | if( !accesslist_hashisvalid( hash ) ) { |
| 53 | mutex_bucket_unlock_by_hash( hash ); | 57 | mutex_bucket_unlock_by_hash( hash, 0 ); |
| 54 | return NULL; | 58 | return 0; |
| 55 | } | 59 | } |
| 56 | 60 | ||
| 57 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 61 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 58 | if( !torrent ) { | 62 | if( !torrent ) { |
| 59 | mutex_bucket_unlock_by_hash( hash ); | 63 | mutex_bucket_unlock_by_hash( hash, 0 ); |
| 60 | return NULL; | 64 | return 0; |
| 61 | } | 65 | } |
| 62 | 66 | ||
| 63 | if( !exactmatch ) { | 67 | if( !exactmatch ) { |
| 64 | /* Create a new torrent entry, then */ | 68 | /* Create a new torrent entry, then */ |
| 65 | int i; for(i=0;i<20;i+=4) WRITE32(&torrent->hash,i,READ32(hash,i)); | 69 | int i; for(i=0;i<20;i+=4) WRITE32(&torrent->hash,i,READ32(hash,i)); |
| 66 | 70 | ||
| 67 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 71 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { |
| 68 | vector_remove_torrent( torrents_list, torrent ); | 72 | vector_remove_torrent( torrents_list, torrent ); |
| 69 | mutex_bucket_unlock_by_hash( hash ); | 73 | mutex_bucket_unlock_by_hash( hash, 0 ); |
| 70 | return NULL; | 74 | return 0; |
| 71 | } | 75 | } |
| 72 | 76 | ||
| 73 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 77 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); |
| 78 | delta_torrentcount = 1; | ||
| 74 | } else | 79 | } else |
| 75 | clean_single_torrent( torrent ); | 80 | clean_single_torrent( torrent ); |
| 76 | 81 | ||
| @@ -79,8 +84,8 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( | |||
| 79 | /* Check for peer in torrent */ | 84 | /* Check for peer in torrent */ |
| 80 | peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), peer, &exactmatch ); | 85 | peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), peer, &exactmatch ); |
| 81 | if( !peer_dest ) { | 86 | if( !peer_dest ) { |
| 82 | mutex_bucket_unlock_by_hash( hash ); | 87 | mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); |
| 83 | return NULL; | 88 | return 0; |
| 84 | } | 89 | } |
| 85 | 90 | ||
| 86 | /* Tell peer that it's fresh */ | 91 | /* Tell peer that it's fresh */ |
| @@ -94,7 +99,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( | |||
| 94 | if( !exactmatch ) { | 99 | if( !exactmatch ) { |
| 95 | 100 | ||
| 96 | #ifdef WANT_SYNC_LIVE | 101 | #ifdef WANT_SYNC_LIVE |
| 97 | if( !from_sync ) | 102 | if( proto == FLAG_MCA ) |
| 98 | livesync_tell( hash, peer ); | 103 | livesync_tell( hash, peer ); |
| 99 | else | 104 | else |
| 100 | OT_PEERFLAG( peer ) |= PEER_FLAG_FROM_SYNC; | 105 | OT_PEERFLAG( peer ) |= PEER_FLAG_FROM_SYNC; |
| @@ -118,17 +123,17 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( | |||
| 118 | printf( " %d.%d.%d.%d:%d\t%d %02X %s\n", _ip[0], _ip[1], _ip[2], _ip[3], OT_PEERTIME( peer_dest ), *(uint16_t*)( ((char*)peer_dest)+4 ), OT_PEERFLAG(peer_dest), g_this_peerid_data ? g_this_peerid_data : "-" ); | 123 | printf( " %d.%d.%d.%d:%d\t%d %02X %s\n", _ip[0], _ip[1], _ip[2], _ip[3], OT_PEERTIME( peer_dest ), *(uint16_t*)( ((char*)peer_dest)+4 ), OT_PEERFLAG(peer_dest), g_this_peerid_data ? g_this_peerid_data : "-" ); |
| 119 | } | 124 | } |
| 120 | #endif | 125 | #endif |
| 121 | 126 | ||
| 122 | #ifdef WANT_SYNC_LIVE | 127 | #ifdef WANT_SYNC_LIVE |
| 123 | /* Won't live sync peers that come back too fast. Only exception: | 128 | /* Won't live sync peers that come back too fast. Only exception: |
| 124 | fresh "completed" reports */ | 129 | fresh "completed" reports */ |
| 125 | if( !from_sync ) { | 130 | if( proto != FLAG_MCA ) { |
| 126 | if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || | 131 | if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || |
| 127 | ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(peer) & PEER_FLAG_COMPLETED ) ) ) | 132 | ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(peer) & PEER_FLAG_COMPLETED ) ) ) |
| 128 | livesync_tell( hash, peer ); | 133 | livesync_tell( hash, peer ); |
| 129 | } | 134 | } |
| 130 | #endif | 135 | #endif |
| 131 | 136 | ||
| 132 | if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) ) | 137 | if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) ) |
| 133 | torrent->peer_list->seed_count--; | 138 | torrent->peer_list->seed_count--; |
| 134 | if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) ) | 139 | if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) ) |
| @@ -141,14 +146,15 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer WANT_SYNC_PARAM( | |||
| 141 | 146 | ||
| 142 | *(uint64_t*)(peer_dest) = *(uint64_t*)(peer); | 147 | *(uint64_t*)(peer_dest) = *(uint64_t*)(peer); |
| 143 | #ifdef WANT_SYNC | 148 | #ifdef WANT_SYNC |
| 144 | /* In order to avoid an unlock/lock between add_peers and return_peers, | 149 | if( proto == FLAG_MCA ) { |
| 145 | we only unlock the bucket if return_peers won't do the job: either | 150 | mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); |
| 146 | if we return NULL or if no reply is expected, i.e. when called | 151 | return 0; |
| 147 | from livesync code. */ | 152 | } |
| 148 | if( from_sync ) | ||
| 149 | mutex_bucket_unlock_by_hash( hash ); | ||
| 150 | #endif | 153 | #endif |
| 151 | return torrent; | 154 | |
| 155 | reply_size = return_peers_for_torrent( torrent, amount, reply, proto ); | ||
| 156 | mutex_bucket_unlock_by_hash( &torrent->hash, delta_torrentcount ); | ||
| 157 | return reply_size; | ||
| 152 | } | 158 | } |
| 153 | 159 | ||
| 154 | static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) { | 160 | static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) { |
| @@ -186,7 +192,7 @@ static size_t return_peers_selection( ot_peerlist *peer_list, size_t amount, cha | |||
| 186 | num_buckets = bucket_list->size; | 192 | num_buckets = bucket_list->size; |
| 187 | bucket_list = (ot_vector *)bucket_list->data; | 193 | bucket_list = (ot_vector *)bucket_list->data; |
| 188 | } | 194 | } |
| 189 | 195 | ||
| 190 | /* Make fixpoint arithmetic as exact as possible */ | 196 | /* Make fixpoint arithmetic as exact as possible */ |
| 191 | #define MAXPRECBIT (1<<(8*sizeof(int)-3)) | 197 | #define MAXPRECBIT (1<<(8*sizeof(int)-3)) |
| 192 | while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; } | 198 | while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; } |
| @@ -220,9 +226,6 @@ static size_t return_peers_selection( ot_peerlist *peer_list, size_t amount, cha | |||
| 220 | /* Compiles a list of random peers for a torrent | 226 | /* Compiles a list of random peers for a torrent |
| 221 | * reply must have enough space to hold 92+6*amount bytes | 227 | * reply must have enough space to hold 92+6*amount bytes |
| 222 | * does not yet check not to return self | 228 | * does not yet check not to return self |
| 223 | * the bucket, torrent resides in has been locked by the | ||
| 224 | add_peer call, the ot_torrent * was gathered from, so we | ||
| 225 | have to unlock it here. | ||
| 226 | */ | 229 | */ |
| 227 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { | 230 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { |
| 228 | ot_peerlist *peer_list = torrent->peer_list; | 231 | ot_peerlist *peer_list = torrent->peer_list; |
| @@ -230,7 +233,7 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply | |||
| 230 | 233 | ||
| 231 | if( amount > peer_list->peer_count ) | 234 | if( amount > peer_list->peer_count ) |
| 232 | amount = peer_list->peer_count; | 235 | amount = peer_list->peer_count; |
| 233 | 236 | ||
| 234 | if( proto == FLAG_TCP ) { | 237 | if( proto == FLAG_TCP ) { |
| 235 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; | 238 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; |
| 236 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, 6*amount ); | 239 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, 6*amount ); |
| @@ -251,13 +254,12 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply | |||
| 251 | if( proto == FLAG_TCP ) | 254 | if( proto == FLAG_TCP ) |
| 252 | *r++ = 'e'; | 255 | *r++ = 'e'; |
| 253 | 256 | ||
| 254 | mutex_bucket_unlock_by_hash( &torrent->hash ); | ||
| 255 | return r - reply; | 257 | return r - reply; |
| 256 | } | 258 | } |
| 257 | 259 | ||
| 258 | /* Fetches scrape info for a specific torrent */ | 260 | /* Fetches scrape info for a specific torrent */ |
| 259 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | 261 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { |
| 260 | int exactmatch; | 262 | int exactmatch, delta_torrentcount = 0; |
| 261 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); | 263 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); |
| 262 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 264 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 263 | 265 | ||
| @@ -269,20 +271,22 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
| 269 | if( clean_single_torrent( torrent ) ) { | 271 | if( clean_single_torrent( torrent ) ) { |
| 270 | vector_remove_torrent( torrents_list, torrent ); | 272 | vector_remove_torrent( torrents_list, torrent ); |
| 271 | memset( reply, 0, 12); | 273 | memset( reply, 0, 12); |
| 274 | delta_torrentcount = -1; | ||
| 272 | } else { | 275 | } else { |
| 273 | r[0] = htonl( torrent->peer_list->seed_count ); | 276 | r[0] = htonl( torrent->peer_list->seed_count ); |
| 274 | r[1] = htonl( torrent->peer_list->down_count ); | 277 | r[1] = htonl( torrent->peer_list->down_count ); |
| 275 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); | 278 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); |
| 276 | } | 279 | } |
| 277 | } | 280 | } |
| 278 | mutex_bucket_unlock_by_hash( hash ); | 281 | mutex_bucket_unlock_by_hash( hash, 0 ); |
| 279 | return 12; | 282 | return 12; |
| 280 | } | 283 | } |
| 281 | 284 | ||
| 282 | /* Fetches scrape info for a specific torrent */ | 285 | /* Fetches scrape info for a specific torrent */ |
| 283 | size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { | 286 | size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { |
| 284 | char *r = reply; | 287 | char *r = reply; |
| 285 | int exactmatch, i; | 288 | int exactmatch, i; |
| 289 | int delta_torrentcount = 0; | ||
| 286 | 290 | ||
| 287 | r += sprintf( r, "d5:filesd" ); | 291 | r += sprintf( r, "d5:filesd" ); |
| 288 | 292 | ||
| @@ -294,6 +298,7 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl | |||
| 294 | if( exactmatch ) { | 298 | if( exactmatch ) { |
| 295 | if( clean_single_torrent( torrent ) ) { | 299 | if( clean_single_torrent( torrent ) ) { |
| 296 | vector_remove_torrent( torrents_list, torrent ); | 300 | vector_remove_torrent( torrents_list, torrent ); |
| 301 | delta_torrentcount = -1; | ||
| 297 | } else { | 302 | } else { |
| 298 | int j; | 303 | int j; |
| 299 | *r++='2';*r++='0';*r++=':'; | 304 | *r++='2';*r++='0';*r++=':'; |
| @@ -302,7 +307,7 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl | |||
| 302 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ); | 307 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ); |
| 303 | } | 308 | } |
| 304 | } | 309 | } |
| 305 | mutex_bucket_unlock_by_hash( hash ); | 310 | mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); |
| 306 | } | 311 | } |
| 307 | 312 | ||
| 308 | *r++ = 'e'; *r++ = 'e'; | 313 | *r++ = 'e'; *r++ = 'e'; |
| @@ -337,7 +342,7 @@ size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROT | |||
| 337 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; | 342 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; |
| 338 | reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2 ); | 343 | reply_size = sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2 ); |
| 339 | } | 344 | } |
| 340 | 345 | ||
| 341 | /* Handle UDP reply */ | 346 | /* Handle UDP reply */ |
| 342 | if( proto == FLAG_UDP ) { | 347 | if( proto == FLAG_UDP ) { |
| 343 | ((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 348 | ((uint32_t*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
| @@ -346,7 +351,7 @@ size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, PROT | |||
| 346 | reply_size = 20; | 351 | reply_size = 20; |
| 347 | } | 352 | } |
| 348 | 353 | ||
| 349 | mutex_bucket_unlock_by_hash( hash ); | 354 | mutex_bucket_unlock_by_hash( hash, 0 ); |
| 350 | return reply_size; | 355 | return reply_size; |
| 351 | } | 356 | } |
| 352 | 357 | ||
| @@ -355,12 +360,7 @@ void exerr( char * message ) { | |||
| 355 | exit( 111 ); | 360 | exit( 111 ); |
| 356 | } | 361 | } |
| 357 | 362 | ||
| 358 | int trackerlogic_init( const char * const serverdir ) { | 363 | void trackerlogic_init( ) { |
| 359 | if( serverdir && chdir( serverdir ) ) { | ||
| 360 | fprintf( stderr, "Could not chdir() to %s, because %s\n", serverdir, strerror(errno) ); | ||
| 361 | return -1; | ||
| 362 | } | ||
| 363 | |||
| 364 | srandom( time(NULL) ); | 364 | srandom( time(NULL) ); |
| 365 | g_tracker_id = random(); | 365 | g_tracker_id = random(); |
| 366 | 366 | ||
| @@ -371,12 +371,10 @@ int trackerlogic_init( const char * const serverdir ) { | |||
| 371 | accesslist_init( ); | 371 | accesslist_init( ); |
| 372 | livesync_init( ); | 372 | livesync_init( ); |
| 373 | stats_init( ); | 373 | stats_init( ); |
| 374 | |||
| 375 | return 0; | ||
| 376 | } | 374 | } |
| 377 | 375 | ||
| 378 | void trackerlogic_deinit( void ) { | 376 | void trackerlogic_deinit( void ) { |
| 379 | int bucket; | 377 | int bucket, delta_torrentcount = 0; |
| 380 | size_t j; | 378 | size_t j; |
| 381 | 379 | ||
| 382 | /* Free all torrents... */ | 380 | /* Free all torrents... */ |
| @@ -386,10 +384,11 @@ void trackerlogic_deinit( void ) { | |||
| 386 | for( j=0; j<torrents_list->size; ++j ) { | 384 | for( j=0; j<torrents_list->size; ++j ) { |
| 387 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; | 385 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; |
| 388 | free_peerlist( torrent->peer_list ); | 386 | free_peerlist( torrent->peer_list ); |
| 387 | delta_torrentcount -= 1; | ||
| 389 | } | 388 | } |
| 390 | free( torrents_list->data ); | 389 | free( torrents_list->data ); |
| 391 | } | 390 | } |
| 392 | mutex_bucket_unlock( bucket ); | 391 | mutex_bucket_unlock( bucket, delta_torrentcount ); |
| 393 | } | 392 | } |
| 394 | 393 | ||
| 395 | /* Deinitialise background worker threads */ | 394 | /* Deinitialise background worker threads */ |
