summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opentracker.c45
-rw-r--r--ot_accesslist.c2
-rw-r--r--ot_fullscrape.c6
-rw-r--r--ot_http.c11
-rw-r--r--ot_stats.c60
-rw-r--r--trackerlogic.c29
-rw-r--r--trackerlogic.h1
7 files changed, 110 insertions, 44 deletions
diff --git a/opentracker.c b/opentracker.c
index c67e331..a82518d 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -51,7 +51,7 @@ static void signal_handler( int s ) {
51 if( s == SIGINT ) { 51 if( s == SIGINT ) {
52 /* Any new interrupt signal quits the application */ 52 /* Any new interrupt signal quits the application */
53 signal( SIGINT, SIG_DFL); 53 signal( SIGINT, SIG_DFL);
54 54
55 /* Tell all other threads to not acquire any new lock on a bucket 55 /* Tell all other threads to not acquire any new lock on a bucket
56 but cancel their operations and return */ 56 but cancel their operations and return */
57 g_opentracker_running = 0; 57 g_opentracker_running = 0;
@@ -250,7 +250,7 @@ static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) {
250#else 250#else
251 if( ip6_isv4mapped(ip) ) { 251 if( ip6_isv4mapped(ip) ) {
252 exerr( "V6 Tracker is V6 only!" ); 252 exerr( "V6 Tracker is V6 only!" );
253 } 253 }
254#endif 254#endif
255 255
256#ifdef _DEBUG 256#ifdef _DEBUG
@@ -261,7 +261,7 @@ static int64_t ot_try_bind( ot_ip6 ip, uint16_t port, PROTO_FLAG proto ) {
261 snprintf( _debug + off, sizeof(_debug)-off, "]:%d...", port); 261 snprintf( _debug + off, sizeof(_debug)-off, "]:%d...", port);
262 fputs( _debug, stderr ); 262 fputs( _debug, stderr );
263#endif 263#endif
264 264
265 if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 ) 265 if( socket_bind6_reuse( sock, ip, port, 0 ) == -1 )
266 panic( "socket_bind6_reuse" ); 266 panic( "socket_bind6_reuse" );
267 267
@@ -394,6 +394,42 @@ int parse_configfile( char * config_filename ) {
394 return bound; 394 return bound;
395} 395}
396 396
397void load_state(const char * const state_filename ) {
398 FILE * state_filehandle;
399 char inbuf[512];
400 ot_hash infohash;
401 unsigned long long base, downcount;
402 int consumed;
403
404 state_filehandle = fopen( state_filename, "r" );
405
406 if( state_filehandle == NULL ) {
407 fprintf( stderr, "Warning: Can't open config file: %s.", state_filename );
408 return;
409 }
410
411 /* We do ignore anything that is not of the form "^[:xdigit:]:\d+:\d+" */
412 while( fgets( inbuf, sizeof(inbuf), state_filehandle ) ) {
413 int i;
414 for( i=0; i<(int)sizeof(ot_hash); ++i ) {
415 int eger = 16 * scan_fromhex( inbuf[ 2*i ] ) + scan_fromhex( inbuf[ 1 + 2*i ] );
416 if( eger < 0 )
417 continue;
418 infohash[i] = eger;
419 }
420
421 if( i != (int)sizeof(ot_hash) ) continue;
422 i *= 2;
423
424 if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &base ) ) ) continue;
425 i += consumed;
426 if( inbuf[ i++ ] != ':' || !( consumed = scan_ulonglong( inbuf+i, &downcount ) ) ) continue;
427 add_torrent_from_saved_state( infohash, base, downcount );
428 }
429
430 fclose( state_filehandle );
431}
432
397int drop_privileges (const char * const serverdir) { 433int drop_privileges (const char * const serverdir) {
398 struct passwd *pws = NULL; 434 struct passwd *pws = NULL;
399 435
@@ -448,7 +484,7 @@ int main( int argc, char **argv ) {
448#endif 484#endif
449 485
450while( scanon ) { 486while( scanon ) {
451 switch( getopt( argc, argv, ":i:p:A:P:d:r:s:f:v" 487 switch( getopt( argc, argv, ":i:p:A:P:d:r:s:f:l:v"
452#ifdef WANT_ACCESSLIST_BLACK 488#ifdef WANT_ACCESSLIST_BLACK
453"b:" 489"b:"
454#elif defined( WANT_ACCESSLIST_WHITE ) 490#elif defined( WANT_ACCESSLIST_WHITE )
@@ -477,6 +513,7 @@ while( scanon ) {
477#endif 513#endif
478 case 'd': set_config_option( &g_serverdir, optarg ); break; 514 case 'd': set_config_option( &g_serverdir, optarg ); break;
479 case 'r': set_config_option( &g_redirecturl, optarg ); break; 515 case 'r': set_config_option( &g_redirecturl, optarg ); break;
516 case 'l': load_state( optarg ); break;
480 case 'A': 517 case 'A':
481 if( !scan_ip6( optarg, tmpip )) { usage( argv[0] ); exit( 1 ); } 518 if( !scan_ip6( optarg, tmpip )) { usage( argv[0] ); exit( 1 ); }
482 accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */ 519 accesslist_blessip( tmpip, 0xffff ); /* Allow everything for now */
diff --git a/ot_accesslist.c b/ot_accesslist.c
index 631ab88..b69035e 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -120,7 +120,7 @@ int accesslist_blessip( ot_ip6 ip, ot_permissions permissions ) {
120 char _debug[512]; 120 char _debug[512];
121 int off = snprintf( _debug, sizeof(_debug), "Blessing ip address " ); 121 int off = snprintf( _debug, sizeof(_debug), "Blessing ip address " );
122 off += fmt_ip6(_debug+off, ip ); 122 off += fmt_ip6(_debug+off, ip );
123 123
124 if( permissions & OT_PERMISSION_MAY_STAT ) off += snprintf( _debug+off, 512-off, " may_fetch_stats" ); 124 if( permissions & OT_PERMISSION_MAY_STAT ) off += snprintf( _debug+off, 512-off, " may_fetch_stats" );
125 if( permissions & OT_PERMISSION_MAY_LIVESYNC ) off += snprintf( _debug+off, 512-off, " may_sync_live" ); 125 if( permissions & OT_PERMISSION_MAY_LIVESYNC ) off += snprintf( _debug+off, 512-off, " may_sync_live" );
126 if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) off += snprintf( _debug+off, 512-off, " may_fetch_fullscrapes" ); 126 if( permissions & OT_PERMISSION_MAY_FULLSCRAPE ) off += snprintf( _debug+off, 512-off, " may_fetch_fullscrapes" );
diff --git a/ot_fullscrape.c b/ot_fullscrape.c
index d284bd4..46ce8f8 100644
--- a/ot_fullscrape.c
+++ b/ot_fullscrape.c
@@ -184,10 +184,8 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas
184 r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count ); 184 r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
185 break; 185 break;
186 case TASK_FULLSCRAPE_TRACKERSTATE: 186 case TASK_FULLSCRAPE_TRACKERSTATE:
187 memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash); 187 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
188 uint64_pack_big( r, (uint64_t)peer_list->down_count ); 188 r += sprintf( r, ":%zd:%zd\n", peer_list->base, peer_list->down_count );
189 uint64_pack_big( r + 8, (uint64_t)peer_list->base );
190 r += 16;
191 break; 189 break;
192 } 190 }
193 191
diff --git a/ot_http.c b/ot_http.c
index aee9d3c..bf60104 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -288,7 +288,7 @@ static ssize_t http_handle_scrape( const int64 sock, struct ot_workstruct *ws, c
288 288
289 /* No info_hash found? Inform user */ 289 /* No info_hash found? Inform user */
290 if( !numwant ) HTTPERROR_400_PARAM; 290 if( !numwant ) HTTPERROR_400_PARAM;
291 291
292 /* Limit number of hashes to process */ 292 /* Limit number of hashes to process */
293 if( numwant > OT_MAXMULTISCRAPE_COUNT ) 293 if( numwant > OT_MAXMULTISCRAPE_COUNT )
294 numwant = OT_MAXMULTISCRAPE_COUNT; 294 numwant = OT_MAXMULTISCRAPE_COUNT;
@@ -312,7 +312,7 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
312 unsigned short port = htons(6881); 312 unsigned short port = htons(6881);
313 char *write_ptr; 313 char *write_ptr;
314 ssize_t len; 314 ssize_t len;
315 struct http_data *cookie = io_getcookie( sock ); 315 struct http_data *cookie = io_getcookie( sock );
316 316
317 /* This is to hack around stupid clients that send "announce ?info_hash" */ 317 /* This is to hack around stupid clients that send "announce ?info_hash" */
318 if( read_ptr[-1] != '?' ) { 318 if( read_ptr[-1] != '?' ) {
@@ -412,6 +412,9 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
412 } 412 }
413 } 413 }
414 414
415 /* XXX DEBUG */
416 stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ws->reply );
417
415 /* Scanned whole query string */ 418 /* Scanned whole query string */
416 if( !hash ) 419 if( !hash )
417 return ws->reply_size = sprintf( ws->reply, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" ); 420 return ws->reply_size = sprintf( ws->reply, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" );
@@ -488,14 +491,14 @@ ssize_t http_handle_request( const int64 sock, struct ot_workstruct *ws ) {
488 */ 491 */
489 reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( ws->outbuf, 0, "%zd", ws->reply_size ); 492 reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( ws->outbuf, 0, "%zd", ws->reply_size );
490 ws->reply = ws->outbuf + reply_off; 493 ws->reply = ws->outbuf + reply_off;
491 494
492 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete 495 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete
493 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ 496 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */
494 ws->reply_size += 1 + sprintf( ws->reply, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", ws->reply_size ); 497 ws->reply_size += 1 + sprintf( ws->reply, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", ws->reply_size );
495 498
496 /* 3. Finally we join both blocks neatly */ 499 /* 3. Finally we join both blocks neatly */
497 ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; 500 ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';
498 501
499 http_senddata( sock, ws ); 502 http_senddata( sock, ws );
500 return ws->reply_size; 503 return ws->reply_size;
501} 504}
diff --git a/ot_stats.c b/ot_stats.c
index e1bce7c..6116c41 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -1,6 +1,6 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org> 1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever. 2 It is considered beerware. Prost. Skol. Cheers or whatever.
3 3
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
@@ -84,10 +84,10 @@ static int stat_increase_network_count( stats_network_node **node, int depth, ui
84 return -1; 84 return -1;
85 memset( *node, 0, sizeof( stats_network_node ) ); 85 memset( *node, 0, sizeof( stats_network_node ) );
86 } 86 }
87 87
88 if( depth < STATS_NETWORK_NODE_MAXDEPTH ) 88 if( depth < STATS_NETWORK_NODE_MAXDEPTH )
89 return stat_increase_network_count( &(*node)->children[ foo ], depth+1, ip ); 89 return stat_increase_network_count( &(*node)->children[ foo ], depth+1, ip );
90 90
91 (*node)->counters[ foo ]++; 91 (*node)->counters[ foo ]++;
92 return 0; 92 return 0;
93} 93}
@@ -122,9 +122,9 @@ static int stats_shift_down_network_count( stats_network_node **node, int depth,
122static void stats_get_highscore_networks( stats_network_node *node, int depth, ot_ip6 node_value, int *scores, ot_ip6 *networks, int network_count ) { 122static void stats_get_highscore_networks( stats_network_node *node, int depth, ot_ip6 node_value, int *scores, ot_ip6 *networks, int network_count ) {
123 uint8_t *_node_value = (uint8_t*)node_value; 123 uint8_t *_node_value = (uint8_t*)node_value;
124 int i; 124 int i;
125 125
126 if( !node ) return; 126 if( !node ) return;
127 127
128 if( depth < STATS_NETWORK_NODE_MAXDEPTH ) { 128 if( depth < STATS_NETWORK_NODE_MAXDEPTH ) {
129 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) 129 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i )
130 if( node->children[i] ) { 130 if( node->children[i] ) {
@@ -139,7 +139,7 @@ static void stats_get_highscore_networks( stats_network_node *node, int depth, o
139 _node_value[depth] = i; 139 _node_value[depth] = i;
140 while( (j<network_count) && (node->counters[i]>scores[j] ) ) ++j; 140 while( (j<network_count) && (node->counters[i]>scores[j] ) ) ++j;
141 --j; 141 --j;
142 142
143 memcpy( scores, scores + 1, j * sizeof( *scores ) ); 143 memcpy( scores, scores + 1, j * sizeof( *scores ) );
144 memcpy( networks, networks + 1, j * sizeof( *networks ) ); 144 memcpy( networks, networks + 1, j * sizeof( *networks ) );
145 scores[ j ] = node->counters[ i ]; 145 scores[ j ] = node->counters[ i ];
@@ -158,7 +158,7 @@ static size_t stats_return_busy_networks( char * reply ) {
158 memset( networks, 0, sizeof( *networks ) * 256 ); 158 memset( networks, 0, sizeof( *networks ) * 256 );
159 159
160 stats_get_highscore_networks( stats_network_counters_root, 0, node_value, scores, networks, 256 ); 160 stats_get_highscore_networks( stats_network_counters_root, 0, node_value, scores, networks, 256 );
161 161
162 for( i=255; i>=0; --i) { 162 for( i=255; i>=0; --i) {
163 r += sprintf( r, "%08i: ", scores[i] ); 163 r += sprintf( r, "%08i: ", scores[i] );
164 r += fmt_ip6c( r, networks[i] ); 164 r += fmt_ip6c( r, networks[i] );
@@ -195,10 +195,10 @@ size_t stats_top10_txt( char * reply ) {
195 ot_record top10s[10], top10c[10]; 195 ot_record top10s[10], top10c[10];
196 char *r = reply, hex_out[42]; 196 char *r = reply, hex_out[42];
197 int idx, bucket; 197 int idx, bucket;
198 198
199 byte_zero( top10s, sizeof( top10s ) ); 199 byte_zero( top10s, sizeof( top10s ) );
200 byte_zero( top10c, sizeof( top10c ) ); 200 byte_zero( top10c, sizeof( top10c ) );
201 201
202 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 202 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
203 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 203 ot_vector *torrents_list = mutex_bucket_lock( bucket );
204 for( j=0; j<torrents_list->size; ++j ) { 204 for( j=0; j<torrents_list->size; ++j ) {
@@ -220,7 +220,7 @@ size_t stats_top10_txt( char * reply ) {
220 if( !g_opentracker_running ) 220 if( !g_opentracker_running )
221 return 0; 221 return 0;
222 } 222 }
223 223
224 r += sprintf( r, "Top 10 torrents by peers:\n" ); 224 r += sprintf( r, "Top 10 torrents by peers:\n" );
225 for( idx=0; idx<10; ++idx ) 225 for( idx=0; idx<10; ++idx )
226 if( top10c[idx].torrent ) 226 if( top10c[idx].torrent )
@@ -229,7 +229,7 @@ size_t stats_top10_txt( char * reply ) {
229 for( idx=0; idx<10; ++idx ) 229 for( idx=0; idx<10; ++idx )
230 if( top10s[idx].torrent ) 230 if( top10s[idx].torrent )
231 r += sprintf( r, "\t%zd\t%s\n", top10s[idx].val, to_hex( hex_out, top10s[idx].torrent->hash) ); 231 r += sprintf( r, "\t%zd\t%s\n", top10s[idx].val, to_hex( hex_out, top10s[idx].torrent->hash) );
232 232
233 return r - reply; 233 return r - reply;
234} 234}
235 235
@@ -237,23 +237,23 @@ size_t stats_top10_txt( char * reply ) {
237 malloc blocks 237 malloc blocks
238 */ 238 */
239static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh ) { 239static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh ) {
240 240
241#define NUM_TOPBITS 12 241#define NUM_TOPBITS 12
242#define NUM_LOWBITS (24-NUM_TOPBITS) 242#define NUM_LOWBITS (24-NUM_TOPBITS)
243#define NUM_BUFS (1<<NUM_TOPBITS) 243#define NUM_BUFS (1<<NUM_TOPBITS)
244#define NUM_S24S (1<<NUM_LOWBITS) 244#define NUM_S24S (1<<NUM_LOWBITS)
245#define MSK_S24S (NUM_S24S-1) 245#define MSK_S24S (NUM_S24S-1)
246 246
247 uint32_t *counts[ NUM_BUFS ]; 247 uint32_t *counts[ NUM_BUFS ];
248 uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */ 248 uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */
249 size_t i, j, k, l; 249 size_t i, j, k, l;
250 char *r = reply; 250 char *r = reply;
251 251
252 byte_zero( counts, sizeof( counts ) ); 252 byte_zero( counts, sizeof( counts ) );
253 byte_zero( slash24s, amount * 2 * sizeof(uint32_t) ); 253 byte_zero( slash24s, amount * 2 * sizeof(uint32_t) );
254 254
255 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); 255 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh );
256 256
257#if 0 257#if 0
258 /* XXX: TOOD: Doesn't work yet with new peer storage model */ 258 /* XXX: TOOD: Doesn't work yet with new peer storage model */
259 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 259 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
@@ -284,7 +284,7 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
284 goto bailout_cleanup; 284 goto bailout_cleanup;
285 } 285 }
286#endif 286#endif
287 287
288 k = l = 0; /* Debug: count allocated bufs */ 288 k = l = 0; /* Debug: count allocated bufs */
289 for( i=0; i < NUM_BUFS; ++i ) { 289 for( i=0; i < NUM_BUFS; ++i ) {
290 uint32_t *count = counts[i]; 290 uint32_t *count = counts[i];
@@ -308,20 +308,20 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
308 } 308 }
309 free( count ); 309 free( count );
310 } 310 }
311 311
312 r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l ); 312 r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l );
313 313
314 for( i=0; i < amount; ++i ) 314 for( i=0; i < amount; ++i )
315 if( slash24s[ 2*i ] >= thresh ) { 315 if( slash24s[ 2*i ] >= thresh ) {
316 uint32_t ip = slash24s[ 2*i +1 ]; 316 uint32_t ip = slash24s[ 2*i +1 ];
317 r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) ); 317 r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) );
318 } 318 }
319 319
320 return r - reply; 320 return r - reply;
321 321
322 for( i=0; i < NUM_BUFS; ++i ) 322 for( i=0; i < NUM_BUFS; ++i )
323 free( counts[i] ); 323 free( counts[i] );
324 324
325 return 0; 325 return 0;
326} 326}
327 327
@@ -395,9 +395,9 @@ static size_t stats_fullscrapes_mrtg( char * reply ) {
395 395
396static size_t stats_peers_mrtg( char * reply ) { 396static size_t stats_peers_mrtg( char * reply ) {
397 torrent_stats stats = {0,0,0}; 397 torrent_stats stats = {0,0,0};
398 398
399 iterate_all_torrents( torrent_statter, (uintptr_t)&stats ); 399 iterate_all_torrents( torrent_statter, (uintptr_t)&stats );
400 400
401 return sprintf( reply, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker", 401 return sprintf( reply, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker",
402 stats.peer_count, 402 stats.peer_count,
403 stats.seed_count, 403 stats.seed_count,
@@ -408,7 +408,7 @@ static size_t stats_peers_mrtg( char * reply ) {
408static size_t stats_torrents_mrtg( char * reply ) 408static size_t stats_torrents_mrtg( char * reply )
409{ 409{
410 size_t torrent_count = mutex_get_torrent_count(); 410 size_t torrent_count = mutex_get_torrent_count();
411 411
412 return sprintf( reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", 412 return sprintf( reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker",
413 torrent_count, 413 torrent_count,
414 (size_t)0, 414 (size_t)0,
@@ -426,7 +426,7 @@ static size_t stats_httperrors_txt ( char * reply ) {
426static size_t stats_return_renew_bucket( char * reply ) { 426static size_t stats_return_renew_bucket( char * reply ) {
427 char *r = reply; 427 char *r = reply;
428 int i; 428 int i;
429 429
430 for( i=0; i<OT_PEER_TIMEOUT; ++i ) 430 for( i=0; i<OT_PEER_TIMEOUT; ++i )
431 r+=sprintf(r,"%02i %llu\n", i, ot_renewed[i] ); 431 r+=sprintf(r,"%02i %llu\n", i, ot_renewed[i] );
432 return r - reply; 432 return r - reply;
@@ -526,12 +526,12 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
526 526
527static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) { 527static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) {
528 char *r; 528 char *r;
529 529
530 *iovec_entries = 0; 530 *iovec_entries = 0;
531 *iovector = NULL; 531 *iovector = NULL;
532 if( !( r = iovec_increase( iovec_entries, iovector, OT_STATS_TMPSIZE ) ) ) 532 if( !( r = iovec_increase( iovec_entries, iovector, OT_STATS_TMPSIZE ) ) )
533 return; 533 return;
534 534
535 switch( mode & TASK_TASK_MASK ) { 535 switch( mode & TASK_TASK_MASK ) {
536 case TASK_STATS_TORRENTS: r += stats_torrents_mrtg( r ); break; 536 case TASK_STATS_TORRENTS: r += stats_torrents_mrtg( r ); break;
537 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break; 537 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break;
@@ -607,9 +607,9 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
607static void * stats_worker( void * args ) { 607static void * stats_worker( void * args ) {
608 int iovec_entries; 608 int iovec_entries;
609 struct iovec *iovector; 609 struct iovec *iovector;
610 610
611 args = args; 611 args = args;
612 612
613 while( 1 ) { 613 while( 1 ) {
614 ot_tasktype tasktype = TASK_STATS; 614 ot_tasktype tasktype = TASK_STATS;
615 ot_taskid taskid = mutex_workqueue_poptask( &tasktype ); 615 ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
diff --git a/trackerlogic.c b/trackerlogic.c
index 8ebaa46..1bd8ac7 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -41,6 +41,33 @@ void free_peerlist( ot_peerlist *peer_list ) {
41 free( peer_list ); 41 free( peer_list );
42} 42}
43 43
44void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count ) {
45 int exactmatch;
46 ot_torrent *torrent;
47 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
48
49 if( !accesslist_hashisvalid( hash ) )
50 return mutex_bucket_unlock_by_hash( hash, 0 );
51
52 torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
53 if( !torrent || exactmatch )
54 return mutex_bucket_unlock_by_hash( hash, 0 );
55
56 /* Create a new torrent entry, then */
57 memcpy( torrent->hash, hash, sizeof(ot_hash) );
58
59 if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
60 vector_remove_torrent( torrents_list, torrent );
61 return mutex_bucket_unlock_by_hash( hash, 0 );
62 }
63
64 byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
65 torrent->peer_list->base = base;
66 torrent->peer_list->down_count = down_count;
67
68 return mutex_bucket_unlock_by_hash( hash, 1 );
69}
70
44size_t add_peer_to_torrent_and_return_peers( ot_hash hash, ot_peer *peer, PROTO_FLAG proto, size_t amount, char * reply ) { 71size_t add_peer_to_torrent_and_return_peers( ot_hash hash, ot_peer *peer, PROTO_FLAG proto, size_t amount, char * reply ) {
45 int exactmatch, delta_torrentcount = 0; 72 int exactmatch, delta_torrentcount = 0;
46 size_t reply_size; 73 size_t reply_size;
@@ -375,7 +402,7 @@ void trackerlogic_init( ) {
375void trackerlogic_deinit( void ) { 402void trackerlogic_deinit( void ) {
376 int bucket, delta_torrentcount = 0; 403 int bucket, delta_torrentcount = 0;
377 size_t j; 404 size_t j;
378 405
379 /* Free all torrents... */ 406 /* Free all torrents... */
380 for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 407 for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
381 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 408 ot_vector *torrents_list = mutex_bucket_lock( bucket );
diff --git a/trackerlogic.h b/trackerlogic.h
index ce3feb1..1cf6127 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -147,6 +147,7 @@ size_t add_peer_to_torrent_and_return_peers( ot_hash hash, ot_peer *peer, PROTO
147size_t remove_peer_from_torrent( ot_hash hash, ot_peer *peer, char *reply, PROTO_FLAG proto ); 147size_t remove_peer_from_torrent( ot_hash hash, ot_peer *peer, char *reply, PROTO_FLAG proto );
148size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply ); 148size_t return_tcp_scrape_for_torrent( ot_hash *hash, int amount, char *reply );
149size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ); 149size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply );
150void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count );
150 151
151/* torrent iterator */ 152/* torrent iterator */
152void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ); 153void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data );