diff options
| author | erdgeist <> | 2007-01-18 02:23:18 +0000 |
|---|---|---|
| committer | erdgeist <> | 2007-01-18 02:23:18 +0000 |
| commit | 2ee37881ff4b464a572eeb413bff6e7a8e2d4113 (patch) | |
| tree | 96d7af8e961b47e70b76d6b95b36189336afba0c | |
| parent | c16330df6ac202197efa9964b7579b98e0571e0e (diff) | |
Rearranged code to try to read data as soon as socket is accepted, also raise backlog for listening socket
| -rw-r--r-- | opentracker.c | 210 | ||||
| -rw-r--r-- | testsuite.sh | 2 |
2 files changed, 116 insertions, 96 deletions
diff --git a/opentracker.c b/opentracker.c index 5fa6548..1d18e49 100644 --- a/opentracker.c +++ b/opentracker.c | |||
| @@ -33,7 +33,7 @@ static time_t ot_start_time; | |||
| 33 | static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80; | 33 | static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80; |
| 34 | static const size_t SUCCESS_HTTP_SIZE_OFF = 17; | 34 | static const size_t SUCCESS_HTTP_SIZE_OFF = 17; |
| 35 | /* To always have space for error messages ;) */ | 35 | /* To always have space for error messages ;) */ |
| 36 | static char static_reply[8192]; | 36 | static char static_scratch[8192]; |
| 37 | 37 | ||
| 38 | static void carp(const char* routine) { | 38 | static void carp(const char* routine) { |
| 39 | buffer_puts(buffer_2,routine); | 39 | buffer_puts(buffer_2,routine); |
| @@ -79,9 +79,9 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void httperror(int64 s,struct http_data* h,const char* title,const char* message) { | 81 | void httperror(int64 s,struct http_data* h,const char* title,const char* message) { |
| 82 | size_t reply_size = sprintf( static_reply, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", | 82 | 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", |
| 83 | title, strlen(message)+strlen(title)+16-4,title+4); | 83 | title, strlen(message)+strlen(title)+16-4,title+4); |
| 84 | senddata(s,h,static_reply,reply_size); | 84 | senddata(s,h,static_scratch,reply_size); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | const char* http_header(struct http_data* r,const char* h) { | 87 | const char* http_header(struct http_data* r,const char* h) { |
| @@ -160,7 +160,7 @@ e400: | |||
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | /* Enough for http header + whole scrape string */ | 162 | /* Enough for http header + whole scrape string */ |
| 163 | if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_reply, mode ) ) <= 0 ) | 163 | if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) |
| 164 | goto e500; | 164 | goto e500; |
| 165 | break; | 165 | break; |
| 166 | case 6: /* scrape ? */ | 166 | case 6: /* scrape ? */ |
| @@ -198,7 +198,7 @@ e400_param: | |||
| 198 | return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes."); | 198 | return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes."); |
| 199 | 199 | ||
| 200 | /* Enough for http header + whole scrape string */ | 200 | /* Enough for http header + whole scrape string */ |
| 201 | if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 ) | 201 | if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) |
| 202 | goto e500; | 202 | goto e500; |
| 203 | break; | 203 | break; |
| 204 | case 8: | 204 | case 8: |
| @@ -290,14 +290,14 @@ e400_param: | |||
| 290 | 290 | ||
| 291 | if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { | 291 | if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { |
| 292 | remove_peer_from_torrent( hash, &peer ); | 292 | remove_peer_from_torrent( hash, &peer ); |
| 293 | memmove( static_reply + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali600e5:peers0:e", reply_size = 55 ); | 293 | memmove( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali600e5:peers0:e", reply_size = 55 ); |
| 294 | } else { | 294 | } else { |
| 295 | torrent = add_peer_to_torrent( hash, &peer ); | 295 | torrent = add_peer_to_torrent( hash, &peer ); |
| 296 | if( !torrent ) { | 296 | if( !torrent ) { |
| 297 | e500: | 297 | e500: |
| 298 | return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later."); | 298 | return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later."); |
| 299 | } | 299 | } |
| 300 | if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 ) | 300 | if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) |
| 301 | goto e500; | 301 | goto e500; |
| 302 | } | 302 | } |
| 303 | break; | 303 | break; |
| @@ -306,7 +306,7 @@ e500: | |||
| 306 | goto e404; | 306 | goto e404; |
| 307 | { | 307 | { |
| 308 | time_t seconds_elapsed = time( NULL ) - ot_start_time; | 308 | time_t seconds_elapsed = time( NULL ) - ot_start_time; |
| 309 | reply_size = sprintf( static_reply + SUCCESS_HTTP_HEADER_LENGTH, | 309 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, |
| 310 | "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", | 310 | "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", |
| 311 | ot_overall_connections, ot_overall_connections, (int)seconds_elapsed, | 311 | ot_overall_connections, ot_overall_connections, (int)seconds_elapsed, |
| 312 | (int)(seconds_elapsed / 3600), (int)ot_overall_connections / ( (int)seconds_elapsed ? (int)seconds_elapsed : 1 ) ); | 312 | (int)(seconds_elapsed / 3600), (int)ot_overall_connections / ( (int)seconds_elapsed ? (int)seconds_elapsed : 1 ) ); |
| @@ -325,16 +325,16 @@ e404: | |||
| 325 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate | 325 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate |
| 326 | the space NOT needed to expand in reply_off | 326 | the space NOT needed to expand in reply_off |
| 327 | */ | 327 | */ |
| 328 | size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_reply, 0, "%zd", reply_size ); | 328 | size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); |
| 329 | 329 | ||
| 330 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete | 330 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete |
| 331 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ | 331 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ |
| 332 | reply_size += 1 + sprintf( static_reply + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); | 332 | 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 ); |
| 333 | 333 | ||
| 334 | /* 3. Finally we join both blocks neatly */ | 334 | /* 3. Finally we join both blocks neatly */ |
| 335 | static_reply[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; | 335 | static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; |
| 336 | 336 | ||
| 337 | senddata( s, h, static_reply + reply_off, reply_size ); | 337 | senddata( s, h, static_scratch + reply_off, reply_size ); |
| 338 | } else { | 338 | } else { |
| 339 | if( h ) array_reset(&h->r); | 339 | if( h ) array_reset(&h->r); |
| 340 | free( h ); io_close( s ); | 340 | free( h ); io_close( s ); |
| @@ -385,17 +385,113 @@ void help( char *name ) { | |||
| 385 | ); | 385 | ); |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | int main( int argc, char **argv ) { | 388 | void handle_read( int64 clientsocket, int afteraccept ) { |
| 389 | int s=socket_tcp4(); | 389 | struct http_data* h = io_getcookie( clientsocket ); |
| 390 | int l = io_tryread( clientsocket, static_scratch, sizeof static_scratch ); | ||
| 391 | tai6464 t; | ||
| 392 | |||
| 393 | taia_now(&t); | ||
| 394 | taia_addsec(&t,&t,OT_CLIENT_TIMEOUT); | ||
| 395 | io_timeout(clientsocket,t); | ||
| 396 | |||
| 397 | if( l <= 0 ) { | ||
| 398 | // getting 0 bytes doesn't mean connection closed, | ||
| 399 | // when we try the shortcut read() after accept() | ||
| 400 | // and nothing is there yet | ||
| 401 | if( afteraccept && ( errno == EAGAIN ) ) | ||
| 402 | return; | ||
| 403 | if( h ) { | ||
| 404 | array_reset(&h->r); | ||
| 405 | free(h); | ||
| 406 | } | ||
| 407 | io_close(clientsocket); | ||
| 408 | return; | ||
| 409 | } | ||
| 410 | |||
| 411 | if( afteraccept ) fprintf( stderr, "*" ); | ||
| 412 | |||
| 413 | array_catb(&h->r,static_scratch,l); | ||
| 414 | |||
| 415 | if( array_failed(&h->r)) | ||
| 416 | httperror(clientsocket,h,"500 Server Error","Request too long."); | ||
| 417 | else if (array_bytes(&h->r)>8192) | ||
| 418 | httperror(clientsocket,h,"500 request too long","You sent too much headers"); | ||
| 419 | else if ((l=header_complete(h))) | ||
| 420 | httpresponse(clientsocket,h); | ||
| 421 | } | ||
| 422 | |||
| 423 | void server_mainloop( int64 serversocket ) { | ||
| 390 | tai6464 t, next_timeout_check; | 424 | tai6464 t, next_timeout_check; |
| 425 | unsigned char ip[4]; | ||
| 426 | uint16 port; | ||
| 427 | |||
| 428 | io_wantread( serversocket ); | ||
| 429 | taia_now( &next_timeout_check ); | ||
| 430 | |||
| 431 | for (;;) { | ||
| 432 | int64 i; | ||
| 433 | taia_now(&t); | ||
| 434 | taia_addsec(&t,&t,OT_CLIENT_TIMEOUT_CHECKINTERVAL); | ||
| 435 | io_waituntil(t); | ||
| 436 | |||
| 437 | taia_now(&t); | ||
| 438 | if( taia_less( &next_timeout_check, &t ) ) { | ||
| 439 | while( ( i = io_timeouted() ) != -1 ) { | ||
| 440 | struct http_data* h=io_getcookie(i); | ||
| 441 | if( h ) { | ||
| 442 | array_reset( &h->r ); | ||
| 443 | free( h ); | ||
| 444 | } | ||
| 445 | io_close(i); | ||
| 446 | } | ||
| 447 | taia_now(&next_timeout_check); | ||
| 448 | taia_addsec(&next_timeout_check,&next_timeout_check,OT_CLIENT_TIMEOUT_CHECKINTERVAL); | ||
| 449 | } | ||
| 450 | |||
| 451 | while( ( i = io_canread() ) != -1 ) { | ||
| 452 | |||
| 453 | if( i != serversocket ) { | ||
| 454 | handle_read( i, 0 ); | ||
| 455 | continue; | ||
| 456 | } | ||
| 457 | |||
| 458 | // Attention, i changes from what io_canread() returned to | ||
| 459 | // what socket_accept4 returns as new socket | ||
| 460 | while( ( i = socket_accept4( serversocket, (char*)ip, &port) ) != -1 ) { | ||
| 461 | if( io_fd( i ) ) { | ||
| 462 | struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data)); | ||
| 463 | io_wantread( i ); | ||
| 464 | |||
| 465 | if (h) { | ||
| 466 | byte_zero(h,sizeof(struct http_data)); | ||
| 467 | memmove(h->ip,ip,sizeof(ip)); | ||
| 468 | io_setcookie(i,h); | ||
| 469 | ++ot_overall_connections; | ||
| 470 | handle_read(i,1); | ||
| 471 | } else | ||
| 472 | io_close(i); | ||
| 473 | } else | ||
| 474 | io_close(i); | ||
| 475 | } | ||
| 476 | |||
| 477 | if( errno==EAGAIN ) | ||
| 478 | io_eagain( serversocket ); | ||
| 479 | else | ||
| 480 | carp( "socket_accept4" ); | ||
| 481 | } | ||
| 482 | } | ||
| 483 | } | ||
| 484 | |||
| 485 | int main( int argc, char **argv ) { | ||
| 486 | int64 s = socket_tcp4( ); | ||
| 391 | char *serverip = NULL; | 487 | char *serverip = NULL; |
| 392 | char *serverdir = "."; | 488 | char *serverdir = "."; |
| 393 | uint16 port = 6969; | 489 | uint16 port = 6969; |
| 394 | unsigned char ip[4]; | 490 | int scanon = 1; |
| 395 | 491 | ||
| 396 | while( 1 ) { | 492 | while( scanon ) { |
| 397 | switch( getopt(argc,argv,":i:p:d:ocbBh") ) { | 493 | switch( getopt(argc,argv,":i:p:d:ocbBh") ) { |
| 398 | case -1: goto allparsed; | 494 | case -1 : scanon = 0; break; |
| 399 | case 'i': serverip = optarg; break; | 495 | case 'i': serverip = optarg; break; |
| 400 | case 'p': port = (uint16)atol( optarg ); break; | 496 | case 'p': port = (uint16)atol( optarg ); break; |
| 401 | case 'd': serverdir = optarg; break; | 497 | case 'd': serverdir = optarg; break; |
| @@ -413,14 +509,13 @@ int main( int argc, char **argv ) { | |||
| 413 | } | 509 | } |
| 414 | } | 510 | } |
| 415 | 511 | ||
| 416 | allparsed: | ||
| 417 | if (socket_bind4_reuse(s,serverip,port)==-1) | 512 | if (socket_bind4_reuse(s,serverip,port)==-1) |
| 418 | panic("socket_bind4_reuse"); | 513 | panic("socket_bind4_reuse"); |
| 419 | 514 | ||
| 420 | setegid((gid_t)-2); setuid((uid_t)-2); | 515 | setegid((gid_t)-2); setuid((uid_t)-2); |
| 421 | setgid((gid_t)-2); seteuid((uid_t)-2); | 516 | setgid((gid_t)-2); seteuid((uid_t)-2); |
| 422 | 517 | ||
| 423 | if (socket_listen(s,16)==-1) | 518 | if (socket_listen(s,SOMAXCONN)==-1) |
| 424 | panic("socket_listen"); | 519 | panic("socket_listen"); |
| 425 | 520 | ||
| 426 | if (!io_fd(s)) | 521 | if (!io_fd(s)) |
| @@ -433,82 +528,7 @@ allparsed: | |||
| 433 | 528 | ||
| 434 | ot_start_time = time( NULL ); | 529 | ot_start_time = time( NULL ); |
| 435 | 530 | ||
| 436 | io_wantread( s ); | 531 | server_mainloop(s); |
| 437 | taia_now( &next_timeout_check ); | ||
| 438 | |||
| 439 | for (;;) { | ||
| 440 | int64 i; | ||
| 441 | taia_now(&t); | ||
| 442 | taia_addsec(&t,&t,OT_CLIENT_TIMEOUT_CHECKINTERVAL); | ||
| 443 | io_waituntil(t); | ||
| 444 | 532 | ||
| 445 | taia_now(&t); | ||
| 446 | if( taia_less( &next_timeout_check, &t ) ) { | ||
| 447 | while( ( i = io_timeouted() ) != -1 ) { | ||
| 448 | struct http_data* h=io_getcookie(i); | ||
| 449 | if( h ) { | ||
| 450 | array_reset( &h->r ); | ||
| 451 | free( h ); | ||
| 452 | } | ||
| 453 | io_close(i); | ||
| 454 | } | ||
| 455 | taia_now(&next_timeout_check); | ||
| 456 | taia_addsec(&next_timeout_check,&next_timeout_check,OT_CLIENT_TIMEOUT_CHECKINTERVAL); | ||
| 457 | } | ||
| 458 | |||
| 459 | while( ( i = io_canread() ) != -1 ) { | ||
| 460 | if( i == s ) { | ||
| 461 | int n; | ||
| 462 | while( ( n = socket_accept4( s, (char*)ip, &port) ) != -1 ) { | ||
| 463 | if( io_fd( n ) ) { | ||
| 464 | struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data)); | ||
| 465 | io_wantread(n); | ||
| 466 | |||
| 467 | if (h) { | ||
| 468 | byte_zero(h,sizeof(struct http_data)); | ||
| 469 | memmove(h->ip,ip,sizeof(ip)); | ||
| 470 | taia_now(&t); | ||
| 471 | taia_addsec(&t,&t,OT_CLIENT_TIMEOUT); | ||
| 472 | io_timeout(n,t); | ||
| 473 | io_setcookie(n,h); | ||
| 474 | ++ot_overall_connections; | ||
| 475 | } else | ||
| 476 | io_close(n); | ||
| 477 | } else | ||
| 478 | io_close(n); | ||
| 479 | } | ||
| 480 | if( errno==EAGAIN ) | ||
| 481 | io_eagain(s); | ||
| 482 | else | ||
| 483 | carp("socket_accept4"); | ||
| 484 | } else { | ||
| 485 | /* unsigned (sic!) */ char buf[8192]; | ||
| 486 | struct http_data* h=io_getcookie(i); | ||
| 487 | |||
| 488 | int l=io_tryread(i,buf,sizeof buf); | ||
| 489 | if( l <= 0 ) { | ||
| 490 | if( h ) { | ||
| 491 | array_reset(&h->r); | ||
| 492 | free(h); | ||
| 493 | } | ||
| 494 | io_close(i); | ||
| 495 | } else { | ||
| 496 | array_catb(&h->r,buf,l); | ||
| 497 | |||
| 498 | if( array_failed(&h->r)) | ||
| 499 | httperror(i,h,"500 Server Error","Request too long."); | ||
| 500 | else if (array_bytes(&h->r)>8192) | ||
| 501 | httperror(i,h,"500 request too long","You sent too much headers"); | ||
| 502 | else if ((l=header_complete(h))) | ||
| 503 | httpresponse(i,h); | ||
| 504 | else { | ||
| 505 | taia_now(&t); | ||
| 506 | taia_addsec(&t,&t,OT_CLIENT_TIMEOUT); | ||
| 507 | io_timeout(i,t); | ||
| 508 | } | ||
| 509 | } | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| 513 | return 0; | 533 | return 0; |
| 514 | } | 534 | } |
diff --git a/testsuite.sh b/testsuite.sh index e0981d1..e5bc7a4 100644 --- a/testsuite.sh +++ b/testsuite.sh | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #!/bin/sh | 1 | #!/bin/sh |
| 2 | 2 | ||
| 3 | while true; do | 3 | while true; do |
| 4 | request_string="GET /announce?info_hash=0123456789012345678%$(printf %02X $(( $RANDOM & 0xf )) )&\ | 4 | request_string="GET /announce?info_hash=0123456789012345678%$(printf %02X $(( $RANDOM & 0xff )) )&\ |
| 5 | ip=10.1.1.$(( $RANDOM & 0xff ))&port=$(( $RANDOM & 0xff )) HTTP/1.0\n" | 5 | ip=10.1.1.$(( $RANDOM & 0xff ))&port=$(( $RANDOM & 0xff )) HTTP/1.0\n" |
| 6 | 6 | ||
| 7 | # echo -e $request_string | 7 | # echo -e $request_string |
