diff --git a/opentracker.c b/opentracker.c index 403fa21..9121103 100644 --- a/opentracker.c +++ b/opentracker.c @@ -1,4 +1,4 @@ -/* This software was written by Dirk Engling +/* This software was written by Dirk Engling It is considered beerware. Prost. Skol. Cheers or whatever. Some of the stuff below is stolen from Fefes example libowfat httpd. */ @@ -26,6 +26,7 @@ #include "trackerlogic.h" #include "scan_urlencoded_query.h" +/* Globals */ static unsigned int ot_overall_connections = 0; static unsigned int ot_overall_successfulannounces = 0; static time_t ot_start_time; @@ -34,35 +35,64 @@ static const size_t SUCCESS_HTTP_SIZE_OFF = 17; /* To always have space for error messages ;) */ static char static_scratch[8192]; -#ifdef _DEBUG_FDS -static char fd_debug_space[0x10000]; -#endif #ifdef _DEBUG_HTTPERROR static char debug_request[8192]; #endif -static void carp(const char* routine ) { +struct http_data { + union { + array request; + io_batch batch; + }; + unsigned char ip[4]; +}; + +/* Prototypes */ + +int main( int argc, char **argv ); + +static int httpheader_complete( struct http_data *h ); +static void httperror( const int64 s, struct http_data *h, const char *title, const char *message ); +static void httpresponse( const int64 s, struct http_data *h); + +static void sendmallocdata( const int64 s, struct http_data *h, char *buffer, const size_t size ); +static void senddata( const int64 s, struct http_data *h, char *buffer, const size_t size ); + +static void server_mainloop( const int64 serversocket ); +static void handle_timeouted( void ); +static void handle_accept( const int64 serversocket ); +static void handle_read( const int64 clientsocket ); +static void handle_write( const int64 clientsocket ); + +static void usage( char *name ); +static void help( char *name ); + +static void carp( const char *routine ); +static void panic( const char *routine ); +static void graceful( int s ); + +#define HTTPERROR_400 return httperror( s, h, "400 Invalid Request", "This server only understands GET." ) +#define HTTPERROR_400_PARAM return httperror( s, h, "400 Invalid Request", "Invalid parameter" ) +#define HTTPERROR_400_COMPACT return httperror( s, h, "400 Invalid Request", "This server only delivers compact results." ) +#define HTTPERROR_404 return httperror( s, h, "404 Not Found", "No such file or directory." ) +#define HTTPERROR_500 return httperror( s, h, "500 Internal Server Error", "A server error has occured. Please retry later." ) + +/* End of prototypes */ + +static void carp( const char *routine ) { buffer_puts( buffer_2, routine ); buffer_puts( buffer_2, ": " ); buffer_puterror( buffer_2 ); buffer_putnlflush( buffer_2 ); } -static void panic( const char* routine ) { +static void panic( const char *routine ) { carp( routine ); exit( 111 ); } -struct http_data { - union { - array request; - io_batch batch; - }; - unsigned char ip[4]; -}; - -int header_complete( struct http_data* h ) { - int l = array_bytes( &h->request ), i; +static int httpheader_complete( struct http_data *h ) { + size_t l = array_bytes( &h->request ), i; const char* c = array_start( &h->request ); for( i=0; i+1%s\n", + title, strlen(message)+strlen(title)+16-4,title+4); +#ifdef _DEBUG_HTTPERROR + fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); +#endif + senddata(s,h,static_scratch,reply_size); +} + +static void sendmallocdata( const int64 s, struct http_data *h, char *buffer, size_t size ) { tai6464 t; char *header; size_t header_size; - if( !h ) { free( buffer); return; } + if( !h ) + return free( buffer); array_reset( &h->request ); header = malloc( SUCCESS_HTTP_HEADER_LENGTH ); - if( !header ) { free( buffer ); return; } + if( !header ) { + free( buffer ); + HTTPERROR_500; + } header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); @@ -89,13 +132,13 @@ void sendmallocdata( int64 s, struct http_data *h, char * buffer, size_t size ) iob_addbuf_free( &h->batch, header, header_size ); iob_addbuf_free( &h->batch, buffer, size ); - // writeable sockets just have a tcp timeout + /* writeable sockets just have a tcp timeout */ taia_uint(&t,0); io_timeout( s, t ); io_dontwantread( s ); io_wantwrite( s ); } -void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { +static void senddata( const int64 s, struct http_data *h, char *buffer, size_t size ) { size_t written_size; /* whoever sends data is not interested in its input-array */ @@ -104,20 +147,12 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { written_size = write( s, buffer, size ); if( ( written_size < 0 ) || ( written_size == size ) ) { -#ifdef _DEBUG_FDS - if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); - fd_debug_space[s] = 0; -#endif free( h ); io_close( s ); } else { char * outbuf = malloc( size - written_size ); tai6464 t; if( !outbuf ) { -#ifdef _DEBUG_FDS - if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); - fd_debug_space[s] = 0; -#endif free(h); io_close( s ); return; } @@ -126,29 +161,21 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { memmove( outbuf, buffer + written_size, size - written_size ); iob_addbuf_free( &h->batch, outbuf, size - written_size ); - // writeable sockets just have a tcp timeout + /* writeable sockets just have a tcp timeout */ taia_uint( &t, 0 ); io_timeout( s, t ); io_dontwantread( s ); io_wantwrite( s ); } } -void httperror(int64 s,struct http_data* h,const char* title,const char* message) { - size_t reply_size = sprintf( static_scratch, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n%s\n", - title, strlen(message)+strlen(title)+16-4,title+4); -#ifdef _DEBUG_HTTPERROR - fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); -#endif - senddata(s,h,static_scratch,reply_size); -} - -void httpresponse( int64 s, struct http_data* h) { - char *c, *data; +static void httpresponse( const int64 s, struct http_data *h) { + char *c, *data, *reply; ot_peer peer; ot_torrent *torrent; ot_hash *hash = NULL; int numwant, tmp, scanon, mode; unsigned short port = htons(6881); + time_t t; size_t reply_size = 0; array_cat0( &h->request ); @@ -158,104 +185,106 @@ void httpresponse( int64 s, struct http_data* h) { memcpy( debug_request, array_start( &h->request ), array_bytes( &h->request ) ); #endif - if( byte_diff( c, 4, "GET ") ) { -e400: - return httperror( s, h, "400 Invalid Request", "This server only understands GET." ); - } + if( byte_diff( c, 4, "GET ") ) HTTPERROR_400; c+=4; for( data = c; *data!=' ' && *data != '\t' && *data != '\n' && *data != '\r'; ++data ) ; - if( *data != ' ' ) goto e400; + if( *data != ' ' ) HTTPERROR_400; *data = 0; - if( c[0] != '/' ) goto e404; + if( c[0] != '/' ) HTTPERROR_404; while( *c == '/' ) ++c; switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { + case 4: /* sync ? */ + if( byte_diff( data, 4, "sync") ) HTTPERROR_404; + scanon = 1; + + while( scanon ) { + switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { + case -2: scanon = 0; break; /* TERMINATOR */ + case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ + case 9: + if(byte_diff(data,9,"info_hash")) { + scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); + continue; + } + /* ignore this, when we have less than 20 bytes */ + if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; + hash = (ot_hash*)data; /* Fall through intended */ + break; + default: + scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); + break; + } + } + + if( !hash ) HTTPERROR_400_PARAM; + if( ( reply_size = return_sync_for_torrent( hash, &reply ) ) <= 0 ) HTTPERROR_500; + + return sendmallocdata( s, h, reply, reply_size ); case 5: /* stats ? */ - if( byte_diff(data,5,"stats")) - goto e404; + if( byte_diff(data,5,"stats")) HTTPERROR_404; scanon = 1; mode = STATS_MRTG; while( scanon ) { switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { - case -2: /* terminator */ - scanon = 0; - break; - case -1: /* error */ - goto e404; + case -2: scanon = 0; break; /* TERMINATOR */ + case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ + default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; case 4: if( byte_diff(data,4,"mode")) { scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); continue; } size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); - if( len <= 0 ) goto e400_param; + if( len <= 0 ) HTTPERROR_400_PARAM; if( !byte_diff(data,4,"mrtg")) mode = STATS_MRTG; else if( !byte_diff(data,4,"top5")) mode = STATS_TOP5; else - goto e400_param; - default: - scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); - break; + HTTPERROR_400_PARAM; } } /* Enough for http header + whole scrape string */ - if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) - goto e500; + if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) HTTPERROR_500; + break; case 6: /* scrape ? */ - if( byte_diff( data, 6, "scrape") ) - goto e404; + if( byte_diff( data, 6, "scrape") ) HTTPERROR_404; scanon = 1; while( scanon ) { switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { - case -2: /* terminator */ - scanon = 0; - break; - case -1: /* error */ - goto e404; + case -2: scanon = 0; break; /* TERMINATOR */ + case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ + default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; case 9: if(byte_diff(data,9,"info_hash")) { scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); continue; } /* ignore this, when we have less than 20 bytes */ - if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) { -e400_param: - return httperror(s,h,"400 Invalid Request","Invalid parameter"); - } + if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; hash = (ot_hash*)data; /* Fall through intended */ break; - default: - scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); - break; } } /* Scanned whole query string, no hash means full scrape... you might want to limit that */ if( !hash ) { - char * reply; - - reply_size = return_fullscrape_for_tracker( &reply ); - if( reply_size ) - return sendmallocdata( s, h, reply, reply_size ); - - goto e500; - } else { - /* Enough for http header + whole scrape string */ - if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) - goto e500; + if( ( reply_size = return_fullscrape_for_tracker( &reply ) ) <= 0 ) HTTPERROR_500; + return sendmallocdata( s, h, reply, reply_size ); } + + /* Enough for http header + whole scrape string */ + if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) HTTPERROR_500; break; case 8: - if( byte_diff(data,8,"announce")) - goto e404; + if( byte_diff(data,8,"announce")) HTTPERROR_404; OT_SETIP( &peer, h->ip); OT_SETPORT( &peer, &port ); @@ -265,17 +294,15 @@ e400_param: while( scanon ) { switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { - case -2: /* terminator */ - scanon = 0; - break; - case -1: /* error */ - goto e404; + case -2: scanon = 0; break; /* TERMINATOR */ + case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ + default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; #ifdef WANT_IP_FROM_QUERY_STRING case 2: if(!byte_diff(data,2,"ip")) { size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); unsigned char ip[4]; - if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param; + if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) HTTPERROR_400_PARAM; OT_SETIP( &peer, ip ); } else scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); @@ -284,11 +311,11 @@ e400_param: case 4: if(!byte_diff(data,4,"port")) { size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); - if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param; + if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; port = htons( tmp ); OT_SETPORT( &peer, &port ); } else if(!byte_diff(data,4,"left")) { size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); - if( len <= 0 ) goto e400_param; + if( len <= 0 ) HTTPERROR_400_PARAM; if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING; } else @@ -299,7 +326,7 @@ e400_param: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { case -1: - goto e400_param; + HTTPERROR_400_PARAM; case 7: if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; break; @@ -312,13 +339,12 @@ e400_param: case 7: if(!byte_diff(data,7,"numwant")) { size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); - if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param; + if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) HTTPERROR_400_PARAM; if( numwant > 200 ) numwant = 200; } else if(!byte_diff(data,7,"compact")) { size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); - if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param; - if( !tmp ) - return httperror(s,h,"400 Invalid Request","This server only delivers compact results."); + if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) HTTPERROR_400_PARAM; + if( !tmp ) HTTPERROR_400_COMPACT; } else scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; @@ -328,79 +354,58 @@ e400_param: continue; } /* ignore this, when we have less than 20 bytes */ - if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) - goto e400; + if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; hash = (ot_hash*)data; break; - default: - scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); - break; } } /* Scanned whole query string */ - if( !hash ) goto e400; + if( !hash ) HTTPERROR_400_PARAM; if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { remove_peer_from_torrent( hash, &peer ); reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); } else { torrent = add_peer_to_torrent( hash, &peer ); - if( !torrent ) { -e500: - return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later."); - } - if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) - goto e500; + if( !torrent || ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) HTTPERROR_500; } ot_overall_successfulannounces++; break; case 11: - if( byte_diff(data,11,"mrtg_scrape")) - goto e404; - { - time_t seconds_elapsed = time( NULL ) - ot_start_time; - reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, - "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", - ot_overall_connections, ot_overall_successfulannounces, (int)seconds_elapsed, - (int)(seconds_elapsed / 3600), (int)ot_overall_connections / ( (int)seconds_elapsed ? (int)seconds_elapsed : 1 ) ); - } + if( byte_diff(data,11,"mrtg_scrape")) HTTPERROR_404; + + t = time( NULL ) - ot_start_time; + reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, + "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", + ot_overall_connections, ot_overall_successfulannounces, (int)t, (int)(t / 3600), (int)ot_overall_connections / ( (int)t ? (int)t : 1 ) ); break; default: /* neither *scrape nor announce */ -e404: - return httperror( s, h, "404 Not Found", "No such file or directory." ); + HTTPERROR_404; } - if( reply_size ) { - /* This one is rather ugly, so I take you step by step through it. + if( reply_size <= 0 ) HTTPERROR_500; - 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to - write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string - plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate - the space NOT needed to expand in reply_off - */ - size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); + /* This one is rather ugly, so I take you step by step through it. - /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete - packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ - reply_size += 1 + sprintf( static_scratch + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); + 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to + write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string + plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate + the space NOT needed to expand in reply_off + */ + size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); - /* 3. Finally we join both blocks neatly */ - static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; + /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete + packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ + reply_size += 1 + sprintf( static_scratch + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); - senddata( s, h, static_scratch + reply_off, reply_size ); - } else { - if( h ) - array_reset( &h->request ); -#ifdef _DEBUG_FDS - if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); - fd_debug_space[s] = 0; -#endif - free( h ); io_close( s ); - } + /* 3. Finally we join both blocks neatly */ + static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; + + senddata( s, h, static_scratch + reply_off, reply_size ); } -void graceful( int s ) { +static void graceful( int s ) { if( s == SIGINT ) { signal( SIGINT, SIG_IGN); deinit_logic(); @@ -408,16 +413,7 @@ void graceful( int s ) { } } -#ifdef _DEBUG_FDS -void count_fds( int s ) { - int i, count = 0; - for( i=0; irequest ); free( h ); } -#ifdef _DEBUG_FDS - if( !fd_debug_space[clientsocket] ) fprintf( stderr, "close on non-open fd\n" ); - fd_debug_space[clientsocket] = 0; -#endif io_close( clientsocket ); return; } @@ -480,26 +472,22 @@ void handle_read( int64 clientsocket ) { httperror( clientsocket, h, "500 Server Error", "Request too long."); else if( array_bytes( &h->request ) > 8192 ) httperror( clientsocket, h, "500 request too long", "You sent too much headers"); - else if( ( l = header_complete( h ) ) ) + else if( ( l = httpheader_complete( h ) ) ) httpresponse( clientsocket, h); } -void handle_write( int64 clientsocket ) { +static void handle_write( const int64 clientsocket ) { struct http_data* h=io_getcookie( clientsocket ); if( !h ) return; if( iob_send( clientsocket, &h->batch ) <= 0 ) { iob_reset( &h->batch ); -#ifdef _DEBUG_FDS - if( !fd_debug_space[clientsocket] ) fprintf( stderr, "close on non-open fd\n" ); - fd_debug_space[clientsocket] = 0; -#endif io_close( clientsocket ); free( h ); } } -void handle_accept( int64 serversocket ) { - struct http_data* h; +static void handle_accept( const int64 serversocket ) { + struct http_data *h; unsigned char ip[4]; uint16 port; tai6464 t; @@ -513,11 +501,6 @@ void handle_accept( int64 serversocket ) { continue; } -#ifdef _DEBUG_FDS - if( fd_debug_space[i] ) fprintf( stderr, "double use of fd: %i\n", (int)i ); - fd_debug_space[i] = 1; -#endif - io_wantread( i ); byte_zero(h,sizeof(struct http_data)); @@ -531,13 +514,9 @@ void handle_accept( int64 serversocket ) { if( errno==EAGAIN ) io_eagain( serversocket ); -/* - else - carp( "socket_accept4" ); -*/ } -void handle_timeouted( ) { +static void handle_timeouted( void ) { int64 i; while( ( i = io_timeouted() ) != -1 ) { struct http_data* h=io_getcookie( i ); @@ -545,15 +524,11 @@ void handle_timeouted( ) { array_reset( &h->request ); free( h ); } -#ifdef _DEBUG_FDS - if( !fd_debug_space[i] ) fprintf( stderr, "close on non-open fd\n" ); - fd_debug_space[i] = 0; -#endif io_close(i); } } -void server_mainloop( int64 serversocket ) { +static void server_mainloop( const int64 serversocket ) { tai6464 t, next_timeout_check; io_wantread( serversocket ); @@ -626,9 +601,6 @@ int main( int argc, char **argv ) { signal( SIGPIPE, SIG_IGN ); signal( SIGINT, graceful ); -#ifdef _DEBUG_FDS - signal( SIGINFO, count_fds ); -#endif if( init_logic( serverdir ) == -1 ) panic( "Logic not started" ); diff --git a/trackerlogic.c b/trackerlogic.c index 4de5038..38de8ca 100644 --- a/trackerlogic.c +++ b/trackerlogic.c @@ -64,7 +64,7 @@ static void *binary_search( const void * const key, const void * base, const siz */ char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t>4];*t++=m[*s++&15];}*t=0;return ths+1;} -static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, int compare_size, int *exactmatch ) { +static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); if( *exactmatch ) return match; @@ -104,7 +104,7 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { } static void free_peerlist( ot_peerlist *peer_list ) { - int i; + size_t i; for( i=0; ipeers[i].data ) free( peer_list->peers[i].data ); @@ -227,9 +227,9 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { * RANDOM may return huge values * does not yet check not to return self */ -size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ) { - char *r = reply; - unsigned int peer_count, seed_count, index; +size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply ) { + char *r = reply; + size_t peer_count, seed_count, index; #ifdef WANT_CLOSED_TRACKER if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) { @@ -247,13 +247,13 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char } #endif - for( peer_count=seed_count=index=0; indexpeer_list->peers[index].size; seed_count += torrent->peer_list->seed_count[index]; } if( peer_count < amount ) amount = peer_count; - r += sprintf( r, "d8:completei%ie10:incompletei%ie8:intervali%ie5:peers%i:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); + r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); if( amount ) { unsigned int pool_offset, pool_index = 0;; unsigned int shifted_pc = peer_count; @@ -292,8 +292,9 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char /* Fetch full scrape info for all torrents */ size_t return_fullscrape_for_tracker( char **reply ) { - int torrent_count = 0, i, j, k; - char* r; + size_t torrent_count = 0, j; + int i, k; + char *r; time_t time_now = NOW; for( i=0; i<256; ++i ) { @@ -301,16 +302,15 @@ size_t return_fullscrape_for_tracker( char **reply ) { torrent_count += torrents_list->size; } - r = *reply = malloc( 128*torrent_count ); - if( !reply ) return 0; - + if( !( r = *reply = malloc( 128*torrent_count ) ) ) return 0; + memmove( r, "d5:filesd", 9 ); r += 9; for( i=0; i<256; ++i ) { ot_vector *torrents_list = &all_torrents[i]; for( j=0; jsize; ++j ) { ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; - int peers = 0, seeds = 0; + size_t peers = 0, seeds = 0; clean_peerlist( time_now, peer_list ); for( k=0; kpeers[k].size; @@ -318,7 +318,7 @@ size_t return_fullscrape_for_tracker( char **reply ) { } memmove( r, "20:", 3 ); r+=3; memmove( r, hash, 20 ); r+=20; - r += sprintf( r, "d8:completei%de10:downloadedi%de10:incompletei%de", seeds, peer_list->downloaded, peers-seeds ); + r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde", seeds, peer_list->downloaded, peers-seeds ); } } @@ -329,7 +329,8 @@ size_t return_fullscrape_for_tracker( char **reply ) { /* Fetches scrape info for a specific torrent */ size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { char *r = reply; - int exactmatch, peers = 0, seeds = 0, i; + int exactmatch, i; + size_t peers = 0, seeds = 0; ot_vector *torrents_list = &all_torrents[*hash[0]]; ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); @@ -342,20 +343,45 @@ size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { } memmove( r, "d5:filesd20:", 12 ); memmove( r+12, hash, 20 ); - r += sprintf( r+32, "d8:completei%de10:downloadedi%de10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32; + r += sprintf( r+32, "d8:completei%zde10:downloadedi%zde10:incompletei%zdeeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32; return r - reply; } +size_t return_sync_for_torrent( ot_hash *hash, char **reply ) { + int exactmatch; + size_t peers = 0; + char *r; + ot_vector *torrents_list = &all_torrents[*hash[0]]; + ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); + + if( exactmatch ) { + clean_peerlist( NOW, torrent->peer_list ); + peers = torrent->peer_list->peers[0].size; + } + + if( !( r = *reply = malloc( 10 + peers * sizeof( ot_peer ) ) ) ) return 0; + + memmove( r, "d4:sync", 7 ); + r += 7; + r += sprintf( r, "%zd:", peers * sizeof( ot_peer ) ); + if( peers ) { + memmove( r, torrent->peer_list->peers[0].data, peers * sizeof( ot_peer ) ); + r += peers * sizeof( ot_peer ); + } + *r++ = 'e'; + return r - *reply; +} + typedef struct { int val; ot_torrent * torrent; } ot_record; /* Fetches stats from tracker */ size_t return_stats_for_tracker( char *reply, int mode ) { - time_t time_now = NOW; - int torrent_count = 0, peer_count = 0, seed_count = 0; + time_t time_now = NOW; + size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; ot_record top5s[5], top5c[5]; - char *r = reply; - int i,j,k; + char *r = reply; + int i,k; byte_zero( top5s, sizeof( top5s ) ); byte_zero( top5c, sizeof( top5c ) ); @@ -365,7 +391,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { torrent_count += torrents_list->size; for( j=0; jsize; ++j ) { ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; - int local_peers = 0, local_seeds = 0; + size_t local_peers = 0, local_seeds = 0; clean_peerlist( time_now, peer_list ); for( k=0; kpeers[k].size; @@ -399,7 +425,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { if( top5s[idx].torrent ) r += sprintf( r, "\t%i\t%s\n", top5s[idx].val, to_hex(top5s[idx].torrent->hash) ); } else { - r += sprintf( r, "%i\n%i\nopentracker serving %i torrents\nSomething else.", peer_count, seed_count, torrent_count ); + r += sprintf( r, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", peer_count, seed_count, torrent_count ); } return r - reply; @@ -429,7 +455,7 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) { } } -int init_logic( char *serverdir ) { +int init_logic( const char * const serverdir ) { if( serverdir && chdir( serverdir ) ) { fprintf( stderr, "Could not chdir() to %s\n", serverdir ); return -1; @@ -443,8 +469,9 @@ int init_logic( char *serverdir ) { return 0; } -void deinit_logic( ) { - int i, j; +void deinit_logic( void ) { + int i; + size_t j; /* Free all torrents... */ for(i=0; i<256; ++i ) { diff --git a/trackerlogic.h b/trackerlogic.h index 8a61b74..083c437 100644 --- a/trackerlogic.h +++ b/trackerlogic.h @@ -64,7 +64,7 @@ static const ot_byte PEER_FLAG_STOPPED = 0x20; typedef struct { ot_time base; size_t seed_count[ OT_POOLS_COUNT ]; - unsigned int downloaded; + size_t downloaded; ot_vector peers[ OT_POOLS_COUNT ]; } ot_peerlist; @@ -77,8 +77,8 @@ typedef struct { Exported functions */ -int init_logic( char *serverdir ); -void deinit_logic( ); +int init_logic( const char * const serverdir ); +void deinit_logic( void ); #ifdef WANT_CLOSED_TRACKER extern int g_closedtracker; @@ -90,9 +90,10 @@ extern int g_check_blacklist; enum { STATS_MRTG, STATS_TOP5 }; ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ); -size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ); +size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply ); size_t return_fullscrape_for_tracker( char **reply ); size_t return_scrape_for_torrent( ot_hash *hash, char *reply ); +size_t return_sync_for_torrent( ot_hash *hash, char **reply ); size_t return_stats_for_tracker( char *reply, int mode ); void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer );