summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <>2009-03-04 14:35:21 +0000
committererdgeist <>2009-03-04 14:35:21 +0000
commit9297967f8523f1ac22bbac1823529b970a07cf56 (patch)
tree0a6bc2a2d3ac9d38e53079040c7057c779e30f15
parent72a1564ca14392cc2e1d044554c6e86a0eda9409 (diff)
Add a stat option the count bucket stalls
Add an iterator for all torrents. It's slower but for stats it's okay. Move some stats collection stuff to the new iterator. More to come. Start a "report all stats" page. Start fixing the code to identify "busy" networks. Add the concept of hosts allowed to proxy. Add a parser for the X-Forwarded-For: HTTP header. Clean up HTTP Header handling code. (Remove some left overs of now vanished sync code).
-rw-r--r--opentracker.c11
-rw-r--r--ot_accesslist.c1
-rw-r--r--ot_accesslist.h3
-rw-r--r--ot_http.c43
-rw-r--r--ot_mutex.c5
-rw-r--r--ot_stats.c341
-rw-r--r--ot_stats.h3
-rw-r--r--trackerlogic.c19
-rw-r--r--trackerlogic.h3
9 files changed, 252 insertions, 177 deletions
diff --git a/opentracker.c b/opentracker.c
index b839efc..c67e331 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -135,12 +135,10 @@ static ssize_t handle_read( const int64 sock, struct ot_workstruct *ws ) {
135 135
136 array_catb( &cookie->data.request, ws->inbuf, byte_count ); 136 array_catb( &cookie->data.request, ws->inbuf, byte_count );
137 137
138 if( array_failed( &cookie->data.request ) ) 138 if( array_failed( &cookie->data.request ) ||
139 array_bytes( &cookie->data.request ) > 8192 )
139 return http_issue_error( sock, ws, CODE_HTTPERROR_500 ); 140 return http_issue_error( sock, ws, CODE_HTTPERROR_500 );
140 141
141 if( array_bytes( &cookie->data.request ) > 8192 )
142 return http_issue_error( sock, ws, CODE_HTTPERROR_500 );
143
144 if( !memchr( array_start( &cookie->data.request ), '\n', array_bytes( &cookie->data.request ) ) ) 142 if( !memchr( array_start( &cookie->data.request ), '\n', array_bytes( &cookie->data.request ) ) )
145 return 0; 143 return 0;
146 144
@@ -370,6 +368,11 @@ int parse_configfile( char * config_filename ) {
370 if( !scan_ip6( p+13, tmpip )) goto parse_error; 368 if( !scan_ip6( p+13, tmpip )) goto parse_error;
371 accesslist_blessip( tmpip, OT_PERMISSION_MAY_STAT ); 369 accesslist_blessip( tmpip, OT_PERMISSION_MAY_STAT );
372#endif 370#endif
371#ifdef WANT_IP_FROM_PROXY
372 } else if(!byte_diff(p, 12, "access.proxy" ) && isspace(p[12])) {
373 if( !scan_ip6( p+13, tmpip )) goto parse_error;
374 accesslist_blessip( tmpip, OT_PERMISSION_MAY_PROXY );
375#endif
373 } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) { 376 } else if(!byte_diff(p, 20, "tracker.redirect_url" ) && isspace(p[20])) {
374 set_config_option( &g_redirecturl, p+21 ); 377 set_config_option( &g_redirecturl, p+21 );
375#ifdef WANT_SYNC_LIVE 378#ifdef WANT_SYNC_LIVE
diff --git a/ot_accesslist.c b/ot_accesslist.c
index 304b3f1..631ab88 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -124,6 +124,7 @@ int accesslist_blessip( ot_ip6 ip, ot_permissions permissions ) {
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" );
127 if( permissions & OT_PERMISSION_MAY_PROXY ) off += snprintf( _debug+off, 512-off, " may_proxy" );
127 if( !permissions ) off += snprintf( _debug+off, sizeof(_debug)-off, " nothing\n" ); 128 if( !permissions ) off += snprintf( _debug+off, sizeof(_debug)-off, " nothing\n" );
128 _debug[off++] = '.'; 129 _debug[off++] = '.';
129 write( 2, _debug, off ); 130 write( 2, _debug, off );
diff --git a/ot_accesslist.h b/ot_accesslist.h
index 836a233..5954a4a 100644
--- a/ot_accesslist.h
+++ b/ot_accesslist.h
@@ -27,7 +27,8 @@ extern char *g_accesslist_filename;
27typedef enum { 27typedef enum {
28 OT_PERMISSION_MAY_FULLSCRAPE = 0x1, 28 OT_PERMISSION_MAY_FULLSCRAPE = 0x1,
29 OT_PERMISSION_MAY_STAT = 0x2, 29 OT_PERMISSION_MAY_STAT = 0x2,
30 OT_PERMISSION_MAY_LIVESYNC = 0x4 30 OT_PERMISSION_MAY_LIVESYNC = 0x4,
31 OT_PERMISSION_MAY_PROXY = 0x8
31} ot_permissions; 32} ot_permissions;
32 33
33int accesslist_blessip( ot_ip6 ip, ot_permissions permissions ); 34int accesslist_blessip( ot_ip6 ip, ot_permissions permissions );
diff --git a/ot_http.c b/ot_http.c
index 971d81d..de57dad 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -306,13 +306,14 @@ static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "even
306{ NULL, -3 } }; 306{ NULL, -3 } };
307static ot_keywords keywords_announce_event[] = { { "completed", 1 }, { "stopped", 2 }, { NULL, -3 } }; 307static ot_keywords keywords_announce_event[] = { { "completed", 1 }, { "stopped", 2 }, { NULL, -3 } };
308static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) { 308static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) {
309 int numwant, tmp, scanon; 309 int numwant, tmp, scanon;
310 ot_peer peer; 310 ot_peer peer;
311 ot_hash *hash = NULL; 311 ot_hash *hash = NULL;
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 315 struct http_data *cookie = io_getcookie( sock );
316
316 /* 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" */
317 if( read_ptr[-1] != '?' ) { 318 if( read_ptr[-1] != '?' ) {
318 while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; 319 while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr;
@@ -320,7 +321,33 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
320 ++read_ptr; 321 ++read_ptr;
321 } 322 }
322 323
323 OT_SETIP( &peer, ((struct http_data*)io_getcookie( sock ) )->ip ); 324#ifdef WANT_IP_FROM_PROXY
325 if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_PROXY ) ) {
326 ot_ip6 proxied_ip;
327 char *fwd, *fwd_new = ws->request;
328
329 /* Zero terminate for string routines. Normally we'd only overwrite bollocks */
330 ws->request[ws->request_size-1] = 0;
331
332 /* Find last occurence of the forwarded header */
333 do {
334 fwd = fwd_new;
335 fwd_new = strcasestr( fwd_new, "\nX-Forwarded-For:" );
336 } while( fwd_new );
337
338 /* Skip spaces between : and the ip address */
339 if( fwd ) {
340 fwd += 18; /* sizeof( "\nX-Forwarded-For:" ) */
341 while( *fwd == ' ' ) ++fwd;
342 }
343
344 if( fwd && scan_ip6( fwd, proxied_ip ) )
345 OT_SETIP( &peer, proxied_ip );
346 else
347 OT_SETIP( &peer, cookie->ip );
348 }
349#endif
350 OT_SETIP( &peer, cookie->ip );
324 OT_SETPORT( &peer, &port ); 351 OT_SETPORT( &peer, &port );
325 OT_PEERFLAG( &peer ) = 0; 352 OT_PEERFLAG( &peer ) = 0;
326 numwant = 50; 353 numwant = 50;
diff --git a/ot_mutex.c b/ot_mutex.c
index 925eb27..2052ffa 100644
--- a/ot_mutex.c
+++ b/ot_mutex.c
@@ -18,6 +18,7 @@
18/* Opentracker */ 18/* Opentracker */
19#include "trackerlogic.h" 19#include "trackerlogic.h"
20#include "ot_mutex.h" 20#include "ot_mutex.h"
21#include "ot_stats.h"
21 22
22/* #define MTX_DBG( STRING ) fprintf( stderr, STRING ) */ 23/* #define MTX_DBG( STRING ) fprintf( stderr, STRING ) */
23#define MTX_DBG( STRING ) 24#define MTX_DBG( STRING )
@@ -47,8 +48,10 @@ static int bucket_check( int bucket ) {
47 48
48 /* See, if bucket is already locked */ 49 /* See, if bucket is already locked */
49 for( i=0; i<bucket_locklist_count; ++i ) 50 for( i=0; i<bucket_locklist_count; ++i )
50 if( bucket_locklist[ i ] == bucket ) 51 if( bucket_locklist[ i ] == bucket ) {
52 stats_issue_event( EVENT_BUCKET_LOCKED, 0, 0 );
51 return -1; 53 return -1;
54 }
52 55
53 return 0; 56 return 0;
54} 57}
diff --git a/ot_stats.c b/ot_stats.c
index a53ac3b..518dbb5 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -1,7 +1,7 @@
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 */
7#include <stdlib.h> 7#include <stdlib.h>
@@ -50,12 +50,13 @@ static unsigned long long ot_full_scrape_size = 0;
50static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT]; 50static unsigned long long ot_failed_request_counts[CODE_HTTPERROR_COUNT];
51static unsigned long long ot_renewed[OT_PEER_TIMEOUT]; 51static unsigned long long ot_renewed[OT_PEER_TIMEOUT];
52static unsigned long long ot_overall_sync_count; 52static unsigned long long ot_overall_sync_count;
53static unsigned long long ot_overall_stall_count;
53 54
54static time_t ot_start_time; 55static time_t ot_start_time;
55 56
56#ifdef WANT_LOG_NETWORKS 57#ifdef WANT_LOG_NETWORKS
57#define STATS_NETWORK_NODE_BITWIDTH 8 58#define STATS_NETWORK_NODE_BITWIDTH 8
58#define STATS_NETWORK_NODE_MAXDEPTH 3 59#define STATS_NETWORK_NODE_MAXDEPTH 16
59 60
60#define STATS_NETWORK_NODE_BITMASK ((1<<STATS_NETWORK_NODE_BITWIDTH)-1) 61#define STATS_NETWORK_NODE_BITMASK ((1<<STATS_NETWORK_NODE_BITWIDTH)-1)
61#define STATS_NETWORK_NODE_COUNT (1<<STATS_NETWORK_NODE_BITWIDTH) 62#define STATS_NETWORK_NODE_COUNT (1<<STATS_NETWORK_NODE_BITWIDTH)
@@ -68,19 +69,20 @@ union stats_network_node {
68 69
69static stats_network_node *stats_network_counters_root = NULL; 70static stats_network_node *stats_network_counters_root = NULL;
70 71
71static int stat_increase_network_count( stats_network_node **node, int depth, uint32_t ip ) { 72static int stat_increase_network_count( stats_network_node **node, int depth, uintptr_t ip ) {
72 int foo = ( ip >> ( 32 - STATS_NETWORK_NODE_BITWIDTH * ( ++depth ) ) ) & STATS_NETWORK_NODE_BITMASK; 73 ot_ip6 *_ip = (ot_ip6*)ip;
73 74 int foo = (*_ip)[depth];
75
74 if( !*node ) { 76 if( !*node ) {
75 *node = malloc( sizeof( stats_network_node ) ); 77 *node = malloc( sizeof( stats_network_node ) );
76 if( !*node ) 78 if( !*node )
77 return -1; 79 return -1;
78 memset( *node, 0, sizeof( stats_network_node ) ); 80 memset( *node, 0, sizeof( stats_network_node ) );
79 } 81 }
80 82
81 if( depth < STATS_NETWORK_NODE_MAXDEPTH ) 83 if( depth < STATS_NETWORK_NODE_MAXDEPTH )
82 return stat_increase_network_count( &(*node)->children[ foo ], depth, ip ); 84 return stat_increase_network_count( &(*node)->children[ foo ], depth, ip );
83 85
84 (*node)->counters[ foo ]++; 86 (*node)->counters[ foo ]++;
85 return 0; 87 return 0;
86} 88}
@@ -88,40 +90,40 @@ static int stat_increase_network_count( stats_network_node **node, int depth, ui
88static int stats_shift_down_network_count( stats_network_node **node, int depth, int shift ) { 90static int stats_shift_down_network_count( stats_network_node **node, int depth, int shift ) {
89 int i, rest = 0; 91 int i, rest = 0;
90 if( !*node ) return 0; 92 if( !*node ) return 0;
91 93
92 if( ++depth == STATS_NETWORK_NODE_MAXDEPTH ) 94 if( ++depth == STATS_NETWORK_NODE_MAXDEPTH )
93 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) { 95 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
94 rest += ((*node)->counters[i]>>=shift); 96 rest += ((*node)->counters[i]>>=shift);
95 return rest; 97 return rest;
96 } 98 }
97 99
98 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) { 100 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
99 stats_network_node **childnode = &(*node)->children[i]; 101 stats_network_node **childnode = &(*node)->children[i];
100 int rest_val; 102 int rest_val;
101 103
102 if( !*childnode ) continue; 104 if( !*childnode ) continue;
103 105
104 rest += rest_val = stats_shift_down_network_count( childnode, depth, shift ); 106 rest += rest_val = stats_shift_down_network_count( childnode, depth, shift );
105 107
106 if( rest_val ) continue; 108 if( rest_val ) continue;
107 109
108 free( (*node)->children[i] ); 110 free( (*node)->children[i] );
109 (*node)->children[i] = NULL; 111 (*node)->children[i] = NULL;
110 } 112 }
111 113
112 return rest; 114 return rest;
113} 115}
114 116
115static void stats_get_highscore_networks( stats_network_node *node, int depth, uint32_t node_value, int *scores, uint32_t *networks, int network_count ) { 117static void stats_get_highscore_networks( stats_network_node *node, int depth, uint32_t node_value, int *scores, uint32_t *networks, int network_count ) {
116 int i; 118 int i;
117 119
118 if( !node ) return; 120 if( !node ) return;
119 121
120 if( !depth++ ) { 122 if( !depth++ ) {
121 memset( scores, 0, sizeof( *scores ) * network_count ); 123 memset( scores, 0, sizeof( *scores ) * network_count );
122 memset( networks, 0, sizeof( *networks ) * network_count ); 124 memset( networks, 0, sizeof( *networks ) * network_count );
123 } 125 }
124 126
125 if( depth < STATS_NETWORK_NODE_MAXDEPTH ) { 127 if( depth < STATS_NETWORK_NODE_MAXDEPTH ) {
126 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) 128 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i )
127 if( node->children[i] ) 129 if( node->children[i] )
@@ -130,15 +132,15 @@ static void stats_get_highscore_networks( stats_network_node *node, int depth, u
130 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) { 132 for( i=0; i<STATS_NETWORK_NODE_COUNT; ++i ) {
131 int j=1; 133 int j=1;
132 if( node->counters[i] <= scores[0] ) continue; 134 if( node->counters[i] <= scores[0] ) continue;
133 135
134 while( (j<network_count) && (node->counters[i]>scores[j] ) ) ++j; 136 while( (j<network_count) && (node->counters[i]>scores[j] ) ) ++j;
135 --j; 137 --j;
136 138
137 memcpy( scores, scores + 1, j * sizeof( *scores ) ); 139 memcpy( scores, scores + 1, j * sizeof( *scores ) );
138 memcpy( networks, networks + 1, j * sizeof( *networks ) ); 140 memcpy( networks, networks + 1, j * sizeof( *networks ) );
139 scores[ j ] = node->counters[ i ]; 141 scores[ j ] = node->counters[ i ];
140 networks[ j ] = node_value | ( i << ( 32 - depth * STATS_NETWORK_NODE_BITWIDTH ) ); 142 networks[ j ] = node_value | ( i << ( 32 - depth * STATS_NETWORK_NODE_BITWIDTH ) );
141 } 143 }
142} 144}
143 145
144static size_t stats_return_busy_networks( char * reply ) { 146static size_t stats_return_busy_networks( char * reply ) {
@@ -146,17 +148,31 @@ static size_t stats_return_busy_networks( char * reply ) {
146 int scores[16]; 148 int scores[16];
147 int i; 149 int i;
148 char * r = reply; 150 char * r = reply;
149 151
150 stats_get_highscore_networks( stats_network_counters_root, 0, 0, scores, networks, 16 ); 152 stats_get_highscore_networks( stats_network_counters_root, 0, 0, scores, networks, 16 );
151 153
152 for( i=15; i>=0; --i) 154 for( i=15; i>=0; --i)
153 r += sprintf( r, "%08i: %d.%d.%d.0/24\n", scores[i], (networks[i]>>24)&0xff, (networks[i]>>16)&0xff, (networks[i]>>8)&0xff ); 155 r += sprintf( r, "%08i: %d.%d.%d.0/24\n", scores[i], (networks[i]>>24)&0xff, (networks[i]>>16)&0xff, (networks[i]>>8)&0xff );
154 156
155 return r - reply; 157 return r - reply;
156} 158}
157 159
158#endif 160#endif
159 161
162typedef struct {
163 unsigned long long torrent_count;
164 unsigned long long peer_count;
165 unsigned long long seed_count;
166} torrent_stats;
167
168static int torrent_statter( ot_torrent *torrent, uintptr_t data ) {
169 torrent_stats *stats = (torrent_stats*)data;
170 stats->torrent_count++;
171 stats->peer_count += torrent->peer_list->peer_count;
172 stats->seed_count += torrent->peer_list->seed_count;
173 return 0;
174}
175
160/* Converter function from memory to human readable hex strings */ 176/* Converter function from memory to human readable hex strings */
161static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;} 177static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=d+40;while(d<e){*d++=m[*s>>4];*d++=m[*s++&15];}*d=0;return t;}
162 178
@@ -168,10 +184,10 @@ size_t stats_top10_txt( char * reply ) {
168 ot_record top10s[10], top10c[10]; 184 ot_record top10s[10], top10c[10];
169 char *r = reply, hex_out[42]; 185 char *r = reply, hex_out[42];
170 int idx, bucket; 186 int idx, bucket;
171 187
172 byte_zero( top10s, sizeof( top10s ) ); 188 byte_zero( top10s, sizeof( top10s ) );
173 byte_zero( top10c, sizeof( top10c ) ); 189 byte_zero( top10c, sizeof( top10c ) );
174 190
175 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 191 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
176 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 192 ot_vector *torrents_list = mutex_bucket_lock( bucket );
177 for( j=0; j<torrents_list->size; ++j ) { 193 for( j=0; j<torrents_list->size; ++j ) {
@@ -193,7 +209,7 @@ size_t stats_top10_txt( char * reply ) {
193 if( !g_opentracker_running ) 209 if( !g_opentracker_running )
194 return 0; 210 return 0;
195 } 211 }
196 212
197 r += sprintf( r, "Top 10 torrents by peers:\n" ); 213 r += sprintf( r, "Top 10 torrents by peers:\n" );
198 for( idx=0; idx<10; ++idx ) 214 for( idx=0; idx<10; ++idx )
199 if( top10c[idx].torrent ) 215 if( top10c[idx].torrent )
@@ -202,31 +218,31 @@ size_t stats_top10_txt( char * reply ) {
202 for( idx=0; idx<10; ++idx ) 218 for( idx=0; idx<10; ++idx )
203 if( top10s[idx].torrent ) 219 if( top10s[idx].torrent )
204 r += sprintf( r, "\t%zd\t%s\n", top10s[idx].val, to_hex( hex_out, top10s[idx].torrent->hash) ); 220 r += sprintf( r, "\t%zd\t%s\n", top10s[idx].val, to_hex( hex_out, top10s[idx].torrent->hash) );
205 221
206 return r - reply; 222 return r - reply;
207} 223}
208 224
209/* This function collects 4096 /24s in 4096 possible 225/* This function collects 4096 /24s in 4096 possible
210 malloc blocks 226 malloc blocks
211*/ 227 */
212static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh ) { 228static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh ) {
213 229
214#define NUM_TOPBITS 12 230#define NUM_TOPBITS 12
215#define NUM_LOWBITS (24-NUM_TOPBITS) 231#define NUM_LOWBITS (24-NUM_TOPBITS)
216#define NUM_BUFS (1<<NUM_TOPBITS) 232#define NUM_BUFS (1<<NUM_TOPBITS)
217#define NUM_S24S (1<<NUM_LOWBITS) 233#define NUM_S24S (1<<NUM_LOWBITS)
218#define MSK_S24S (NUM_S24S-1) 234#define MSK_S24S (NUM_S24S-1)
219 235
220 uint32_t *counts[ NUM_BUFS ]; 236 uint32_t *counts[ NUM_BUFS ];
221 uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */ 237 uint32_t slash24s[amount*2]; /* first dword amount, second dword subnet */
222 size_t i, j, k, l; 238 size_t i, j, k, l;
223 char *r = reply; 239 char *r = reply;
224 240
225 byte_zero( counts, sizeof( counts ) ); 241 byte_zero( counts, sizeof( counts ) );
226 byte_zero( slash24s, amount * 2 * sizeof(uint32_t) ); 242 byte_zero( slash24s, amount * 2 * sizeof(uint32_t) );
227 243
228 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); 244 r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh );
229 245
230#if 0 246#if 0
231 /* XXX: TOOD: Doesn't work yet with new peer storage model */ 247 /* XXX: TOOD: Doesn't work yet with new peer storage model */
232 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 248 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
@@ -257,7 +273,7 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
257 goto bailout_cleanup; 273 goto bailout_cleanup;
258 } 274 }
259#endif 275#endif
260 276
261 k = l = 0; /* Debug: count allocated bufs */ 277 k = l = 0; /* Debug: count allocated bufs */
262 for( i=0; i < NUM_BUFS; ++i ) { 278 for( i=0; i < NUM_BUFS; ++i ) {
263 uint32_t *count = counts[i]; 279 uint32_t *count = counts[i];
@@ -281,28 +297,28 @@ static size_t stats_slash24s_txt( char * reply, size_t amount, uint32_t thresh )
281 } 297 }
282 free( count ); 298 free( count );
283 } 299 }
284 300
285 r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l ); 301 r += sprintf( r, "Allocated bufs: %zd, used s24s: %zd\n", k, l );
286 302
287 for( i=0; i < amount; ++i ) 303 for( i=0; i < amount; ++i )
288 if( slash24s[ 2*i ] >= thresh ) { 304 if( slash24s[ 2*i ] >= thresh ) {
289 uint32_t ip = slash24s[ 2*i +1 ]; 305 uint32_t ip = slash24s[ 2*i +1 ];
290 r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) ); 306 r += sprintf( r, "% 10ld %d.%d.%d.0/24\n", (long)slash24s[ 2*i ], (int)(ip >> 16), (int)(255 & ( ip >> 8 )), (int)(ip & 255) );
291 } 307 }
292 308
293 return r - reply; 309 return r - reply;
294 310
295 for( i=0; i < NUM_BUFS; ++i ) 311 for( i=0; i < NUM_BUFS; ++i )
296 free( counts[i] ); 312 free( counts[i] );
297 313
298 return 0; 314 return 0;
299} 315}
300 316
301/* 317/*
302 struct { 318 struct {
303 size_t size 319 size_t size
304 size_t space 320 size_t space
305 size_t count 321 size_t count
306 } 322 }
307 */ 323 */
308 324
@@ -313,105 +329,95 @@ static unsigned long events_per_time( unsigned long long events, time_t t ) {
313static size_t stats_connections_mrtg( char * reply ) { 329static size_t stats_connections_mrtg( char * reply ) {
314 ot_time t = time( NULL ) - ot_start_time; 330 ot_time t = time( NULL ) - ot_start_time;
315 return sprintf( reply, 331 return sprintf( reply,
316 "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", 332 "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.",
317 ot_overall_tcp_connections+ot_overall_udp_connections, 333 ot_overall_tcp_connections+ot_overall_udp_connections,
318 ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces+ot_overall_udp_connects, 334 ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces+ot_overall_udp_connects,
319 (int)t, 335 (int)t,
320 (int)(t / 3600), 336 (int)(t / 3600),
321 events_per_time( ot_overall_tcp_connections+ot_overall_udp_connections, t ), 337 events_per_time( ot_overall_tcp_connections+ot_overall_udp_connections, t ),
322 events_per_time( ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces+ot_overall_udp_connects, t ) 338 events_per_time( ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces+ot_overall_udp_connects, t )
323 ); 339 );
324} 340}
325 341
326static size_t stats_udpconnections_mrtg( char * reply ) { 342static size_t stats_udpconnections_mrtg( char * reply ) {
327 ot_time t = time( NULL ) - ot_start_time; 343 ot_time t = time( NULL ) - ot_start_time;
328 return sprintf( reply, 344 return sprintf( reply,
329 "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", 345 "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.",
330 ot_overall_udp_connections, 346 ot_overall_udp_connections,
331 ot_overall_udp_successfulannounces+ot_overall_udp_connects, 347 ot_overall_udp_successfulannounces+ot_overall_udp_connects,
332 (int)t, 348 (int)t,
333 (int)(t / 3600), 349 (int)(t / 3600),
334 events_per_time( ot_overall_udp_connections, t ), 350 events_per_time( ot_overall_udp_connections, t ),
335 events_per_time( ot_overall_udp_successfulannounces+ot_overall_udp_connects, t ) 351 events_per_time( ot_overall_udp_successfulannounces+ot_overall_udp_connects, t )
336 ); 352 );
337} 353}
338 354
339static size_t stats_tcpconnections_mrtg( char * reply ) { 355static size_t stats_tcpconnections_mrtg( char * reply ) {
340 time_t t = time( NULL ) - ot_start_time; 356 time_t t = time( NULL ) - ot_start_time;
341 return sprintf( reply, 357 return sprintf( reply,
342 "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", 358 "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.",
343 ot_overall_tcp_connections, 359 ot_overall_tcp_connections,
344 ot_overall_tcp_successfulannounces, 360 ot_overall_tcp_successfulannounces,
345 (int)t, 361 (int)t,
346 (int)(t / 3600), 362 (int)(t / 3600),
347 events_per_time( ot_overall_tcp_connections, t ), 363 events_per_time( ot_overall_tcp_connections, t ),
348 events_per_time( ot_overall_tcp_successfulannounces, t ) 364 events_per_time( ot_overall_tcp_successfulannounces, t )
349 ); 365 );
350} 366}
351 367
352static size_t stats_scrape_mrtg( char * reply ) { 368static size_t stats_scrape_mrtg( char * reply ) {
353 time_t t = time( NULL ) - ot_start_time; 369 time_t t = time( NULL ) - ot_start_time;
354 return sprintf( reply, 370 return sprintf( reply,
355 "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)", 371 "%llu\n%llu\n%i seconds (%i hours)\nopentracker scrape stats, %lu scrape/s (tcp and udp)",
356 ot_overall_tcp_successfulscrapes, 372 ot_overall_tcp_successfulscrapes,
357 ot_overall_udp_successfulscrapes, 373 ot_overall_udp_successfulscrapes,
358 (int)t, 374 (int)t,
359 (int)(t / 3600), 375 (int)(t / 3600),
360 events_per_time( (ot_overall_tcp_successfulscrapes+ot_overall_udp_successfulscrapes), t ) 376 events_per_time( (ot_overall_tcp_successfulscrapes+ot_overall_udp_successfulscrapes), t )
361 ); 377 );
362} 378}
363 379
364static size_t stats_fullscrapes_mrtg( char * reply ) { 380static size_t stats_fullscrapes_mrtg( char * reply ) {
365 ot_time t = time( NULL ) - ot_start_time; 381 ot_time t = time( NULL ) - ot_start_time;
366 return sprintf( reply, 382 return sprintf( reply,
367 "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.", 383 "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.",
368 ot_full_scrape_count * 1000, 384 ot_full_scrape_count * 1000,
369 ot_full_scrape_size, 385 ot_full_scrape_size,
370 (int)t, 386 (int)t,
371 (int)(t / 3600), 387 (int)(t / 3600),
372 events_per_time( ot_full_scrape_count, t ), 388 events_per_time( ot_full_scrape_count, t ),
373 events_per_time( ot_full_scrape_size, t ) 389 events_per_time( ot_full_scrape_size, t )
374 ); 390 );
375} 391}
376 392
377static size_t stats_peers_mrtg( char * reply ) { 393static size_t stats_peers_mrtg( char * reply ) {
378 size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; 394 torrent_stats stats = {0,0,0};
379 int bucket; 395
380 396 iterate_all_torrents( torrent_statter, (uintptr_t)&stats );
381 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 397
382 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 398 return sprintf( reply, "%llu\n%llu\nopentracker serving %llu torrents\nopentracker",
383 torrent_count += torrents_list->size; 399 stats.peer_count,
384 for( j=0; j<torrents_list->size; ++j ) { 400 stats.seed_count,
385 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 401 stats.torrent_count
386 peer_count += peer_list->peer_count; seed_count += peer_list->seed_count; 402 );
387 }
388 mutex_bucket_unlock( bucket, 0 );
389 if( !g_opentracker_running )
390 return 0;
391 }
392 return sprintf( reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker",
393 peer_count,
394 seed_count,
395 torrent_count
396 );
397} 403}
398 404
399static size_t stats_startstop_mrtg( char * reply ) 405static size_t stats_startstop_mrtg( char * reply )
400{ 406{
401 size_t torrent_count = mutex_get_torrent_count(); 407 size_t torrent_count = mutex_get_torrent_count();
402 408
403 return sprintf( reply, "%zd\n%zd\nopentracker handling %zd torrents\nopentracker", 409 return sprintf( reply, "%zd\n%zd\nopentracker handling %zd torrents\nopentracker",
404 (size_t)0, 410 (size_t)0,
405 (size_t)0, 411 (size_t)0,
406 torrent_count 412 torrent_count
407 ); 413 );
408} 414}
409 415
410static size_t stats_toraddrem_mrtg( char * reply ) 416static size_t stats_toraddrem_mrtg( char * reply )
411{ 417{
412 size_t peer_count = 0, j; 418 size_t peer_count = 0, j;
413 int bucket; 419 int bucket;
414 420
415 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) 421 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket )
416 { 422 {
417 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 423 ot_vector *torrents_list = mutex_bucket_lock( bucket );
@@ -424,53 +430,63 @@ static size_t stats_toraddrem_mrtg( char * reply )
424 if( !g_opentracker_running ) 430 if( !g_opentracker_running )
425 return 0; 431 return 0;
426 } 432 }
427 433
428 return sprintf( reply, "%zd\n%zd\nopentracker handling %zd peers\nopentracker", 434 return sprintf( reply, "%zd\n%zd\nopentracker handling %zd peers\nopentracker",
429 (size_t)0, 435 (size_t)0,
430 (size_t)0, 436 (size_t)0,
431 peer_count 437 peer_count
432 ); 438 );
433} 439}
434 440
435static size_t stats_torrents_mrtg( char * reply ) 441static size_t stats_torrents_mrtg( char * reply )
436{ 442{
437 size_t torrent_count = mutex_get_torrent_count(); 443 size_t torrent_count = mutex_get_torrent_count();
438 444
439 return sprintf( reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", 445 return sprintf( reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker",
440 torrent_count, 446 torrent_count,
441 (size_t)0, 447 (size_t)0,
442 torrent_count 448 torrent_count
443 ); 449 );
444} 450}
445 451
446static size_t stats_httperrors_txt ( char * reply ) { 452static size_t stats_httperrors_txt ( char * reply ) {
447 return sprintf( reply, "302 RED %llu\n400 ... %llu\n400 PAR %llu\n400 COM %llu\n403 IP %llu\n404 INV %llu\n500 SRV %llu\n", 453 return sprintf( reply, "302 RED %llu\n400 ... %llu\n400 PAR %llu\n400 COM %llu\n403 IP %llu\n404 INV %llu\n500 SRV %llu\n",
448 ot_failed_request_counts[0], ot_failed_request_counts[1], ot_failed_request_counts[2], 454 ot_failed_request_counts[0], ot_failed_request_counts[1], ot_failed_request_counts[2],
449 ot_failed_request_counts[3], ot_failed_request_counts[4], ot_failed_request_counts[5], 455 ot_failed_request_counts[3], ot_failed_request_counts[4], ot_failed_request_counts[5],
450 ot_failed_request_counts[6] ); 456 ot_failed_request_counts[6] );
451} 457}
452 458
453static size_t stats_return_renew_bucket( char * reply ) { 459static size_t stats_return_renew_bucket( char * reply ) {
454 char *r = reply; 460 char *r = reply;
455 int i; 461 int i;
456 462
457 for( i=0; i<OT_PEER_TIMEOUT; ++i ) 463 for( i=0; i<OT_PEER_TIMEOUT; ++i )
458 r+=sprintf(r,"%02i %llu\n", i, ot_renewed[i] ); 464 r+=sprintf(r,"%02i %llu\n", i, ot_renewed[i] );
459 return r - reply; 465 return r - reply;
460} 466}
461 467
462static size_t stats_return_sync_mrtg( char * reply ) 468static size_t stats_return_sync_mrtg( char * reply ) {
463{
464 ot_time t = time( NULL ) - ot_start_time; 469 ot_time t = time( NULL ) - ot_start_time;
465 return sprintf( reply, 470 return sprintf( reply,
466 "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", 471 "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.",
467 ot_overall_sync_count, 472 ot_overall_sync_count,
468 0LL, 473 0LL,
469 (int)t, 474 (int)t,
470 (int)(t / 3600), 475 (int)(t / 3600),
471 events_per_time( ot_overall_tcp_connections+ot_overall_udp_connections, t ), 476 events_per_time( ot_overall_tcp_connections+ot_overall_udp_connections, t ),
472 events_per_time( ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces+ot_overall_udp_connects, t ) 477 events_per_time( ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces+ot_overall_udp_connects, t )
473 ); 478 );
479}
480
481static size_t stats_return_everything( char * reply ) {
482 char * r = reply;
483 r += sprintf( r, "<stats>\n" );
484 r += sprintf( r, " <uptime>%llu</uptime>\n", (unsigned long long)(time( NULL ) - ot_start_time) );
485 r += sprintf( r, " <torrents>%zd</torrents>\n", mutex_get_torrent_count() );
486 /* r += sprintf( r, " <peers>%llu</peers>\n", ); */
487
488 r += sprintf( reply, "</stats>" );
489 return r - reply;
474} 490}
475 491
476extern const char 492extern const char
@@ -480,9 +496,9 @@ extern const char
480 496
481size_t stats_return_tracker_version( char *reply ) { 497size_t stats_return_tracker_version( char *reply ) {
482 return sprintf( reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s", 498 return sprintf( reply, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
483 g_version_opentracker_c, g_version_accesslist_c, g_version_clean_c, g_version_fullscrape_c, g_version_http_c, 499 g_version_opentracker_c, g_version_accesslist_c, g_version_clean_c, g_version_fullscrape_c, g_version_http_c,
484 g_version_iovec_c, g_version_mutex_c, g_version_stats_c, g_version_udp_c, g_version_vector_c, 500 g_version_iovec_c, g_version_mutex_c, g_version_stats_c, g_version_udp_c, g_version_vector_c,
485 g_version_scan_urlencoded_query_c, g_version_trackerlogic_c, g_version_livesync_c ); 501 g_version_scan_urlencoded_query_c, g_version_trackerlogic_c, g_version_livesync_c );
486} 502}
487 503
488size_t return_stats_for_tracker( char *reply, int mode, int format ) { 504size_t return_stats_for_tracker( char *reply, int mode, int format ) {
@@ -509,7 +525,7 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
509 case TASK_STATS_RENEW: 525 case TASK_STATS_RENEW:
510 return stats_return_renew_bucket( reply ); 526 return stats_return_renew_bucket( reply );
511 case TASK_STATS_SYNCS: 527 case TASK_STATS_SYNCS:
512 return stats_return_sync_mrtg( reply ); 528 return stats_return_sync_mrtg( reply );
513#ifdef WANT_LOG_NETWORKS 529#ifdef WANT_LOG_NETWORKS
514 case TASK_STATS_BUSY_NETWORKS: 530 case TASK_STATS_BUSY_NETWORKS:
515 return stats_return_busy_networks( reply ); 531 return stats_return_busy_networks( reply );
@@ -521,12 +537,12 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
521 537
522static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) { 538static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) {
523 char *r; 539 char *r;
524 540
525 *iovec_entries = 0; 541 *iovec_entries = 0;
526 *iovector = NULL; 542 *iovector = NULL;
527 if( !( r = iovec_increase( iovec_entries, iovector, OT_STATS_TMPSIZE ) ) ) 543 if( !( r = iovec_increase( iovec_entries, iovector, OT_STATS_TMPSIZE ) ) )
528 return; 544 return;
529 545
530 switch( mode & TASK_TASK_MASK ) { 546 switch( mode & TASK_TASK_MASK ) {
531 case TASK_STATS_TORRENTS: r += stats_torrents_mrtg( r ); break; 547 case TASK_STATS_TORRENTS: r += stats_torrents_mrtg( r ); break;
532 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break; 548 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break;
@@ -560,26 +576,26 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
560 ot_full_scrape_size += event_data; 576 ot_full_scrape_size += event_data;
561 break; 577 break;
562 case EVENT_FULLSCRAPE_REQUEST: 578 case EVENT_FULLSCRAPE_REQUEST:
563 { 579 {
564 ot_ip6 *ip = (ot_ip6*)event_data; /* ugly hack to transfer ip to stats */ 580 ot_ip6 *ip = (ot_ip6*)event_data; /* ugly hack to transfer ip to stats */
565 char _debug[512]; 581 char _debug[512];
566 int off = snprintf( _debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time)/60 ); 582 int off = snprintf( _debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time)/60 );
567 off += fmt_ip6( _debug+off, *ip ); 583 off += fmt_ip6( _debug+off, *ip );
568 off += snprintf( _debug+off, sizeof(_debug)-off, " - FULL SCRAPE\n" ); 584 off += snprintf( _debug+off, sizeof(_debug)-off, " - FULL SCRAPE\n" );
569 write( 2, _debug, off ); 585 write( 2, _debug, off );
570 ot_full_scrape_request_count++; 586 ot_full_scrape_request_count++;
571 } 587 }
572 break; 588 break;
573 case EVENT_FULLSCRAPE_REQUEST_GZIP: 589 case EVENT_FULLSCRAPE_REQUEST_GZIP:
574 { 590 {
575 ot_ip6 *ip = (ot_ip6*)event_data; /* ugly hack to transfer ip to stats */ 591 ot_ip6 *ip = (ot_ip6*)event_data; /* ugly hack to transfer ip to stats */
576 char _debug[512]; 592 char _debug[512];
577 int off = snprintf( _debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time)/60 ); 593 int off = snprintf( _debug, sizeof(_debug), "[%08d] scrp: ", (unsigned int)(g_now_seconds - ot_start_time)/60 );
578 off += fmt_ip6(_debug+off, *ip ); 594 off += fmt_ip6(_debug+off, *ip );
579 off += snprintf( _debug+off, sizeof(_debug)-off, " - FULL SCRAPE\n" ); 595 off += snprintf( _debug+off, sizeof(_debug)-off, " - FULL SCRAPE\n" );
580 write( 2, _debug, off ); 596 write( 2, _debug, off );
581 ot_full_scrape_request_count++; 597 ot_full_scrape_request_count++;
582 } 598 }
583 break; 599 break;
584 case EVENT_FAILED: 600 case EVENT_FAILED:
585 ot_failed_request_counts[event_data]++; 601 ot_failed_request_counts[event_data]++;
@@ -590,6 +606,9 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
590 case EVENT_SYNC: 606 case EVENT_SYNC:
591 ot_overall_sync_count+=event_data; 607 ot_overall_sync_count+=event_data;
592 break; 608 break;
609 case EVENT_BUCKET_LOCKED:
610 ot_overall_stall_count++;
611 break;
593 default: 612 default:
594 break; 613 break;
595 } 614 }
@@ -598,9 +617,9 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
598static void * stats_worker( void * args ) { 617static void * stats_worker( void * args ) {
599 int iovec_entries; 618 int iovec_entries;
600 struct iovec *iovector; 619 struct iovec *iovector;
601 620
602 args = args; 621 args = args;
603 622
604 while( 1 ) { 623 while( 1 ) {
605 ot_tasktype tasktype = TASK_STATS; 624 ot_tasktype tasktype = TASK_STATS;
606 ot_taskid taskid = mutex_workqueue_poptask( &tasktype ); 625 ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
diff --git a/ot_stats.h b/ot_stats.h
index b8a64a1..7753947 100644
--- a/ot_stats.h
+++ b/ot_stats.h
@@ -17,7 +17,8 @@ typedef enum {
17 EVENT_FULLSCRAPE_REQUEST, 17 EVENT_FULLSCRAPE_REQUEST,
18 EVENT_FULLSCRAPE_REQUEST_GZIP, 18 EVENT_FULLSCRAPE_REQUEST_GZIP,
19 EVENT_FULLSCRAPE, /* TCP only */ 19 EVENT_FULLSCRAPE, /* TCP only */
20 EVENT_FAILED 20 EVENT_FAILED,
21 EVENT_BUCKET_LOCKED
21} ot_status_event; 22} ot_status_event;
22 23
23enum { 24enum {
diff --git a/trackerlogic.c b/trackerlogic.c
index 249a2a0..8ebaa46 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -337,6 +337,23 @@ size_t remove_peer_from_torrent( ot_hash hash, ot_peer *peer, char *reply, PROTO
337 return reply_size; 337 return reply_size;
338} 338}
339 339
340void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ) {
341 int bucket;
342 size_t j;
343
344 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
345 ot_vector *torrents_list = mutex_bucket_lock( bucket );
346 ot_torrent *torrents = (ot_torrent*)(torrents_list->data);
347
348 for( j=0; j<torrents_list->size; ++j )
349 if( for_each( torrents + j, data ) )
350 break;
351
352 mutex_bucket_unlock( bucket, 0 );
353 if( !g_opentracker_running ) return;
354 }
355}
356
340void exerr( char * message ) { 357void exerr( char * message ) {
341 fprintf( stderr, "%s\n", message ); 358 fprintf( stderr, "%s\n", message );
342 exit( 111 ); 359 exit( 111 );
@@ -358,7 +375,7 @@ void trackerlogic_init( ) {
358void trackerlogic_deinit( void ) { 375void trackerlogic_deinit( void ) {
359 int bucket, delta_torrentcount = 0; 376 int bucket, delta_torrentcount = 0;
360 size_t j; 377 size_t j;
361 378
362 /* Free all torrents... */ 379 /* Free all torrents... */
363 for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 380 for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
364 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 381 ot_vector *torrents_list = mutex_bucket_lock( bucket );
diff --git a/trackerlogic.h b/trackerlogic.h
index 69deddd..ce3feb1 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -148,6 +148,9 @@ size_t remove_peer_from_torrent( ot_hash hash, ot_peer *peer, char *reply, PROT
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 );
150 150
151/* torrent iterator */
152void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data );
153
151/* Helper, before it moves to its own object */ 154/* Helper, before it moves to its own object */
152void free_peerlist( ot_peerlist *peer_list ); 155void free_peerlist( ot_peerlist *peer_list );
153 156