1 /* thttpd.c - tiny/turbo/throttling HTTP server
2 **
3 ** Copyright � 1995,1998,1999,2000,2001,2015 by
4 ** Jef Poskanzer <jef@mail.acme.com>. All rights reserved.
5 **
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions
8 ** are met:
9 ** 1. Redistributions of source code must retain the above copyright
10 **    notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 **    notice, this list of conditions and the following disclaimer in the
13 **    documentation and/or other materials provided with the distribution.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 */
27 
28 
29 #include "config.h"
30 #include "version.h"
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37 #include <sys/uio.h>
38 
39 #include <errno.h>
40 #ifdef HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43 #include <pwd.h>
44 #ifdef HAVE_GRP_H
45 #include <grp.h>
46 #endif
47 #include <signal.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #ifdef TIME_WITH_SYS_TIME
53 #include <time.h>
54 #endif
55 #include <unistd.h>
56 
57 #include "fdwatch.h"
58 #include "libhttpd.h"
59 #include "mmc.h"
60 #include "timers.h"
61 #include "match.h"
62 
63 #ifndef SHUT_WR
64 #define SHUT_WR 1
65 #endif
66 
67 #ifndef HAVE_INT64T
68 typedef long long int64_t;
69 #endif
70 
71 
72 static char* argv0;
73 static int debug;
74 static unsigned short port;
75 static char* dir;
76 static char* data_dir;
77 static int do_chroot, no_log, no_symlink_check, do_vhost, do_global_passwd;
78 static char* cgi_pattern;
79 static int cgi_limit;
80 static char* url_pattern;
81 static int no_empty_referrers;
82 static char* local_pattern;
83 static char* logfile;
84 static char* throttlefile;
85 static char* hostname;
86 static char* pidfile;
87 static char* user;
88 static char* charset;
89 static char* p3p;
90 static int max_age;
91 
92 
93 typedef struct {
94     char* pattern;
95     long max_limit, min_limit;
96     long rate;
97     off_t bytes_since_avg;
98     int num_sending;
99     } throttletab;
100 static throttletab* throttles;
101 static int numthrottles, maxthrottles;
102 
103 #define THROTTLE_NOLIMIT -1
104 
105 
106 typedef struct {
107     int conn_state;
108     int next_free_connect;
109     httpd_conn* hc;
110     int tnums[MAXTHROTTLENUMS];         /* throttle indexes */
111     int numtnums;
112     long max_limit, min_limit;
113     time_t started_at, active_at;
114     Timer* wakeup_timer;
115     Timer* linger_timer;
116     long wouldblock_delay;
117     off_t bytes;
118     off_t end_byte_index;
119     off_t next_byte_index;
120     } connecttab;
121 static connecttab* connects;
122 static int num_connects, max_connects, first_free_connect;
123 static int httpd_conn_count;
124 
125 /* The connection states. */
126 #define CNST_FREE 0
127 #define CNST_READING 1
128 #define CNST_SENDING 2
129 #define CNST_PAUSING 3
130 #define CNST_LINGERING 4
131 
132 
133 static httpd_server* hs = (httpd_server*) 0;
134 int terminate = 0;
135 time_t start_time, stats_time;
136 long stats_connections;
137 off_t stats_bytes;
138 int stats_simultaneous;
139 
140 static volatile int got_hup, got_usr1, watchdog_flag;
141 
142 
143 /* Forwards. */
144 static void parse_args( int argc, char** argv );
145 static void usage( void );
146 static void read_config( char* filename );
147 static void value_required( char* name, char* value );
148 static void no_value_required( char* name, char* value );
149 static char* e_strdup( char* oldstr );
150 static void lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P );
151 static void read_throttlefile( char* tf );
152 static void shut_down( void );
153 static int handle_newconnect( struct timeval* tvP, int listen_fd );
154 static void handle_read( connecttab* c, struct timeval* tvP );
155 static void handle_send( connecttab* c, struct timeval* tvP );
156 static void handle_linger( connecttab* c, struct timeval* tvP );
157 static int check_throttles( connecttab* c );
158 static void clear_throttles( connecttab* c, struct timeval* tvP );
159 static void update_throttles( ClientData client_data, struct timeval* nowP );
160 static void finish_connection( connecttab* c, struct timeval* tvP );
161 static void clear_connection( connecttab* c, struct timeval* tvP );
162 static void really_clear_connection( connecttab* c, struct timeval* tvP );
163 static void idle( ClientData client_data, struct timeval* nowP );
164 static void wakeup_connection( ClientData client_data, struct timeval* nowP );
165 static void linger_clear_connection( ClientData client_data, struct timeval* nowP );
166 static void occasional( ClientData client_data, struct timeval* nowP );
167 #ifdef STATS_TIME
168 static void show_stats( ClientData client_data, struct timeval* nowP );
169 #endif /* STATS_TIME */
170 static void logstats( struct timeval* nowP );
171 static void thttpd_logstats( long secs );
172 
173 
174 /* SIGTERM and SIGINT say to exit immediately. */
175 static void
handle_term(int sig)176 handle_term( int sig )
177     {
178     /* Don't need to set up the handler again, since it's a one-shot. */
179 
180     shut_down();
181     syslog( LOG_NOTICE, "exiting due to signal %d", sig );
182     closelog();
183     exit( 1 );
184     }
185 
186 
187 /* SIGCHLD - a chile process exitted, so we need to reap the zombie */
188 static void
handle_chld(int sig)189 handle_chld( int sig )
190     {
191     const int oerrno = errno;
192     pid_t pid;
193     int status;
194 
195 #ifndef HAVE_SIGSET
196     /* Set up handler again. */
197     (void) signal( SIGCHLD, handle_chld );
198 #endif /* ! HAVE_SIGSET */
199 
200     /* Reap defunct children until there aren't any more. */
201     for (;;)
202 	{
203 #ifdef HAVE_WAITPID
204 	pid = waitpid( (pid_t) -1, &status, WNOHANG );
205 #else /* HAVE_WAITPID */
206 	pid = wait3( &status, WNOHANG, (struct rusage*) 0 );
207 #endif /* HAVE_WAITPID */
208 	if ( (int) pid == 0 )		/* none left */
209 	    break;
210 	if ( (int) pid < 0 )
211 	    {
212 	    if ( errno == EINTR || errno == EAGAIN )
213 		continue;
214 	    /* ECHILD shouldn't happen with the WNOHANG option,
215 	    ** but with some kernels it does anyway.  Ignore it.
216 	    */
217 	    if ( errno != ECHILD )
218 		syslog( LOG_ERR, "child wait - %m" );
219 	    break;
220 	    }
221 	/* Decrement the CGI count.  Note that this is not accurate, since
222 	** each CGI can involve two or even three child processes.
223 	** Decrementing for each child means that when there is heavy CGI
224 	** activity, the count will be lower than it should be, and therefore
225 	** more CGIs will be allowed than should be.
226 	*/
227 	if ( hs != (httpd_server*) 0 )
228 	    {
229 	    --hs->cgi_count;
230 	    if ( hs->cgi_count < 0 )
231 		hs->cgi_count = 0;
232 	    }
233 	}
234 
235     /* Restore previous errno. */
236     errno = oerrno;
237     }
238 
239 
240 /* SIGHUP says to re-open the log file. */
241 static void
handle_hup(int sig)242 handle_hup( int sig )
243     {
244     const int oerrno = errno;
245 
246 #ifndef HAVE_SIGSET
247     /* Set up handler again. */
248     (void) signal( SIGHUP, handle_hup );
249 #endif /* ! HAVE_SIGSET */
250 
251     /* Just set a flag that we got the signal. */
252     got_hup = 1;
253 
254     /* Restore previous errno. */
255     errno = oerrno;
256     }
257 
258 
259 /* SIGUSR1 says to exit as soon as all current connections are done. */
260 static void
handle_usr1(int sig)261 handle_usr1( int sig )
262     {
263     /* Don't need to set up the handler again, since it's a one-shot. */
264 
265     if ( num_connects == 0 )
266 	{
267 	/* If there are no active connections we want to exit immediately
268 	** here.  Not only is it faster, but without any connections the
269 	** main loop won't wake up until the next new connection.
270 	*/
271 	shut_down();
272 	syslog( LOG_NOTICE, "exiting" );
273 	closelog();
274 	exit( 0 );
275 	}
276 
277     /* Otherwise, just set a flag that we got the signal. */
278     got_usr1 = 1;
279 
280     /* Don't need to restore old errno, since we didn't do any syscalls. */
281     }
282 
283 
284 /* SIGUSR2 says to generate the stats syslogs immediately. */
285 static void
handle_usr2(int sig)286 handle_usr2( int sig )
287     {
288     const int oerrno = errno;
289 
290 #ifndef HAVE_SIGSET
291     /* Set up handler again. */
292     (void) signal( SIGUSR2, handle_usr2 );
293 #endif /* ! HAVE_SIGSET */
294 
295     logstats( (struct timeval*) 0 );
296 
297     /* Restore previous errno. */
298     errno = oerrno;
299     }
300 
301 
302 /* SIGALRM is used as a watchdog. */
303 static void
handle_alrm(int sig)304 handle_alrm( int sig )
305     {
306     const int oerrno = errno;
307 
308     /* If nothing has been happening */
309     if ( ! watchdog_flag )
310 	{
311 	/* Try changing dirs to someplace we can write. */
312 	(void) chdir( "/tmp" );
313 	/* Dump core. */
314 	abort();
315 	}
316     watchdog_flag = 0;
317 
318 #ifndef HAVE_SIGSET
319     /* Set up handler again. */
320     (void) signal( SIGALRM, handle_alrm );
321 #endif /* ! HAVE_SIGSET */
322     /* Set up alarm again. */
323     (void) alarm( OCCASIONAL_TIME * 3 );
324 
325     /* Restore previous errno. */
326     errno = oerrno;
327     }
328 
329 
330 static void
re_open_logfile(void)331 re_open_logfile( void )
332     {
333     FILE* logfp;
334     int retchmod;
335 
336     if ( no_log || hs == (httpd_server*) 0 )
337 	return;
338 
339     /* Re-open the log file. */
340     if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 )
341 	{
342 	syslog( LOG_NOTICE, "re-opening logfile" );
343 	logfp = fopen( logfile, "a" );
344 	retchmod = chmod( logfile, S_IRUSR|S_IWUSR|S_IRGRP );
345 	if ( logfp == (FILE*) 0 || retchmod != 0 )
346 	    {
347 	    syslog( LOG_CRIT, "re-opening %.80s - %m", logfile );
348 	    return;
349 	    }
350 	(void) fcntl( fileno( logfp ), F_SETFD, 1 );
351 	httpd_set_logfp( hs, logfp );
352 	}
353     }
354 
355 
356 int
main(int argc,char ** argv)357 main( int argc, char** argv )
358     {
359     char* cp;
360     struct passwd* pwd;
361     uid_t uid = 32767;
362     gid_t gid = 32767;
363     char cwd[MAXPATHLEN+1];
364     FILE* logfp;
365     int retchmod;
366     int num_ready;
367     int cnum;
368     connecttab* c;
369     httpd_conn* hc;
370     httpd_sockaddr sa4;
371     httpd_sockaddr sa6;
372     int gotv4, gotv6;
373     struct timeval tv;
374 
375     argv0 = argv[0];
376 
377     cp = strrchr( argv0, '/' );
378     if ( cp != (char*) 0 )
379 	++cp;
380     else
381 	cp = argv0;
382     openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY );
383 
384     /* Handle command-line arguments. */
385     parse_args( argc, argv );
386 
387     /* Read zone info now, in case we chroot(). */
388     tzset();
389 
390     /* Look up hostname now, in case we chroot(). */
391     lookup_hostname( &sa4, sizeof(sa4), &gotv4, &sa6, sizeof(sa6), &gotv6 );
392     if ( ! ( gotv4 || gotv6 ) )
393 	{
394 	syslog( LOG_ERR, "can't find any valid address" );
395 	(void) fprintf( stderr, "%s: can't find any valid address\n", argv0 );
396 	exit( 1 );
397 	}
398 
399     /* Throttle file. */
400     numthrottles = 0;
401     maxthrottles = 0;
402     throttles = (throttletab*) 0;
403     if ( throttlefile != (char*) 0 )
404 	read_throttlefile( throttlefile );
405 
406     /* If we're root and we're going to become another user, get the uid/gid
407     ** now.
408     */
409     if ( getuid() == 0 )
410 	{
411 	pwd = getpwnam( user );
412 	if ( pwd == (struct passwd*) 0 )
413 	    {
414 	    syslog( LOG_CRIT, "unknown user - '%.80s'", user );
415 	    (void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user );
416 	    exit( 1 );
417 	    }
418 	uid = pwd->pw_uid;
419 	gid = pwd->pw_gid;
420 	}
421 
422     /* Log file. */
423     if ( logfile != (char*) 0 )
424 	{
425 	if ( strcmp( logfile, "/dev/null" ) == 0 )
426 	    {
427 	    no_log = 1;
428 	    logfp = (FILE*) 0;
429 	    }
430 	else if ( strcmp( logfile, "-" ) == 0 )
431 	    logfp = stdout;
432 	else
433 	    {
434 	    logfp = fopen( logfile, "a" );
435 	    retchmod = chmod( logfile, S_IRUSR|S_IWUSR|S_IRGRP );
436 	    if ( logfp == (FILE*) 0 || retchmod != 0 )
437 		{
438 		syslog( LOG_CRIT, "%.80s - %m", logfile );
439 		perror( logfile );
440 		exit( 1 );
441 		}
442 	    if ( logfile[0] != '/' )
443 		{
444 		syslog( LOG_WARNING, "logfile is not an absolute path, you may not be able to re-open it" );
445 		(void) fprintf( stderr, "%s: logfile is not an absolute path, you may not be able to re-open it\n", argv0 );
446 		}
447 	    (void) fcntl( fileno( logfp ), F_SETFD, 1 );
448 	    if ( getuid() == 0 )
449 		{
450 		/* If we are root then we chown the log file to the user we'll
451 		** be switching to.
452 		*/
453 		if ( fchown( fileno( logfp ), uid, gid ) < 0 )
454 		    {
455 		    syslog( LOG_WARNING, "fchown logfile - %m" );
456 		    perror( "fchown logfile" );
457 		    }
458 		}
459 	    }
460 	}
461     else
462 	logfp = (FILE*) 0;
463 
464     /* Switch directories if requested. */
465     if ( dir != (char*) 0 )
466 	{
467 	if ( chdir( dir ) < 0 )
468 	    {
469 	    syslog( LOG_CRIT, "chdir - %m" );
470 	    perror( "chdir" );
471 	    exit( 1 );
472 	    }
473 	}
474 #ifdef USE_USER_DIR
475     else if ( getuid() == 0 )
476 	{
477 	/* No explicit directory was specified, we're root, and the
478 	** USE_USER_DIR option is set - switch to the specified user's
479 	** home dir.
480 	*/
481 	if ( chdir( pwd->pw_dir ) < 0 )
482 	    {
483 	    syslog( LOG_CRIT, "chdir - %m" );
484 	    perror( "chdir" );
485 	    exit( 1 );
486 	    }
487 	}
488 #endif /* USE_USER_DIR */
489 
490     /* Get current directory. */
491     (void) getcwd( cwd, sizeof(cwd) - 1 );
492     if ( cwd[strlen( cwd ) - 1] != '/' )
493 	(void) strcat( cwd, "/" );
494 
495     if ( ! debug )
496 	{
497 	/* We're not going to use stdin stdout or stderr from here on, so close
498 	** them to save file descriptors.
499 	*/
500 	(void) fclose( stdin );
501 	if ( logfp != stdout )
502 	    (void) fclose( stdout );
503 	(void) fclose( stderr );
504 
505 	/* Daemonize - make ourselves a subprocess. */
506 #ifdef HAVE_DAEMON
507 	if ( daemon( 1, 1 ) < 0 )
508 	    {
509 	    syslog( LOG_CRIT, "daemon - %m" );
510 	    exit( 1 );
511 	    }
512 #else /* HAVE_DAEMON */
513 	switch ( fork() )
514 	    {
515 	    case 0:
516 	    break;
517 	    case -1:
518 	    syslog( LOG_CRIT, "fork - %m" );
519 	    exit( 1 );
520 	    default:
521 	    exit( 0 );
522 	    }
523 #ifdef HAVE_SETSID
524         (void) setsid();
525 #endif /* HAVE_SETSID */
526 #endif /* HAVE_DAEMON */
527 	}
528     else
529 	{
530 	/* Even if we don't daemonize, we still want to disown our parent
531 	** process.
532 	*/
533 #ifdef HAVE_SETSID
534         (void) setsid();
535 #endif /* HAVE_SETSID */
536 	}
537 
538     if ( pidfile != (char*) 0 )
539 	{
540 	/* Write the PID file. */
541 	FILE* pidfp = fopen( pidfile, "w" );
542 	if ( pidfp == (FILE*) 0 )
543 	    {
544 	    syslog( LOG_CRIT, "%.80s - %m", pidfile );
545 	    exit( 1 );
546 	    }
547 	(void) fprintf( pidfp, "%d\n", (int) getpid() );
548 	(void) fclose( pidfp );
549 	}
550 
551     /* Initialize the fdwatch package.  Have to do this before chroot,
552     ** if /dev/poll is used.
553     */
554     max_connects = fdwatch_get_nfiles();
555     if ( max_connects < 0 )
556 	{
557 	syslog( LOG_CRIT, "fdwatch initialization failure" );
558 	exit( 1 );
559 	}
560     max_connects -= SPARE_FDS;
561 
562     /* Chroot if requested. */
563     if ( do_chroot )
564 	{
565 	if ( chroot( cwd ) < 0 )
566 	    {
567 	    syslog( LOG_CRIT, "chroot - %m" );
568 	    perror( "chroot" );
569 	    exit( 1 );
570 	    }
571 	/* If we're logging and the logfile's pathname begins with the
572 	** chroot tree's pathname, then elide the chroot pathname so
573 	** that the logfile pathname still works from inside the chroot
574 	** tree.
575 	*/
576 	if ( logfile != (char*) 0 && strcmp( logfile, "-" ) != 0 )
577 	    {
578 	    if ( strncmp( logfile, cwd, strlen( cwd ) ) == 0 )
579 		{
580 		(void) ol_strcpy( logfile, &logfile[strlen( cwd ) - 1] );
581 		/* (We already guaranteed that cwd ends with a slash, so leaving
582 		** that slash in logfile makes it an absolute pathname within
583 		** the chroot tree.)
584 		*/
585 		}
586 	    else
587 		{
588 		syslog( LOG_WARNING, "logfile is not within the chroot tree, you will not be able to re-open it" );
589 		(void) fprintf( stderr, "%s: logfile is not within the chroot tree, you will not be able to re-open it\n", argv0 );
590 		}
591 	    }
592 	(void) strcpy( cwd, "/" );
593 	/* Always chdir to / after a chroot. */
594 	if ( chdir( cwd ) < 0 )
595 	    {
596 	    syslog( LOG_CRIT, "chroot chdir - %m" );
597 	    perror( "chroot chdir" );
598 	    exit( 1 );
599 	    }
600 	}
601 
602     /* Switch directories again if requested. */
603     if ( data_dir != (char*) 0 )
604 	{
605 	if ( chdir( data_dir ) < 0 )
606 	    {
607 	    syslog( LOG_CRIT, "data_dir chdir - %m" );
608 	    perror( "data_dir chdir" );
609 	    exit( 1 );
610 	    }
611 	}
612 
613     /* Set up to catch signals. */
614 #ifdef HAVE_SIGSET
615     (void) sigset( SIGTERM, handle_term );
616     (void) sigset( SIGINT, handle_term );
617     (void) sigset( SIGCHLD, handle_chld );
618     (void) sigset( SIGPIPE, SIG_IGN );          /* get EPIPE instead */
619     (void) sigset( SIGHUP, handle_hup );
620     (void) sigset( SIGUSR1, handle_usr1 );
621     (void) sigset( SIGUSR2, handle_usr2 );
622     (void) sigset( SIGALRM, handle_alrm );
623 #else /* HAVE_SIGSET */
624     (void) signal( SIGTERM, handle_term );
625     (void) signal( SIGINT, handle_term );
626     (void) signal( SIGCHLD, handle_chld );
627     (void) signal( SIGPIPE, SIG_IGN );          /* get EPIPE instead */
628     (void) signal( SIGHUP, handle_hup );
629     (void) signal( SIGUSR1, handle_usr1 );
630     (void) signal( SIGUSR2, handle_usr2 );
631     (void) signal( SIGALRM, handle_alrm );
632 #endif /* HAVE_SIGSET */
633     got_hup = 0;
634     got_usr1 = 0;
635     watchdog_flag = 0;
636     (void) alarm( OCCASIONAL_TIME * 3 );
637 
638     /* Initialize the timer package. */
639     tmr_init();
640 
641     /* Initialize the HTTP layer.  Got to do this before giving up root,
642     ** so that we can bind to a privileged port.
643     */
644     hs = httpd_initialize(
645 	hostname,
646 	gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0,
647 	port, cgi_pattern, cgi_limit, charset, p3p, max_age, cwd, no_log, logfp,
648 	no_symlink_check, do_vhost, do_global_passwd, url_pattern,
649 	local_pattern, no_empty_referrers );
650     if ( hs == (httpd_server*) 0 )
651 	exit( 1 );
652 
653     /* Set up the occasional timer. */
654     if ( tmr_create( (struct timeval*) 0, occasional, JunkClientData, OCCASIONAL_TIME * 1000L, 1 ) == (Timer*) 0 )
655 	{
656 	syslog( LOG_CRIT, "tmr_create(occasional) failed" );
657 	exit( 1 );
658 	}
659     /* Set up the idle timer. */
660     if ( tmr_create( (struct timeval*) 0, idle, JunkClientData, 5 * 1000L, 1 ) == (Timer*) 0 )
661 	{
662 	syslog( LOG_CRIT, "tmr_create(idle) failed" );
663 	exit( 1 );
664 	}
665     if ( numthrottles > 0 )
666 	{
667 	/* Set up the throttles timer. */
668 	if ( tmr_create( (struct timeval*) 0, update_throttles, JunkClientData, THROTTLE_TIME * 1000L, 1 ) == (Timer*) 0 )
669 	    {
670 	    syslog( LOG_CRIT, "tmr_create(update_throttles) failed" );
671 	    exit( 1 );
672 	    }
673 	}
674 #ifdef STATS_TIME
675     /* Set up the stats timer. */
676     if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 )
677 	{
678 	syslog( LOG_CRIT, "tmr_create(show_stats) failed" );
679 	exit( 1 );
680 	}
681 #endif /* STATS_TIME */
682     start_time = stats_time = time( (time_t*) 0 );
683     stats_connections = 0;
684     stats_bytes = 0;
685     stats_simultaneous = 0;
686 
687     /* If we're root, try to become someone else. */
688     if ( getuid() == 0 )
689 	{
690 	/* Set aux groups to null. */
691 	if ( setgroups( 0, (const gid_t*) 0 ) < 0 )
692 	    {
693 	    syslog( LOG_CRIT, "setgroups - %m" );
694 	    exit( 1 );
695 	    }
696 	/* Set primary group. */
697 	if ( setgid( gid ) < 0 )
698 	    {
699 	    syslog( LOG_CRIT, "setgid - %m" );
700 	    exit( 1 );
701 	    }
702 	/* Try setting aux groups correctly - not critical if this fails. */
703 	if ( initgroups( user, gid ) < 0 )
704 	    syslog( LOG_WARNING, "initgroups - %m" );
705 #ifdef HAVE_SETLOGIN
706 	/* Set login name. */
707         (void) setlogin( user );
708 #endif /* HAVE_SETLOGIN */
709 	/* Set uid. */
710 	if ( setuid( uid ) < 0 )
711 	    {
712 	    syslog( LOG_CRIT, "setuid - %m" );
713 	    exit( 1 );
714 	    }
715 	/* Check for unnecessary security exposure. */
716 	if ( ! do_chroot )
717 	    syslog(
718 		LOG_WARNING,
719 		"started as root without requesting chroot(), warning only" );
720 	}
721 
722     /* Initialize our connections table. */
723     connects = NEW( connecttab, max_connects );
724     if ( connects == (connecttab*) 0 )
725 	{
726 	syslog( LOG_CRIT, "out of memory allocating a connecttab" );
727 	exit( 1 );
728 	}
729     for ( cnum = 0; cnum < max_connects; ++cnum )
730 	{
731 	connects[cnum].conn_state = CNST_FREE;
732 	connects[cnum].next_free_connect = cnum + 1;
733 	connects[cnum].hc = (httpd_conn*) 0;
734 	}
735     connects[max_connects - 1].next_free_connect = -1;	/* end of link list */
736     first_free_connect = 0;
737     num_connects = 0;
738     httpd_conn_count = 0;
739 
740     if ( hs != (httpd_server*) 0 )
741 	{
742 	if ( hs->listen4_fd != -1 )
743 	    fdwatch_add_fd( hs->listen4_fd, (void*) 0, FDW_READ );
744 	if ( hs->listen6_fd != -1 )
745 	    fdwatch_add_fd( hs->listen6_fd, (void*) 0, FDW_READ );
746 	}
747 
748     /* Main loop. */
749     (void) gettimeofday( &tv, (struct timezone*) 0 );
750     while ( ( ! terminate ) || num_connects > 0 )
751 	{
752 	/* Do we need to re-open the log file? */
753 	if ( got_hup )
754 	    {
755 	    re_open_logfile();
756 	    got_hup = 0;
757 	    }
758 
759 	/* Do the fd watch. */
760 	num_ready = fdwatch( tmr_mstimeout( &tv ) );
761 	if ( num_ready < 0 )
762 	    {
763 	    if ( errno == EINTR || errno == EAGAIN )
764 		continue;       /* try again */
765 	    syslog( LOG_ERR, "fdwatch - %m" );
766 	    exit( 1 );
767 	    }
768 	(void) gettimeofday( &tv, (struct timezone*) 0 );
769 
770 	if ( num_ready == 0 )
771 	    {
772 	    /* No fd's are ready - run the timers. */
773 	    tmr_run( &tv );
774 	    continue;
775 	    }
776 
777 	/* Is it a new connection? */
778 	if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 &&
779 	     fdwatch_check_fd( hs->listen6_fd ) )
780 	    {
781 	    if ( handle_newconnect( &tv, hs->listen6_fd ) )
782 		/* Go around the loop and do another fdwatch, rather than
783 		** dropping through and processing existing connections.
784 		** New connections always get priority.
785 		*/
786 		continue;
787 	    }
788 	if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 &&
789 	     fdwatch_check_fd( hs->listen4_fd ) )
790 	    {
791 	    if ( handle_newconnect( &tv, hs->listen4_fd ) )
792 		/* Go around the loop and do another fdwatch, rather than
793 		** dropping through and processing existing connections.
794 		** New connections always get priority.
795 		*/
796 		continue;
797 	    }
798 
799 	/* Find the connections that need servicing. */
800 	while ( ( c = (connecttab*) fdwatch_get_next_client_data() ) != (connecttab*) -1 )
801 	    {
802 	    if ( c == (connecttab*) 0 )
803 		continue;
804 	    hc = c->hc;
805 	    if ( ! fdwatch_check_fd( hc->conn_fd ) )
806 		/* Something went wrong. */
807 		clear_connection( c, &tv );
808 	    else
809 		switch ( c->conn_state )
810 		    {
811 		    case CNST_READING: handle_read( c, &tv ); break;
812 		    case CNST_SENDING: handle_send( c, &tv ); break;
813 		    case CNST_LINGERING: handle_linger( c, &tv ); break;
814 		    }
815 	    }
816 	tmr_run( &tv );
817 
818 	if ( got_usr1 && ! terminate )
819 	    {
820 	    terminate = 1;
821 	    if ( hs != (httpd_server*) 0 )
822 		{
823 		if ( hs->listen4_fd != -1 )
824 		    fdwatch_del_fd( hs->listen4_fd );
825 		if ( hs->listen6_fd != -1 )
826 		    fdwatch_del_fd( hs->listen6_fd );
827 		httpd_unlisten( hs );
828 		}
829 	    }
830 	}
831 
832     /* The main loop terminated. */
833     shut_down();
834     syslog( LOG_NOTICE, "exiting" );
835     closelog();
836     exit( 0 );
837     }
838 
839 
840 static void
parse_args(int argc,char ** argv)841 parse_args( int argc, char** argv )
842     {
843     int argn;
844 
845     debug = 0;
846     port = DEFAULT_PORT;
847     dir = (char*) 0;
848     data_dir = (char*) 0;
849 #ifdef ALWAYS_CHROOT
850     do_chroot = 1;
851 #else /* ALWAYS_CHROOT */
852     do_chroot = 0;
853 #endif /* ALWAYS_CHROOT */
854     no_log = 0;
855     no_symlink_check = do_chroot;
856 #ifdef ALWAYS_VHOST
857     do_vhost = 1;
858 #else /* ALWAYS_VHOST */
859     do_vhost = 0;
860 #endif /* ALWAYS_VHOST */
861 #ifdef ALWAYS_GLOBAL_PASSWD
862     do_global_passwd = 1;
863 #else /* ALWAYS_GLOBAL_PASSWD */
864     do_global_passwd = 0;
865 #endif /* ALWAYS_GLOBAL_PASSWD */
866 #ifdef CGI_PATTERN
867     cgi_pattern = CGI_PATTERN;
868 #else /* CGI_PATTERN */
869     cgi_pattern = (char*) 0;
870 #endif /* CGI_PATTERN */
871 #ifdef CGI_LIMIT
872     cgi_limit = CGI_LIMIT;
873 #else /* CGI_LIMIT */
874     cgi_limit = 0;
875 #endif /* CGI_LIMIT */
876     url_pattern = (char*) 0;
877     no_empty_referrers = 0;
878     local_pattern = (char*) 0;
879     throttlefile = (char*) 0;
880     hostname = (char*) 0;
881     logfile = (char*) 0;
882     pidfile = (char*) 0;
883     user = DEFAULT_USER;
884     charset = DEFAULT_CHARSET;
885     p3p = "";
886     max_age = -1;
887     argn = 1;
888     while ( argn < argc && argv[argn][0] == '-' )
889 	{
890 	if ( strcmp( argv[argn], "-V" ) == 0 )
891 	    {
892 	    (void) printf( "%s\n", SERVER_SOFTWARE );
893 	    exit( 0 );
894 	    }
895 	else if ( strcmp( argv[argn], "-C" ) == 0 && argn + 1 < argc )
896 	    {
897 	    ++argn;
898 	    read_config( argv[argn] );
899 	    }
900 	else if ( strcmp( argv[argn], "-p" ) == 0 && argn + 1 < argc )
901 	    {
902 	    ++argn;
903 	    port = (unsigned short) atoi( argv[argn] );
904 	    }
905 	else if ( strcmp( argv[argn], "-d" ) == 0 && argn + 1 < argc )
906 	    {
907 	    ++argn;
908 	    dir = argv[argn];
909 	    }
910 	else if ( strcmp( argv[argn], "-r" ) == 0 )
911 	    {
912 	    do_chroot = 1;
913 	    no_symlink_check = 1;
914 	    }
915 	else if ( strcmp( argv[argn], "-nor" ) == 0 )
916 	    {
917 	    do_chroot = 0;
918 	    no_symlink_check = 0;
919 	    }
920 	else if ( strcmp( argv[argn], "-dd" ) == 0 && argn + 1 < argc )
921 	    {
922 	    ++argn;
923 	    data_dir = argv[argn];
924 	    }
925 	else if ( strcmp( argv[argn], "-s" ) == 0 )
926 	    no_symlink_check = 0;
927 	else if ( strcmp( argv[argn], "-nos" ) == 0 )
928 	    no_symlink_check = 1;
929 	else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc )
930 	    {
931 	    ++argn;
932 	    user = argv[argn];
933 	    }
934 	else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc )
935 	    {
936 	    ++argn;
937 	    cgi_pattern = argv[argn];
938 	    }
939 	else if ( strcmp( argv[argn], "-t" ) == 0 && argn + 1 < argc )
940 	    {
941 	    ++argn;
942 	    throttlefile = argv[argn];
943 	    }
944 	else if ( strcmp( argv[argn], "-h" ) == 0 && argn + 1 < argc )
945 	    {
946 	    ++argn;
947 	    hostname = argv[argn];
948 	    }
949 	else if ( strcmp( argv[argn], "-l" ) == 0 && argn + 1 < argc )
950 	    {
951 	    ++argn;
952 	    logfile = argv[argn];
953 	    }
954 	else if ( strcmp( argv[argn], "-v" ) == 0 )
955 	    do_vhost = 1;
956 	else if ( strcmp( argv[argn], "-nov" ) == 0 )
957 	    do_vhost = 0;
958 	else if ( strcmp( argv[argn], "-g" ) == 0 )
959 	    do_global_passwd = 1;
960 	else if ( strcmp( argv[argn], "-nog" ) == 0 )
961 	    do_global_passwd = 0;
962 	else if ( strcmp( argv[argn], "-i" ) == 0 && argn + 1 < argc )
963 	    {
964 	    ++argn;
965 	    pidfile = argv[argn];
966 	    }
967 	else if ( strcmp( argv[argn], "-T" ) == 0 && argn + 1 < argc )
968 	    {
969 	    ++argn;
970 	    charset = argv[argn];
971 	    }
972 	else if ( strcmp( argv[argn], "-P" ) == 0 && argn + 1 < argc )
973 	    {
974 	    ++argn;
975 	    p3p = argv[argn];
976 	    }
977 	else if ( strcmp( argv[argn], "-M" ) == 0 && argn + 1 < argc )
978 	    {
979 	    ++argn;
980 	    max_age = atoi( argv[argn] );
981 	    }
982 	else if ( strcmp( argv[argn], "-D" ) == 0 )
983 	    debug = 1;
984 	else
985 	    usage();
986 	++argn;
987 	}
988     if ( argn != argc )
989 	usage();
990     }
991 
992 
993 static void
usage(void)994 usage( void )
995     {
996     (void) fprintf( stderr,
997 "usage:  %s [-C configfile] [-p port] [-d dir] [-r|-nor] [-dd data_dir] [-s|-nos] [-v|-nov] [-g|-nog] [-u user] [-c cgipat] [-t throttles] [-h host] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage] [-V] [-D]\n",
998 	argv0 );
999     exit( 1 );
1000     }
1001 
1002 
1003 static void
read_config(char * filename)1004 read_config( char* filename )
1005     {
1006     FILE* fp;
1007     char line[10000];
1008     char* cp;
1009     char* cp2;
1010     char* name;
1011     char* value;
1012 
1013     fp = fopen( filename, "r" );
1014     if ( fp == (FILE*) 0 )
1015 	{
1016 	perror( filename );
1017 	exit( 1 );
1018 	}
1019 
1020     while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
1021 	{
1022 	/* Trim comments. */
1023 	if ( ( cp = strchr( line, '#' ) ) != (char*) 0 )
1024 	    *cp = '\0';
1025 
1026 	/* Skip leading whitespace. */
1027 	cp = line;
1028 	cp += strspn( cp, " \t\n\r" );
1029 
1030 	/* Split line into words. */
1031 	while ( *cp != '\0' )
1032 	    {
1033 	    /* Find next whitespace. */
1034 	    cp2 = cp + strcspn( cp, " \t\n\r" );
1035 	    /* Insert EOS and advance next-word pointer. */
1036 	    while ( *cp2 == ' ' || *cp2 == '\t' || *cp2 == '\n' || *cp2 == '\r' )
1037 		*cp2++ = '\0';
1038 	    /* Split into name and value. */
1039 	    name = cp;
1040 	    value = strchr( name, '=' );
1041 	    if ( value != (char*) 0 )
1042 		*value++ = '\0';
1043 	    /* Interpret. */
1044 	    if ( strcasecmp( name, "debug" ) == 0 )
1045 		{
1046 		no_value_required( name, value );
1047 		debug = 1;
1048 		}
1049 	    else if ( strcasecmp( name, "port" ) == 0 )
1050 		{
1051 		value_required( name, value );
1052 		port = (unsigned short) atoi( value );
1053 		}
1054 	    else if ( strcasecmp( name, "dir" ) == 0 )
1055 		{
1056 		value_required( name, value );
1057 		dir = e_strdup( value );
1058 		}
1059 	    else if ( strcasecmp( name, "chroot" ) == 0 )
1060 		{
1061 		no_value_required( name, value );
1062 		do_chroot = 1;
1063 		no_symlink_check = 1;
1064 		}
1065 	    else if ( strcasecmp( name, "nochroot" ) == 0 )
1066 		{
1067 		no_value_required( name, value );
1068 		do_chroot = 0;
1069 		no_symlink_check = 0;
1070 		}
1071 	    else if ( strcasecmp( name, "data_dir" ) == 0 )
1072 		{
1073 		value_required( name, value );
1074 		data_dir = e_strdup( value );
1075 		}
1076 	    else if ( strcasecmp( name, "nosymlinkcheck" ) == 0 )
1077 		{
1078 		no_value_required( name, value );
1079 		no_symlink_check = 1;
1080 		}
1081 	    else if ( strcasecmp( name, "symlinkcheck" ) == 0 )
1082 		{
1083 		no_value_required( name, value );
1084 		no_symlink_check = 0;
1085 		}
1086 	    else if ( strcasecmp( name, "user" ) == 0 )
1087 		{
1088 		value_required( name, value );
1089 		user = e_strdup( value );
1090 		}
1091 	    else if ( strcasecmp( name, "cgipat" ) == 0 )
1092 		{
1093 		value_required( name, value );
1094 		cgi_pattern = e_strdup( value );
1095 		}
1096 	    else if ( strcasecmp( name, "cgilimit" ) == 0 )
1097 		{
1098 		value_required( name, value );
1099 		cgi_limit = atoi( value );
1100 		}
1101 	    else if ( strcasecmp( name, "urlpat" ) == 0 )
1102 		{
1103 		value_required( name, value );
1104 		url_pattern = e_strdup( value );
1105 		}
1106 	    else if ( strcasecmp( name, "noemptyreferers" ) == 0 ||
1107 	              strcasecmp( name, "noemptyreferrers" ) == 0 )
1108 		{
1109 		no_value_required( name, value );
1110 		no_empty_referrers = 1;
1111 		}
1112 	    else if ( strcasecmp( name, "localpat" ) == 0 )
1113 		{
1114 		value_required( name, value );
1115 		local_pattern = e_strdup( value );
1116 		}
1117 	    else if ( strcasecmp( name, "throttles" ) == 0 )
1118 		{
1119 		value_required( name, value );
1120 		throttlefile = e_strdup( value );
1121 		}
1122 	    else if ( strcasecmp( name, "host" ) == 0 )
1123 		{
1124 		value_required( name, value );
1125 		hostname = e_strdup( value );
1126 		}
1127 	    else if ( strcasecmp( name, "logfile" ) == 0 )
1128 		{
1129 		value_required( name, value );
1130 		logfile = e_strdup( value );
1131 		}
1132 	    else if ( strcasecmp( name, "vhost" ) == 0 )
1133 		{
1134 		no_value_required( name, value );
1135 		do_vhost = 1;
1136 		}
1137 	    else if ( strcasecmp( name, "novhost" ) == 0 )
1138 		{
1139 		no_value_required( name, value );
1140 		do_vhost = 0;
1141 		}
1142 	    else if ( strcasecmp( name, "globalpasswd" ) == 0 )
1143 		{
1144 		no_value_required( name, value );
1145 		do_global_passwd = 1;
1146 		}
1147 	    else if ( strcasecmp( name, "noglobalpasswd" ) == 0 )
1148 		{
1149 		no_value_required( name, value );
1150 		do_global_passwd = 0;
1151 		}
1152 	    else if ( strcasecmp( name, "pidfile" ) == 0 )
1153 		{
1154 		value_required( name, value );
1155 		pidfile = e_strdup( value );
1156 		}
1157 	    else if ( strcasecmp( name, "charset" ) == 0 )
1158 		{
1159 		value_required( name, value );
1160 		charset = e_strdup( value );
1161 		}
1162 	    else if ( strcasecmp( name, "p3p" ) == 0 )
1163 		{
1164 		value_required( name, value );
1165 		p3p = e_strdup( value );
1166 		}
1167 	    else if ( strcasecmp( name, "max_age" ) == 0 )
1168 		{
1169 		value_required( name, value );
1170 		max_age = atoi( value );
1171 		}
1172 	    else
1173 		{
1174 		(void) fprintf(
1175 		    stderr, "%s: unknown config option '%s'\n", argv0, name );
1176 		exit( 1 );
1177 		}
1178 
1179 	    /* Advance to next word. */
1180 	    cp = cp2;
1181 	    cp += strspn( cp, " \t\n\r" );
1182 	    }
1183 	}
1184 
1185     (void) fclose( fp );
1186     }
1187 
1188 
1189 static void
value_required(char * name,char * value)1190 value_required( char* name, char* value )
1191     {
1192     if ( value == (char*) 0 )
1193 	{
1194 	(void) fprintf(
1195 	    stderr, "%s: value required for %s option\n", argv0, name );
1196 	exit( 1 );
1197 	}
1198     }
1199 
1200 
1201 static void
no_value_required(char * name,char * value)1202 no_value_required( char* name, char* value )
1203     {
1204     if ( value != (char*) 0 )
1205 	{
1206 	(void) fprintf(
1207 	    stderr, "%s: no value required for %s option\n",
1208 	    argv0, name );
1209 	exit( 1 );
1210 	}
1211     }
1212 
1213 
1214 static char*
e_strdup(char * oldstr)1215 e_strdup( char* oldstr )
1216     {
1217     char* newstr;
1218 
1219     newstr = strdup( oldstr );
1220     if ( newstr == (char*) 0 )
1221 	{
1222 	syslog( LOG_CRIT, "out of memory copying a string" );
1223 	(void) fprintf( stderr, "%s: out of memory copying a string\n", argv0 );
1224 	exit( 1 );
1225 	}
1226     return newstr;
1227     }
1228 
1229 
1230 static void
lookup_hostname(httpd_sockaddr * sa4P,size_t sa4_len,int * gotv4P,httpd_sockaddr * sa6P,size_t sa6_len,int * gotv6P)1231 lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P )
1232     {
1233 #ifdef USE_IPV6
1234 
1235     struct addrinfo hints;
1236     char portstr[10];
1237     int gaierr;
1238     struct addrinfo* ai;
1239     struct addrinfo* ai2;
1240     struct addrinfo* aiv6;
1241     struct addrinfo* aiv4;
1242 
1243     (void) memset( &hints, 0, sizeof(hints) );
1244     hints.ai_family = PF_UNSPEC;
1245     hints.ai_flags = AI_PASSIVE;
1246     hints.ai_socktype = SOCK_STREAM;
1247     (void) snprintf( portstr, sizeof(portstr), "%d", (int) port );
1248     if ( (gaierr = getaddrinfo( hostname, portstr, &hints, &ai )) != 0 )
1249 	{
1250 	syslog(
1251 	    LOG_CRIT, "getaddrinfo %.80s - %.80s",
1252 	    hostname, gai_strerror( gaierr ) );
1253 	(void) fprintf(
1254 	    stderr, "%s: getaddrinfo %s - %s\n",
1255 	    argv0, hostname, gai_strerror( gaierr ) );
1256 	exit( 1 );
1257 	}
1258 
1259     /* Find the first IPv6 and IPv4 entries. */
1260     aiv6 = (struct addrinfo*) 0;
1261     aiv4 = (struct addrinfo*) 0;
1262     for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
1263 	{
1264 	switch ( ai2->ai_family )
1265 	    {
1266 	    case AF_INET6:
1267 	    if ( aiv6 == (struct addrinfo*) 0 )
1268 		aiv6 = ai2;
1269 	    break;
1270 	    case AF_INET:
1271 	    if ( aiv4 == (struct addrinfo*) 0 )
1272 		aiv4 = ai2;
1273 	    break;
1274 	    }
1275 	}
1276 
1277     if ( aiv6 == (struct addrinfo*) 0 )
1278 	*gotv6P = 0;
1279     else
1280 	{
1281 	if ( sa6_len < aiv6->ai_addrlen )
1282 	    {
1283 	    syslog(
1284 		LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)",
1285 		hostname, (unsigned long) sa6_len,
1286 		(unsigned long) aiv6->ai_addrlen );
1287 	    exit( 1 );
1288 	    }
1289 	(void) memset( sa6P, 0, sa6_len );
1290 	(void) memmove( sa6P, aiv6->ai_addr, aiv6->ai_addrlen );
1291 	*gotv6P = 1;
1292 	}
1293 
1294     if ( aiv4 == (struct addrinfo*) 0 )
1295 	*gotv4P = 0;
1296     else
1297 	{
1298 	if ( sa4_len < aiv4->ai_addrlen )
1299 	    {
1300 	    syslog(
1301 		LOG_CRIT, "%.80s - sockaddr too small (%lu < %lu)",
1302 		hostname, (unsigned long) sa4_len,
1303 		(unsigned long) aiv4->ai_addrlen );
1304 	    exit( 1 );
1305 	    }
1306 	(void) memset( sa4P, 0, sa4_len );
1307 	(void) memmove( sa4P, aiv4->ai_addr, aiv4->ai_addrlen );
1308 	*gotv4P = 1;
1309 	}
1310 
1311     freeaddrinfo( ai );
1312 
1313 #else /* USE_IPV6 */
1314 
1315     struct hostent* he;
1316 
1317     *gotv6P = 0;
1318 
1319     (void) memset( sa4P, 0, sa4_len );
1320     sa4P->sa.sa_family = AF_INET;
1321     if ( hostname == (char*) 0 )
1322 	sa4P->sa_in.sin_addr.s_addr = htonl( INADDR_ANY );
1323     else
1324 	{
1325 	sa4P->sa_in.sin_addr.s_addr = inet_addr( hostname );
1326 	if ( (int) sa4P->sa_in.sin_addr.s_addr == -1 )
1327 	    {
1328 	    he = gethostbyname( hostname );
1329 	    if ( he == (struct hostent*) 0 )
1330 		{
1331 #ifdef HAVE_HSTRERROR
1332 		syslog(
1333 		    LOG_CRIT, "gethostbyname %.80s - %.80s",
1334 		    hostname, hstrerror( h_errno ) );
1335 		(void) fprintf(
1336 		    stderr, "%s: gethostbyname %s - %s\n",
1337 		    argv0, hostname, hstrerror( h_errno ) );
1338 #else /* HAVE_HSTRERROR */
1339 		syslog( LOG_CRIT, "gethostbyname %.80s failed", hostname );
1340 		(void) fprintf(
1341 		    stderr, "%s: gethostbyname %s failed\n", argv0, hostname );
1342 #endif /* HAVE_HSTRERROR */
1343 		exit( 1 );
1344 		}
1345 	    if ( he->h_addrtype != AF_INET )
1346 		{
1347 		syslog( LOG_CRIT, "%.80s - non-IP network address", hostname );
1348 		(void) fprintf(
1349 		    stderr, "%s: %s - non-IP network address\n",
1350 		    argv0, hostname );
1351 		exit( 1 );
1352 		}
1353 	    (void) memmove(
1354 		&sa4P->sa_in.sin_addr.s_addr, he->h_addr, he->h_length );
1355 	    }
1356 	}
1357     sa4P->sa_in.sin_port = htons( port );
1358     *gotv4P = 1;
1359 
1360 #endif /* USE_IPV6 */
1361     }
1362 
1363 
1364 static void
read_throttlefile(char * tf)1365 read_throttlefile( char* tf )
1366     {
1367     FILE* fp;
1368     char buf[5000];
1369     char* cp;
1370     int len;
1371     char pattern[5000];
1372     long max_limit, min_limit;
1373     struct timeval tv;
1374 
1375     fp = fopen( tf, "r" );
1376     if ( fp == (FILE*) 0 )
1377 	{
1378 	syslog( LOG_CRIT, "%.80s - %m", tf );
1379 	perror( tf );
1380 	exit( 1 );
1381 	}
1382 
1383     (void) gettimeofday( &tv, (struct timezone*) 0 );
1384 
1385     while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 )
1386 	{
1387 	/* Nuke comments. */
1388 	cp = strchr( buf, '#' );
1389 	if ( cp != (char*) 0 )
1390 	    *cp = '\0';
1391 
1392 	/* Nuke trailing whitespace. */
1393 	len = strlen( buf );
1394 	while ( len > 0 &&
1395 		( buf[len-1] == ' ' || buf[len-1] == '\t' ||
1396 		  buf[len-1] == '\n' || buf[len-1] == '\r' ) )
1397 	    buf[--len] = '\0';
1398 
1399 	/* Ignore empty lines. */
1400 	if ( len == 0 )
1401 	    continue;
1402 
1403 	/* Parse line. */
1404 	if ( sscanf( buf, " %4900[^ \t] %ld-%ld", pattern, &min_limit, &max_limit ) == 3 )
1405 	    {}
1406 	else if ( sscanf( buf, " %4900[^ \t] %ld", pattern, &max_limit ) == 2 )
1407 	    min_limit = 0;
1408 	else
1409 	    {
1410 	    syslog( LOG_CRIT,
1411 		"unparsable line in %.80s - %.80s", tf, buf );
1412 	    (void) fprintf( stderr,
1413 		"%s: unparsable line in %.80s - %.80s\n",
1414 		argv0, tf, buf );
1415 	    continue;
1416 	    }
1417 
1418 	/* Nuke any leading slashes in pattern. */
1419 	if ( pattern[0] == '/' )
1420 	    (void) ol_strcpy( pattern, &pattern[1] );
1421 	while ( ( cp = strstr( pattern, "|/" ) ) != (char*) 0 )
1422 	    (void) ol_strcpy( cp + 1, cp + 2 );
1423 
1424 	/* Check for room in throttles. */
1425 	if ( numthrottles >= maxthrottles )
1426 	    {
1427 	    if ( maxthrottles == 0 )
1428 		{
1429 		maxthrottles = 100;     /* arbitrary */
1430 		throttles = NEW( throttletab, maxthrottles );
1431 		}
1432 	    else
1433 		{
1434 		maxthrottles *= 2;
1435 		throttles = RENEW( throttles, throttletab, maxthrottles );
1436 		}
1437 	    if ( throttles == (throttletab*) 0 )
1438 		{
1439 		syslog( LOG_CRIT, "out of memory allocating a throttletab" );
1440 		(void) fprintf(
1441 		    stderr, "%s: out of memory allocating a throttletab\n",
1442 		    argv0 );
1443 		exit( 1 );
1444 		}
1445 	    }
1446 
1447 	/* Add to table. */
1448 	throttles[numthrottles].pattern = e_strdup( pattern );
1449 	throttles[numthrottles].max_limit = max_limit;
1450 	throttles[numthrottles].min_limit = min_limit;
1451 	throttles[numthrottles].rate = 0;
1452 	throttles[numthrottles].bytes_since_avg = 0;
1453 	throttles[numthrottles].num_sending = 0;
1454 
1455 	++numthrottles;
1456 	}
1457     (void) fclose( fp );
1458     }
1459 
1460 
1461 static void
shut_down(void)1462 shut_down( void )
1463     {
1464     int cnum;
1465     struct timeval tv;
1466 
1467     (void) gettimeofday( &tv, (struct timezone*) 0 );
1468     logstats( &tv );
1469     for ( cnum = 0; cnum < max_connects; ++cnum )
1470 	{
1471 	if ( connects[cnum].conn_state != CNST_FREE )
1472 	    httpd_close_conn( connects[cnum].hc, &tv );
1473 	if ( connects[cnum].hc != (httpd_conn*) 0 )
1474 	    {
1475 	    httpd_destroy_conn( connects[cnum].hc );
1476 	    free( (void*) connects[cnum].hc );
1477 	    --httpd_conn_count;
1478 	    connects[cnum].hc = (httpd_conn*) 0;
1479 	    }
1480 	}
1481     if ( hs != (httpd_server*) 0 )
1482 	{
1483 	httpd_server* ths = hs;
1484 	hs = (httpd_server*) 0;
1485 	if ( ths->listen4_fd != -1 )
1486 	    fdwatch_del_fd( ths->listen4_fd );
1487 	if ( ths->listen6_fd != -1 )
1488 	    fdwatch_del_fd( ths->listen6_fd );
1489 	httpd_terminate( ths );
1490 	}
1491     mmc_term();
1492     tmr_term();
1493     free( (void*) connects );
1494     if ( throttles != (throttletab*) 0 )
1495 	free( (void*) throttles );
1496     }
1497 
1498 
1499 static int
handle_newconnect(struct timeval * tvP,int listen_fd)1500 handle_newconnect( struct timeval* tvP, int listen_fd )
1501     {
1502     connecttab* c;
1503     ClientData client_data;
1504 
1505     /* This loops until the accept() fails, trying to start new
1506     ** connections as fast as possible so we don't overrun the
1507     ** listen queue.
1508     */
1509     for (;;)
1510 	{
1511 	/* Is there room in the connection table? */
1512 	if ( num_connects >= max_connects )
1513 	    {
1514 	    /* Out of connection slots.  Run the timers, then the
1515 	    ** existing connections, and maybe we'll free up a slot
1516 	    ** by the time we get back here.
1517 	    */
1518 	    syslog( LOG_WARNING, "too many connections!" );
1519 	    tmr_run( tvP );
1520 	    return 0;
1521 	    }
1522 	/* Get the first free connection entry off the free list. */
1523 	if ( first_free_connect == -1 || connects[first_free_connect].conn_state != CNST_FREE )
1524 	    {
1525 	    syslog( LOG_CRIT, "the connects free list is messed up" );
1526 	    exit( 1 );
1527 	    }
1528 	c = &connects[first_free_connect];
1529 	/* Make the httpd_conn if necessary. */
1530 	if ( c->hc == (httpd_conn*) 0 )
1531 	    {
1532 	    c->hc = NEW( httpd_conn, 1 );
1533 	    if ( c->hc == (httpd_conn*) 0 )
1534 		{
1535 		syslog( LOG_CRIT, "out of memory allocating an httpd_conn" );
1536 		exit( 1 );
1537 		}
1538 	    c->hc->initialized = 0;
1539 	    ++httpd_conn_count;
1540 	    }
1541 
1542 	/* Get the connection. */
1543 	switch ( httpd_get_conn( hs, listen_fd, c->hc ) )
1544 	    {
1545 	    /* Some error happened.  Run the timers, then the
1546 	    ** existing connections.  Maybe the error will clear.
1547 	    */
1548 	    case GC_FAIL:
1549 	    tmr_run( tvP );
1550 	    return 0;
1551 
1552 	    /* No more connections to accept for now. */
1553 	    case GC_NO_MORE:
1554 	    return 1;
1555 	    }
1556 	c->conn_state = CNST_READING;
1557 	/* Pop it off the free list. */
1558 	first_free_connect = c->next_free_connect;
1559 	c->next_free_connect = -1;
1560 	++num_connects;
1561 	client_data.p = c;
1562 	c->active_at = tvP->tv_sec;
1563 	c->wakeup_timer = (Timer*) 0;
1564 	c->linger_timer = (Timer*) 0;
1565 	c->next_byte_index = 0;
1566 	c->numtnums = 0;
1567 
1568 	/* Set the connection file descriptor to no-delay mode. */
1569 	httpd_set_ndelay( c->hc->conn_fd );
1570 
1571 	fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
1572 
1573 	++stats_connections;
1574 	if ( num_connects > stats_simultaneous )
1575 	    stats_simultaneous = num_connects;
1576 	}
1577     }
1578 
1579 
1580 static void
handle_read(connecttab * c,struct timeval * tvP)1581 handle_read( connecttab* c, struct timeval* tvP )
1582     {
1583     int sz;
1584     ClientData client_data;
1585     httpd_conn* hc = c->hc;
1586 
1587     /* Is there room in our buffer to read more bytes? */
1588     if ( hc->read_idx >= hc->read_size )
1589 	{
1590 	if ( hc->read_size > 5000 )
1591 	    {
1592 	    httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1593 	    finish_connection( c, tvP );
1594 	    return;
1595 	    }
1596 	httpd_realloc_str(
1597 	    &hc->read_buf, &hc->read_size, hc->read_size + 1000 );
1598 	}
1599 
1600     /* Read some more bytes. */
1601     sz = read(
1602 	hc->conn_fd, &(hc->read_buf[hc->read_idx]),
1603 	hc->read_size - hc->read_idx );
1604     if ( sz == 0 )
1605 	{
1606 	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1607 	finish_connection( c, tvP );
1608 	return;
1609 	}
1610     if ( sz < 0 )
1611 	{
1612 	/* Ignore EINTR and EAGAIN.  Also ignore EWOULDBLOCK.  At first glance
1613 	** you would think that connections returned by fdwatch as readable
1614 	** should never give an EWOULDBLOCK; however, this apparently can
1615 	** happen if a packet gets garbled.
1616 	*/
1617 	if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK )
1618 	    return;
1619 	httpd_send_err(
1620 	    hc, 400, httpd_err400title, "", httpd_err400form, "" );
1621 	finish_connection( c, tvP );
1622 	return;
1623 	}
1624     hc->read_idx += sz;
1625     c->active_at = tvP->tv_sec;
1626 
1627     /* Do we have a complete request yet? */
1628     switch ( httpd_got_request( hc ) )
1629 	{
1630 	case GR_NO_REQUEST:
1631 	return;
1632 	case GR_BAD_REQUEST:
1633 	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
1634 	finish_connection( c, tvP );
1635 	return;
1636 	}
1637 
1638     /* Yes.  Try parsing and resolving it. */
1639     if ( httpd_parse_request( hc ) < 0 )
1640 	{
1641 	finish_connection( c, tvP );
1642 	return;
1643 	}
1644 
1645     /* Check the throttle table */
1646     if ( ! check_throttles( c ) )
1647 	{
1648 	httpd_send_err(
1649 	    hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl );
1650 	finish_connection( c, tvP );
1651 	return;
1652 	}
1653 
1654     /* Start the connection going. */
1655     if ( httpd_start_request( hc, tvP ) < 0 )
1656 	{
1657 	/* Something went wrong.  Close down the connection. */
1658 	finish_connection( c, tvP );
1659 	return;
1660 	}
1661 
1662     /* Fill in end_byte_index. */
1663     if ( hc->got_range )
1664 	{
1665 	c->next_byte_index = hc->first_byte_index;
1666 	c->end_byte_index = hc->last_byte_index + 1;
1667 	}
1668     else if ( hc->bytes_to_send < 0 )
1669 	c->end_byte_index = 0;
1670     else
1671 	c->end_byte_index = hc->bytes_to_send;
1672 
1673     /* Check if it's already handled. */
1674     if ( hc->file_address == (char*) 0 )
1675 	{
1676 	/* No file address means someone else is handling it. */
1677 	int tind;
1678 	for ( tind = 0; tind < c->numtnums; ++tind )
1679 	    throttles[c->tnums[tind]].bytes_since_avg += hc->bytes_sent;
1680 	c->next_byte_index = hc->bytes_sent;
1681 	finish_connection( c, tvP );
1682 	return;
1683 	}
1684     if ( c->next_byte_index >= c->end_byte_index )
1685 	{
1686 	/* There's nothing to send. */
1687 	finish_connection( c, tvP );
1688 	return;
1689 	}
1690 
1691     /* Cool, we have a valid connection and a file to send to it. */
1692     c->conn_state = CNST_SENDING;
1693     c->started_at = tvP->tv_sec;
1694     c->wouldblock_delay = 0;
1695     client_data.p = c;
1696 
1697     fdwatch_del_fd( hc->conn_fd );
1698     fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE );
1699     }
1700 
1701 
1702 static void
handle_send(connecttab * c,struct timeval * tvP)1703 handle_send( connecttab* c, struct timeval* tvP )
1704     {
1705     size_t max_bytes;
1706     int sz, coast;
1707     ClientData client_data;
1708     time_t elapsed;
1709     httpd_conn* hc = c->hc;
1710     int tind;
1711 
1712     if ( c->max_limit == THROTTLE_NOLIMIT )
1713 	max_bytes = 1000000000L;
1714     else
1715 	max_bytes = c->max_limit / 4;	/* send at most 1/4 seconds worth */
1716 
1717     /* Do we need to write the headers first? */
1718     if ( hc->responselen == 0 )
1719 	{
1720 	/* No, just write the file. */
1721 #ifdef USE_SENDFILE
1722 	off_t sbytes;
1723 
1724 	sz = sendfile(
1725 	     hc->file_fd, hc->conn_fd, c->next_byte_index,
1726 	     MIN( c->end_byte_index - c->next_byte_index, max_bytes ),
1727 	     NULL, &sbytes, 0 );
1728 	if (sz == -1 && errno == EAGAIN)
1729 	    sz = sbytes > 0 ? sbytes : -1;
1730 	else if (sz == 0)
1731 	    sz = sbytes;
1732 #else
1733 	sz = write(
1734 	    hc->conn_fd, &(hc->file_address[c->next_byte_index]),
1735 	    MIN( c->end_byte_index - c->next_byte_index, max_bytes ) );
1736 #endif
1737 	}
1738     else
1739 	{
1740 #ifdef USE_SENDFILE
1741 	struct sf_hdtr sf;
1742 	struct iovec iv;
1743 	off_t sbytes;
1744 
1745 	iv.iov_base = hc->response;
1746 	iv.iov_len = hc->responselen;
1747 	sf.headers = &iv;
1748 	sf.hdr_cnt = 1;
1749 	sf.trailers = NULL;
1750 	sf.trl_cnt = 0;
1751 	sz = sendfile(
1752 	     hc->file_fd, hc->conn_fd, c->next_byte_index,
1753 	     MIN( c->end_byte_index - c->next_byte_index, max_bytes ),
1754 	     &sf, &sbytes, 0 );
1755 	if (sz == -1 && errno == EAGAIN)
1756 	    sz = sbytes > 0 ? sbytes : -1;
1757 	else if (sz == 0)
1758 	    sz = sbytes;
1759 #else
1760 	/* Yes.  We'll combine headers and file into a single writev(),
1761 	** hoping that this generates a single packet.
1762 	*/
1763 	struct iovec iv[2];
1764 
1765 	iv[0].iov_base = hc->response;
1766 	iv[0].iov_len = hc->responselen;
1767 	iv[1].iov_base = &(hc->file_address[c->next_byte_index]);
1768 	iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes );
1769 	sz = writev( hc->conn_fd, iv, 2 );
1770 #endif
1771 	}
1772 
1773     if ( sz < 0 && errno == EINTR )
1774 	return;
1775 
1776     if ( sz == 0 ||
1777 	 ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) )
1778 	{
1779 	/* This shouldn't happen, but some kernels, e.g.
1780 	** SunOS 4.1.x, are broken and select() says that
1781 	** O_NDELAY sockets are always writable even when
1782 	** they're actually not.
1783 	**
1784 	** Current workaround is to block sending on this
1785 	** socket for a brief adaptively-tuned period.
1786 	** Fortunately we already have all the necessary
1787 	** blocking code, for use with throttling.
1788 	*/
1789 	c->wouldblock_delay += MIN_WOULDBLOCK_DELAY;
1790 	c->conn_state = CNST_PAUSING;
1791 	fdwatch_del_fd( hc->conn_fd );
1792 	client_data.p = c;
1793 	if ( c->wakeup_timer != (Timer*) 0 )
1794 	    syslog( LOG_ERR, "replacing non-null wakeup_timer!" );
1795 	c->wakeup_timer = tmr_create(
1796 	    tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 );
1797 	if ( c->wakeup_timer == (Timer*) 0 )
1798 	    {
1799 	    syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" );
1800 	    exit( 1 );
1801 	    }
1802 	return;
1803 	}
1804 
1805     if ( sz < 0 )
1806 	{
1807 	/* Something went wrong, close this connection.
1808 	**
1809 	** If it's just an EPIPE, don't bother logging, that
1810 	** just means the client hung up on us.
1811 	**
1812 	** On some systems, write() occasionally gives an EINVAL.
1813 	** Dunno why, something to do with the socket going
1814 	** bad.  Anyway, we don't log those either.
1815 	**
1816 	** And ECONNRESET isn't interesting either.
1817 	*/
1818 	if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET
1819 #ifdef USE_SENDFILE
1820 	&& errno != ENOTCONN
1821 #endif
1822 	)
1823 	    syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl );
1824 	clear_connection( c, tvP );
1825 	return;
1826 	}
1827 
1828     /* Ok, we wrote something. */
1829     c->active_at = tvP->tv_sec;
1830     /* Was this a headers + file writev()? */
1831     if ( hc->responselen > 0 )
1832 	{
1833 	/* Yes; did we write only part of the headers? */
1834 	if ( sz < hc->responselen )
1835 	    {
1836 	    /* Yes; move the unwritten part to the front of the buffer. */
1837 	    int newlen = hc->responselen - sz;
1838 	    (void) memmove( hc->response, &(hc->response[sz]), newlen );
1839 	    hc->responselen = newlen;
1840 	    sz = 0;
1841 	    }
1842 	else
1843 	    {
1844 	    /* Nope, we wrote the full headers, so adjust accordingly. */
1845 	    sz -= hc->responselen;
1846 	    hc->responselen = 0;
1847 	    }
1848 	}
1849     /* And update how much of the file we wrote. */
1850     c->next_byte_index += sz;
1851     c->hc->bytes_sent += sz;
1852     for ( tind = 0; tind < c->numtnums; ++tind )
1853 	throttles[c->tnums[tind]].bytes_since_avg += sz;
1854 
1855     /* Are we done? */
1856     if ( c->next_byte_index >= c->end_byte_index )
1857 	{
1858 	/* This connection is finished! */
1859 	finish_connection( c, tvP );
1860 	return;
1861 	}
1862 
1863     /* Tune the (blockheaded) wouldblock delay. */
1864     if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY )
1865 	c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY;
1866 
1867     /* If we're throttling, check if we're sending too fast. */
1868     if ( c->max_limit != THROTTLE_NOLIMIT )
1869 	{
1870 	elapsed = tvP->tv_sec - c->started_at;
1871 	if ( elapsed == 0 )
1872 	    elapsed = 1;	/* count at least one second */
1873 	if ( c->hc->bytes_sent / elapsed > c->max_limit )
1874 	    {
1875 	    c->conn_state = CNST_PAUSING;
1876 	    fdwatch_del_fd( hc->conn_fd );
1877 	    /* How long should we wait to get back on schedule?  If less
1878 	    ** than a second (integer math rounding), use 1/2 second.
1879 	    */
1880 	    coast = c->hc->bytes_sent / c->max_limit - elapsed;
1881 	    client_data.p = c;
1882 	    if ( c->wakeup_timer != (Timer*) 0 )
1883 		syslog( LOG_ERR, "replacing non-null wakeup_timer!" );
1884 	    c->wakeup_timer = tmr_create(
1885 		tvP, wakeup_connection, client_data,
1886 		coast > 0 ? ( coast * 1000L ) : 500L, 0 );
1887 	    if ( c->wakeup_timer == (Timer*) 0 )
1888 		{
1889 		syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" );
1890 		exit( 1 );
1891 		}
1892 	    }
1893 	}
1894     /* (No check on min_limit here, that only controls connection startups.) */
1895     }
1896 
1897 
1898 static void
handle_linger(connecttab * c,struct timeval * tvP)1899 handle_linger( connecttab* c, struct timeval* tvP )
1900     {
1901     char buf[4096];
1902     int r;
1903 
1904     /* In lingering-close mode we just read and ignore bytes.  An error
1905     ** or EOF ends things, otherwise we go until a timeout.
1906     */
1907     r = read( c->hc->conn_fd, buf, sizeof(buf) );
1908     if ( r < 0 && ( errno == EINTR || errno == EAGAIN ) )
1909 	return;
1910     if ( r <= 0 )
1911 	really_clear_connection( c, tvP );
1912     }
1913 
1914 
1915 static int
check_throttles(connecttab * c)1916 check_throttles( connecttab* c )
1917     {
1918     int tnum;
1919     long l;
1920 
1921     c->numtnums = 0;
1922     c->max_limit = c->min_limit = THROTTLE_NOLIMIT;
1923     for ( tnum = 0; tnum < numthrottles && c->numtnums < MAXTHROTTLENUMS;
1924 	  ++tnum )
1925 	if ( match( throttles[tnum].pattern, c->hc->expnfilename ) )
1926 	    {
1927 	    /* If we're way over the limit, don't even start. */
1928 	    if ( throttles[tnum].rate > throttles[tnum].max_limit * 2 )
1929 		return 0;
1930 	    /* Also don't start if we're under the minimum. */
1931 	    if ( throttles[tnum].rate < throttles[tnum].min_limit )
1932 		return 0;
1933 	    if ( throttles[tnum].num_sending < 0 )
1934 		{
1935 		syslog( LOG_ERR, "throttle sending count was negative - shouldn't happen!" );
1936 		throttles[tnum].num_sending = 0;
1937 		}
1938 	    c->tnums[c->numtnums++] = tnum;
1939 	    ++throttles[tnum].num_sending;
1940 	    l = throttles[tnum].max_limit / throttles[tnum].num_sending;
1941 	    if ( c->max_limit == THROTTLE_NOLIMIT )
1942 		c->max_limit = l;
1943 	    else
1944 		c->max_limit = MIN( c->max_limit, l );
1945 	    l = throttles[tnum].min_limit;
1946 	    if ( c->min_limit == THROTTLE_NOLIMIT )
1947 		c->min_limit = l;
1948 	    else
1949 		c->min_limit = MAX( c->min_limit, l );
1950 	    }
1951     return 1;
1952     }
1953 
1954 
1955 static void
clear_throttles(connecttab * c,struct timeval * tvP)1956 clear_throttles( connecttab* c, struct timeval* tvP )
1957     {
1958     int tind;
1959 
1960     for ( tind = 0; tind < c->numtnums; ++tind )
1961 	--throttles[c->tnums[tind]].num_sending;
1962     }
1963 
1964 
1965 static void
update_throttles(ClientData client_data,struct timeval * nowP)1966 update_throttles( ClientData client_data, struct timeval* nowP )
1967     {
1968     int tnum, tind;
1969     int cnum;
1970     connecttab* c;
1971     long l;
1972 
1973     /* Update the average sending rate for each throttle.  This is only used
1974     ** when new connections start up.
1975     */
1976     for ( tnum = 0; tnum < numthrottles; ++tnum )
1977 	{
1978 	throttles[tnum].rate = ( 2 * throttles[tnum].rate + throttles[tnum].bytes_since_avg / THROTTLE_TIME ) / 3;
1979 	throttles[tnum].bytes_since_avg = 0;
1980 	/* Log a warning message if necessary. */
1981 	if ( throttles[tnum].rate > throttles[tnum].max_limit && throttles[tnum].num_sending != 0 )
1982 	    {
1983 	    if ( throttles[tnum].rate > throttles[tnum].max_limit * 2 )
1984 		syslog( LOG_NOTICE, "throttle #%d '%.80s' rate %ld greatly exceeding limit %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].max_limit, throttles[tnum].num_sending );
1985 	    else
1986 		syslog( LOG_INFO, "throttle #%d '%.80s' rate %ld exceeding limit %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].max_limit, throttles[tnum].num_sending );
1987 	    }
1988 	if ( throttles[tnum].rate < throttles[tnum].min_limit && throttles[tnum].num_sending != 0 )
1989 	    {
1990 	    syslog( LOG_NOTICE, "throttle #%d '%.80s' rate %ld lower than minimum %ld; %d sending", tnum, throttles[tnum].pattern, throttles[tnum].rate, throttles[tnum].min_limit, throttles[tnum].num_sending );
1991 	    }
1992 	}
1993 
1994     /* Now update the sending rate on all the currently-sending connections,
1995     ** redistributing it evenly.
1996     */
1997     for ( cnum = 0; cnum < max_connects; ++cnum )
1998 	{
1999 	c = &connects[cnum];
2000 	if ( c->conn_state == CNST_SENDING || c->conn_state == CNST_PAUSING )
2001 	    {
2002 	    c->max_limit = THROTTLE_NOLIMIT;
2003 	    for ( tind = 0; tind < c->numtnums; ++tind )
2004 		{
2005 		tnum = c->tnums[tind];
2006 		l = throttles[tnum].max_limit / throttles[tnum].num_sending;
2007 		if ( c->max_limit == THROTTLE_NOLIMIT )
2008 		    c->max_limit = l;
2009 		else
2010 		    c->max_limit = MIN( c->max_limit, l );
2011 		}
2012 	    }
2013 	}
2014     }
2015 
2016 
2017 static void
finish_connection(connecttab * c,struct timeval * tvP)2018 finish_connection( connecttab* c, struct timeval* tvP )
2019     {
2020     /* If we haven't actually sent the buffered response yet, do so now. */
2021     httpd_write_response( c->hc );
2022 
2023     /* And clear. */
2024     clear_connection( c, tvP );
2025     }
2026 
2027 
2028 static void
clear_connection(connecttab * c,struct timeval * tvP)2029 clear_connection( connecttab* c, struct timeval* tvP )
2030     {
2031     ClientData client_data;
2032 
2033     if ( c->wakeup_timer != (Timer*) 0 )
2034 	{
2035 	tmr_cancel( c->wakeup_timer );
2036 	c->wakeup_timer = 0;
2037 	}
2038 
2039     /* This is our version of Apache's lingering_close() routine, which is
2040     ** their version of the often-broken SO_LINGER socket option.  For why
2041     ** this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html
2042     ** What we do is delay the actual closing for a few seconds, while reading
2043     ** any bytes that come over the connection.  However, we don't want to do
2044     ** this unless it's necessary, because it ties up a connection slot and
2045     ** file descriptor which means our maximum connection-handling rate
2046     ** is lower.  So, elsewhere we set a flag when we detect the few
2047     ** circumstances that make a lingering close necessary.  If the flag
2048     ** isn't set we do the real close now.
2049     */
2050     if ( c->conn_state == CNST_LINGERING )
2051 	{
2052 	/* If we were already lingering, shut down for real. */
2053 	tmr_cancel( c->linger_timer );
2054 	c->linger_timer = (Timer*) 0;
2055 	c->hc->should_linger = 0;
2056 	}
2057     if ( c->hc->should_linger )
2058 	{
2059 	if ( c->conn_state != CNST_PAUSING )
2060 	    fdwatch_del_fd( c->hc->conn_fd );
2061 	c->conn_state = CNST_LINGERING;
2062 	shutdown( c->hc->conn_fd, SHUT_WR );
2063 	fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ );
2064 	client_data.p = c;
2065 	if ( c->linger_timer != (Timer*) 0 )
2066 	    syslog( LOG_ERR, "replacing non-null linger_timer!" );
2067 	c->linger_timer = tmr_create(
2068 	    tvP, linger_clear_connection, client_data, LINGER_TIME, 0 );
2069 	if ( c->linger_timer == (Timer*) 0 )
2070 	    {
2071 	    syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" );
2072 	    exit( 1 );
2073 	    }
2074 	}
2075     else
2076 	really_clear_connection( c, tvP );
2077     }
2078 
2079 
2080 static void
really_clear_connection(connecttab * c,struct timeval * tvP)2081 really_clear_connection( connecttab* c, struct timeval* tvP )
2082     {
2083     stats_bytes += c->hc->bytes_sent;
2084     if ( c->conn_state != CNST_PAUSING )
2085 	fdwatch_del_fd( c->hc->conn_fd );
2086     httpd_close_conn( c->hc, tvP );
2087     clear_throttles( c, tvP );
2088     if ( c->linger_timer != (Timer*) 0 )
2089 	{
2090 	tmr_cancel( c->linger_timer );
2091 	c->linger_timer = 0;
2092 	}
2093     c->conn_state = CNST_FREE;
2094     c->next_free_connect = first_free_connect;
2095     first_free_connect = c - connects;	/* division by sizeof is implied */
2096     --num_connects;
2097     }
2098 
2099 
2100 static void
idle(ClientData client_data,struct timeval * nowP)2101 idle( ClientData client_data, struct timeval* nowP )
2102     {
2103     int cnum;
2104     connecttab* c;
2105 
2106     for ( cnum = 0; cnum < max_connects; ++cnum )
2107 	{
2108 	c = &connects[cnum];
2109 	switch ( c->conn_state )
2110 	    {
2111 	    case CNST_READING:
2112 	    if ( nowP->tv_sec - c->active_at >= IDLE_READ_TIMELIMIT )
2113 		{
2114 		syslog( LOG_INFO,
2115 		    "%.80s connection timed out reading",
2116 		    httpd_ntoa( &c->hc->client_addr ) );
2117 		httpd_send_err(
2118 		    c->hc, 408, httpd_err408title, "", httpd_err408form, "" );
2119 		finish_connection( c, nowP );
2120 		}
2121 	    break;
2122 	    case CNST_SENDING:
2123 	    case CNST_PAUSING:
2124 	    if ( nowP->tv_sec - c->active_at >= IDLE_SEND_TIMELIMIT )
2125 		{
2126 		syslog( LOG_INFO,
2127 		    "%.80s connection timed out sending",
2128 		    httpd_ntoa( &c->hc->client_addr ) );
2129 		clear_connection( c, nowP );
2130 		}
2131 	    break;
2132 	    }
2133 	}
2134     }
2135 
2136 
2137 static void
wakeup_connection(ClientData client_data,struct timeval * nowP)2138 wakeup_connection( ClientData client_data, struct timeval* nowP )
2139     {
2140     connecttab* c;
2141 
2142     c = (connecttab*) client_data.p;
2143     c->wakeup_timer = (Timer*) 0;
2144     if ( c->conn_state == CNST_PAUSING )
2145 	{
2146 	c->conn_state = CNST_SENDING;
2147 	fdwatch_add_fd( c->hc->conn_fd, c, FDW_WRITE );
2148 	}
2149     }
2150 
2151 static void
linger_clear_connection(ClientData client_data,struct timeval * nowP)2152 linger_clear_connection( ClientData client_data, struct timeval* nowP )
2153     {
2154     connecttab* c;
2155 
2156     c = (connecttab*) client_data.p;
2157     c->linger_timer = (Timer*) 0;
2158     really_clear_connection( c, nowP );
2159     }
2160 
2161 
2162 static void
occasional(ClientData client_data,struct timeval * nowP)2163 occasional( ClientData client_data, struct timeval* nowP )
2164     {
2165     mmc_cleanup( nowP );
2166     tmr_cleanup();
2167     watchdog_flag = 1;		/* let the watchdog know that we are alive */
2168     }
2169 
2170 
2171 #ifdef STATS_TIME
2172 static void
show_stats(ClientData client_data,struct timeval * nowP)2173 show_stats( ClientData client_data, struct timeval* nowP )
2174     {
2175     logstats( nowP );
2176     }
2177 #endif /* STATS_TIME */
2178 
2179 
2180 /* Generate debugging statistics syslog messages for all packages. */
2181 static void
logstats(struct timeval * nowP)2182 logstats( struct timeval* nowP )
2183     {
2184     struct timeval tv;
2185     time_t now;
2186     long up_secs, stats_secs;
2187 
2188     if ( nowP == (struct timeval*) 0 )
2189 	{
2190 	(void) gettimeofday( &tv, (struct timezone*) 0 );
2191 	nowP = &tv;
2192 	}
2193     now = nowP->tv_sec;
2194     up_secs = now - start_time;
2195     stats_secs = now - stats_time;
2196     if ( stats_secs == 0 )
2197 	stats_secs = 1;	/* fudge */
2198     stats_time = now;
2199     syslog( LOG_NOTICE,
2200 	"up %ld seconds, stats for %ld seconds:", up_secs, stats_secs );
2201 
2202     thttpd_logstats( stats_secs );
2203     httpd_logstats( stats_secs );
2204     mmc_logstats( stats_secs );
2205     fdwatch_logstats( stats_secs );
2206     tmr_logstats( stats_secs );
2207     }
2208 
2209 
2210 /* Generate debugging statistics syslog message. */
2211 static void
thttpd_logstats(long secs)2212 thttpd_logstats( long secs )
2213     {
2214     if ( secs > 0 )
2215 	syslog( LOG_NOTICE,
2216 	    "  thttpd - %ld connections (%g/sec), %d max simultaneous, %lld bytes (%g/sec), %d httpd_conns allocated",
2217 	    stats_connections, (float) stats_connections / secs,
2218 	    stats_simultaneous, (long long) stats_bytes,
2219 	    (float) stats_bytes / secs, httpd_conn_count );
2220     stats_connections = 0;
2221     stats_bytes = 0;
2222     stats_simultaneous = 0;
2223     }
2224