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 | ||
