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

📄 thttpd.c.bak

📁 修改后的thttp
💻 BAK
📖 第 1 页 / 共 2 页
字号:
	{	/* Nuke comments. */	cp = strchr( buf, '#' );	if ( cp != (char*) 0 )	    *cp = '\0';	/* Nuke trailing whitespace. */	len = strlen( buf );	while ( len > 0 &&		( buf[len-1] == ' ' || buf[len-1] == '\t' ||		  buf[len-1] == '\n' || buf[len-1] == '\r' ) )	    buf[--len] = '\0';	/* Ignore empty lines. */	if ( len == 0 )	    continue;	/* Parse line. */	if ( sscanf( buf, " %[^ \t] %ld", pattern, &limit ) != 2 || limit <= 0 )	    {	    syslog( LOG_CRIT,		"unparsable line in %.80s - %.80s", throttlefile, buf );	    (void) fprintf( stderr,		"unparsable line in %.80s - %.80s\n", throttlefile, buf );	    continue;	    }	/* Nuke any leading slashes in pattern. */	if ( pattern[0] == '/' )	    (void) strcpy( pattern, &pattern[1] );	while ( ( cp = strstr( pattern, "|/" ) ) != (char*) 0 )	    (void) strcpy( cp + 1, cp + 2 );	/* Check for room in throttles. */	if ( numthrottles >= maxthrottles )	    {	    if ( maxthrottles == 0 )		{		maxthrottles = 100;	/* arbitrary */		throttles = NEW( throttletab, maxthrottles );		}	    else		{		maxthrottles *= 2;		throttles = RENEW( throttles, throttletab, maxthrottles );		}	    if ( throttles == (throttletab*) 0 )		{		syslog( LOG_CRIT, "out of memory" );		(void) fprintf( stderr, "out of memory\n" );		exit( 1 );		}	    }	/* Add to table. */	throttles[numthrottles].pattern = strdup( pattern );	if ( throttles[numthrottles].pattern == (char*) 0 )	    {	    syslog( LOG_CRIT, "out of memory" );	    (void) fprintf( stderr, "out of memory\n" );	    exit( 1 );	    }	throttles[numthrottles].limit = limit;	throttles[numthrottles].rate = 0;	throttles[numthrottles].last_avg = tv.tv_sec;	throttles[numthrottles].bytes_since_avg = 0;	throttles[numthrottles].num_sending = 0;	++numthrottles;	}    (void) fclose( fp );    }static voidshut_down( void )    {    int cnum;    struct timeval tv;#ifdef STATS_TIME    show_stats( (ClientData) 0, (struct timeval*) 0 );#endif /* STATS_TIME */    (void) gettimeofday( &tv, (struct timezone*) 0 );    for ( cnum = 0; cnum < maxconnects; ++cnum )	{	if ( connects[cnum].conn_state != CNST_FREE )	    httpd_close_conn( &connects[cnum].hc, &tv );	httpd_destroy_conn( &connects[cnum].hc );	}    if ( hs != (httpd_server*) 0 )	{	httpd_terminate( hs );	hs = (httpd_server*) 0;	}    mmc_destroy();    tmr_destroy();    free( (void*) connects );    }static inthandle_newconnect( struct timeval* tvP )    {    int cnum;    connecttab* c;    ClientData client_data;    /* This loops until the accept() fails, trying to start new    ** connections as fast as possible so we don't overrun the    ** listen queue.    */    for (;;)	{	/* Is there room in the connection table? */	if ( numconnects >= maxconnects )	    {	    /* Out of connection slots.  Run the timers, then the	    ** existing connections, and maybe we'll free up a slot	    ** by the time we get back here.	    **/	    syslog( LOG_WARNING, "too many connections!" );	    tmr_run( tvP );	    return 0;	    }	/* Find a free connection entry. */	for ( cnum = 0; cnum < maxconnects; ++cnum )	    if ( connects[cnum].conn_state == CNST_FREE )		break;	c = &connects[cnum];	/* Get the connection. */	switch ( httpd_get_conn( hs, &connects[cnum].hc ) )	    {	    case GC_FAIL:	    case GC_NO_MORE:	    return 1;	    }	c->conn_state = CNST_READING;	recompute_fdsets = 1;	++numconnects;	client_data.p = c;	c->idle_read_timer = tmr_create(	    tvP, idle_read_connection, client_data, IDLE_READ_TIMELIMIT * 1000L,	    0 );	c->idle_send_timer = (Timer*) 0;	c->wakeup_timer = (Timer*) 0;	c->linger_timer = (Timer*) 0;	c->bytes_sent = 0;	/* Set the connection file descriptor to no-delay mode. */	if ( fcntl( c->hc.conn_fd, F_SETFL, O_NDELAY ) < 0 )	    syslog( LOG_ERR, "fcntl O_NDELAY - %m" );#ifdef STATS_TIME	++stats_connections;	if ( numconnects > stats_simultaneous )	    stats_simultaneous = numconnects;#endif /* STATS_TIME */	}    }static voidhandle_read( connecttab* c, struct timeval* tvP )    {    int sz;    ClientData client_data;    /* Is there room in our buffer to read more bytes? */    if ( c->hc.read_idx >= sizeof(c->hc.read_buf) )	{	httpd_send_err( &c->hc, 400, httpd_err400title, httpd_err400form, "" );	clear_connection( c, tvP );	return;	}    /* Read some more bytes. */    sz = read(        c->hc.conn_fd, &(c->hc.read_buf[c->hc.read_idx]),	sizeof(c->hc.read_buf) - c->hc.read_idx );    if ( sz <= 0 )	{	httpd_send_err( &c->hc, 400, httpd_err400title, httpd_err400form, "" );	clear_connection( c, tvP );	return;	}    c->hc.read_idx += sz;        /* Do we have a complete request yet? */    switch ( httpd_got_request( &c->hc ) )	{	case GR_NO_REQUEST:	return;	case GR_BAD_REQUEST:	httpd_send_err( &c->hc, 400, httpd_err400title, httpd_err400form, "" );	clear_connection( c, tvP );	return;	}        /* Yes.  Try parsing it. */    if ( httpd_parse_request( &c->hc ) < 0 )	{	clear_connection( c, tvP );	return;	}    /* Check the throttle table */    if ( ! check_throttles( c ) )	{	httpd_send_err(	    &c->hc, 503, httpd_err503title, httpd_err503form,	    c->hc.encodedurl );	clear_connection( c, tvP );	return;	}    /* Start the connection going. */    if ( httpd_start_request( &c->hc ) < 0 )	{	/* Something went wrong.  Close down the connection. */	clear_connection( c, tvP );	return;	}    /* Fill in bytes_to_send. */    if ( c->hc.got_range )	{	c->bytes_sent = c->hc.init_byte_loc;	c->bytes_to_send = c->hc.end_byte_loc + 1;	}    else	c->bytes_to_send = c->hc.bytes;    /* Check if it's already handled. */    if ( c->hc.file_address == (char*) 0 )	{	/* No file address means someone else is handling it. */	c->bytes_sent = c->hc.bytes;	clear_connection( c, tvP );	return;	}    if ( c->bytes_sent >= c->bytes_to_send )	{	/* There's nothing to send. */	clear_connection( c, tvP );	return;	}    /* Cool, we have a valid connection and a file to send to it. */    c->conn_state = CNST_SENDING;    recompute_fdsets = 1;    c->started_at = tvP->tv_sec;    c->wouldblock_delay = 0;    client_data.p = c;    tmr_cancel( c->idle_read_timer );    c->idle_read_timer = (Timer*) 0;    c->idle_send_timer = tmr_create(	tvP, idle_send_connection, client_data, IDLE_SEND_TIMELIMIT * 1000L,	0 );    }static voidhandle_send( connecttab* c, struct timeval* tvP )    {    int sz, coast;    ClientData client_data;    time_t elapsed;    /* Do we need to write the headers first? */    if ( c->hc.responselen == 0 )	{	/* No, just write the file. */	sz = write(	    c->hc.conn_fd, &c->hc.file_address[c->bytes_sent],	    MIN( c->bytes_to_send - c->bytes_sent, c->limit ) );	}    else	{	/* Yes.  We'll combine headers and file into a single writev(),	** hoping that this generates a single packet.	*/	struct iovec iv[2];	iv[0].iov_base = c->hc.response;	iv[0].iov_len = c->hc.responselen;	iv[1].iov_base = &c->hc.file_address[c->bytes_sent];	iv[1].iov_len = MIN( c->bytes_to_send - c->bytes_sent, c->limit );	sz = writev( c->hc.conn_fd, iv, 2 );	}    if ( sz == 0 ||	 ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) )	{	/* This shouldn't happen, but some kernels, e.g.	** SunOS 4.1.x, are broken and select() says that	** O_NDELAY sockets are always writable even when	** they're actually not.	**	** Current workaround is to block sending on this	** socket for a brief adaptively-tuned period.	** Fortunately we already have all the necessary	** blocking code, for use with throttling.	*/	c->wouldblock_delay += MIN_WOULDBLOCK_DELAY;	c->conn_state = CNST_PAUSING;	recompute_fdsets = 1;	client_data.p = c;	c->wakeup_timer = tmr_create(	    tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 );	return;	}    if ( sz < 0 )	{	/* Something went wrong, close this connection.	**	** If it's just an EPIPE, don't bother logging, that	** just means the client hung up on us.	**	** On some systems, write() occasionally gives an EINVAL.	** Dunno why, something to do with the socket going	** bad.  Anyway, we don't log those either.	*/	if ( errno != EPIPE && errno != EINVAL )	    syslog( LOG_ERR, "write - %m" );	clear_connection( c, tvP );	return;	}    /* Ok, we wrote something. */    tmr_reset( tvP, c->idle_send_timer );    /* Was this a headers + file writev()? */    if ( c->hc.responselen > 0 )	{	/* Yes; did we write only part of the headers? */	if ( sz < c->hc.responselen )	    {	    /* Yes; move the unwritten part to the front of the buffer. */	    int newlen = c->hc.responselen - sz;	    (void) memcpy( c->hc.response, &(c->hc.response[sz]), newlen );	    c->hc.responselen = newlen;	    sz = 0;	    }	else	    {	    /* Nope, we wrote the full headers, so adjust accordingly. */	    sz -= c->hc.responselen;	    c->hc.responselen = 0;	    }	}    /* And update how much of the file we wrote. */    c->bytes_sent += sz;    /* Are we done? */    if ( c->bytes_sent >= c->bytes_to_send )	{	/* This conection is finished! */	clear_connection( c, tvP );	return;	}    /* Tune the (blockheaded) wouldblock delay. */    if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY )	c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY;    /* Check if we're sending faster than the throttle. */    elapsed = tvP->tv_sec - c->started_at;    if ( elapsed == 0 || c->bytes_sent / elapsed > c->limit )	{	c->conn_state = CNST_PAUSING;	recompute_fdsets = 1;	/* When should we send the next c->limit bytes	** to get back on schedule?  If less than a second	** (integer math rounding), use 1/8 second.	*/	coast = ( c->bytes_sent + c->limit ) / c->limit - elapsed;	client_data.p = c;	c->wakeup_timer = tmr_create(	    tvP, wakeup_connection, client_data,	    coast ? ( coast * 1000L ) : 125L, 0 );	}    }static voidhandle_linger( connecttab* c, struct timeval* tvP )    {    char buf[1024];    int r;    /* In lingering-close mode we just read and ignore bytes.  An error    ** or EOF ends things, otherwise we go until a timeout.    */    r = read( c->hc.conn_fd, buf, sizeof(buf) );    if ( r <= 0 )	really_clear_connection( c, tvP );    }static intcheck_throttles( connecttab* c )    {    int tnum;    c->numtnums = 0;    c->limit = 1234567890L;    for ( tnum = 0; tnum < numthrottles && c->numtnums < MAXTHROTTLENUMS;	  ++tnum )	if ( match( throttles[tnum].pattern, c->hc.expnfilename ) )	    {	    c->tnums[c->numtnums++] = tnum;	    /* If we're way over the limit, don't even start. */	    if ( throttles[tnum].rate > throttles[tnum].limit * 3 / 2 )		return 0;	    ++throttles[tnum].num_sending;	    c->limit = MIN(		c->limit, throttles[tnum].limit / throttles[tnum].num_sending );	    }    return 1;    }static voidclear_throttles( connecttab* c, struct timeval* tvP )    {    int i, tnum;    time_t elapsed;    for ( i = 0; i < c->numtnums; ++i )	{	tnum = c->tnums[i];	--throttles[tnum].num_sending;	throttles[tnum].bytes_since_avg += c->bytes_sent;	elapsed = tvP->tv_sec - throttles[tnum].last_avg;	if ( elapsed >= THROTTLE_TIME )	    {	    throttles[tnum].rate =		( throttles[tnum].rate +		  throttles[tnum].bytes_since_avg / elapsed ) / 2;	    throttles[tnum].bytes_since_avg = 0;	    }	}    }static voidclear_connection( connecttab* c, struct timeval* tvP )    {    ClientData client_data;    /* If we haven't actually sent the buffered response yet, do so now. */    httpd_write_response( &c->hc );    if ( c->idle_read_timer != (Timer*) 0 )	{	tmr_cancel( c->idle_read_timer );	c->idle_read_timer = 0;	}    if ( c->idle_send_timer != (Timer*) 0 )	{	tmr_cancel( c->idle_send_timer );	c->idle_send_timer = 0;	}    if ( c->wakeup_timer != (Timer*) 0 )	{	tmr_cancel( c->wakeup_timer );	c->wakeup_timer = 0;	}    /* This is our version of Apache's lingering_close() routine, which is    ** their version of the often-broken SO_LINGER socket option.  For why    ** this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html    ** What we do is delay the actual closing for a few seconds, while reading    ** any bytes that come over the connection.  However, we don't want to do    ** this unless it's necessary, because it ties up a connection slot and    ** file descriptor which means our maximum connection-handling rate    ** is lower.  So, elsewhere we set a flag when we detect the few    ** circumstances that make a lingering close necessary.  If the flag    ** isn't set we do the real close now.    */    if ( c->hc.should_linger )	{	c->conn_state = CNST_LINGERING;	recompute_fdsets = 1;	client_data.p = c;	c->linger_timer = tmr_create(	    tvP, linger_clear_connection, client_data, LINGER_TIME * 1000L, 0 );	}    else	really_clear_connection( c, tvP );    }static voidreally_clear_connection( connecttab* c, struct timeval* tvP )    {    httpd_close_conn( &c->hc, tvP );    clear_throttles( c, tvP );    if ( c->linger_timer != (Timer*) 0 )	{	tmr_cancel( c->linger_timer );	c->linger_timer = 0;	}    c->conn_state = CNST_FREE;    recompute_fdsets = 1;    --numconnects;    }static voididle_read_connection( ClientData client_data, struct timeval* nowP )    {    connecttab* c;    c = (connecttab*) client_data.p;    c->idle_read_timer = (Timer*) 0;    if ( c->conn_state != CNST_FREE )	{	syslog( LOG_NOTICE,	    "%.80s connection timed out reading",	    inet_ntoa( c->hc.client_addr ) );	httpd_send_err( &c->hc, 408, httpd_err408title, httpd_err408form, "" );	clear_connection( c, nowP );	}    }static voididle_send_connection( ClientData client_data, struct timeval* nowP )    {    connecttab* c;    c = (connecttab*) client_data.p;    c->idle_send_timer = (Timer*) 0;    if ( c->conn_state != CNST_FREE )	{	syslog( LOG_NOTICE,	    "%.80s connection timed out sending",	    inet_ntoa( c->hc.client_addr ) );	clear_connection( c, nowP );	}    }static voidwakeup_connection( ClientData client_data, struct timeval* nowP )    {    connecttab* c;    c = (connecttab*) client_data.p;    c->wakeup_timer = (Timer*) 0;    if ( c->conn_state == CNST_PAUSING )	{	c->conn_state = CNST_SENDING;	recompute_fdsets = 1;	}    }static voidlinger_clear_connection( ClientData client_data, struct timeval* nowP )    {    connecttab* c;    c = (connecttab*) client_data.p;    c->linger_timer = (Timer*) 0;    really_clear_connection( c, nowP );    }static voidoccasional( ClientData client_data, struct timeval* nowP )    {    mmc_cleanup( nowP );    tmr_cleanup();    }#ifdef STATS_TIMEstatic voidshow_stats( ClientData client_data, struct timeval* nowP )    {    int am, fm, at, ft;    mmc_stats( &am, &fm );    tmr_stats( &at, &ft );    syslog( LOG_INFO,	"%d seconds, %d connections, %d simultaneous, %d maps, %d timers",	STATS_TIME, stats_connections, stats_simultaneous, am, at );    stats_connections = stats_simultaneous = 0;    }#endif /* STATS_TIME */

⌨️ 快捷键说明

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