1 #define _GNU_SOURCE
2 #include "gatling.h"
3
4 #include "socket.h"
5 #include "io.h"
6 #include "buffer.h"
7 #include "ip4.h"
8 #include "ip6.h"
9 #include "array.h"
10 #include "case.h"
11 #include "fmt.h"
12 #include "iob.h"
13 #include "str.h"
14 #include "scan.h"
15 #include "textcode.h"
16 #include "uint32.h"
17 #include "uint16.h"
18 #include "mmap.h"
19 #include "rangecheck.h"
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #ifndef __MINGW32__
26 #include <sys/resource.h>
27 #include <sys/socket.h>
28 #include <pwd.h>
29 #include <grp.h>
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
32 #include <sys/mman.h>
33 #include <fnmatch.h>
34 #include <sys/wait.h>
35 #endif
36 #include <stdlib.h>
37 #include <dirent.h>
38 #include <time.h>
39 #include <signal.h>
40 #include "version.h"
41 #include <assert.h>
42 #ifdef SUPPORT_SMB
43 #include <iconv.h>
44 #endif
45 #ifdef SUPPORT_PROXY
46 #include <regex.h>
47 #endif
48 #include <limits.h>
49 #include <fcntl.h>
50 #include <string.h>
51 #include <ctype.h>
52 // #include <crypt.h>
53 #include "havealloca.h"
54 #include "havesetresuid.h"
55 #include "dirfd.h"
56
57 #include <stdio.h>
58
59 #if !defined(__OPTIMIZE__) && defined(__linux__)
60 #include <sys/prctl.h>
61 #endif
62
63 char serverroot[1024];
64
65 #ifdef SUPPORT_MULTIPROC
66 unsigned long instances=1;
67 #endif
68 unsigned long timeout_secs=23;
69 tai6464 now,next;
70
71 #ifdef TIMEOUT_DEBUG
new_io_timeout(int64 d,tai6464 t)72 void new_io_timeout(int64 d,tai6464 t) {
73 struct taia now;
74 struct taia diff;
75 taia_now(&now);
76 taia_sub(&diff,&t,&now);
77 buffer_puts(buffer_2,"DEBUG: scheduling timeout for fd #");
78 buffer_putlonglong(buffer_2,d);
79 buffer_puts(buffer_2," in ");
80 buffer_putlonglong(buffer_2,diff.sec.x);
81 buffer_putsflush(buffer_2," seconds.\n");
82 io_timeout(d,t);
83 }
84
new_io_timeouted()85 int64 new_io_timeouted() {
86 int64 x=io_timeouted();
87 buffer_puts(buffer_2,"DEBUG: io_timeouted called, returned ");
88 buffer_putlonglong(buffer_2,x);
89 buffer_putnlflush(buffer_2);
90 return x;
91 }
92
93 #define io_timeout new_io_timeout
94 #define io_timeouted new_io_timeouted
95 #endif
96
97 const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
98
99 #ifdef SUPPORT_CGI
100 int forksock[2];
101 #endif
102
103 #if defined(__OpenBSD__) || defined(__NetBSD__)
104 #define __broken_itojun_v6__
105 #endif
106
107 int virtual_hosts;
108 int transproxy;
109 int directory_index;
110 int logging;
111 int nouploads;
112 int chmoduploads;
113 #ifdef __MINGW32__
114 char origdir[PATH_MAX];
115 #else
116 int64 origdir;
117 #endif
118
119 #ifdef SUPPORT_SMB
120 char workgroup[20]="FNORD";
121 int wglen;
122 char workgroup_utf16[100];
123 int wglen16;
124 #endif
125
carp(const char * routine)126 static void carp(const char* routine) {
127 buffer_putmflush(buffer_2,routine,": ",strerror(errno),"\n");
128 }
129
panic(const char * routine)130 static void panic(const char* routine) {
131 carp(routine);
132 exit(111);
133 }
134
135 unsigned long connections;
136 unsigned long http_connections, https_connections, ftp_connections, smb_connections;
137 unsigned long cps,cps1; /* connections per second */
138 unsigned long rps,rps1; /* requests per second */
139 unsigned long eps,eps1; /* events per second */
140 unsigned long long tin,tin1; /* traffic inbound */
141 unsigned long long tout,tout1; /* traffic outbound */
142
143
144 #ifdef SUPPORT_THREADED_OPEN
145 unsigned int threads;
146 int threadpipe_query[2];
147 int threadpipe_response[2];
148
worker_thread(void * unused)149 void* worker_thread(void* unused) {
150 int src=threadpipe_query[0];
151 int dest=threadpipe_response[1];
152 (void)unused;
153 for (;;) {
154 int fd;
155 struct http_data* x;
156 if (read(src,&fd,sizeof(fd))!=fd) return 0;
157 x=io_getcookie(fd);
158 if (!x) continue;
159 if (fchdir(x->cwd)==-1) continue;
160 x->filefd=open(x->name_of_file_to_open,O_RDONLY);
161 write(dest,&fd,sizeof(fd));
162 }
163 }
164
init_threads(int n)165 void init_threads(int n) {
166 threads=0;
167 if (n<=0) return;
168 if (threads>0) {
169 int i;
170 if (pipe(threadpipe_query)==-1 || pipe(threadpipe_response)==-1) return;
171 for (i=0; i<n; ++i) {
172 pthread_t tmp;
173 pthread_create(&tmp,0,worker_thread,0);
174 pthread_detach(tmp);
175 }
176 threads=n;
177 }
178 }
179 #endif
180
181
182 #if defined(SUPPORT_PROXY) || defined(SUPPORT_CGI)
183 /* You configure a list of regular expressions, and if a request matches
184 * one of them, the request is forwarded to some other IP:port. You can
185 * run another httpd there that can handle CGI, PHP, JSP and whatnot. */
186 struct cgi_proxy* cgis,* last;
187
188 char** _envp;
189
190 /* if port==0 then execute the CGI locally */
191 #endif
192
193 #ifdef SUPPORT_CGI
add_cgi(const char * c)194 static int add_cgi(const char* c) {
195 struct cgi_proxy* x=malloc(sizeof(struct cgi_proxy));
196 if (!x) return -1;
197 byte_zero(x,sizeof(struct cgi_proxy));
198 if (!strcmp(c,"+x"))
199 x->file_executable=1;
200 else if (regcomp(&x->r,c,REG_EXTENDED)) {
201 free(x);
202 return -1;
203 }
204 if (!last)
205 cgis=x;
206 else
207 last->next=x;
208 last=x;
209 return 0;
210 }
211 #endif
212
cleanup(int64 fd)213 void cleanup(int64 fd) {
214 struct http_data* h=io_getcookie(fd);
215 int buddyfd=-1;
216 if (h) {
217 buddyfd=h->buddy;
218
219 if (h->t==HTTPREQUEST
220 #ifdef SUPPORT_FTP
221 || h->t==FTPCONTROL6 || h->t==FTPCONTROL4
222 #endif
223 #ifdef SUPPORT_SMB
224 || h->t==SMBREQUEST
225 #endif
226 #ifdef SUPPORT_HTTPS
227 || h->t==HTTPSREQUEST || h->t==HTTPSACCEPT || h->t==HTTPSPOST
228 #endif
229 ) --connections;
230 if (h->t==HTTPREQUEST
231 #ifdef SUPPORT_PROXY
232 || h->t==HTTPPOST
233 #endif
234 ) --http_connections;
235 #ifdef SUPPORT_FTP
236 if (h->t==FTPCONTROL4 || h->t==FTPCONTROL6) --ftp_connections;
237 #endif
238 #ifdef SUPPORT_SMB
239 if (h->t==SMBREQUEST) --smb_connections;
240 #endif
241 #ifdef SUPPORT_HTTPS
242 if (h->t==HTTPSREQUEST || h->t==HTTPSPOST || h->t==HTTPSACCEPT ||
243 h->t==HTTPSACCEPT_CHECK || h->t==HTTPSRESPONSE) {
244 --https_connections;
245 #ifdef USE_OPENSSL
246 SSL_shutdown(h->ssl);
247 #endif
248 }
249 #endif
250
251 #if defined(SUPPORT_FTP)
252 if (h->t==FTPSLAVE || h->t==FTPACTIVE || h->t==FTPPASSIVE) {
253 if (buddyfd!=-1) {
254 struct http_data* b=io_getcookie(buddyfd);
255 if (b)
256 b->buddy=-1;
257 }
258 buddyfd=-1;
259 }
260 #endif
261 if (h->filefd!=-1) io_close(h->filefd);
262 array_reset(&h->r);
263 iob_reset(&h->iob);
264 #if defined(SUPPORT_FTP) || defined(SUPPORT_SMB)
265 free(h->ftppath);
266 #endif
267 #ifdef SUPPORT_HTTPS
268 #ifdef USE_OPENSSL
269 if (h->ssl) SSL_free(h->ssl);
270 #endif
271 #ifdef USE_POLARSSL
272 if (h->ssldata) {
273 free_tls_ctx(h->ssldata);
274 free(h->ssldata);
275 }
276 #endif
277 #endif
278 #ifdef SUPPORT_SMB
279 close_all_handles(&h->h);
280 #endif
281 free(h);
282 }
283 io_close(fd);
284 if (buddyfd>=0) {
285 h=io_getcookie(buddyfd);
286 if (h) h->buddy=-1;
287 cleanup(buddyfd);
288 }
289 }
290
header_complete(struct http_data * r,int64 sock)291 size_t header_complete(struct http_data* r,int64 sock) {
292 long i;
293 long l=array_bytes(&r->r);
294 const char* c=array_start(&r->r);
295 if (r->t==HTTPREQUEST
296 #ifdef SUPPORT_PROXY
297 || r->t==HTTPPOST
298 #endif
299 #ifdef SUPPORT_HTTPS
300 || r->t==HTTPSREQUEST || r->t==HTTPSPOST
301 #endif
302 )
303 {
304 /* first of all, in case someone is bombarding me with crap, detect
305 * that early so we can drop the connection */
306 if (l>10) {
307 tai6464 tarpit;
308 for (i=0; i<l; ++i) {
309 if (c[i]==' ') goto ok;
310 if (c[i]<'A' || c[i]>'Z') break;
311 }
312 /* detected invalid HTTP request */
313 if (logging) {
314 char buf[100];
315 buffer_puts(buffer_1,"close/not_http_traffic ");
316 buffer_putulong(buffer_1,sock);
317 buffer_putspace(buffer_1);
318 buffer_put(buffer_1,buf,fmt_ip6c(buf,r->peerip));
319 buffer_putnlflush(buffer_1);
320 }
321 io_dontwantread(sock);
322 io_dontwantwrite(sock);
323 --http_connections;
324 changestate(r,PUNISHMENT);
325 tarpit=now;
326 tarpit.sec.x+=10;
327 io_timeout(sock,tarpit);
328 return 0;
329 }
330 ok:
331
332 /* Erdgeist nudged me into optimizing this :-)
333 * I'd be surprised if this optimization has any measurable
334 * advantage, but it sure is impressive */
335 for (i=0; i+1<l; i+=2) {
336 if (c[i+1]=='\n') {
337 if (c[i]=='\n') return i+2;
338 else if (c[i]=='\r' && i+3<l && c[i+2]=='\r' && c[i+3]=='\n')
339 return i+4;
340 --i;
341 } else if (c[i+1]=='\r') {
342 if (i+4<l && c[i+2]=='\n' && c[i+3]=='\r' && c[i+4]=='\n')
343 return i+5;
344 --i;
345 }
346 }
347
348 #ifdef SUPPORT_SMB
349 } else if (r->t==SMBREQUEST) {
350 /* SMB */
351 /* first four bytes are the NetBIOS session;
352 * byte 0: 0 ("session message"),
353 * bytes 1-3: message length (big endian) */
354 uint32 len;
355 if (c[0]!=0) {
356 // printf("can't happen error: netbios byte 0 was not 0!?\n");
357 return 1;
358 }
359 len=uint32_read_big(c) & 0x00ffffff;
360 if (l>=len+4) return len+4;
361 #endif
362 } else {
363 /* FTP */
364 for (i=0; i<l; ++i)
365 if (c[i]=='\n')
366 return i+1;
367 }
368 return 0;
369 }
370
371 static char oom[]="HTTP/1.0 500 internal error\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nout of memory\n";
372
httperror_realm(struct http_data * r,const char * title,const char * message,const char * realm,int nobody)373 void httperror_realm(struct http_data* r,const char* title,const char* message,const char* realm,int nobody) {
374 char* c;
375 if (r->t==HTTPSERVER4 || r->t==HTTPSERVER6 || r->t==HTTPREQUEST
376 #ifdef SUPPORT_HTTPS
377 || r->t==HTTPSSERVER4 || r->t==HTTPSSERVER6
378 || r->t==HTTPSREQUEST || r->t==HTTPSRESPONSE
379 #endif
380 ) {
381 c=r->hdrbuf=(char*)malloc(str_len(message)+str_len(title)+str_len(realm?realm:"")+300);
382 if (!c) {
383 r->hdrbuf=oom;
384 r->hlen=str_len(r->hdrbuf);
385 buffer_putsflush(buffer_1,"error_oom\n");
386 iob_addbuf(&r->iob,r->hdrbuf,r->hlen);
387 } else {
388 c+=fmt_str(c,"HTTP/1.0 ");
389 c+=fmt_str(c,title);
390 c+=fmt_str(c,"\r\nContent-Type: text/html\r\nConnection: ");
391 c+=fmt_str(c,r->keepalive?"keep-alive":"close");
392 c+=fmt_str(c,"\r\nServer: " RELEASE "\r\nContent-Length: ");
393 c+=fmt_ulong(c,str_len(message)+str_len(title)-4+17);
394 if (realm) {
395 c+=fmt_str(c,"\r\nWWW-Authenticate: Basic realm=\"");
396 c+=fmt_str(c,realm);
397 c+=fmt_str(c,"\"");
398 }
399 c+=fmt_str(c,"\r\n\r\n");
400 if (!nobody) {
401 c+=fmt_str(c,"<title>");
402 c+=fmt_str(c,title+4);
403 c+=fmt_str(c,"</title>\n");
404 c+=fmt_str(c,message);
405 c+=fmt_str(c,"\n");
406 }
407 r->hlen=c - r->hdrbuf;
408 iob_addbuf_free(&r->iob,r->hdrbuf,r->hlen);
409 }
410 } else {
411 /* FTP */
412 c=r->hdrbuf=(char*)malloc(str_len(title)+3);
413 c+=fmt_str(c,title);
414 c+=fmt_str(c,"\r\n");
415 r->hlen=c-r->hdrbuf;
416 iob_addbuf_free(&r->iob,r->hdrbuf,r->hlen);
417 }
418 }
419
httperror(struct http_data * r,const char * title,const char * message,int nobody)420 void httperror(struct http_data* r,const char* title,const char* message,int nobody) {
421 httperror_realm(r,title,message,0,nobody);
422 }
423
fmt_2digits(char * dest,int i)424 unsigned int fmt_2digits(char* dest,int i) {
425 dest[0]=(i/10)+'0';
426 dest[1]=(i%10)+'0';
427 return 2;
428 }
429
430
431
432 #if 0
433 _ _ _
434 | |__ | |_| |_ _ __
435 | '_ \| __| __| '_ \
436 | | | | |_| |_| |_) |
437 |_| |_|\__|\__| .__/
438 |_|
439 #endif
440
441 const char* mimetypesfilename;
442
443 char* base;
444
sort_name_a(de * x,de * y)445 int sort_name_a(de* x,de* y) { return (str_diff(base+x->name,base+y->name)); }
sort_name_d(de * x,de * y)446 int sort_name_d(de* x,de* y) { return (str_diff(base+y->name,base+x->name)); }
sort_mtime_a(de * x,de * y)447 int sort_mtime_a(de* x,de* y) { return x->ss.st_mtime-y->ss.st_mtime; }
sort_mtime_d(de * x,de * y)448 int sort_mtime_d(de* x,de* y) { return y->ss.st_mtime-x->ss.st_mtime; }
sort_size_a(de * x,de * y)449 int sort_size_a(de* x,de* y) { return x->ss.st_size-y->ss.st_size; }
sort_size_d(de * x,de * y)450 int sort_size_d(de* x,de* y) { return y->ss.st_size-x->ss.st_size; }
451
452
453
454 #ifndef __MINGW32__
455 static uid_t __uid;
456 static gid_t __gid;
457 static int do_switch_uid;
458
prepare_switch_uid(const char * new_uid)459 static int prepare_switch_uid(const char* new_uid) {
460 uid_t u=0;
461 gid_t g=0;
462 if (new_uid) {
463 if (new_uid[0]>='0' && new_uid[0]<='9') {
464 unsigned long l;
465 const char *c=new_uid+scan_ulong(new_uid,&l);
466 if (*c && *c!=':' && *c!='.') return -1;
467 if ((u=l)!=l) return -1; /* catch overflow */
468 if (*c) {
469 ++c;
470 c=c+scan_ulong(c,&l);
471 if ((g=l)!=l) return -1; /* catch overflow */
472 if (*c) return -1;
473 }
474 } else {
475 struct passwd *p=getpwnam(new_uid);
476 if (!p) return -1;
477 u=p->pw_uid;
478 g=p->pw_gid;
479 }
480 __uid=u;
481 __gid=g;
482 do_switch_uid=1;
483 }
484 return 0;
485 }
486
switch_uid()487 int switch_uid() {
488 if (!do_switch_uid) return 0;
489 #ifdef LIBC_HAS_SETRESUID
490 if (setresgid(__gid,__gid,__gid) ||
491 setgroups(1,&__gid) ||
492 setresuid(__uid,__uid,__uid))
493 #else
494 if (setgid(__gid) ||
495 setgroups(1,&__gid) ||
496 setuid(__uid))
497 #endif
498 {
499 /* if dropping privileges failed with EPERM, we are already running
500 * with reduced privileges. Don't make a fuss about it then. */
501 if (errno==EPERM) return 0;
502 return -1;
503 }
504 return 0;
505 }
506 #endif
507
508 static volatile int fini;
509
sighandler(int sig)510 void sighandler(int sig) {
511 fini=(sig==SIGINT?1:2); /* 2 for SIGHUP */
512 }
513
514
515
is_server_connection(enum conntype t)516 static int is_server_connection(enum conntype t) {
517 return (t==HTTPSERVER6 || t==HTTPSERVER4
518 #ifdef SUPPORT_FTP
519 || t==FTPSERVER6 || t==FTPSERVER4
520 #endif
521 #ifdef SUPPORT_SMB
522 || t==SMBSERVER6 || t==SMBSERVER4
523 #endif
524 #ifdef SUPPORT_HTTPS
525 || t==HTTPSSERVER6 || t==HTTPSSERVER4
526 #endif
527 );
528 }
529
530 #ifdef __broken_itojun_v6__
531 #warning "working around idiotic openbse ipv6 stupidity - please kick itojun for this!"
532 int s4; /* ipv4 http socket */
533 #ifdef SUPPORT_FTP
534 int f4; /* ipv4 ftp socket */
535 #endif
536 #ifdef SUPPORT_HTTPS
537 int httpss4; /* ipv4 https socket */
538 #endif
539 #endif
540
541 #ifdef SUPPORT_HTTPS
542 char* sshd;
543 unsigned long ssh_timeout;
544 #endif
545
546 int limit_to_lan;
547
accept_server_connection(int64 i,struct http_data * H,unsigned long ftptimeout_secs,tai6464 nextftp)548 static void accept_server_connection(int64 i,struct http_data* H,unsigned long ftptimeout_secs,tai6464 nextftp) {
549 /* This is an FTP or HTTP(S) or SMB server connection.
550 * This read event means that someone connected to us.
551 * accept() the connection, establish connection type from
552 * server connection type, and put the new connection into the
553 * state table */
554 char ip[16];
555 uint16 port;
556 uint32 scope_id;
557 int n;
558
559 while (1) {
560 int punk;
561 #ifdef __broken_itojun_v6__
562 if (H->t==HTTPSERVER4 || H->t==FTPSERVER4
563 #ifdef SUPPORT_SMB
564 || H->t==SMBSERVER4
565 #endif
566 #ifdef SUPPORT_HTTPS
567 || H->t==HTTPSSERVER4
568 #endif
569 ) {
570 byte_copy(ip,12,V4mappedprefix);
571 scope_id=0;
572 n=socket_accept4(i,ip+12,&port);
573 } else
574 #endif
575 n=socket_accept6(i,ip,&port,&scope_id);
576 if (n==-1) break;
577 punk=new_request_from_ip(ip,now.sec.x-4611686018427387914ULL)==1;
578 ++cps1;
579 ++connections;
580 if (logging) {
581 char buf[IP6_FMT];
582
583 buffer_puts(buffer_1,punk?(timeout_secs?"dos_tarpit ":"dos_drop "):"accept ");
584 buffer_putulong(buffer_1,n);
585 buffer_puts(buffer_1," ");
586 buffer_put(buffer_1,buf,fmt_ip6c(buf,ip));
587 buffer_puts(buffer_1," ");
588 buffer_putulong(buffer_1,port);
589 buffer_puts(buffer_1," ");
590 buffer_putulong(buffer_1,connections-1);
591 buffer_puts(buffer_1," ");
592 {
593 const char* service;
594 switch (H->t) {
595 case HTTPSERVER4:
596 case HTTPSERVER6: service="http"; break;
597 #ifdef SUPPORT_HTTPS
598 case HTTPSSERVER4:
599 case HTTPSSERVER6: service="https"; break;
600 #endif
601 #ifdef SUPPORT_FTP
602 case FTPSERVER4:
603 case FTPSERVER6: service="ftp"; break;
604 #endif
605 #ifdef SUPPORT_SMB
606 case SMBSERVER4:
607 case SMBSERVER6: service="smb"; break;
608 #endif
609 default: service="unk";
610 }
611 buffer_puts(buffer_1,service);
612 }
613 buffer_putnlflush(buffer_1);
614 }
615 if (limit_to_lan) {
616 int passed;
617 /* if the -L option is given, only accept connections from local
618 * or reserved IP ranges */
619 if (byte_equal(ip,12,V4mappedprefix)) {
620 unsigned char* ip4=(unsigned char*)ip+12;
621 passed = ip4[0]==127 || /* 127.0.0.1/8 */
622 ip4[0]==10 || /* RFC1918: 10.0.0.0/8 */
623 (ip4[0]==192 && ip4[1]==168) || /* RFC1918: 192.168.0.0/16 */
624 (ip4[0]==172 && ip4[1]>=16 && ip4[1]<=31) || /* RFC1918: 172.16.0.0/12 */
625 (ip4[0]==169 && ip4[1]==254 && ip4[2]!=0 && ip4[2]!=255); /* RFC 5735: 169.254.0.0/16 */
626 } else { /* IPv6 */
627 unsigned char* ip6=(unsigned char*)ip;
628 passed = byte_equal(ip6,16,V6loopback) || /* ::1 */
629 (ip6[0]==0xfc && (ip6[1]&0xfe)==0) || /* RF4193 ULA fc00::/7 */
630 (ip6[0]==0xfe && (ip6[1]&0xfc)==0xc0) || /* deprecated site-local */
631 (ip6[0]==0xfe && (ip6[1]&0xfc)==0x80); /* RFC5735 link-local */
632 }
633 if (!passed) {
634 timeout_secs=0;
635 punk=1;
636 if (logging) {
637 buffer_puts(buffer_1,"close/outside_lan_drop ");
638 buffer_putulong(buffer_1,n);
639 buffer_putnlflush(buffer_1);
640 }
641 }
642 }
643 if (punk && !timeout_secs) {
644 io_close(n);
645 continue;
646 }
647 #ifdef SUPPORT_SERVERSTATUS
648 if (H->t==HTTPSERVER4 || H->t==HTTPSERVER6) ++http_connections;
649 #ifdef SUPPORT_HTTPS
650 if (H->t==HTTPSSERVER4 || H->t==HTTPSSERVER6) ++https_connections;
651 #endif
652 #ifdef SUPPORT_FTP
653 if (H->t==FTPSERVER4 || H->t==FTPSERVER6) ++ftp_connections;
654 #endif
655 #ifdef SUPPORT_SMB
656 if (H->t==SMBSERVER4 || H->t==SMBSERVER6) ++smb_connections;
657 #endif
658 #endif
659
660 #ifdef TCP_NODELAY
661 {
662 int i=1;
663 setsockopt(n,IPPROTO_TCP,TCP_NODELAY,&i,sizeof(i));
664 }
665 #else
666 #warning TCP_NODELAY not defined
667 #endif
668
669 #ifdef HAVE_IO_FD_FLAGS
670 if (io_fd_flags(n,IO_FD_CANWRITE|IO_FD_NONBLOCK))
671 #else
672 if (io_fd_canwrite(n))
673 #endif
674 {
675 struct http_data* h;
676 h=(struct http_data*)malloc(sizeof(struct http_data));
677 if (h) {
678 io_nonblock(n);
679 if (!punk) {
680 if (H->t==HTTPSERVER6 || H->t==HTTPSERVER4
681 #ifdef SUPPORT_SMB
682 || H->t==SMBSERVER6 || H->t==SMBSERVER4
683 #endif
684 #ifdef SUPPORT_HTTPS
685 || H->t==HTTPSSERVER6 || H->t==HTTPSSERVER4
686 #endif
687 )
688 io_wantread(n);
689 else
690 io_wantwrite(n);
691 }
692 byte_zero(h,sizeof(struct http_data));
693 #ifdef STATE_DEBUG
694 h->myfd=n;
695 #endif
696 #ifdef __broken_itojun_v6__
697 if (i==s4 || i==f4) {
698 byte_copy(h->myip,12,V4mappedprefix);
699 socket_local4(n,h->myip+12,&h->myport);
700 } else
701 socket_local6(n,h->myip,&h->myport,0);
702 #else
703 socket_local6(n,h->myip,&h->myport,0);
704 #endif
705 byte_copy(h->peerip,16,ip);
706 h->peerport=port;
707 h->myscope_id=scope_id;
708 if (punk) {
709 changestate(h,PUNISHMENT);
710 io_timeout(n,next);
711 } else if (H->t==HTTPSERVER4 || H->t==HTTPSERVER6) {
712 changestate(h,HTTPREQUEST);
713 if (timeout_secs)
714 io_timeout(n,next);
715 #ifdef SUPPORT_HTTPS
716 } else if (H->t==HTTPSSERVER4 || H->t==HTTPSSERVER6) {
717 #ifdef __MINGW32__
718 // printf("chdir(\"%s\") -> %d\n",origdir,chdir(origdir));
719 // chdir(origdir);
720 #else
721 fchdir(origdir);
722 #endif
723 #ifdef USE_OPENSSL
724 if (init_serverside_tls(&h->ssl,n))
725 #elif defined(USE_POLARSSL)
726 h->ssldata=malloc(sizeof(*h->ssldata));
727 if (!h->ssldata || init_serverside_tls(h->ssldata,n))
728 #endif
729 {
730 if (logging) {
731 char a[FMT_ULONG];
732 a[fmt_ulong(a,n)]=0;
733 buffer_putmflush(buffer_1,"ssl_setup_failed ",a," ",strerror(errno),"\nclose/readerr ",a,"\n");
734 }
735 cleanup(n);
736 continue;
737 }
738
739 changestate(h,HTTPSACCEPT_CHECK);
740 if (timeout_secs)
741 io_timeout(n,nextftp);
742 #endif
743 #ifdef SUPPORT_SMB
744 } else if (H->t==SMBSERVER4 || H->t==SMBSERVER6) {
745 changestate(h,SMBREQUEST);
746 if (timeout_secs)
747 io_timeout(n,next);
748 #endif
749 #ifdef SUPPORT_FTP
750 } else {
751 if (H->t==FTPSERVER6)
752 changestate(h,FTPCONTROL6);
753 else
754 changestate(h,FTPCONTROL4);
755 iob_addbuf(&h->iob,"220 Hi there!\r\n",15);
756 h->keepalive=1;
757 if (ftptimeout_secs)
758 io_timeout(n,nextftp);
759 #endif
760 }
761 h->buddy=-1;
762 h->filefd=-1;
763 io_setcookie(n,h);
764 } else {
765 buffer_puts(buffer_1,"close/malloc_failed ");
766 buffer_putulong(buffer_1,n);
767 buffer_putnlflush(buffer_1);
768 io_close(n);
769 }
770 } else {
771 buffer_puts(buffer_1,"close/io_fd_canwrite_failed ");
772 buffer_putulong(buffer_1,n);
773 buffer_putnlflush(buffer_1);
774 io_close(n);
775 }
776 #ifdef SUPPORT_MULTIPROC
777 if (instances>1) break;
778 #endif
779 }
780 if (errno==EAGAIN)
781 io_eagain_read(i);
782 else
783 #ifdef __broken_itojun_v6__
784 carp(H->t==HTTPSERVER4||H->t==FTPSERVER4?"socket_accept4":"socket_accept6");
785 #else
786 if (errno==EINVAL) {
787 static int64 lasteinval;
788 if (lasteinval!=i) {
789 lasteinval=i;
790 carp("socket_accept6");
791 }
792 }
793 #endif
794 }
795
796 #ifdef SUPPORT_HTTPS
797
handle_ssl_error_code(int sock,int code,int reading)798 int handle_ssl_error_code(int sock,int code,int reading) {
799 #ifdef USE_POLARSSL
800 char errorbuf[256];
801 #endif
802
803 // printf("handle_ssl_error_code(sock %d,code %d,reading %d)\n",sock,code,reading);
804 switch (code) {
805 #ifdef USE_OPENSSL
806 case SSL_ERROR_WANT_READ:
807 io_eagain_read(sock);
808 io_wantread(sock);
809 io_dontwantwrite(sock);
810 return 0;
811 case SSL_ERROR_WANT_WRITE:
812 io_eagain_write(sock);
813 io_wantwrite(sock);
814 io_dontwantread(sock);
815 return 0;
816 #elif defined(USE_POLARSSL)
817 case MBEDTLS_ERR_SSL_WANT_READ:
818 io_eagain_read(sock);
819 io_wantread(sock);
820 io_dontwantwrite(sock);
821 return 0;
822 case MBEDTLS_ERR_SSL_WANT_WRITE:
823 io_eagain_write(sock);
824 io_wantwrite(sock);
825 io_dontwantread(sock);
826 return 0;
827 #endif
828 #ifdef USE_OPENSSL
829 case SSL_ERROR_SYSCALL:
830 #elif defined(USE_POLARSSL)
831 case MBEDTLS_ERR_NET_RECV_FAILED:
832 case MBEDTLS_ERR_NET_SEND_FAILED:
833 case MBEDTLS_ERR_NET_CONN_RESET:
834 errno=ECONNRESET;
835 #endif
836 // we already signal the error up and upsteam will then write an
837 // error message
838 return -1;
839 default:
840 if (logging) {
841 buffer_puts(buffer_1,"ssl_protocol_error ");
842 buffer_putulong(buffer_1,sock);
843 #ifdef USE_POLARSSL
844 mbedtls_strerror(code,errorbuf,sizeof(errorbuf));
845 buffer_putm(buffer_1," ",errorbuf);
846 #endif
847 buffer_puts(buffer_1,"\nclose/readerr ");
848 buffer_putulong(buffer_1,sock);
849 buffer_putnlflush(buffer_1);
850 }
851 errno=EPROTO;
852 return -1;
853 }
854 }
855
do_sslaccept(int sock,struct http_data * h,int reading)856 void do_sslaccept(int sock,struct http_data* h,int reading) {
857 int r;
858 if (h->t == HTTPSACCEPT_CHECK) {
859 unsigned char buf[10];
860 changestate(h,HTTPSACCEPT);
861 /* now, try to peek into the buffer, and see if it looks like an SSL
862 * handshake */
863 r=recv(sock,buf,sizeof(buf),MSG_PEEK);
864 if (r>5) {
865 if (sshd && buf[0]=='S' && buf[1]=='S' && buf[2]=='H') {
866 if (logging) {
867 char numbuf[FMT_ULONG];
868 numbuf[fmt_ulong(numbuf,sock)]=0;
869 buffer_putmflush(buffer_1,"close/ssh_handshake ",numbuf,"\n");
870 }
871 {
872 uint32 a=0;
873 write(forksock[0],&a,4);
874 io_passfd(forksock[0],sock);
875 }
876 --https_connections;
877 changestate(h,PUNISHMENT);
878 cleanup(sock);
879 return;
880 }
881 /* Apparently the packets look radically different depending on
882 * whether it's TLS or SSLv2. GREAT! */
883 /* first packet must be handshake */
884 if (buf[0]!=0x16 || /* content type: handshake */
885 buf[1]>3 || /* version major */
886 buf[2]>3 || /* version minor */
887 buf[3]>2) { /* length > 0x200 */
888 if (buf[0]!=0x80 ||
889 buf[2]!=1 || /* Client Hello */
890 buf[3]>3 || /* version major */
891 buf[4]>3) { /* version minor */
892 tai6464 tarpit;
893 /* this does not look like an SSL packet. */
894 if (logging) {
895 char tmp[100];
896 buffer_puts(buffer_1,"close/not_ssl_traffic ");
897 buffer_putulong(buffer_1,sock);
898 buffer_putspace(buffer_1);
899 buffer_put(buffer_1,tmp,fmt_ip6c(tmp,h->peerip));
900 buffer_putnlflush(buffer_1);
901 }
902 io_dontwantread(sock);
903 io_dontwantwrite(sock);
904 --https_connections;
905 changestate(h,PUNISHMENT);
906 tarpit=now;
907 tarpit.sec.x+=10;
908 io_timeout(sock,tarpit);
909 return;
910 }
911 }
912 }
913 }
914
915 #ifdef USE_OPENSSL
916 // printf("got SSL traffic on fd %d, calling SSL_accept\n",sock); fflush(stdout);
917 r=SSL_get_error(h->ssl,SSL_accept(h->ssl));
918 // printf("SSL_accept returned %d\n",r); fflush(stdout);
919 // printf("do_sslaccept -> %d\n",r);
920 if (r==SSL_ERROR_NONE)
921 #elif defined(USE_POLARSSL)
922 r=mbedtls_ssl_handshake(&h->ssldata->ssl);
923 if (r==0)
924 #endif
925 {
926 #if 0
927 h->writefail=1;
928 #endif
929 changestate(h,HTTPSREQUEST);
930 if (logging) {
931 buffer_puts(buffer_1,"ssl_handshake_ok ");
932 buffer_putulong(buffer_1,sock);
933 buffer_putnlflush(buffer_1);
934 }
935 return;
936 } else
937 if (handle_ssl_error_code(sock,r,reading)==-1)
938 cleanup(sock);
939 }
940 #endif
941
handle_incoming_data(int64 i,struct http_data * h)942 static void handle_incoming_data(int64 i,struct http_data* h) {
943 int l;
944 if ((l=header_complete(h,i))) {
945 /* at this point we saw a \r\n\r\n */
946 long alen;
947 pipeline:
948 /* The h->mimetype reference is here so that we don't count both the HTTP
949 * connection and the first request on it as a dos attack. */
950 if (h->mimetype && new_request_from_ip(h->peerip,now.sec.x-4611686018427387914ULL)==1) {
951 changestate(h,PUNISHMENT);
952 if (logging) {
953 char buf[IP6_FMT];
954 char n[FMT_LONG];
955 n[fmt_ulong(n,i)]=0;
956 buf[fmt_ip6c(buf,h->peerip)]=0;
957
958 buffer_putmflush(buffer_1,"dos_tarpit2 ",n," ",buf,"\n");
959 }
960 if (timeout_secs) {
961 io_dontwantread(i);
962 io_dontwantwrite(i);
963 } else
964 /* if we don't have timeouts enabled, just drop the connection */
965 cleanup(i);
966 return;
967 }
968 #ifdef SUPPORT_HTTPS
969 if (h->t==HTTPREQUEST || h->t==HTTPSREQUEST) {
970 httpresponse(h,i,l);
971 if (h->t == HTTPSREQUEST) changestate(h,HTTPSRESPONSE);
972 }
973 #else
974 if (h->t==HTTPREQUEST)
975 httpresponse(h,i,l);
976 #endif
977 #ifdef SUPPORT_SMB
978 else if (h->t==SMBREQUEST) {
979 if (smbresponse(h,i)==-1) {
980 cleanup(i);
981 return;
982 }
983 }
984 #endif
985 #ifdef SUPPORT_FTP
986 else
987 ftpresponse(h,i);
988 #endif
989 #ifdef SUPPORT_PROXY
990 if (h->t != HTTPPOST
991 #ifdef SUPPORT_HTTPS
992 && h->t != HTTPSPOST
993 #endif
994 ) {
995 #endif
996 if (l < (alen=array_bytes(&h->r))) {
997 char* c=array_start(&h->r);
998
999 #if 0
1000 printf("continuation: consumed %lu bytes from buffer (%lu still there)\n",
1001 (unsigned long)l,
1002 (unsigned long)(alen-l));
1003 #endif
1004 byte_copy(c,alen-l,c+l);
1005 array_truncate(&h->r,1,alen-l);
1006 l=header_complete(h,i);
1007
1008 #if 0
1009 write(1,"\n\n",2);
1010 write(1,array_start(&h->r),array_bytes(&h->r));
1011 write(1,"\n\n",2);
1012 #endif
1013
1014 if (l) {
1015 /* this breaks SMB: */
1016 // if (h->r.initialized) --h->r.initialized;
1017 goto pipeline;
1018 }
1019 } else
1020 array_reset(&h->r);
1021 #ifdef SUPPORT_PROXY
1022 }
1023 #endif
1024 } else
1025 io_wantread(i);
1026 }
1027
handle_read_misc(int64 i,struct http_data * h,unsigned long ftptimeout_secs,tai6464 nextftp)1028 static void handle_read_misc(int64 i,struct http_data* h,unsigned long ftptimeout_secs,tai6464 nextftp) {
1029 /* This is a TCP client connection waiting for input, i.e.
1030 * - an HTTP connection waiting for a HTTP request, or
1031 * - an FTP connection waiting for a command, or
1032 * - an FTP upload waiting for more data, or
1033 * - an SMB connection waiting for the next command */
1034 char buf[8192];
1035 int l;
1036 #ifdef SUPPORT_HTTPS
1037 assert(h->t != HTTPSRESPONSE);
1038 if (h->t == HTTPSREQUEST) {
1039 // printf("calling SSL_read on fd %d\n",(int)i); fflush(stdout);
1040 #ifdef USE_OPENSSL
1041 l=SSL_read(h->ssl,buf,sizeof(buf));
1042 #elif defined(USE_POLARSSL)
1043 l=mbedtls_ssl_read(&h->ssldata->ssl,(unsigned char*)buf,sizeof(buf));
1044 #else
1045 #error fixme
1046 #endif
1047 // printf("SSL_read(sock %d,buf %p,n %d) -> %d\n",(int)i,buf,(int)sizeof(buf),(int)l); fflush(stdout);
1048 #ifdef USE_OPENSSL
1049 if (l==-1) {
1050 l=SSL_get_error(h->ssl,l);
1051 // printf("SSL_get_error -> %d (SSL_ERROR_WANT_READ=%d, SSL_ERROR_WANT_WRITE=%d)\n",l,SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE); fflush(stdout);
1052 if (l==SSL_ERROR_WANT_READ || l==SSL_ERROR_WANT_WRITE) {
1053 #elif defined(USE_POLARSSL)
1054 if (l<0) {
1055 if (l==MBEDTLS_ERR_SSL_WANT_READ || l==MBEDTLS_ERR_SSL_WANT_WRITE) {
1056 #else
1057 #error fixme
1058 #endif
1059 // printf(" error %d %s\n",l,ERR_error_string(l,0));
1060 #ifdef USE_OPENSSL
1061 if (l==SSL_ERROR_WANT_READ) io_eagain_read(i);
1062 else if (l==SSL_ERROR_WANT_WRITE) io_eagain_write(i);
1063 #elif defined(USE_POLARSSL)
1064 if (l==MBEDTLS_ERR_SSL_WANT_READ) io_eagain_read(i);
1065 else if (l==MBEDTLS_ERR_SSL_WANT_WRITE) io_eagain_write(i);
1066 #else
1067 #error fixme
1068 #endif
1069 if (handle_ssl_error_code(i,l,1)==-1) {
1070 cleanup(i);
1071 return;
1072 }
1073 l=-1;
1074 #ifdef USE_POLARSSL
1075 } else if (l==MBEDTLS_ERR_NET_RECV_FAILED) {
1076 l=0;
1077 #endif
1078 } else {
1079 printf("got polarssl error %x\n",l);
1080 errno=ECONNRESET;
1081 l=-3;
1082 }
1083 }
1084 } else
1085 #endif
1086 l=io_tryread(i,buf,sizeof buf);
1087 if (l==-3) {
1088 #ifdef SUPPORT_FTP
1089 ioerror:
1090 #endif
1091 if (logging) {
1092 char a[FMT_ULONG];
1093 a[fmt_ulong(a,i)]=0;
1094 buffer_putmflush(buffer_1,"io_error ",a," ",strerror(errno),"\nclose/readerr ",a,"\n");
1095 }
1096 cleanup(i);
1097 } else if (l==0) {
1098 if (logging) {
1099 buffer_puts(buffer_1,"close/read0 ");
1100 buffer_putulong(buffer_1,i);
1101 buffer_putnlflush(buffer_1);
1102 }
1103 #ifdef SUPPORT_FTP
1104 if (h->t==FTPSLAVE) {
1105 /* This is an FTP upload, it just finished. */
1106 struct http_data* b=io_getcookie(h->buddy);
1107 assert(b);
1108 b->buddy=-1;
1109 iob_reset(&b->iob);
1110 iob_adds(&b->iob,"226 Got it.\r\n");
1111 io_dontwantread(h->buddy);
1112 io_wantwrite(h->buddy);
1113 if (chmoduploads)
1114 fchmod(h->filefd,0644);
1115 if (logging) {
1116 struct stat ss;
1117 if (fstat(h->filefd,&ss)==0) {
1118 char a[FMT_ULONG];
1119 char b[FMT_ULONG];
1120 a[fmt_ulong(a,i)]=0;
1121 b[fmt_ulong(b,ss.st_size)]=0;
1122 buffer_putmflush(buffer_1,"received ",a," ",b,"\n");
1123 }
1124 }
1125 }
1126 #endif
1127 #ifdef SUPPORT_HTTPS
1128 if (h->t==HTTPSPOST || h->t==HTTPSRESPONSE || h->t==HTTPSREQUEST) {
1129 #ifdef USE_OPENSSL
1130 SSL_shutdown(h->ssl);
1131 #endif
1132 }
1133 #endif
1134 cleanup(i);
1135 } else if (l>0) {
1136 /* successfully read some data (l bytes) */
1137 h->received+=l;
1138 tin1+=l;
1139 #ifdef SUPPORT_FTP
1140 if (h->t==FTPCONTROL4 || h->t==FTPCONTROL6) {
1141 if (ftptimeout_secs)
1142 io_timeout(i,nextftp);
1143 } else {
1144 if (timeout_secs)
1145 io_timeout(i,next);
1146 }
1147
1148 if (h->t==FTPSLAVE) {
1149 /* receive an upload */
1150 if (ftptimeout_secs)
1151 io_timeout(h->buddy,nextftp);
1152 if (write(h->filefd,buf,l)!=l)
1153 goto ioerror;
1154 } else
1155 #endif
1156 {
1157 /* received a request */
1158 // printf("previous size: %lu, adding %lu bytes.\n",(unsigned long)array_bytes(&h->r),(unsigned long)l);
1159 array_catb(&h->r,buf,l);
1160 if (array_failed(&h->r)) {
1161 httperror(h,"500 Server Error","request too long.",0);
1162 emerge:
1163 io_dontwantread(i);
1164 io_wantwrite(i);
1165 } else if (array_bytes(&h->r)>MAX_HEADER_SIZE) {
1166 httperror(h,"500 request too long","You sent too much header data",0);
1167 array_reset(&h->r);
1168 goto emerge;
1169 } else
1170 handle_incoming_data(i,h);
1171 }
1172 }
1173 }
1174
1175 #ifdef SUPPORT_HTTPS
1176 int64 https_write_callback(int64 sock,const void* buf,uint64 n) {
1177 int l;
1178 struct http_data* H=io_getcookie(sock);
1179 if (!H) return -3;
1180
1181 #if 0
1182 H->writefail=!H->writefail;
1183 if (H->writefail) { errno=EAGAIN; return -1; }
1184 #endif
1185 if (n>65536) n=65536;
1186 #ifdef USE_OPENSSL
1187 l=SSL_write(H->ssl,buf,n);
1188 // fprintf(stderr,"SSL_write(\"%.*s\",%u) -> %d\n",n>16?16:(int)n,buf,(unsigned int)n,l);
1189 if (l<0) {
1190 l=SSL_get_error(H->ssl,l);
1191 #elif defined(USE_POLARSSL)
1192 l=mbedtls_ssl_write(&H->ssldata->ssl,buf,n);
1193 if (l<0) {
1194 #endif
1195 if (handle_ssl_error_code(sock,l,0)==-1) {
1196 // cleanup(sock);
1197 return -3;
1198 }
1199 #ifdef USE_OPENSSL
1200 if (l==SSL_ERROR_WANT_READ || l==SSL_ERROR_WANT_WRITE) {
1201 #elif defined(USE_POLARSSL)
1202 if (l==MBEDTLS_ERR_SSL_WANT_READ || l==MBEDTLS_ERR_SSL_WANT_WRITE) {
1203 #endif
1204 l=-1; errno=EAGAIN;
1205 } else
1206 l=-3;
1207 }
1208 return l;
1209 }
1210 #endif
1211
1212 /* call iob_send and handle errors;
1213 * if keep-alive is on, detect HTTP pipelining and return 1 if there is
1214 * more data left in h->r, otherwise return 0 */
1215 static int handle_write_misc(int64 i,struct http_data* h,uint64 prefetchquantum) {
1216 int64 r;
1217 #ifdef SUPPORT_HTTPS
1218 assert(h->t != HTTPSREQUEST);
1219 if (h->t == HTTPSRESPONSE)
1220 r=iob_write(i,&h->iob,https_write_callback);
1221 else
1222 #endif
1223 r=iob_send(i,&h->iob);
1224 if (r==-1)
1225 io_eagain_write(i);
1226 else if (r<=0) {
1227 if (r==-3) {
1228 if (logging) {
1229 char a[FMT_ULONG];
1230 char r[FMT_ULONG];
1231 char s[FMT_ULONG];
1232 a[fmt_ulong(a,i)]=0;
1233 r[fmt_ulonglong(r,h->received)]=0;
1234 s[fmt_ulonglong(s,h->sent)]=0;
1235 buffer_putmflush(buffer_1,"socket_error ",a," ",strerror(errno),"\nclose/writefail ",a," ",r," ",s,"\n");
1236 }
1237 #ifdef SUPPORT_FTP
1238 if (h->t==FTPSLAVE || h->t==FTPACTIVE) {
1239 struct http_data* b=io_getcookie(h->buddy);
1240 if (b) {
1241 b->buddy=-1;
1242 iob_reset(&b->iob);
1243 iob_adds(&b->iob,"554 socket error.\r\n");
1244 io_wantwrite(h->buddy);
1245 } else {
1246 /* Apparently the main control connection already died.
1247 * Nothing more to do here except clean up. */
1248 }
1249 }
1250 #endif
1251 cleanup(i);
1252 } else { /* returned 0, i.e. we wrote it all */
1253 wroteitall:
1254 #ifdef SUPPORT_HTTPS
1255 if (h->t == HTTPSRESPONSE) h->t = HTTPSREQUEST;
1256 #endif
1257 #ifdef SUPPORT_PROXY
1258 #ifdef SUPPORT_HTTPS
1259 if ((h->t == HTTPREQUEST || h->t == HTTPSREQUEST) && h->buddy!=-1)
1260 #else
1261 if (h->t == HTTPREQUEST && h->buddy!=-1)
1262 #endif
1263 {
1264 io_dontwantwrite(i);
1265 io_wantread(h->buddy);
1266 return 0;
1267 }
1268 #endif
1269 if (logging && (h->t == HTTPREQUEST
1270 #ifdef SUPPORT_HTTPS
1271 || h->t == HTTPSREQUEST
1272 #endif
1273 )) {
1274 buffer_puts(buffer_1,"request_done ");
1275 buffer_putulong(buffer_1,i);
1276 buffer_puts(buffer_1," ");
1277 buffer_putulonglong(buffer_1,h->received);
1278 buffer_puts(buffer_1," ");
1279 buffer_putulonglong(buffer_1,h->sent);
1280 buffer_putnlflush(buffer_1);
1281 h->received=h->sent=0;
1282 }
1283 // if (array_bytes(&h->r)>0 && h->r.p[h->r.initialized-1]==0) --h->r.initialized;
1284 iob_reset(&h->iob);
1285 h->hdrbuf=0;
1286 if (h->keepalive) {
1287 if (array_bytes(&h->r)>0)
1288 return 1;
1289 // iob_reset(&h->iob);
1290 io_dontwantwrite(i);
1291 io_wantread(i);
1292 } else {
1293 if (logging) {
1294 buffer_puts(buffer_1,"close/reqdone ");
1295 buffer_putulong(buffer_1,i);
1296 buffer_putnlflush(buffer_1);
1297 }
1298 #ifdef SUPPORT_FTP
1299 if (h->t==FTPSLAVE) {
1300 struct http_data* b=io_getcookie(h->buddy);
1301 if (b) {
1302 b->buddy=-1;
1303 // iob_reset(&b->iob);
1304 iob_adds(&b->iob,"226 Done.\r\n");
1305 io_dontwantread(h->buddy);
1306 io_wantwrite(h->buddy);
1307 } else
1308 buffer_putsflush(buffer_2,"ARGH: no cookie or no buddy for FTP slave!\n");
1309 }
1310 #endif
1311 cleanup(i);
1312 }
1313 }
1314 } else {
1315 h->sent+=r;
1316 tout1+=r;
1317 /* write OK, now would be a good time to do some prefetching */
1318 h->sent_until+=r;
1319 if (prefetchquantum) {
1320 if (h->prefetched_until<h->sent_until || h->prefetched_until+prefetchquantum<h->sent_until) {
1321 if (prefetchquantum) iob_prefetch(&h->iob,2*prefetchquantum);
1322 h->prefetched_until+=2*prefetchquantum;
1323 }
1324 }
1325 if (iob_bytesleft(&h->iob)==0) /* optimization, not strictly necessary */
1326 goto wroteitall;
1327 }
1328 return 0;
1329 }
1330
1331 static void prepare_listen(int s,void* whatever) {
1332 if (s!=-1) {
1333 #ifdef HAVE_IO_FD_FLAGS
1334 if (!io_fd_flags(s,IO_FD_NONBLOCK))
1335 #else
1336 if (!io_fd(s))
1337 #endif
1338 panic("io_fd");
1339 io_setcookie(s,whatever);
1340 io_wantread(s);
1341 }
1342 }
1343
1344 #ifdef SUPPORT_BITTORRENT
1345 int handle_torrent_request(int64 sock,struct http_data* h) {
1346 /* http://wiki.theory.org/BitTorrentSpecification#Tracker_HTTP.2FHTTPS_Protocol */
1347 /* http://www.bittorrent.org/protocol.html */
1348 char* req=array_start(&h->r); /* "GET /announce?info_hash=%c3%f4%31%0e%aa%ec%ae%3d%84%c1%63%70%a2%36%67%6b%24%99%b6%e1&peer_id=-TR0006-u0u5j57kcmm4&port=6887&uploaded=0&downloaded=0&left=243269632&compact=1&numwant=50&key=njyytouhv5fymdafkhzi&event=started\r\n" */
1349 char* t=strchr(req,'\n');
1350 char* s=strchr(req,'?');
1351 if (s && t && s<t) {
1352 if (t[-1]=='\r') --t;
1353 } else
1354 httperror(h,"500 invalid bittorrent request","Invalid BitTorrent request",*req=='H');
1355 return 0;
1356 }
1357 #endif
1358
1359 /* Attempt to enable TCP fast open (linux only for now).
1360 * This means that the client sends the first bytes of the HTTP request
1361 * with the third packet of the TCP handshake, instead of sending a
1362 * useless ACK there. I'm not sure why we are expected to switch this
1363 * on server-side, but hey, we'll do what we have to.
1364 * This is only useful for protocols where the client sends data first,
1365 * i.e. not for FTP and not for SSL */
1366 #ifndef HAVE_SOCKET_FASTOPEN
1367 static void socket_fastopen(int sock) {
1368 #ifdef TCP_FASTOPEN
1369 setsockopt(sock,SOL_TCP,TCP_FASTOPEN,(int[]){ 5 }, sizeof(int));
1370 #endif
1371 }
1372 #endif
1373
1374 /* Attempt to turn off quick ack mode (linux only for now).
1375 * This means that the server won't ACK incoming data immediately
1376 * because it knows we will be replying to it soon anyway and can
1377 * drive-by ACK their stuff then.
1378 * This is useful for all non-interactive protocols. */
1379 static void quickackoff(int sock) {
1380 #ifdef HAVE_SOCKET_FASTOPEN
1381 socket_quickack(sock,0);
1382 #else
1383 #ifdef TCP_QUICKACK
1384 setsockopt(sock,SOL_TCP,TCP_QUICKACK,(int[]){ 0 }, sizeof(int));
1385 #endif
1386 #endif
1387 }
1388
1389 int main(int argc,char* argv[],char* envp[]) {
1390 int s; /* http socket */
1391 int f=-1; /* ftp socket */
1392 #ifdef SUPPORT_SMB
1393 int smbs=-1; /* smb socket */
1394 enum conntype sct=SMBSERVER6;
1395 #endif
1396 int doftp=0; /* -1 = don't, 0 = try, but don't fail if not working, 1 = do */
1397 int dohttp=0; /* -1 = don't, 0 = try, but don't fail if not working, 1 = do */
1398 int dosmb=0;
1399 enum { HTTP, FTP, SMB, HTTPS } lastopt=HTTP;
1400 enum conntype ct=HTTPSERVER6; /* used as cookie to recognize server connections */
1401 #ifdef SUPPORT_FTP
1402 enum conntype fct=FTPSERVER6; /* dito */
1403 #endif
1404 #ifdef SUPPORT_HTTPS
1405 int httpss=-1; /* https socket */
1406 enum conntype httpsct=HTTPSSERVER6;
1407 int dohttps=0;
1408 #endif
1409 #ifdef __broken_itojun_v6__
1410 enum conntype ct4=HTTPSERVER4;
1411 #ifdef SUPPORT_FTP
1412 enum conntype fct4=FTPSERVER4;
1413 #endif
1414 #ifdef SUPPORT_HTTPS
1415 enum conntype httpsct4=HTTPSSERVER4;
1416 #endif
1417 #endif
1418 uint32 scope_id;
1419 char ip[16];
1420 uint16 port,fport,sport;
1421 #ifdef SUPPORT_HTTPS
1422 uint16 httpsport=0;
1423 static tai6464 nexthttps;
1424 #endif
1425 static tai6464 last,tick,nextftp;
1426 unsigned long ftptimeout_secs=600;
1427 char* new_uid=0;
1428 char* chroot_to=0;
1429 unsigned long long prefetchquantum=0;
1430 #ifdef SUPPORT_MULTIPROC
1431 pid_t* Instances;
1432 #endif
1433
1434 initdircache();
1435
1436 #if defined(DEBUG_EVENTS) || defined(SMDEBUG) || defined(STATE_DEBUG)
1437 #ifdef __dietlibc__
1438 fflush(stdout);
1439 #endif
1440 #endif
1441
1442 #ifdef SUPPORT_HTTPS
1443 #ifdef USE_OPENSSL
1444 SSL_load_error_strings();
1445 #endif
1446 #endif
1447
1448 #if defined(SUPPORT_CGI) || defined(SUPPORT_PROXY)
1449 _envp=envp;
1450 #endif
1451 #ifdef SUPPORT_CGI
1452 {
1453 int found;
1454 int _argc=argc;
1455 char* new_uid=0;
1456 char** _argv=argv;
1457
1458 found=0;
1459 for (;;) {
1460 int c=getopt(_argc,_argv,"HP:hnfFi:p:vVdDtT:c:u:Uaw:sSO:C:lLeEr:o:N:m:A:X:I:");
1461 if (c==-1) break;
1462 switch (c) {
1463 case 'c':
1464 chroot_to=optarg;
1465 break;
1466 #ifdef SUPPORT_HTTPS
1467 case 'X':
1468 sshd=optarg;
1469 if (isdigit(*sshd)) {
1470 while (isdigit(*sshd)) ++sshd;
1471 ++sshd;
1472 }
1473 /* fall through */
1474 #endif
1475 case 'C':
1476 found=1;
1477 break;
1478 case 'u':
1479 new_uid=optarg;
1480 break;
1481 case '?':
1482 break;
1483 }
1484 }
1485
1486 optind=0;
1487
1488 forksock[0]=forksock[1]=-1;
1489 if (found) {
1490 if (socketpair(AF_UNIX,SOCK_STREAM,0,forksock)==-1)
1491 panic("socketpair");
1492 switch (fork()) {
1493 case -1:
1494 panic("fork");
1495 case 0:
1496 close(forksock[0]);
1497 {
1498 int64 savedir;
1499 buffer fsb;
1500 /* we want to drop privileges here unless we are configured to
1501 * support sshd mode, in which case sshd won't work if we
1502 * change our uid before executing it */
1503 #ifdef SUPPORT_HTTPS
1504 if (!sshd) {
1505 #endif
1506 #ifndef __MINGW32__
1507 if (chroot_to) { chdir(chroot_to); chroot(chroot_to); }
1508 if (prepare_switch_uid(new_uid)==-1 || switch_uid()==-1) panic("switch_uid failed");
1509 #endif
1510 #ifdef SUPPORT_HTTPS
1511 #ifndef __MINGW32__
1512 } else {
1513 if (prepare_switch_uid(new_uid)==-1) panic("switch_uid failed");
1514 #endif
1515 }
1516 #endif
1517 if (!io_readfile(&savedir,".")) panic("open()");
1518 buffer_init(&fsb,(void*)read,forksock[1],fsbuf,sizeof fsbuf);
1519 while (1) {
1520 pid_t r;
1521 do {
1522 r=waitpid(-1,0,WNOHANG);
1523 } while (r!=0 && r!=-1);
1524 forkslave(forksock[1],&fsb,savedir,chroot_to);
1525 fchdir(savedir);
1526 }
1527 }
1528 break;
1529 default:
1530 close(forksock[1]);
1531 break;
1532 }
1533 }
1534 }
1535
1536 #if 0
1537 { /* debug test for the forkslave code */
1538 int64 fd;
1539 uint32 a; uint16 b;
1540 char* req="GET /?/ HTTP/1.0\r\nHost: localhost:80\r\n\r\n";
1541 char* dir="default";
1542 char* ra="127.0.0.1";
1543 a=strlen(req); write(forksock[0],&a,4);
1544 a=strlen(dir); write(forksock[0],&a,4);
1545 a=strlen(ra); write(forksock[0],&a,4);
1546 write(forksock[0],req,strlen(req));
1547 write(forksock[0],dir,strlen(dir));
1548 write(forksock[0],ra,strlen(ra));
1549 b=12345; write(forksock[0],&b,2);
1550 b=80; write(forksock[0],&b,2);
1551
1552 read(forksock[0],&a,4);
1553 buffer_puts(buffer_1,"code ");
1554 buffer_putulong(buffer_1,a);
1555 buffer_putnlflush(buffer_1);
1556
1557 read(forksock[0],&a,4);
1558 if (a) {
1559 char* c=alloca(a+1);
1560 read(forksock[0],c,a);
1561 buffer_put(buffer_1,c,a);
1562 buffer_putnlflush(buffer_1);
1563 } else {
1564 read(forksock[0],&a,4); /* PID */
1565 fd=io_receivefd(forksock[0]);
1566 if (fd==-1)
1567 buffer_putsflush(buffer_2,"received no file descriptor for CGI\n");
1568 else {
1569 char buf[1024];
1570 int l;
1571 while ((l=read(fd,buf,sizeof buf))) {
1572 write(1,buf,l);
1573 }
1574 }
1575 }
1576 }
1577 exit(0);
1578 #endif
1579 #endif
1580
1581 s=socket_tcp6();
1582 #ifdef __broken_itojun_v6__
1583 #ifdef SUPPORT_FTP
1584 f4=socket_tcp4();
1585 #endif
1586 s4=socket_tcp4();
1587 #endif
1588
1589 #ifndef __MINGW32__
1590 signal(SIGPIPE,SIG_IGN);
1591
1592 {
1593 struct sigaction sa;
1594 byte_zero(&sa,sizeof(sa));
1595 sigemptyset(&sa.sa_mask);
1596 sa.sa_handler=sighandler;
1597 sigaction(SIGINT,&sa,0);
1598 sigaction(SIGHUP,&sa,0);
1599 }
1600
1601 if (!geteuid()) {
1602 struct rlimit orig,rl;
1603 long l;
1604 getrlimit(RLIMIT_NOFILE,&orig);
1605 #ifdef RLIMIT_NPROC
1606 rl.rlim_cur=RLIM_INFINITY; rl.rlim_max=RLIM_INFINITY;
1607 setrlimit(RLIMIT_NPROC,&rl);
1608 #endif
1609 for (l=orig.rlim_max; l<20000; l+=500) {
1610 rl.rlim_cur=l; rl.rlim_max=l;
1611 if (setrlimit(RLIMIT_NOFILE,&rl)==-1) {
1612 if (errno==EPERM) {
1613 /* We run as root but we still get EPERM? That only happens
1614 * on linux-vserver. There is no good way to handle this, so
1615 * we'll set the soft limit to the hard limit */
1616 orig.rlim_cur=orig.rlim_max;
1617 setrlimit(RLIMIT_NOFILE,&orig);
1618 }
1619 break;
1620 }
1621 }
1622 }
1623 #endif
1624
1625 byte_zero(ip,16);
1626 port=0; fport=0; sport=0; scope_id=0;
1627
1628 logging=1;
1629
1630 #if !defined(__linux__)
1631 optind=1;
1632 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
1633 optreset=1;
1634 #endif
1635 #endif
1636
1637 for (;;) {
1638 int i;
1639 int c=getopt(argc,argv,"HP:hnfFi:p:vVdDtT:c:u:Uaw:sSO:C:lLeEr:o:N:m:A:X:I:");
1640 if (c==-1) break;
1641 switch (c) {
1642 case 'L':
1643 limit_to_lan=1;
1644 break;
1645 case 'U':
1646 nouploads=1;
1647 break;
1648 case 'a':
1649 chmoduploads=1;
1650 break;
1651 case 'n':
1652 logging=0;
1653 break;
1654 case 'u':
1655 new_uid=optarg;
1656 break;
1657 case 'c':
1658 chroot_to=optarg;
1659 break;
1660 case 'm':
1661 mimetypesfilename=optarg;
1662 break;
1663 case 'P':
1664 i=scan_ulonglong(optarg,&prefetchquantum);
1665 if (i==0) {
1666 buffer_puts(buffer_2,"gatling: warning: could not parse prefetch quantum");
1667 buffer_puts(buffer_2,optarg+i+1);
1668 buffer_putsflush(buffer_2,".\n");
1669 }
1670 if (optarg[i]=='M') prefetchquantum*=1024*1024;
1671 if (optarg[i]=='G') prefetchquantum*=1024*1024*1024;
1672 break;
1673 case 'i':
1674 i=scan_ip6if(optarg,ip,&scope_id);
1675 if (optarg[i]!=0) {
1676 buffer_puts(buffer_2,"gatling: warning: could not parse IP address ");
1677 buffer_puts(buffer_2,optarg+i+1);
1678 buffer_putsflush(buffer_2,".\n");
1679 }
1680 break;
1681 case 'I':
1682 defaultindex=optarg;
1683 break;
1684 case 'p':
1685 if (lastopt==FTP)
1686 i=scan_ushort(optarg,&fport);
1687 else if (lastopt==SMB)
1688 i=scan_ushort(optarg,&sport);
1689 #ifdef SUPPORT_HTTPS
1690 else if (lastopt==HTTPS)
1691 i=scan_ushort(optarg,&httpsport);
1692 #endif
1693 else
1694 i=scan_ushort(optarg,&port);
1695 if (i==0) {
1696 buffer_puts(buffer_2,"gatling: warning: could not parse port ");
1697 buffer_puts(buffer_2,optarg+i+1);
1698 buffer_putsflush(buffer_2,".\n");
1699 }
1700 break;
1701 case 'v': virtual_hosts=1; break;
1702 case 'V': virtual_hosts=-1; break;
1703 case 't': transproxy=1; break;
1704 case 'd': directory_index=1; break;
1705 case 'D': directory_index=-1; break;
1706 #ifdef SUPPORT_FTP
1707 case 'f': doftp=1; lastopt=FTP; break;
1708 case 'F': doftp=-1; break;
1709 case 'l':
1710 askforpassword=1;
1711 break;
1712 #endif
1713 #ifdef SUPPORT_HTTPS
1714 case 'e': dohttps=1; lastopt=HTTPS; break;
1715 case 'E': dohttps=-1; break;
1716 case 'X': sshd=optarg;
1717 if (isdigit(sshd[0])) {
1718 i=scan_ulong(optarg,&ssh_timeout);
1719 if (sshd[i]!=',' && sshd[i]!=' ') goto usage;
1720 sshd+=i+1;
1721 } else ssh_timeout=2;
1722 break;
1723 #endif
1724 case 'H': dohttp=-1; break;
1725 case 's': dosmb=1; lastopt=SMB; break;
1726 case 'S': dosmb=-1; break;
1727 case 'T':
1728 i=scan_ulong(optarg,doftp?&ftptimeout_secs:&timeout_secs);
1729 if (i==0) {
1730 buffer_puts(buffer_2,"gatling: warning: could not parse timeout in seconds ");
1731 buffer_puts(buffer_2,optarg+i+1);
1732 buffer_putsflush(buffer_2,".\n");
1733 }
1734 break;
1735 #ifdef SUPPORT_SMB
1736 case 'w':
1737 if (str_len(optarg)>12)
1738 buffer_putsflush(buffer_2,"gatling: workgroup name too long (12 max)\n");
1739 else
1740 str_copy(workgroup,optarg);
1741 break;
1742 #endif
1743 #ifdef SUPPORT_CGI
1744 case 'C':
1745 errno=0;
1746 if (add_cgi(optarg)) {
1747 if (errno==ENOMEM)
1748 buffer_putmflush(buffer_2,"gatling: out of memory\n");
1749 else
1750 buffer_putmflush(buffer_2,"gatling: could not parse `",optarg,"': expected something like `\\.cgi$'\n");
1751 }
1752 break;
1753 #endif
1754 #ifdef SUPPORT_PROXY
1755 case 'O':
1756 errno=0;
1757 if (add_proxy(optarg)) {
1758 if (errno==ENOMEM)
1759 buffer_putmflush(buffer_2,"gatling: out of memory\n");
1760 else
1761 buffer_putmflush(buffer_2,"gatling: could not parse `",optarg,"': expected something like `127.0.0.1/8001/\\.jsp'\n");
1762 }
1763 break;
1764 #endif
1765 #ifdef SUPPORT_FALLBACK_REDIR
1766 case 'r':
1767 if (strstr(optarg,"://"))
1768 redir=optarg;
1769 else
1770 buffer_putmflush(buffer_2,"gatling: -r needs something like http://fallback.example.com as argument!\n");
1771 break;
1772 #endif
1773 #ifdef SUPPORT_MULTIPROC
1774 case 'N':
1775 i=scan_ulong(optarg,&instances);
1776 if (i==0) {
1777 buffer_puts(buffer_2,"gatling: warning: could not parse instances at ");
1778 buffer_puts(buffer_2,optarg+i+1);
1779 buffer_putsflush(buffer_2,".\n");
1780 }
1781 break;
1782 #endif
1783 case 'A':
1784 i=scan_uint(optarg,&max_requests_per_minute);
1785 if (i==0) {
1786 buffer_puts(buffer_2,"gatling: warning: could not parse max_requests_per_minute at ");
1787 buffer_puts(buffer_2,optarg+i+1);
1788 buffer_putsflush(buffer_2,".\n");
1789 }
1790 break;
1791
1792 #ifdef SUPPORT_THREADED_OPEN
1793 case 'o':
1794 #endif
1795 default:
1796 case '?':
1797 case 'h':
1798 usage:
1799 buffer_putsflush(buffer_2,
1800 "usage: gatling [-HhnvVtdDfFUa] [-i bind-to-ip] [-p bind-to-port] [-T seconds]\n"
1801 " [-u uid] [-c dir] [-w workgroup] [-P bytes] [-O ip/port/regex]\n"
1802 " [-r redirurl] [-N processes] [-I filename]\n"
1803 "\n"
1804 "\t-h\tprint this help\n"
1805 "\t-H\tdo not provide HTTP\n"
1806 "\t-v\tenable virtual hosting mode\n"
1807 "\t-V\tdisable virtual hosting mode\n"
1808 "\t\t(default is to try both)\n"
1809 "\t-t\ttransproxy mode: do not replace :port in Host headers\n"
1810 "\t-d\tgenerate directory index\n"
1811 "\t-D\tdo not generate directory index\n"
1812 "\t\t(default is -d unless in virtual hosting mode)\n"
1813 "\t-T n\tset timeout in seconds (0 to disable, default 23)\n"
1814 "\t-u uid\tswitch to this UID after binding\n"
1815 "\t-c dir\tchroot to dir after binding\n"
1816 "\t-n\tdo not produce logging output\n"
1817 "\t-f\tprovide FTP (default); next -p is meant for the FTP port (default: 21)\n"
1818 "\t-F\tdo not provide FTP\n"
1819 "\t-U\tdisallow FTP uploads, even to world writable directories\n"
1820 "\t-a\tchmod go+r uploaded files, so they can be downloaded immediately\n"
1821 "\t-P n\tenable experimental prefetching code (may actually be slower)\n"
1822 "\t-l\task for password (FTP server; work around buggy proxies)\n"
1823 "\t-m fn\tparse fn as mime.types style mime type database\n"
1824 "\t-A rpm\ttarpit clients if they have more than rpm request per minute\n"
1825 #ifdef SUPPORT_MULTIPROC
1826 "\t-N n\tfork n instances of gatling\n"
1827 #endif
1828 #ifdef SUPPORT_CGI
1829 "\t-C regex\tregex for local CGI execution (\"\\.cgi\")\n"
1830 "\t\tuse -C+x to assume executables are CGIs\n"
1831 #endif
1832 "\t-I name\talso try name, used for \"index.php\" etc\n"
1833 #ifdef SUPPORT_PROXY
1834 "\t-O [flag/]ip/port/regex\tregex for proxy mode (\"F/127.0.0.1/8001/\\.jsp$\")\n"
1835 "\t-O [flag/]|filename|regex\tregex for proxy mode (\"F/|/tmp/php.sock|\\.jsp$\")\n"
1836 "\t\tflags: F - FastCGI, S - SCGI, J - JSP\n"
1837 #endif
1838 #ifdef SUPPORT_SMB
1839 "\t-s\tprovide SMB service (default)\n"
1840 "\t-S\tdo not provide SMB service\n"
1841 "\t-w name\tset SMB workgroup\n"
1842 #endif
1843 #ifdef SUPPORT_HTTPS
1844 "\t-e\tprovide encryption (https://...)\n"
1845 "\t-E\tdo not provide encryption\n"
1846 "\t-X timeout,sshd (\"2,/opt/diet/sbin/sshd -u0\")\n"
1847 "\t\tforward TLS socket to sshd if no activity after connect\n"
1848 #endif
1849 #ifdef SUPPORT_FALLBACK_REDIR
1850 "\t-r url\tinstead of a 404, generate a redirect to url+localpart\n"
1851 #endif
1852 "\t-L\tonly accept connections from localhost or link/site local reserved IP addresses\n"
1853 );
1854 return 0;
1855 }
1856 }
1857 #ifdef SUPPORT_SMB
1858 {
1859 iconv_t i=iconv_open("UTF-16LE","ISO-8859-1");
1860 size_t X,Y;
1861 char* x,* y;
1862 X=str_len(workgroup)+1;
1863 Y=sizeof(workgroup_utf16);
1864 x=workgroup;
1865 y=workgroup_utf16;
1866 #if defined(__sun__) || defined(__FreeBSD__)
1867 if (iconv(i,(const char**)&x,&X,&y,&Y)) panic("UTF-16 conversion of workgroup failed.\n");
1868 #else
1869 if (iconv(i,&x,&X,&y,&Y)) panic("UTF-16 conversion of workgroup failed.\n");
1870 #endif
1871 wglen=str_len(workgroup);
1872 wglen16=sizeof(workgroup_utf16)-Y;
1873 iconv_close(i);
1874
1875 }
1876 {
1877 extern iconv_t wc2utf8;
1878 extern iconv_t utf82wc2;
1879 wc2utf8=iconv_open("UTF-8","UTF-16LE");
1880 utf82wc2=iconv_open("UTF-16LE","UTF-8");
1881 }
1882 #endif
1883 if (!directory_index)
1884 directory_index=virtual_hosts<1;
1885 else if (directory_index==-1)
1886 directory_index=0;
1887
1888 if (timeout_secs) {
1889 taia_now(&last);
1890 byte_copy(&next,sizeof(next),&last);
1891 next.sec.x += timeout_secs;
1892 byte_copy(&nextftp,sizeof(next),&last);
1893 nextftp.sec.x += ftptimeout_secs;
1894 #ifdef SUPPORT_HTTPS
1895 if (ssh_timeout) {
1896 byte_copy(&nexthttps,sizeof(now),&now);
1897 nexthttps.sec.x += ssh_timeout;
1898 } else
1899 byte_copy(&nexthttps,sizeof(next),&next);
1900 #endif
1901 byte_copy(&tick,sizeof(next),&last);
1902 ++tick.sec.x;
1903 }
1904
1905 {
1906 #ifdef __MINGW32__
1907 int euid=0;
1908 #else
1909 uid_t euid=geteuid();
1910 #endif
1911 if (port==0)
1912 port=euid?8000:80;
1913 if (fport==0)
1914 fport=euid?2121:21;
1915 #ifdef SUPPORT_SMB
1916 if (sport==0)
1917 sport=445;
1918 #endif
1919 #ifdef SUPPORT_HTTPS
1920 if (httpsport==0)
1921 httpsport=euid?4433:443;
1922 #endif
1923 }
1924 #ifdef __broken_itojun_v6__
1925 if (byte_equal(ip,12,V4mappedprefix) || byte_equal(ip,16,V6any)) {
1926 if (byte_equal(ip,16,V6any)) {
1927 if (dohttp==-1) {
1928 close(s); s=-1;
1929 } else {
1930 if (socket_bind6_reuse(s,ip,port,scope_id)==-1 || socket_listen(s,16)==-1)
1931 panic("socket_bind6_reuse for http");
1932 }
1933 #ifdef SUPPORT_FTP
1934 f=socket_tcp6();
1935 if (doftp>=0) {
1936 if (socket_bind6_reuse(f,ip,fport,scope_id)==-1 || socket_listen(f,16)==-1) {
1937 if (doftp==1)
1938 panic("socket_bind6_reuse for ftp");
1939 buffer_putsflush(buffer_2,"warning: could not bind to FTP port; FTP will be unavailable.\n");
1940 io_close(f); f=-1;
1941 }
1942 }
1943 #endif
1944 } else {
1945 io_close(s); s=-1;
1946 }
1947 if (socket_bind4_reuse(s4,ip+12,port)==-1 || socket_listen(s4,16)==-1)
1948 panic("socket_bind4_reuse");
1949 #ifdef SUPPORT_FTP
1950 if (doftp>=0)
1951 if (socket_bind4_reuse(f4,ip+12,fport)==-1 || socket_listen(f4,16)==-1) {
1952 if (doftp==1)
1953 panic("socket_bind4_reuse");
1954 buffer_putsflush(buffer_2,"warning: could not bind to FTP port; FTP will be unavailable.\n");
1955 io_close(f4); f4=-1;
1956 }
1957 #endif
1958 } else {
1959 if (dohttp==-1) {
1960 close(s);
1961 s=-1;
1962 } else {
1963 if (socket_bind6_reuse(s,ip,port,scope_id)==-1 || socket_listen(s,16)==-1)
1964 panic("socket_bind6_reuse");
1965 }
1966 s4=-1;
1967 #ifdef SUPPORT_FTP
1968 if (doftp>=0)
1969 if (socket_bind6_reuse(f,ip,fport,scope_id)==-1 || socket_listen(f,16)==-1) {
1970 if (doftp==1)
1971 panic("socket_bind6_reuse");
1972 buffer_putsflush(buffer_2,"warning: could not bind to FTP port; FTP will be unavailable.\n");
1973 io_close(f); f=-1;
1974 }
1975 f4=-1;
1976 #endif
1977 }
1978 buffer_putsflush(buffer_2,"WARNING: We are taking heavy losses working around itojun KAME madness here.\n"
1979 " Please consider using an operating system with real IPv6 support instead!\n");
1980 #else
1981 if (dohttp==-1) {
1982 close(s);
1983 s=-1;
1984 } else {
1985 #ifndef __linux__
1986 /* Enabling this on Linux leads to a denial of service attack when
1987 * somebody just opens 16 or so connections without sending HTTP
1988 * requests, stalling the whole HTTP server in the process */
1989 socket_deferaccept(s,HTTPIN);
1990 #endif
1991 if (socket_bind6_reuse(s,ip,port,0)==-1 || socket_listen(s,16)==-1)
1992 panic("socket_bind6_reuse");
1993 socket_fastopen(s);
1994 quickackoff(s);
1995 }
1996 #ifdef SUPPORT_FTP
1997 if (doftp>=0) {
1998 f=socket_tcp6();
1999 if (socket_bind6_reuse(f,ip,fport,scope_id)==-1 || socket_listen(f,16)==-1) {
2000 if (doftp==1)
2001 panic("socket_bind6_reuse");
2002 buffer_putsflush(buffer_2,"warning: could not bind to FTP port; FTP will be unavailable.\n");
2003 io_close(f); f=-1;
2004 }
2005 quickackoff(f);
2006 }
2007 #endif
2008 #ifdef SUPPORT_SMB
2009 if (dosmb>=0) {
2010 smbs=socket_tcp6();
2011 #ifndef __linux__
2012 socket_deferaccept(smbs,DATAIN);
2013 #endif
2014 if (socket_bind6_reuse(smbs,ip,sport,scope_id)==-1 || socket_listen(smbs,16)) {
2015 if (dosmb==1)
2016 panic("socket_bind6_reuse");
2017 buffer_putsflush(buffer_2,"warning: could not bind to SMB port; SMB will be unavailable.\n");
2018 io_close(smbs); smbs=-1;
2019 }
2020 socket_fastopen(smbs);
2021 quickackoff(smbs);
2022 }
2023 #endif
2024 #ifdef SUPPORT_HTTPS
2025 if (dohttps>=0) {
2026 httpss=socket_tcp6();
2027 #ifndef __linux__
2028 if (ssh_timeout==0)
2029 socket_deferaccept(httpss,DATAIN);
2030 #endif
2031 if (socket_bind6_reuse(httpss,ip,httpsport,scope_id)==-1 || socket_listen(httpss,16)) {
2032 if (dohttps==1)
2033 panic("socket_bind6_reuse");
2034 buffer_putsflush(buffer_2,"warning: could not bind to HTTPS port; HTTPS will be unavailable.\n");
2035 io_close(httpss); httpss=-1;
2036 }
2037 quickackoff(httpss);
2038 }
2039 #endif
2040 #endif
2041
2042 #ifndef __MINGW32__
2043 if (prepare_switch_uid(new_uid)==-1)
2044 goto usage;
2045 if (chroot_to) {
2046 if (chroot(chroot_to)==-1)
2047 panic("chroot");
2048 if (chdir("/")==-1)
2049 panic("chdir");
2050 }
2051 if (new_uid && switch_uid()==-1)
2052 panic("switch_uid");
2053
2054 #endif
2055
2056 #ifdef __MINGW32__
2057 _getcwd(origdir,sizeof(origdir));
2058 strncpy(serverroot,origdir,sizeof(serverroot));
2059 // printf("origdir is \"%s\"\n",origdir);
2060 #else
2061 /* get fd for . so we can always fchdir back */
2062 if (!io_readfile(&origdir,".")) panic("open()");
2063 /* note the server root path for CGI $SCRIPT_FILENAME */
2064 if (!getcwd(serverroot,sizeof(serverroot))) {
2065 serverroot[0]='.';
2066 serverroot[1]=0;
2067 }
2068 #endif
2069
2070 #ifdef SUPPORT_MULTIPROC
2071
2072 if (instances>1) {
2073 unsigned long i;
2074 --instances;
2075
2076 if (instances>100) instances=100;
2077 Instances=alloca(instances*sizeof(pid_t));
2078 for (i=0; i<instances; ++i) {
2079 if ((Instances[i]=fork()) == -1)
2080 panic("fork failed");
2081 else if (Instances[i] == 0) {
2082 instances=0;
2083 break;
2084 }
2085 }
2086
2087 #ifdef __broken_itojun_v6__
2088 prepare_listen(s,&ct);
2089 prepare_listen(s4,&ct4);
2090 prepare_listen(f,&fct);
2091 prepare_listen(f4,&fct4);
2092 #else
2093 prepare_listen(s,&ct);
2094 #ifdef SUPPORT_FTP
2095 prepare_listen(f,&fct);
2096 #endif
2097 #ifdef SUPPORT_SMB
2098 prepare_listen(smbs,&sct);
2099 #endif
2100 #ifdef SUPPORT_HTTPS
2101 prepare_listen(httpss,&httpsct);
2102 #endif
2103 #endif
2104
2105 } else {
2106 #endif
2107 #ifdef SUPPORT_MULTIPROC
2108 Instances=0;
2109 instances=0;
2110 #endif
2111
2112 #ifdef __broken_itojun_v6__
2113 prepare_listen(s,&ct);
2114 prepare_listen(s4,&ct4);
2115 prepare_listen(f,&fct);
2116 prepare_listen(f4,&fct4);
2117 #else
2118 prepare_listen(s,&ct);
2119 #ifdef SUPPORT_FTP
2120 prepare_listen(f,&fct);
2121 #endif
2122 #ifdef SUPPORT_SMB
2123 prepare_listen(smbs,&sct);
2124 #endif
2125 #ifdef SUPPORT_HTTPS
2126 prepare_listen(httpss,&httpsct);
2127 #endif
2128 #endif
2129
2130 #ifdef SUPPORT_MULTIPROC
2131 }
2132 #endif
2133
2134 #ifdef __linux__
2135 if (io_fd(ifd))
2136 io_wantread(ifd);
2137 #endif
2138
2139 {
2140 char buf[IP6_FMT];
2141 if (s!=-1) {
2142 buffer_puts(buffer_1,"starting_up 0 ");
2143 buffer_put(buffer_1,buf,fmt_ip6c(buf,ip));
2144 buffer_puts(buffer_1," ");
2145 buffer_putulong(buffer_1,port);
2146 buffer_putnlflush(buffer_1);
2147 }
2148 if (f!=-1) {
2149 buffer_puts(buffer_1,"start_ftp 0 ");
2150 buffer_put(buffer_1,buf,fmt_ip6c(buf,ip));
2151 buffer_puts(buffer_1," ");
2152 buffer_putulong(buffer_1,fport);
2153 buffer_putnlflush(buffer_1);
2154 }
2155 #ifdef SUPPORT_SMB
2156 if (smbs!=-1) {
2157 buffer_puts(buffer_1,"start_smb 0 ");
2158 buffer_put(buffer_1,buf,fmt_ip6c(buf,ip));
2159 buffer_puts(buffer_1," ");
2160 buffer_putulong(buffer_1,sport);
2161 buffer_putnlflush(buffer_1);
2162 }
2163 #endif
2164 #ifdef SUPPORT_HTTPS
2165 if (httpss!=-1) {
2166 buffer_puts(buffer_1,"start_https 0 ");
2167 buffer_put(buffer_1,buf,fmt_ip6c(buf,ip));
2168 buffer_puts(buffer_1," ");
2169 buffer_putulong(buffer_1,httpsport);
2170 buffer_putnlflush(buffer_1);
2171 }
2172 #endif
2173 }
2174
2175 connections=1;
2176
2177 #if !defined(__OPTIMIZE__) && defined(__linux__)
2178 /* This happens only if the code was compiled without optimization */
2179 /* make sure we can dump core even if we switched uid */
2180 prctl(PR_SET_DUMPABLE,1,0,0);
2181 /* and make sure we don't have a core dump size limit in place */
2182 {
2183 struct rlimit orig;
2184 orig.rlim_cur=orig.rlim_max=RLIM_INFINITY;
2185 setrlimit(RLIMIT_CORE,&orig);
2186 }
2187 #endif
2188
2189 for (;;) {
2190 int events; /* accept new connections asap */
2191 int64 i;
2192 events=0;
2193
2194 if (fini==2) {
2195 --connections;
2196 io_close(s);
2197 #ifdef __broken_itojun_v6__
2198 io_close(s4);
2199 #endif
2200 #ifdef SUPPORT_FTP
2201 io_close(f);
2202 #ifdef __broken_itojun_v6__
2203 io_close(f4);
2204 #endif
2205 #endif
2206 #ifdef SUPPORT_SMB
2207 io_close(smbs);
2208 #endif
2209 buffer_puts(buffer_1,"closing_server_sockets ");
2210 buffer_putulong(buffer_1,connections);
2211 buffer_putnlflush(buffer_1);
2212 fini=0;
2213 }
2214 if (!connections) fini=1;
2215 if (fini) {
2216 buffer_putsflush(buffer_1,"stopping\n");
2217 break;
2218 }
2219
2220 if (timeout_secs)
2221 io_waituntil(tick);
2222 else
2223 io_wait();
2224
2225 taia_now(&now);
2226 if (timeout_secs) {
2227 if (now.sec.x != last.sec.x) {
2228 cps=cps1; cps1=0;
2229 rps=rps1; rps1=0;
2230 eps=eps1; eps1=0;
2231 tin=tin1; tin1=0;
2232 tout=tout1; tout1=0;
2233 byte_copy(&last,sizeof(now),&now);
2234 byte_copy(&next,sizeof(now),&now);
2235 next.sec.x += timeout_secs;
2236 byte_copy(&nextftp,sizeof(now),&now);
2237 nextftp.sec.x += ftptimeout_secs;
2238 #if defined(SUPPORT_HTTPS) && !defined(SUPPORT_MULTIPROC)
2239 if (ssh_timeout) {
2240 byte_copy(&nexthttps,sizeof(now),&now);
2241 nexthttps.sec.x += ssh_timeout;
2242 } else
2243 byte_copy(&nexthttps,sizeof(next),&next);
2244 #endif
2245 byte_copy(&tick,sizeof(next),&now);
2246 ++tick.sec.x;
2247 while ((i=io_timeouted())!=-1) {
2248 struct http_data* x;
2249 #if defined(SUPPORT_HTTPS) && !defined(SUPPORT_MULTIPROC)
2250 if (ssh_timeout && (x=io_getcookie(i)) && x->t == HTTPSACCEPT_CHECK) {
2251 if (logging) {
2252 char numbuf[FMT_ULONG];
2253 numbuf[fmt_ulong(numbuf,i)]=0;
2254 buffer_putmflush(buffer_1,"timeout/sshd ",numbuf,"\n");
2255 }
2256 {
2257 uint32 a=0;
2258 write(forksock[0],&a,4);
2259 io_passfd(forksock[0],i);
2260 }
2261 --https_connections;
2262 }
2263 #endif
2264 if (logging) {
2265 /* shut up in the tarpit case, don't give them the
2266 * satisfaction of spamming our logs too much */
2267 if ((x=io_getcookie(i)) && x->t != PUNISHMENT) {
2268 char numbuf[FMT_ULONG];
2269 numbuf[fmt_ulong(numbuf,i)]=0;
2270 buffer_putmflush(buffer_1,"timeout ",numbuf,"\nclose/timeout ",numbuf,"\n");
2271 }
2272 }
2273 cleanup(i);
2274 }
2275 }
2276 }
2277
2278 /* HANDLE READ EVENTS */
2279 while ((i=io_canread())!=-1) {
2280 #ifdef __linux__
2281 if (i==ifd) {
2282 handle_inotify_events();
2283 continue;
2284 }
2285 #endif
2286 struct http_data* H=io_getcookie(i);
2287
2288 ++eps1;
2289 if (!H) {
2290 char a[FMT_ULONG];
2291 a[fmt_ulong(a,i)]=0;
2292 buffer_putmflush(buffer_2,"canthappen ",a,": got read event on socket with no cookie!\n");
2293 io_dontwantread(i);
2294 io_close(i);
2295 continue;
2296 }
2297
2298 #ifdef SMDEBUG
2299 {
2300 char a[FMT_ULONG];
2301 a[fmt_ulong(a,i)]=0;
2302 buffer_putmflush(buffer_2,"DEBUG: fd ",a," got READ event, state is ",state2string(H->t),"!\n");
2303 }
2304 #endif
2305
2306 /* This is a speed hack. If we have a LOT of connections, we
2307 * might get swamped handling events and it might take a while for
2308 * us to get around to accepting new connections. Unfortunately,
2309 * the kernel has a limited number of connections that can be
2310 * incoming but not accepted; if more attempts come in, the kernel
2311 * just drops them, and they then run into a timeout and try
2312 * again. To avoid this, we try accepting connections even
2313 * without any events. */
2314 if (++events==10) {
2315 events=0;
2316 if (s!=-1) accept_server_connection(s,(struct http_data*)&ct,ftptimeout_secs,nextftp);
2317 #ifdef SUPPORT_FTP
2318 if (f!=-1) accept_server_connection(f,(struct http_data*)&fct,ftptimeout_secs,nextftp);
2319 #endif
2320 #ifdef SUPPORT_HTTPS
2321 if (httpss!=-1) {
2322 if (ssh_timeout)
2323 accept_server_connection(httpss,(struct http_data*)&httpsct,ssh_timeout,nexthttps);
2324 else
2325 accept_server_connection(httpss,(struct http_data*)&httpsct,ftptimeout_secs,nextftp);
2326 }
2327 #endif
2328 #ifdef __broken_itojun_v6__
2329 if (s4!=-1) accept_server_connection(s4,(struct http_data*)&ct4,ftptimeout_secs,nextftp);
2330 #ifdef SUPPORT_FTP
2331 if (f4!=-1) accept_server_connection(f4,(struct http_data*)&fct4,ftptimeout_secs,nextftp);
2332 #endif
2333 #ifdef SUPPORT_HTTPS
2334 if (httpss4!=-1) {
2335 if (ssh_timeout)
2336 accept_server_connection(httpss4,(struct http_data*)&httpsct4,ssh_timeout,nexthttps);
2337 else
2338 accept_server_connection(httpss4,(struct http_data*)&httpsct4,ftptimeout_secs,nextftp);
2339 }
2340 #endif
2341 #endif
2342 }
2343
2344 if (H->t == HTTPREQUEST
2345 #ifdef SUPPORT_FTP
2346 || H->t == FTPSLAVE
2347 #endif
2348 #ifdef SUPPORT_SMB
2349 || H->t == SMBREQUEST
2350 #endif
2351 #ifdef SUPPORT_HTTPS
2352 || H->t == HTTPSRESPONSE
2353 #endif
2354 )
2355 H->sent_until=H->prefetched_until=0;
2356
2357 #ifdef SUPPORT_PROXY
2358 /* read on PROXYPOST means the CGI sent some data */
2359 if (H->t==PROXYPOST) {
2360 int64 mainsock=H->buddy;
2361 if (handle_read_proxypost(i,H)==-4) {
2362 /* the CGI was done, we closed the CGI socket, now check if
2363 * there is keep-alive / pipelining to take care of */
2364 struct http_data* h=io_getcookie(mainsock);
2365 if (h->keepalive) {
2366 #ifdef SUPPORT_HTTPS
2367 if (h->t==HTTPSPOST) h->t=HTTPSREQUEST;
2368 #endif
2369 if (h->t==HTTPPOST) h->t=HTTPREQUEST;
2370 handle_incoming_data(mainsock,h);
2371 } else {
2372 #ifdef SUPPORT_HTTPS
2373 if (h->t==HTTPSPOST) {
2374 #ifdef USE_OPENSSL
2375 SSL_shutdown(h->ssl);
2376 #endif
2377 }
2378 #endif
2379 cleanup(i);
2380 }
2381 }
2382 } else if (H->t==HTTPPOST
2383 #ifdef SUPPORT_HTTPS
2384 || H->t==HTTPSPOST
2385 #endif
2386 )
2387 /* read on HTTPPOST means the browser sent some more POST data */
2388 handle_read_httppost(i,H);
2389 else
2390 #endif
2391 #ifdef SUPPORT_FTP
2392 if (H->t==FTPPASSIVE)
2393 handle_read_ftppassive(i,H);
2394 else
2395 #endif
2396 #ifdef SUPPORT_HTTPS
2397 if (H->t==HTTPSACCEPT || H->t==HTTPSACCEPT_CHECK)
2398 do_sslaccept(i,H,1);
2399 else
2400 #endif
2401 if (is_server_connection(H->t)) {
2402 #ifdef SUPPORT_HTTPS
2403 if (ssh_timeout && (H->t == HTTPSSERVER6 || H->t == HTTPSSERVER4))
2404 accept_server_connection(i,H,ssh_timeout,nexthttps);
2405 else
2406 #endif
2407 accept_server_connection(i,H,ftptimeout_secs,nextftp);
2408 }
2409 else {
2410 #ifdef SUPPORT_HTTPS
2411 /* This looks wrong but isn't. SSL has renegotiation.
2412 If that happens, we can be waiting for read when we are actually trying to write something */
2413 if (H->t == HTTPSRESPONSE)
2414 handle_write_misc(i,H,prefetchquantum);
2415 else
2416 #endif
2417 handle_read_misc(i,H,ftptimeout_secs,nextftp);
2418 }
2419 }
2420
2421 /* HANDLE WRITABLE EVENTS */
2422 while ((i=io_canwrite())!=-1) {
2423 struct http_data* h=io_getcookie(i);
2424 ++eps1;
2425 if (!h) {
2426 char a[FMT_ULONG];
2427 a[fmt_ulong(a,i)]=0;
2428 buffer_putmflush(buffer_2,"canthappen ",a,": got write event on socket with no cookie!\n");
2429 io_dontwantwrite(i);
2430 io_close(i);
2431 continue;
2432 }
2433
2434 #ifdef SMDEBUG
2435 {
2436 char a[FMT_ULONG];
2437 a[fmt_ulong(a,i)]=0;
2438 buffer_putmflush(buffer_2,"DEBUG: fd ",a," got WRITE event, state is ",state2string(h->t),"!\n");
2439 }
2440 #endif
2441
2442 if (++events==10) {
2443 events=0;
2444 accept_server_connection(s,(struct http_data*)&ct,ftptimeout_secs,nextftp);
2445 #ifdef SUPPORT_FTP
2446 if (f!=-1) accept_server_connection(f,(struct http_data*)&fct,ftptimeout_secs,nextftp);
2447 #endif
2448 #ifdef SUPPORT_HTTPS
2449 if (httpss!=-1) {
2450 if (ssh_timeout)
2451 accept_server_connection(httpss,(struct http_data*)&httpsct,ssh_timeout,nexthttps);
2452 else
2453 accept_server_connection(httpss,(struct http_data*)&httpsct,ftptimeout_secs,nextftp);
2454 }
2455 #endif
2456 #ifdef __broken_itojun_v6__
2457 if (s4!=-1) accept_server_connection(s4,(struct http_data*)&ct4,ftptimeout_secs,nextftp);
2458 #ifdef SUPPORT_FTP
2459 if (f4!=-1) accept_server_connection(f4,(struct http_data*)&fct4,ftptimeout_secs,nextftp);
2460 #endif
2461 #ifdef SUPPORT_HTTPS
2462 if (httpss4!=-1) {
2463 if (ssh_timeout)
2464 accept_server_connection(httpss4,(struct http_data*)&httpsct4,ssh_timeout,nexthttps);
2465 else
2466 accept_server_connection(httpss4,(struct http_data*)&httpsct4,ftptimeout_secs,nextftp);
2467 }
2468 #endif
2469 #endif
2470 }
2471
2472 #ifdef SUPPORT_FTP
2473 if (h->t==FTPCONTROL4 || h->t==FTPCONTROL6) {
2474 if (ftptimeout_secs)
2475 io_timeout(i,nextftp);
2476 } else
2477 #endif
2478 if (timeout_secs) {
2479 io_timeout(i,next);
2480 if (h->buddy>0) {
2481 #ifdef SUPPORT_FTP
2482 if (h->t==FTPSLAVE) {
2483 io_timeout(h->buddy,nextftp);
2484 } else
2485 #endif
2486 io_timeout(h->buddy,next);
2487 }
2488 }
2489
2490 #ifdef SUPPORT_PROXY
2491 if (h->t==PROXYSLAVE)
2492 handle_write_proxyslave(i,h);
2493 else if (h->t==PROXYPOST)
2494 handle_write_proxypost(i,h);
2495 else if (h->t==HTTPPOST
2496 #ifdef SUPPORT_HTTPS
2497 || h->t==HTTPSPOST
2498 #endif
2499 )
2500 handle_write_httppost(i,h);
2501 else
2502 #endif
2503 #ifdef SUPPORT_HTTPS
2504 if (h->t==HTTPSACCEPT)
2505 do_sslaccept(i,h,0);
2506 else if (h->t == HTTPSREQUEST)
2507 handle_read_misc(i,h,ftptimeout_secs,nextftp);
2508 else
2509 #endif
2510 #ifdef SUPPORT_FTP
2511 if (h->t==FTPACTIVE)
2512 handle_write_ftpactive(i,h);
2513 else
2514 #endif
2515 {
2516 if (handle_write_misc(i,h,prefetchquantum)==1)
2517 /* keep-alive && pipelining, generate read event on i */
2518 handle_incoming_data(i,h);
2519 }
2520 }
2521 }
2522 #ifdef SUPPORT_MULTIPROC
2523 if (instances) {
2524 unsigned long i;
2525 for (i=0; i<instances; ++i)
2526 kill(Instances[i],15);
2527 }
2528 #endif
2529 io_finishandshutdown();
2530 #ifdef SUPPORT_HTTPS
2531 free_tls_memory();
2532 #endif
2533 #ifdef SUPPORT_SMB
2534 {
2535 extern iconv_t wc2utf8;
2536 extern iconv_t utf82wc2;
2537 iconv_close(wc2utf8);
2538 iconv_close(utf82wc2);
2539 }
2540 #endif
2541 _exit(0);
2542 return 0;
2543 }
2544
2545 #if 0
2546 int epoll_create(int i) { return -1; }
2547 #endif
2548