diff options
-rw-r--r-- | opentracker.c | 356 | ||||
-rw-r--r-- | trackerlogic.c | 77 | ||||
-rw-r--r-- | trackerlogic.h | 9 |
3 files changed, 221 insertions, 221 deletions
diff --git a/opentracker.c b/opentracker.c index 403fa21..9121103 100644 --- a/opentracker.c +++ b/opentracker.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> | 1 | /* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
2 | It is considered beerware. Prost. Skol. Cheers or whatever. | 2 | It is considered beerware. Prost. Skol. Cheers or whatever. |
3 | Some of the stuff below is stolen from Fefes example libowfat httpd. | 3 | Some of the stuff below is stolen from Fefes example libowfat httpd. |
4 | */ | 4 | */ |
@@ -26,6 +26,7 @@ | |||
26 | #include "trackerlogic.h" | 26 | #include "trackerlogic.h" |
27 | #include "scan_urlencoded_query.h" | 27 | #include "scan_urlencoded_query.h" |
28 | 28 | ||
29 | /* Globals */ | ||
29 | static unsigned int ot_overall_connections = 0; | 30 | static unsigned int ot_overall_connections = 0; |
30 | static unsigned int ot_overall_successfulannounces = 0; | 31 | static unsigned int ot_overall_successfulannounces = 0; |
31 | static time_t ot_start_time; | 32 | static time_t ot_start_time; |
@@ -34,35 +35,64 @@ static const size_t SUCCESS_HTTP_SIZE_OFF = 17; | |||
34 | /* To always have space for error messages ;) */ | 35 | /* To always have space for error messages ;) */ |
35 | static char static_scratch[8192]; | 36 | static char static_scratch[8192]; |
36 | 37 | ||
37 | #ifdef _DEBUG_FDS | ||
38 | static char fd_debug_space[0x10000]; | ||
39 | #endif | ||
40 | #ifdef _DEBUG_HTTPERROR | 38 | #ifdef _DEBUG_HTTPERROR |
41 | static char debug_request[8192]; | 39 | static char debug_request[8192]; |
42 | #endif | 40 | #endif |
43 | 41 | ||
44 | static void carp(const char* routine ) { | 42 | struct http_data { |
43 | union { | ||
44 | array request; | ||
45 | io_batch batch; | ||
46 | }; | ||
47 | unsigned char ip[4]; | ||
48 | }; | ||
49 | |||
50 | /* Prototypes */ | ||
51 | |||
52 | int main( int argc, char **argv ); | ||
53 | |||
54 | static int httpheader_complete( struct http_data *h ); | ||
55 | static void httperror( const int64 s, struct http_data *h, const char *title, const char *message ); | ||
56 | static void httpresponse( const int64 s, struct http_data *h); | ||
57 | |||
58 | static void sendmallocdata( const int64 s, struct http_data *h, char *buffer, const size_t size ); | ||
59 | static void senddata( const int64 s, struct http_data *h, char *buffer, const size_t size ); | ||
60 | |||
61 | static void server_mainloop( const int64 serversocket ); | ||
62 | static void handle_timeouted( void ); | ||
63 | static void handle_accept( const int64 serversocket ); | ||
64 | static void handle_read( const int64 clientsocket ); | ||
65 | static void handle_write( const int64 clientsocket ); | ||
66 | |||
67 | static void usage( char *name ); | ||
68 | static void help( char *name ); | ||
69 | |||
70 | static void carp( const char *routine ); | ||
71 | static void panic( const char *routine ); | ||
72 | static void graceful( int s ); | ||
73 | |||
74 | #define HTTPERROR_400 return httperror( s, h, "400 Invalid Request", "This server only understands GET." ) | ||
75 | #define HTTPERROR_400_PARAM return httperror( s, h, "400 Invalid Request", "Invalid parameter" ) | ||
76 | #define HTTPERROR_400_COMPACT return httperror( s, h, "400 Invalid Request", "This server only delivers compact results." ) | ||
77 | #define HTTPERROR_404 return httperror( s, h, "404 Not Found", "No such file or directory." ) | ||
78 | #define HTTPERROR_500 return httperror( s, h, "500 Internal Server Error", "A server error has occured. Please retry later." ) | ||
79 | |||
80 | /* End of prototypes */ | ||
81 | |||
82 | static void carp( const char *routine ) { | ||
45 | buffer_puts( buffer_2, routine ); | 83 | buffer_puts( buffer_2, routine ); |
46 | buffer_puts( buffer_2, ": " ); | 84 | buffer_puts( buffer_2, ": " ); |
47 | buffer_puterror( buffer_2 ); | 85 | buffer_puterror( buffer_2 ); |
48 | buffer_putnlflush( buffer_2 ); | 86 | buffer_putnlflush( buffer_2 ); |
49 | } | 87 | } |
50 | 88 | ||
51 | static void panic( const char* routine ) { | 89 | static void panic( const char *routine ) { |
52 | carp( routine ); | 90 | carp( routine ); |
53 | exit( 111 ); | 91 | exit( 111 ); |
54 | } | 92 | } |
55 | 93 | ||
56 | struct http_data { | 94 | static int httpheader_complete( struct http_data *h ) { |
57 | union { | 95 | size_t l = array_bytes( &h->request ), i; |
58 | array request; | ||
59 | io_batch batch; | ||
60 | }; | ||
61 | unsigned char ip[4]; | ||
62 | }; | ||
63 | |||
64 | int header_complete( struct http_data* h ) { | ||
65 | int l = array_bytes( &h->request ), i; | ||
66 | const char* c = array_start( &h->request ); | 96 | const char* c = array_start( &h->request ); |
67 | 97 | ||
68 | for( i=0; i+1<l; ++i) { | 98 | for( i=0; i+1<l; ++i) { |
@@ -72,16 +102,29 @@ int header_complete( struct http_data* h ) { | |||
72 | return 0; | 102 | return 0; |
73 | } | 103 | } |
74 | 104 | ||
75 | void sendmallocdata( int64 s, struct http_data *h, char * buffer, size_t size ) { | 105 | static void httperror( const int64 s, struct http_data *h, const char *title, const char *message ) { |
106 | size_t reply_size = sprintf( static_scratch, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", | ||
107 | title, strlen(message)+strlen(title)+16-4,title+4); | ||
108 | #ifdef _DEBUG_HTTPERROR | ||
109 | fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); | ||
110 | #endif | ||
111 | senddata(s,h,static_scratch,reply_size); | ||
112 | } | ||
113 | |||
114 | static void sendmallocdata( const int64 s, struct http_data *h, char *buffer, size_t size ) { | ||
76 | tai6464 t; | 115 | tai6464 t; |
77 | char *header; | 116 | char *header; |
78 | size_t header_size; | 117 | size_t header_size; |
79 | 118 | ||
80 | if( !h ) { free( buffer); return; } | 119 | if( !h ) |
120 | return free( buffer); | ||
81 | array_reset( &h->request ); | 121 | array_reset( &h->request ); |
82 | 122 | ||
83 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH ); | 123 | header = malloc( SUCCESS_HTTP_HEADER_LENGTH ); |
84 | if( !header ) { free( buffer ); return; } | 124 | if( !header ) { |
125 | free( buffer ); | ||
126 | HTTPERROR_500; | ||
127 | } | ||
85 | 128 | ||
86 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); | 129 | header_size = sprintf( header, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r\n", size ); |
87 | 130 | ||
@@ -89,13 +132,13 @@ void sendmallocdata( int64 s, struct http_data *h, char * buffer, size_t size ) | |||
89 | iob_addbuf_free( &h->batch, header, header_size ); | 132 | iob_addbuf_free( &h->batch, header, header_size ); |
90 | iob_addbuf_free( &h->batch, buffer, size ); | 133 | iob_addbuf_free( &h->batch, buffer, size ); |
91 | 134 | ||
92 | // writeable sockets just have a tcp timeout | 135 | /* writeable sockets just have a tcp timeout */ |
93 | taia_uint(&t,0); io_timeout( s, t ); | 136 | taia_uint(&t,0); io_timeout( s, t ); |
94 | io_dontwantread( s ); | 137 | io_dontwantread( s ); |
95 | io_wantwrite( s ); | 138 | io_wantwrite( s ); |
96 | } | 139 | } |
97 | 140 | ||
98 | void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { | 141 | static void senddata( const int64 s, struct http_data *h, char *buffer, size_t size ) { |
99 | size_t written_size; | 142 | size_t written_size; |
100 | 143 | ||
101 | /* whoever sends data is not interested in its input-array */ | 144 | /* whoever sends data is not interested in its input-array */ |
@@ -104,20 +147,12 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { | |||
104 | 147 | ||
105 | written_size = write( s, buffer, size ); | 148 | written_size = write( s, buffer, size ); |
106 | if( ( written_size < 0 ) || ( written_size == size ) ) { | 149 | if( ( written_size < 0 ) || ( written_size == size ) ) { |
107 | #ifdef _DEBUG_FDS | ||
108 | if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); | ||
109 | fd_debug_space[s] = 0; | ||
110 | #endif | ||
111 | free( h ); io_close( s ); | 150 | free( h ); io_close( s ); |
112 | } else { | 151 | } else { |
113 | char * outbuf = malloc( size - written_size ); | 152 | char * outbuf = malloc( size - written_size ); |
114 | tai6464 t; | 153 | tai6464 t; |
115 | 154 | ||
116 | if( !outbuf ) { | 155 | if( !outbuf ) { |
117 | #ifdef _DEBUG_FDS | ||
118 | if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); | ||
119 | fd_debug_space[s] = 0; | ||
120 | #endif | ||
121 | free(h); io_close( s ); | 156 | free(h); io_close( s ); |
122 | return; | 157 | return; |
123 | } | 158 | } |
@@ -126,29 +161,21 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { | |||
126 | memmove( outbuf, buffer + written_size, size - written_size ); | 161 | memmove( outbuf, buffer + written_size, size - written_size ); |
127 | iob_addbuf_free( &h->batch, outbuf, size - written_size ); | 162 | iob_addbuf_free( &h->batch, outbuf, size - written_size ); |
128 | 163 | ||
129 | // writeable sockets just have a tcp timeout | 164 | /* writeable sockets just have a tcp timeout */ |
130 | taia_uint( &t, 0 ); io_timeout( s, t ); | 165 | taia_uint( &t, 0 ); io_timeout( s, t ); |
131 | io_dontwantread( s ); | 166 | io_dontwantread( s ); |
132 | io_wantwrite( s ); | 167 | io_wantwrite( s ); |
133 | } | 168 | } |
134 | } | 169 | } |
135 | 170 | ||
136 | void httperror(int64 s,struct http_data* h,const char* title,const char* message) { | 171 | static void httpresponse( const int64 s, struct http_data *h) { |
137 | size_t reply_size = sprintf( static_scratch, "HTTP/1.0 %s\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: %zd\r\n\r\n<title>%s</title>\n", | 172 | char *c, *data, *reply; |
138 | title, strlen(message)+strlen(title)+16-4,title+4); | ||
139 | #ifdef _DEBUG_HTTPERROR | ||
140 | fprintf( stderr, "DEBUG: invalid request was: %s\n", debug_request ); | ||
141 | #endif | ||
142 | senddata(s,h,static_scratch,reply_size); | ||
143 | } | ||
144 | |||
145 | void httpresponse( int64 s, struct http_data* h) { | ||
146 | char *c, *data; | ||
147 | ot_peer peer; | 173 | ot_peer peer; |
148 | ot_torrent *torrent; | 174 | ot_torrent *torrent; |
149 | ot_hash *hash = NULL; | 175 | ot_hash *hash = NULL; |
150 | int numwant, tmp, scanon, mode; | 176 | int numwant, tmp, scanon, mode; |
151 | unsigned short port = htons(6881); | 177 | unsigned short port = htons(6881); |
178 | time_t t; | ||
152 | size_t reply_size = 0; | 179 | size_t reply_size = 0; |
153 | 180 | ||
154 | array_cat0( &h->request ); | 181 | array_cat0( &h->request ); |
@@ -158,104 +185,106 @@ void httpresponse( int64 s, struct http_data* h) { | |||
158 | memcpy( debug_request, array_start( &h->request ), array_bytes( &h->request ) ); | 185 | memcpy( debug_request, array_start( &h->request ), array_bytes( &h->request ) ); |
159 | #endif | 186 | #endif |
160 | 187 | ||
161 | if( byte_diff( c, 4, "GET ") ) { | 188 | if( byte_diff( c, 4, "GET ") ) HTTPERROR_400; |
162 | e400: | ||
163 | return httperror( s, h, "400 Invalid Request", "This server only understands GET." ); | ||
164 | } | ||
165 | 189 | ||
166 | c+=4; | 190 | c+=4; |
167 | for( data = c; *data!=' ' && *data != '\t' && *data != '\n' && *data != '\r'; ++data ) ; | 191 | for( data = c; *data!=' ' && *data != '\t' && *data != '\n' && *data != '\r'; ++data ) ; |
168 | 192 | ||
169 | if( *data != ' ' ) goto e400; | 193 | if( *data != ' ' ) HTTPERROR_400; |
170 | *data = 0; | 194 | *data = 0; |
171 | if( c[0] != '/' ) goto e404; | 195 | if( c[0] != '/' ) HTTPERROR_404; |
172 | while( *c == '/' ) ++c; | 196 | while( *c == '/' ) ++c; |
173 | 197 | ||
174 | switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { | 198 | switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) { |
199 | case 4: /* sync ? */ | ||
200 | if( byte_diff( data, 4, "sync") ) HTTPERROR_404; | ||
201 | scanon = 1; | ||
202 | |||
203 | while( scanon ) { | ||
204 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | ||
205 | case -2: scanon = 0; break; /* TERMINATOR */ | ||
206 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ | ||
207 | case 9: | ||
208 | if(byte_diff(data,9,"info_hash")) { | ||
209 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
210 | continue; | ||
211 | } | ||
212 | /* ignore this, when we have less than 20 bytes */ | ||
213 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; | ||
214 | hash = (ot_hash*)data; /* Fall through intended */ | ||
215 | break; | ||
216 | default: | ||
217 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | if( !hash ) HTTPERROR_400_PARAM; | ||
223 | if( ( reply_size = return_sync_for_torrent( hash, &reply ) ) <= 0 ) HTTPERROR_500; | ||
224 | |||
225 | return sendmallocdata( s, h, reply, reply_size ); | ||
175 | case 5: /* stats ? */ | 226 | case 5: /* stats ? */ |
176 | if( byte_diff(data,5,"stats")) | 227 | if( byte_diff(data,5,"stats")) HTTPERROR_404; |
177 | goto e404; | ||
178 | scanon = 1; | 228 | scanon = 1; |
179 | mode = STATS_MRTG; | 229 | mode = STATS_MRTG; |
180 | 230 | ||
181 | while( scanon ) { | 231 | while( scanon ) { |
182 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 232 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { |
183 | case -2: /* terminator */ | 233 | case -2: scanon = 0; break; /* TERMINATOR */ |
184 | scanon = 0; | 234 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
185 | break; | 235 | default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; |
186 | case -1: /* error */ | ||
187 | goto e404; | ||
188 | case 4: | 236 | case 4: |
189 | if( byte_diff(data,4,"mode")) { | 237 | if( byte_diff(data,4,"mode")) { |
190 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 238 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
191 | continue; | 239 | continue; |
192 | } | 240 | } |
193 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 241 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
194 | if( len <= 0 ) goto e400_param; | 242 | if( len <= 0 ) HTTPERROR_400_PARAM; |
195 | if( !byte_diff(data,4,"mrtg")) | 243 | if( !byte_diff(data,4,"mrtg")) |
196 | mode = STATS_MRTG; | 244 | mode = STATS_MRTG; |
197 | else if( !byte_diff(data,4,"top5")) | 245 | else if( !byte_diff(data,4,"top5")) |
198 | mode = STATS_TOP5; | 246 | mode = STATS_TOP5; |
199 | else | 247 | else |
200 | goto e400_param; | 248 | HTTPERROR_400_PARAM; |
201 | default: | ||
202 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
203 | break; | ||
204 | } | 249 | } |
205 | } | 250 | } |
206 | 251 | ||
207 | /* Enough for http header + whole scrape string */ | 252 | /* Enough for http header + whole scrape string */ |
208 | if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) | 253 | if( ( reply_size = return_stats_for_tracker( SUCCESS_HTTP_HEADER_LENGTH + static_scratch, mode ) ) <= 0 ) HTTPERROR_500; |
209 | goto e500; | 254 | |
210 | break; | 255 | break; |
211 | case 6: /* scrape ? */ | 256 | case 6: /* scrape ? */ |
212 | if( byte_diff( data, 6, "scrape") ) | 257 | if( byte_diff( data, 6, "scrape") ) HTTPERROR_404; |
213 | goto e404; | ||
214 | scanon = 1; | 258 | scanon = 1; |
215 | 259 | ||
216 | while( scanon ) { | 260 | while( scanon ) { |
217 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 261 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { |
218 | case -2: /* terminator */ | 262 | case -2: scanon = 0; break; /* TERMINATOR */ |
219 | scanon = 0; | 263 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
220 | break; | 264 | default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; |
221 | case -1: /* error */ | ||
222 | goto e404; | ||
223 | case 9: | 265 | case 9: |
224 | if(byte_diff(data,9,"info_hash")) { | 266 | if(byte_diff(data,9,"info_hash")) { |
225 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 267 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
226 | continue; | 268 | continue; |
227 | } | 269 | } |
228 | /* ignore this, when we have less than 20 bytes */ | 270 | /* ignore this, when we have less than 20 bytes */ |
229 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) { | 271 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; |
230 | e400_param: | ||
231 | return httperror(s,h,"400 Invalid Request","Invalid parameter"); | ||
232 | } | ||
233 | hash = (ot_hash*)data; /* Fall through intended */ | 272 | hash = (ot_hash*)data; /* Fall through intended */ |
234 | break; | 273 | break; |
235 | default: | ||
236 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
237 | break; | ||
238 | } | 274 | } |
239 | } | 275 | } |
240 | 276 | ||
241 | /* Scanned whole query string, no hash means full scrape... you might want to limit that */ | 277 | /* Scanned whole query string, no hash means full scrape... you might want to limit that */ |
242 | if( !hash ) { | 278 | if( !hash ) { |
243 | char * reply; | 279 | if( ( reply_size = return_fullscrape_for_tracker( &reply ) ) <= 0 ) HTTPERROR_500; |
244 | 280 | return sendmallocdata( s, h, reply, reply_size ); | |
245 | reply_size = return_fullscrape_for_tracker( &reply ); | ||
246 | if( reply_size ) | ||
247 | return sendmallocdata( s, h, reply, reply_size ); | ||
248 | |||
249 | goto e500; | ||
250 | } else { | ||
251 | /* Enough for http header + whole scrape string */ | ||
252 | if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) | ||
253 | goto e500; | ||
254 | } | 281 | } |
282 | |||
283 | /* Enough for http header + whole scrape string */ | ||
284 | if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) HTTPERROR_500; | ||
255 | break; | 285 | break; |
256 | case 8: | 286 | case 8: |
257 | if( byte_diff(data,8,"announce")) | 287 | if( byte_diff(data,8,"announce")) HTTPERROR_404; |
258 | goto e404; | ||
259 | 288 | ||
260 | OT_SETIP( &peer, h->ip); | 289 | OT_SETIP( &peer, h->ip); |
261 | OT_SETPORT( &peer, &port ); | 290 | OT_SETPORT( &peer, &port ); |
@@ -265,17 +294,15 @@ e400_param: | |||
265 | 294 | ||
266 | while( scanon ) { | 295 | while( scanon ) { |
267 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { | 296 | switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) { |
268 | case -2: /* terminator */ | 297 | case -2: scanon = 0; break; /* TERMINATOR */ |
269 | scanon = 0; | 298 | case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ |
270 | break; | 299 | default: scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); break; |
271 | case -1: /* error */ | ||
272 | goto e404; | ||
273 | #ifdef WANT_IP_FROM_QUERY_STRING | 300 | #ifdef WANT_IP_FROM_QUERY_STRING |
274 | case 2: | 301 | case 2: |
275 | if(!byte_diff(data,2,"ip")) { | 302 | if(!byte_diff(data,2,"ip")) { |
276 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 303 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
277 | unsigned char ip[4]; | 304 | unsigned char ip[4]; |
278 | if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param; | 305 | if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) HTTPERROR_400_PARAM; |
279 | OT_SETIP( &peer, ip ); | 306 | OT_SETIP( &peer, ip ); |
280 | } else | 307 | } else |
281 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 308 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
@@ -284,11 +311,11 @@ e400_param: | |||
284 | case 4: | 311 | case 4: |
285 | if(!byte_diff(data,4,"port")) { | 312 | if(!byte_diff(data,4,"port")) { |
286 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 313 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
287 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param; | 314 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; |
288 | port = htons( tmp ); OT_SETPORT( &peer, &port ); | 315 | port = htons( tmp ); OT_SETPORT( &peer, &port ); |
289 | } else if(!byte_diff(data,4,"left")) { | 316 | } else if(!byte_diff(data,4,"left")) { |
290 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 317 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
291 | if( len <= 0 ) goto e400_param; | 318 | if( len <= 0 ) HTTPERROR_400_PARAM; |
292 | if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; | 319 | if( scan_fixed_int( data, len, &tmp ) ) tmp = 0; |
293 | if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING; | 320 | if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING; |
294 | } else | 321 | } else |
@@ -299,7 +326,7 @@ e400_param: | |||
299 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 326 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
300 | else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { | 327 | else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { |
301 | case -1: | 328 | case -1: |
302 | goto e400_param; | 329 | HTTPERROR_400_PARAM; |
303 | case 7: | 330 | case 7: |
304 | if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; | 331 | if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED; |
305 | break; | 332 | break; |
@@ -312,13 +339,12 @@ e400_param: | |||
312 | case 7: | 339 | case 7: |
313 | if(!byte_diff(data,7,"numwant")) { | 340 | if(!byte_diff(data,7,"numwant")) { |
314 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 341 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
315 | if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param; | 342 | if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) HTTPERROR_400_PARAM; |
316 | if( numwant > 200 ) numwant = 200; | 343 | if( numwant > 200 ) numwant = 200; |
317 | } else if(!byte_diff(data,7,"compact")) { | 344 | } else if(!byte_diff(data,7,"compact")) { |
318 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); | 345 | size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); |
319 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param; | 346 | if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) HTTPERROR_400_PARAM; |
320 | if( !tmp ) | 347 | if( !tmp ) HTTPERROR_400_COMPACT; |
321 | return httperror(s,h,"400 Invalid Request","This server only delivers compact results."); | ||
322 | } else | 348 | } else |
323 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | 349 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); |
324 | break; | 350 | break; |
@@ -328,79 +354,58 @@ e400_param: | |||
328 | continue; | 354 | continue; |
329 | } | 355 | } |
330 | /* ignore this, when we have less than 20 bytes */ | 356 | /* ignore this, when we have less than 20 bytes */ |
331 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) | 357 | if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; |
332 | goto e400; | ||
333 | hash = (ot_hash*)data; | 358 | hash = (ot_hash*)data; |
334 | break; | 359 | break; |
335 | default: | ||
336 | scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); | ||
337 | break; | ||
338 | } | 360 | } |
339 | } | 361 | } |
340 | 362 | ||
341 | /* Scanned whole query string */ | 363 | /* Scanned whole query string */ |
342 | if( !hash ) goto e400; | 364 | if( !hash ) HTTPERROR_400_PARAM; |
343 | 365 | ||
344 | if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { | 366 | if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { |
345 | remove_peer_from_torrent( hash, &peer ); | 367 | remove_peer_from_torrent( hash, &peer ); |
346 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 368 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, "d8:completei0e10:incompletei0e8:intervali%ie5:peers0:e", OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
347 | } else { | 369 | } else { |
348 | torrent = add_peer_to_torrent( hash, &peer ); | 370 | torrent = add_peer_to_torrent( hash, &peer ); |
349 | if( !torrent ) { | 371 | if( !torrent || ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) HTTPERROR_500; |
350 | e500: | ||
351 | return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later."); | ||
352 | } | ||
353 | if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_scratch ) ) <= 0 ) | ||
354 | goto e500; | ||
355 | } | 372 | } |
356 | ot_overall_successfulannounces++; | 373 | ot_overall_successfulannounces++; |
357 | break; | 374 | break; |
358 | case 11: | 375 | case 11: |
359 | if( byte_diff(data,11,"mrtg_scrape")) | 376 | if( byte_diff(data,11,"mrtg_scrape")) HTTPERROR_404; |
360 | goto e404; | 377 | |
361 | { | 378 | t = time( NULL ) - ot_start_time; |
362 | time_t seconds_elapsed = time( NULL ) - ot_start_time; | 379 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, |
363 | reply_size = sprintf( static_scratch + SUCCESS_HTTP_HEADER_LENGTH, | 380 | "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", |
364 | "%i\n%i\nUp: %i seconds (%i hours)\nPretuned by german engineers, currently handling %i connections per second.", | 381 | ot_overall_connections, ot_overall_successfulannounces, (int)t, (int)(t / 3600), (int)ot_overall_connections / ( (int)t ? (int)t : 1 ) ); |
365 | ot_overall_connections, ot_overall_successfulannounces, (int)seconds_elapsed, | ||
366 | (int)(seconds_elapsed / 3600), (int)ot_overall_connections / ( (int)seconds_elapsed ? (int)seconds_elapsed : 1 ) ); | ||
367 | } | ||
368 | break; | 382 | break; |
369 | default: /* neither *scrape nor announce */ | 383 | default: /* neither *scrape nor announce */ |
370 | e404: | 384 | HTTPERROR_404; |
371 | return httperror( s, h, "404 Not Found", "No such file or directory." ); | ||
372 | } | 385 | } |
373 | 386 | ||
374 | if( reply_size ) { | 387 | if( reply_size <= 0 ) HTTPERROR_500; |
375 | /* This one is rather ugly, so I take you step by step through it. | ||
376 | 388 | ||
377 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to | 389 | /* This one is rather ugly, so I take you step by step through it. |
378 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string | ||
379 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate | ||
380 | the space NOT needed to expand in reply_off | ||
381 | */ | ||
382 | size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); | ||
383 | 390 | ||
384 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete | 391 | 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to |
385 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ | 392 | write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string |
386 | reply_size += 1 + sprintf( static_scratch + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); | 393 | plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate |
394 | the space NOT needed to expand in reply_off | ||
395 | */ | ||
396 | size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_scratch, 0, "%zd", reply_size ); | ||
387 | 397 | ||
388 | /* 3. Finally we join both blocks neatly */ | 398 | /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete |
389 | static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; | 399 | packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */ |
400 | reply_size += 1 + sprintf( static_scratch + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); | ||
390 | 401 | ||
391 | senddata( s, h, static_scratch + reply_off, reply_size ); | 402 | /* 3. Finally we join both blocks neatly */ |
392 | } else { | 403 | static_scratch[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; |
393 | if( h ) | 404 | |
394 | array_reset( &h->request ); | 405 | senddata( s, h, static_scratch + reply_off, reply_size ); |
395 | #ifdef _DEBUG_FDS | ||
396 | if( !fd_debug_space[s] ) fprintf( stderr, "close on non-open fd\n" ); | ||
397 | fd_debug_space[s] = 0; | ||
398 | #endif | ||
399 | free( h ); io_close( s ); | ||
400 | } | ||
401 | } | 406 | } |
402 | 407 | ||
403 | void graceful( int s ) { | 408 | static void graceful( int s ) { |
404 | if( s == SIGINT ) { | 409 | if( s == SIGINT ) { |
405 | signal( SIGINT, SIG_IGN); | 410 | signal( SIGINT, SIG_IGN); |
406 | deinit_logic(); | 411 | deinit_logic(); |
@@ -408,16 +413,7 @@ void graceful( int s ) { | |||
408 | } | 413 | } |
409 | } | 414 | } |
410 | 415 | ||
411 | #ifdef _DEBUG_FDS | 416 | static void usage( char *name ) { |
412 | void count_fds( int s ) { | ||
413 | int i, count = 0; | ||
414 | for( i=0; i<sizeof(fd_debug_space); ++i ) | ||
415 | if( fd_debug_space[i] ) ++count; | ||
416 | fprintf( stderr, "Open fds here: %i\n", count ); | ||
417 | } | ||
418 | #endif | ||
419 | |||
420 | void usage( char *name ) { | ||
421 | fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]" | 417 | fprintf( stderr, "Usage: %s [-i serverip] [-p serverport] [-d serverdirectory]" |
422 | #ifdef WANT_CLOSED_TRACKER | 418 | #ifdef WANT_CLOSED_TRACKER |
423 | " [-oc]" | 419 | " [-oc]" |
@@ -428,7 +424,7 @@ void usage( char *name ) { | |||
428 | "\n", name ); | 424 | "\n", name ); |
429 | } | 425 | } |
430 | 426 | ||
431 | void help( char *name ) { | 427 | static void help( char *name ) { |
432 | usage( name ); | 428 | usage( name ); |
433 | fprintf( stderr, "\t-i serverip\tspecify ip to bind to (default: *)\n" | 429 | fprintf( stderr, "\t-i serverip\tspecify ip to bind to (default: *)\n" |
434 | "\t-p serverport\tspecify port to bind to (default: 6969)\n" | 430 | "\t-p serverport\tspecify port to bind to (default: 6969)\n" |
@@ -453,19 +449,15 @@ void help( char *name ) { | |||
453 | ); | 449 | ); |
454 | } | 450 | } |
455 | 451 | ||
456 | void handle_read( int64 clientsocket ) { | 452 | static void handle_read( const int64 clientsocket ) { |
457 | struct http_data* h = io_getcookie( clientsocket ); | 453 | struct http_data* h = io_getcookie( clientsocket ); |
458 | int l = io_tryread( clientsocket, static_scratch, sizeof static_scratch ); | 454 | size_t l; |
459 | 455 | ||
460 | if( l <= 0 ) { | 456 | if( ( l = io_tryread( clientsocket, static_scratch, sizeof static_scratch ) ) <= 0 ) { |
461 | if( h ) { | 457 | if( h ) { |
462 | array_reset( &h->request ); | 458 | array_reset( &h->request ); |
463 | free( h ); | 459 | free( h ); |
464 | } | 460 | } |
465 | #ifdef _DEBUG_FDS | ||
466 | if( !fd_debug_space[clientsocket] ) fprintf( stderr, "close on non-open fd\n" ); | ||
467 | fd_debug_space[clientsocket] = 0; | ||
468 | #endif | ||
469 | io_close( clientsocket ); | 461 | io_close( clientsocket ); |
470 | return; | 462 | return; |
471 | } | 463 | } |
@@ -480,26 +472,22 @@ void handle_read( int64 clientsocket ) { | |||
480 | httperror( clientsocket, h, "500 Server Error", "Request too long."); | 472 | httperror( clientsocket, h, "500 Server Error", "Request too long."); |
481 | else if( array_bytes( &h->request ) > 8192 ) | 473 | else if( array_bytes( &h->request ) > 8192 ) |
482 | httperror( clientsocket, h, "500 request too long", "You sent too much headers"); | 474 | httperror( clientsocket, h, "500 request too long", "You sent too much headers"); |
483 | else if( ( l = header_complete( h ) ) ) | 475 | else if( ( l = httpheader_complete( h ) ) ) |
484 | httpresponse( clientsocket, h); | 476 | httpresponse( clientsocket, h); |
485 | } | 477 | } |
486 | 478 | ||
487 | void handle_write( int64 clientsocket ) { | 479 | static void handle_write( const int64 clientsocket ) { |
488 | struct http_data* h=io_getcookie( clientsocket ); | 480 | struct http_data* h=io_getcookie( clientsocket ); |
489 | if( !h ) return; | 481 | if( !h ) return; |
490 | if( iob_send( clientsocket, &h->batch ) <= 0 ) { | 482 | if( iob_send( clientsocket, &h->batch ) <= 0 ) { |
491 | iob_reset( &h->batch ); | 483 | iob_reset( &h->batch ); |
492 | #ifdef _DEBUG_FDS | ||
493 | if( !fd_debug_space[clientsocket] ) fprintf( stderr, "close on non-open fd\n" ); | ||
494 | fd_debug_space[clientsocket] = 0; | ||
495 | #endif | ||
496 | io_close( clientsocket ); | 484 | io_close( clientsocket ); |
497 | free( h ); | 485 | free( h ); |
498 | } | 486 | } |
499 | } | 487 | } |
500 | 488 | ||
501 | void handle_accept( int64 serversocket ) { | 489 | static void handle_accept( const int64 serversocket ) { |
502 | struct http_data* h; | 490 | struct http_data *h; |
503 | unsigned char ip[4]; | 491 | unsigned char ip[4]; |
504 | uint16 port; | 492 | uint16 port; |
505 | tai6464 t; | 493 | tai6464 t; |
@@ -513,11 +501,6 @@ void handle_accept( int64 serversocket ) { | |||
513 | continue; | 501 | continue; |
514 | } | 502 | } |
515 | 503 | ||
516 | #ifdef _DEBUG_FDS | ||
517 | if( fd_debug_space[i] ) fprintf( stderr, "double use of fd: %i\n", (int)i ); | ||
518 | fd_debug_space[i] = 1; | ||
519 | #endif | ||
520 | |||
521 | io_wantread( i ); | 504 | io_wantread( i ); |
522 | 505 | ||
523 | byte_zero(h,sizeof(struct http_data)); | 506 | byte_zero(h,sizeof(struct http_data)); |
@@ -531,13 +514,9 @@ void handle_accept( int64 serversocket ) { | |||
531 | 514 | ||
532 | if( errno==EAGAIN ) | 515 | if( errno==EAGAIN ) |
533 | io_eagain( serversocket ); | 516 | io_eagain( serversocket ); |
534 | /* | ||
535 | else | ||
536 | carp( "socket_accept4" ); | ||
537 | */ | ||
538 | } | 517 | } |
539 | 518 | ||
540 | void handle_timeouted( ) { | 519 | static void handle_timeouted( void ) { |
541 | int64 i; | 520 | int64 i; |
542 | while( ( i = io_timeouted() ) != -1 ) { | 521 | while( ( i = io_timeouted() ) != -1 ) { |
543 | struct http_data* h=io_getcookie( i ); | 522 | struct http_data* h=io_getcookie( i ); |
@@ -545,15 +524,11 @@ void handle_timeouted( ) { | |||
545 | array_reset( &h->request ); | 524 | array_reset( &h->request ); |
546 | free( h ); | 525 | free( h ); |
547 | } | 526 | } |
548 | #ifdef _DEBUG_FDS | ||
549 | if( !fd_debug_space[i] ) fprintf( stderr, "close on non-open fd\n" ); | ||
550 | fd_debug_space[i] = 0; | ||
551 | #endif | ||
552 | io_close(i); | 527 | io_close(i); |
553 | } | 528 | } |
554 | } | 529 | } |
555 | 530 | ||
556 | void server_mainloop( int64 serversocket ) { | 531 | static void server_mainloop( const int64 serversocket ) { |
557 | tai6464 t, next_timeout_check; | 532 | tai6464 t, next_timeout_check; |
558 | 533 | ||
559 | io_wantread( serversocket ); | 534 | io_wantread( serversocket ); |
@@ -626,9 +601,6 @@ int main( int argc, char **argv ) { | |||
626 | 601 | ||
627 | signal( SIGPIPE, SIG_IGN ); | 602 | signal( SIGPIPE, SIG_IGN ); |
628 | signal( SIGINT, graceful ); | 603 | signal( SIGINT, graceful ); |
629 | #ifdef _DEBUG_FDS | ||
630 | signal( SIGINFO, count_fds ); | ||
631 | #endif | ||
632 | if( init_logic( serverdir ) == -1 ) | 604 | if( init_logic( serverdir ) == -1 ) |
633 | panic( "Logic not started" ); | 605 | panic( "Logic not started" ); |
634 | 606 | ||
diff --git a/trackerlogic.c b/trackerlogic.c index 4de5038..38de8ca 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -64,7 +64,7 @@ static void *binary_search( const void * const key, const void * base, const siz | |||
64 | */ | 64 | */ |
65 | char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;} | 65 | char ths[2+2*20]="-";char*to_hex(ot_byte*s){char*m="0123456789ABCDEF";char*e=ths+41;char*t=ths+1;while(t<e){*t++=m[*s>>4];*t++=m[*s++&15];}*t=0;return ths+1;} |
66 | 66 | ||
67 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, int compare_size, int *exactmatch ) { | 67 | static void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { |
68 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); | 68 | ot_byte *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); |
69 | 69 | ||
70 | if( *exactmatch ) return match; | 70 | if( *exactmatch ) return match; |
@@ -104,7 +104,7 @@ static int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { | |||
104 | } | 104 | } |
105 | 105 | ||
106 | static void free_peerlist( ot_peerlist *peer_list ) { | 106 | static void free_peerlist( ot_peerlist *peer_list ) { |
107 | int i; | 107 | size_t i; |
108 | for( i=0; i<OT_POOLS_COUNT; ++i ) | 108 | for( i=0; i<OT_POOLS_COUNT; ++i ) |
109 | if( peer_list->peers[i].data ) | 109 | if( peer_list->peers[i].data ) |
110 | free( peer_list->peers[i].data ); | 110 | free( peer_list->peers[i].data ); |
@@ -227,9 +227,9 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) { | |||
227 | * RANDOM may return huge values | 227 | * RANDOM may return huge values |
228 | * does not yet check not to return self | 228 | * does not yet check not to return self |
229 | */ | 229 | */ |
230 | size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ) { | 230 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply ) { |
231 | char *r = reply; | 231 | char *r = reply; |
232 | unsigned int peer_count, seed_count, index; | 232 | size_t peer_count, seed_count, index; |
233 | 233 | ||
234 | #ifdef WANT_CLOSED_TRACKER | 234 | #ifdef WANT_CLOSED_TRACKER |
235 | if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) { | 235 | if( torrent == OT_TORRENT_NOT_ON_WHITELIST ) { |
@@ -247,13 +247,13 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char | |||
247 | } | 247 | } |
248 | #endif | 248 | #endif |
249 | 249 | ||
250 | for( peer_count=seed_count=index=0; index<OT_POOLS_COUNT; ++index) { | 250 | for( peer_count = seed_count = index = 0; index < OT_POOLS_COUNT; ++index ) { |
251 | peer_count += torrent->peer_list->peers[index].size; | 251 | peer_count += torrent->peer_list->peers[index].size; |
252 | seed_count += torrent->peer_list->seed_count[index]; | 252 | seed_count += torrent->peer_list->seed_count[index]; |
253 | } | 253 | } |
254 | if( peer_count < amount ) amount = peer_count; | 254 | if( peer_count < amount ) amount = peer_count; |
255 | 255 | ||
256 | r += sprintf( r, "d8:completei%ie10:incompletei%ie8:intervali%ie5:peers%i:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); | 256 | r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); |
257 | if( amount ) { | 257 | if( amount ) { |
258 | unsigned int pool_offset, pool_index = 0;; | 258 | unsigned int pool_offset, pool_index = 0;; |
259 | unsigned int shifted_pc = peer_count; | 259 | unsigned int shifted_pc = peer_count; |
@@ -292,8 +292,9 @@ size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char | |||
292 | 292 | ||
293 | /* Fetch full scrape info for all torrents */ | 293 | /* Fetch full scrape info for all torrents */ |
294 | size_t return_fullscrape_for_tracker( char **reply ) { | 294 | size_t return_fullscrape_for_tracker( char **reply ) { |
295 | int torrent_count = 0, i, j, k; | 295 | size_t torrent_count = 0, j; |
296 | char* r; | 296 | int i, k; |
297 | char *r; | ||
297 | time_t time_now = NOW; | 298 | time_t time_now = NOW; |
298 | 299 | ||
299 | for( i=0; i<256; ++i ) { | 300 | for( i=0; i<256; ++i ) { |
@@ -301,16 +302,15 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
301 | torrent_count += torrents_list->size; | 302 | torrent_count += torrents_list->size; |
302 | } | 303 | } |
303 | 304 | ||
304 | r = *reply = malloc( 128*torrent_count ); | 305 | if( !( r = *reply = malloc( 128*torrent_count ) ) ) return 0; |
305 | if( !reply ) return 0; | 306 | |
306 | |||
307 | memmove( r, "d5:filesd", 9 ); r += 9; | 307 | memmove( r, "d5:filesd", 9 ); r += 9; |
308 | for( i=0; i<256; ++i ) { | 308 | for( i=0; i<256; ++i ) { |
309 | ot_vector *torrents_list = &all_torrents[i]; | 309 | ot_vector *torrents_list = &all_torrents[i]; |
310 | for( j=0; j<torrents_list->size; ++j ) { | 310 | for( j=0; j<torrents_list->size; ++j ) { |
311 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 311 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
312 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | 312 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
313 | int peers = 0, seeds = 0; | 313 | size_t peers = 0, seeds = 0; |
314 | clean_peerlist( time_now, peer_list ); | 314 | clean_peerlist( time_now, peer_list ); |
315 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 315 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
316 | peers += peer_list->peers[k].size; | 316 | peers += peer_list->peers[k].size; |
@@ -318,7 +318,7 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
318 | } | 318 | } |
319 | memmove( r, "20:", 3 ); r+=3; | 319 | memmove( r, "20:", 3 ); r+=3; |
320 | memmove( r, hash, 20 ); r+=20; | 320 | memmove( r, hash, 20 ); r+=20; |
321 | r += sprintf( r, "d8:completei%de10:downloadedi%de10:incompletei%de", seeds, peer_list->downloaded, peers-seeds ); | 321 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde", seeds, peer_list->downloaded, peers-seeds ); |
322 | } | 322 | } |
323 | } | 323 | } |
324 | 324 | ||
@@ -329,7 +329,8 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
329 | /* Fetches scrape info for a specific torrent */ | 329 | /* Fetches scrape info for a specific torrent */ |
330 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { | 330 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { |
331 | char *r = reply; | 331 | char *r = reply; |
332 | int exactmatch, peers = 0, seeds = 0, i; | 332 | int exactmatch, i; |
333 | size_t peers = 0, seeds = 0; | ||
333 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | 334 | ot_vector *torrents_list = &all_torrents[*hash[0]]; |
334 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 335 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
335 | 336 | ||
@@ -342,20 +343,45 @@ size_t return_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
342 | } | 343 | } |
343 | 344 | ||
344 | memmove( r, "d5:filesd20:", 12 ); memmove( r+12, hash, 20 ); | 345 | memmove( r, "d5:filesd20:", 12 ); memmove( r+12, hash, 20 ); |
345 | r += sprintf( r+32, "d8:completei%de10:downloadedi%de10:incompletei%deeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32; | 346 | r += sprintf( r+32, "d8:completei%zde10:downloadedi%zde10:incompletei%zdeeee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 32; |
346 | 347 | ||
347 | return r - reply; | 348 | return r - reply; |
348 | } | 349 | } |
349 | 350 | ||
351 | size_t return_sync_for_torrent( ot_hash *hash, char **reply ) { | ||
352 | int exactmatch; | ||
353 | size_t peers = 0; | ||
354 | char *r; | ||
355 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | ||
356 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
357 | |||
358 | if( exactmatch ) { | ||
359 | clean_peerlist( NOW, torrent->peer_list ); | ||
360 | peers = torrent->peer_list->peers[0].size; | ||
361 | } | ||
362 | |||
363 | if( !( r = *reply = malloc( 10 + peers * sizeof( ot_peer ) ) ) ) return 0; | ||
364 | |||
365 | memmove( r, "d4:sync", 7 ); | ||
366 | r += 7; | ||
367 | r += sprintf( r, "%zd:", peers * sizeof( ot_peer ) ); | ||
368 | if( peers ) { | ||
369 | memmove( r, torrent->peer_list->peers[0].data, peers * sizeof( ot_peer ) ); | ||
370 | r += peers * sizeof( ot_peer ); | ||
371 | } | ||
372 | *r++ = 'e'; | ||
373 | return r - *reply; | ||
374 | } | ||
375 | |||
350 | typedef struct { int val; ot_torrent * torrent; } ot_record; | 376 | typedef struct { int val; ot_torrent * torrent; } ot_record; |
351 | 377 | ||
352 | /* Fetches stats from tracker */ | 378 | /* Fetches stats from tracker */ |
353 | size_t return_stats_for_tracker( char *reply, int mode ) { | 379 | size_t return_stats_for_tracker( char *reply, int mode ) { |
354 | time_t time_now = NOW; | 380 | time_t time_now = NOW; |
355 | int torrent_count = 0, peer_count = 0, seed_count = 0; | 381 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; |
356 | ot_record top5s[5], top5c[5]; | 382 | ot_record top5s[5], top5c[5]; |
357 | char *r = reply; | 383 | char *r = reply; |
358 | int i,j,k; | 384 | int i,k; |
359 | 385 | ||
360 | byte_zero( top5s, sizeof( top5s ) ); | 386 | byte_zero( top5s, sizeof( top5s ) ); |
361 | byte_zero( top5c, sizeof( top5c ) ); | 387 | byte_zero( top5c, sizeof( top5c ) ); |
@@ -365,7 +391,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
365 | torrent_count += torrents_list->size; | 391 | torrent_count += torrents_list->size; |
366 | for( j=0; j<torrents_list->size; ++j ) { | 392 | for( j=0; j<torrents_list->size; ++j ) { |
367 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 393 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
368 | int local_peers = 0, local_seeds = 0; | 394 | size_t local_peers = 0, local_seeds = 0; |
369 | clean_peerlist( time_now, peer_list ); | 395 | clean_peerlist( time_now, peer_list ); |
370 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 396 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
371 | local_peers += peer_list->peers[k].size; | 397 | local_peers += peer_list->peers[k].size; |
@@ -399,7 +425,7 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
399 | if( top5s[idx].torrent ) | 425 | if( top5s[idx].torrent ) |
400 | r += sprintf( r, "\t%i\t%s\n", top5s[idx].val, to_hex(top5s[idx].torrent->hash) ); | 426 | r += sprintf( r, "\t%i\t%s\n", top5s[idx].val, to_hex(top5s[idx].torrent->hash) ); |
401 | } else { | 427 | } else { |
402 | r += sprintf( r, "%i\n%i\nopentracker serving %i torrents\nSomething else.", peer_count, seed_count, torrent_count ); | 428 | r += sprintf( r, "%zd\n%zd\nopentracker serving %zd torrents\nopentracker", peer_count, seed_count, torrent_count ); |
403 | } | 429 | } |
404 | 430 | ||
405 | return r - reply; | 431 | return r - reply; |
@@ -429,7 +455,7 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) { | |||
429 | } | 455 | } |
430 | } | 456 | } |
431 | 457 | ||
432 | int init_logic( char *serverdir ) { | 458 | int init_logic( const char * const serverdir ) { |
433 | if( serverdir && chdir( serverdir ) ) { | 459 | if( serverdir && chdir( serverdir ) ) { |
434 | fprintf( stderr, "Could not chdir() to %s\n", serverdir ); | 460 | fprintf( stderr, "Could not chdir() to %s\n", serverdir ); |
435 | return -1; | 461 | return -1; |
@@ -443,8 +469,9 @@ int init_logic( char *serverdir ) { | |||
443 | return 0; | 469 | return 0; |
444 | } | 470 | } |
445 | 471 | ||
446 | void deinit_logic( ) { | 472 | void deinit_logic( void ) { |
447 | int i, j; | 473 | int i; |
474 | size_t j; | ||
448 | 475 | ||
449 | /* Free all torrents... */ | 476 | /* Free all torrents... */ |
450 | for(i=0; i<256; ++i ) { | 477 | for(i=0; i<256; ++i ) { |
diff --git a/trackerlogic.h b/trackerlogic.h index 8a61b74..083c437 100644 --- a/trackerlogic.h +++ b/trackerlogic.h | |||
@@ -64,7 +64,7 @@ static const ot_byte PEER_FLAG_STOPPED = 0x20; | |||
64 | typedef struct { | 64 | typedef struct { |
65 | ot_time base; | 65 | ot_time base; |
66 | size_t seed_count[ OT_POOLS_COUNT ]; | 66 | size_t seed_count[ OT_POOLS_COUNT ]; |
67 | unsigned int downloaded; | 67 | size_t downloaded; |
68 | ot_vector peers[ OT_POOLS_COUNT ]; | 68 | ot_vector peers[ OT_POOLS_COUNT ]; |
69 | } ot_peerlist; | 69 | } ot_peerlist; |
70 | 70 | ||
@@ -77,8 +77,8 @@ typedef struct { | |||
77 | Exported functions | 77 | Exported functions |
78 | */ | 78 | */ |
79 | 79 | ||
80 | int init_logic( char *serverdir ); | 80 | int init_logic( const char * const serverdir ); |
81 | void deinit_logic( ); | 81 | void deinit_logic( void ); |
82 | 82 | ||
83 | #ifdef WANT_CLOSED_TRACKER | 83 | #ifdef WANT_CLOSED_TRACKER |
84 | extern int g_closedtracker; | 84 | extern int g_closedtracker; |
@@ -90,9 +90,10 @@ extern int g_check_blacklist; | |||
90 | enum { STATS_MRTG, STATS_TOP5 }; | 90 | enum { STATS_MRTG, STATS_TOP5 }; |
91 | 91 | ||
92 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ); | 92 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ); |
93 | size_t return_peers_for_torrent( ot_torrent *torrent, unsigned int amount, char *reply ); | 93 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply ); |
94 | size_t return_fullscrape_for_tracker( char **reply ); | 94 | size_t return_fullscrape_for_tracker( char **reply ); |
95 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ); | 95 | size_t return_scrape_for_torrent( ot_hash *hash, char *reply ); |
96 | size_t return_sync_for_torrent( ot_hash *hash, char **reply ); | ||
96 | size_t return_stats_for_tracker( char *reply, int mode ); | 97 | size_t return_stats_for_tracker( char *reply, int mode ); |
97 | void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ); | 98 | void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ); |
98 | 99 | ||