⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thttpd.c.bak

📁 修改后的thttp
💻 BAK
📖 第 1 页 / 共 2 页
字号:
/* thttpd.c - tiny/turbo/throttling HTTP server**** Copyright (C)1995,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.**** Redistribution and use in source and binary forms, with or without** modification, are permitted provided that the following conditions** are met:** 1. Redistributions of source code must retain the above copyright**    notice, this list of conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright**    notice, this list of conditions and the following disclaimer in the**    documentation and/or other materials provided with the distribution.**** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF** SUCH DAMAGE.*/#include "config.h"#include "version.h"#include <sys/param.h>#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/uio.h>#include <errno.h>#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#include <pwd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#ifdef TIME_WITH_SYS_TIME#include <time.h>#endif#include <unistd.h>#include "libhttpd.h"#include "mmc.h"#include "timers.h"#include "match.h"#ifndef FD_SET#define NFDBITS		32#define FD_SETSIZE	32#define FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))#define FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))#define FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))#endif /* !FD_SET */#define EMBED#undef HAVE_MMAPstatic char* argv0;typedef struct {    char* pattern;    long limit;    long rate;    time_t last_avg;    off_t bytes_since_avg;    int num_sending;    } throttletab;static throttletab* throttles;static int numthrottles, maxthrottles;typedef struct {    int conn_state;    httpd_conn hc;    int tnums[MAXTHROTTLENUMS];		/* throttle indexes */    int numtnums;    long limit;    time_t started_at;    Timer* idle_read_timer;    Timer* idle_send_timer;    Timer* wakeup_timer;    Timer* linger_timer;    long wouldblock_delay;    off_t bytes;    off_t bytes_sent;    off_t bytes_to_send;    } connecttab;static connecttab* connects;static int numconnects, maxconnects;static int recompute_fdsets;/* The connection states. */#define CNST_FREE 0#define CNST_READING 1#define CNST_SENDING 2#define CNST_PAUSING 3#define CNST_LINGERING 4static httpd_server* hs = (httpd_server*) 0;#ifdef STATS_TIMEint stats_connections, stats_simultaneous;#endif /* STATS_TIME *//* Forwards. */static void usage( void );static void read_throttlefile( char* throttlefile );static void shut_down( void );static int handle_newconnect( struct timeval* tvP );static void handle_read( connecttab* c, struct timeval* tvP );static void handle_send( connecttab* c, struct timeval* tvP );static void handle_linger( connecttab* c, struct timeval* tvP );static int check_throttles( connecttab* c );static void clear_throttles( connecttab* c, struct timeval* tvP );static void clear_connection( connecttab* c, struct timeval* tvP );static void really_clear_connection( connecttab* c, struct timeval* tvP );static void idle_read_connection( ClientData client_data, struct timeval* nowP );static void idle_send_connection( ClientData client_data, struct timeval* nowP );static void wakeup_connection( ClientData client_data, struct timeval* nowP );static void linger_clear_connection( ClientData client_data, struct timeval* nowP );static void occasional( ClientData client_data, struct timeval* nowP );#ifdef STATS_TIMEstatic void show_stats( ClientData client_data, struct timeval* nowP );#endif /* STATS_TIME */static voidhandle_kill( int sig )    {    shut_down();    syslog( LOG_NOTICE, "exiting due to signal %d", sig );    closelog();    exit( 1 );    }intmain( int argc, char** argv )    {    char* cp;    int argn;    int debug;    int port;    char* dir;    int do_chroot;#ifndef EMBED    struct passwd* pwd;#endif    uid_t uid;    gid_t gid;    char* cgi_pattern;    char* throttlefile;    char* hostname;    char* logfile;    char* user;    char cwd[MAXPATHLEN];    FILE* logfp;    int nfiles;    fd_set master_rfdset;    fd_set master_wfdset;    fd_set working_rfdset;    fd_set working_wfdset;    int num_ready;    int cnum;    connecttab* c;    u_int addr;    struct timeval tv;    struct hostent* he;    argv0 = argv[0];    cp = strrchr( argv0, '/' );    if ( cp != (char*) 0 )	++cp;    else	cp = argv0;    openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY );    (void) signal( SIGINT, handle_kill );    (void) signal( SIGTERM, handle_kill );    (void) signal( SIGPIPE, SIG_IGN );		/* get EPIPE instead */    debug = 0;    port = DEFAULT_PORT;#ifdef EMBED    dir = DEFAULT_DIR;#else    dir = (char*) 0;#endif#ifdef ALWAYS_CHROOT    do_chroot = 1;#else /* ALWAYS_CHROOT */    do_chroot = 0;#endif /* ALWAYS_CHROOT */#ifdef CGI_PATTERN    cgi_pattern = CGI_PATTERN;#else /* CGI_PATTERN */    cgi_pattern = (char*) 0;#endif /* CGI_PATTERN */    throttlefile = (char*) 0;    hostname = (char*) 0;    logfile = (char*) 0;    user = DEFAULT_USER;    argn = 1;    while ( argn < argc && argv[argn][0] == '-' )	{	if ( strcmp( argv[argn], "-D" ) == 0 )	    debug = 1;	else if ( strcmp( argv[argn], "-p" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    port = atoi( argv[argn] );	    }	else if ( strcmp( argv[argn], "-d" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    dir = argv[argn];	    }	else if ( strcmp( argv[argn], "-r" ) == 0 )	    do_chroot = 1;	else if ( strcmp( argv[argn], "-nor" ) == 0 )	    do_chroot = 0;	else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    user = argv[argn];	    }	else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    cgi_pattern = argv[argn];	    }	else if ( strcmp( argv[argn], "-t" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    throttlefile = argv[argn];	    }	else if ( strcmp( argv[argn], "-h" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    hostname = argv[argn];	    }	else if ( strcmp( argv[argn], "-l" ) == 0 && argn + 1 < argc )	    {	    ++argn;	    logfile = argv[argn];	    }	else	    usage();	++argn;	}    if ( argn != argc )	usage();    /* Lookup hostname now in case we're going to chroot(). */    if ( hostname == (char*) 0 )	addr = htonl( INADDR_ANY );    else	{	addr = inet_addr( hostname );	if ( (int) addr == -1 )	    {	    he = gethostbyname( hostname );	    if ( he == (struct hostent*) 0 )		{#ifdef HAVE_HSTRERROR		syslog( LOG_CRIT, "gethostbyname %.80s - %s", hostname, hstrerror( h_errno ) );		(void) fprintf( stderr, "gethostbyname %.80s - %s", hostname, hstrerror( h_errno ) );#else /* HAVE_HSTRERROR */		syslog( LOG_CRIT, "gethostbyname %.80s", hostname );		(void) fprintf( stderr, "gethostbyname %.80s\n", hostname );#endif /* HAVE_HSTRERROR */		exit( 1 );		}	    if ( he->h_addrtype != AF_INET || he->h_length != sizeof(addr) )		{		syslog( LOG_CRIT, "%.80s - non-IP network address", hostname );		(void) fprintf( stderr, "%.80s - non-IP network address\n", hostname );		exit( 1 );		}	    (void) memcpy( &addr, he->h_addr, sizeof(addr) );	    }	}    /* Check port number. */    if ( port <= 0 )	{	syslog( LOG_CRIT, "illegal port number" );	(void) fprintf( stderr, "illegal port number\n" );	exit( 1 );	}    /* Throttle file. */    numthrottles = 0;    maxthrottles = 0;    if ( throttlefile != (char*) 0 )	read_throttlefile( throttlefile );    /* Log file. */    if ( logfile != (char*) 0 )	{	logfp = fopen( logfile, "a" );	if ( logfp == (FILE*) 0 )	    {	    syslog( LOG_CRIT, "%.80s - %m", logfile );	    perror( logfile );	    exit( 1 );	    }	(void) fcntl( fileno( logfp ), F_SETFD, 1 );	}    else	logfp = (FILE*) 0;#ifdef EMBED    uid = 0;    gid = 0;#else    /* Figure out uid/gid from user. */    pwd = getpwnam( user );    if ( pwd == (struct passwd*) 0 )	{	syslog( LOG_CRIT, "unknown user - '%.80s'", user );	(void) fprintf( stderr, "unknown user - '%s'\n", user );	exit( 1 );	}    uid = pwd->pw_uid;    gid = pwd->pw_gid;#endif    /* Switch directories if requested. */    if ( dir != (char*) 0 )	{	if ( chdir( dir ) < 0 )	    {	    syslog( LOG_CRIT, "chdir - %m" );	    perror( "chdir" );	    exit( 1 );	    }	}#ifdef USE_USER_DIR    else if ( getuid() == 0 )	{	/* No explicit directory was specified, we're root, and the	** USE_USER_DIR option is set - switch to the specified user's	** home dir.	*/	if ( chdir( pwd->pw_dir ) < 0 )	    {	    syslog( LOG_CRIT, "chdir - %m" );	    perror( "chdir" );	    exit( 1 );	    }	}#endif /* USE_USER_DIR */    /* Get current directory. */    (void) getcwd( cwd, sizeof(cwd) );    if ( cwd[strlen( cwd ) - 1] != '/' )	(void) strcat( cwd, "/" );    /* Chroot if requested. */    if ( do_chroot )	{	if ( chroot( cwd ) < 0 )	    {	    syslog( LOG_CRIT, "chroot - %m" );	    perror( "chroot" );	    exit( 1 );	    }	(void) strcpy( cwd, "/" );	}    /* Figure out how many file descriptors we can use. */    nfiles = MIN( httpd_get_nfiles(), FD_SETSIZE );    if ( ! debug )	{	/* We're not going to use stdin stdout or stderr from here on, so close	** them to save file descriptors.	*/#ifndef EMBED	(void) fclose( stdin );	(void) fclose( stdout );	(void) fclose( stderr );	/* Daemonize - make ourselves a subprocess. */	switch ( fork() )	    {	    case 0:	    break;	    case -1:	    syslog( LOG_CRIT, "fork - %m" );	    exit( 1 );	    default:	    exit( 0 );	    }#endif	}    /* Initialize the HTTP layer.  Got to do this before giving up root,    ** so that we can bind to a privileged port.    */    hs = httpd_initialize(	hostname, addr, port, cgi_pattern, cwd, logfp, do_chroot );    if ( hs == (httpd_server*) 0 )	exit( 1 );    /* Set up the occasional timer. */    (void) tmr_create(	(struct timeval*) 0, occasional, (ClientData) 0,	OCCASIONAL_TIME * 1000L, 1 );#ifdef STATS_TIME    /* Set up the stats timer. */    (void) tmr_create(	(struct timeval*) 0, show_stats, (ClientData) 0, STATS_TIME * 1000L,	1 );    stats_connections = stats_simultaneous = 0;#endif /* STATS_TIME */    /* If we're root, try to become someone else. */    if ( getuid() == 0 )	{	if ( setgroups( 0, (const gid_t*) 0 ) < 0 )	    {	    syslog( LOG_CRIT, "setgroups - %m" );	    exit( 1 );	    }	if ( setgid( gid ) < 0 )	    {	    syslog( LOG_CRIT, "setgid - %m" );	    exit( 1 );	    }	if ( setuid( uid ) < 0 )	    {	    syslog( LOG_CRIT, "setuid - %m" );	    exit( 1 );	    }	/* Check for unnecessary security exposure. */	if ( ! do_chroot )	    syslog(		LOG_CRIT,		"started as root without requesting chroot(), warning only" );	}    /* Initialize our connections table. */    maxconnects = nfiles - SPARE_FDS;    connects = NEW( connecttab, maxconnects );    if ( connects == (connecttab*) 0 )	{	syslog( LOG_CRIT, "out of memory" );	exit( 1 );	}    for ( cnum = 0; cnum < maxconnects; ++cnum )	{	connects[cnum].conn_state = CNST_FREE;	connects[cnum].hc.initialized = 0;	}    numconnects = 0;    recompute_fdsets = 1;    /* Main loop. */    (void) gettimeofday( &tv, (struct timezone*) 0 );    for (;;)	{	if ( recompute_fdsets )	    {	    /* Set up the fdsets. */	    FD_ZERO( &master_rfdset );	    FD_ZERO( &master_wfdset );	    FD_SET( hs->listen_fd, &master_rfdset );	    if ( numconnects > 0 )		for ( cnum = 0; cnum < maxconnects; ++cnum )		    switch ( connects[cnum].conn_state )			{			case CNST_READING:			case CNST_LINGERING:			FD_SET( connects[cnum].hc.conn_fd, &master_rfdset );			break;			case CNST_SENDING:			FD_SET( connects[cnum].hc.conn_fd, &master_wfdset );			break;			}	    recompute_fdsets = 0;	    }	/* Do the select. */	working_rfdset = master_rfdset;	working_wfdset = master_wfdset;	num_ready = select(	    nfiles, &working_rfdset, &working_wfdset, (fd_set*) 0,	    tmr_timeout( &tv ) );	if ( num_ready < 0 )	    {	    if ( errno == EINTR )		continue;	/* try again */	    syslog( LOG_ERR, "select - %m" );	    exit( 1 );	    }	(void) gettimeofday( &tv, (struct timezone*) 0 );	if ( num_ready == 0 )	    {	    /* No fd's are ready - run the timers. */	    tmr_run( &tv );	    continue;	    }	/* Is it a new connection? */	if ( FD_ISSET( hs->listen_fd, &working_rfdset ) )	    {	    --num_ready;	    if ( handle_newconnect( &tv ) )		/* Go around the loop and do another select, rather than		** dropping through and processing existing connections.		** New connections always get priority.		*/		continue;	    /* Only if handle_newconnect() fails in a particular way do	    ** we fall through.	    */	    }	/* Find the connections that need servicing. */	for ( cnum = 0; num_ready > 0 && cnum < maxconnects; ++cnum )	    {	    c = &connects[cnum];	    if ( c->conn_state == CNST_READING &&		 FD_ISSET( c->hc.conn_fd, &working_rfdset ) )		{		--num_ready;		handle_read( c, &tv );		}	    else if ( c->conn_state == CNST_SENDING &&		 FD_ISSET( c->hc.conn_fd, &working_wfdset ) )		{		--num_ready;		handle_send( c, &tv );		}	    else if ( c->conn_state == CNST_LINGERING &&		 FD_ISSET( c->hc.conn_fd, &working_rfdset ) )		{		--num_ready;		handle_linger( c, &tv );		}	    }	tmr_run( &tv );	}    }static voidusage( void )    {    (void) fprintf( stderr,"usage:  %s [-p port] [-d dir] [-r|-nor] [-u user] [-c cgipat] [-t throttles] [-h host] [-l logfile]\n",	argv0 );    exit( 1 );    }static voidread_throttlefile( char* throttlefile )    {    FILE* fp;    char buf[5000];    char* cp;    int len;    char pattern[5000];    long limit;    struct timeval tv;    fp = fopen( throttlefile, "r" );    if ( fp == (FILE*) 0 )	{	syslog( LOG_CRIT, "%.80s - %m", throttlefile );	perror( throttlefile );	exit( 1 );	}    (void) gettimeofday( &tv, (struct timezone*) 0 );    while ( fgets( buf, sizeof(buf), fp ) != (char*) 0 )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -