diff options
Diffstat (limited to 'ot_stats.c')
-rw-r--r-- | ot_stats.c | 186 |
1 files changed, 153 insertions, 33 deletions
@@ -17,57 +17,59 @@ | |||
17 | #include "ot_mutex.h" | 17 | #include "ot_mutex.h" |
18 | #include "ot_stats.h" | 18 | #include "ot_stats.h" |
19 | 19 | ||
20 | /* Clumsy counters... to be rethought */ | ||
21 | static unsigned long long ot_overall_tcp_connections = 0; | ||
22 | static unsigned long long ot_overall_udp_connections = 0; | ||
23 | static unsigned long long ot_overall_tcp_successfulannounces = 0; | ||
24 | static unsigned long long ot_overall_udp_successfulannounces = 0; | ||
25 | static unsigned long long ot_overall_tcp_successfulscrapes = 0; | ||
26 | static unsigned long long ot_overall_udp_successfulscrapes = 0; | ||
27 | static unsigned long long ot_full_scrape_count = 0; | ||
28 | static unsigned long long ot_full_scrape_size = 0; | ||
29 | |||
20 | /* Converter function from memory to human readable hex strings */ | 30 | /* Converter function from memory to human readable hex strings */ |
21 | static char*to_hex(char*d,ot_byte*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;} | 31 | static char*to_hex(char*d,ot_byte*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;} |
22 | 32 | ||
23 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; | 33 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; |
24 | 34 | ||
25 | /* Fetches stats from tracker */ | 35 | /* Fetches stats from tracker */ |
26 | size_t return_stats_for_tracker( char *reply, int mode ) { | 36 | size_t stats_top5_txt( char * reply ) { |
27 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; | 37 | size_t j; |
28 | ot_record top5s[5], top5c[5]; | 38 | ot_record top5s[5], top5c[5]; |
29 | char *r = reply; | 39 | char *r = reply, hex_out[42]; |
30 | int bucket; | 40 | int idx, bucket; |
31 | 41 | ||
32 | byte_zero( top5s, sizeof( top5s ) ); | 42 | byte_zero( top5s, sizeof( top5s ) ); |
33 | byte_zero( top5c, sizeof( top5c ) ); | 43 | byte_zero( top5c, sizeof( top5c ) ); |
34 | 44 | ||
35 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | 45 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { |
36 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | 46 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); |
37 | torrent_count += torrents_list->size; | ||
38 | for( j=0; j<torrents_list->size; ++j ) { | 47 | for( j=0; j<torrents_list->size; ++j ) { |
39 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 48 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
40 | if( mode == STATS_TOP5 ) { | 49 | int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx; |
41 | int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx; | 50 | if ( idx++ != 4 ) { |
42 | if ( idx++ != 4 ) { | 51 | memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); |
43 | memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); | 52 | top5c[idx].val = peer_list->peer_count; |
44 | top5c[idx].val = peer_list->peer_count; | 53 | top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; |
45 | top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | 54 | } |
46 | } | 55 | idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx; |
47 | idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx; | 56 | if ( idx++ != 4 ) { |
48 | if ( idx++ != 4 ) { | 57 | memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); |
49 | memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); | 58 | top5s[idx].val = peer_list->seed_count; |
50 | top5s[idx].val = peer_list->seed_count; | 59 | top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; |
51 | top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | ||
52 | } | ||
53 | } | 60 | } |
54 | peer_count += peer_list->peer_count; seed_count += peer_list->seed_count; | ||
55 | } | 61 | } |
56 | mutex_bucket_unlock( bucket ); | 62 | mutex_bucket_unlock( bucket ); |
57 | } | 63 | } |
58 | if( mode == STATS_TOP5 ) { | 64 | |
59 | char hex_out[42]; | 65 | r += sprintf( r, "Top5 torrents by peers:\n" ); |
60 | int idx; | 66 | for( idx=0; idx<5; ++idx ) |
61 | r += sprintf( r, "Top5 torrents by peers:\n" ); | 67 | if( top5c[idx].torrent ) |
62 | for( idx=0; idx<5; ++idx ) | 68 | r += sprintf( r, "\t%zd\t%s\n", top5c[idx].val, to_hex( hex_out, top5c[idx].torrent->hash) ); |
63 | if( top5c[idx].torrent ) | 69 | r += sprintf( r, "Top5 torrents by seeds:\n" ); |
64 | r += sprintf( r, "\t%zd\t%s\n", top5c[idx].val, to_hex( hex_out, top5c[idx].torrent->hash) ); | 70 | for( idx=0; idx<5; ++idx ) |
65 | r += sprintf( r, "Top5 torrents by seeds:\n" ); | 71 | if( top5s[idx].torrent ) |
66 | for( idx=0; idx<5; ++idx ) | 72 | r += sprintf( r, "\t%zd\t%s\n", top5s[idx].val, to_hex( hex_out, top5s[idx].torrent->hash) ); |
67 | if( top5s[idx].torrent ) | ||
68 | r += sprintf( r, "\t%zd\t%s\n", top5s[idx].val, to_hex( hex_out, top5s[idx].torrent->hash) ); | ||
69 | } else | ||
70 | r += sprintf( r, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", peer_count, seed_count, torrent_count ); | ||
71 | 73 | ||
72 | return r - reply; | 74 | return r - reply; |
73 | } | 75 | } |
@@ -75,7 +77,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
75 | /* This function collects 4096 /24s in 4096 possible | 77 | /* This function collects 4096 /24s in 4096 possible |
76 | malloc blocks | 78 | malloc blocks |
77 | */ | 79 | */ |
78 | size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ) { | 80 | static size_t stats_slash24s_txt( char * reply, size_t amount, ot_dword thresh ) { |
79 | 81 | ||
80 | #define NUM_TOPBITS 12 | 82 | #define NUM_TOPBITS 12 |
81 | #define NUM_LOWBITS (24-NUM_TOPBITS) | 83 | #define NUM_LOWBITS (24-NUM_TOPBITS) |
@@ -200,3 +202,121 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
200 | 202 | ||
201 | return replysize; | 203 | return replysize; |
202 | } | 204 | } |
205 | |||
206 | static unsigned long events_per_time( unsigned long long events, time_t t ) { | ||
207 | return events / ( (unsigned int)t ? (unsigned int)t : 1 ); | ||
208 | } | ||
209 | |||
210 | static size_t stats_connections_mrtg( char * reply ) { | ||
211 | ot_time t = time( NULL ) - ot_start_time; | ||
212 | return sprintf( reply, | ||
213 | "%llu\n%llu\n%i seconds (%i hours)\nopentracker connections, %lu conns/s :: %lu success/s.", | ||
214 | ot_overall_tcp_connections+ot_overall_udp_connections, | ||
215 | ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces, | ||
216 | (int)t, | ||
217 | (int)(t / 3600), | ||
218 | events_per_time( ot_overall_tcp_connections+ot_overall_udp_connections, t ), | ||
219 | events_per_time( ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces, t ) | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | static size_t stats_udpconnections_mrtg( char * reply ) { | ||
224 | ot_time t = time( NULL ) - ot_start_time; | ||
225 | return sprintf( reply, | ||
226 | "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats, %lu conns/s :: %lu success/s.", | ||
227 | ot_overall_udp_connections, | ||
228 | ot_overall_udp_successfulannounces, | ||
229 | (int)t, | ||
230 | (int)(t / 3600), | ||
231 | events_per_time( ot_overall_udp_connections, t ), | ||
232 | events_per_time( ot_overall_udp_successfulannounces, t ) | ||
233 | ); | ||
234 | } | ||
235 | |||
236 | static size_t stats_tcpconnections_mrtg( char * reply ) { | ||
237 | time_t t = time( NULL ) - ot_start_time; | ||
238 | return sprintf( reply, | ||
239 | "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats, %lu conns/s :: %lu success/s.", | ||
240 | ot_overall_tcp_connections, | ||
241 | ot_overall_tcp_successfulannounces, | ||
242 | (int)t, | ||
243 | (int)(t / 3600), | ||
244 | events_per_time( ot_overall_tcp_connections, t ), | ||
245 | events_per_time( ot_overall_tcp_successfulannounces, t ) | ||
246 | ); | ||
247 | } | ||
248 | |||
249 | |||
250 | static size_t stats_fullscrapes_mrtg( char * reply ) { | ||
251 | ot_time t = time( NULL ) - ot_start_time; | ||
252 | return sprintf( reply, | ||
253 | "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats, %lu conns/s :: %lu bytes/s.", | ||
254 | ot_full_scrape_count * 1000, | ||
255 | ot_full_scrape_size, | ||
256 | (int)t, | ||
257 | (int)(t / 3600), | ||
258 | events_per_time( ot_full_scrape_count, t ), | ||
259 | events_per_time( ot_full_scrape_size, t ) | ||
260 | ); | ||
261 | } | ||
262 | |||
263 | static size_t stats_peers_mrtg( char * reply ) { | ||
264 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; | ||
265 | int bucket; | ||
266 | |||
267 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | ||
268 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | ||
269 | torrent_count += torrents_list->size; | ||
270 | for( j=0; j<torrents_list->size; ++j ) { | ||
271 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
272 | peer_count += peer_list->peer_count; seed_count += peer_list->seed_count; | ||
273 | } | ||
274 | mutex_bucket_unlock( bucket ); | ||
275 | } | ||
276 | return sprintf( reply, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", | ||
277 | peer_count, | ||
278 | seed_count, | ||
279 | torrent_count | ||
280 | ); | ||
281 | } | ||
282 | |||
283 | size_t return_stats_for_tracker( char *reply, int mode, int format ) { | ||
284 | format = format; | ||
285 | switch( mode ) { | ||
286 | case STATS_CONNS: | ||
287 | return stats_connections_mrtg( reply ); | ||
288 | case STATS_UDP: | ||
289 | return stats_udpconnections_mrtg( reply ); | ||
290 | case STATS_TCP: | ||
291 | return stats_tcpconnections_mrtg( reply ); | ||
292 | case STATS_PEERS: | ||
293 | return stats_peers_mrtg( reply ); | ||
294 | case STATS_SLASH24S: | ||
295 | return stats_slash24s_txt( reply, 25, 16 ); | ||
296 | case STATS_TOP5: | ||
297 | return stats_top5_txt( reply ); | ||
298 | case STATS_FULLSCRAPE: | ||
299 | return stats_fullscrapes_mrtg( reply ); | ||
300 | default: | ||
301 | return 0; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | void stats_issue_event( ot_status_event event, int is_tcp, size_t event_data ) { | ||
306 | switch( event ) { | ||
307 | case EVENT_ACCEPT: | ||
308 | if( is_tcp ) ot_overall_tcp_connections++; else ot_overall_udp_connections++; | ||
309 | break; | ||
310 | case EVENT_ANNOUNCE: | ||
311 | if( is_tcp ) ot_overall_tcp_successfulannounces++; else ot_overall_udp_successfulannounces++; | ||
312 | break; | ||
313 | case EVENT_SCRAPE: | ||
314 | if( is_tcp ) ot_overall_tcp_successfulscrapes++; else ot_overall_udp_successfulscrapes++; | ||
315 | case EVENT_FULLSCRAPE: | ||
316 | ot_full_scrape_count++; | ||
317 | ot_full_scrape_size += event_data; | ||
318 | break; | ||
319 | default: | ||
320 | break; | ||
321 | } | ||
322 | } \ No newline at end of file | ||