summaryrefslogtreecommitdiff
path: root/trackerlogic.c
diff options
context:
space:
mode:
Diffstat (limited to 'trackerlogic.c')
-rw-r--r--trackerlogic.c78
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;
34static ot_torrent* const OT_TORRENT_ON_BLACKLIST = (ot_torrent*)2; 34static 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*/
40static 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*/
64char 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
66static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { 73static 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
87static 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*/
100static 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*/
120static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { 138static 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*/
144static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) { 165static 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
163ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { 187ot_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;