@ -26,6 +26,7 @@
# include "trackerlogic.h"
# include "trackerlogic.h"
# include "scan_urlencoded_query.h"
# include "scan_urlencoded_query.h"
/* Globals */
static unsigned int ot_overall_connections = 0 ;
static unsigned int ot_overall_connections = 0 ;
static unsigned int ot_overall_successfulannounces = 0 ;
static unsigned int ot_overall_successfulannounces = 0 ;
static time_t ot_start_time ;
static time_t ot_start_time ;
@ -34,13 +35,50 @@ static const size_t SUCCESS_HTTP_SIZE_OFF = 17;
/* To always have space for error messages ;) */
/* To always have space for error messages ;) */
static char static_scratch [ 8192 ] ;
static char static_scratch [ 8192 ] ;
# ifdef _DEBUG_FDS
static char fd_debug_space [ 0x10000 ] ;
# endif
# ifdef _DEBUG_HTTPERROR
# ifdef _DEBUG_HTTPERROR
static char debug_request [ 8192 ] ;
static char debug_request [ 8192 ] ;
# endif
# endif
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 ) {
static void carp ( const char * routine ) {
buffer_puts ( buffer_2 , routine ) ;
buffer_puts ( buffer_2 , routine ) ;
buffer_puts ( buffer_2 , " : " ) ;
buffer_puts ( buffer_2 , " : " ) ;
@ -53,16 +91,8 @@ static void panic( const char* routine ) {
exit ( 111 ) ;
exit ( 111 ) ;
}
}
struct http_data {
static int httpheader_complete ( struct http_data * h ) {
union {
size_t l = array_bytes ( & h - > request ) , i ;
array request ;
io_batch batch ;
} ;
unsigned char ip [ 4 ] ;
} ;
int header_complete ( struct http_data * h ) {
int l = array_bytes ( & h - > request ) , i ;
const char * c = array_start ( & h - > request ) ;
const char * c = array_start ( & h - > request ) ;
for ( i = 0 ; i + 1 < l ; + + i ) {
for ( i = 0 ; i + 1 < l ; + + i ) {
@ -72,16 +102,29 @@ int header_complete( struct http_data* h ) {
return 0 ;
return 0 ;
}
}
void sendmallocdata ( int64 s , struct http_data * h , char * buffer , size_t size ) {
static void httperror ( const int64 s , struct http_data * h , const char * title , const char * message ) {
size_t reply_size = sprintf ( static_scratch , " HTTP/1.0 %s \r \n Content-Type: text/html \r \n Connection: close \r \n Content-Length: %zd \r \n \r \n <title>%s</title> \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 ;
tai6464 t ;
char * header ;
char * header ;
size_t header_size ;
size_t header_size ;
if ( ! h ) { free ( buffer ) ; return ; }
if ( ! h )
return free ( buffer ) ;
array_reset ( & h - > request ) ;
array_reset ( & h - > request ) ;
header = malloc ( SUCCESS_HTTP_HEADER_LENGTH ) ;
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 \n Content-Type: text/plain \r \n Content-Length: %zd \r \n \r \n " , size ) ;
header_size = sprintf ( header , " HTTP/1.0 200 OK \r \n Content-Type: text/plain \r \n Content-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 , header , header_size ) ;
iob_addbuf_free ( & h - > batch , buffer , 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 ) ;
taia_uint ( & t , 0 ) ; io_timeout ( s , t ) ;
io_dontwantread ( s ) ;
io_dontwantread ( s ) ;
io_wantwrite ( 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 ;
size_t written_size ;
/* whoever sends data is not interested in its input-array */
/* 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 ) ;
written_size = write ( s , buffer , size ) ;
if ( ( written_size < 0 ) | | ( written_size = = 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 ) ;
free ( h ) ; io_close ( s ) ;
} else {
} else {
char * outbuf = malloc ( size - written_size ) ;
char * outbuf = malloc ( size - written_size ) ;
tai6464 t ;
tai6464 t ;
if ( ! outbuf ) {
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 ) ;
free ( h ) ; io_close ( s ) ;
return ;
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 ) ;
memmove ( outbuf , buffer + written_size , size - written_size ) ;
iob_addbuf_free ( & h - > batch , outbuf , 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 ) ;
taia_uint ( & t , 0 ) ; io_timeout ( s , t ) ;
io_dontwantread ( s ) ;
io_dontwantread ( s ) ;
io_wantwrite ( s ) ;
io_wantwrite ( s ) ;
}
}
}
}
void httperror ( int64 s , struct http_data * h , const char * title , const char * message ) {
static void httpresponse ( const int64 s , struct http_data * h ) {
size_t reply_size = sprintf ( static_scratch , " HTTP/1.0 %s \r \n Content-Type: text/html \r \n Connection: close \r \n Content-Length: %zd \r \n \r \n <title>%s</title> \n " ,
char * c , * data , * reply ;
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 ;
ot_peer peer ;
ot_peer peer ;
ot_torrent * torrent ;
ot_torrent * torrent ;
ot_hash * hash = NULL ;
ot_hash * hash = NULL ;
int numwant , tmp , scanon , mode ;
int numwant , tmp , scanon , mode ;
unsigned short port = htons ( 6881 ) ;
unsigned short port = htons ( 6881 ) ;
time_t t ;
size_t reply_size = 0 ;
size_t reply_size = 0 ;
array_cat0 ( & h - > request ) ;
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 ) ) ;
memcpy ( debug_request , array_start ( & h - > request ) , array_bytes ( & h - > request ) ) ;
# endif
# endif
if ( byte_diff ( c , 4 , " GET " ) ) {
if ( byte_diff ( c , 4 , " GET " ) ) HTTPERROR_400 ;
e400 :
return httperror ( s , h , " 400 Invalid Request " , " This server only understands GET. " ) ;
}
c + = 4 ;
c + = 4 ;
for ( data = c ; * data ! = ' ' & & * data ! = ' \t ' & & * data ! = ' \n ' & & * data ! = ' \r ' ; + + data ) ;
for ( data = c ; * data ! = ' ' & & * data ! = ' \t ' & & * data ! = ' \n ' & & * data ! = ' \r ' ; + + data ) ;
if ( * data ! = ' ' ) goto e 400;
if ( * data ! = ' ' ) HTTPERROR_ 400;
* data = 0 ;
* data = 0 ;
if ( c [ 0 ] ! = ' / ' ) goto e 404;
if ( c [ 0 ] ! = ' / ' ) HTTPERROR_ 404;
while ( * c = = ' / ' ) + + c ;
while ( * c = = ' / ' ) + + c ;
switch ( scan_urlencoded_query ( & c , data = c , SCAN_PATH ) ) {
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 ? */
case 5 : /* stats ? */
if ( byte_diff ( data , 5 , " stats " ) )
if ( byte_diff ( data , 5 , " stats " ) ) HTTPERROR_404 ;
goto e404 ;
scanon = 1 ;
scanon = 1 ;
mode = STATS_MRTG ;
mode = STATS_MRTG ;
while ( scanon ) {
while ( scanon ) {
switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_PARAM ) ) {
switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_PARAM ) ) {
case - 2 : /* terminator */
case - 2 : scanon = 0 ; break ; /* TERMINATOR */
scanon = 0 ;
case - 1 : HTTPERROR_400_PARAM ; /* PARSE ERROR */
break ;
default : scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ; break ;
case - 1 : /* error */
goto e404 ;
case 4 :
case 4 :
if ( byte_diff ( data , 4 , " mode " ) ) {
if ( byte_diff ( data , 4 , " mode " ) ) {
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
continue ;
continue ;
}
}
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
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 " ) )
if ( ! byte_diff ( data , 4 , " mrtg " ) )
mode = STATS_MRTG ;
mode = STATS_MRTG ;
else if ( ! byte_diff ( data , 4 , " top5 " ) )
else if ( ! byte_diff ( data , 4 , " top5 " ) )
mode = STATS_TOP5 ;
mode = STATS_TOP5 ;
else
else
goto e400_param ;
HTTPERROR_400_PARAM ;
default :
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
break ;
}
}
}
}
/* Enough for http header + whole scrape string */
/* Enough for http header + whole scrape string */
if ( ( reply_size = return_stats_for_tracker ( SUCCESS_HTTP_HEADER_LENGTH + static_scratch , mode ) ) < = 0 )
if ( ( reply_size = return_stats_for_tracker ( SUCCESS_HTTP_HEADER_LENGTH + static_scratch , mode ) ) < = 0 ) HTTPERROR_500 ;
goto e500 ;
break ;
break ;
case 6 : /* scrape ? */
case 6 : /* scrape ? */
if ( byte_diff ( data , 6 , " scrape " ) )
if ( byte_diff ( data , 6 , " scrape " ) ) HTTPERROR_404 ;
goto e404 ;
scanon = 1 ;
scanon = 1 ;
while ( scanon ) {
while ( scanon ) {
switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_PARAM ) ) {
switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_PARAM ) ) {
case - 2 : /* terminator */
case - 2 : scanon = 0 ; break ; /* TERMINATOR */
scanon = 0 ;
case - 1 : HTTPERROR_400_PARAM ; /* PARSE ERROR */
break ;
default : scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ; break ;
case - 1 : /* error */
goto e404 ;
case 9 :
case 9 :
if ( byte_diff ( data , 9 , " info_hash " ) ) {
if ( byte_diff ( data , 9 , " info_hash " ) ) {
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
continue ;
continue ;
}
}
/* ignore this, when we have less than 20 bytes */
/* ignore this, when we have less than 20 bytes */
if ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ! = 20 ) {
if ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ! = 20 ) HTTPERROR_400_PARAM ;
e400_param :
return httperror ( s , h , " 400 Invalid Request " , " Invalid parameter " ) ;
}
hash = ( ot_hash * ) data ; /* Fall through intended */
hash = ( ot_hash * ) data ; /* Fall through intended */
break ;
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 */
/* Scanned whole query string, no hash means full scrape... you might want to limit that */
if ( ! hash ) {
if ( ! hash ) {
char * reply ;
if ( ( reply_size = return_fullscrape_for_tracker ( & reply ) ) < = 0 ) HTTPERROR_500 ;
reply_size = return_fullscrape_for_tracker ( & reply ) ;
if ( reply_size )
return sendmallocdata ( s , h , reply , reply_size ) ;
return sendmallocdata ( s , h , reply , reply_size ) ;
}
goto e500 ;
} else {
/* Enough for http header + whole scrape string */
/* Enough for http header + whole scrape string */
if ( ( reply_size = return_scrape_for_torrent ( hash , SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) < = 0 )
if ( ( reply_size = return_scrape_for_torrent ( hash , SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) < = 0 ) HTTPERROR_500 ;
goto e500 ;
}
break ;
break ;
case 8 :
case 8 :
if ( byte_diff ( data , 8 , " announce " ) )
if ( byte_diff ( data , 8 , " announce " ) ) HTTPERROR_404 ;
goto e404 ;
OT_SETIP ( & peer , h - > ip ) ;
OT_SETIP ( & peer , h - > ip ) ;
OT_SETPORT ( & peer , & port ) ;
OT_SETPORT ( & peer , & port ) ;
@ -265,17 +294,15 @@ e400_param:
while ( scanon ) {
while ( scanon ) {
switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_PARAM ) ) {
switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_PARAM ) ) {
case - 2 : /* terminator */
case - 2 : scanon = 0 ; break ; /* TERMINATOR */
scanon = 0 ;
case - 1 : HTTPERROR_400_PARAM ; /* PARSE ERROR */
break ;
default : scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ; break ;
case - 1 : /* error */
goto e404 ;
# ifdef WANT_IP_FROM_QUERY_STRING
# ifdef WANT_IP_FROM_QUERY_STRING
case 2 :
case 2 :
if ( ! byte_diff ( data , 2 , " ip " ) ) {
if ( ! byte_diff ( data , 2 , " ip " ) ) {
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
unsigned char ip [ 4 ] ;
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 ) ;
OT_SETIP ( & peer , ip ) ;
} else
} else
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
@ -284,11 +311,11 @@ e400_param:
case 4 :
case 4 :
if ( ! byte_diff ( data , 4 , " port " ) ) {
if ( ! byte_diff ( data , 4 , " port " ) ) {
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
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 ) ;
port = htons ( tmp ) ; OT_SETPORT ( & peer , & port ) ;
} else if ( ! byte_diff ( data , 4 , " left " ) ) {
} else if ( ! byte_diff ( data , 4 , " left " ) ) {
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
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 ( scan_fixed_int ( data , len , & tmp ) ) tmp = 0 ;
if ( ! tmp ) OT_FLAG ( & peer ) | = PEER_FLAG_SEEDING ;
if ( ! tmp ) OT_FLAG ( & peer ) | = PEER_FLAG_SEEDING ;
} else
} else
@ -299,7 +326,7 @@ e400_param:
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
else switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ) {
else switch ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ) {
case - 1 :
case - 1 :
goto e400_param ;
HTTPERROR_400_PARAM ;
case 7 :
case 7 :
if ( ! byte_diff ( data , 7 , " stopped " ) ) OT_FLAG ( & peer ) | = PEER_FLAG_STOPPED ;
if ( ! byte_diff ( data , 7 , " stopped " ) ) OT_FLAG ( & peer ) | = PEER_FLAG_STOPPED ;
break ;
break ;
@ -312,13 +339,12 @@ e400_param:
case 7 :
case 7 :
if ( ! byte_diff ( data , 7 , " numwant " ) ) {
if ( ! byte_diff ( data , 7 , " numwant " ) ) {
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
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 ;
if ( numwant > 200 ) numwant = 200 ;
} else if ( ! byte_diff ( data , 7 , " compact " ) ) {
} else if ( ! byte_diff ( data , 7 , " compact " ) ) {
size_t len = scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ;
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 ( ( len < = 0 ) | | scan_fixed_int ( data , len , & tmp ) ) HTTPERROR_400_PARAM ;
if ( ! tmp )
if ( ! tmp ) HTTPERROR_400_COMPACT ;
return httperror ( s , h , " 400 Invalid Request " , " This server only delivers compact results. " ) ;
} else
} else
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
break ;
break ;
@ -328,50 +354,38 @@ e400_param:
continue ;
continue ;
}
}
/* ignore this, when we have less than 20 bytes */
/* ignore this, when we have less than 20 bytes */
if ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ! = 20 )
if ( scan_urlencoded_query ( & c , data = c , SCAN_SEARCHPATH_VALUE ) ! = 20 ) HTTPERROR_400_PARAM ;
goto e400 ;
hash = ( ot_hash * ) data ;
hash = ( ot_hash * ) data ;
break ;
break ;
default :
scan_urlencoded_query ( & c , NULL , SCAN_SEARCHPATH_VALUE ) ;
break ;
}
}
}
}
/* Scanned whole query string */
/* Scanned whole query string */
if ( ! hash ) goto e400 ;
if ( ! hash ) HTTPERROR_400_PARAM ;
if ( OT_FLAG ( & peer ) & PEER_FLAG_STOPPED ) {
if ( OT_FLAG ( & peer ) & PEER_FLAG_STOPPED ) {
remove_peer_from_torrent ( hash , & peer ) ;
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 ) ;
reply_size = sprintf ( static_scratch + SUCCESS_HTTP_HEADER_LENGTH , " d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e " , OT_CLIENT_REQUEST_INTERVAL_RANDOM ) ;
} else {
} else {
torrent = add_peer_to_torrent ( hash , & peer ) ;
torrent = add_peer_to_torrent ( hash , & peer ) ;
if ( ! torrent ) {
if ( ! torrent | | ( reply_size = return_peers_for_torrent ( torrent , numwant , SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) < = 0 ) HTTPERROR_500 ;
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 ;
}
}
ot_overall_successfulannounces + + ;
ot_overall_successfulannounces + + ;
break ;
break ;
case 11 :
case 11 :
if ( byte_diff ( data , 11 , " mrtg_scrape " ) )
if ( byte_diff ( data , 11 , " mrtg_scrape " ) ) HTTPERROR_404 ;
goto e404 ;
{
t = time ( NULL ) - ot_start_time ;
time_t seconds_elapsed = time ( NULL ) - ot_start_time ;
reply_size = sprintf ( static_scratch + SUCCESS_HTTP_HEADER_LENGTH ,
reply_size = sprintf ( static_scratch + SUCCESS_HTTP_HEADER_LENGTH ,
" %i \n %i \n Up: %i seconds (%i hours) \n Pretuned by german engineers, currently handling %i connections per second. " ,
" %i \n %i \n Up: %i seconds (%i hours) \n Pretuned by german engineers, currently handling %i connections per second. " ,
ot_overall_connections , ot_overall_successfulannounces , ( int ) seconds_elapsed ,
ot_overall_connections , ot_overall_successfulannounces , ( int ) t , ( int ) ( t / 3600 ) , ( int ) ot_overall_connections / ( ( int ) t ? ( int ) t : 1 ) ) ;
( int ) ( seconds_elapsed / 3600 ) , ( int ) ot_overall_connections / ( ( int ) seconds_elapsed ? ( int ) seconds_elapsed : 1 ) ) ;
}
break ;
break ;
default : /* neither *scrape nor announce */
default : /* neither *scrape nor announce */
e404 :
HTTPERROR_404 ;
return httperror ( s , h , " 404 Not Found " , " No such file or directory. " ) ;
}
}
if ( reply_size ) {
if ( reply_size < = 0 ) HTTPERROR_500 ;
/* This one is rather ugly, so I take you step by step through it.
/* This one is rather ugly, so I take you step by step through it.
1. In order to avoid having two buffers , one for header and one for content , we allow all above functions from trackerlogic to
1. In order to avoid having two buffers , one for header and one for content , we allow all above functions from trackerlogic to
@ -389,18 +403,9 @@ e404:
static_scratch [ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = ' \n ' ;
static_scratch [ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = ' \n ' ;
senddata ( s , h , static_scratch + reply_off , 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 ) ;
}
}
}
void graceful ( int s ) {
static void graceful ( int s ) {
if ( s = = SIGINT ) {
if ( s = = SIGINT ) {
signal ( SIGINT , SIG_IGN ) ;
signal ( SIGINT , SIG_IGN ) ;
deinit_logic ( ) ;
deinit_logic ( ) ;
@ -408,16 +413,7 @@ void graceful( int s ) {
}
}
}
}
# ifdef _DEBUG_FDS
static void usage ( char * name ) {
void count_fds ( int s ) {
int i , count = 0 ;
for ( i = 0 ; i < sizeof ( fd_debug_space ) ; + + i )
if ( fd_debug_space [ i ] ) + + count ;
fprintf ( stderr , " Open fds here: %i \n " , count ) ;
}
# endif
void usage ( char * name ) {
fprintf ( stderr , " Usage: %s [-i serverip] [-p serverport] [-d serverdirectory] "
fprintf ( stderr , " Usage: %s [-i serverip] [-p serverport] [-d serverdirectory] "
# ifdef WANT_CLOSED_TRACKER
# ifdef WANT_CLOSED_TRACKER
" [-oc] "
" [-oc] "
@ -428,7 +424,7 @@ void usage( char *name ) {
" \n " , name ) ;
" \n " , name ) ;
}
}
void help ( char * name ) {
static void help ( char * name ) {
usage ( name ) ;
usage ( name ) ;
fprintf ( stderr , " \t -i serverip \t specify ip to bind to (default: *) \n "
fprintf ( stderr , " \t -i serverip \t specify ip to bind to (default: *) \n "
" \t -p serverport \t specify port to bind to (default: 6969) \n "
" \t -p serverport \t specify port to bind to (default: 6969) \n "
@ -453,19 +449,15 @@ void help( char *name ) {
) ;
) ;
}
}
void handle_read ( int64 clientsocket ) {
static void handle_read ( const int64 clientsocket ) {
struct http_data * h = io_getcookie ( clientsocket ) ;
struct http_data * h = io_getcookie ( clientsocket ) ;
int l = io_tryread ( clientsocket , static_scratch , sizeof static_scratch ) ;
size_t l ;
if ( l < = 0 ) {
if ( ( l = io_tryread ( clientsocket , static_scratch , sizeof static_scratch ) ) < = 0 ) {
if ( h ) {
if ( h ) {
array_reset ( & h - > request ) ;
array_reset ( & h - > request ) ;
free ( h ) ;
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 ) ;
io_close ( clientsocket ) ;
return ;
return ;
}
}
@ -480,25 +472,21 @@ void handle_read( int64 clientsocket ) {
httperror ( clientsocket , h , " 500 Server Error " , " Request too long. " ) ;
httperror ( clientsocket , h , " 500 Server Error " , " Request too long. " ) ;
else if ( array_bytes ( & h - > request ) > 8192 )
else if ( array_bytes ( & h - > request ) > 8192 )
httperror ( clientsocket , h , " 500 request too long " , " You sent too much headers " ) ;
httperror ( clientsocket , h , " 500 request too long " , " You sent too much headers " ) ;
else if ( ( l = header_complete ( h ) ) )
else if ( ( l = httph eader_complete ( h ) ) )
httpresponse ( clientsocket , h ) ;
httpresponse ( clientsocket , h ) ;
}
}
void handle_write ( int64 clientsocket ) {
static void handle_write ( const int64 clientsocket ) {
struct http_data * h = io_getcookie ( clientsocket ) ;
struct http_data * h = io_getcookie ( clientsocket ) ;
if ( ! h ) return ;
if ( ! h ) return ;
if ( iob_send ( clientsocket , & h - > batch ) < = 0 ) {
if ( iob_send ( clientsocket , & h - > batch ) < = 0 ) {
iob_reset ( & h - > batch ) ;
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 ) ;
io_close ( clientsocket ) ;
free ( h ) ;
free ( h ) ;
}
}
}
}
void handle_accept ( int64 serversocket ) {
static void handle_accept ( const int64 serversocket ) {
struct http_data * h ;
struct http_data * h ;
unsigned char ip [ 4 ] ;
unsigned char ip [ 4 ] ;
uint16 port ;
uint16 port ;
@ -513,11 +501,6 @@ void handle_accept( int64 serversocket ) {
continue ;
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 ) ;
io_wantread ( i ) ;
byte_zero ( h , sizeof ( struct http_data ) ) ;
byte_zero ( h , sizeof ( struct http_data ) ) ;
@ -531,13 +514,9 @@ void handle_accept( int64 serversocket ) {
if ( errno = = EAGAIN )
if ( errno = = EAGAIN )
io_eagain ( serversocket ) ;
io_eagain ( serversocket ) ;
/*
else
carp ( " socket_accept4 " ) ;
*/
}
}
void handle_timeouted ( ) {
static void handle_timeouted ( void ) {
int64 i ;
int64 i ;
while ( ( i = io_timeouted ( ) ) ! = - 1 ) {
while ( ( i = io_timeouted ( ) ) ! = - 1 ) {
struct http_data * h = io_getcookie ( i ) ;
struct http_data * h = io_getcookie ( i ) ;
@ -545,15 +524,11 @@ void handle_timeouted( ) {
array_reset ( & h - > request ) ;
array_reset ( & h - > request ) ;
free ( h ) ;
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 ) ;
io_close ( i ) ;
}
}
}
}
void server_mainloop ( int64 serversocket ) {
static void server_mainloop ( const int64 serversocket ) {
tai6464 t , next_timeout_check ;
tai6464 t , next_timeout_check ;
io_wantread ( serversocket ) ;
io_wantread ( serversocket ) ;
@ -626,9 +601,6 @@ int main( int argc, char **argv ) {
signal ( SIGPIPE , SIG_IGN ) ;
signal ( SIGPIPE , SIG_IGN ) ;
signal ( SIGINT , graceful ) ;
signal ( SIGINT , graceful ) ;
# ifdef _DEBUG_FDS
signal ( SIGINFO , count_fds ) ;
# endif
if ( init_logic ( serverdir ) = = - 1 )
if ( init_logic ( serverdir ) = = - 1 )
panic ( " Logic not started " ) ;
panic ( " Logic not started " ) ;