summaryrefslogtreecommitdiff
path: root/opentracker.c
diff options
context:
space:
mode:
Diffstat (limited to 'opentracker.c')
-rw-r--r--opentracker.c402
1 files changed, 204 insertions, 198 deletions
diff --git a/opentracker.c b/opentracker.c
index ac09089..f4b5e21 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -6,8 +6,8 @@
6#include "socket.h" 6#include "socket.h"
7#include "io.h" 7#include "io.h"
8#include "buffer.h" 8#include "buffer.h"
9#include "ip6.h"
10#include "array.h" 9#include "array.h"
10#include "byte.h"
11#include "case.h" 11#include "case.h"
12#include "fmt.h" 12#include "fmt.h"
13#include "str.h" 13#include "str.h"
@@ -25,14 +25,14 @@
25#include "trackerlogic.h" 25#include "trackerlogic.h"
26#include "scan_urlencoded_query.h" 26#include "scan_urlencoded_query.h"
27 27
28unsigned long const OT_CLIENT_TIMEOUT = 15; 28unsigned int const OT_CLIENT_TIMEOUT = 15;
29unsigned long const OT_CLIENT_TIMEOUT_CHECKINTERVAL = 5; 29unsigned int const OT_CLIENT_TIMEOUT_CHECKINTERVAL = 5;
30 30
31static unsigned int ot_overall_connections = 0; 31static unsigned int ot_overall_connections = 0;
32static time_t ot_start_time; 32static time_t ot_start_time;
33static const unsigned int SUCCESS_HTTP_HEADER_LENGTH = 80; 33static const size_t SUCCESS_HTTP_HEADER_LENGTH = 80;
34static const unsigned int SUCCESS_HTTP_SIZE_OFF = 17; 34static const size_t SUCCESS_HTTP_SIZE_OFF = 17;
35// To always have space for error messages 35/* To always have space for error messages ;) */
36static char static_reply[8192]; 36static char static_reply[8192];
37 37
38static void carp(const char* routine) { 38static void carp(const char* routine) {
@@ -49,13 +49,12 @@ static void panic(const char* routine) {
49 49
50struct http_data { 50struct http_data {
51 array r; 51 array r;
52 unsigned long ip; 52 unsigned char ip[4];
53}; 53};
54 54
55int header_complete(struct http_data* r) { 55int header_complete(struct http_data* r) {
56 long l = array_bytes(&r->r); 56 int l = array_bytes(&r->r), i;
57 const char* c = array_start(&r->r); 57 const char* c = array_start(&r->r);
58 long i;
59 58
60 for (i=0; i+1<l; ++i) { 59 for (i=0; i+1<l; ++i) {
61 if (c[i]=='\n' && c[i+1]=='\n') return i+2; 60 if (c[i]=='\n' && c[i+1]=='\n') return i+2;
@@ -64,7 +63,7 @@ int header_complete(struct http_data* r) {
64 return 0; 63 return 0;
65} 64}
66 65
67// whoever sends data is not interested in its input-array 66/* whoever sends data is not interested in its input-array */
68void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) { 67void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) {
69 size_t written_size; 68 size_t written_size;
70 69
@@ -73,7 +72,7 @@ void senddata(int64 s, struct http_data* h, char *buffer, size_t size ) {
73 if( ( written_size < 0 ) || ( written_size == size ) ) { 72 if( ( written_size < 0 ) || ( written_size == size ) ) {
74 free(h); io_close( s ); 73 free(h); io_close( s );
75 } else { 74 } else {
76 // here we would take a copy of the buffer and remember it 75 /* here we would take a copy of the buffer and remember it */
77 fprintf( stderr, "Should have handled this.\n" ); 76 fprintf( stderr, "Should have handled this.\n" );
78 free(h); io_close( s ); 77 free(h); io_close( s );
79 } 78 }
@@ -85,218 +84,225 @@ void httperror(int64 s,struct http_data* h,const char* title,const char* message
85 senddata(s,h,static_reply,reply_size); 84 senddata(s,h,static_reply,reply_size);
86} 85}
87 86
88// bestimmten http parameter auslesen und adresse zurueckgeben
89const char* http_header(struct http_data* r,const char* h) { 87const char* http_header(struct http_data* r,const char* h) {
90 long i; 88 int i, l = array_bytes(&r->r);
91 89 int sl = strlen(h);
92 long l = array_bytes(&r->r); 90 const char* c = array_start(&r->r);
93 long sl = strlen(h); 91
94 const char* c = array_start(&r->r); 92 for (i=0; i+sl+2<l; ++i) {
95 93 if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':') {
96 for (i=0; i+sl+2<l; ++i) 94 c+=i+sl+1;
97 { 95 if (*c==' ' || *c=='\t') ++c;
98 if (c[i]=='\n' && case_equalb(c+i+1,sl,h) && c[i+sl+1]==':') 96 return c;
99 {
100 c+=i+sl+1;
101 if (*c==' ' || *c=='\t') ++c;
102 return c;
103 }
104 return 0;
105 } 97 }
106 return 0; 98 return 0;
99 }
100 return 0;
107} 101}
108 102
109void httpresponse(int64 s,struct http_data* h) 103void httpresponse(int64 s,struct http_data* h)
110{ 104{
111 char *c, *data; // must be enough 105 char *c, *data;
112 ot_peer peer; 106 ot_peer peer;
113 ot_torrent *torrent; 107 ot_torrent *torrent;
114 ot_hash *hash = NULL; 108 ot_hash *hash = NULL;
115 int numwant, tmp, scanon; 109 int numwant, tmp, scanon;
116 unsigned short port = htons(6881); 110 unsigned short port = htons(6881);
117 size_t reply_size = 0; 111 size_t reply_size = 0;
118 112
119 array_cat0(&h->r); 113 array_cat0(&h->r);
120 c = array_start(&h->r); 114 c = array_start(&h->r);
121 115
122 if (byte_diff(c,4,"GET ")) { 116 if (byte_diff(c,4,"GET ")) {
123e400: 117e400:
124 return httperror(s,h,"400 Invalid Request","This server only understands GET."); 118 return httperror(s,h,"400 Invalid Request","This server only understands GET.");
125 } 119 }
126
127 c+=4;
128 for (data=c; *data!=' '&&*data!='\t'&&*data!='\n'&&*data!='\r'; ++data) ;
129
130 if (*data!=' ') goto e400;
131 *data=0;
132 if (c[0]!='/') goto e404;
133 while (*c=='/') ++c;
134 120
135 switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) 121 c+=4;
136 { 122 for (data=c; *data!=' '&&*data!='\t'&&*data!='\n'&&*data!='\r'; ++data) ;
137 case 6: /* scrape ? */ 123
138 if (byte_diff(data,6,"scrape")) 124 if (*data!=' ') goto e400;
125 *data=0;
126 if (c[0]!='/') goto e404;
127 while (*c=='/') ++c;
128
129 switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) {
130 case 6: /* scrape ? */
131 if (byte_diff(data,6,"scrape"))
132 goto e404;
133 scanon = 1;
134
135 while( scanon ) {
136 switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
137 case -2: /* terminator */
138 scanon = 0;
139 break;
140 case -1: /* error */
139 goto e404; 141 goto e404;
140 scanon = 1; 142 case 9:
141 143 if(byte_diff(data,9,"info_hash")) {
142 while( scanon ) {
143 switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
144 case -2: /* terminator */
145 scanon = 0;
146 break;
147 case -1: /* error */
148 goto e404;
149 case 9:
150 if(byte_diff(data,9,"info_hash")) {
151 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
152 continue;
153 }
154 /* ignore this, when we have less than 20 bytes */
155 if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) {
156e400_param:
157 return httperror(s,h,"400 Invalid Request","Invalid parameter");
158 }
159 hash = (ot_hash*)data; /* Fall through intended */
160 break;
161 default:
162 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); 144 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
163 break; 145 continue;
146 }
147 /* ignore this, when we have less than 20 bytes */
148 if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) {
149e400_param:
150 return httperror(s,h,"400 Invalid Request","Invalid parameter");
164 } 151 }
152 hash = (ot_hash*)data; /* Fall through intended */
153 break;
154 default:
155 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
156 break;
165 } 157 }
158 }
166 159
167 /* Scanned whole query string, wo */ 160 /* Scanned whole query string, wo */
168 if( !hash ) 161 if( !hash )
169 return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes."); 162 return httperror(s,h,"400 Invalid Request","This server only serves specific scrapes.");
170 163
171 // Enough for http header + whole scrape string 164 /* Enough for http header + whole scrape string */
172 if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 ) 165 if( ( reply_size = return_scrape_for_torrent( hash, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
173 goto e500; 166 goto e500;
174 break; 167 break;
175 case 8: 168 case 8:
176 if( byte_diff(data,8,"announce")) 169 if( byte_diff(data,8,"announce"))
170 goto e404;
171
172 OT_SETIP( &peer, h->ip);
173 OT_SETPORT( &peer, &port );
174 OT_FLAG( &peer ) = 0;
175 numwant = 50;
176 scanon = 1;
177
178 while( scanon ) {
179 switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
180 case -2: /* terminator */
181 scanon = 0;
182 break;
183 case -1: /* error */
177 goto e404; 184 goto e404;
178
179 OT_SETIP( &peer, &h->ip);
180 OT_SETPORT( &peer, &port );
181 OT_FLAG( &peer ) = 0;
182 numwant = 50;
183 scanon = 1;
184
185 while( scanon ) {
186 switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
187 case -2: /* terminator */
188 scanon = 0;
189 break;
190 case -1: /* error */
191 goto e404;
192#ifdef WANT_IP_FROM_QUERY_STRING 185#ifdef WANT_IP_FROM_QUERY_STRING
193 case 2: 186 case 2:
194 if(!byte_diff(data,2,"ip")) { 187 if(!byte_diff(data,2,"ip")) {
195 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); 188 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
196 unsigned char ip[4]; 189 unsigned char ip[4];
197 if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param; 190 if( ( len <= 0 ) || scan_fixed_ip( data, len, ip ) ) goto e400_param;
198 OT_SETIP ( &peer, ip ); 191 OT_SETIP ( &peer, ip );
199 } else 192 } else
200 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); 193 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
201 break; 194 break;
202#endif 195#endif
203 case 4: 196 case 4:
204 if(!byte_diff(data,4,"port")) { 197 if(!byte_diff(data,4,"port")) {
205 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); 198 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
206 if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param; 199 if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) || ( tmp > 0xffff ) ) goto e400_param;
207 port = htons( tmp ); OT_SETPORT ( &peer, &port ); 200 port = htons( tmp ); OT_SETPORT ( &peer, &port );
208 } else if(!byte_diff(data,4,"left")) { 201 } else if(!byte_diff(data,4,"left")) {
209 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ); 202 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
210 if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param; 203 if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
211 if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING; 204 if( !tmp ) OT_FLAG( &peer ) |= PEER_FLAG_SEEDING;
212 } else 205 } else
213 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); 206 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
214 break; 207 break;
215 case 5: 208 case 5:
216 if(byte_diff(data,5,"event")) 209 if(byte_diff(data,5,"event"))
217 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); 210 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
218 else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) { 211 else switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) ) {
219 case -1: 212 case -1:
220 goto e400_param; 213 goto e400_param;
221 case 7:
222 if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED;
223 break;
224 case 9:
225 if(!byte_diff(data,9,"complete")) OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED;
226 default: // Fall through intended
227 break;
228 }
229 break;
230 case 7: 214 case 7:
231 if(!byte_diff(data,7,"numwant")) { 215 if(!byte_diff(data,7,"stopped")) OT_FLAG( &peer ) |= PEER_FLAG_STOPPED;
232 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
233 if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param;
234 if( numwant > 200 ) numwant = 200;
235 } else if(!byte_diff(data,7,"compact")) {
236 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
237 if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
238 if( !tmp )
239 return httperror(s,h,"400 Invalid Request","This server only delivers compact results.");
240 } else
241 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
242 break; 216 break;
243 case 9: 217 case 9:
244 if(byte_diff(data,9,"info_hash")) { 218 if(!byte_diff(data,9,"complete")) OT_FLAG( &peer ) |= PEER_FLAG_COMPLETED;
245 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); 219 default: /* Fall through intended */
246 continue;
247 }
248 /* ignore this, when we have less than 20 bytes */
249 if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 )
250 goto e400;
251 hash = (ot_hash*)data;
252 break; 220 break;
253 default: 221 }
222 break;
223 case 7:
224 if(!byte_diff(data,7,"numwant")) {
225 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
226 if( ( len <= 0 ) || scan_fixed_int( data, len, &numwant ) ) goto e400_param;
227 if( numwant > 200 ) numwant = 200;
228 } else if(!byte_diff(data,7,"compact")) {
229 size_t len = scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE );
230 if( ( len <= 0 ) || scan_fixed_int( data, len, &tmp ) ) goto e400_param;
231 if( !tmp )
232 return httperror(s,h,"400 Invalid Request","This server only delivers compact results.");
233 } else
254 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE ); 234 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
255 break; 235 break;
236 case 9:
237 if(byte_diff(data,9,"info_hash")) {
238 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
239 continue;
256 } 240 }
241 /* ignore this, when we have less than 20 bytes */
242 if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 )
243 goto e400;
244 hash = (ot_hash*)data;
245 break;
246 default:
247 scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
248 break;
257 } 249 }
250 }
258 251
259 /* Scanned whole query string */ 252 /* Scanned whole query string */
260 if( !hash ) goto e400; 253 if( !hash ) goto e400;
261 254
262 if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) { 255 if( OT_FLAG( &peer ) & PEER_FLAG_STOPPED ) {
263 remove_peer_from_torrent( hash, &peer ); 256 remove_peer_from_torrent( hash, &peer );
264 MEMMOVE( static_reply + SUCCESS_HTTP_HEADER_LENGTH, "d15:warning message4:Okaye", reply_size = 26 ); 257 memmove( static_reply + SUCCESS_HTTP_HEADER_LENGTH, "d15:warning message4:Okaye", reply_size = 26 );
265 } else { 258 } else {
266 torrent = add_peer_to_torrent( hash, &peer ); 259 torrent = add_peer_to_torrent( hash, &peer );
267 if( !torrent ) { 260 if( !torrent ) {
268e500: 261e500:
269 return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later."); 262 return httperror(s,h,"500 Internal Server Error","A server error has occured. Please retry later.");
270 }
271 if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
272 goto e500;
273 } 263 }
274 break; 264 if( ( reply_size = return_peers_for_torrent( torrent, numwant, SUCCESS_HTTP_HEADER_LENGTH + static_reply ) ) <= 0 )
275 case 11: 265 goto e500;
276 if( byte_diff(data,11,"mrtg_scrape"))
277 goto e404;
278 {
279 unsigned long seconds_elapsed = time( NULL ) - ot_start_time;
280 reply_size = sprintf( static_reply + SUCCESS_HTTP_HEADER_LENGTH,
281 "%d\n%d\nUp: %ld seconds (%ld hours)\nPretuned by german engineers, currently handling %li connections per second.",
282 ot_overall_connections, ot_overall_connections, seconds_elapsed,
283 seconds_elapsed / 3600, ot_overall_connections / ( seconds_elapsed ? seconds_elapsed : 1 ) );
284 }
285 break;
286 default: /* neither *scrape nor announce */
287e404:
288 return httperror(s,h,"404 Not Found","No such file or directory.");
289 } 266 }
290 267 break;
291 if( reply_size ) { 268 case 11:
292 size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_reply, 0, "%zd", reply_size ); 269 if( byte_diff(data,11,"mrtg_scrape"))
293 reply_size += 1 + sprintf( static_reply + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size ); 270 goto e404;
294 static_reply[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n'; 271 {
295 senddata( s, h, static_reply + reply_off, reply_size ); 272 time_t seconds_elapsed = time( NULL ) - ot_start_time;
296 } else { 273 reply_size = sprintf( static_reply + SUCCESS_HTTP_HEADER_LENGTH,
297 if( h ) array_reset(&h->r); 274 "%d\n%d\nUp: %ld seconds (%ld hours)\nPretuned by german engineers, currently handling %li connections per second.",
298 free( h ); io_close( s ); 275 ot_overall_connections, ot_overall_connections, seconds_elapsed,
276 seconds_elapsed / 3600, ot_overall_connections / ( seconds_elapsed ? seconds_elapsed : 1 ) );
299 } 277 }
278 break;
279 default: /* neither *scrape nor announce */
280e404:
281 return httperror(s,h,"404 Not Found","No such file or directory.");
282 }
283
284 if( reply_size ) {
285 /* This one is rather ugly, so I take you step by step through it.
286
287 1. In order to avoid having two buffers, one for header and one for content, we allow all above functions from trackerlogic to
288 write to a fixed location, leaving SUCCESS_HTTP_HEADER_LENGTH bytes in our static buffer, which is enough for the static string
289 plus dynamic space needed to expand our Content-Length value. We reserve SUCCESS_HTTP_SIZE_OFF for it expansion and calculate
290 the space NOT needed to expand in reply_off
291 */
292 size_t reply_off = SUCCESS_HTTP_SIZE_OFF - snprintf( static_reply, 0, "%zd", reply_size );
293
294 /* 2. Now we sprintf our header so that sprintf writes its terminating '\0' exactly one byte before content starts. Complete
295 packet size is increased by size of header plus one byte '\n', we will copy over '\0' in next step */
296 reply_size += 1 + sprintf( static_reply + reply_off, "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %zd\r\n\r", reply_size );
297
298 /* 3. Finally we join both blocks neatly */
299 static_reply[ SUCCESS_HTTP_HEADER_LENGTH - 1 ] = '\n';
300
301 senddata( s, h, static_reply + reply_off, reply_size );
302 } else {
303 if( h ) array_reset(&h->r);
304 free( h ); io_close( s );
305 }
300} 306}
301 307
302void graceful( int s ) { 308void graceful( int s ) {
@@ -346,10 +352,10 @@ void help( char *name ) {
346int main( int argc, char **argv ) { 352int main( int argc, char **argv ) {
347 int s=socket_tcp4(); 353 int s=socket_tcp4();
348 tai6464 t, next_timeout_check; 354 tai6464 t, next_timeout_check;
349 unsigned long ip;
350 char *serverip = NULL; 355 char *serverip = NULL;
351 char *serverdir = "."; 356 char *serverdir = ".";
352 uint16 port = 6969; 357 uint16 port = 6969;
358 unsigned char ip[4];
353 359
354 while( 1 ) { 360 while( 1 ) {
355 switch( getopt(argc,argv,":i:p:d:ocbBh") ) { 361 switch( getopt(argc,argv,":i:p:d:ocbBh") ) {
@@ -412,16 +418,16 @@ allparsed:
412 } 418 }
413 419
414 while( ( i = io_canread() ) != -1 ) { 420 while( ( i = io_canread() ) != -1 ) {
415 if( i == s ) { // ist es der serversocket? 421 if( i == s ) {
416 int n; 422 int n;
417 while( ( n = socket_accept4( s, (void*)&ip, &port) ) != -1 ) { 423 while( ( n = socket_accept4( s, (char*)ip, &port) ) != -1 ) {
418 if( io_fd( n ) ) { 424 if( io_fd( n ) ) {
419 struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data)); 425 struct http_data* h=(struct http_data*)malloc(sizeof(struct http_data));
420 io_wantread(n); 426 io_wantread(n);
421 427
422 if (h) { 428 if (h) {
423 byte_zero(h,sizeof(struct http_data)); 429 byte_zero(h,sizeof(struct http_data));
424 h->ip=ip; 430 memmove(h->ip,ip,sizeof(ip));
425 taia_now(&t); 431 taia_now(&t);
426 taia_addsec(&t,&t,OT_CLIENT_TIMEOUT); 432 taia_addsec(&t,&t,OT_CLIENT_TIMEOUT);
427 io_timeout(n,t); 433 io_timeout(n,t);
@@ -437,7 +443,7 @@ allparsed:
437 else 443 else
438 carp("socket_accept4"); 444 carp("socket_accept4");
439 } else { 445 } else {
440 char buf[8192]; 446 /* unsigned (sic!) */ char buf[8192];
441 struct http_data* h=io_getcookie(i); 447 struct http_data* h=io_getcookie(i);
442 448
443 int l=io_tryread(i,buf,sizeof buf); 449 int l=io_tryread(i,buf,sizeof buf);