uhttpd: protect tcp receive operations with select, make tcp keep-alive optional (#8272)
SVN-Revision: 24952
This commit is contained in:
		
							parent
							
								
									8067116c10
								
							
						
					
					
						commit
						f38a320e69
					
				@ -8,7 +8,7 @@
 | 
			
		||||
include $(TOPDIR)/rules.mk
 | 
			
		||||
 | 
			
		||||
PKG_NAME:=uhttpd
 | 
			
		||||
PKG_RELEASE:=20
 | 
			
		||||
PKG_RELEASE:=21
 | 
			
		||||
 | 
			
		||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 | 
			
		||||
PKG_BUILD_DEPENDS := libcyassl liblua
 | 
			
		||||
 | 
			
		||||
@ -51,6 +51,13 @@ config uhttpd main
 | 
			
		||||
	# request process.
 | 
			
		||||
	option network_timeout	30
 | 
			
		||||
 | 
			
		||||
	# TCP Keep-Alive, send periodic keep-alive probes
 | 
			
		||||
	# over established connections to detect dead peers.
 | 
			
		||||
	# The value is given in seconds to specify the
 | 
			
		||||
	# interval between subsequent probes.
 | 
			
		||||
	# Setting this to 0 will disable TCP keep-alive.
 | 
			
		||||
	option tcp_keepalive	1
 | 
			
		||||
 | 
			
		||||
	# Basic auth realm, defaults to local hostname
 | 
			
		||||
#	option realm	OpenWrt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -66,6 +66,7 @@ start_instance()
 | 
			
		||||
	append_arg "$cfg" lua_handler "-L"
 | 
			
		||||
	append_arg "$cfg" script_timeout "-t"
 | 
			
		||||
	append_arg "$cfg" network_timeout "-T"
 | 
			
		||||
	append_arg "$cfg" tcp_keepalive "-A"
 | 
			
		||||
	append_arg "$cfg" error_page "-E"
 | 
			
		||||
	append_arg "$cfg" index_page "-I"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -167,6 +167,9 @@ int uh_tcp_recv(struct client *cl, char *buf, int len)
 | 
			
		||||
	int sz = 0;
 | 
			
		||||
	int rsz = 0;
 | 
			
		||||
 | 
			
		||||
	fd_set reader;
 | 
			
		||||
	struct timeval timeout;
 | 
			
		||||
 | 
			
		||||
	/* first serve data from peek buffer */
 | 
			
		||||
	if( cl->peeklen > 0 )
 | 
			
		||||
	{
 | 
			
		||||
@ -180,15 +183,28 @@ int uh_tcp_recv(struct client *cl, char *buf, int len)
 | 
			
		||||
	/* caller wants more */
 | 
			
		||||
	if( len > 0 )
 | 
			
		||||
	{
 | 
			
		||||
#ifdef HAVE_TLS
 | 
			
		||||
		if( cl->tls )
 | 
			
		||||
			rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
 | 
			
		||||
		else
 | 
			
		||||
#endif
 | 
			
		||||
			rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
 | 
			
		||||
		FD_ZERO(&reader);
 | 
			
		||||
		FD_SET(cl->socket, &reader);
 | 
			
		||||
 | 
			
		||||
		if( (sz == 0) || (rsz > 0) )
 | 
			
		||||
			sz += rsz;
 | 
			
		||||
		timeout.tv_sec  = cl->server->conf->network_timeout;
 | 
			
		||||
		timeout.tv_usec = 0;
 | 
			
		||||
 | 
			
		||||
		if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
 | 
			
		||||
		{
 | 
			
		||||
#ifdef HAVE_TLS
 | 
			
		||||
			if( cl->tls )
 | 
			
		||||
				rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
 | 
			
		||||
			else
 | 
			
		||||
#endif
 | 
			
		||||
				rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
 | 
			
		||||
 | 
			
		||||
			if( (sz == 0) || (rsz > 0) )
 | 
			
		||||
				sz += rsz;
 | 
			
		||||
		}
 | 
			
		||||
		else if( sz == 0 )
 | 
			
		||||
		{
 | 
			
		||||
			sz = -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sz;
 | 
			
		||||
@ -233,7 +249,7 @@ int uh_http_sendc(struct client *cl, const char *data, int len)
 | 
			
		||||
 | 
			
		||||
	if( len > 0 )
 | 
			
		||||
	{
 | 
			
		||||
	 	clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
 | 
			
		||||
		clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
 | 
			
		||||
		ensure_ret(uh_tcp_send(cl, chunk, clen));
 | 
			
		||||
		ensure_ret(uh_tcp_send(cl, data, len));
 | 
			
		||||
		ensure_ret(uh_tcp_send(cl, "\r\n", 2));
 | 
			
		||||
 | 
			
		||||
@ -127,9 +127,7 @@ static int uh_socket_bind(
 | 
			
		||||
	int status;
 | 
			
		||||
	int bound = 0;
 | 
			
		||||
 | 
			
		||||
	int tcp_ka_idl = 1;
 | 
			
		||||
	int tcp_ka_int = 1;
 | 
			
		||||
	int tcp_ka_cnt = 3;
 | 
			
		||||
	int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt;
 | 
			
		||||
 | 
			
		||||
	struct listener *l = NULL;
 | 
			
		||||
	struct addrinfo *addrs = NULL, *p = NULL;
 | 
			
		||||
@ -157,13 +155,20 @@ static int uh_socket_bind(
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* TCP keep-alive */
 | 
			
		||||
		if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
 | 
			
		||||
		    setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,  &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
 | 
			
		||||
		    setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
 | 
			
		||||
		    setsockopt(sock, SOL_TCP, TCP_KEEPCNT,   &tcp_ka_cnt, sizeof(tcp_ka_cnt)) )
 | 
			
		||||
		if( conf->tcp_keepalive > 0 )
 | 
			
		||||
		{
 | 
			
		||||
		    fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
 | 
			
		||||
		    	strerror(errno));
 | 
			
		||||
			tcp_ka_idl = 1;
 | 
			
		||||
			tcp_ka_cnt = 3;
 | 
			
		||||
			tcp_ka_int = conf->tcp_keepalive;
 | 
			
		||||
 | 
			
		||||
			if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
 | 
			
		||||
			    setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,  &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
 | 
			
		||||
			    setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
 | 
			
		||||
			    setsockopt(sock, SOL_TCP, TCP_KEEPCNT,   &tcp_ka_cnt, sizeof(tcp_ka_cnt)) )
 | 
			
		||||
			{
 | 
			
		||||
			    fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
 | 
			
		||||
			    	strerror(errno));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* required to get parallel v4 + v6 working */
 | 
			
		||||
@ -619,7 +624,7 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
 | 
			
		||||
int main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	/* master file descriptor list */
 | 
			
		||||
	fd_set used_fds, serv_fds, read_fds;
 | 
			
		||||
	fd_set serv_fds;
 | 
			
		||||
 | 
			
		||||
	/* working structs */
 | 
			
		||||
	struct addrinfo hints;
 | 
			
		||||
@ -650,10 +655,7 @@ int main (int argc, char **argv)
 | 
			
		||||
	void *lib;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* clear the master and temp sets */
 | 
			
		||||
	FD_ZERO(&used_fds);
 | 
			
		||||
	FD_ZERO(&serv_fds);
 | 
			
		||||
	FD_ZERO(&read_fds);
 | 
			
		||||
 | 
			
		||||
	/* handle SIGPIPE, SIGINT, SIGTERM, SIGCHLD */
 | 
			
		||||
	sa.sa_flags = 0;
 | 
			
		||||
@ -722,7 +724,7 @@ int main (int argc, char **argv)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	while( (opt = getopt(argc, argv,
 | 
			
		||||
		"fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:")) > 0
 | 
			
		||||
		"fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:A:")) > 0
 | 
			
		||||
	) {
 | 
			
		||||
		switch(opt)
 | 
			
		||||
		{
 | 
			
		||||
@ -896,6 +898,11 @@ int main (int argc, char **argv)
 | 
			
		||||
				conf.network_timeout = atoi(optarg);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			/* tcp keep-alive */
 | 
			
		||||
			case 'A':
 | 
			
		||||
				conf.tcp_keepalive = atoi(optarg);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			/* no fork */
 | 
			
		||||
			case 'f':
 | 
			
		||||
				nofork = 1;
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,7 @@ struct config {
 | 
			
		||||
	int no_dirlists;
 | 
			
		||||
	int network_timeout;
 | 
			
		||||
	int rfc1918_filter;
 | 
			
		||||
	int tcp_keepalive;
 | 
			
		||||
#ifdef HAVE_CGI
 | 
			
		||||
	char *cgi_prefix;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user