summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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