diff options
-rw-r--r-- | opentracker.c | 59 | ||||
-rw-r--r-- | ot_fullscrape.c | 70 |
2 files changed, 104 insertions, 25 deletions
diff --git a/opentracker.c b/opentracker.c index a2ada33..57c7e9a 100644 --- a/opentracker.c +++ b/opentracker.c | |||
@@ -43,6 +43,7 @@ | |||
43 | 43 | ||
44 | /* Globals */ | 44 | /* Globals */ |
45 | static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80; | 45 | static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80; |
46 | static const size_t SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING = 32; | ||
46 | static const size_t SUCCESS_HTTP_SIZE_OFF = 17; | 47 | static const size_t SUCCESS_HTTP_SIZE_OFF = 17; |
47 | static uint32_t g_adminip_addresses[OT_ADMINIP_MAX]; | 48 | static uint32_t g_adminip_addresses[OT_ADMINIP_MAX]; |
48 | static unsigned int g_adminip_count = 0; | 49 | static unsigned int g_adminip_count = 0; |
@@ -73,15 +74,14 @@ static size_t ot_sockets_count = 0; | |||
73 | 74 | ||
74 | #ifdef _DEBUG_HTTPERROR | 75 | #ifdef _DEBUG_HTTPERROR |
75 | static char debug_request[8192]; | 76 | static char debug_request[8192]; |
76 | #define _DEBUG_HTTPERROR_PARAM( param ) , param | ||
77 | #else | ||
78 | #define _DEBUG_HTTPERROR_PARAM( param ) | ||
79 | #endif | 77 | #endif |
80 | 78 | ||
81 | typedef enum { | 79 | typedef enum { |
82 | STRUCT_HTTP_FLAG_ARRAY_USED = 1, | 80 | STRUCT_HTTP_FLAG_ARRAY_USED = 1, |
83 | STRUCT_HTTP_FLAG_IOB_USED = 2, | 81 | STRUCT_HTTP_FLAG_IOB_USED = 2, |
84 | STRUCT_HTTP_FLAG_WAITINGFORTASK = 4 | 82 | STRUCT_HTTP_FLAG_WAITINGFORTASK = 4, |
83 | STRUCT_HTTP_FLAG_GZIP = 8, | ||
84 | STRUCT_HTTP_FLAG_BZIP2 = 16 | ||
85 | } STRUCT_HTTP_FLAG; | 85 | } STRUCT_HTTP_FLAG; |
86 | 86 | ||
87 | struct http_data { | 87 | struct http_data { |
@@ -100,7 +100,7 @@ static int ot_ip_compare( const void *a, const void *b ) { return memcmp( a,b,4 | |||
100 | int main( int argc, char **argv ); | 100 | int main( int argc, char **argv ); |
101 | 101 | ||
102 | static void httperror( const int64 s, const char *title, const char *message ); | 102 | static void httperror( const int64 s, const char *title, const char *message ); |
103 | static void httpresponse( const int64 s, char *data _DEBUG_HTTPERROR_PARAM(size_t l ) ); | 103 | static void httpresponse( const int64 s, char *data, size_t l ); |
104 | 104 | ||
105 | static void sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovector ); | 105 | static void sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovector ); |
106 | static void senddata( const int64 s, char *buffer, const size_t size ); | 106 | static void senddata( const int64 s, char *buffer, const size_t size ); |
@@ -162,7 +162,7 @@ static void sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovec | |||
162 | iovec_free( &iovec_entries, &iovector ); | 162 | iovec_free( &iovec_entries, &iovector ); |
163 | HTTPERROR_500; | 163 | HTTPERROR_500; |
164 | } | 164 | } |
165 | 165 | ||
166 | /* If this socket collected request in a buffer, | 166 | /* If this socket collected request in a buffer, |
167 | free it now */ | 167 | free it now */ |
168 | if( h->flag & STRUCT_HTTP_FLAG_ARRAY_USED ) { | 168 | if( h->flag & STRUCT_HTTP_FLAG_ARRAY_USED ) { |
@@ -173,20 +173,24 @@ static void sendiovecdata( const int64 s, int iovec_entries, struct iovec *iovec | |||
173 | /* If we came here, wait for the answer is over */ | 173 | /* If we came here, wait for the answer is over */ |
174 | h->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; | 174 | h->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; |
175 | 175 | ||
176 | /* Our answers never are 0 bytes. Return an error. */ | 176 | /* Our answers never are 0 vectors. Return an error. */ |
177 | if( !iovec_entries || !iovector[0].iov_len ) { | 177 | if( !iovec_entries ) { |
178 | iovec_free( &iovec_entries, &iovector ); | ||
179 | HTTPERROR_500; | 178 | HTTPERROR_500; |
180 | } | 179 | } |
181 | 180 | ||
182 | /* Prepare space for http header */ | 181 | /* Prepare space for http header */ |
183 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH ); | 182 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH + SUCCESS_HTTP_HEADER_LENGHT_CONTENT_ENCODING ); |
184 | if( !header ) { | 183 | if( !header ) { |
185 | iovec_free( &iovec_entries, &iovector ); | 184 | iovec_free( &iovec_entries, &iovector ); |
186 | HTTPERROR_500; | 185 | HTTPERROR_500; |
187 | } | 186 | } |
188 | 187 | ||
189 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); | 188 | if( h->flag & STRUCT_HTTP_FLAG_GZIP ) |
189 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Encoding: gzip\r\nContent-Length: %zd\r\n\r\n", size ); | ||
190 | else if( h->flag & STRUCT_HTTP_FLAG_BZIP2 ) | ||
191 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Encoding: bzip2\r\nContent-Length: %zd\r\n\r\n", size ); | ||
192 | else | ||
193 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); | ||
190 | 194 | ||
191 | iob_reset( &h->batch ); | 195 | iob_reset( &h->batch ); |
192 | iob_addbuf_free( &h->batch, header, header_size ); | 196 | iob_addbuf_free( &h->batch, header, header_size ); |
@@ -241,9 +245,9 @@ static void senddata( const int64 s, char *buffer, size_t size ) { | |||
241 | } | 245 | } |
242 | } | 246 | } |
243 | 247 | ||
244 | static void httpresponse( const int64 s, char *data _DEBUG_HTTPERROR_PARAM( size_t l ) ) { | 248 | static void httpresponse( const int64 s, char *data, size_t l ) { |
245 | struct http_data* h = io_getcookie( s ); | 249 | struct http_data* h = io_getcookie( s ); |
246 | char *c; | 250 | char *c, *d=data; |
247 | ot_peer peer; | 251 | ot_peer peer; |
248 | ot_torrent *torrent; | 252 | ot_torrent *torrent; |
249 | ot_hash *hash = NULL; | 253 | ot_hash *hash = NULL; |
@@ -253,6 +257,9 @@ static void httpresponse( const int64 s, char *data _DEBUG_HTTPERROR_PARAM( size | |||
253 | ssize_t len; | 257 | ssize_t len; |
254 | size_t reply_size = 0, reply_off; | 258 | size_t reply_size = 0, reply_off; |
255 | 259 | ||
260 | /* Touch l and d in case it is unused */ | ||
261 | l = l; d = d; | ||
262 | |||
256 | #ifdef _DEBUG_HTTPERROR | 263 | #ifdef _DEBUG_HTTPERROR |
257 | if( l >= sizeof( debug_request ) ) | 264 | if( l >= sizeof( debug_request ) ) |
258 | l = sizeof( debug_request) - 1; | 265 | l = sizeof( debug_request) - 1; |
@@ -379,6 +386,12 @@ LOG_TO_STDERR( "sync: %d.%d.%d.%d\n", h->ip[0], h->ip[1], h->ip[2], h->ip[3] ); | |||
379 | } | 386 | } |
380 | 387 | ||
381 | if( mode == TASK_STATS_TPB ) { | 388 | if( mode == TASK_STATS_TPB ) { |
389 | #ifdef WANT_COMPRESSION_GZIP | ||
390 | if( strnstr( d, "gzip", l ) ) { | ||
391 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | ||
392 | format |= TASK_FLAG_GZIP; | ||
393 | } | ||
394 | #endif | ||
382 | /* Pass this task to the worker thread */ | 395 | /* Pass this task to the worker thread */ |
383 | h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; | 396 | h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; |
384 | fullscrape_deliver( s, format ); | 397 | fullscrape_deliver( s, format ); |
@@ -403,9 +416,17 @@ LOG_TO_STDERR( "[%08d] scrp: %d.%d.%d.%d - FULL SCRAPE\n", (unsigned int)(g_now | |||
403 | #ifdef _DEBUG_HTTPERROR | 416 | #ifdef _DEBUG_HTTPERROR |
404 | write( 2, debug_request, l ); | 417 | write( 2, debug_request, l ); |
405 | #endif | 418 | #endif |
419 | format = 0; | ||
420 | #ifdef WANT_COMPRESSION_GZIP | ||
421 | if( strnstr( d, "gzip", l ) ) { | ||
422 | h->flag |= STRUCT_HTTP_FLAG_GZIP; | ||
423 | format = TASK_FLAG_GZIP; | ||
424 | } | ||
425 | #endif | ||
426 | |||
406 | /* Pass this task to the worker thread */ | 427 | /* Pass this task to the worker thread */ |
407 | h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; | 428 | h->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK; |
408 | fullscrape_deliver( s, TASK_FULLSCRAPE ); | 429 | fullscrape_deliver( s, TASK_FULLSCRAPE | format ); |
409 | io_dontwantread( s ); | 430 | io_dontwantread( s ); |
410 | return; | 431 | return; |
411 | } | 432 | } |
@@ -655,7 +676,7 @@ static void handle_read( const int64 clientsocket ) { | |||
655 | /* If we get the whole request in one packet, handle it without copying */ | 676 | /* If we get the whole request in one packet, handle it without copying */ |
656 | if( !array_start( &h->request ) ) { | 677 | if( !array_start( &h->request ) ) { |
657 | if( memchr( static_inbuf, '\n', l ) ) | 678 | if( memchr( static_inbuf, '\n', l ) ) |
658 | return httpresponse( clientsocket, static_inbuf _DEBUG_HTTPERROR_PARAM( l ) ); | 679 | return httpresponse( clientsocket, static_inbuf, l ); |
659 | h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; | 680 | h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; |
660 | return array_catb( &h->request, static_inbuf, l ); | 681 | return array_catb( &h->request, static_inbuf, l ); |
661 | } | 682 | } |
@@ -670,7 +691,7 @@ static void handle_read( const int64 clientsocket ) { | |||
670 | return httperror( clientsocket, "500 request too long", "You sent too much headers"); | 691 | return httperror( clientsocket, "500 request too long", "You sent too much headers"); |
671 | 692 | ||
672 | if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) ) | 693 | if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) ) |
673 | return httpresponse( clientsocket, array_start( &h->request ) _DEBUG_HTTPERROR_PARAM( array_bytes( &h->request ) ) ); | 694 | return httpresponse( clientsocket, array_start( &h->request ), array_bytes( &h->request ) ); |
674 | } | 695 | } |
675 | 696 | ||
676 | static void handle_write( const int64 clientsocket ) { | 697 | static void handle_write( const int64 clientsocket ) { |
@@ -722,9 +743,9 @@ static void handle_timeouted( void ) { | |||
722 | } | 743 | } |
723 | 744 | ||
724 | static void server_mainloop( ) { | 745 | static void server_mainloop( ) { |
725 | time_t next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL; | 746 | time_t next_timeout_check = g_now + OT_CLIENT_TIMEOUT_CHECKINTERVAL; |
726 | struct iovec *iovector; | 747 | struct iovec *iovector; |
727 | int iovec_entries; | 748 | int iovec_entries; |
728 | 749 | ||
729 | for( ; ; ) { | 750 | for( ; ; ) { |
730 | int64 i; | 751 | int64 i; |
diff --git a/ot_fullscrape.c b/ot_fullscrape.c index bb78b8a..d9c872e 100644 --- a/ot_fullscrape.c +++ b/ot_fullscrape.c | |||
@@ -7,8 +7,12 @@ | |||
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include <pthread.h> | 8 | #include <pthread.h> |
9 | #include <arpa/inet.h> | 9 | #include <arpa/inet.h> |
10 | #ifdef WANT_COMPRESSION_GZIP | ||
11 | #include <zlib.h> | ||
12 | #endif | ||
10 | 13 | ||
11 | /* Libowfat */ | 14 | /* Libowfat */ |
15 | #include "byte.h" | ||
12 | #include "textcode.h" | 16 | #include "textcode.h" |
13 | 17 | ||
14 | /* Opentracker */ | 18 | /* Opentracker */ |
@@ -24,7 +28,7 @@ | |||
24 | #define OT_SCRAPE_CHUNK_SIZE (512*1024) | 28 | #define OT_SCRAPE_CHUNK_SIZE (512*1024) |
25 | 29 | ||
26 | /* "d8:completei%zde10:downloadedi%zde10:incompletei%zdee" */ | 30 | /* "d8:completei%zde10:downloadedi%zde10:incompletei%zdee" */ |
27 | #define OT_FULLSCRAPE_MAXENTRYLEN 100 | 31 | #define OT_FULLSCRAPE_MAXENTRYLEN 256 |
28 | 32 | ||
29 | /* Forward declaration */ | 33 | /* Forward declaration */ |
30 | static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ); | 34 | static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ); |
@@ -66,8 +70,12 @@ void fullscrape_deliver( int64 socket, ot_tasktype tasktype ) { | |||
66 | } | 70 | } |
67 | 71 | ||
68 | static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) { | 72 | static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) { |
69 | int bucket; | 73 | int bucket; |
70 | char *r, *re; | 74 | char *r, *re; |
75 | #ifdef WANT_COMPRESSION_GZIP | ||
76 | char compress_buffer[OT_FULLSCRAPE_MAXENTRYLEN]; | ||
77 | z_stream strm; | ||
78 | #endif | ||
71 | 79 | ||
72 | /* Setup return vector... */ | 80 | /* Setup return vector... */ |
73 | *iovec_entries = 0; | 81 | *iovec_entries = 0; |
@@ -79,8 +87,21 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas | |||
79 | This works as a low watermark */ | 87 | This works as a low watermark */ |
80 | re = r + OT_SCRAPE_CHUNK_SIZE; | 88 | re = r + OT_SCRAPE_CHUNK_SIZE; |
81 | 89 | ||
90 | #ifdef WANT_COMPRESSION_GZIP | ||
91 | if( mode & TASK_FLAG_GZIP ) { | ||
92 | byte_zero( &strm, sizeof(strm) ); | ||
93 | strm.next_in = (ot_byte*)r; | ||
94 | if( deflateInit2(&strm,9,Z_DEFLATED,31,8,Z_DEFAULT_STRATEGY) != Z_OK ) | ||
95 | fprintf( stderr, "not ok.\n" ); | ||
96 | |||
97 | strm.next_out = (unsigned char*)r; | ||
98 | strm.avail_out = OT_SCRAPE_CHUNK_SIZE; | ||
99 | r = compress_buffer; | ||
100 | } | ||
101 | #endif | ||
102 | |||
82 | /* Reply dictionary only needed for bencoded fullscrape */ | 103 | /* Reply dictionary only needed for bencoded fullscrape */ |
83 | if( mode == TASK_FULLSCRAPE ) { | 104 | if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE ) { |
84 | memmove( r, "d5:filesd", 9 ); | 105 | memmove( r, "d5:filesd", 9 ); |
85 | r += 9; | 106 | r += 9; |
86 | } | 107 | } |
@@ -97,7 +118,7 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas | |||
97 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[tor_offset] ).peer_list; | 118 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[tor_offset] ).peer_list; |
98 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[tor_offset] ).hash; | 119 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[tor_offset] ).hash; |
99 | 120 | ||
100 | switch( mode ) { | 121 | switch( mode & TASK_TASK_MASK ) { |
101 | case TASK_FULLSCRAPE: | 122 | case TASK_FULLSCRAPE: |
102 | default: | 123 | default: |
103 | /* push hash as bencoded string */ | 124 | /* push hash as bencoded string */ |
@@ -122,6 +143,16 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas | |||
122 | break; | 143 | break; |
123 | } | 144 | } |
124 | 145 | ||
146 | #ifdef WANT_COMPRESSION_GZIP | ||
147 | if( mode & TASK_FLAG_GZIP ) { | ||
148 | strm.next_in = (ot_byte*)compress_buffer; | ||
149 | strm.avail_in = r - compress_buffer; | ||
150 | if( deflate( &strm, Z_NO_FLUSH ) != Z_OK ) | ||
151 | fprintf( stderr, "Not ok.\n" ); | ||
152 | r = (char*)strm.next_out; | ||
153 | } | ||
154 | #endif | ||
155 | |||
125 | /* If we reached our low watermark in buffer... */ | 156 | /* If we reached our low watermark in buffer... */ |
126 | if( re - r <= OT_FULLSCRAPE_MAXENTRYLEN ) { | 157 | if( re - r <= OT_FULLSCRAPE_MAXENTRYLEN ) { |
127 | 158 | ||
@@ -134,6 +165,10 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas | |||
134 | /* If this fails: free buffers */ | 165 | /* If this fails: free buffers */ |
135 | iovec_free( iovec_entries, iovector ); | 166 | iovec_free( iovec_entries, iovector ); |
136 | 167 | ||
168 | #ifdef WANT_COMPRESSION_GZIP | ||
169 | deflateEnd(&strm); | ||
170 | #endif | ||
171 | |||
137 | /* Release lock on current bucket and return */ | 172 | /* Release lock on current bucket and return */ |
138 | mutex_bucket_unlock( bucket ); | 173 | mutex_bucket_unlock( bucket ); |
139 | return; | 174 | return; |
@@ -141,7 +176,19 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas | |||
141 | 176 | ||
142 | /* Adjust new end of output buffer */ | 177 | /* Adjust new end of output buffer */ |
143 | re = r + OT_SCRAPE_CHUNK_SIZE; | 178 | re = r + OT_SCRAPE_CHUNK_SIZE; |
179 | |||
180 | #ifdef WANT_COMPRESSION_GZIP | ||
181 | if( mode & TASK_FLAG_GZIP ) { | ||
182 | strm.next_out = (ot_byte*)r; | ||
183 | strm.avail_out = OT_SCRAPE_CHUNK_SIZE; | ||
184 | } | ||
185 | #endif | ||
186 | } | ||
187 | #ifdef WANT_COMPRESSION_GZIP | ||
188 | if( mode & TASK_FLAG_GZIP ) { | ||
189 | r = compress_buffer; | ||
144 | } | 190 | } |
191 | #endif | ||
145 | } | 192 | } |
146 | 193 | ||
147 | /* All torrents done: release lock on currenct bucket */ | 194 | /* All torrents done: release lock on currenct bucket */ |
@@ -149,10 +196,21 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas | |||
149 | } | 196 | } |
150 | 197 | ||
151 | /* Close bencoded scrape dictionary if necessary */ | 198 | /* Close bencoded scrape dictionary if necessary */ |
152 | if( mode == TASK_FULLSCRAPE ) { | 199 | if( ( mode & TASK_TASK_MASK ) == TASK_FULLSCRAPE ) { |
153 | *r++='e'; *r++='e'; | 200 | *r++='e'; *r++='e'; |
154 | } | 201 | } |
155 | 202 | ||
203 | #ifdef WANT_COMPRESSION_GZIP | ||
204 | if( mode & TASK_FLAG_GZIP ) { | ||
205 | strm.next_in = (ot_byte*) compress_buffer; | ||
206 | strm.avail_in = r - compress_buffer; | ||
207 | if( deflate( &strm, Z_FINISH ) != Z_STREAM_END ) | ||
208 | fprintf( stderr, "Not ok.\n" ); | ||
209 | r = (char*)strm.next_out; | ||
210 | deflateEnd(&strm); | ||
211 | } | ||
212 | #endif | ||
213 | |||
156 | /* Release unused memory in current output buffer */ | 214 | /* Release unused memory in current output buffer */ |
157 | iovec_fixlast( iovec_entries, iovector, OT_SCRAPE_CHUNK_SIZE - ( re - r ) ); | 215 | iovec_fixlast( iovec_entries, iovector, OT_SCRAPE_CHUNK_SIZE - ( re - r ) ); |
158 | } | 216 | } |