summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c210
1 files changed, 115 insertions, 95 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;
33static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80; 33static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80;
34static const size_t SUCCESS_HTTP_SIZE_OFF = 17; 34static const size_t SUCCESS_HTTP_SIZE_OFF = 17;
35/* To always have space for error messages ;) */ 35/* To always have space for error messages ;) */
36static char static_reply[8192]; 36static char static_scratch[8192];
37 37
38static void carp(const char* routine) { 38static 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
81void httperror(int64 s,struct http_data* h,const char* title,const char* message) { 81void 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
87const char* http_header(struct http_data* r,const char* h) { 87const 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 ) {
297e500: 297e500:
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
388int main( int argc, char **argv ) { 388void 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
423void 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
485int 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
416allparsed:
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}