diff options
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 78 |
1 files changed, 52 insertions, 26 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index acd89b6..d112abd 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -34,6 +34,11 @@ int g_check_blacklist = 1; | |||
34 | static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2; | 34 | static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2; |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | /* Converter function from memory to human readable hex strings | ||
38 | - definitely not thread safe!!! | ||
39 | */ | ||
40 | 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;} | ||
41 | |||
37 | /* This function gives us a binary search that returns a pointer, even if | 42 | /* This function gives us a binary search that returns a pointer, even if |
38 | no exact match is found. In that case it sets exactmatch 0 and gives | 43 | no exact match is found. In that case it sets exactmatch 0 and gives |
39 | calling functions the chance to insert data | 44 | calling functions the chance to insert data |
@@ -58,11 +63,13 @@ static void *binary_search( const void * const key, const void * base, const siz | |||
58 | return (void*)lookat; | 63 | return (void*)lookat; |
59 | } | 64 | } |
60 | 65 | ||
61 | /* Converter function from memory to human readable hex strings | 66 | /* This is the generic insert operation for our vector type. |
62 | - definitely not thread safe!!! | 67 | It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with |
68 | those of objects in vector. Our special "binary_search" function does that and either returns the match or a | ||
69 | pointer to where the object is to be inserted. vector_find_or_insert makes space for the object and copies it, | ||
70 | if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert | ||
71 | took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector. | ||
63 | */ | 72 | */ |
64 | 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;} | ||
65 | |||
66 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { | 73 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { |
67 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); | 74 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); |
68 | 75 | ||
@@ -83,9 +90,16 @@ static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_ | |||
83 | vector->size++; | 90 | vector->size++; |
84 | return match; | 91 | return match; |
85 | } | 92 | } |
86 | 93 | ||
87 | static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { | 94 | /* This is the non-generic delete from vector-operation specialized for peers in pools. |
88 | int exactmatch; | 95 | Set hysteresis == 0 if you expect the vector not to ever grow again. |
96 | It returns 0 if no peer was found (and thus not removed) | ||
97 | 1 if a non-seeding peer was removed | ||
98 | 2 if a seeding peer was removed | ||
99 | */ | ||
100 | static int vector_remove_peer( ot_vector *vector, ot_peer *peer, int hysteresis ) { | ||
101 | int exactmatch; | ||
102 | size_t shrink_thresh = hysteresis ? OT_VECTOR_SHRINK_THRESH : OT_VECTOR_SHRINK_RATIO; | ||
89 | ot_peer *end = ((ot_peer*)vector->data) + vector->size; | 103 | ot_peer *end = ((ot_peer*)vector->data) + vector->size; |
90 | ot_peer *match; | 104 | ot_peer *match; |
91 | 105 | ||
@@ -95,7 +109,7 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { | |||
95 | if( !exactmatch ) return 0; | 109 | if( !exactmatch ) return 0; |
96 | exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; | 110 | exactmatch = ( OT_FLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; |
97 | memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); | 111 | memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); |
98 | if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) { | 112 | if( ( --vector->size * shrink_thresh < vector->space ) && ( vector->space > OT_VECTOR_MIN_MEMBERS ) ) { |
99 | vector->space /= OT_VECTOR_SHRINK_RATIO; | 113 | vector->space /= OT_VECTOR_SHRINK_RATIO; |
100 | vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); | 114 | vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); |
101 | } | 115 | } |
@@ -117,14 +131,18 @@ static void free_peerlist( ot_peerlist *peer_list ) { | |||
117 | free( peer_list ); | 131 | free( peer_list ); |
118 | } | 132 | } |
119 | 133 | ||
134 | /* This is the non-generic delete from vector-operation specialized for torrents in buckets. | ||
135 | it returns 0 if the hash wasn't found in vector | ||
136 | 1 if the torrent was removed from vector | ||
137 | */ | ||
120 | static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { | 138 | static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { |
121 | int exactmatch; | 139 | int exactmatch; |
122 | ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; | 140 | ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; |
123 | ot_torrent *match; | 141 | ot_torrent *match; |
124 | 142 | ||
125 | if( !vector->size ) return 0; | 143 | if( !vector->size ) return 0; |
126 | match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
127 | 144 | ||
145 | match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
128 | if( !exactmatch ) return 0; | 146 | if( !exactmatch ) return 0; |
129 | 147 | ||
130 | /* If this is being called after a unsuccessful malloc() for peer_list | 148 | /* 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 ) { | |||
139 | return 1; | 157 | return 1; |
140 | } | 158 | } |
141 | 159 | ||
142 | /* Returns 1, if torrent is gone, 0 otherwise | 160 | /* This function deallocates all timedouted pools and shifts all other pools |
143 | We expect NOW as a parameter since calling time() may be expensive*/ | 161 | it Returns 1 if torrent itself has not seen an announce for more than OT_TORRENT_TIMEOUT time units |
162 | 0 if torrent is not yet timed out | ||
163 | Note: We expect NOW as a parameter since calling time() may be expensive | ||
164 | */ | ||
144 | static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) { | 165 | static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) { |
145 | int i, timedout = (int)( time_now - peer_list->base ); | 166 | int i, timedout = (int)( time_now - peer_list->base ); |
146 | 167 | ||
@@ -156,8 +177,11 @@ static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) { | |||
156 | memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) ); | 177 | memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) ); |
157 | byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout ); | 178 | byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout ); |
158 | 179 | ||
159 | peer_list->base = NOW; | 180 | if( timedout == OT_POOLS_COUNT ) |
160 | return timedout == OT_POOLS_COUNT; | 181 | return time_now - peer_list->base > OT_TORRENT_TIMEOUT; |
182 | |||
183 | peer_list->base = time_now; | ||
184 | return 0; | ||
161 | } | 185 | } |
162 | 186 | ||
163 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | 187 | 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 ) { | |||
187 | /* Create a new torrent entry, then */ | 211 | /* Create a new torrent entry, then */ |
188 | memmove( &torrent->hash, hash, sizeof( ot_hash ) ); | 212 | memmove( &torrent->hash, hash, sizeof( ot_hash ) ); |
189 | 213 | ||
190 | torrent->peer_list = malloc( sizeof (ot_peerlist) ); | 214 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { |
191 | if( !torrent->peer_list ) { | ||
192 | vector_remove_torrent( torrents_list, hash ); | 215 | vector_remove_torrent( torrents_list, hash ); |
193 | return NULL; | 216 | return NULL; |
194 | } | 217 | } |
195 | 218 | ||
196 | byte_zero( torrent->peer_list, sizeof( ot_peerlist )); | 219 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); |
197 | torrent->peer_list->base = NOW; | 220 | torrent->peer_list->base = NOW; |
198 | } else | 221 | } else |
199 | clean_peerlist( NOW, torrent->peer_list ); | 222 | clean_peerlist( NOW, torrent->peer_list ); |
@@ -201,7 +224,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | |||
201 | peer_pool = &torrent->peer_list->peers[0]; | 224 | peer_pool = &torrent->peer_list->peers[0]; |
202 | peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch ); | 225 | peer_dest = vector_find_or_insert( peer_pool, (void*)peer, sizeof( ot_peer ), OT_PEER_COMPARE_SIZE, &exactmatch ); |
203 | 226 | ||
204 | if( OT_FLAG(peer) & PEER_FLAG_COMPLETED ) | 227 | if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) |
205 | torrent->peer_list->downloaded++; | 228 | torrent->peer_list->downloaded++; |
206 | 229 | ||
207 | /* If we hadn't had a match in current pool, create peer there and | 230 | /* 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 ) { | |||
213 | torrent->peer_list->seed_count[0]++; | 236 | torrent->peer_list->seed_count[0]++; |
214 | 237 | ||
215 | for( i=1; i<OT_POOLS_COUNT; ++i ) { | 238 | for( i=1; i<OT_POOLS_COUNT; ++i ) { |
216 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer ) ) { | 239 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) { |
217 | case 0: continue; | 240 | case 0: continue; |
218 | case 2: torrent->peer_list->seed_count[i]--; | 241 | case 2: torrent->peer_list->seed_count[i]--; |
219 | case 1: default: return torrent; | 242 | case 1: default: return torrent; |
@@ -231,7 +254,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | |||
231 | } | 254 | } |
232 | 255 | ||
233 | /* Compiles a list of random peers for a torrent | 256 | /* Compiles a list of random peers for a torrent |
234 | * reply must have enough space to hold 24+6*amount bytes | 257 | * reply must have enough space to hold 92+6*amount bytes |
235 | * Selector function can be anything, maybe test for seeds, etc. | 258 | * Selector function can be anything, maybe test for seeds, etc. |
236 | * RANDOM may return huge values | 259 | * RANDOM may return huge values |
237 | * does not yet check not to return self | 260 | * does not yet check not to return self |
@@ -349,7 +372,7 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
349 | if( !( r = *reply = malloc( 256*32 + (43+OT_POOLS_COUNT*32)*torrent_count ) ) ) return 0; | 372 | if( !( r = *reply = malloc( 256*32 + (43+OT_POOLS_COUNT*32)*torrent_count ) ) ) return 0; |
350 | 373 | ||
351 | for( i=0; i<256; ++i ) | 374 | for( i=0; i<256; ++i ) |
352 | r += sprintf( r, "%02X: %04X %04X\n", i, (ot_dword)all_torrents[i].size, (ot_dword)all_torrents[i].space ); | 375 | r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space ); |
353 | 376 | ||
354 | for( i=0; i<256; ++i ) { | 377 | for( i=0; i<256; ++i ) { |
355 | ot_vector *torrents_list = &all_torrents[i]; | 378 | ot_vector *torrents_list = &all_torrents[i]; |
@@ -359,7 +382,7 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
359 | r += sprintf( r, "\n%s:\n", to_hex( (ot_byte*)hash ) ); | 382 | r += sprintf( r, "\n%s:\n", to_hex( (ot_byte*)hash ) ); |
360 | clean_peerlist( time_now, peer_list ); | 383 | clean_peerlist( time_now, peer_list ); |
361 | for( k=0; k<OT_POOLS_COUNT; ++k ) | 384 | for( k=0; k<OT_POOLS_COUNT; ++k ) |
362 | r += sprintf( r, "\t%04X %04X\n", peer_list->peers[k].size, peer_list->peers[k].space ); | 385 | r += sprintf( r, "\t%04X %04X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space ); |
363 | } | 386 | } |
364 | } | 387 | } |
365 | 388 | ||
@@ -432,7 +455,13 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
432 | for( j=0; j<torrents_list->size; ++j ) { | 455 | for( j=0; j<torrents_list->size; ++j ) { |
433 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 456 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
434 | size_t local_peers = 0, local_seeds = 0; | 457 | size_t local_peers = 0, local_seeds = 0; |
435 | clean_peerlist( time_now, peer_list ); | 458 | |
459 | if( clean_peerlist( time_now, peer_list ) ) { | ||
460 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | ||
461 | vector_remove_torrent( torrents_list->data, hash ); | ||
462 | --j; | ||
463 | continue; | ||
464 | } | ||
436 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 465 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
437 | local_peers += peer_list->peers[k].size; | 466 | local_peers += peer_list->peers[k].size; |
438 | local_seeds += peer_list->seed_count[k]; | 467 | local_seeds += peer_list->seed_count[k]; |
@@ -480,15 +509,12 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) { | |||
480 | 509 | ||
481 | /* Maybe this does the job */ | 510 | /* Maybe this does the job */ |
482 | if( clean_peerlist( NOW, torrent->peer_list ) ) { | 511 | if( clean_peerlist( NOW, torrent->peer_list ) ) { |
483 | #ifdef WANT_CLOSED_TRACKER | ||
484 | if( !g_closedtracker ) | ||
485 | #endif | ||
486 | vector_remove_torrent( torrents_list, hash ); | 512 | vector_remove_torrent( torrents_list, hash ); |
487 | return; | 513 | return; |
488 | } | 514 | } |
489 | 515 | ||
490 | for( i=0; i<OT_POOLS_COUNT; ++i ) | 516 | for( i=0; i<OT_POOLS_COUNT; ++i ) |
491 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer ) ) { | 517 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, i == 0 ) ) { |
492 | case 0: continue; | 518 | case 0: continue; |
493 | case 2: torrent->peer_list->seed_count[i]--; | 519 | case 2: torrent->peer_list->seed_count[i]--; |
494 | case 1: default: return; | 520 | case 1: default: return; |