summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--README8
-rw-r--r--opentracker.c192
-rw-r--r--ot_stats.c186
-rw-r--r--ot_stats.h16
-rw-r--r--trackerlogic.h6
6 files changed, 204 insertions, 208 deletions
diff --git a/Makefile b/Makefile
index 822716e..37dd8d3 100644
--- a/Makefile
+++ b/Makefile
@@ -6,8 +6,8 @@ CFLAGS+=-I../libowfat -Wall -pipe -Wextra #-pedantic -ansi
6LDFLAGS+=-L../libowfat/ -lowfat 6LDFLAGS+=-L../libowfat/ -lowfat
7 7
8BINARY =opentracker 8BINARY =opentracker
9HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.h ot_stats.h ot_sync.h ot_vector.h ot_clean.h 9HEADERS=trackerlogic.h scan_urlencoded_query.h ot_mutex.h ot_stats.h ot_sync.h ot_vector.h ot_clean.h ot_udp.h
10SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_sync.c ot_vector.c ot_clean.c 10SOURCES=opentracker.c trackerlogic.c scan_urlencoded_query.c ot_mutex.c ot_stats.c ot_sync.c ot_vector.c ot_clean.c ot_udp.c
11 11
12OBJECTS = $(SOURCES:%.c=%.o) 12OBJECTS = $(SOURCES:%.c=%.o)
13OBJECTS_debug = $(SOURCES:%.c=%.debug.o) 13OBJECTS_debug = $(SOURCES:%.c=%.debug.o)
diff --git a/README b/README
index 8fac50b..84c4455 100644
--- a/README
+++ b/README
@@ -4,14 +4,12 @@ You need libowfat (http://www.fefe.de/libowfat/).
4 4
5Steps to go: 5Steps to go:
6 6
7fetch http://dl.fefe.de/libowfat-0.25.tar.bz2 7cvs -d :pserver:cvs@cvs.fefe.de:/cvs -z9 co libowfat
8tar xjf libowfat-0.25.tar.bz2
9cd libowfat 8cd libowfat
10make 9make
11cd .. 10cd ..
12fetch http://erdgeist.org/arts/software/opentracker/opentracker-1.0.tar.bz2 11cvs -d:pserver:anoncvs@cvs.erdgeist.org:/home/cvsroot co opentracker
13tar xjf opentracker-1.0.tar.bz2 12cd opentracker
14cd opentracker-1.0
15make 13make
16./opentracker 14./opentracker
17 15
diff --git a/opentracker.c b/opentracker.c
index 0345177..6bde42e 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -3,17 +3,7 @@
3 Some of the stuff below is stolen from Fefes example libowfat httpd. 3 Some of the stuff below is stolen from Fefes example libowfat httpd.
4*/ 4*/
5 5
6#include "socket.h" 6/* System */
7#include "io.h"
8#include "iob.h"
9#include "buffer.h"
10#include "array.h"
11#include "byte.h"
12#include "case.h"
13#include "fmt.h"
14#include "str.h"
15#include "scan.h"
16#include "ip4.h"
17#include <string.h> 7#include <string.h>
18#include <sys/types.h> 8#include <sys/types.h>
19#include <sys/stat.h> 9#include <sys/stat.h>
@@ -27,23 +17,32 @@
27#include <stdio.h> 17#include <stdio.h>
28#include <pwd.h> 18#include <pwd.h>
29 19
20/* Libowfat */
21#include "socket.h"
22#include "io.h"
23#include "iob.h"
24#include "buffer.h"
25#include "array.h"
26#include "byte.h"
27#include "case.h"
28#include "fmt.h"
29#include "str.h"
30#include "scan.h"
31#include "ip4.h"
32
33/* Opentracker */
30#include "trackerlogic.h" 34#include "trackerlogic.h"
31#include "scan_urlencoded_query.h" 35#include "scan_urlencoded_query.h"
32#include "ot_stats.h" 36#include "ot_stats.h"
33#include "ot_sync.h" 37#include "ot_sync.h"
38#include "ot_udp.h"
34 39
35/* Globals */ 40/* Globals */
36static unsigned long long ot_overall_tcp_connections = 0;
37static unsigned long long ot_overall_udp_connections = 0;
38static unsigned long long ot_overall_tcp_successfulannounces = 0;
39static unsigned long long ot_overall_udp_successfulannounces = 0;
40static unsigned long long ot_full_scrape_count = 0;
41static unsigned long long ot_full_scrape_size = 0;
42static time_t ot_start_time;
43static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80; 41static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80;
44static const size_t SUCCESS_HTTP_SIZE_OFF = 17; 42static const size_t SUCCESS_HTTP_SIZE_OFF = 17;
45static uint32_t g_adminip_addresses[OT_ADMINIP_MAX]; 43static uint32_t g_adminip_addresses[OT_ADMINIP_MAX];
46static unsigned int g_adminip_count = 0; 44static unsigned int g_adminip_count = 0;
45time_t ot_start_time;
47time_t g_now; 46time_t g_now;
48 47
49#if defined ( WANT_BLACKLISTING ) && defined (WANT_CLOSED_TRACKER ) 48#if defined ( WANT_BLACKLISTING ) && defined (WANT_CLOSED_TRACKER )
@@ -65,9 +64,8 @@ static char *accesslist_filename = NULL;
65#endif 64#endif
66 65
67/* To always have space for error messages ;) */ 66/* To always have space for error messages ;) */
68 67char static_inbuf[8192];
69static char static_inbuf[8192]; 68char static_outbuf[8192];
70static char static_outbuf[8192];
71 69
72#define OT_MAXMULTISCRAPE_COUNT 64 70#define OT_MAXMULTISCRAPE_COUNT 64
73static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT]; 71static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT];
@@ -114,7 +112,6 @@ static void handle_timeouted( void );
114static void handle_accept( const int64 serversocket ); 112static void handle_accept( const int64 serversocket );
115static void handle_read( const int64 clientsocket ); 113static void handle_read( const int64 clientsocket );
116static void handle_write( const int64 clientsocket ); 114static void handle_write( const int64 clientsocket );
117static void handle_udp4( const int64 serversocket );
118 115
119static void ot_try_bind( char ip[4], uint16 port, int is_tcp ); 116static void ot_try_bind( char ip[4], uint16 port, int is_tcp );
120 117
@@ -234,7 +231,6 @@ static void httpresponse( const int64 s, char *data _DEBUG_HTTPERROR_PARAM( size
234 ot_hash *hash = NULL; 231 ot_hash *hash = NULL;
235 int numwant, tmp, scanon, mode; 232 int numwant, tmp, scanon, mode;
236 unsigned short port = htons(6881); 233 unsigned short port = htons(6881);
237 time_t t;
238 ssize_t len; 234 ssize_t len;
239 size_t reply_size = 0, reply_off; 235 size_t reply_size = 0, reply_off;
240 236
@@ -347,47 +343,9 @@ LOG_TO_STDERR( "sync: %d.%d.%d.%d\n", h->ip[0], h->ip[1], h->ip[2], h->ip[3] );
347 case STATS_DMEM: 343 case STATS_DMEM:
348 if( !( reply_size = return_memstat_for_tracker( &reply ) ) ) HTTPERROR_500; 344 if( !( reply_size = return_memstat_for_tracker( &reply ) ) ) HTTPERROR_500;
349 return sendmmapdata( s, reply, reply_size ); 345 return sendmmapdata( s, reply, reply_size );
350
351 case STATS_CONNS:
352 t = time( NULL ) - ot_start_time;
353 reply_size = sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH,
354 "%llu\n%llu\n%i seconds (%i hours)\nopentracker - Pretuned by german engineers, currently handling %llu connections per second.",
355 ot_overall_tcp_connections+ot_overall_udp_connections, ot_overall_tcp_successfulannounces+ot_overall_udp_successfulannounces, (int)t, (int)(t / 3600), (ot_overall_tcp_connections+ot_overall_udp_connections) / ( (unsigned int)t ? (unsigned int)t : 1 ) );
356 break;
357 case STATS_UDP:
358 t = time( NULL ) - ot_start_time;
359 reply_size = sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH,
360 "%llu\n%llu\n%i seconds (%i hours)\nopentracker udp4 stats.",
361 ot_overall_udp_connections, ot_overall_udp_successfulannounces, (int)t, (int)(t / 3600) );
362 break;
363
364 case STATS_TCP:
365 t = time( NULL ) - ot_start_time;
366 reply_size = sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH,
367 "%llu\n%llu\n%i seconds (%i hours)\nopentracker tcp4 stats.",
368 ot_overall_tcp_connections, ot_overall_tcp_successfulannounces, (int)t, (int)(t / 3600) );
369 break;
370
371 default: 346 default:
372 case STATS_PEERS: 347 // default format for now
373 /* Enough for http header + whole scrape string */ 348 if( !( reply_size = return_stats_for_tracker( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, mode, 0 ) ) ) HTTPERROR_500;
374 if( !( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, mode ) ) ) HTTPERROR_500;
375 break;
376
377 case STATS_FULLSCRAPE:
378 t = time( NULL ) - ot_start_time;
379 reply_size = sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH,
380 "%llu\n%llu\n%i seconds (%i hours)\nopentracker full scrape stats.",
381 ot_full_scrape_count * 1000, ot_full_scrape_size, (int)t, (int)(t / 3600) );
382 break;
383
384 case STATS_SLASH24S:
385 {
386 ot_dword diff; struct timeval tv1, tv2; gettimeofday( &tv1, NULL );
387 if( !( reply_size = return_stats_for_slash24s( SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 25, 16 ) ) ) HTTPERROR_500;
388 gettimeofday( &tv2, NULL ); diff = ( tv2.tv_sec - tv1.tv_sec ) * 1000000 + tv2.tv_usec - tv1.tv_usec;
389 reply_size += sprintf( SUCCESS_HTTP_HEADER_LENGTH + static_outbuf + reply_size, "Time taken: %u\n", diff );
390 }
391 break; 349 break;
392 } 350 }
393 break; 351 break;
@@ -409,10 +367,7 @@ write( 2, debug_request, l );
409 if( !( reply_size = return_fullscrape_for_tracker( &reply ) ) ) HTTPERROR_500; 367 if( !( reply_size = return_fullscrape_for_tracker( &reply ) ) ) HTTPERROR_500;
410 368
411 /* Stat keeping */ 369 /* Stat keeping */
412 ot_overall_tcp_successfulannounces++; 370 stats_issue_event( EVENT_FULLSCRAPE, 1, reply_size);
413 ot_full_scrape_count++;
414 ot_full_scrape_size += reply_size;
415
416 return sendmmapdata( s, reply, reply_size ); 371 return sendmmapdata( s, reply, reply_size );
417 } 372 }
418 373
@@ -460,8 +415,7 @@ UTORRENT1600_WORKAROUND:
460 415
461 /* Enough for http header + whole scrape string */ 416 /* Enough for http header + whole scrape string */
462 if( !( reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf ) ) ) HTTPERROR_500; 417 if( !( reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf ) ) ) HTTPERROR_500;
463 418 stats_issue_event( EVENT_SCRAPE, 1, reply_size );
464 ot_overall_tcp_successfulannounces++;
465 break; 419 break;
466/****************************** 420/******************************
467 * A N N O U N C E * 421 * A N N O U N C E *
@@ -564,7 +518,7 @@ ANNOUNCE_WORKAROUND:
564 torrent = add_peer_to_torrent( hash, &peer, 0 ); 518 torrent = add_peer_to_torrent( hash, &peer, 0 );
565 if( !torrent || !( reply_size = return_peers_for_torrent( hash, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 1 ) ) ) HTTPERROR_500; 519 if( !torrent || !( reply_size = return_peers_for_torrent( hash, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, 1 ) ) ) HTTPERROR_500;
566 } 520 }
567 ot_overall_tcp_successfulannounces++; 521 stats_issue_event( EVENT_ANNOUNCE, 1, reply_size);
568 break; 522 break;
569 default: 523 default:
570 if( ( *data == 'a' ) || ( *data == '?' ) ) goto ANNOUNCE_WORKAROUND; 524 if( ( *data == 'a' ) || ( *data == '?' ) ) goto ANNOUNCE_WORKAROUND;
@@ -702,14 +656,13 @@ static void handle_accept( const int64 serversocket ) {
702 byte_zero( h, sizeof( struct http_data ) ); 656 byte_zero( h, sizeof( struct http_data ) );
703 memmove( h->ip, ip, sizeof( ip ) ); 657 memmove( h->ip, ip, sizeof( ip ) );
704 658
705 ++ot_overall_tcp_connections; 659 stats_issue_event( EVENT_ACCEPT, 1, 0);
706 660
707 /* That breaks taia encapsulation. But there is no way to take system 661 /* That breaks taia encapsulation. But there is no way to take system
708 time this often in FreeBSD and libowfat does not allow to set unix time */ 662 time this often in FreeBSD and libowfat does not allow to set unix time */
709 taia_uint( &t, 0 ); /* Clear t */ 663 taia_uint( &t, 0 ); /* Clear t */
710 tai_unix( &(t.sec), (g_now + OT_CLIENT_TIMEOUT) ); 664 tai_unix( &(t.sec), (g_now + OT_CLIENT_TIMEOUT) );
711 io_timeout( i, t ); 665 io_timeout( i, t );
712
713 } 666 }
714 667
715 if( errno == EAGAIN ) 668 if( errno == EAGAIN )
@@ -731,94 +684,6 @@ static void handle_timeouted( void ) {
731 } 684 }
732} 685}
733 686
734/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
735
736static void handle_udp4( int64 serversocket ) {
737 ot_peer peer;
738 ot_torrent *torrent;
739 ot_hash *hash = NULL;
740 char remoteip[4];
741 ot_dword *inpacket = (ot_dword*)static_inbuf;
742 ot_dword *outpacket = (ot_dword*)static_outbuf;
743 ot_dword numwant, left, event;
744 ot_word port, remoteport;
745 size_t r, r_out;
746
747 r = socket_recv4( serversocket, static_inbuf, 8192, remoteip, &remoteport);
748
749 ot_overall_udp_connections++;
750
751 /* Minimum udp tracker packet size, also catches error */
752 if( r < 16 )
753 return;
754
755 /* look for udp bittorrent magic id */
756 if( (ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980) )
757 return;
758
759 switch( ntohl( inpacket[2] ) ) {
760 case 0: /* This is a connect action */
761 outpacket[0] = 0; outpacket[1] = inpacket[3];
762 outpacket[2] = inpacket[0]; outpacket[3] = inpacket[1];
763 socket_send4( serversocket, static_outbuf, 16, remoteip, remoteport );
764 ot_overall_udp_successfulannounces++;
765 break;
766 case 1: /* This is an announce action */
767 /* Minimum udp announce packet size */
768 if( r < 98 )
769 return;
770
771 numwant = 200;
772 /* We do only want to know, if it is zero */
773 left = inpacket[64/4] | inpacket[68/4];
774
775 event = ntohl( inpacket[80/4] );
776 port = *(ot_word*)( static_inbuf + 96 );
777 hash = (ot_hash*)( static_inbuf + 16 );
778
779 OT_SETIP( &peer, remoteip );
780 OT_SETPORT( &peer, &port );
781 OT_FLAG( &peer ) = 0;
782
783 switch( event ) {
784 case 1: OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED; break;
785 case 3: OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; break;
786 default: break;
787 }
788
789 if( !left )
790 OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
791
792 outpacket[0] = htonl( 1 ); /* announce action */
793 outpacket[1] = inpacket[12/4];
794
795 if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) /* Peer is gone. */
796 r = remove_peer_from_torrent( hash, &peer, static_outbuf, 0 );
797 else {
798 torrent = add_peer_to_torrent( hash, &peer, 0 );
799 if( !torrent )
800 return; /* XXX maybe send error */
801
802 r = 8 + return_peers_for_torrent( hash, numwant, static_outbuf + 8, 0 );
803 }
804
805 socket_send4( serversocket, static_outbuf, r, remoteip, remoteport );
806 ot_overall_udp_successfulannounces++;
807 break;
808
809 case 2: /* This is a scrape action */
810 outpacket[0] = htonl( 2 ); /* scrape action */
811 outpacket[1] = inpacket[12/4];
812
813 for( r_out = 0; ( r_out * 20 < r - 16) && ( r_out <= 74 ); r_out++ )
814 return_udp_scrape_for_torrent( (ot_hash*)( static_inbuf + 16 + 20 * r_out ), static_outbuf + 8 + 12 * r_out );
815
816 socket_send4( serversocket, static_outbuf, 8 + 12 * r_out, remoteip, remoteport );
817 ot_overall_udp_successfulannounces++;
818 break;
819 }
820}
821
822static void server_mainloop( ) { 687static void server_mainloop( ) {
823 time_t next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 688 time_t next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
824 689
@@ -892,17 +757,14 @@ void read_accesslist_file( int foo ) {
892 for( i=0; i<20; ++i ) { 757 for( i=0; i<20; ++i ) {
893 int eger = 16 * scan_fromhex( static_inbuf[ 2*i ] ) + scan_fromhex( static_inbuf[ 1 + 2*i ] ); 758 int eger = 16 * scan_fromhex( static_inbuf[ 2*i ] ) + scan_fromhex( static_inbuf[ 1 + 2*i ] );
894 if( eger < 0 ) 759 if( eger < 0 )
895 goto ignore_line; 760 continue;
896 infohash[i] = eger; 761 infohash[i] = eger;
897 } 762 }
898 if( scan_fromhex( static_inbuf[ 40 ] ) >= 0 ) 763 if( scan_fromhex( static_inbuf[ 40 ] ) >= 0 )
899 goto ignore_line; 764 continue;
900 765
901 /* Append accesslist to accesslist vector */ 766 /* Append accesslist to accesslist vector */
902 accesslist_addentry( &infohash ); 767 accesslist_addentry( &infohash );
903
904ignore_line:
905 continue;
906 } 768 }
907 769
908 fclose( accesslist_filehandle ); 770 fclose( accesslist_filehandle );
diff --git a/ot_stats.c b/ot_stats.c
index 6857376..7cfb1dc 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -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 */
21static unsigned long long ot_overall_tcp_connections = 0;
22static unsigned long long ot_overall_udp_connections = 0;
23static unsigned long long ot_overall_tcp_successfulannounces = 0;
24static unsigned long long ot_overall_udp_successfulannounces = 0;
25static unsigned long long ot_overall_tcp_successfulscrapes = 0;
26static unsigned long long ot_overall_udp_successfulscrapes = 0;
27static unsigned long long ot_full_scrape_count = 0;
28static 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 */
21static 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;} 31static 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
23typedef struct { size_t val; ot_torrent * torrent; } ot_record; 33typedef struct { size_t val; ot_torrent * torrent; } ot_record;
24 34
25/* Fetches stats from tracker */ 35/* Fetches stats from tracker */
26size_t return_stats_for_tracker( char *reply, int mode ) { 36size_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*/
78size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ) { 80static 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
206static unsigned long events_per_time( unsigned long long events, time_t t ) {
207 return events / ( (unsigned int)t ? (unsigned int)t : 1 );
208}
209
210static 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
223static 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
236static 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
250static 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
263static 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
283size_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
305void 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
diff --git a/ot_stats.h b/ot_stats.h
index e4d7c06..58eec71 100644
--- a/ot_stats.h
+++ b/ot_stats.h
@@ -5,9 +5,21 @@
5#define __OT_STATS_H__ 5#define __OT_STATS_H__
6 6
7enum { STATS_CONNS, STATS_PEERS, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, STATS_SLASH24S, SYNC_IN, SYNC_OUT, STATS_FULLSCRAPE }; 7enum { STATS_CONNS, STATS_PEERS, STATS_TOP5, STATS_DMEM, STATS_TCP, STATS_UDP, STATS_SLASH24S, SYNC_IN, SYNC_OUT, STATS_FULLSCRAPE };
8typedef enum {
9 EVENT_ACCEPT,
10 EVENT_READ,
11 EVENT_CONNECT, /* UDP only */
12 EVENT_ANNOUNCE,
13 EVENT_SCRAPE,
14 EVENT_FULLSCRAPE, /* TCP only */
15 EVENT_FAILED_400,
16 EVENT_FAILED_404,
17 EVENT_FAILED_505
18} ot_status_event;
8 19
9size_t return_stats_for_tracker( char *reply, int mode ); 20size_t return_stats_for_tracker( char *reply, int mode, int format );
10size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh );
11size_t return_memstat_for_tracker( char **reply ); 21size_t return_memstat_for_tracker( char **reply );
12 22
23void stats_issue_event( ot_status_event event, int is_tcp, size_t event_data );
24
13#endif 25#endif
diff --git a/trackerlogic.h b/trackerlogic.h
index fd80f92..9c13a62 100644
--- a/trackerlogic.h
+++ b/trackerlogic.h
@@ -47,7 +47,11 @@ typedef time_t ot_time;
47#define OT_POOLS_COUNT 9 47#define OT_POOLS_COUNT 9
48#define OT_POOLS_TIMEOUT (60*5) 48#define OT_POOLS_TIMEOUT (60*5)
49 49
50extern time_t g_now; 50/* From opentracker.c */
51extern char static_inbuf[8192];
52extern char static_outbuf[8192];
53extern time_t ot_start_time;
54extern time_t g_now;
51#define NOW (g_now/OT_POOLS_TIMEOUT) 55#define NOW (g_now/OT_POOLS_TIMEOUT)
52 56
53typedef struct { 57typedef struct {