[PATCH] Add support for tcp_user_timeout in http listen directive

Andy Isaacson adi at hexapodia.org
Mon Jun 29 22:55:25 UTC 2015


# HG changeset patch
# User Andy Isaacson <adi at orionlabs.co>
# Date 1435618451 25200
#      Mon Jun 29 15:54:11 2015 -0700
# Node ID c11304760218324ea55de7250a613af8f13e431b
# Parent  b95e70ae6bcdbae99a967df01e1011839f19ee0e
Add support for tcp_user_timeout in http listen directive

This commit adds support for a new tcp_user_timeout=<timeout_sec>
parameter to the listen directive.  When enabled and set to a value
greater than zero, the TCP_USER_TIMEOUT sockopt is set.  From tcp(7):

    This specifies the maximum amount of time in milliseconds
    that transmitted data may remain unacknowledged before TCP
    will forcibly close the corresponding connection and return
    ETIMEDOUT to the application.

Without this capability, a HTTP longpoll connection can remain active
for up to 950 seconds after the last ACK from the client.

Note that the tcp_user_timeout value is specified in (integer) seconds,
but the setsockopt API is specified in milliseconds.

This capability is similar to the systemwide configuration
net.ipv4.tcp_retries2 on Linux, but more flexible and per-socket.

diff -r b95e70ae6bcd -r c11304760218 auto/unix
--- a/auto/unix	Thu Sep 05 16:53:02 2013 +0400
+++ b/auto/unix	Mon Jun 29 15:54:11 2015 -0700
@@ -330,6 +330,18 @@
 . auto/feature
 
 
+ngx_feature="TCP_USER_TIMEOUT"
+ngx_feature_name="NGX_HAVE_TCP_USER_TIMEOUT"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>
+                  #include <netinet/in.h>
+                  #include <netinet/tcp.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_USER_TIMEOUT, NULL, 0)"
+. auto/feature
+
+
 ngx_feature="TCP_KEEPIDLE"
 ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
 ngx_feature_run=no
diff -r b95e70ae6bcd -r c11304760218 src/core/ngx_connection.h
--- a/src/core/ngx_connection.h	Thu Sep 05 16:53:02 2013 +0400
+++ b/src/core/ngx_connection.h	Mon Jun 29 15:54:11 2015 -0700
@@ -80,6 +80,10 @@
     int                 setfib;
 #endif
 
+#if (NGX_HAVE_TCP_USER_TIMEOUT)
+    int                 tcp_user_timeout;
+#endif
+
 };
 
 
diff -r b95e70ae6bcd -r c11304760218 src/event/ngx_event_accept.c
--- a/src/event/ngx_event_accept.c	Thu Sep 05 16:53:02 2013 +0400
+++ b/src/event/ngx_event_accept.c	Mon Jun 29 15:54:11 2015 -0700
@@ -284,6 +284,23 @@
             }
         }
 
+#if (NGX_HAVE_TCP_USER_TIMEOUT)
+#ifdef TCP_USER_TIMEOUT
+        if (ls->tcp_user_timeout) {
+            int value = ls->tcp_user_timeout;
+
+            if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &value,
+                            sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
+                              "setsockopt(TCP_USER_TIMEOUT, %d) for %V failed",
+                              value, c->addr_text);
+            }
+        }
+#endif
+#endif
+
 #if (NGX_DEBUG)
         {
 
diff -r b95e70ae6bcd -r c11304760218 src/http/ngx_http.c
--- a/src/http/ngx_http.c	Thu Sep 05 16:53:02 2013 +0400
+++ b/src/http/ngx_http.c	Mon Jun 29 15:54:11 2015 -0700
@@ -1800,6 +1800,10 @@
     ls->deferred_accept = addr->opt.deferred_accept;
 #endif
 
+#if (NGX_HAVE_TCP_USER_TIMEOUT && defined TCP_USER_TIMEOUT)
+    ls->tcp_user_timeout = addr->opt.tcp_user_timeout;
+#endif
+
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
     ls->ipv6only = addr->opt.ipv6only;
 #endif
diff -r b95e70ae6bcd -r c11304760218 src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c	Thu Sep 05 16:53:02 2013 +0400
+++ b/src/http/ngx_http_core_module.c	Mon Jun 29 15:54:11 2015 -0700
@@ -4085,6 +4085,31 @@
             continue;
         }
 
+        if (ngx_strncmp(value[n].data, "tcp_user_timeout=", 17) == 0) {
+#if (NGX_HAVE_TCP_USER_TIMEOUT && defined TCP_USER_TIMEOUT)
+            int timeout_sec = ngx_atoi(value[n].data + 17, value[n].len - 17);
+
+            /*
+             * convert from seconds (in config file) to milliseconds (for
+             * setsockopt)
+             */
+            lsopt.tcp_user_timeout = timeout_sec * 1000;
+
+            if (lsopt.tcp_user_timeout < 0) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "Invalid tcp_user_timeout \"%V\"",
+                                   &value[n]);
+                return NGX_CONF_ERROR;
+            }
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "tcp_user_timeout \"%V\" is not supported on "
+                               "this platform, ignored",
+                               &value[n]);
+#endif
+            continue;
+        }
+
         if (ngx_strcmp(value[n].data, "deferred") == 0) {
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
             lsopt.deferred_accept = 1;
diff -r b95e70ae6bcd -r c11304760218 src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h	Thu Sep 05 16:53:02 2013 +0400
+++ b/src/http/ngx_http_core_module.h	Mon Jun 29 15:54:11 2015 -0700
@@ -102,6 +102,10 @@
     ngx_uint_t                 deferred_accept;
 #endif
 
+#if (NGX_HAVE_TCP_USER_TIMEOUT && defined TCP_USER_TIMEOUT)
+    int                        tcp_user_timeout;
+#endif
+
     u_char                     addr[NGX_SOCKADDR_STRLEN + 1];
 } ngx_http_listen_opt_t;
 



More information about the nginx-devel mailing list