mirror of
git://erdgeist.org/opentracker
synced 2025-02-22 09:01:29 +08:00
* http and udp routines now use thread local buffers passed in workstruct containers. In other words they do not use static_buffer anymore and are considered to be thread safe.
* the new workstruct also introduces a well defined buffer and result passing path * a new function scan_find_keywords is a wrapper around scan_urlencoded_query that maps keys in url to values passed in an array of ot_keywords structs * this new function cleans up much of url parameter parsing work, where read_ptr and write_ptr have been introduced rather than the confusing char *c, *data variables * I now use memcmp instead of byte_diff to allow compiler to optimize constant size string compares * got rid of UTORRENT_1600_WORKAROUND * livesync_ticker is now only called from one (currently main) thread to avoid race conditions
This commit is contained in:
parent
8bdc0d73f6
commit
779d6c235f
3
Makefile
3
Makefile
@ -24,7 +24,6 @@ BINDIR?=$(PREFIX)/bin
|
||||
|
||||
#FEATURES+=-DWANT_SYNC_LIVE
|
||||
#FEATURES+=-DWANT_SYNC_SCRAPE
|
||||
#FEATURES+=-DWANT_UTORRENT1600_WORKAROUND
|
||||
#FEATURES+=-DWANT_IP_FROM_QUERY_STRING
|
||||
#FEATURES+=-DWANT_COMPRESSION_GZIP
|
||||
#FEATURES+=-DWANT_LOG_NETWORKS
|
||||
@ -37,7 +36,7 @@ FEATURES+=-DWANT_FULLSCRAPE
|
||||
OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage
|
||||
OPTS_production=-Os
|
||||
|
||||
CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-pedantic -ansi
|
||||
CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-ansi -pedantic
|
||||
LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz
|
||||
|
||||
BINARY =opentracker
|
||||
|
@ -41,9 +41,6 @@ volatile int g_opentracker_running = 1;
|
||||
|
||||
static char * g_serverdir = NULL;
|
||||
|
||||
/* To always have space for error messages ;) */
|
||||
static char static_inbuf[8192];
|
||||
|
||||
static void panic( const char *routine ) {
|
||||
fprintf( stderr, "%s: %s\n", routine, strerror(errno) );
|
||||
exit( 111 );
|
||||
@ -107,37 +104,44 @@ static void handle_dead( const int64 socket ) {
|
||||
io_close( socket );
|
||||
}
|
||||
|
||||
static ssize_t handle_read( const int64 clientsocket ) {
|
||||
static ssize_t handle_read( const int64 clientsocket, struct ot_workstruct *ws ) {
|
||||
struct http_data* h = io_getcookie( clientsocket );
|
||||
ssize_t l;
|
||||
|
||||
if( ( l = io_tryread( clientsocket, static_inbuf, sizeof static_inbuf ) ) <= 0 ) {
|
||||
if( ( l = io_tryread( clientsocket, ws->inbuf, ws->inbuf_size ) ) <= 0 ) {
|
||||
handle_dead( clientsocket );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we get the whole request in one packet, handle it without copying */
|
||||
if( !array_start( &h->data.request ) ) {
|
||||
if( memchr( static_inbuf, '\n', l ) )
|
||||
return http_handle_request( clientsocket, static_inbuf, l );
|
||||
if( memchr( ws->inbuf, '\n', l ) ) {
|
||||
ws->request = ws->inbuf;
|
||||
ws->request_size = l;
|
||||
return http_handle_request( clientsocket, ws );
|
||||
}
|
||||
|
||||
/* ... else take a copy */
|
||||
h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
|
||||
array_catb( &h->data.request, static_inbuf, l );
|
||||
array_catb( &h->data.request, ws->inbuf, l );
|
||||
return 0;
|
||||
}
|
||||
|
||||
h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
|
||||
array_catb( &h->data.request, static_inbuf, l );
|
||||
array_catb( &h->data.request, ws->inbuf, l );
|
||||
|
||||
if( array_failed( &h->data.request ) )
|
||||
return http_issue_error( clientsocket, CODE_HTTPERROR_500 );
|
||||
return http_issue_error( clientsocket, ws, CODE_HTTPERROR_500 );
|
||||
|
||||
if( array_bytes( &h->data.request ) > 8192 )
|
||||
return http_issue_error( clientsocket, CODE_HTTPERROR_500 );
|
||||
return http_issue_error( clientsocket, ws, CODE_HTTPERROR_500 );
|
||||
|
||||
if( memchr( array_start( &h->data.request ), '\n', array_bytes( &h->data.request ) ) )
|
||||
return http_handle_request( clientsocket, array_start( &h->data.request ), array_bytes( &h->data.request ) );
|
||||
if( !memchr( array_start( &h->data.request ), '\n', array_bytes( &h->data.request ) ) )
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
ws->request = array_start( &h->data.request );
|
||||
ws->request_size = array_bytes( &h->data.request );
|
||||
return http_handle_request( clientsocket, ws );
|
||||
}
|
||||
|
||||
static void handle_write( const int64 clientsocket ) {
|
||||
@ -183,9 +187,25 @@ static void handle_accept( const int64 serversocket ) {
|
||||
}
|
||||
|
||||
static void server_mainloop( ) {
|
||||
time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
|
||||
struct iovec *iovector;
|
||||
int iovec_entries;
|
||||
struct ot_workstruct ws;
|
||||
time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
|
||||
struct iovec *iovector;
|
||||
int iovec_entries;
|
||||
|
||||
/* Initialize our "thread local storage" */
|
||||
ws.inbuf = malloc( THREAD_INBUF_SIZE );
|
||||
ws.outbuf = malloc( THREAD_OUTBUF_SIZE );
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
ws.debugbuf= malloc( THREAD_INBUF_SIZE );
|
||||
#endif
|
||||
if( !ws.inbuf || !ws.outbuf )
|
||||
panic( "Initializing worker failed" );
|
||||
|
||||
ws.inbuf_size = THREAD_INBUF_SIZE;
|
||||
ws.outbuf_size = THREAD_OUTBUF_SIZE;
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
ws.debugbuf_size= THREAD_INBUF_SIZE;
|
||||
#endif
|
||||
|
||||
for( ; ; ) {
|
||||
int64 i;
|
||||
@ -197,13 +217,13 @@ static void server_mainloop( ) {
|
||||
if( (intptr_t)cookie == FLAG_TCP )
|
||||
handle_accept( i );
|
||||
else if( (intptr_t)cookie == FLAG_UDP )
|
||||
handle_udp4( i );
|
||||
handle_udp4( i, &ws );
|
||||
else
|
||||
handle_read( i );
|
||||
handle_read( i, &ws );
|
||||
}
|
||||
|
||||
while( ( i = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 )
|
||||
http_sendiovecdata( i, iovec_entries, iovector );
|
||||
http_sendiovecdata( i, &ws, iovec_entries, iovector );
|
||||
|
||||
while( ( i = io_canwrite( ) ) != -1 )
|
||||
handle_write( i );
|
||||
@ -431,7 +451,12 @@ while( scanon ) {
|
||||
break;
|
||||
case 'f': bound += parse_configfile( optarg ); break;
|
||||
case 'h': help( argv[0] ); exit( 0 );
|
||||
case 'v': stats_return_tracker_version( static_inbuf ); fputs( static_inbuf, stderr ); exit( 0 );
|
||||
case 'v': {
|
||||
char buffer[8192];
|
||||
stats_return_tracker_version( buffer );
|
||||
fputs( buffer, stderr );
|
||||
exit( 0 );
|
||||
}
|
||||
default:
|
||||
case '?': usage( argv[0] ); exit( 1 );
|
||||
}
|
||||
|
454
ot_http.c
454
ot_http.c
@ -27,26 +27,19 @@
|
||||
#include "ot_accesslist.h"
|
||||
|
||||
#define OT_MAXMULTISCRAPE_COUNT 64
|
||||
static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT];
|
||||
extern char *g_redirecturl;
|
||||
|
||||
enum {
|
||||
SUCCESS_HTTP_HEADER_LENGTH = 80,
|
||||
SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING = 32,
|
||||
SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING = 32,
|
||||
SUCCESS_HTTP_SIZE_OFF = 17 };
|
||||
|
||||
/* Our static output buffer */
|
||||
static char static_outbuf[8192];
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
static char debug_request[8192];
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG_PEERID
|
||||
size_t g_this_peerid_len = 0;
|
||||
char *g_this_peerid_data = NULL;
|
||||
#endif
|
||||
|
||||
static void http_senddata( const int64 client_socket, char *buffer, size_t size ) {
|
||||
static void http_senddata( const int64 client_socket, struct ot_workstruct *ws ) {
|
||||
struct http_data *h = io_getcookie( client_socket );
|
||||
ssize_t written_size;
|
||||
|
||||
@ -56,22 +49,22 @@ static void http_senddata( const int64 client_socket, char *buffer, size_t size
|
||||
array_reset( &h->data.request );
|
||||
}
|
||||
|
||||
written_size = write( client_socket, buffer, size );
|
||||
if( ( written_size < 0 ) || ( (size_t)written_size == size ) ) {
|
||||
written_size = write( client_socket, ws->reply, ws->reply_size );
|
||||
if( ( written_size < 0 ) || ( written_size == ws->reply_size ) ) {
|
||||
free( h ); io_close( client_socket );
|
||||
} else {
|
||||
char * outbuf;
|
||||
tai6464 t;
|
||||
|
||||
if( !h ) return;
|
||||
if( !( outbuf = malloc( size - written_size ) ) ) {
|
||||
if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) {
|
||||
free(h); io_close( client_socket );
|
||||
return;
|
||||
}
|
||||
|
||||
iob_reset( &h->data.batch );
|
||||
memmove( outbuf, buffer + written_size, size - written_size );
|
||||
iob_addbuf_free( &h->data.batch, outbuf, size - written_size );
|
||||
memmove( outbuf, ws->reply + written_size, ws->reply_size - written_size );
|
||||
iob_addbuf_free( &h->data.batch, outbuf, ws->reply_size - written_size );
|
||||
h->flag |= STRUCT_HTTP_FLAG_IOB_USED;
|
||||
|
||||
/* writeable short data sockets just have a tcp timeout */
|
||||
@ -81,33 +74,34 @@ static void http_senddata( const int64 client_socket, char *buffer, size_t size
|
||||
}
|
||||
}
|
||||
|
||||
#define HTTPERROR_302 return http_issue_error( client_socket, CODE_HTTPERROR_302 )
|
||||
#define HTTPERROR_400 return http_issue_error( client_socket, CODE_HTTPERROR_400 )
|
||||
#define HTTPERROR_400_PARAM return http_issue_error( client_socket, CODE_HTTPERROR_400_PARAM )
|
||||
#define HTTPERROR_400_COMPACT return http_issue_error( client_socket, CODE_HTTPERROR_400_COMPACT )
|
||||
#define HTTPERROR_403_IP return http_issue_error( client_socket, CODE_HTTPERROR_403_IP )
|
||||
#define HTTPERROR_404 return http_issue_error( client_socket, CODE_HTTPERROR_404 )
|
||||
#define HTTPERROR_500 return http_issue_error( client_socket, CODE_HTTPERROR_500 )
|
||||
ssize_t http_issue_error( const int64 client_socket, int code ) {
|
||||
#define HTTPERROR_302 return http_issue_error( client_socket, ws, CODE_HTTPERROR_302 )
|
||||
#define HTTPERROR_400 return http_issue_error( client_socket, ws, CODE_HTTPERROR_400 )
|
||||
#define HTTPERROR_400_PARAM return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_PARAM )
|
||||
#define HTTPERROR_400_COMPACT return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_COMPACT )
|
||||
#define HTTPERROR_400_DOUBLEHASH return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_PARAM )
|
||||
#define HTTPERROR_403_IP return http_issue_error( client_socket, ws, CODE_HTTPERROR_403_IP )
|
||||
#define HTTPERROR_404 return http_issue_error( client_socket, ws, CODE_HTTPERROR_404 )
|
||||
#define HTTPERROR_500 return http_issue_error( client_socket, ws, CODE_HTTPERROR_500 )
|
||||
ssize_t http_issue_error( const int64 client_socket, struct ot_workstruct *ws, int code ) {
|
||||
char *error_code[] = { "302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request",
|
||||
"403 Access Denied", "404 Not Found", "500 Internal Server Error" };
|
||||
char *title = error_code[code];
|
||||
size_t reply_size;
|
||||
char *title = error_code[code];
|
||||
|
||||
ws->reply = ws->outbuf;
|
||||
if( code == CODE_HTTPERROR_302 )
|
||||
reply_size = sprintf( static_outbuf, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl );
|
||||
ws->reply_size = snprintf( ws->reply, ws->outbuf_size, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl );
|
||||
else
|
||||
reply_size = sprintf( static_outbuf, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", title, strlen(title)+16-4,title+4);
|
||||
ws->reply_size = snprintf( ws->reply, ws->outbuf_size, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", title, strlen(title)+16-4,title+4);
|
||||
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request );
|
||||
fprintf( stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf );
|
||||
#endif
|
||||
stats_issue_event( EVENT_FAILED, FLAG_TCP, code );
|
||||
http_senddata( client_socket, static_outbuf, reply_size);
|
||||
return -2;
|
||||
http_senddata( client_socket, ws );
|
||||
return ws->reply_size = -2;
|
||||
}
|
||||
|
||||
ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct iovec *iovector ) {
|
||||
ssize_t http_sendiovecdata( const int64 client_socket, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector ) {
|
||||
struct http_data *h = io_getcookie( client_socket );
|
||||
char *header;
|
||||
int i;
|
||||
@ -136,7 +130,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct
|
||||
}
|
||||
|
||||
/* Prepare space for http header */
|
||||
header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING );
|
||||
header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING );
|
||||
if( !header ) {
|
||||
iovec_free( &iovec_entries, &iovector );
|
||||
HTTPERROR_500;
|
||||
@ -159,7 +153,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct
|
||||
|
||||
h->flag |= STRUCT_HTTP_FLAG_IOB_USED;
|
||||
|
||||
/* writeable sockets timeout after 10 minutes) */
|
||||
/* writeable sockets timeout after 10 minutes */
|
||||
taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND );
|
||||
io_timeout( client_socket, t );
|
||||
io_dontwantread( client_socket );
|
||||
@ -167,9 +161,21 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) {
|
||||
char *c = data;
|
||||
static ssize_t http_handle_stats( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) {
|
||||
static const ot_keywords keywords_main[] =
|
||||
{ { "mode", 1 }, {"format", 2 }, { NULL, -3 } };
|
||||
static const ot_keywords keywords_mode[] =
|
||||
{ { "peer", TASK_STATS_PEERS }, { "conn", TASK_STATS_CONNS }, { "scrp", TASK_STATS_SCRAPE }, { "udp4", TASK_STATS_UDP },
|
||||
{ "busy", TASK_STATS_BUSY_NETWORKS }, { "torr", TASK_STATS_TORRENTS }, { "fscr", TASK_STATS_FULLSCRAPE },
|
||||
{ "s24s", TASK_STATS_SLASH24S }, { "tpbs", TASK_STATS_TPB }, { "herr", TASK_STATS_HTTPERRORS },
|
||||
{ "top10", TASK_STATS_TOP10 }, { "renew", TASK_STATS_RENEW }, { "syncs", TASK_STATS_SYNCS }, { "version", TASK_STATS_VERSION },
|
||||
{ "startstop", TASK_STATS_STARTSTOP }, { "toraddrem", TASK_STATS_TORADDREM }, { NULL, -3 } };
|
||||
static const ot_keywords keywords_format[] =
|
||||
{ { "bin", TASK_FULLSCRAPE_TPB_BINARY }, { "ben", TASK_FULLSCRAPE }, { "url", TASK_FULLSCRAPE_TPB_URLENCODED },
|
||||
{ "txt", TASK_FULLSCRAPE_TPB_ASCII }, { NULL, -3 } };
|
||||
|
||||
int mode = TASK_STATS_PEERS, scanon = 1, format = 0;
|
||||
|
||||
#ifdef WANT_RESTRICT_STATS
|
||||
struct http_data *h = io_getcookie( client_socket );
|
||||
|
||||
@ -178,97 +184,26 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
|
||||
#endif
|
||||
|
||||
while( scanon ) {
|
||||
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
switch( scan_find_keywords( keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
case -2: scanon = 0; break; /* TERMINATOR */
|
||||
case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
|
||||
default: scan_urlencoded_skipvalue( &c ); break;
|
||||
case 4:
|
||||
if( byte_diff(data,4,"mode")) {
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
continue;
|
||||
}
|
||||
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
|
||||
case 4:
|
||||
if( !byte_diff(data,4,"peer"))
|
||||
mode = TASK_STATS_PEERS;
|
||||
else if( !byte_diff(data,4,"conn"))
|
||||
mode = TASK_STATS_CONNS;
|
||||
else if( !byte_diff(data,4,"scrp"))
|
||||
mode = TASK_STATS_SCRAPE;
|
||||
else if( !byte_diff(data,4,"tcp4"))
|
||||
mode = TASK_STATS_TCP;
|
||||
else if( !byte_diff(data,4,"udp4"))
|
||||
mode = TASK_STATS_UDP;
|
||||
else if( !byte_diff(data,4,"busy"))
|
||||
mode = TASK_STATS_BUSY_NETWORKS;
|
||||
else if( !byte_diff(data,4,"torr"))
|
||||
mode = TASK_STATS_TORRENTS;
|
||||
else if( !byte_diff(data,4,"fscr"))
|
||||
mode = TASK_STATS_FULLSCRAPE;
|
||||
else if( !byte_diff(data,4,"s24s"))
|
||||
mode = TASK_STATS_SLASH24S;
|
||||
else if( !byte_diff(data,4,"tpbs"))
|
||||
mode = TASK_STATS_TPB;
|
||||
else if( !byte_diff(data,4,"herr"))
|
||||
mode = TASK_STATS_HTTPERRORS;
|
||||
else
|
||||
HTTPERROR_400_PARAM;
|
||||
break;
|
||||
case 5:
|
||||
if( !byte_diff(data,5,"top10"))
|
||||
mode = TASK_STATS_TOP10;
|
||||
else if( !byte_diff(data,5,"renew"))
|
||||
mode = TASK_STATS_RENEW;
|
||||
else if( !byte_diff(data,5,"syncs"))
|
||||
mode = TASK_STATS_SYNCS;
|
||||
else
|
||||
HTTPERROR_400_PARAM;
|
||||
break;
|
||||
case 7:
|
||||
if( !byte_diff(data,7,"version"))
|
||||
mode = TASK_STATS_VERSION;
|
||||
else
|
||||
HTTPERROR_400_PARAM;
|
||||
break;
|
||||
case 9:
|
||||
if( !byte_diff(data,9,"startstop"))
|
||||
mode = TASK_STATS_STARTSTOP;
|
||||
else if( !byte_diff(data,9,"toraddrem"))
|
||||
mode = TASK_STATS_TORADDREM;
|
||||
else
|
||||
HTTPERROR_400_PARAM;
|
||||
break;
|
||||
}
|
||||
case -3: scan_urlencoded_skipvalue( &read_ptr ); break;
|
||||
case 1: /* matched "mode" */
|
||||
if( ( mode = scan_find_keywords( keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
|
||||
break;
|
||||
case 6:
|
||||
if( byte_diff(data,6,"format")) {
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
continue;
|
||||
}
|
||||
if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 3 ) HTTPERROR_400_PARAM;
|
||||
if( !byte_diff(data,3,"bin"))
|
||||
format = TASK_FULLSCRAPE_TPB_BINARY;
|
||||
else if( !byte_diff(data,3,"ben"))
|
||||
format = TASK_FULLSCRAPE;
|
||||
else if( !byte_diff(data,3,"url"))
|
||||
format = TASK_FULLSCRAPE_TPB_URLENCODED;
|
||||
else if( !byte_diff(data,3,"txt"))
|
||||
format = TASK_FULLSCRAPE_TPB_ASCII;
|
||||
else
|
||||
HTTPERROR_400_PARAM;
|
||||
case 2: /* matched "format" */
|
||||
if( ( format = scan_find_keywords( keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch variable */
|
||||
d=d;
|
||||
#ifdef WANT_FULLSCRAPE
|
||||
if( mode == TASK_STATS_TPB ) {
|
||||
struct http_data* h = io_getcookie( client_socket );
|
||||
tai6464 t;
|
||||
#ifdef WANT_COMPRESSION_GZIP
|
||||
d[l-1] = 0;
|
||||
if( strstr( d, "gzip" ) ) {
|
||||
ws->request[ws->request_size] = 0;
|
||||
if( strstr( read_ptr - 1, "gzip" ) ) {
|
||||
h->flag |= STRUCT_HTTP_FLAG_GZIP;
|
||||
format |= TASK_FLAG_GZIP;
|
||||
}
|
||||
@ -280,7 +215,7 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
|
||||
taia_uint( &t, 0 ); io_timeout( client_socket, t );
|
||||
fullscrape_deliver( client_socket, format );
|
||||
io_dontwantread( client_socket );
|
||||
return -2;
|
||||
return ws->reply_size = -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -290,27 +225,24 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d
|
||||
/* Complex stats also include expensive memory debugging tools */
|
||||
taia_uint( &t, 0 ); io_timeout( client_socket, t );
|
||||
stats_deliver( client_socket, mode );
|
||||
return -2;
|
||||
return ws->reply_size = -2;
|
||||
}
|
||||
|
||||
/* Simple stats can be answerred immediately */
|
||||
if( !( l = return_stats_for_tracker( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, mode, 0 ) ) ) HTTPERROR_500;
|
||||
if( !( ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 ) ) ) HTTPERROR_500;
|
||||
|
||||
return l;
|
||||
return ws->reply_size;
|
||||
}
|
||||
|
||||
#ifdef WANT_FULLSCRAPE
|
||||
static ssize_t http_handle_fullscrape( const int64 client_socket, char *d, size_t l ) {
|
||||
static ssize_t http_handle_fullscrape( const int64 client_socket, struct ot_workstruct *ws ) {
|
||||
struct http_data* h = io_getcookie( client_socket );
|
||||
int format = 0;
|
||||
tai6464 t;
|
||||
|
||||
/* Touch variables */
|
||||
d=d;l=l;
|
||||
|
||||
#ifdef WANT_COMPRESSION_GZIP
|
||||
d[l-1] = 0;
|
||||
if( strstr( d, "gzip" ) ) {
|
||||
ws->request[ws->request_size-1] = 0;
|
||||
if( strstr( ws->request, "gzip" ) ) {
|
||||
h->flag |= STRUCT_HTTP_FLAG_GZIP;
|
||||
format = TASK_FLAG_GZIP;
|
||||
stats_issue_event( EVENT_FULLSCRAPE_REQUEST_GZIP, *(int*)h->ip, 0 );
|
||||
@ -319,7 +251,7 @@ static ssize_t http_handle_fullscrape( const int64 client_socket, char *d, size_
|
||||
stats_issue_event( EVENT_FULLSCRAPE_REQUEST, *(int*)h->ip, 0 );
|
||||
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
write( 2, debug_request, l );
|
||||
write( 2, ws->debugbuf, ws->debugbuf_size );
|
||||
#endif
|
||||
|
||||
/* Pass this task to the worker thread */
|
||||
@ -328,72 +260,70 @@ write( 2, debug_request, l );
|
||||
taia_uint( &t, 0 ); io_timeout( client_socket, t );
|
||||
fullscrape_deliver( client_socket, TASK_FULLSCRAPE | format );
|
||||
io_dontwantread( client_socket );
|
||||
return -2;
|
||||
return ws->reply_size = -2;
|
||||
}
|
||||
#endif
|
||||
static ssize_t http_handle_scrape( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) {
|
||||
static const ot_keywords keywords_scrape[] = { { "info_hash", 1 }, { NULL, -3 } };
|
||||
|
||||
static ssize_t http_handle_scrape( const int64 client_socket, char *data ) {
|
||||
ot_hash * multiscrape_buf = (ot_hash*)ws->request;
|
||||
int scanon = 1, numwant = 0;
|
||||
char *c = data;
|
||||
size_t l;
|
||||
|
||||
/* This is to hack around stupid clients that send "scrape ?info_hash" */
|
||||
if( c[-1] != '?' ) {
|
||||
while( ( *c != '?' ) && ( *c != '\n' ) ) ++c;
|
||||
if( *c == '\n' ) HTTPERROR_400_PARAM;
|
||||
++c;
|
||||
if( read_ptr[-1] != '?' ) {
|
||||
while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr;
|
||||
if( *read_ptr == '\n' ) HTTPERROR_400_PARAM;
|
||||
++read_ptr;
|
||||
}
|
||||
|
||||
while( scanon ) {
|
||||
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
switch( scan_find_keywords( keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
case -2: scanon = 0; break; /* TERMINATOR */
|
||||
case -1:
|
||||
if( numwant )
|
||||
goto UTORRENT1600_WORKAROUND;
|
||||
HTTPERROR_400_PARAM; /* PARSE ERROR */
|
||||
default: scan_urlencoded_skipvalue( &c ); break;
|
||||
case 9:
|
||||
if(byte_diff(data,9,"info_hash")) {
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
continue;
|
||||
}
|
||||
default: HTTPERROR_400_PARAM; /* PARSE ERROR */
|
||||
case -3: scan_urlencoded_skipvalue( &read_ptr ); break;
|
||||
case 1: /* matched "info_hash" */
|
||||
/* ignore this, when we have less than 20 bytes */
|
||||
if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) ) {
|
||||
#ifdef WANT_UTORRENT1600_WORKAROUND
|
||||
if( data[20] != '?' )
|
||||
#endif
|
||||
if( scan_urlencoded_query( &read_ptr, (char*)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) )
|
||||
HTTPERROR_400_PARAM;
|
||||
}
|
||||
if( numwant < OT_MAXMULTISCRAPE_COUNT )
|
||||
memmove( multiscrape_buf + numwant++, data, sizeof(ot_hash) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UTORRENT1600_WORKAROUND:
|
||||
|
||||
/* No info_hash found? Inform user */
|
||||
if( !numwant ) HTTPERROR_400_PARAM;
|
||||
|
||||
/* Limit number of hashes to process */
|
||||
if( numwant > OT_MAXMULTISCRAPE_COUNT )
|
||||
numwant = OT_MAXMULTISCRAPE_COUNT;
|
||||
|
||||
/* Enough for http header + whole scrape string */
|
||||
if( !( l = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf ) ) ) HTTPERROR_500;
|
||||
stats_issue_event( EVENT_SCRAPE, FLAG_TCP, l );
|
||||
return l;
|
||||
if( !( ws->reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, ws->reply ) ) ) HTTPERROR_500;
|
||||
stats_issue_event( EVENT_SCRAPE, FLAG_TCP, ws->reply_size );
|
||||
return ws->reply_size;
|
||||
}
|
||||
|
||||
static ssize_t http_handle_announce( const int64 client_socket, char *data ) {
|
||||
char *c = data;
|
||||
int numwant, tmp, scanon;
|
||||
ot_peer peer;
|
||||
ot_hash *hash = NULL;
|
||||
static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "event", 3 }, { "numwant", 4 }, { "compact", 5 }, { "info_hash", 6 },
|
||||
#ifdef WANT_IP_FROM_QUERY_STRING
|
||||
{ "ip", 7 },
|
||||
#endif
|
||||
#ifdef _DEBUG_PEERID
|
||||
{ "peer_id", 8 },
|
||||
#endif
|
||||
{ NULL, -3 } };
|
||||
static ot_keywords keywords_announce_event[] = { { "completed", 1 }, { "stopped", 2 }, { NULL, -3 } };
|
||||
static ssize_t http_handle_announce( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) {
|
||||
int numwant, tmp, scanon;
|
||||
ot_peer peer;
|
||||
ot_hash *hash = NULL;
|
||||
unsigned short port = htons(6881);
|
||||
ssize_t len;
|
||||
|
||||
char *write_ptr;
|
||||
ssize_t len;
|
||||
|
||||
/* This is to hack around stupid clients that send "announce ?info_hash" */
|
||||
if( c[-1] != '?' ) {
|
||||
while( ( *c != '?' ) && ( *c != '\n' ) ) ++c;
|
||||
if( *c == '\n' ) HTTPERROR_400_PARAM;
|
||||
++c;
|
||||
if( read_ptr[-1] != '?' ) {
|
||||
while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr;
|
||||
if( *read_ptr == '\n' ) HTTPERROR_400_PARAM;
|
||||
++read_ptr;
|
||||
}
|
||||
|
||||
OT_SETIP( &peer, ((struct http_data*)io_getcookie( client_socket ) )->ip );
|
||||
@ -403,168 +333,156 @@ static ssize_t http_handle_announce( const int64 client_socket, char *data ) {
|
||||
scanon = 1;
|
||||
|
||||
#ifdef _DEBUG_PEERID
|
||||
g_this_peerid_data = NULL;
|
||||
ws->peer_id = NULL;
|
||||
#endif
|
||||
|
||||
while( scanon ) {
|
||||
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
switch( scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
case -2: scanon = 0; break; /* TERMINATOR */
|
||||
case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
|
||||
default: scan_urlencoded_skipvalue( &c ); break;
|
||||
#ifdef WANT_IP_FROM_QUERY_STRING
|
||||
case 2:
|
||||
if(!byte_diff(data,2,"ip")) {
|
||||
unsigned char ip[4];
|
||||
len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) HTTPERROR_400_PARAM;
|
||||
OT_SETIP( &peer, ip );
|
||||
} else
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
break;
|
||||
#endif
|
||||
case 4:
|
||||
if( !byte_diff( data, 4, "port" ) ) {
|
||||
len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM;
|
||||
port = htons( tmp ); OT_SETPORT( &peer, &port );
|
||||
} else if( !byte_diff( data, 4, "left" ) ) {
|
||||
if( ( len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
|
||||
if( scan_fixed_int( data, len, &tmp ) ) tmp = 0;
|
||||
if( !tmp ) OT_PEERFLAG( &peer ) |= PEER_FLAG_SEEDING;
|
||||
} else
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
case -3: scan_urlencoded_skipvalue( &read_ptr ); break;
|
||||
case 1: /* matched "port" */
|
||||
len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM;
|
||||
port = htons( tmp ); OT_SETPORT( &peer, &port );
|
||||
break;
|
||||
case 5:
|
||||
if( byte_diff( data, 5, "event" ) )
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
|
||||
case -1:
|
||||
HTTPERROR_400_PARAM;
|
||||
case 7:
|
||||
if( !byte_diff( data, 7, "stopped" ) ) OT_PEERFLAG( &peer ) |= PEER_FLAG_STOPPED;
|
||||
break;
|
||||
case 9:
|
||||
if( !byte_diff( data, 9, "completed" ) ) OT_PEERFLAG( &peer ) |= PEER_FLAG_COMPLETED;
|
||||
default: /* Fall through intended */
|
||||
break;
|
||||
case 2: /* matched "left" */
|
||||
if( ( len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
|
||||
if( scan_fixed_int( write_ptr, len, &tmp ) ) tmp = 0;
|
||||
if( !tmp ) OT_PEERFLAG( &peer ) |= PEER_FLAG_SEEDING;
|
||||
break;
|
||||
case 3: /* matched "event" */
|
||||
switch( scan_find_keywords( keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) {
|
||||
case -1: HTTPERROR_400_PARAM;
|
||||
case 1: /* matched "completed" */
|
||||
OT_PEERFLAG( &peer ) |= PEER_FLAG_COMPLETED;
|
||||
break;
|
||||
case 2: /* matched "stopped" */
|
||||
OT_PEERFLAG( &peer ) |= PEER_FLAG_STOPPED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if(!byte_diff(data,7,"numwant")) {
|
||||
len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) HTTPERROR_400_PARAM;
|
||||
if( numwant < 0 ) numwant = 50;
|
||||
if( numwant > 200 ) numwant = 200;
|
||||
} else if(!byte_diff(data,7,"compact")) {
|
||||
len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) HTTPERROR_400_PARAM;
|
||||
if( !tmp ) HTTPERROR_400_COMPACT;
|
||||
} else
|
||||
#ifdef _DEBUG_PEERID
|
||||
if(!byte_diff(data,7,"peer_id")) {
|
||||
g_this_peerid_len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
|
||||
g_this_peerid_data = g_this_peerid_len > 0 ? data : 0;
|
||||
} else
|
||||
#endif
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
case 4: /* matched "numwant" */
|
||||
len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &numwant ) ) HTTPERROR_400_PARAM;
|
||||
if( numwant < 0 ) numwant = 50;
|
||||
if( numwant > 200 ) numwant = 200;
|
||||
break;
|
||||
case 9:
|
||||
if(byte_diff(data,9,"info_hash")) {
|
||||
scan_urlencoded_skipvalue( &c );
|
||||
continue;
|
||||
}
|
||||
case 5: /* matched "compact" */
|
||||
len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) ) HTTPERROR_400_PARAM;
|
||||
if( !tmp ) HTTPERROR_400_COMPACT;
|
||||
break;
|
||||
case 6: /* matched "info_hash" */
|
||||
if( hash ) HTTPERROR_400_DOUBLEHASH;
|
||||
/* 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;
|
||||
if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM;
|
||||
hash = (ot_hash*)write_ptr;
|
||||
break;
|
||||
#ifdef WANT_IP_FROM_QUERY_STRING
|
||||
case 7: /* matched "ip" */
|
||||
len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
|
||||
if( ( len <= 0 ) || scan_fixed_ip( write_ptr, len, (unsigned char*)/*tmp*/ws->reply ) ) HTTPERROR_400_PARAM;
|
||||
OT_SETIP( &peer, /*tmp*/ws->reply );
|
||||
break;
|
||||
#endif
|
||||
#ifdef _DEBUG_PEERID
|
||||
case 8: /* matched "peer_id" */
|
||||
ws->peer_id_size = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
|
||||
ws->peer_id = ws->peer_id_size > 0 ? write_ptr : 0;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Scanned whole query string */
|
||||
if( !hash )
|
||||
return sprintf( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" );
|
||||
return ws->reply_size = sprintf( ws->reply, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" );
|
||||
|
||||
if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED )
|
||||
len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP );
|
||||
ws->reply_size = remove_peer_from_torrent( hash, &peer, ws->reply, FLAG_TCP );
|
||||
else
|
||||
len = add_peer_to_torrent_and_return_peers(hash, &peer, FLAG_TCP, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf);
|
||||
ws->reply_size = add_peer_to_torrent_and_return_peers(hash, &peer, FLAG_TCP, numwant, ws->reply );
|
||||
|
||||
if( !len ) HTTPERROR_500;
|
||||
if( !ws->reply_size ) HTTPERROR_500;
|
||||
|
||||
stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, len);
|
||||
return len;
|
||||
stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size);
|
||||
return ws->reply_size;
|
||||
}
|
||||
|
||||
ssize_t http_handle_request( const int64 client_socket, char *data, size_t recv_length ) {
|
||||
char *c, *recv_header=data;
|
||||
ssize_t reply_size = 0, reply_off, len;
|
||||
ssize_t http_handle_request( const int64 client_socket, struct ot_workstruct *ws ) {
|
||||
ssize_t reply_off, len;
|
||||
char *read_ptr = ws->request, *write_ptr;
|
||||
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
if( recv_length >= sizeof( debug_request ) )
|
||||
recv_length = sizeof( debug_request) - 1;
|
||||
memmove( debug_request, recv_header, recv_length );
|
||||
debug_request[ recv_length ] = 0;
|
||||
reply_off = ws->request_size;
|
||||
if( ws->request_size >= (ssize_t)ws->debugbuf_size )
|
||||
reply_off = ws->debugbuf_size - 1;
|
||||
memmove( ws->debugbuf, ws->request, reply_off );
|
||||
ws->debugbuf[ reply_off ] = 0;
|
||||
#endif
|
||||
|
||||
/* Tell subroutines where to put reply data */
|
||||
ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH;
|
||||
|
||||
/* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */
|
||||
if( byte_diff( data, 5, "GET /") ) HTTPERROR_400;
|
||||
if( memcmp( read_ptr, "GET /", 5) ) HTTPERROR_400;
|
||||
|
||||
/* Skip leading '/' */
|
||||
for( c = data+4; *c == '/'; ++c);
|
||||
for( read_ptr+=4; *read_ptr == '/'; ++read_ptr);
|
||||
|
||||
/* Try to parse the request.
|
||||
In reality we abandoned requiring the url to be correct. This now
|
||||
only decodes url encoded characters, we check for announces and
|
||||
scrapes by looking for "a*" or "sc" */
|
||||
len = scan_urlencoded_query( &c, data = c, SCAN_PATH );
|
||||
len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_PATH );
|
||||
|
||||
/* If parsing returned an error, leave with not found */
|
||||
if( g_redirecturl && ( len == -2 ) ) HTTPERROR_302;
|
||||
if( len <= 0 ) HTTPERROR_404;
|
||||
|
||||
/* This is the hardcore match for announce*/
|
||||
if( ( *data == 'a' ) || ( *data == '?' ) )
|
||||
reply_size = http_handle_announce( client_socket, c );
|
||||
if( ( *write_ptr == 'a' ) || ( *write_ptr == '?' ) )
|
||||
http_handle_announce( client_socket, ws, read_ptr );
|
||||
#ifdef WANT_FULLSCRAPE
|
||||
else if( !byte_diff( data, 12, "scrape HTTP/" ) )
|
||||
reply_size = http_handle_fullscrape( client_socket, recv_header, recv_length );
|
||||
else if( !memcmp( write_ptr, "scrape HTTP/", 12 ) )
|
||||
http_handle_fullscrape( client_socket, ws );
|
||||
#endif
|
||||
/* This is the hardcore match for scrape */
|
||||
else if( !byte_diff( data, 2, "sc" ) )
|
||||
reply_size = http_handle_scrape( client_socket, c );
|
||||
else if( !memcmp( write_ptr, "sc", 2 ) )
|
||||
http_handle_scrape( client_socket, ws, read_ptr );
|
||||
/* All the rest is matched the standard way */
|
||||
else switch( len ) {
|
||||
case 5: /* stats ? */
|
||||
if( byte_diff( data, 5, "stats") ) HTTPERROR_404;
|
||||
reply_size = http_handle_stats( client_socket, c, recv_header, recv_length );
|
||||
break;
|
||||
default:
|
||||
else if( !memcmp( write_ptr, "stats", 5) )
|
||||
http_handle_stats( client_socket, ws, read_ptr );
|
||||
else
|
||||
HTTPERROR_404;
|
||||
}
|
||||
|
||||
/* If routines handled sending themselves, just return */
|
||||
if( reply_size == -2 ) return 0;
|
||||
if( ws->reply_size == -2 ) return 0;
|
||||
/* If routine failed, let http error take over */
|
||||
if( reply_size == -1 ) HTTPERROR_500;
|
||||
if( ws->reply_size == -1 ) HTTPERROR_500;
|
||||
|
||||
/* 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
|
||||
write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string
|
||||
write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our work buffer, which is enough for the static string
|
||||
plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate
|
||||
the space NOT needed to expand in reply_off
|
||||
*/
|
||||
reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_outbuf, 0, "%zd", reply_size );
|
||||
|
||||
reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( ws->outbuf, 0, "%zd", ws->reply_size );
|
||||
ws->reply = ws->outbuf + reply_off;
|
||||
|
||||
/* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete
|
||||
packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */
|
||||
reply_size += 1 + sprintf( static_outbuf + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size );
|
||||
ws->reply_size += 1 + sprintf( ws->reply, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", ws->reply_size );
|
||||
|
||||
/* 3. Finally we join both blocks neatly */
|
||||
static_outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';
|
||||
|
||||
http_senddata( client_socket, static_outbuf + reply_off, reply_size );
|
||||
return reply_size;
|
||||
ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';
|
||||
|
||||
http_senddata( client_socket, ws );
|
||||
return ws->reply_size;
|
||||
}
|
||||
|
||||
const char *g_version_http_c = "$Source$: $Revision$\n";
|
||||
|
@ -23,8 +23,8 @@ struct http_data {
|
||||
STRUCT_HTTP_FLAG flag;
|
||||
};
|
||||
|
||||
ssize_t http_handle_request( const int64 s, char *data, size_t l );
|
||||
ssize_t http_sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovector );
|
||||
ssize_t http_issue_error( const int64 s, int code );
|
||||
ssize_t http_handle_request( const int64 s, struct ot_workstruct *ws );
|
||||
ssize_t http_sendiovecdata( const int64 s, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector );
|
||||
ssize_t http_issue_error( const int64 s, struct ot_workstruct *ws, int code );
|
||||
|
||||
#endif
|
||||
|
@ -400,9 +400,6 @@ static void * livesync_worker( void * args ) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle outstanding requests */
|
||||
livesync_ticker( );
|
||||
}
|
||||
|
||||
/* Never returns. */
|
||||
|
29
ot_udp.c
29
ot_udp.c
@ -17,9 +17,6 @@
|
||||
#include "ot_udp.h"
|
||||
#include "ot_stats.h"
|
||||
|
||||
static char static_inbuf[8192];
|
||||
static char static_outbuf[8192];
|
||||
|
||||
static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
|
||||
|
||||
static void udp_make_connectionid( uint32_t * connid, const char * remoteip ) {
|
||||
@ -39,17 +36,17 @@ static int udp_test_connectionid( const uint32_t * const connid, const char * re
|
||||
}
|
||||
|
||||
/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
|
||||
void handle_udp4( int64 serversocket ) {
|
||||
void handle_udp4( int64 serversocket, struct ot_workstruct *ws ) {
|
||||
ot_peer peer;
|
||||
ot_hash *hash = NULL;
|
||||
char remoteip[4];
|
||||
uint32_t *inpacket = (uint32_t*)static_inbuf;
|
||||
uint32_t *outpacket = (uint32_t*)static_outbuf;
|
||||
uint32_t *inpacket = (uint32_t*)ws->inbuf;
|
||||
uint32_t *outpacket = (uint32_t*)ws->outbuf;
|
||||
uint32_t numwant, left, event;
|
||||
uint16_t port, remoteport;
|
||||
size_t r, r_out;
|
||||
|
||||
r = socket_recv4( serversocket, static_inbuf, sizeof( static_inbuf ), remoteip, &remoteport);
|
||||
r = socket_recv4( serversocket, ws->inbuf, ws->inbuf_size, remoteip, &remoteport);
|
||||
|
||||
stats_issue_event( EVENT_ACCEPT, FLAG_UDP, ntohl(*(uint32_t*)remoteip) );
|
||||
stats_issue_event( EVENT_READ, FLAG_UDP, r );
|
||||
@ -58,8 +55,6 @@ void handle_udp4( int64 serversocket ) {
|
||||
if( r < 16 )
|
||||
return;
|
||||
|
||||
/* fprintf( stderr, "UDP Connection id: %16llX\n", *(uint64_t*)inpacket ); */
|
||||
|
||||
switch( ntohl( inpacket[2] ) ) {
|
||||
case 0: /* This is a connect action */
|
||||
/* look for udp bittorrent magic id */
|
||||
@ -70,7 +65,7 @@ void handle_udp4( int64 serversocket ) {
|
||||
outpacket[1] = inpacket[3];
|
||||
udp_make_connectionid( outpacket + 2, remoteip );
|
||||
|
||||
socket_send4( serversocket, static_outbuf, 16, remoteip, remoteport );
|
||||
socket_send4( serversocket, ws->outbuf, 16, remoteip, remoteport );
|
||||
stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 );
|
||||
break;
|
||||
case 1: /* This is an announce action */
|
||||
@ -88,8 +83,8 @@ void handle_udp4( int64 serversocket ) {
|
||||
if (numwant > 200) numwant = 200;
|
||||
|
||||
event = ntohl( inpacket[80/4] );
|
||||
port = *(uint16_t*)( static_inbuf + 96 );
|
||||
hash = (ot_hash*)( static_inbuf + 16 );
|
||||
port = *(uint16_t*)( ((char*)inpacket) + 96 );
|
||||
hash = (ot_hash*)( ((char*)inpacket) + 16 );
|
||||
|
||||
OT_SETIP( &peer, remoteip );
|
||||
OT_SETPORT( &peer, &port );
|
||||
@ -108,11 +103,11 @@ void handle_udp4( int64 serversocket ) {
|
||||
outpacket[1] = inpacket[12/4];
|
||||
|
||||
if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) /* Peer is gone. */
|
||||
r = remove_peer_from_torrent( hash, &peer, static_outbuf, FLAG_UDP );
|
||||
r = remove_peer_from_torrent( hash, &peer, ws->outbuf, FLAG_UDP );
|
||||
else
|
||||
r = 8 + add_peer_to_torrent_and_return_peers( hash, &peer, FLAG_UDP, numwant, static_outbuf + 8 );
|
||||
r = 8 + add_peer_to_torrent_and_return_peers( hash, &peer, FLAG_UDP, numwant, ((char*)outpacket) + 8 );
|
||||
|
||||
socket_send4( serversocket, static_outbuf, r, remoteip, remoteport );
|
||||
socket_send4( serversocket, ws->outbuf, r, remoteip, remoteport );
|
||||
stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, r );
|
||||
break;
|
||||
|
||||
@ -124,9 +119,9 @@ void handle_udp4( int64 serversocket ) {
|
||||
outpacket[1] = inpacket[12/4];
|
||||
|
||||
for( r_out = 0; ( r_out * 20 < r - 16) && ( r_out <= 74 ); r_out++ )
|
||||
return_udp_scrape_for_torrent( (ot_hash*)( static_inbuf + 16 + 20 * r_out ), static_outbuf + 8 + 12 * r_out );
|
||||
return_udp_scrape_for_torrent( (ot_hash*)( ((char*)inpacket) + 16 + 20 * r_out ), ((char*)outpacket) + 8 + 12 * r_out );
|
||||
|
||||
socket_send4( serversocket, static_outbuf, 8 + 12 * r_out, remoteip, remoteport );
|
||||
socket_send4( serversocket, ws->outbuf, 8 + 12 * r_out, remoteip, remoteport );
|
||||
stats_issue_event( EVENT_SCRAPE, FLAG_UDP, r );
|
||||
break;
|
||||
}
|
||||
|
2
ot_udp.h
2
ot_udp.h
@ -6,6 +6,6 @@
|
||||
#ifndef __OT_UDP_H__
|
||||
#define __OT_UDP_H__
|
||||
|
||||
void handle_udp4( int64 serversocket );
|
||||
void handle_udp4( int64 serversocket, struct ot_workstruct *ws );
|
||||
|
||||
#endif
|
||||
|
@ -9,6 +9,9 @@
|
||||
/* Libwofat */
|
||||
#include "scan.h"
|
||||
|
||||
/* System */
|
||||
#include <string.h>
|
||||
|
||||
/* Idea is to do a in place replacement or guarantee at least
|
||||
strlen( string ) bytes in deststring
|
||||
watch http://www.ietf.org/rfc/rfc2396.txt
|
||||
@ -64,6 +67,22 @@ void scan_urlencoded_skipvalue( char **string ) {
|
||||
*string = (char*)s;
|
||||
}
|
||||
|
||||
int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCHPATH_FLAG flags) {
|
||||
char *deststring = *string;
|
||||
ssize_t match_length = scan_urlencoded_query(string, deststring, flags );
|
||||
|
||||
if( match_length < 0 ) return match_length;
|
||||
if( match_length == 0 ) return -3;
|
||||
|
||||
while( keywords->key ) {
|
||||
if( !memcmp( keywords->key, deststring, match_length ) )
|
||||
return keywords->value;
|
||||
keywords++;
|
||||
}
|
||||
|
||||
return -3;
|
||||
}
|
||||
|
||||
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) {
|
||||
const unsigned char* s=*(const unsigned char**) string;
|
||||
unsigned char *d = (unsigned char*)deststring;
|
||||
@ -95,9 +114,7 @@ ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_F
|
||||
--s;
|
||||
break;
|
||||
case '?':
|
||||
/* XXX to help us parse path?param=value?param=value?... sent by µTorrent 1600
|
||||
do not return an error but silently terminate
|
||||
if( flags != SCAN_PATH ) return -1; */
|
||||
if( flags != SCAN_PATH ) return -1;
|
||||
break;
|
||||
case '=':
|
||||
if( flags != SCAN_SEARCHPATH_PARAM ) return -1;
|
||||
|
@ -8,6 +8,11 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
char *key;
|
||||
int value;
|
||||
} ot_keywords;
|
||||
|
||||
typedef enum {
|
||||
SCAN_PATH = 1,
|
||||
SCAN_SEARCHPATH_PARAM = 2,
|
||||
@ -21,9 +26,20 @@ typedef enum {
|
||||
flags determines, what to parse
|
||||
returns number of valid converted characters in deststring
|
||||
or -1 for parse error
|
||||
or -2 for terminator found
|
||||
*/
|
||||
ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags);
|
||||
|
||||
/* string in: pointer to source
|
||||
out: pointer to next scan position
|
||||
flags determines, what to parse
|
||||
returns value for matched keyword
|
||||
or -1 for parse error
|
||||
or -2 for terminator found
|
||||
or -3 for no keyword matched
|
||||
*/
|
||||
int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCHPATH_FLAG flags);
|
||||
|
||||
/* string in: pointer to value of a param=value pair to skip
|
||||
out: pointer to next scan position on return
|
||||
*/
|
||||
|
@ -96,6 +96,31 @@ struct ot_peerlist {
|
||||
};
|
||||
#define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list) && ((peer_list)->peers.size > (peer_list)->peers.space))
|
||||
|
||||
struct ot_workstruct {
|
||||
/* Thread specific, static */
|
||||
#define THREAD_INBUF_SIZE 8192
|
||||
char *inbuf;
|
||||
size_t inbuf_size;
|
||||
#define THREAD_OUTBUF_SIZE 8192
|
||||
char *outbuf;
|
||||
size_t outbuf_size;
|
||||
#ifdef _DEBUG_HTTPERROR
|
||||
#define THREAD_DEBUGBUF_SIZE 8192
|
||||
char *debugbuf;
|
||||
size_t debugbuf_size;
|
||||
#endif
|
||||
|
||||
/* HTTP specific, non static */
|
||||
char *request;
|
||||
ssize_t request_size;
|
||||
char *reply;
|
||||
ssize_t reply_size;
|
||||
#ifdef _DEBUG_PEERID
|
||||
char *peer_id;
|
||||
ssize_t peer_id_size;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
Exported functions
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user