diff options
| author | erdgeist <> | 2007-01-26 16:26:49 +0000 |
|---|---|---|
| committer | erdgeist <> | 2007-01-26 16:26:49 +0000 |
| commit | 05420c40e5b1660bcd9b72868b6e2a23672048ba (patch) | |
| tree | a510cbd8fa33e97f383b44b92b019c7fde421304 | |
| parent | dffea5da69b19c6812700839885c9997e73db7ec (diff) | |
Introduce another unspec'd command: sync which syncs the most recent peer pool for a torrent out. Do some variable type clean up. Do some code structure clean up.
| -rw-r--r-- | opentracker.c | 356 | ||||
| -rw-r--r-- | trackerlogic.c | 77 | ||||
| -rw-r--r-- | trackerlogic.h | 9 |
3 files changed, 221 insertions, 221 deletions
diff --git a/opentracker.c b/opentracker.c index 403fa21..9121103 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
| 2 | It is considered beerware. Prost. Skol. Cheers or whatever. | 2 | It is considered beerware. Prost. Skol. Cheers or whatever. |
| 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 | */ |
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "trackerlogic.h" | 26 | #include "trackerlogic.h" |
| 27 | #include "scan_urlencoded_query.h" | 27 | #include "scan_urlencoded_query.h" |
| 28 | 28 | ||
| 29 | /* Globals */ | ||
| 29 | static unsigned int ot_overall_connections = 0; | 30 | static unsigned int ot_overall_connections = 0; |
| 30 | static unsigned int ot_overall_successfulannounces = 0; | 31 | static unsigned int ot_overall_successfulannounces = 0; |
| 31 | static time_t ot_start_time; | 32 | static time_t ot_start_time; |
| @@ -34,35 +35,64 @@ static const size_t SUCCESS_HTTP_SIZE_OFF = 17; | |||
| 34 | /* To always have space for error messages ;) */ | 35 | /* To always have space for error messages ;) */ |
| 35 | static char static_scratch[8192]; | 36 | static char static_scratch[8192]; |
| 36 | 37 | ||
| 37 | #ifdef _DEBUG_FDS | ||
| 38 | static char fd_debug_space[0x10000]; | ||
| 39 | #endif | ||
| 40 | #ifdef _DEBUG_HTTPERROR | 38 | #ifdef _DEBUG_HTTPERROR |
| 41 | static char debug_request[8192]; | 39 | static char debug_request[8192]; |
| 42 | #endif | 40 | #endif |
| 43 | 41 | ||
| 44 | static void carp(const char* routine ) { | 42 | struct http_data { |
| 43 | union { | ||
| 44 | array request; | ||
| 45 | io_batch batch; | ||
| 46 | }; | ||
| 47 | unsigned char ip[4]; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /* Prototypes */ | ||
| 51 | |||
| 52 | int main( int argc, char **argv ); | ||
| 53 | |||
| 54 | static int httpheader_complete( struct http_data *h ); | ||
| 55 | static void httperror( const int64 s, struct http_data *h, const char *title, const char *message ); | ||
| 56 | static void httpresponse( const int64 s, struct http_data *h); | ||
| 57 | |||
| 58 | static void sendmallocdata( const int64 s, struct http_data *h, char *buffer, const size_t size ); | ||
| 59 | static void senddata( const int64 s, struct http_data *h, char *buffer, const size_t size ); | ||
| 60 | |||
| 61 | static void server_mainloop( const int64 serversocket ); | ||
| 62 | static void handle_timeouted( void ); | ||
| 63 | static void handle_accept( const int64 serversocket ); | ||
| 64 | static void handle_read( const int64 clientsocket ); | ||
| 65 | static void handle_write( const int64 clientsocket ); | ||
| 66 | |||
| 67 | static void usage( char *name ); | ||
| 68 | static void help( char *name ); | ||
| 69 | |||
| 70 | static void carp( const char *routine ); | ||
| 71 | static void panic( const char *routine ); | ||
| 72 | static void graceful( int s ); | ||
| 73 | |||
| 74 | #define HTTPERROR_400 return httperror( s, h, "400 Invalid Request", "This server only understands GET." ) | ||
| 75 | #define HTTPERROR_400_PARAM return httperror( s, h, "400 Invalid Request", "Invalid parameter" ) | ||
| 76 | #define HTTPERROR_400_COMPACT return httperror( s, h, "400 Invalid Request", "This server only delivers compact results." ) | ||
| 77 | #define HTTPERROR_404 return httperror( s, h, "404 Not Found", "No such file or directory." ) | ||
| 78 | #define HTTPERROR_500 return httperror( s, h, "500 Internal Server Error", "A server error has occured. Please retry later." ) | ||
| 79 | |||
| 80 | /* End of prototypes */ | ||
| 81 | |||
| 82 | static void carp( const char *routine ) { | ||
| 45 | buffer_puts( buffer_2, routine ); | 83 | buffer_puts( buffer_2, routine ); |
| 46 | buffer_puts( buffer_2, ": " ); | 84 | buffer_puts( buffer_2, ": " ); |
| 47 | buffer_puterror( buffer_2 ); | 85 | buffer_puterror( buffer_2 ); |
| 48 | buffer_putnlflush( buffer_2 ); | 86 | buffer_putnlflush( buffer_2 ); |
| 49 | } | 87 | } |
| 50 | 88 | ||
| 51 | static void panic( const char* routine ) { | 89 | static void panic( const char *routine ) { |
| 52 | carp( routine ); | 90 | carp( routine ); |
| 53 | exit( 111 ); | 91 | exit( 111 ); |
| 54 | } | 92 | } |
| 55 | 93 | ||
| 56 | struct http_data { | 94 | static int httpheader_complete( struct http_data *h ) { |
| 57 | union { | 95 | size_t l = array_bytes( &h->request ), i; |
| 58 | array request; | ||
| 59 | io_batch batch; | ||
| 60 | }; | ||
| 61 | unsigned char ip[4]; | ||
| 62 | }; | ||
| 63 | |||
| 64 | int header_complete( struct http_data* h ) { | ||
| 65 | int l = array_bytes( &h->request ), i; | ||
| 66 | const char* c = array_start( &h->request ); | 96 | const char* c = array_start( &h->request ); |
| 67 | 97 | ||
| 68 | for( i=0; i+1<l; ++i) { | 98 | for( i=0; i+1<l; ++i) { |
| @@ -72,16 +102,29 @@ int header_complete( struct http_data* h ) { | |||
| 72 | return 0; | 102 | return 0; |
| 73 | } | 103 | } |
| 74 | 104 | ||
| 75 | void sendmallocdata( int64 s, struct http_data *h, char * buffer, size_t size ) { | 105 | static void httperror( const int64 s, struct http_data *h, const char *title, const char *message ) { |
| 106 | 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<title>%s</title>\n", | ||
| 107 | title, strlen(message)+strlen(title)+16-4,title+4); | ||
| 108 | #ifdef _DEBUG_HTTPERROR | ||
| 109 | fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); | ||
| 110 | #endif | ||
| 111 | senddata(s,h,static_scratch,reply_size); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void sendmallocdata( const int64 s, struct http_data *h, char *buffer, size_t size ) { | ||
| 76 | tai6464 t; | 115 | tai6464 t; |
| 77 | char *header; | 116 | char *header; |
| 78 | size_t header_size; | 117 | size_t header_size; |
| 79 | 118 | ||
| 80 | if( !h ) { free( buffer); return; } | 119 | if( !h ) |
| 120 | return free( buffer); | ||
| 81 | array_reset( &h->request ); | 121 | array_reset( &h->request ); |
| 82 | 122 | ||
| 83 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH ); | 123 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH ); |
| 84 | if( !header ) { free( buffer ); return; } | 124 | if( !header ) { |
| 125 | free( buffer ); | ||
| 126 | HTTPERROR_500; | ||
| 127 | } | ||
| 85 | 128 | ||
| 86 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); | 129 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); |
| 87 | 130 | ||
| @@ -89,13 +132,13 @@ void sendmallocdata( int64 s, struct http_data *h, char * buffer, size_t size ) | |||
| 89 | iob_addbuf_free( &h->batch, header, header_size ); | 132 | iob_addbuf_free( &h->batch, header, header_size ); |
| 90 | iob_addbuf_free( &h->batch, buffer, size ); | 133 | iob_addbuf_free( &h->batch, buffer, size ); |
| 91 | 134 | ||
| 92 | // writeable sockets just have a tcp timeout | 135 | /* writeable sockets just have a tcp timeout */ |
| 93 | taia_uint(&t,0); io_timeout( s, t ); | 136 | taia_uint(&t,0); io_timeout( s, t ); |
| 94 | io_dontwantread( s ); | 137 | io_dontwantread( s ); |
| 95 | io_wantwrite( s ); | 138 | io_wantwrite( s ); |
| 96 | } | 139 | } |
| 97 | 140 | ||
| 98 | void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { | 141 | static void senddata( const int64 s, struct http_data *h, char *buffer, size_t size ) { |
| 99 | size_t written_size; | 142 | size_t written_size; |
| 100 | 143 | ||
| 101 | /* whoever sends data is not interested in its input-array */ | 144 | /* 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 ) { | |||
| 104 | 147 | ||
| 105 | written_size = write( s, buffer, size ); | 148 | written_size = write( s, buffer, size ); |
| 106 | if( ( written_size < 0 ) || ( written_size == size ) ) { | 149 | if( ( written_size < 0 ) || ( written_size == size ) ) { |
| 107 | #ifdef _DEBUG_FDS | ||
| 108 | if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); | ||
| 109 | fd_debug_space[s] = 0; | ||
| 110 | #endif | ||
| 111 | free( h ); io_close( s ); | 150 | free( h ); io_close( s ); |
| 112 | } else { | 151 | } else { |
| 113 | char * outbuf = malloc( size - written_size ); | 152 | char * outbuf = malloc( size - written_size ); |
| 114 | tai6464 t; | 153 | tai6464 t; |
| 115 | 154 | ||
| 116 | if( !outbuf ) { | 155 | if( !outbuf ) { |
| 117 | #ifdef _DEBUG_FDS | ||
| 118 | if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); | ||
| 119 | fd_debug_space[s] = 0; | ||
| 120 | #endif | ||
| 121 | free(h); io_close( s ); | 156 | free(h); io_close( s ); |
| 122 | return; | 157 | return; |
| 123 | } | 158 | } |
| @@ -126,29 +161,21 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { | |||
| 126 | memmove( outbuf, buffer + written_size, size - written_size ); | 161 | memmove( outbuf, buffer + written_size, size - written_size ); |
| 127 | iob_addbuf_free( &h->batch, outbuf, size - written_size ); | 162 | iob_addbuf_free( &h->batch, outbuf, size - written_size ); |
| 128 | 163 | ||
| 129 | // writeable sockets just have a tcp timeout | 164 | /* writeable sockets just have a tcp timeout */ |
| 130 | taia_uint( &t, 0 ); io_timeout( s, t ); | 165 | taia_uint( &t, 0 ); io_timeout( s, t ); |
| 131 | io_dontwantread( s ); | 166 | io_dontwantread( s ); |
| 132 | io_wantwrite( s ); | 167 | io_wantwrite( s ); |
| 133 | } | 168 | } |
| 134 | } | 169 | } |
| 135 | 170 | ||
| 136 | void httperror(int64 s,struct http_data* h,const char* title,const char* message) { | 171 | static void httpresponse( const int64 s, struct http_data *h) { |
| 137 | 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<title>%s</title>\n", | 172 | char *c, *data, *reply; |
| 138 | title, strlen(message)+strlen(title)+16-4,title+4); | ||
| 139 | #ifdef _DEBUG_HTTPERROR | ||
| 140 | fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); | ||
| 141 | #endif | ||
| 142 | senddata(s,h,static_scratch,reply_size); | ||
| 143 | } | ||
| 144 | |||
| 145 | void httpresponse( int64 s, struct http_data* h) { | ||
| 146 | char *c, *data; | ||
| 147 | ot_peer peer; | 173 | ot_peer peer; |
| 148 | ot_torrent *torrent; | 174 | ot_torrent *torrent; |
| 149 | ot_hash *hash = NULL; | 175 | ot_hash *hash = NULL; |
| 150 | int numwant, tmp, scanon, mode; | 176 | int numwant, tmp, scanon, mode; |
| 151 | unsigned short port = htons(6881); | 177 | unsigned short port = htons(6881); |
| 178 | time_t t; | ||
| 152 | size_t reply_size = 0; | 179 | size_t reply_size = 0; |
| 153 | 180 | ||
| 154 | array_cat0( &h->request ); | 181 | array_cat0( &h->request ); |
| @@ -158,104 +185,106 @@ void httpresponse( int64 s, struct http_data* h) { | |||
| 158 | memcpy( debug_request, array_start( &h->request ), array_bytes( &h->request ) ); | 185 | memcpy( debug_request, array_start( &h->request ), array_bytes( &h->request ) ); |
| 159 | #endif | 186 | #endif |
| 160 | 187 | ||
| 161 | if( byte_diff( c, 4, "GET ") ) { | 188 | if( byte_diff( c, 4, "GET ") ) HTTPERROR_400; |
| 162 | e400: | ||
| 163 | return httperror( s, h, "400 Invalid Request", "This server only understands GET." ); | ||
| 164 | } | ||
| 165 | 189 | ||
| 166 | c+=4; | 190 | c+=4; |
| 167 | for( data = c; *data!=' ' && *data != '\t' && *data != '\n' && *data != '\r'; ++data ) ; | 191 | for( data = c; *data!=' ' && *data != '\t' && *data != '\n' && *data != '\r'; ++data ) ; |
| 168 | 192 | ||
| 169 | if( *data != ' ' ) goto e400; | 193 | if( *data != ' ' ) HTTPERROR_400; |
| 170 | *data = 0; | 194 | *data = 0; |
| 171 | if( c[0] != '/' ) goto e404; | 195 | if( c[0] != '/' ) HTTPERROR_404; |
| 172 | while( *c == '/' ) ++c; | 196 | while( *c == '/' ) ++c; |
| 173 | 197 | ||
| 174 | switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { | 198 | switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { |
| 199 | case 4: /* sync ? */ | ||
| 200 | if( byte_diff( data, 4, "sync") ) HTTPERROR_404; | ||
| 201 | scanon = 1; | ||
| 202 | |||
| 203 | while( scanon ) { | ||
| 204 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | ||
| 205 | case -2: scanon = 0; break; /* TERMINATOR */ | ||
| 206 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | ||
| 207 | case 9: | ||
| 208 | if(byte_diff(data,9,"info_hash")) { | ||
| 209 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
| 210 | continue; | ||
| 211 | } | ||
| 212 | /* ignore this, when we have less than 20 bytes */ | ||
| 213 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; | ||
| 214 | hash = (ot_hash*)data; /* Fall through intended */ | ||
| 215 | break; | ||
| 216 | default: | ||
| 217 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | if( !hash ) HTTPERROR_400_PARAM; | ||
| 223 | if( ( reply_size = return_sync_for_torrent( hash, &reply ) ) <= 0 ) HTTPERROR_500; | ||
| 224 | |||
| 225 | return sendmallocdata( s, h, reply, reply_size ); | ||
| 175 | case 5: /* stats ? */ | 226 | case 5: /* stats ? */ |
| 176 | if( byte_diff(data,5,"stats")) | 227 | if( byte_diff(data,5,"stats")) HTTPERROR_404; |
| 177 | goto e404; | ||
| 178 | scanon = 1; | 228 | scanon = 1; |
| 179 | mode = STATS_MRTG; | 229 | mode = STATS_MRTG; |
| 180 | 230 | ||
| 181 | while( scanon ) { | 231 | while( scanon ) { |
| 182 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 232 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { |
| 183 | case -2: /* terminator */ | 233 | case -2: scanon = 0; break; /* TERMINATOR */ |
| 184 | scanon = 0; | 234 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
| 185 | break; | 235 | default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; |
| 186 | case -1: /* error */ | ||
| 187 | goto e404; | ||
| 188 | case 4: | 236 | case 4: |
| 189 | if( byte_diff(data,4,"mode")) { | 237 | if( byte_diff(data,4,"mode")) { |
| 190 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 238 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
| 191 | continue; | 239 | continue; |
| 192 | } | 240 | } |
| 193 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 241 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
| 194 | if( len <= 0 ) goto e400_param; | 242 | if( len <= 0 ) HTTPERROR_400_PARAM; |
| 195 | if( !byte_diff(data,4,"mrtg")) | 243 | if( !byte_diff(data,4,"mrtg")) |
| 196 | mode = STATS_MRTG; | 244 | mode = STATS_MRTG; |
| 197 | else if( !byte_diff(data,4,"top5")) | 245 | else if( !byte_diff(data,4,"top5")) |
| 198 | mode = STATS_TOP5; | 246 | mode = STATS_TOP5; |
| 199 | else | 247 | else |
| 200 | goto e400_param; | 248 | HTTPERROR_400_PARAM; |
| 201 | default: | ||
| 202 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
| 203 | break; | ||
| 204 | } | 249 | } |
| 205 | } | 250 | } |
| 206 | 251 | ||
| 207 | /* Enough for http header + whole scrape string */ | 252 | /* Enough for http header + whole scrape string */ |
| 208 | if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) | 253 | if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) HTTPERROR_500; |
| 209 | goto e500; | 254 | |
| 210 | break; | 255 | break; |
| 211 | case 6: /* scrape ? */ | 256 | case 6: /* scrape ? */ |
| 212 | if( byte_diff( data, 6, "scrape") ) | 257 | if( byte_diff( data, 6, "scrape") ) HTTPERROR_404; |
| 213 | goto e404; | ||
| 214 | scanon = 1; | 258 | scanon = 1; |
| 215 | 259 | ||
| 216 | while( scanon ) { | 260 | while( scanon ) { |
| 217 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 261 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { |
| 218 | case -2: /* terminator */ | 262 | case -2: scanon = 0; break; /* TERMINATOR */ |
| 219 | scanon = 0; | 263 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
| 220 | break; | 264 | default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; |
| 221 | case -1: /* error */ | ||
| 222 | goto e404; | ||
| 223 | case 9: | 265 | case 9: |
| 224 | if(byte_diff(data,9,"info_hash")) { | 266 | if(byte_diff(data,9,"info_hash")) { |
| 225 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 267 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
| 226 | continue; | 268 | continue; |
| 227 | } | 269 | } |
| 228 | /* ignore this, when we have less than 20 bytes */ | 270 | /* ignore this, when we have less than 20 bytes */ |
| 229 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) { | 271 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; |
| 230 | e400_param: | ||
| 231 | return httperror(s,h,"400 Invalid Request","Invalid parameter"); | ||
| 232 | } | ||
| 233 | hash = (ot_hash*)data; /* Fall through intended */ | 272 | hash = (ot_hash*)data; /* Fall through intended */ |
| 234 | break; | 273 | break; |
| 235 | default: | ||
| 236 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
| 237 | break; | ||
| 238 | } | 274 | } |
| 239 | } | 275 | } |
| 240 | 276 | ||
| 241 | /* Scanned whole query string, no hash means full scrape... you might want to limit that */ | 277 | /* Scanned whole query string, no hash means full scrape... you might want to limit that */ |
| 242 | if( !hash ) { | 278 | if( !hash ) { |
| 243 | char * reply; | 279 | if( ( reply_size = return_fullscrape_for_tracker( &reply ) ) <= 0 ) HTTPERROR_500; |
| 244 | 280 | return sendmallocdata( s, h, reply, reply_size ); | |
| 245 | reply_size = return_fullscrape_for_tracker( &reply ); | ||
| 246 | if( reply_size ) | ||
| 247 | return sendmallocdata( s, h, reply, reply_size ); | ||
| 248 | |||
| 249 | goto e500; | ||
| 250 | } else { | ||
| 251 | /* Enough for http header + whole scrape string */ | ||
| 252 | if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) | ||
| 253 | goto e500; | ||
| 254 | } | 281 | } |
| 282 | |||
| 283 | /* Enough for http header + whole scrape string */ | ||
| 284 | if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) HTTPERROR_500; | ||
| 255 | break; | 285 | break; |
| 256 | case 8: | 286 | case 8: |
| 257 | if( byte_diff(data,8,"announce")) | 287 | if( byte_diff(data,8,"announce")) HTTPERROR_404; |
| 258 | goto e404; | ||
| 259 | 288 | ||
| 260 | OT_SETIP( &peer, h->ip); | 289 | OT_SETIP( &peer, h->ip); |
| 261 | OT_SETPORT( &peer, &port ); | 290 | OT_SETPORT( &peer, &port ); |
| @@ -265,17 +294,15 @@ e400_param: | |||
| 265 | 294 | ||
| 266 | while( scanon ) { | 295 | while( scanon ) { |
| 267 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 296 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { |
| 268 | case -2: /* terminator */ | 297 | case -2: scanon = 0; break; /* TERMINATOR */ |
| 269 | scanon = 0; | 298 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
| 270 | break; | 299 | default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; |
| 271 | case -1: /* error */ | ||
| 272 | goto e404; | ||
| 273 | #ifdef WANT_IP_FROM_QUERY_STRING | 300 | #ifdef WANT_IP_FROM_QUERY_STRING |
| 274 | case 2: | 301 | case 2: |
| 275 | if(!byte_diff(data,2,"ip")) { | 302 | if(!byte_diff(data,2,"ip")) { |
| 276 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 303 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
| 277 | unsigned char ip[4]; | 304 | unsigned char ip[4]; |
| 278 | if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param; | 305 | if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) HTTPERROR_400_PARAM; |
| 279 | OT_SETIP( &peer, ip ); | 306 | OT_SETIP( &peer, ip ); |
| 280 | } else | 307 | } else |
| 281 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 308 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
| @@ -284,11 +311,11 @@ e400_param: | |||
| 284 | case 4: | 311 | case 4: |
| 285 | if(!byte_diff(data,4,"port")) { | 312 | if(!byte_diff(data,4,"port")) { |
| 286 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 313 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
| 287 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param; | 314 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; |
| 288 | port = htons( tmp ); OT_SETPORT( &peer, &port ); | 315 | port = htons( tmp ); OT_SETPORT( &peer, &port ); |
| 289 | } else if(!byte_diff(data,4,"left")) { | 316 | } else if(!byte_diff(data,4,"left")) { |
| 290 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 317 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
| 291 | if( len <= 0 ) goto e400_param; | 318 | if( len <= 0 ) HTTPERROR_400_PARAM; |
| 292 | if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; | 319 | if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; |
| 293 | if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING; | 320 | if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING; |
| 294 | } else | 321 | } else |
| @@ -299,7 +326,7 @@ e400_param: | |||
| 299 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 326 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
| 300 | else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { | 327 | else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { |
| 301 | case -1: | 328 | case -1: |
| 302 | goto e400_param; | 329 | HTTPERROR_400_PARAM; |
| 303 | case 7: | 330 | case 7: |
| 304 | if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; | 331 | if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; |
| 305 | break; | 332 | break; |
| @@ -312,13 +339,12 @@ e400_param: | |||
| 312 | case 7: | 339 | case 7: |
| 313 | if(!byte_diff(data,7,"numwant")) { | 340 | if(!byte_diff(data,7,"numwant")) { |
| 314 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 341 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
| 315 | if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param; | 342 | if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) HTTPERROR_400_PARAM; |
| 316 | if( numwant > 200 ) numwant = 200; | 343 | if( numwant > 200 ) numwant = 200; |
| 317 | } else if(!byte_diff(data,7,"compact")) { | 344 | } else if(!byte_diff(data,7,"compact")) { |
| 318 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 345 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
| 319 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param; | 346 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) HTTPERROR_400_PARAM; |
| 320 | if( !tmp ) | 347 | if( !tmp ) HTTPERROR_400_COMPACT; |
| 321 | return httperror(s,h,"400 Invalid Request","This server only delivers compact results."); | ||
| 322 | } else | 348 | } else |
| 323 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 349 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
| 324 | break; | 350 | break; |
| @@ -328,79 +354,58 @@ e400_param: | |||
| 328 | continue; | 354 | continue; |
| 329 | } | 355 | } |
| 330 | /* ignore this, when we have less than 20 bytes */ | 356 | /* ignore this, when we have less than 20 bytes */ |
| 331 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) | 357 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; |
| 332 | goto e400; | ||
| 333 | hash = (ot_hash*)data; | 358 | hash = (ot_hash*)data; |
| 334 | break; | 359 | break; |
| 335 | default: | ||
| 336 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
| 337 | break; | ||
| 338 | } | 360 | } |
| 339 | } | 361 | } |
| 340 | 362 | ||
| 341 | /* Scanned whole query string */ | 363 | /* Scanned whole query string */ |
| 342 | if( !hash ) goto e400; | 364 | if( !hash ) HTTPERROR_400_PARAM; |
| 343 | 365 | ||
| 344 | if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { | 366 | if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { |
| 345 | remove_peer_from_torrent( hash, &peer ); | 367 | remove_peer_from_torrent( hash, &peer ); |
| 346 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 368 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
| 347 | } else { | 369 | } else { |
| 348 | torrent = add_peer_to_torrent( hash, &peer ); | 370 | torrent = add_peer_to_torrent( hash, &peer ); |
| 349 | if( !torrent ) { | 371 | if( !torrent || ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) HTTPERROR_500; |
| 350 | e500: | ||
| 351 | return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later."); | ||
| 352 | } | ||
| 353 | if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) | ||
| 354 | goto e500; | ||
| 355 | } | 372 | } |
| 356 | ot_overall_successfulannounces++; | 373 | ot_overall_successfulannounces++; |
| 357 | break; | 374 | break; |
| 358 | case 11: | 375 | case 11: |
| 359 | if( byte_diff(data,11,"mrtg_scrape")) | 376 | if( byte_diff(data,11,"mrtg_scrape")) HTTPERROR_404; |
| 360 | goto e404; | 377 | |
| 361 | { | 378 | t = time( NULL ) - ot_start_time; |
| 362 | time_t seconds_elapsed = time( NULL ) - ot_start_time; | 379 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, |
| 363 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, | 380 | "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", |
| 364 | "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", | 381 | ot_overall_connections, ot_overall_successfulannounces, (int)t, (int)(t / 3600), (int)ot_overall_connections / ( (int)t ? (int)t : 1 ) ); |
| 365 | ot_overall_connections, ot_overall_successfulannounces, (int)seconds_elapsed, | ||
| 366 | (int)(seconds_elapsed / 3600), (int)ot_overall_connections / ( (int)seconds_elapsed ? (int)seconds_elapsed : 1 ) ); | ||
| 367 | } | ||
| 368 | break; | 382 | break; |
| 369 | default: /* neither *scrape nor announce */ | 383 | default: /* neither *scrape nor announce */ |
| 370 | e404: | 384 | HTTPERROR_404; |
| 371 | return httperror( s, h, "404 Not Found", "No such file or directory." ); | ||
| 372 | } | 385 | } |
| 373 | 386 | ||
| 374 | if( reply_size ) { | 387 | if( reply_size <= 0 ) HTTPERROR_500; |
| 375 | /* This one is rather ugly, so I take you step by step through it. | ||
| 376 | 388 | ||
| 377 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to | 389 | /* This one is rather ugly, so I take you step by step through it. |
| 378 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string | ||
| 379 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate | ||
| 380 | the space NOT needed to expand in reply_off | ||
| 381 | */ | ||
| 382 | size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); | ||
| 383 | 390 | ||
| 384 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete | 391 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to |
| 385 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ | 392 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string |
| 386 | 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 ); | 393 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate |
| 394 | the space NOT needed to expand in reply_off | ||
| 395 | */ | ||
| 396 | size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); | ||
| 387 | 397 | ||
| 388 | /* 3. Finally we join both blocks neatly */ | 398 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete |
| 389 | static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; | 399 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ |
| 400 | 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 ); | ||
| 390 | 401 | ||
| 391 | senddata( s, h, static_scratch + reply_off, reply_size ); | 402 | /* 3. Finally we join both blocks neatly */ |
| 392 | } else { | 403 | static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; |
| 393 | if( h ) | 404 | |
| 394 | array_reset( &h->request ); | 405 | senddata( s, h, static_scratch + reply_off, reply_size ); |
| 395 | #ifdef _DEBUG_FDS | ||
| 396 | if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); | ||
| 397 | fd_debug_space[s] = 0; | ||
| 398 | #endif | ||
| 399 | free( h ); io_close( s ); | ||
| 400 | } | ||
| 401 | } | 406 | } |
| 402 | 407 | ||
| 403 | void graceful( int s ) { | 408 | static void graceful( int s ) { |
| 404 | if( s == SIGINT ) { | 409 | if( s == SIGINT ) { |
| 405 | signal( SIGINT, SIG_IGN); | 410 | signal( SIGINT, SIG_IGN); |
| 406 | deinit_logic(); | 411 | deinit_logic(); |
| @@ -408,16 +413,7 @@ void graceful( int s ) { | |||
| 408 | } | 413 | } |
| 409 | } | 414 | } |
| 410 | 415 | ||
| 411 | #ifdef _DEBUG_FDS | 416 | static void usage( char *name ) { |
| 412 | void count_fds( int s ) { | ||
| 413 | int i, count = 0; | ||
| 414 | for( i=0; i<sizeof(fd_debug_space); ++i ) | ||
| 415 | if( fd_debug_space[i] ) ++count; | ||
| 416 | fprintf( stderr, "Open fds here: %i\n", count ); | ||
| 417 | } | ||
| 418 | #endif | ||
| 419 | |||
| 420 | void usage( char *name ) { | ||
| 421 | fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]" | 417 | fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]" |
| 422 | #ifdef WANT_CLOSED_TRACKER | 418 | #ifdef WANT_CLOSED_TRACKER |
| 423 | " [-oc]" | 419 | " [-oc]" |
| @@ -428,7 +424,7 @@ void usage( char *name ) { | |||
| 428 | "\n", name ); | 424 | "\n", name ); |
| 429 | } | 425 | } |
| 430 | 426 | ||
| 431 | void help( char *name ) { | 427 | static void help( char *name ) { |
| 432 | usage( name ); | 428 | usage( name ); |
| 433 | fprintf( stderr, "\t-i serverip\tspecify ip to bind to (default: *)\n" | 429 | fprintf( stderr, "\t-i serverip\tspecify ip to bind to (default: *)\n" |
| 434 | "\t-p serverport\tspecify port to bind to (default: 6969)\n" | 430 | "\t-p serverport\tspecify port to bind to (default: 6969)\n" |
| @@ -453,19 +449,15 @@ void help( char *name ) { | |||
| 453 | ); | 449 | ); |
| 454 | } | 450 | } |
| 455 | 451 | ||
| 456 | void handle_read( int64 clientsocket ) { | 452 | static void handle_read( const int64 clientsocket ) { |
| 457 | struct http_data* h = io_getcookie( clientsocket ); | 453 | struct http_data* h = io_getcookie( clientsocket ); |
| 458 | int l = io_tryread( clientsocket, static_scratch, sizeof static_scratch ); | 454 | size_t l; |
| 459 | 455 | ||
| 460 | if( l <= 0 ) { | 456 | if( ( l = io_tryread( clientsocket, static_scratch, sizeof static_scratch ) ) <= 0 ) { |
| 461 | if( h ) { | 457 | if( h ) { |
| 462 | array_reset( &h->request ); | 458 | array_reset( &h->request ); |
| 463 | free( h ); | 459 | free( h ); |
| 464 | } | 460 | } |
| 465 | #ifdef _DEBUG_FDS | ||
| 466 | if( !fd_debug_space[clientsocket] ) fprintf( stderr, "close on non-open fd\n" ); | ||
| 467 | fd_debug_space[clientsocket] = 0; | ||
| 468 | #endif | ||
| 469 | io_close( clientsocket ); | 461 | io_close( clientsocket ); |
| 470 | return; | 462 | return; |
| 471 | } | 463 | } |
| @@ -480,26 +472,22 @@ void handle_read( int64 clientsocket ) { | |||
| 480 | httperror( clientsocket, h, "500 Server Error", "Request too long."); | 472 | httperror( clientsocket, h, "500 Server Error", "Request too long."); |
| 481 | else if( array_bytes( &h->request ) > 8192 ) | 473 | else if( array_bytes( &h->request ) > 8192 ) |
| 482 | httperror( clientsocket, h, "500 request too long", "You sent too much headers"); | 474 | httperror( clientsocket, h, "500 request too long", "You sent too much headers"); |
| 483 | else if( ( l = header_complete( h ) ) ) | 475 | else if( ( l = httpheader_complete( h ) ) ) |
| 484 | httpresponse( clientsocket, h); | 476 | httpresponse( clientsocket, h); |
| 485 | } | 477 | } |
| 486 | 478 | ||
| 487 | void handle_write( int64 clientsocket ) { | 479 | static void handle_write( const int64 clientsocket ) { |
| 488 | struct http_data* h=io_getcookie( clientsocket ); | 480 | struct http_data* h=io_getcookie( clientsocket ); |
| 489 | if( !h ) return; | 481 | if( !h ) return; |
| 490 | if( iob_send( clientsocket, &h->batch ) <= 0 ) { | 482 | if( iob_send( clientsocket, &h->batch ) <= 0 ) { |
| 491 | iob_reset( &h->batch ); | 483 | iob_reset( &h->batch ); |
| 492 | #ifdef _DEBUG_FDS | ||
| 493 | if( !fd_debug_space[clientsocket] ) fprintf( stderr, "close on non-open fd\n" ); | ||
| 494 | fd_debug_space[clientsocket] = 0; | ||
| 495 | #endif | ||
| 496 | io_close( clientsocket ); | 484 | io_close( clientsocket ); |
| 497 | free( h ); | 485 | free( h ); |
| 498 | } | 486 | } |
| 499 | } | 487 | } |
| 500 | 488 | ||
| 501 | void handle_accept( int64 serversocket ) { | 489 | static void handle_accept( const int64 serversocket ) { |
| 502 | struct http_data* h; | 490 | struct http_data *h; |
| 503 | unsigned char ip[4]; | 491 | unsigned char ip[4]; |
| 504 | uint16 port; | 492 | uint16 port; |
| 505 | tai6464 t; | 493 | tai6464 t; |
| @@ -513,11 +501,6 @@ void handle_accept( int64 serversocket ) { | |||
| 513 | continue; | 501 | continue; |
| 514 | } | 502 | } |
| 515 | 503 | ||
| 516 | #ifdef _DEBUG_FDS | ||
| 517 | if( fd_debug_space[i] ) fprintf( stderr, "double use of fd: %i\n", (int)i ); | ||
| 518 | fd_debug_space[i] = 1; | ||
| 519 | #endif | ||
| 520 | |||
| 521 | io_wantread( i ); | 504 | io_wantread( i ); |
| 522 | 505 | ||
| 523 | byte_zero(h,sizeof(struct http_data)); | 506 | byte_zero(h,sizeof(struct http_data)); |
| @@ -531,13 +514,9 @@ void handle_accept( int64 serversocket ) { | |||
| 531 | 514 | ||
| 532 | if( errno==EAGAIN ) | 515 | if( errno==EAGAIN ) |
| 533 | io_eagain( serversocket ); | 516 | io_eagain( serversocket ); |
| 534 | /* | ||
| 535 | else | ||
| 536 | carp( "socket_accept4" ); | ||
| 537 | */ | ||
| 538 | } | 517 | } |
| 539 | 518 | ||
| 540 | void handle_timeouted( ) { | 519 | static void handle_timeouted( void ) { |
| 541 | int64 i; | 520 | int64 i; |
| 542 | while( ( i = io_timeouted() ) != -1 ) { | 521 | while( ( i = io_timeouted() ) != -1 ) { |
| 543 | struct http_data* h=io_getcookie( i ); | 522 | struct http_data* h=io_getcookie( i ); |
| @@ -545,15 +524,11 @@ void handle_timeouted( ) { | |||
| 545 | array_reset( &h->request ); | 524 | array_reset( &h->request ); |
| 546 | free( h ); | 525 | free( h ); |
| 547 | } | 526 | } |
| 548 | #ifdef _DEBUG_FDS | ||
| 549 | if( !fd_debug_space[i] ) fprintf( stderr, "close on non-open fd\n" ); | ||
| 550 | fd_debug_space[i] = 0; | ||
| 551 | #endif | ||
| 552 | io_close(i); | 527 | io_close(i); |
| 553 | } | 528 | } |
| 554 | } | 529 | } |
| 555 | 530 | ||
| 556 | void server_mainloop( int64 serversocket ) { | 531 | static void server_mainloop( const int64 serversocket ) { |
| 557 | tai6464 t, next_timeout_check; | 532 | tai6464 t, next_timeout_check; |
| 558 | 533 | ||
| 559 | io_wantread( serversocket ); | 534 | io_wantread( serversocket ); |
| @@ -626,9 +601,6 @@ int main( int argc, char **argv ) { | |||
| 626 | 601 | ||
| 627 | signal( SIGPIPE, SIG_IGN ); | 602 | signal( SIGPIPE, SIG_IGN ); |
| 628 | signal( SIGINT, graceful ); | 603 | signal( SIGINT, graceful ); |
| 629 | #ifdef _DEBUG_FDS | ||
| 630 | signal( SIGINFO, count_fds ); | ||
| 631 | #endif | ||
| 632 | if( init_logic( serverdir ) == -1 ) | 604 | if( init_logic( serverdir ) == -1 ) |
| 633 | panic( "Logic not started" ); | 605 | panic( "Logic not started" ); |
| 634 | 606 | ||
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 | |||
| 64 | */ | 64 | */ |
| 65 | char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;} | 65 | char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;} |
| 66 | 66 | ||
| 67 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, int compare_size, int *exactmatch ) { | 67 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { |
| 68 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); | 68 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); |
| 69 | 69 | ||
| 70 | if( *exactmatch ) return match; | 70 | if( *exactmatch ) return match; |
| @@ -104,7 +104,7 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | static void free_peerlist( ot_peerlist *peer_list ) { | 106 | static void free_peerlist( ot_peerlist *peer_list ) { |
| 107 | int i; | 107 | size_t i; |
| 108 | for( i=0; i<OT_POOLS_COUNT; ++i ) | 108 | for( i=0; i<OT_POOLS_COUNT; ++i ) |
| 109 | if( peer_list->peers[i].data ) | 109 | if( peer_list->peers[i].data ) |
| 110 | free( peer_list->peers[i].data ); | 110 | free( peer_list->peers[i].data ); |
| @@ -227,9 +227,9 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | |||
| 227 | * RANDOM may return huge values | 227 | * RANDOM may return huge values |
| 228 | * does not yet check not to return self | 228 | * does not yet check not to return self |
| 229 | */ | 229 | */ |
| 230 | size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ) { | 230 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply ) { |
| 231 | char *r = reply; | 231 | char *r = reply; |
| 232 | unsigned int peer_count, seed_count, index; | 232 | size_t peer_count, seed_count, index; |
| 233 | 233 | ||
| 234 | #ifdef WANT_CLOSED_TRACKER | 234 | #ifdef WANT_CLOSED_TRACKER |
| 235 | if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) { | 235 | if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) { |
| @@ -247,13 +247,13 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char | |||
| 247 | } | 247 | } |
| 248 | #endif | 248 | #endif |
| 249 | 249 | ||
| 250 | for( peer_count=seed_count=index=0; index<OT_POOLS_COUNT; ++index) { | 250 | for( peer_count = seed_count = index = 0; index < OT_POOLS_COUNT; ++index ) { |
| 251 | peer_count += torrent->peer_list->peers[index].size; | 251 | peer_count += torrent->peer_list->peers[index].size; |
| 252 | seed_count += torrent->peer_list->seed_count[index]; | 252 | seed_count += torrent->peer_list->seed_count[index]; |
| 253 | } | 253 | } |
| 254 | if( peer_count < amount ) amount = peer_count; | 254 | if( peer_count < amount ) amount = peer_count; |
| 255 | 255 | ||
| 256 | 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 ); | 256 | 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 ); |
| 257 | if( amount ) { | 257 | if( amount ) { |
| 258 | unsigned int pool_offset, pool_index = 0;; | 258 | unsigned int pool_offset, pool_index = 0;; |
| 259 | unsigned int shifted_pc = peer_count; | 259 | unsigned int shifted_pc = peer_count; |
| @@ -292,8 +292,9 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char | |||
| 292 | 292 | ||
| 293 | /* Fetch full scrape info for all torrents */ | 293 | /* Fetch full scrape info for all torrents */ |
| 294 | size_t return_fullscrape_for_tracker( char **reply ) { | 294 | size_t return_fullscrape_for_tracker( char **reply ) { |
| 295 | int torrent_count = 0, i, j, k; | 295 | size_t torrent_count = 0, j; |
| 296 | char* r; | 296 | int i, k; |
| 297 | char *r; | ||
| 297 | time_t time_now = NOW; | 298 | time_t time_now = NOW; |
| 298 | 299 | ||
| 299 | for( i=0; i<256; ++i ) { | 300 | for( i=0; i<256; ++i ) { |
| @@ -301,16 +302,15 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
| 301 | torrent_count += torrents_list->size; | 302 | torrent_count += torrents_list->size; |
| 302 | } | 303 | } |
| 303 | 304 | ||
| 304 | r = *reply = malloc( 128*torrent_count ); | 305 | if( !( r = *reply = malloc( 128*torrent_count ) ) ) return 0; |
| 305 | if( !reply ) return 0; | 306 | |
| 306 | |||
| 307 | memmove( r, "d5:filesd", 9 ); r += 9; | 307 | memmove( r, "d5:filesd", 9 ); r += 9; |
| 308 | for( i=0; i<256; ++i ) { | 308 | for( i=0; i<256; ++i ) { |
| 309 | ot_vector *torrents_list = &all_torrents[i]; | 309 | ot_vector *torrents_list = &all_torrents[i]; |
| 310 | for( j=0; j<torrents_list->size; ++j ) { | 310 | for( j=0; j<torrents_list->size; ++j ) { |
| 311 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 311 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
| 312 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | 312 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
| 313 | int peers = 0, seeds = 0; | 313 | size_t peers = 0, seeds = 0; |
| 314 | clean_peerlist( time_now, peer_list ); | 314 | clean_peerlist( time_now, peer_list ); |
| 315 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 315 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
| 316 | peers += peer_list->peers[k].size; | 316 | peers += peer_list->peers[k].size; |
| @@ -318,7 +318,7 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
| 318 | } | 318 | } |
| 319 | memmove( r, "20:", 3 ); r+=3; | 319 | memmove( r, "20:", 3 ); r+=3; |
| 320 | memmove( r, hash, 20 ); r+=20; | 320 | memmove( r, hash, 20 ); r+=20; |
| 321 | r += sprintf( r, "d8:completei%de10:downloadedi%de10:incompletei%de", seeds, peer_list->downloaded, peers-seeds ); | 321 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde", seeds, peer_list->downloaded, peers-seeds ); |
| 322 | } | 322 | } |
| 323 | } | 323 | } |
| 324 | 324 | ||
| @@ -329,7 +329,8 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
| 329 | /* Fetches scrape info for a specific torrent */ | 329 | /* Fetches scrape info for a specific torrent */ |
| 330 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { | 330 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { |
| 331 | char *r = reply; | 331 | char *r = reply; |
| 332 | int exactmatch, peers = 0, seeds = 0, i; | 332 | int exactmatch, i; |
| 333 | size_t peers = 0, seeds = 0; | ||
| 333 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | 334 | ot_vector *torrents_list = &all_torrents[*hash[0]]; |
| 334 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 335 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
| 335 | 336 | ||
| @@ -342,20 +343,45 @@ size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
| 342 | } | 343 | } |
| 343 | 344 | ||
| 344 | memmove( r, "d5:filesd20:", 12 ); memmove( r+12, hash, 20 ); | 345 | memmove( r, "d5:filesd20:", 12 ); memmove( r+12, hash, 20 ); |
| 345 | r += sprintf( r+32, "d8:completei%de10:downloadedi%de10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32; | 346 | r += sprintf( r+32, "d8:completei%zde10:downloadedi%zde10:incompletei%zdeeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32; |
| 346 | 347 | ||
| 347 | return r - reply; | 348 | return r - reply; |
| 348 | } | 349 | } |
| 349 | 350 | ||
| 351 | size_t return_sync_for_torrent( ot_hash *hash, char **reply ) { | ||
| 352 | int exactmatch; | ||
| 353 | size_t peers = 0; | ||
| 354 | char *r; | ||
| 355 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | ||
| 356 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
| 357 | |||
| 358 | if( exactmatch ) { | ||
| 359 | clean_peerlist( NOW, torrent->peer_list ); | ||
| 360 | peers = torrent->peer_list->peers[0].size; | ||
| 361 | } | ||
| 362 | |||
| 363 | if( !( r = *reply = malloc( 10 + peers * sizeof( ot_peer ) ) ) ) return 0; | ||
| 364 | |||
| 365 | memmove( r, "d4:sync", 7 ); | ||
| 366 | r += 7; | ||
| 367 | r += sprintf( r, "%zd:", peers * sizeof( ot_peer ) ); | ||
| 368 | if( peers ) { | ||
| 369 | memmove( r, torrent->peer_list->peers[0].data, peers * sizeof( ot_peer ) ); | ||
| 370 | r += peers * sizeof( ot_peer ); | ||
| 371 | } | ||
| 372 | *r++ = 'e'; | ||
| 373 | return r - *reply; | ||
| 374 | } | ||
| 375 | |||
| 350 | typedef struct { int val; ot_torrent * torrent; } ot_record; | 376 | typedef struct { int val; ot_torrent * torrent; } ot_record; |
| 351 | 377 | ||
| 352 | /* Fetches stats from tracker */ | 378 | /* Fetches stats from tracker */ |
| 353 | size_t return_stats_for_tracker( char *reply, int mode ) { | 379 | size_t return_stats_for_tracker( char *reply, int mode ) { |
| 354 | time_t time_now = NOW; | 380 | time_t time_now = NOW; |
| 355 | int torrent_count = 0, peer_count = 0, seed_count = 0; | 381 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; |
| 356 | ot_record top5s[5], top5c[5]; | 382 | ot_record top5s[5], top5c[5]; |
| 357 | char *r = reply; | 383 | char *r = reply; |
| 358 | int i,j,k; | 384 | int i,k; |
| 359 | 385 | ||
| 360 | byte_zero( top5s, sizeof( top5s ) ); | 386 | byte_zero( top5s, sizeof( top5s ) ); |
| 361 | byte_zero( top5c, sizeof( top5c ) ); | 387 | byte_zero( top5c, sizeof( top5c ) ); |
| @@ -365,7 +391,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
| 365 | torrent_count += torrents_list->size; | 391 | torrent_count += torrents_list->size; |
| 366 | for( j=0; j<torrents_list->size; ++j ) { | 392 | for( j=0; j<torrents_list->size; ++j ) { |
| 367 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 393 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
| 368 | int local_peers = 0, local_seeds = 0; | 394 | size_t local_peers = 0, local_seeds = 0; |
| 369 | clean_peerlist( time_now, peer_list ); | 395 | clean_peerlist( time_now, peer_list ); |
| 370 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 396 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
| 371 | local_peers += peer_list->peers[k].size; | 397 | local_peers += peer_list->peers[k].size; |
| @@ -399,7 +425,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
| 399 | if( top5s[idx].torrent ) | 425 | if( top5s[idx].torrent ) |
| 400 | r += sprintf( r, "\t%i\t%s\n", top5s[idx].val, to_hex(top5s[idx].torrent->hash) ); | 426 | r += sprintf( r, "\t%i\t%s\n", top5s[idx].val, to_hex(top5s[idx].torrent->hash) ); |
| 401 | } else { | 427 | } else { |
| 402 | r += sprintf( r, "%i\n%i\nopentracker serving %i torrents\nSomething else.", peer_count, seed_count, torrent_count ); | 428 | r += sprintf( r, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", peer_count, seed_count, torrent_count ); |
| 403 | } | 429 | } |
| 404 | 430 | ||
| 405 | return r - reply; | 431 | return r - reply; |
| @@ -429,7 +455,7 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) { | |||
| 429 | } | 455 | } |
| 430 | } | 456 | } |
| 431 | 457 | ||
| 432 | int init_logic( char *serverdir ) { | 458 | int init_logic( const char * const serverdir ) { |
| 433 | if( serverdir && chdir( serverdir ) ) { | 459 | if( serverdir && chdir( serverdir ) ) { |
| 434 | fprintf( stderr, "Could not chdir() to %s\n", serverdir ); | 460 | fprintf( stderr, "Could not chdir() to %s\n", serverdir ); |
| 435 | return -1; | 461 | return -1; |
| @@ -443,8 +469,9 @@ int init_logic( char *serverdir ) { | |||
| 443 | return 0; | 469 | return 0; |
| 444 | } | 470 | } |
| 445 | 471 | ||
| 446 | void deinit_logic( ) { | 472 | void deinit_logic( void ) { |
| 447 | int i, j; | 473 | int i; |
| 474 | size_t j; | ||
| 448 | 475 | ||
| 449 | /* Free all torrents... */ | 476 | /* Free all torrents... */ |
| 450 | for(i=0; i<256; ++i ) { | 477 | 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; | |||
| 64 | typedef struct { | 64 | typedef struct { |
| 65 | ot_time base; | 65 | ot_time base; |
| 66 | size_t seed_count[ OT_POOLS_COUNT ]; | 66 | size_t seed_count[ OT_POOLS_COUNT ]; |
| 67 | unsigned int downloaded; | 67 | size_t downloaded; |
| 68 | ot_vector peers[ OT_POOLS_COUNT ]; | 68 | ot_vector peers[ OT_POOLS_COUNT ]; |
| 69 | } ot_peerlist; | 69 | } ot_peerlist; |
| 70 | 70 | ||
| @@ -77,8 +77,8 @@ typedef struct { | |||
| 77 | Exported functions | 77 | Exported functions |
| 78 | */ | 78 | */ |
| 79 | 79 | ||
| 80 | int init_logic( char *serverdir ); | 80 | int init_logic( const char * const serverdir ); |
| 81 | void deinit_logic( ); | 81 | void deinit_logic( void ); |
| 82 | 82 | ||
| 83 | #ifdef WANT_CLOSED_TRACKER | 83 | #ifdef WANT_CLOSED_TRACKER |
| 84 | extern int g_closedtracker; | 84 | extern int g_closedtracker; |
| @@ -90,9 +90,10 @@ extern int g_check_blacklist; | |||
| 90 | enum { STATS_MRTG, STATS_TOP5 }; | 90 | enum { STATS_MRTG, STATS_TOP5 }; |
| 91 | 91 | ||
| 92 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ); | 92 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ); |
| 93 | size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ); | 93 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply ); |
| 94 | size_t return_fullscrape_for_tracker( char **reply ); | 94 | size_t return_fullscrape_for_tracker( char **reply ); |
| 95 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ); | 95 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ); |
| 96 | size_t return_sync_for_torrent( ot_hash *hash, char **reply ); | ||
| 96 | size_t return_stats_for_tracker( char *reply, int mode ); | 97 | size_t return_stats_for_tracker( char *reply, int mode ); |
| 97 | void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ); | 98 | void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ); |
| 98 | 99 | ||
