@ -34,6 +34,11 @@ int g_check_blacklist = 1;
static ot_torrent * const OT_TORRENT_ON_BLACKLIST = ( ot_torrent * ) 2 ;
# endif
/* Converter function from memory to human readable hex strings
- definitely not thread safe ! ! !
*/
static char ths [ 2 + 2 * 20 ] = " - " ; static char * to_hex ( ot_byte * s ) { const char * m = " 0123456789ABCDEF " ; char * e = ths + 41 ; char * t = ths + 1 ; while ( t < e ) { * t + + = m [ * s > > 4 ] ; * t + + = m [ * s + + & 15 ] ; } * t = 0 ; return ths + 1 ; }
/* This function gives us a binary search that returns a pointer, even if
no exact match is found . In that case it sets exactmatch 0 and gives
calling functions the chance to insert data
@ -58,11 +63,13 @@ static void *binary_search( const void * const key, const void * base, const siz
return ( void * ) lookat ;
}
/* Converter function from memory to human readable hex strings
- definitely not thread safe ! ! !
/* This is the generic insert operation for our vector type.
It tries to locate the object at " key " with size " member_size " by comparing its first " compare_size " bytes with
those of objects in vector . Our special " binary_search " function does that and either returns the match or a
pointer to where the object is to be inserted . vector_find_or_insert makes space for the object and copies it ,
if it wasn ' t found in vector . Caller needs to check the passed " exactmatch " variable to see , whether an insert
took place . If resizing the vector failed , NULL is returned , else the pointer to the object in vector .
*/
char ths [ 2 + 2 * 20 ] = " - " ; char * to_hex ( ot_byte * s ) { char * m = " 0123456789ABCDEF " ; char * e = ths + 41 ; char * t = ths + 1 ; while ( t < e ) { * t + + = m [ * s > > 4 ] ; * t + + = m [ * s + + & 15 ] ; } * t = 0 ; return ths + 1 ; }
static void * vector_find_or_insert ( ot_vector * vector , void * key , size_t member_size , size_t compare_size , int * exactmatch ) {
ot_byte * match = binary_search ( key , vector - > data , vector - > size , member_size , compare_size , exactmatch ) ;
@ -84,8 +91,15 @@ static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_
return match ;
}
static int vector_remove_peer ( ot_vector * vector , ot_peer * peer ) {
int exactmatch ;
/* This is the non-generic delete from vector-operation specialized for peers in pools.
Set hysteresis = = 0 if you expect the vector not to ever grow again .
It returns 0 if no peer was found ( and thus not removed )
1 if a non - seeding peer was removed
2 if a seeding peer was removed
*/
static int vector_remove_peer ( ot_vector * vector , ot_peer * peer , int hysteresis ) {
int exactmatch ;
size_t shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO ;
ot_peer * end = ( ( ot_peer * ) vector - > data ) + vector - > size ;
ot_peer * match ;
@ -95,7 +109,7 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
if ( ! exactmatch ) return 0 ;
exactmatch = ( OT_FLAG ( match ) & PEER_FLAG_SEEDING ) ? 2 : 1 ;
memmove ( match , match + 1 , sizeof ( ot_peer ) * ( end - match - 1 ) ) ;
if ( ( - - vector - > size * OT_VECTOR_SHRINK_THRESH < vector - > space ) & & ( vector - > space > OT_VECTOR_MIN_MEMBERS ) ) {
if ( ( - - vector - > size * shrink_thresh < vector - > space ) & & ( vector - > space > OT_VECTOR_MIN_MEMBERS ) ) {
vector - > space / = OT_VECTOR_SHRINK_RATIO ;
vector - > data = realloc ( vector - > data , vector - > space * sizeof ( ot_peer ) ) ;
}
@ -117,14 +131,18 @@ static void free_peerlist( ot_peerlist *peer_list ) {
free ( peer_list ) ;
}
/* This is the non-generic delete from vector-operation specialized for torrents in buckets.
it returns 0 if the hash wasn ' t found in vector
1 if the torrent was removed from vector
*/
static int vector_remove_torrent ( ot_vector * vector , ot_hash * hash ) {
int exactmatch ;
ot_torrent * end = ( ( ot_torrent * ) vector - > data ) + vector - > size ;
ot_torrent * match ;
if ( ! vector - > size ) return 0 ;
match = binary_search ( hash , vector - > data , vector - > size , sizeof ( ot_torrent ) , OT_HASH_COMPARE_SIZE , & exactmatch ) ;
match = binary_search ( hash , vector - > data , vector - > size , sizeof ( ot_torrent ) , OT_HASH_COMPARE_SIZE , & exactmatch ) ;
if ( ! exactmatch ) return 0 ;
/* If this is being called after a unsuccessful malloc() for peer_list
@ -139,8 +157,11 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
return 1 ;
}
/* Returns 1, if torrent is gone, 0 otherwise
We expect NOW as a parameter since calling time ( ) may be expensive */
/* This function deallocates all timedouted pools and shifts all other pools
it Returns 1 if torrent itself has not seen an announce for more than OT_TORRENT_TIMEOUT time units
0 if torrent is not yet timed out
Note : We expect NOW as a parameter since calling time ( ) may be expensive
*/
static int clean_peerlist ( time_t time_now , ot_peerlist * peer_list ) {
int i , timedout = ( int ) ( time_now - peer_list - > base ) ;
@ -156,8 +177,11 @@ static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) {
memmove ( peer_list - > seed_count + timedout , peer_list - > seed_count , sizeof ( size_t ) * ( OT_POOLS_COUNT - timedout ) ) ;
byte_zero ( peer_list - > seed_count , sizeof ( size_t ) * timedout ) ;
peer_list - > base = NOW ;
return timedout = = OT_POOLS_COUNT ;
if ( timedout = = OT_POOLS_COUNT )
return time_now - peer_list - > base > OT_TORRENT_TIMEOUT ;
peer_list - > base = time_now ;
return 0 ;
}
ot_torrent * add_peer_to_torrent ( ot_hash * hash , ot_peer * peer ) {
@ -187,13 +211,12 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
/* Create a new torrent entry, then */
memmove ( & torrent - > hash , hash , sizeof ( ot_hash ) ) ;
torrent - > peer_list = malloc ( sizeof ( ot_peerlist ) ) ;
if ( ! torrent - > peer_list ) {
if ( ! ( torrent - > peer_list = malloc ( sizeof ( ot_peerlist ) ) ) ) {
vector_remove_torrent ( torrents_list , hash ) ;
return NULL ;
}
byte_zero ( torrent - > peer_list , sizeof ( ot_peerlist ) ) ;
byte_zero ( torrent - > peer_list , sizeof ( ot_peerlist ) ) ;
torrent - > peer_list - > base = NOW ;
} else
clean_peerlist ( NOW , torrent - > peer_list ) ;
@ -201,7 +224,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
peer_pool = & torrent - > peer_list - > peers [ 0 ] ;
peer_dest = vector_find_or_insert ( peer_pool , ( void * ) peer , sizeof ( ot_peer ) , OT_PEER_COMPARE_SIZE , & exactmatch ) ;
if ( OT_FLAG ( peer ) & PEER_FLAG_COMPLETED )
if ( OT_FLAG ( peer ) & PEER_FLAG_COMPLETED )
torrent - > peer_list - > downloaded + + ;
/* If we hadn't had a match in current pool, create peer there and
@ -213,7 +236,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
torrent - > peer_list - > seed_count [ 0 ] + + ;
for ( i = 1 ; i < OT_POOLS_COUNT ; + + i ) {
switch ( vector_remove_peer ( & torrent - > peer_list - > peers [ i ] , peer ) ) {
switch ( vector_remove_peer ( & torrent - > peer_list - > peers [ i ] , peer , 0 ) ) {
case 0 : continue ;
case 2 : torrent - > peer_list - > seed_count [ i ] - - ;
case 1 : default : return torrent ;
@ -231,7 +254,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
}
/* Compiles a list of random peers for a torrent
* reply must have enough space to hold 24 + 6 * amount bytes
* reply must have enough space to hold 9 2+ 6 * amount bytes
* Selector function can be anything , maybe test for seeds , etc .
* RANDOM may return huge values
* does not yet check not to return self
@ -349,7 +372,7 @@ size_t return_memstat_for_tracker( char **reply ) {
if ( ! ( r = * reply = malloc ( 256 * 32 + ( 43 + OT_POOLS_COUNT * 32 ) * torrent_count ) ) ) return 0 ;
for ( i = 0 ; i < 256 ; + + i )
r + = sprintf ( r , " %02X: %0 4X %04X\n " , i , ( ot_dword ) all_torrents [ i ] . size , ( ot_dword ) all_torrents [ i ] . space ) ;
r + = sprintf ( r , " %02X: %0 8X %08X\n " , i , ( unsigned int ) all_torrents [ i ] . size , ( unsigned int ) all_torrents [ i ] . space ) ;
for ( i = 0 ; i < 256 ; + + i ) {
ot_vector * torrents_list = & all_torrents [ i ] ;
@ -359,7 +382,7 @@ size_t return_memstat_for_tracker( char **reply ) {
r + = sprintf ( r , " \n %s: \n " , to_hex ( ( ot_byte * ) hash ) ) ;
clean_peerlist ( time_now , peer_list ) ;
for ( k = 0 ; k < OT_POOLS_COUNT ; + + k )
r + = sprintf ( r , " \t %04X %04X \n " , peer_list - > peers [ k ] . size , peer_list - > peers [ k ] . space ) ;
r + = sprintf ( r , " \t %04X %04X \n " , ( ( unsigned int ) peer_list - > peers [ k ] . size ) , ( unsigned int ) peer_list - > peers [ k ] . space ) ;
}
}
@ -432,7 +455,13 @@ size_t return_stats_for_tracker( char *reply, int mode ) {
for ( j = 0 ; j < torrents_list - > size ; + + j ) {
ot_peerlist * peer_list = ( ( ( ot_torrent * ) ( torrents_list - > data ) ) [ j ] ) . peer_list ;
size_t local_peers = 0 , local_seeds = 0 ;
clean_peerlist ( time_now , peer_list ) ;
if ( clean_peerlist ( time_now , peer_list ) ) {
ot_hash * hash = & ( ( ( ot_torrent * ) ( torrents_list - > data ) ) [ j ] ) . hash ;
vector_remove_torrent ( torrents_list - > data , hash ) ;
- - j ;
continue ;
}
for ( k = 0 ; k < OT_POOLS_COUNT ; + + k ) {
local_peers + = peer_list - > peers [ k ] . size ;
local_seeds + = peer_list - > seed_count [ k ] ;
@ -480,15 +509,12 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
/* Maybe this does the job */
if ( clean_peerlist ( NOW , torrent - > peer_list ) ) {
# ifdef WANT_CLOSED_TRACKER
if ( ! g_closedtracker )
# endif
vector_remove_torrent ( torrents_list , hash ) ;
return ;
}
for ( i = 0 ; i < OT_POOLS_COUNT ; + + i )
switch ( vector_remove_peer ( & torrent - > peer_list - > peers [ i ] , peer ) ) {
switch ( vector_remove_peer ( & torrent - > peer_list - > peers [ i ] , peer , i = = 0 ) ) {
case 0 : continue ;
case 2 : torrent - > peer_list - > seed_count [ i ] - - ;
case 1 : default : return ;