From 779d6c235ff8fe5284fd10dc82a9b99e7fa38d06 Mon Sep 17 00:00:00 2001 From: erdgeist <> Date: Mon, 5 Jan 2009 18:05:39 +0000 Subject: * 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 --- Makefile | 3 +- opentracker.c | 67 ++++--- ot_http.c | 454 ++++++++++++++++++++---------------------------- ot_http.h | 6 +- ot_livesync.c | 3 - ot_udp.c | 29 ++-- ot_udp.h | 2 +- scan_urlencoded_query.c | 23 ++- scan_urlencoded_query.h | 16 ++ trackerlogic.h | 25 +++ 10 files changed, 310 insertions(+), 318 deletions(-) diff --git a/Makefile b/Makefile index 000103e..ca4e71b 100644 --- a/Makefile +++ b/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 diff --git a/opentracker.c b/opentracker.c index bce5be0..8a4126c 100644 --- a/opentracker.c +++ b/opentracker.c @@ -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 ); } diff --git a/ot_http.c b/ot_http.c index 55c524d..8c85689 100644 --- a/ot_http.c +++ b/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%s\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%s\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"; diff --git a/ot_http.h b/ot_http.h index cd8c3cb..18e8156 100644 --- a/ot_http.h +++ b/ot_http.h @@ -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 diff --git a/ot_livesync.c b/ot_livesync.c index 47a371a..a47edba 100644 --- a/ot_livesync.c +++ b/ot_livesync.c @@ -400,9 +400,6 @@ static void * livesync_worker( void * args ) { default: break; } - - /* Handle outstanding requests */ - livesync_ticker( ); } /* Never returns. */ diff --git a/ot_udp.c b/ot_udp.c index fb171e7..81c4d63 100644 --- a/ot_udp.c +++ b/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; } diff --git a/ot_udp.h b/ot_udp.h index c5f3959..c146392 100644 --- a/ot_udp.h +++ b/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 diff --git a/scan_urlencoded_query.c b/scan_urlencoded_query.c index a17db2a..c3acefc 100644 --- a/scan_urlencoded_query.c +++ b/scan_urlencoded_query.c @@ -9,6 +9,9 @@ /* Libwofat */ #include "scan.h" +/* System */ +#include + /* 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; diff --git a/scan_urlencoded_query.h b/scan_urlencoded_query.h index 7ff6e42..a0b77af 100644 --- a/scan_urlencoded_query.h +++ b/scan_urlencoded_query.h @@ -8,6 +8,11 @@ #include +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 */ diff --git a/trackerlogic.h b/trackerlogic.h index 34cee3b..eb2906b 100644 --- a/trackerlogic.h +++ b/trackerlogic.h @@ -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 */ -- cgit v1.2.3