diff options
author | erdgeist <> | 2009-01-05 18:05:39 +0000 |
---|---|---|
committer | erdgeist <> | 2009-01-05 18:05:39 +0000 |
commit | 779d6c235ff8fe5284fd10dc82a9b99e7fa38d06 (patch) | |
tree | 043369d2a98a45b902e5d0968e28d78c1771b143 | |
parent | 8bdc0d73f6f0bcaf83b7fb3d39e79e8fa4e6050d (diff) |
* 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
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | opentracker.c | 67 | ||||
-rw-r--r-- | ot_http.c | 454 | ||||
-rw-r--r-- | ot_http.h | 6 | ||||
-rw-r--r-- | ot_livesync.c | 3 | ||||
-rw-r--r-- | ot_udp.c | 29 | ||||
-rw-r--r-- | ot_udp.h | 2 | ||||
-rw-r--r-- | scan_urlencoded_query.c | 23 | ||||
-rw-r--r-- | scan_urlencoded_query.h | 16 | ||||
-rw-r--r-- | trackerlogic.h | 25 |
10 files changed, 310 insertions, 318 deletions
@@ -24,7 +24,6 @@ BINDIR?=$(PREFIX)/bin | |||
24 | 24 | ||
25 | #FEATURES+=-DWANT_SYNC_LIVE | 25 | #FEATURES+=-DWANT_SYNC_LIVE |
26 | #FEATURES+=-DWANT_SYNC_SCRAPE | 26 | #FEATURES+=-DWANT_SYNC_SCRAPE |
27 | #FEATURES+=-DWANT_UTORRENT1600_WORKAROUND | ||
28 | #FEATURES+=-DWANT_IP_FROM_QUERY_STRING | 27 | #FEATURES+=-DWANT_IP_FROM_QUERY_STRING |
29 | #FEATURES+=-DWANT_COMPRESSION_GZIP | 28 | #FEATURES+=-DWANT_COMPRESSION_GZIP |
30 | #FEATURES+=-DWANT_LOG_NETWORKS | 29 | #FEATURES+=-DWANT_LOG_NETWORKS |
@@ -37,7 +36,7 @@ FEATURES+=-DWANT_FULLSCRAPE | |||
37 | OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage | 36 | OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage |
38 | OPTS_production=-Os | 37 | OPTS_production=-Os |
39 | 38 | ||
40 | CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-pedantic -ansi | 39 | CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra #-ansi -pedantic |
41 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz | 40 | LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lz |
42 | 41 | ||
43 | BINARY =opentracker | 42 | 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; | |||
41 | 41 | ||
42 | static char * g_serverdir = NULL; | 42 | static char * g_serverdir = NULL; |
43 | 43 | ||
44 | /* To always have space for error messages ;) */ | ||
45 | static char static_inbuf[8192]; | ||
46 | |||
47 | static void panic( const char *routine ) { | 44 | static void panic( const char *routine ) { |
48 | fprintf( stderr, "%s: %s\n", routine, strerror(errno) ); | 45 | fprintf( stderr, "%s: %s\n", routine, strerror(errno) ); |
49 | exit( 111 ); | 46 | exit( 111 ); |
@@ -107,37 +104,44 @@ static void handle_dead( const int64 socket ) { | |||
107 | io_close( socket ); | 104 | io_close( socket ); |
108 | } | 105 | } |
109 | 106 | ||
110 | static ssize_t handle_read( const int64 clientsocket ) { | 107 | static ssize_t handle_read( const int64 clientsocket, struct ot_workstruct *ws ) { |
111 | struct http_data* h = io_getcookie( clientsocket ); | 108 | struct http_data* h = io_getcookie( clientsocket ); |
112 | ssize_t l; | 109 | ssize_t l; |
113 | 110 | ||
114 | if( ( l = io_tryread( clientsocket, static_inbuf, sizeof static_inbuf ) ) <= 0 ) { | 111 | if( ( l = io_tryread( clientsocket, ws->inbuf, ws->inbuf_size ) ) <= 0 ) { |
115 | handle_dead( clientsocket ); | 112 | handle_dead( clientsocket ); |
116 | return 0; | 113 | return 0; |
117 | } | 114 | } |
118 | 115 | ||
119 | /* If we get the whole request in one packet, handle it without copying */ | 116 | /* If we get the whole request in one packet, handle it without copying */ |
120 | if( !array_start( &h->data.request ) ) { | 117 | if( !array_start( &h->data.request ) ) { |
121 | if( memchr( static_inbuf, '\n', l ) ) | 118 | if( memchr( ws->inbuf, '\n', l ) ) { |
122 | return http_handle_request( clientsocket, static_inbuf, l ); | 119 | ws->request = ws->inbuf; |
120 | ws->request_size = l; | ||
121 | return http_handle_request( clientsocket, ws ); | ||
122 | } | ||
123 | |||
124 | /* ... else take a copy */ | ||
123 | h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; | 125 | h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; |
124 | array_catb( &h->data.request, static_inbuf, l ); | 126 | array_catb( &h->data.request, ws->inbuf, l ); |
125 | return 0; | 127 | return 0; |
126 | } | 128 | } |
127 | 129 | ||
128 | h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; | 130 | h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; |
129 | array_catb( &h->data.request, static_inbuf, l ); | 131 | array_catb( &h->data.request, ws->inbuf, l ); |
130 | 132 | ||
131 | if( array_failed( &h->data.request ) ) | 133 | if( array_failed( &h->data.request ) ) |
132 | return http_issue_error( clientsocket, CODE_HTTPERROR_500 ); | 134 | return http_issue_error( clientsocket, ws, CODE_HTTPERROR_500 ); |
133 | 135 | ||
134 | if( array_bytes( &h->data.request ) > 8192 ) | 136 | if( array_bytes( &h->data.request ) > 8192 ) |
135 | return http_issue_error( clientsocket, CODE_HTTPERROR_500 ); | 137 | return http_issue_error( clientsocket, ws, CODE_HTTPERROR_500 ); |
136 | 138 | ||
137 | if( memchr( array_start( &h->data.request ), '\n', array_bytes( &h->data.request ) ) ) | 139 | if( !memchr( array_start( &h->data.request ), '\n', array_bytes( &h->data.request ) ) ) |
138 | return http_handle_request( clientsocket, array_start( &h->data.request ), array_bytes( &h->data.request ) ); | 140 | return 0; |
139 | 141 | ||
140 | return 0; | 142 | ws->request = array_start( &h->data.request ); |
143 | ws->request_size = array_bytes( &h->data.request ); | ||
144 | return http_handle_request( clientsocket, ws ); | ||
141 | } | 145 | } |
142 | 146 | ||
143 | static void handle_write( const int64 clientsocket ) { | 147 | static void handle_write( const int64 clientsocket ) { |
@@ -183,9 +187,25 @@ static void handle_accept( const int64 serversocket ) { | |||
183 | } | 187 | } |
184 | 188 | ||
185 | static void server_mainloop( ) { | 189 | static void server_mainloop( ) { |
186 | time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; | 190 | struct ot_workstruct ws; |
187 | struct iovec *iovector; | 191 | time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; |
188 | int iovec_entries; | 192 | struct iovec *iovector; |
193 | int iovec_entries; | ||
194 | |||
195 | /* Initialize our "thread local storage" */ | ||
196 | ws.inbuf = malloc( THREAD_INBUF_SIZE ); | ||
197 | ws.outbuf = malloc( THREAD_OUTBUF_SIZE ); | ||
198 | #ifdef _DEBUG_HTTPERROR | ||
199 | ws.debugbuf= malloc( THREAD_INBUF_SIZE ); | ||
200 | #endif | ||
201 | if( !ws.inbuf || !ws.outbuf ) | ||
202 | panic( "Initializing worker failed" ); | ||
203 | |||
204 | ws.inbuf_size = THREAD_INBUF_SIZE; | ||
205 | ws.outbuf_size = THREAD_OUTBUF_SIZE; | ||
206 | #ifdef _DEBUG_HTTPERROR | ||
207 | ws.debugbuf_size= THREAD_INBUF_SIZE; | ||
208 | #endif | ||
189 | 209 | ||
190 | for( ; ; ) { | 210 | for( ; ; ) { |
191 | int64 i; | 211 | int64 i; |
@@ -197,13 +217,13 @@ static void server_mainloop( ) { | |||
197 | if( (intptr_t)cookie == FLAG_TCP ) | 217 | if( (intptr_t)cookie == FLAG_TCP ) |
198 | handle_accept( i ); | 218 | handle_accept( i ); |
199 | else if( (intptr_t)cookie == FLAG_UDP ) | 219 | else if( (intptr_t)cookie == FLAG_UDP ) |
200 | handle_udp4( i ); | 220 | handle_udp4( i, &ws ); |
201 | else | 221 | else |
202 | handle_read( i ); | 222 | handle_read( i, &ws ); |
203 | } | 223 | } |
204 | 224 | ||
205 | while( ( i = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 ) | 225 | while( ( i = mutex_workqueue_popresult( &iovec_entries, &iovector ) ) != -1 ) |
206 | http_sendiovecdata( i, iovec_entries, iovector ); | 226 | http_sendiovecdata( i, &ws, iovec_entries, iovector ); |
207 | 227 | ||
208 | while( ( i = io_canwrite( ) ) != -1 ) | 228 | while( ( i = io_canwrite( ) ) != -1 ) |
209 | handle_write( i ); | 229 | handle_write( i ); |
@@ -431,7 +451,12 @@ while( scanon ) { | |||
431 | break; | 451 | break; |
432 | case 'f': bound += parse_configfile( optarg ); break; | 452 | case 'f': bound += parse_configfile( optarg ); break; |
433 | case 'h': help( argv[0] ); exit( 0 ); | 453 | case 'h': help( argv[0] ); exit( 0 ); |
434 | case 'v': stats_return_tracker_version( static_inbuf ); fputs( static_inbuf, stderr ); exit( 0 ); | 454 | case 'v': { |
455 | char buffer[8192]; | ||
456 | stats_return_tracker_version( buffer ); | ||
457 | fputs( buffer, stderr ); | ||
458 | exit( 0 ); | ||
459 | } | ||
435 | default: | 460 | default: |
436 | case '?': usage( argv[0] ); exit( 1 ); | 461 | case '?': usage( argv[0] ); exit( 1 ); |
437 | } | 462 | } |
@@ -27,26 +27,19 @@ | |||
27 | #include "ot_accesslist.h" | 27 | #include "ot_accesslist.h" |
28 | 28 | ||
29 | #define OT_MAXMULTISCRAPE_COUNT 64 | 29 | #define OT_MAXMULTISCRAPE_COUNT 64 |
30 | static ot_hash multiscrape_buf[OT_MAXMULTISCRAPE_COUNT]; | ||
31 | extern char *g_redirecturl; | 30 | extern char *g_redirecturl; |
32 | 31 | ||
33 | enum { | 32 | enum { |
34 | SUCCESS_HTTP_HEADER_LENGTH = 80, | 33 | SUCCESS_HTTP_HEADER_LENGTH = 80, |
35 | SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING = 32, | 34 | SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING = 32, |
36 | SUCCESS_HTTP_SIZE_OFF = 17 }; | 35 | SUCCESS_HTTP_SIZE_OFF = 17 }; |
37 | 36 | ||
38 | /* Our static output buffer */ | ||
39 | static char static_outbuf[8192]; | ||
40 | #ifdef _DEBUG_HTTPERROR | ||
41 | static char debug_request[8192]; | ||
42 | #endif | ||
43 | |||
44 | #ifdef _DEBUG_PEERID | 37 | #ifdef _DEBUG_PEERID |
45 | size_t g_this_peerid_len = 0; | 38 | size_t g_this_peerid_len = 0; |
46 | char *g_this_peerid_data = NULL; | 39 | char *g_this_peerid_data = NULL; |
47 | #endif | 40 | #endif |
48 | 41 | ||
49 | static void http_senddata( const int64 client_socket, char *buffer, size_t size ) { | 42 | static void http_senddata( const int64 client_socket, struct ot_workstruct *ws ) { |
50 | struct http_data *h = io_getcookie( client_socket ); | 43 | struct http_data *h = io_getcookie( client_socket ); |
51 | ssize_t written_size; | 44 | ssize_t written_size; |
52 | 45 | ||
@@ -56,22 +49,22 @@ static void http_senddata( const int64 client_socket, char *buffer, size_t size | |||
56 | array_reset( &h->data.request ); | 49 | array_reset( &h->data.request ); |
57 | } | 50 | } |
58 | 51 | ||
59 | written_size = write( client_socket, buffer, size ); | 52 | written_size = write( client_socket, ws->reply, ws->reply_size ); |
60 | if( ( written_size < 0 ) || ( (size_t)written_size == size ) ) { | 53 | if( ( written_size < 0 ) || ( written_size == ws->reply_size ) ) { |
61 | free( h ); io_close( client_socket ); | 54 | free( h ); io_close( client_socket ); |
62 | } else { | 55 | } else { |
63 | char * outbuf; | 56 | char * outbuf; |
64 | tai6464 t; | 57 | tai6464 t; |
65 | 58 | ||
66 | if( !h ) return; | 59 | if( !h ) return; |
67 | if( !( outbuf = malloc( size - written_size ) ) ) { | 60 | if( !( outbuf = malloc( ws->reply_size - written_size ) ) ) { |
68 | free(h); io_close( client_socket ); | 61 | free(h); io_close( client_socket ); |
69 | return; | 62 | return; |
70 | } | 63 | } |
71 | 64 | ||
72 | iob_reset( &h->data.batch ); | 65 | iob_reset( &h->data.batch ); |
73 | memmove( outbuf, buffer + written_size, size - written_size ); | 66 | memmove( outbuf, ws->reply + written_size, ws->reply_size - written_size ); |
74 | iob_addbuf_free( &h->data.batch, outbuf, size - written_size ); | 67 | iob_addbuf_free( &h->data.batch, outbuf, ws->reply_size - written_size ); |
75 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; | 68 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; |
76 | 69 | ||
77 | /* writeable short data sockets just have a tcp timeout */ | 70 | /* 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 | |||
81 | } | 74 | } |
82 | } | 75 | } |
83 | 76 | ||
84 | #define HTTPERROR_302 return http_issue_error( client_socket, CODE_HTTPERROR_302 ) | 77 | #define HTTPERROR_302 return http_issue_error( client_socket, ws, CODE_HTTPERROR_302 ) |
85 | #define HTTPERROR_400 return http_issue_error( client_socket, CODE_HTTPERROR_400 ) | 78 | #define HTTPERROR_400 return http_issue_error( client_socket, ws, CODE_HTTPERROR_400 ) |
86 | #define HTTPERROR_400_PARAM return http_issue_error( client_socket, CODE_HTTPERROR_400_PARAM ) | 79 | #define HTTPERROR_400_PARAM return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_PARAM ) |
87 | #define HTTPERROR_400_COMPACT return http_issue_error( client_socket, CODE_HTTPERROR_400_COMPACT ) | 80 | #define HTTPERROR_400_COMPACT return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_COMPACT ) |
88 | #define HTTPERROR_403_IP return http_issue_error( client_socket, CODE_HTTPERROR_403_IP ) | 81 | #define HTTPERROR_400_DOUBLEHASH return http_issue_error( client_socket, ws, CODE_HTTPERROR_400_PARAM ) |
89 | #define HTTPERROR_404 return http_issue_error( client_socket, CODE_HTTPERROR_404 ) | 82 | #define HTTPERROR_403_IP return http_issue_error( client_socket, ws, CODE_HTTPERROR_403_IP ) |
90 | #define HTTPERROR_500 return http_issue_error( client_socket, CODE_HTTPERROR_500 ) | 83 | #define HTTPERROR_404 return http_issue_error( client_socket, ws, CODE_HTTPERROR_404 ) |
91 | ssize_t http_issue_error( const int64 client_socket, int code ) { | 84 | #define HTTPERROR_500 return http_issue_error( client_socket, ws, CODE_HTTPERROR_500 ) |
85 | ssize_t http_issue_error( const int64 client_socket, struct ot_workstruct *ws, int code ) { | ||
92 | char *error_code[] = { "302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", | 86 | char *error_code[] = { "302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", |
93 | "403 Access Denied", "404 Not Found", "500 Internal Server Error" }; | 87 | "403 Access Denied", "404 Not Found", "500 Internal Server Error" }; |
94 | char *title = error_code[code]; | 88 | char *title = error_code[code]; |
95 | size_t reply_size; | ||
96 | 89 | ||
90 | ws->reply = ws->outbuf; | ||
97 | if( code == CODE_HTTPERROR_302 ) | 91 | if( code == CODE_HTTPERROR_302 ) |
98 | reply_size = sprintf( static_outbuf, "HTTP/1.0 302 Found\r\nContent-Length: 0\r\nLocation: %s\r\n\r\n", g_redirecturl ); | 92 | 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 ); |
99 | else | 93 | else |
100 | 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); | 94 | 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); |
101 | 95 | ||
102 | #ifdef _DEBUG_HTTPERROR | 96 | #ifdef _DEBUG_HTTPERROR |
103 | fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); | 97 | fprintf( stderr, "DEBUG: invalid request was: %s\n", ws->debugbuf ); |
104 | #endif | 98 | #endif |
105 | stats_issue_event( EVENT_FAILED, FLAG_TCP, code ); | 99 | stats_issue_event( EVENT_FAILED, FLAG_TCP, code ); |
106 | http_senddata( client_socket, static_outbuf, reply_size); | 100 | http_senddata( client_socket, ws ); |
107 | return -2; | 101 | return ws->reply_size = -2; |
108 | } | 102 | } |
109 | 103 | ||
110 | ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct iovec *iovector ) { | 104 | ssize_t http_sendiovecdata( const int64 client_socket, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector ) { |
111 | struct http_data *h = io_getcookie( client_socket ); | 105 | struct http_data *h = io_getcookie( client_socket ); |
112 | char *header; | 106 | char *header; |
113 | int i; | 107 | int i; |
@@ -136,7 +130,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct | |||
136 | } | 130 | } |
137 | 131 | ||
138 | /* Prepare space for http header */ | 132 | /* Prepare space for http header */ |
139 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING ); | 133 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGTH_CONTENT_ENCODING ); |
140 | if( !header ) { | 134 | if( !header ) { |
141 | iovec_free( &iovec_entries, &iovector ); | 135 | iovec_free( &iovec_entries, &iovector ); |
142 | HTTPERROR_500; | 136 | HTTPERROR_500; |
@@ -159,7 +153,7 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct | |||
159 | 153 | ||
160 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; | 154 | h->flag |= STRUCT_HTTP_FLAG_IOB_USED; |
161 | 155 | ||
162 | /* writeable sockets timeout after 10 minutes) */ | 156 | /* writeable sockets timeout after 10 minutes */ |
163 | taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND ); | 157 | taia_now( &t ); taia_addsec( &t, &t, OT_CLIENT_TIMEOUT_SEND ); |
164 | io_timeout( client_socket, t ); | 158 | io_timeout( client_socket, t ); |
165 | io_dontwantread( client_socket ); | 159 | io_dontwantread( client_socket ); |
@@ -167,9 +161,21 @@ ssize_t http_sendiovecdata( const int64 client_socket, int iovec_entries, struct | |||
167 | return 0; | 161 | return 0; |
168 | } | 162 | } |
169 | 163 | ||
170 | static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d, size_t l ) { | 164 | static ssize_t http_handle_stats( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) { |
171 | char *c = data; | 165 | static const ot_keywords keywords_main[] = |
166 | { { "mode", 1 }, {"format", 2 }, { NULL, -3 } }; | ||
167 | static const ot_keywords keywords_mode[] = | ||
168 | { { "peer", TASK_STATS_PEERS }, { "conn", TASK_STATS_CONNS }, { "scrp", TASK_STATS_SCRAPE }, { "udp4", TASK_STATS_UDP }, | ||
169 | { "busy", TASK_STATS_BUSY_NETWORKS }, { "torr", TASK_STATS_TORRENTS }, { "fscr", TASK_STATS_FULLSCRAPE }, | ||
170 | { "s24s", TASK_STATS_SLASH24S }, { "tpbs", TASK_STATS_TPB }, { "herr", TASK_STATS_HTTPERRORS }, | ||
171 | { "top10", TASK_STATS_TOP10 }, { "renew", TASK_STATS_RENEW }, { "syncs", TASK_STATS_SYNCS }, { "version", TASK_STATS_VERSION }, | ||
172 | { "startstop", TASK_STATS_STARTSTOP }, { "toraddrem", TASK_STATS_TORADDREM }, { NULL, -3 } }; | ||
173 | static const ot_keywords keywords_format[] = | ||
174 | { { "bin", TASK_FULLSCRAPE_TPB_BINARY }, { "ben", TASK_FULLSCRAPE }, { "url", TASK_FULLSCRAPE_TPB_URLENCODED }, | ||
175 | { "txt", TASK_FULLSCRAPE_TPB_ASCII }, { NULL, -3 } }; | ||
176 | |||
172 | int mode = TASK_STATS_PEERS, scanon = 1, format = 0; | 177 | int mode = TASK_STATS_PEERS, scanon = 1, format = 0; |
178 | |||
173 | #ifdef WANT_RESTRICT_STATS | 179 | #ifdef WANT_RESTRICT_STATS |
174 | struct http_data *h = io_getcookie( client_socket ); | 180 | struct http_data *h = io_getcookie( client_socket ); |
175 | 181 | ||
@@ -178,97 +184,26 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d | |||
178 | #endif | 184 | #endif |
179 | 185 | ||
180 | while( scanon ) { | 186 | while( scanon ) { |
181 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 187 | switch( scan_find_keywords( keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { |
182 | case -2: scanon = 0; break; /* TERMINATOR */ | 188 | case -2: scanon = 0; break; /* TERMINATOR */ |
183 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 189 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
184 | default: scan_urlencoded_skipvalue( &c ); break; | 190 | case -3: scan_urlencoded_skipvalue( &read_ptr ); break; |
185 | case 4: | 191 | case 1: /* matched "mode" */ |
186 | if( byte_diff(data,4,"mode")) { | 192 | if( ( mode = scan_find_keywords( keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; |
187 | scan_urlencoded_skipvalue( &c ); | ||
188 | continue; | ||
189 | } | ||
190 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { | ||
191 | case 4: | ||
192 | if( !byte_diff(data,4,"peer")) | ||
193 | mode = TASK_STATS_PEERS; | ||
194 | else if( !byte_diff(data,4,"conn")) | ||
195 | mode = TASK_STATS_CONNS; | ||
196 | else if( !byte_diff(data,4,"scrp")) | ||
197 | mode = TASK_STATS_SCRAPE; | ||
198 | else if( !byte_diff(data,4,"tcp4")) | ||
199 | mode = TASK_STATS_TCP; | ||
200 | else if( !byte_diff(data,4,"udp4")) | ||
201 | mode = TASK_STATS_UDP; | ||
202 | else if( !byte_diff(data,4,"busy")) | ||
203 | mode = TASK_STATS_BUSY_NETWORKS; | ||
204 | else if( !byte_diff(data,4,"torr")) | ||
205 | mode = TASK_STATS_TORRENTS; | ||
206 | else if( !byte_diff(data,4,"fscr")) | ||
207 | mode = TASK_STATS_FULLSCRAPE; | ||
208 | else if( !byte_diff(data,4,"s24s")) | ||
209 | mode = TASK_STATS_SLASH24S; | ||
210 | else if( !byte_diff(data,4,"tpbs")) | ||
211 | mode = TASK_STATS_TPB; | ||
212 | else if( !byte_diff(data,4,"herr")) | ||
213 | mode = TASK_STATS_HTTPERRORS; | ||
214 | else | ||
215 | HTTPERROR_400_PARAM; | ||
216 | break; | ||
217 | case 5: | ||
218 | if( !byte_diff(data,5,"top10")) | ||
219 | mode = TASK_STATS_TOP10; | ||
220 | else if( !byte_diff(data,5,"renew")) | ||
221 | mode = TASK_STATS_RENEW; | ||
222 | else if( !byte_diff(data,5,"syncs")) | ||
223 | mode = TASK_STATS_SYNCS; | ||
224 | else | ||
225 | HTTPERROR_400_PARAM; | ||
226 | break; | ||
227 | case 7: | ||
228 | if( !byte_diff(data,7,"version")) | ||
229 | mode = TASK_STATS_VERSION; | ||
230 | else | ||
231 | HTTPERROR_400_PARAM; | ||
232 | break; | ||
233 | case 9: | ||
234 | if( !byte_diff(data,9,"startstop")) | ||
235 | mode = TASK_STATS_STARTSTOP; | ||
236 | else if( !byte_diff(data,9,"toraddrem")) | ||
237 | mode = TASK_STATS_TORADDREM; | ||
238 | else | ||
239 | HTTPERROR_400_PARAM; | ||
240 | break; | ||
241 | } | ||
242 | break; | 193 | break; |
243 | case 6: | 194 | case 2: /* matched "format" */ |
244 | if( byte_diff(data,6,"format")) { | 195 | if( ( format = scan_find_keywords( keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; |
245 | scan_urlencoded_skipvalue( &c ); | ||
246 | continue; | ||
247 | } | ||
248 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 3 ) HTTPERROR_400_PARAM; | ||
249 | if( !byte_diff(data,3,"bin")) | ||
250 | format = TASK_FULLSCRAPE_TPB_BINARY; | ||
251 | else if( !byte_diff(data,3,"ben")) | ||
252 | format = TASK_FULLSCRAPE; | ||
253 | else if( !byte_diff(data,3,"url")) | ||
254 | format = TASK_FULLSCRAPE_TPB_URLENCODED; | ||
255 | else if( !byte_diff(data,3,"txt")) | ||
256 | format = TASK_FULLSCRAPE_TPB_ASCII; | ||
257 | else | ||
258 | HTTPERROR_400_PARAM; | ||
259 | break; | 196 | break; |
260 | } | 197 | } |
261 | } | 198 | } |
262 | 199 | ||
263 | /* Touch variable */ | ||
264 | d=d; | ||
265 | #ifdef WANT_FULLSCRAPE | 200 | #ifdef WANT_FULLSCRAPE |
266 | if( mode == TASK_STATS_TPB ) { | 201 | if( mode == TASK_STATS_TPB ) { |
267 | struct http_data* h = io_getcookie( client_socket ); | 202 | struct http_data* h = io_getcookie( client_socket ); |
268 | tai6464 t; | 203 | tai6464 t; |
269 | #ifdef WANT_COMPRESSION_GZIP | 204 | #ifdef WANT_COMPRESSION_GZIP |
270 | d[l-1] = 0; | 205 | ws->request[ws->request_size] = 0; |
271 | if( strstr( d, "gzip" ) ) { | 206 | if( strstr( read_ptr - 1, "gzip" ) ) { |
272 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | 207 | h->flag |= STRUCT_HTTP_FLAG_GZIP; |
273 | format |= TASK_FLAG_GZIP; | 208 | format |= TASK_FLAG_GZIP; |
274 | } | 209 | } |
@@ -280,7 +215,7 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d | |||
280 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 215 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); |
281 | fullscrape_deliver( client_socket, format ); | 216 | fullscrape_deliver( client_socket, format ); |
282 | io_dontwantread( client_socket ); | 217 | io_dontwantread( client_socket ); |
283 | return -2; | 218 | return ws->reply_size = -2; |
284 | } | 219 | } |
285 | #endif | 220 | #endif |
286 | 221 | ||
@@ -290,27 +225,24 @@ static ssize_t http_handle_stats( const int64 client_socket, char *data, char *d | |||
290 | /* Complex stats also include expensive memory debugging tools */ | 225 | /* Complex stats also include expensive memory debugging tools */ |
291 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 226 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); |
292 | stats_deliver( client_socket, mode ); | 227 | stats_deliver( client_socket, mode ); |
293 | return -2; | 228 | return ws->reply_size = -2; |
294 | } | 229 | } |
295 | 230 | ||
296 | /* Simple stats can be answerred immediately */ | 231 | /* Simple stats can be answerred immediately */ |
297 | if( !( l = return_stats_for_tracker( static_outbuf + SUCCESS_HTTP_HEADER_LENGTH, mode, 0 ) ) ) HTTPERROR_500; | 232 | if( !( ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 ) ) ) HTTPERROR_500; |
298 | 233 | ||
299 | return l; | 234 | return ws->reply_size; |
300 | } | 235 | } |
301 | 236 | ||
302 | #ifdef WANT_FULLSCRAPE | 237 | #ifdef WANT_FULLSCRAPE |
303 | static ssize_t http_handle_fullscrape( const int64 client_socket, char *d, size_t l ) { | 238 | static ssize_t http_handle_fullscrape( const int64 client_socket, struct ot_workstruct *ws ) { |
304 | struct http_data* h = io_getcookie( client_socket ); | 239 | struct http_data* h = io_getcookie( client_socket ); |
305 | int format = 0; | 240 | int format = 0; |
306 | tai6464 t; | 241 | tai6464 t; |
307 | 242 | ||
308 | /* Touch variables */ | ||
309 | d=d;l=l; | ||
310 | |||
311 | #ifdef WANT_COMPRESSION_GZIP | 243 | #ifdef WANT_COMPRESSION_GZIP |
312 | d[l-1] = 0; | 244 | ws->request[ws->request_size-1] = 0; |
313 | if( strstr( d, "gzip" ) ) { | 245 | if( strstr( ws->request, "gzip" ) ) { |
314 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | 246 | h->flag |= STRUCT_HTTP_FLAG_GZIP; |
315 | format = TASK_FLAG_GZIP; | 247 | format = TASK_FLAG_GZIP; |
316 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST_GZIP, *(int*)h->ip, 0 ); | 248 | 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_ | |||
319 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST, *(int*)h->ip, 0 ); | 251 | stats_issue_event( EVENT_FULLSCRAPE_REQUEST, *(int*)h->ip, 0 ); |
320 | 252 | ||
321 | #ifdef _DEBUG_HTTPERROR | 253 | #ifdef _DEBUG_HTTPERROR |
322 | write( 2, debug_request, l ); | 254 | write( 2, ws->debugbuf, ws->debugbuf_size ); |
323 | #endif | 255 | #endif |
324 | 256 | ||
325 | /* Pass this task to the worker thread */ | 257 | /* Pass this task to the worker thread */ |
@@ -328,72 +260,70 @@ write( 2, debug_request, l ); | |||
328 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); | 260 | taia_uint( &t, 0 ); io_timeout( client_socket, t ); |
329 | fullscrape_deliver( client_socket, TASK_FULLSCRAPE | format ); | 261 | fullscrape_deliver( client_socket, TASK_FULLSCRAPE | format ); |
330 | io_dontwantread( client_socket ); | 262 | io_dontwantread( client_socket ); |
331 | return -2; | 263 | return ws->reply_size = -2; |
332 | } | 264 | } |
333 | #endif | 265 | #endif |
266 | static ssize_t http_handle_scrape( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) { | ||
267 | static const ot_keywords keywords_scrape[] = { { "info_hash", 1 }, { NULL, -3 } }; | ||
334 | 268 | ||
335 | static ssize_t http_handle_scrape( const int64 client_socket, char *data ) { | 269 | ot_hash * multiscrape_buf = (ot_hash*)ws->request; |
336 | int scanon = 1, numwant = 0; | 270 | int scanon = 1, numwant = 0; |
337 | char *c = data; | ||
338 | size_t l; | ||
339 | 271 | ||
340 | /* This is to hack around stupid clients that send "scrape ?info_hash" */ | 272 | /* This is to hack around stupid clients that send "scrape ?info_hash" */ |
341 | if( c[-1] != '?' ) { | 273 | if( read_ptr[-1] != '?' ) { |
342 | while( ( *c != '?' ) && ( *c != '\n' ) ) ++c; | 274 | while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; |
343 | if( *c == '\n' ) HTTPERROR_400_PARAM; | 275 | if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; |
344 | ++c; | 276 | ++read_ptr; |
345 | } | 277 | } |
346 | 278 | ||
347 | while( scanon ) { | 279 | while( scanon ) { |
348 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 280 | switch( scan_find_keywords( keywords_scrape, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { |
349 | case -2: scanon = 0; break; /* TERMINATOR */ | 281 | case -2: scanon = 0; break; /* TERMINATOR */ |
350 | case -1: | 282 | default: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
351 | if( numwant ) | 283 | case -3: scan_urlencoded_skipvalue( &read_ptr ); break; |
352 | goto UTORRENT1600_WORKAROUND; | 284 | case 1: /* matched "info_hash" */ |
353 | HTTPERROR_400_PARAM; /* PARSE ERROR */ | ||
354 | default: scan_urlencoded_skipvalue( &c ); break; | ||
355 | case 9: | ||
356 | if(byte_diff(data,9,"info_hash")) { | ||
357 | scan_urlencoded_skipvalue( &c ); | ||
358 | continue; | ||
359 | } | ||
360 | /* ignore this, when we have less than 20 bytes */ | 285 | /* ignore this, when we have less than 20 bytes */ |
361 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) ) { | 286 | if( scan_urlencoded_query( &read_ptr, (char*)(multiscrape_buf + numwant++), SCAN_SEARCHPATH_VALUE ) != (ssize_t)sizeof(ot_hash) ) |
362 | #ifdef WANT_UTORRENT1600_WORKAROUND | ||
363 | if( data[20] != '?' ) | ||
364 | #endif | ||
365 | HTTPERROR_400_PARAM; | 287 | HTTPERROR_400_PARAM; |
366 | } | ||
367 | if( numwant < OT_MAXMULTISCRAPE_COUNT ) | ||
368 | memmove( multiscrape_buf + numwant++, data, sizeof(ot_hash) ); | ||
369 | break; | 288 | break; |
370 | } | 289 | } |
371 | } | 290 | } |
372 | 291 | ||
373 | UTORRENT1600_WORKAROUND: | ||
374 | |||
375 | /* No info_hash found? Inform user */ | 292 | /* No info_hash found? Inform user */ |
376 | if( !numwant ) HTTPERROR_400_PARAM; | 293 | if( !numwant ) HTTPERROR_400_PARAM; |
294 | |||
295 | /* Limit number of hashes to process */ | ||
296 | if( numwant > OT_MAXMULTISCRAPE_COUNT ) | ||
297 | numwant = OT_MAXMULTISCRAPE_COUNT; | ||
377 | 298 | ||
378 | /* Enough for http header + whole scrape string */ | 299 | /* Enough for http header + whole scrape string */ |
379 | if( !( l = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf ) ) ) HTTPERROR_500; | 300 | if( !( ws->reply_size = return_tcp_scrape_for_torrent( multiscrape_buf, numwant, ws->reply ) ) ) HTTPERROR_500; |
380 | stats_issue_event( EVENT_SCRAPE, FLAG_TCP, l ); | 301 | stats_issue_event( EVENT_SCRAPE, FLAG_TCP, ws->reply_size ); |
381 | return l; | 302 | return ws->reply_size; |
382 | } | 303 | } |
383 | 304 | ||
384 | static ssize_t http_handle_announce( const int64 client_socket, char *data ) { | 305 | static ot_keywords keywords_announce[] = { { "port", 1 }, { "left", 2 }, { "event", 3 }, { "numwant", 4 }, { "compact", 5 }, { "info_hash", 6 }, |
385 | char *c = data; | 306 | #ifdef WANT_IP_FROM_QUERY_STRING |
386 | int numwant, tmp, scanon; | 307 | { "ip", 7 }, |
387 | ot_peer peer; | 308 | #endif |
388 | ot_hash *hash = NULL; | 309 | #ifdef _DEBUG_PEERID |
310 | { "peer_id", 8 }, | ||
311 | #endif | ||
312 | { NULL, -3 } }; | ||
313 | static ot_keywords keywords_announce_event[] = { { "completed", 1 }, { "stopped", 2 }, { NULL, -3 } }; | ||
314 | static ssize_t http_handle_announce( const int64 client_socket, struct ot_workstruct *ws, char *read_ptr ) { | ||
315 | int numwant, tmp, scanon; | ||
316 | ot_peer peer; | ||
317 | ot_hash *hash = NULL; | ||
389 | unsigned short port = htons(6881); | 318 | unsigned short port = htons(6881); |
390 | ssize_t len; | 319 | char *write_ptr; |
391 | 320 | ssize_t len; | |
321 | |||
392 | /* This is to hack around stupid clients that send "announce ?info_hash" */ | 322 | /* This is to hack around stupid clients that send "announce ?info_hash" */ |
393 | if( c[-1] != '?' ) { | 323 | if( read_ptr[-1] != '?' ) { |
394 | while( ( *c != '?' ) && ( *c != '\n' ) ) ++c; | 324 | while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; |
395 | if( *c == '\n' ) HTTPERROR_400_PARAM; | 325 | if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; |
396 | ++c; | 326 | ++read_ptr; |
397 | } | 327 | } |
398 | 328 | ||
399 | OT_SETIP( &peer, ((struct http_data*)io_getcookie( client_socket ) )->ip ); | 329 | 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 ) { | |||
403 | scanon = 1; | 333 | scanon = 1; |
404 | 334 | ||
405 | #ifdef _DEBUG_PEERID | 335 | #ifdef _DEBUG_PEERID |
406 | g_this_peerid_data = NULL; | 336 | ws->peer_id = NULL; |
407 | #endif | 337 | #endif |
408 | 338 | ||
409 | while( scanon ) { | 339 | while( scanon ) { |
410 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 340 | switch( scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { |
411 | case -2: scanon = 0; break; /* TERMINATOR */ | 341 | case -2: scanon = 0; break; /* TERMINATOR */ |
412 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | 342 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
413 | default: scan_urlencoded_skipvalue( &c ); break; | 343 | case -3: scan_urlencoded_skipvalue( &read_ptr ); break; |
414 | #ifdef WANT_IP_FROM_QUERY_STRING | 344 | case 1: /* matched "port" */ |
415 | case 2: | 345 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); |
416 | if(!byte_diff(data,2,"ip")) { | 346 | if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; |
417 | unsigned char ip[4]; | 347 | port = htons( tmp ); OT_SETPORT( &peer, &port ); |
418 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
419 | if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) HTTPERROR_400_PARAM; | ||
420 | OT_SETIP( &peer, ip ); | ||
421 | } else | ||
422 | scan_urlencoded_skipvalue( &c ); | ||
423 | break; | ||
424 | #endif | ||
425 | case 4: | ||
426 | if( !byte_diff( data, 4, "port" ) ) { | ||
427 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
428 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; | ||
429 | port = htons( tmp ); OT_SETPORT( &peer, &port ); | ||
430 | } else if( !byte_diff( data, 4, "left" ) ) { | ||
431 | if( ( len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; | ||
432 | if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; | ||
433 | if( !tmp ) OT_PEERFLAG( &peer ) |= PEER_FLAG_SEEDING; | ||
434 | } else | ||
435 | scan_urlencoded_skipvalue( &c ); | ||
436 | break; | 348 | break; |
437 | case 5: | 349 | case 2: /* matched "left" */ |
438 | if( byte_diff( data, 5, "event" ) ) | 350 | if( ( len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; |
439 | scan_urlencoded_skipvalue( &c ); | 351 | if( scan_fixed_int( write_ptr, len, &tmp ) ) tmp = 0; |
440 | else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { | 352 | if( !tmp ) OT_PEERFLAG( &peer ) |= PEER_FLAG_SEEDING; |
441 | case -1: | 353 | break; |
442 | HTTPERROR_400_PARAM; | 354 | case 3: /* matched "event" */ |
443 | case 7: | 355 | switch( scan_find_keywords( keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) { |
444 | if( !byte_diff( data, 7, "stopped" ) ) OT_PEERFLAG( &peer ) |= PEER_FLAG_STOPPED; | 356 | case -1: HTTPERROR_400_PARAM; |
445 | break; | 357 | case 1: /* matched "completed" */ |
446 | case 9: | 358 | OT_PEERFLAG( &peer ) |= PEER_FLAG_COMPLETED; |
447 | if( !byte_diff( data, 9, "completed" ) ) OT_PEERFLAG( &peer ) |= PEER_FLAG_COMPLETED; | 359 | break; |
448 | default: /* Fall through intended */ | 360 | case 2: /* matched "stopped" */ |
449 | break; | 361 | OT_PEERFLAG( &peer ) |= PEER_FLAG_STOPPED; |
362 | break; | ||
363 | default: | ||
364 | break; | ||
450 | } | 365 | } |
451 | break; | 366 | break; |
452 | case 7: | 367 | case 4: /* matched "numwant" */ |
453 | if(!byte_diff(data,7,"numwant")) { | 368 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); |
454 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 369 | if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &numwant ) ) HTTPERROR_400_PARAM; |
455 | if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) HTTPERROR_400_PARAM; | 370 | if( numwant < 0 ) numwant = 50; |
456 | if( numwant < 0 ) numwant = 50; | 371 | if( numwant > 200 ) numwant = 200; |
457 | if( numwant > 200 ) numwant = 200; | ||
458 | } else if(!byte_diff(data,7,"compact")) { | ||
459 | len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
460 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) HTTPERROR_400_PARAM; | ||
461 | if( !tmp ) HTTPERROR_400_COMPACT; | ||
462 | } else | ||
463 | #ifdef _DEBUG_PEERID | ||
464 | if(!byte_diff(data,7,"peer_id")) { | ||
465 | g_this_peerid_len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | ||
466 | g_this_peerid_data = g_this_peerid_len > 0 ? data : 0; | ||
467 | } else | ||
468 | #endif | ||
469 | scan_urlencoded_skipvalue( &c ); | ||
470 | break; | 372 | break; |
471 | case 9: | 373 | case 5: /* matched "compact" */ |
472 | if(byte_diff(data,9,"info_hash")) { | 374 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); |
473 | scan_urlencoded_skipvalue( &c ); | 375 | if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) ) HTTPERROR_400_PARAM; |
474 | continue; | 376 | if( !tmp ) HTTPERROR_400_COMPACT; |
475 | } | 377 | break; |
378 | case 6: /* matched "info_hash" */ | ||
379 | if( hash ) HTTPERROR_400_DOUBLEHASH; | ||
476 | /* ignore this, when we have less than 20 bytes */ | 380 | /* ignore this, when we have less than 20 bytes */ |
477 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; | 381 | if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; |
478 | hash = (ot_hash*)data; | 382 | hash = (ot_hash*)write_ptr; |
383 | break; | ||
384 | #ifdef WANT_IP_FROM_QUERY_STRING | ||
385 | case 7: /* matched "ip" */ | ||
386 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | ||
387 | if( ( len <= 0 ) || scan_fixed_ip( write_ptr, len, (unsigned char*)/*tmp*/ws->reply ) ) HTTPERROR_400_PARAM; | ||
388 | OT_SETIP( &peer, /*tmp*/ws->reply ); | ||
479 | break; | 389 | break; |
390 | #endif | ||
391 | #ifdef _DEBUG_PEERID | ||
392 | case 8: /* matched "peer_id" */ | ||
393 | ws->peer_id_size = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); | ||
394 | ws->peer_id = ws->peer_id_size > 0 ? write_ptr : 0; | ||
395 | break; | ||
396 | #endif | ||
480 | } | 397 | } |
481 | } | 398 | } |
482 | 399 | ||
483 | /* Scanned whole query string */ | 400 | /* Scanned whole query string */ |
484 | if( !hash ) | 401 | if( !hash ) |
485 | 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" ); | 402 | 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" ); |
486 | 403 | ||
487 | if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) | 404 | if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) |
488 | len = remove_peer_from_torrent( hash, &peer, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf, FLAG_TCP ); | 405 | ws->reply_size = remove_peer_from_torrent( hash, &peer, ws->reply, FLAG_TCP ); |
489 | else | 406 | else |
490 | len = add_peer_to_torrent_and_return_peers(hash, &peer, FLAG_TCP, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_outbuf); | 407 | ws->reply_size = add_peer_to_torrent_and_return_peers(hash, &peer, FLAG_TCP, numwant, ws->reply ); |
491 | 408 | ||
492 | if( !len ) HTTPERROR_500; | 409 | if( !ws->reply_size ) HTTPERROR_500; |
493 | 410 | ||
494 | stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, len); | 411 | stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size); |
495 | return len; | 412 | return ws->reply_size; |
496 | } | 413 | } |
497 | 414 | ||
498 | ssize_t http_handle_request( const int64 client_socket, char *data, size_t recv_length ) { | 415 | ssize_t http_handle_request( const int64 client_socket, struct ot_workstruct *ws ) { |
499 | char *c, *recv_header=data; | 416 | ssize_t reply_off, len; |
500 | ssize_t reply_size = 0, reply_off, len; | 417 | char *read_ptr = ws->request, *write_ptr; |
501 | 418 | ||
502 | #ifdef _DEBUG_HTTPERROR | 419 | #ifdef _DEBUG_HTTPERROR |
503 | if( recv_length >= sizeof( debug_request ) ) | 420 | reply_off = ws->request_size; |
504 | recv_length = sizeof( debug_request) - 1; | 421 | if( ws->request_size >= (ssize_t)ws->debugbuf_size ) |
505 | memmove( debug_request, recv_header, recv_length ); | 422 | reply_off = ws->debugbuf_size - 1; |
506 | debug_request[ recv_length ] = 0; | 423 | memmove( ws->debugbuf, ws->request, reply_off ); |
424 | ws->debugbuf[ reply_off ] = 0; | ||
507 | #endif | 425 | #endif |
508 | 426 | ||
427 | /* Tell subroutines where to put reply data */ | ||
428 | ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH; | ||
429 | |||
509 | /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */ | 430 | /* This one implicitely tests strlen < 5, too -- remember, it is \n terminated */ |
510 | if( byte_diff( data, 5, "GET /") ) HTTPERROR_400; | 431 | if( memcmp( read_ptr, "GET /", 5) ) HTTPERROR_400; |
511 | 432 | ||
512 | /* Skip leading '/' */ | 433 | /* Skip leading '/' */ |
513 | for( c = data+4; *c == '/'; ++c); | 434 | for( read_ptr+=4; *read_ptr == '/'; ++read_ptr); |
514 | 435 | ||
515 | /* Try to parse the request. | 436 | /* Try to parse the request. |
516 | In reality we abandoned requiring the url to be correct. This now | 437 | In reality we abandoned requiring the url to be correct. This now |
517 | only decodes url encoded characters, we check for announces and | 438 | only decodes url encoded characters, we check for announces and |
518 | scrapes by looking for "a*" or "sc" */ | 439 | scrapes by looking for "a*" or "sc" */ |
519 | len = scan_urlencoded_query( &c, data = c, SCAN_PATH ); | 440 | len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_PATH ); |
520 | 441 | ||
521 | /* If parsing returned an error, leave with not found */ | 442 | /* If parsing returned an error, leave with not found */ |
522 | if( g_redirecturl && ( len == -2 ) ) HTTPERROR_302; | 443 | if( g_redirecturl && ( len == -2 ) ) HTTPERROR_302; |
523 | if( len <= 0 ) HTTPERROR_404; | 444 | if( len <= 0 ) HTTPERROR_404; |
524 | 445 | ||
525 | /* This is the hardcore match for announce*/ | 446 | /* This is the hardcore match for announce*/ |
526 | if( ( *data == 'a' ) || ( *data == '?' ) ) | 447 | if( ( *write_ptr == 'a' ) || ( *write_ptr == '?' ) ) |
527 | reply_size = http_handle_announce( client_socket, c ); | 448 | http_handle_announce( client_socket, ws, read_ptr ); |
528 | #ifdef WANT_FULLSCRAPE | 449 | #ifdef WANT_FULLSCRAPE |
529 | else if( !byte_diff( data, 12, "scrape HTTP/" ) ) | 450 | else if( !memcmp( write_ptr, "scrape HTTP/", 12 ) ) |
530 | reply_size = http_handle_fullscrape( client_socket, recv_header, recv_length ); | 451 | http_handle_fullscrape( client_socket, ws ); |
531 | #endif | 452 | #endif |
532 | /* This is the hardcore match for scrape */ | 453 | /* This is the hardcore match for scrape */ |
533 | else if( !byte_diff( data, 2, "sc" ) ) | 454 | else if( !memcmp( write_ptr, "sc", 2 ) ) |
534 | reply_size = http_handle_scrape( client_socket, c ); | 455 | http_handle_scrape( client_socket, ws, read_ptr ); |
535 | /* All the rest is matched the standard way */ | 456 | /* All the rest is matched the standard way */ |
536 | else switch( len ) { | 457 | else if( !memcmp( write_ptr, "stats", 5) ) |
537 | case 5: /* stats ? */ | 458 | http_handle_stats( client_socket, ws, read_ptr ); |
538 | if( byte_diff( data, 5, "stats") ) HTTPERROR_404; | 459 | else |
539 | reply_size = http_handle_stats( client_socket, c, recv_header, recv_length ); | ||
540 | break; | ||
541 | default: | ||
542 | HTTPERROR_404; | 460 | HTTPERROR_404; |
543 | } | ||
544 | 461 | ||
545 | /* If routines handled sending themselves, just return */ | 462 | /* If routines handled sending themselves, just return */ |
546 | if( reply_size == -2 ) return 0; | 463 | if( ws->reply_size == -2 ) return 0; |
547 | /* If routine failed, let http error take over */ | 464 | /* If routine failed, let http error take over */ |
548 | if( reply_size == -1 ) HTTPERROR_500; | 465 | if( ws->reply_size == -1 ) HTTPERROR_500; |
549 | 466 | ||
550 | /* This one is rather ugly, so I take you step by step through it. | 467 | /* This one is rather ugly, so I take you step by step through it. |
551 | 468 | ||
552 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to | 469 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to |
553 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string | 470 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our work buffer, which is enough for the static string |
554 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate | 471 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for its expansion and calculate |
555 | the space NOT needed to expand in reply_off | 472 | the space NOT needed to expand in reply_off |
556 | */ | 473 | */ |
557 | reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_outbuf, 0, "%zd", reply_size ); | 474 | reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( ws->outbuf, 0, "%zd", ws->reply_size ); |
558 | 475 | ws->reply = ws->outbuf + reply_off; | |
476 | |||
559 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete | 477 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete |
560 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ | 478 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ |
561 | 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 ); | 479 | 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 ); |
562 | 480 | ||
563 | /* 3. Finally we join both blocks neatly */ | 481 | /* 3. Finally we join both blocks neatly */ |
564 | static_outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; | 482 | ws->outbuf[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; |
565 | 483 | ||
566 | http_senddata( client_socket, static_outbuf + reply_off, reply_size ); | 484 | http_senddata( client_socket, ws ); |
567 | return reply_size; | 485 | return ws->reply_size; |
568 | } | 486 | } |
569 | 487 | ||
570 | const char *g_version_http_c = "$Source$: $Revision$\n"; | 488 | const char *g_version_http_c = "$Source$: $Revision$\n"; |
@@ -23,8 +23,8 @@ struct http_data { | |||
23 | STRUCT_HTTP_FLAG flag; | 23 | STRUCT_HTTP_FLAG flag; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | ssize_t http_handle_request( const int64 s, char *data, size_t l ); | 26 | ssize_t http_handle_request( const int64 s, struct ot_workstruct *ws ); |
27 | ssize_t http_sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovector ); | 27 | ssize_t http_sendiovecdata( const int64 s, struct ot_workstruct *ws, int iovec_entries, struct iovec *iovector ); |
28 | ssize_t http_issue_error( const int64 s, int code ); | 28 | ssize_t http_issue_error( const int64 s, struct ot_workstruct *ws, int code ); |
29 | 29 | ||
30 | #endif | 30 | #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 ) { | |||
400 | default: | 400 | default: |
401 | break; | 401 | break; |
402 | } | 402 | } |
403 | |||
404 | /* Handle outstanding requests */ | ||
405 | livesync_ticker( ); | ||
406 | } | 403 | } |
407 | 404 | ||
408 | /* Never returns. */ | 405 | /* Never returns. */ |
@@ -17,9 +17,6 @@ | |||
17 | #include "ot_udp.h" | 17 | #include "ot_udp.h" |
18 | #include "ot_stats.h" | 18 | #include "ot_stats.h" |
19 | 19 | ||
20 | static char static_inbuf[8192]; | ||
21 | static char static_outbuf[8192]; | ||
22 | |||
23 | static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; | 20 | static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; |
24 | 21 | ||
25 | static void udp_make_connectionid( uint32_t * connid, const char * remoteip ) { | 22 | 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 | |||
39 | } | 36 | } |
40 | 37 | ||
41 | /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ | 38 | /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ |
42 | void handle_udp4( int64 serversocket ) { | 39 | void handle_udp4( int64 serversocket, struct ot_workstruct *ws ) { |
43 | ot_peer peer; | 40 | ot_peer peer; |
44 | ot_hash *hash = NULL; | 41 | ot_hash *hash = NULL; |
45 | char remoteip[4]; | 42 | char remoteip[4]; |
46 | uint32_t *inpacket = (uint32_t*)static_inbuf; | 43 | uint32_t *inpacket = (uint32_t*)ws->inbuf; |
47 | uint32_t *outpacket = (uint32_t*)static_outbuf; | 44 | uint32_t *outpacket = (uint32_t*)ws->outbuf; |
48 | uint32_t numwant, left, event; | 45 | uint32_t numwant, left, event; |
49 | uint16_t port, remoteport; | 46 | uint16_t port, remoteport; |
50 | size_t r, r_out; | 47 | size_t r, r_out; |
51 | 48 | ||
52 | r = socket_recv4( serversocket, static_inbuf, sizeof( static_inbuf ), remoteip, &remoteport); | 49 | r = socket_recv4( serversocket, ws->inbuf, ws->inbuf_size, remoteip, &remoteport); |
53 | 50 | ||
54 | stats_issue_event( EVENT_ACCEPT, FLAG_UDP, ntohl(*(uint32_t*)remoteip) ); | 51 | stats_issue_event( EVENT_ACCEPT, FLAG_UDP, ntohl(*(uint32_t*)remoteip) ); |
55 | stats_issue_event( EVENT_READ, FLAG_UDP, r ); | 52 | stats_issue_event( EVENT_READ, FLAG_UDP, r ); |
@@ -58,8 +55,6 @@ void handle_udp4( int64 serversocket ) { | |||
58 | if( r < 16 ) | 55 | if( r < 16 ) |
59 | return; | 56 | return; |
60 | 57 | ||
61 | /* fprintf( stderr, "UDP Connection id: %16llX\n", *(uint64_t*)inpacket ); */ | ||
62 | |||
63 | switch( ntohl( inpacket[2] ) ) { | 58 | switch( ntohl( inpacket[2] ) ) { |
64 | case 0: /* This is a connect action */ | 59 | case 0: /* This is a connect action */ |
65 | /* look for udp bittorrent magic id */ | 60 | /* look for udp bittorrent magic id */ |
@@ -70,7 +65,7 @@ void handle_udp4( int64 serversocket ) { | |||
70 | outpacket[1] = inpacket[3]; | 65 | outpacket[1] = inpacket[3]; |
71 | udp_make_connectionid( outpacket + 2, remoteip ); | 66 | udp_make_connectionid( outpacket + 2, remoteip ); |
72 | 67 | ||
73 | socket_send4( serversocket, static_outbuf, 16, remoteip, remoteport ); | 68 | socket_send4( serversocket, ws->outbuf, 16, remoteip, remoteport ); |
74 | stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 ); | 69 | stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 ); |
75 | break; | 70 | break; |
76 | case 1: /* This is an announce action */ | 71 | case 1: /* This is an announce action */ |
@@ -88,8 +83,8 @@ void handle_udp4( int64 serversocket ) { | |||
88 | if (numwant > 200) numwant = 200; | 83 | if (numwant > 200) numwant = 200; |
89 | 84 | ||
90 | event = ntohl( inpacket[80/4] ); | 85 | event = ntohl( inpacket[80/4] ); |
91 | port = *(uint16_t*)( static_inbuf + 96 ); | 86 | port = *(uint16_t*)( ((char*)inpacket) + 96 ); |
92 | hash = (ot_hash*)( static_inbuf + 16 ); | 87 | hash = (ot_hash*)( ((char*)inpacket) + 16 ); |
93 | 88 | ||
94 | OT_SETIP( &peer, remoteip ); | 89 | OT_SETIP( &peer, remoteip ); |
95 | OT_SETPORT( &peer, &port ); | 90 | OT_SETPORT( &peer, &port ); |
@@ -108,11 +103,11 @@ void handle_udp4( int64 serversocket ) { | |||
108 | outpacket[1] = inpacket[12/4]; | 103 | outpacket[1] = inpacket[12/4]; |
109 | 104 | ||
110 | if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) /* Peer is gone. */ | 105 | if( OT_PEERFLAG( &peer ) & PEER_FLAG_STOPPED ) /* Peer is gone. */ |
111 | r = remove_peer_from_torrent( hash, &peer, static_outbuf, FLAG_UDP ); | 106 | r = remove_peer_from_torrent( hash, &peer, ws->outbuf, FLAG_UDP ); |
112 | else | 107 | else |
113 | r = 8 + add_peer_to_torrent_and_return_peers( hash, &peer, FLAG_UDP, numwant, static_outbuf + 8 ); | 108 | r = 8 + add_peer_to_torrent_and_return_peers( hash, &peer, FLAG_UDP, numwant, ((char*)outpacket) + 8 ); |
114 | 109 | ||
115 | socket_send4( serversocket, static_outbuf, r, remoteip, remoteport ); | 110 | socket_send4( serversocket, ws->outbuf, r, remoteip, remoteport ); |
116 | stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, r ); | 111 | stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, r ); |
117 | break; | 112 | break; |
118 | 113 | ||
@@ -124,9 +119,9 @@ void handle_udp4( int64 serversocket ) { | |||
124 | outpacket[1] = inpacket[12/4]; | 119 | outpacket[1] = inpacket[12/4]; |
125 | 120 | ||
126 | for( r_out = 0; ( r_out * 20 < r - 16) && ( r_out <= 74 ); r_out++ ) | 121 | for( r_out = 0; ( r_out * 20 < r - 16) && ( r_out <= 74 ); r_out++ ) |
127 | return_udp_scrape_for_torrent( (ot_hash*)( static_inbuf + 16 + 20 * r_out ), static_outbuf + 8 + 12 * r_out ); | 122 | return_udp_scrape_for_torrent( (ot_hash*)( ((char*)inpacket) + 16 + 20 * r_out ), ((char*)outpacket) + 8 + 12 * r_out ); |
128 | 123 | ||
129 | socket_send4( serversocket, static_outbuf, 8 + 12 * r_out, remoteip, remoteport ); | 124 | socket_send4( serversocket, ws->outbuf, 8 + 12 * r_out, remoteip, remoteport ); |
130 | stats_issue_event( EVENT_SCRAPE, FLAG_UDP, r ); | 125 | stats_issue_event( EVENT_SCRAPE, FLAG_UDP, r ); |
131 | break; | 126 | break; |
132 | } | 127 | } |
@@ -6,6 +6,6 @@ | |||
6 | #ifndef __OT_UDP_H__ | 6 | #ifndef __OT_UDP_H__ |
7 | #define __OT_UDP_H__ | 7 | #define __OT_UDP_H__ |
8 | 8 | ||
9 | void handle_udp4( int64 serversocket ); | 9 | void handle_udp4( int64 serversocket, struct ot_workstruct *ws ); |
10 | 10 | ||
11 | #endif | 11 | #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 @@ | |||
9 | /* Libwofat */ | 9 | /* Libwofat */ |
10 | #include "scan.h" | 10 | #include "scan.h" |
11 | 11 | ||
12 | /* System */ | ||
13 | #include <string.h> | ||
14 | |||
12 | /* Idea is to do a in place replacement or guarantee at least | 15 | /* Idea is to do a in place replacement or guarantee at least |
13 | strlen( string ) bytes in deststring | 16 | strlen( string ) bytes in deststring |
14 | watch http://www.ietf.org/rfc/rfc2396.txt | 17 | watch http://www.ietf.org/rfc/rfc2396.txt |
@@ -64,6 +67,22 @@ void scan_urlencoded_skipvalue( char **string ) { | |||
64 | *string = (char*)s; | 67 | *string = (char*)s; |
65 | } | 68 | } |
66 | 69 | ||
70 | int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCHPATH_FLAG flags) { | ||
71 | char *deststring = *string; | ||
72 | ssize_t match_length = scan_urlencoded_query(string, deststring, flags ); | ||
73 | |||
74 | if( match_length < 0 ) return match_length; | ||
75 | if( match_length == 0 ) return -3; | ||
76 | |||
77 | while( keywords->key ) { | ||
78 | if( !memcmp( keywords->key, deststring, match_length ) ) | ||
79 | return keywords->value; | ||
80 | keywords++; | ||
81 | } | ||
82 | |||
83 | return -3; | ||
84 | } | ||
85 | |||
67 | ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) { | 86 | ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags) { |
68 | const unsigned char* s=*(const unsigned char**) string; | 87 | const unsigned char* s=*(const unsigned char**) string; |
69 | unsigned char *d = (unsigned char*)deststring; | 88 | unsigned char *d = (unsigned char*)deststring; |
@@ -95,9 +114,7 @@ ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_F | |||
95 | --s; | 114 | --s; |
96 | break; | 115 | break; |
97 | case '?': | 116 | case '?': |
98 | /* XXX to help us parse path?param=value?param=value?... sent by µTorrent 1600 | 117 | if( flags != SCAN_PATH ) return -1; |
99 | do not return an error but silently terminate | ||
100 | if( flags != SCAN_PATH ) return -1; */ | ||
101 | break; | 118 | break; |
102 | case '=': | 119 | case '=': |
103 | if( flags != SCAN_SEARCHPATH_PARAM ) return -1; | 120 | 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 @@ | |||
8 | 8 | ||
9 | #include <sys/types.h> | 9 | #include <sys/types.h> |
10 | 10 | ||
11 | typedef struct { | ||
12 | char *key; | ||
13 | int value; | ||
14 | } ot_keywords; | ||
15 | |||
11 | typedef enum { | 16 | typedef enum { |
12 | SCAN_PATH = 1, | 17 | SCAN_PATH = 1, |
13 | SCAN_SEARCHPATH_PARAM = 2, | 18 | SCAN_SEARCHPATH_PARAM = 2, |
@@ -21,9 +26,20 @@ typedef enum { | |||
21 | flags determines, what to parse | 26 | flags determines, what to parse |
22 | returns number of valid converted characters in deststring | 27 | returns number of valid converted characters in deststring |
23 | or -1 for parse error | 28 | or -1 for parse error |
29 | or -2 for terminator found | ||
24 | */ | 30 | */ |
25 | ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags); | 31 | ssize_t scan_urlencoded_query(char **string, char *deststring, SCAN_SEARCHPATH_FLAG flags); |
26 | 32 | ||
33 | /* string in: pointer to source | ||
34 | out: pointer to next scan position | ||
35 | flags determines, what to parse | ||
36 | returns value for matched keyword | ||
37 | or -1 for parse error | ||
38 | or -2 for terminator found | ||
39 | or -3 for no keyword matched | ||
40 | */ | ||
41 | int scan_find_keywords( const ot_keywords * keywords, char **string, SCAN_SEARCHPATH_FLAG flags); | ||
42 | |||
27 | /* string in: pointer to value of a param=value pair to skip | 43 | /* string in: pointer to value of a param=value pair to skip |
28 | out: pointer to next scan position on return | 44 | out: pointer to next scan position on return |
29 | */ | 45 | */ |
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 { | |||
96 | }; | 96 | }; |
97 | #define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list) && ((peer_list)->peers.size > (peer_list)->peers.space)) | 97 | #define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list) && ((peer_list)->peers.size > (peer_list)->peers.space)) |
98 | 98 | ||
99 | struct ot_workstruct { | ||
100 | /* Thread specific, static */ | ||
101 | #define THREAD_INBUF_SIZE 8192 | ||
102 | char *inbuf; | ||
103 | size_t inbuf_size; | ||
104 | #define THREAD_OUTBUF_SIZE 8192 | ||
105 | char *outbuf; | ||
106 | size_t outbuf_size; | ||
107 | #ifdef _DEBUG_HTTPERROR | ||
108 | #define THREAD_DEBUGBUF_SIZE 8192 | ||
109 | char *debugbuf; | ||
110 | size_t debugbuf_size; | ||
111 | #endif | ||
112 | |||
113 | /* HTTP specific, non static */ | ||
114 | char *request; | ||
115 | ssize_t request_size; | ||
116 | char *reply; | ||
117 | ssize_t reply_size; | ||
118 | #ifdef _DEBUG_PEERID | ||
119 | char *peer_id; | ||
120 | ssize_t peer_id_size; | ||
121 | #endif | ||
122 | }; | ||
123 | |||
99 | /* | 124 | /* |
100 | Exported functions | 125 | Exported functions |
101 | */ | 126 | */ |