uhttpd: protect tcp receive operations with select, make tcp keep-alive optional...
authorJo-Philipp Wich <jow@openwrt.org>
Sun, 9 Jan 2011 23:35:45 +0000 (23:35 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sun, 9 Jan 2011 23:35:45 +0000 (23:35 +0000)
SVN-Revision: 24952

package/uhttpd/Makefile
package/uhttpd/files/uhttpd.config
package/uhttpd/files/uhttpd.init
package/uhttpd/src/uhttpd-utils.c
package/uhttpd/src/uhttpd.c
package/uhttpd/src/uhttpd.h

index a0b7d24ebfb536ca8bd18213cc4a8532afb1bf9f..bba7ac53ad255c5c38a7f1a21b9f5526ca8494a9 100644 (file)
@@ -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
index a29910a65f38b3d1409dfb40bd2aedad788bfcf7..08ca5e5e02e3726769e7f95a8b8031fd9d4599ac 100644 (file)
@@ -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
 
index f8f1754e9065b7587b961fb4345a45bda2d8079b..069e16fff1ca769028d98764e615294230a2ade9 100755 (executable)
@@ -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"
 
index c7bc867aab2da63913d48548070a6ecfc99fa959..ac00af824e7801e314b854c32940739a75a746e0 100644 (file)
@@ -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));
index 2c7755f8da4c5ed5d61aa0ee5d8d02813fc6d7ce..1fd21344fee54ed2b22473e82c88b77fe8e02436 100644 (file)
@@ -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;
index 6747b905ff459f7a69ccbc9ec187904b8c226a74..ff058d62bff3e214e4dee0e5c8cb5e35a63050e7 100644 (file)
@@ -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