changeset 9416:2034e305475d

Core: added support for TCP keepalive parameters on macOS. The support first appeared in OS X Mavericks 10.9 and documented since OS X Yosemite 10.10. It has a subtle implementation difference from other operating systems in that the TCP_KEEPALIVE socket option (used in place of TCP_KEEPIDLE) isn't inherited from a listening socket to an accepted socket. An apparent reason for this behaviour is that it might be preserved for the sake of backward compatibility. The TCP_KEEPALIVE socket option is not inherited since appearance in OS X Panther 10.3, which long predates two other TCP_KEEPINTVL and TCP_KEEPCNT socket options. Thanks to Andy Pan for initial work.
author Sergey Kandaurov <pluknet@nginx.com>
date Mon, 26 May 2025 16:11:36 +0400
parents f1c6fdc44ac2
children b4cfd7b4e4ea
files auto/os/darwin auto/unix src/core/ngx_connection.c src/event/ngx_event_accept.c
diffstat 4 files changed, 51 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/auto/os/darwin	Fri Jan 17 12:24:08 2025 -0800
+++ b/auto/os/darwin	Mon May 26 16:11:36 2025 +0400
@@ -118,3 +118,19 @@
 ngx_feature_test="int32_t  lock = 0;
                   if (!OSAtomicCompareAndSwap32Barrier(0, 1, &lock)) return 1"
 . auto/feature
+
+
+ngx_feature="TCP_KEEPALIVE"
+ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
+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_KEEPALIVE, NULL, 0);
+                  setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0);
+                  setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)"
+. auto/feature
+
+NGX_KEEPALIVE_CHECKED=YES
--- a/auto/unix	Fri Jan 17 12:24:08 2025 -0800
+++ b/auto/unix	Mon May 26 16:11:36 2025 +0400
@@ -508,18 +508,20 @@
 . auto/feature
 
 
-ngx_feature="TCP_KEEPIDLE"
-ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
-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_KEEPIDLE, NULL, 0);
-                  setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0);
-                  setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)"
-. auto/feature
+if test -z "$NGX_KEEPALIVE_CHECKED"; then
+    ngx_feature="TCP_KEEPIDLE"
+    ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
+    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_KEEPIDLE, NULL, 0);
+                      setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0);
+                      setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)"
+    . auto/feature
+fi
 
 
 ngx_feature="TCP_FASTOPEN"
--- a/src/core/ngx_connection.c	Fri Jan 17 12:24:08 2025 -0800
+++ b/src/core/ngx_connection.c	Mon May 26 16:11:36 2025 +0400
@@ -765,6 +765,8 @@
 
 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
 
+#if !(NGX_DARWIN)
+
         if (ls[i].keepidle) {
             value = ls[i].keepidle;
 
@@ -782,6 +784,8 @@
             }
         }
 
+#endif
+
         if (ls[i].keepintvl) {
             value = ls[i].keepintvl;
 
--- a/src/event/ngx_event_accept.c	Fri Jan 17 12:24:08 2025 -0800
+++ b/src/event/ngx_event_accept.c	Mon May 26 16:11:36 2025 +0400
@@ -203,6 +203,23 @@
             }
         }
 
+#if (NGX_HAVE_KEEPALIVE_TUNABLE && NGX_DARWIN)
+
+        /* Darwin doesn't inherit TCP_KEEPALIVE from a listening socket */
+
+        if (ls->keepidle) {
+            if (setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,
+                           (const void *) &ls->keepidle, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
+                              "setsockopt(TCP_KEEPALIVE, %d) failed, ignored",
+                              ls->keepidle);
+            }
+        }
+
+#endif
+
         *log = ls->log;
 
         c->recv = ngx_recv;