From: Jo-Philipp Wich Date: Sun, 9 Jan 2011 23:35:45 +0000 (+0000) Subject: uhttpd: protect tcp receive operations with select, make tcp keep-alive optional... X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=f38a320e693d951e6bcd0fb2ee4e81855d48a21c;p=openwrt%2Fstaging%2F981213.git uhttpd: protect tcp receive operations with select, make tcp keep-alive optional (#8272) SVN-Revision: 24952 --- diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile index a0b7d24ebf..bba7ac53ad 100644 --- a/package/uhttpd/Makefile +++ b/package/uhttpd/Makefile @@ -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 diff --git a/package/uhttpd/files/uhttpd.config b/package/uhttpd/files/uhttpd.config index a29910a65f..08ca5e5e02 100644 --- a/package/uhttpd/files/uhttpd.config +++ b/package/uhttpd/files/uhttpd.config @@ -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 diff --git a/package/uhttpd/files/uhttpd.init b/package/uhttpd/files/uhttpd.init index f8f1754e90..069e16fff1 100755 --- a/package/uhttpd/files/uhttpd.init +++ b/package/uhttpd/files/uhttpd.init @@ -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" diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c index c7bc867aab..ac00af824e 100644 --- a/package/uhttpd/src/uhttpd-utils.c +++ b/package/uhttpd/src/uhttpd-utils.c @@ -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 ) { + FD_ZERO(&reader); + FD_SET(cl->socket, &reader); + + 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 + 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); + rsz = recv(cl->socket, (void *)&buf[sz], len, 0); - if( (sz == 0) || (rsz > 0) ) - sz += rsz; + 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)); diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c index 2c7755f8da..1fd21344fe 100644 --- a/package/uhttpd/src/uhttpd.c +++ b/package/uhttpd/src/uhttpd.c @@ -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; diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h index 6747b905ff..ff058d62bf 100644 --- a/package/uhttpd/src/uhttpd.h +++ b/package/uhttpd/src/uhttpd.h @@ -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