mirror of
https://github.com/nginx/nginx.git
synced 2025-06-11 12:22:41 +08:00
Core: enable TCP keepalive for macOS and accepted sockets.
For TCP keepalive mechanism, SO_KEEPALIVE is inherited by a accepted socket from the listening socket on most UNIX-like OS's, whereas TCP_KEEP* options are only inherited on Linux, FreeBSD, or DragonFlyBSD. This PR does two things: 1. Set TCP keepalive options on accepted sockets in addition to the listening socket when the OS is not one of Linux, FreeBSD, or DragonFlyBSD. 2. Enable TCP keepalive on macOS by detecting and setting TCP_KEEPALIVE along with TCP_KEEPINTVL and TCP_KEEPCNT on the accepted sockets. Fixes #336 https://man7.org/linux/man-pages/man7/tcp.7.html https://man.freebsd.org/cgi/man.cgi?query=tcp https://groups.google.com/g/erlang-programming/c/vCI3PCZuj9k/m/PKnFAL5ZBQAJ
This commit is contained in:
parent
f3542500b6
commit
744629c1eb
@ -118,3 +118,24 @@ ngx_feature_libs=
|
||||
ngx_feature_test="int32_t lock = 0;
|
||||
if (!OSAtomicCompareAndSwap32Barrier(0, 1, &lock)) return 1"
|
||||
. auto/feature
|
||||
|
||||
|
||||
# TCP keepalive
|
||||
#
|
||||
# Darwin way to set TCP keepalive tunables, appeared in OS X Mavericks 10.9.
|
||||
# Tunable values are set on the accepted socket.
|
||||
|
||||
NGX_TCP_KEEPALIVE_CHECKED=YES
|
||||
|
||||
ngx_feature="TCP_KEEPALIVE"
|
||||
ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
|
||||
ngx_feature_run=yes
|
||||
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
|
||||
|
@ -90,12 +90,14 @@ EVENT_DEPS="src/event/ngx_event.h \
|
||||
src/event/ngx_event_posted.h \
|
||||
src/event/ngx_event_connect.h \
|
||||
src/event/ngx_event_pipe.h \
|
||||
src/event/ngx_event_tcp.h \
|
||||
src/event/ngx_event_udp.h"
|
||||
|
||||
EVENT_SRCS="src/event/ngx_event.c \
|
||||
src/event/ngx_event_timer.c \
|
||||
src/event/ngx_event_posted.c \
|
||||
src/event/ngx_event_accept.c \
|
||||
src/event/ngx_event_tcp.c \
|
||||
src/event/ngx_event_udp.c \
|
||||
src/event/ngx_event_connect.c \
|
||||
src/event/ngx_event_pipe.c"
|
||||
|
26
auto/unix
26
auto/unix
@ -508,18 +508,20 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_DEFER_ACCEPT, NULL, 0)"
|
||||
. 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 [ -z "$NGX_TCP_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"
|
||||
|
@ -764,52 +764,14 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
|
||||
}
|
||||
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
|
||||
|
||||
if (ls[i].keepidle) {
|
||||
value = ls[i].keepidle;
|
||||
|
||||
#if (NGX_KEEPALIVE_FACTOR)
|
||||
value *= NGX_KEEPALIVE_FACTOR;
|
||||
#endif
|
||||
|
||||
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
(const void *) &value, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
|
||||
"setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored",
|
||||
value, &ls[i].addr_text);
|
||||
}
|
||||
if (ngx_tcp_keepalive(ls[i].fd, ls[i].keepidle,
|
||||
ls[i].keepintvl, ls[i].keepcnt) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
|
||||
"ngx_tcp_keepalive(%d, %d, %d, %d) %V failed, ignored",
|
||||
ls[i].fd, ls[i].keepidle, ls[i].keepintvl, ls[i].keepcnt,
|
||||
&ls[i].addr_text);
|
||||
}
|
||||
|
||||
if (ls[i].keepintvl) {
|
||||
value = ls[i].keepintvl;
|
||||
|
||||
#if (NGX_KEEPALIVE_FACTOR)
|
||||
value *= NGX_KEEPALIVE_FACTOR;
|
||||
#endif
|
||||
|
||||
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
(const void *) &value, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
|
||||
"setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored",
|
||||
value, &ls[i].addr_text);
|
||||
}
|
||||
}
|
||||
|
||||
if (ls[i].keepcnt) {
|
||||
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
(const void *) &ls[i].keepcnt, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
|
||||
"setsockopt(TCP_KEEPCNT, %d) %V failed, ignored",
|
||||
ls[i].keepcnt, &ls[i].addr_text);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_SETFIB)
|
||||
|
@ -523,6 +523,7 @@ ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat);
|
||||
|
||||
#include <ngx_event_timer.h>
|
||||
#include <ngx_event_posted.h>
|
||||
#include <ngx_event_tcp.h>
|
||||
#include <ngx_event_udp.h>
|
||||
|
||||
#if (NGX_WIN32)
|
||||
|
@ -156,6 +156,26 @@ ngx_event_accept(ngx_event_t *ev)
|
||||
(void) ngx_atomic_fetch_add(ngx_stat_active, 1);
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE) && \
|
||||
!defined(__DragonFly__) && \
|
||||
!defined(__FreeBSD__) && \
|
||||
!defined(__linux__)
|
||||
/*
|
||||
* TCP keepalive options are not inherited from the listening socket
|
||||
* on platforms other than Linux, FreeBSD, or DragonFlyBSD.
|
||||
* We therefore need to set them on the accepted socket explicitly.
|
||||
*/
|
||||
|
||||
if (ngx_tcp_keepalive(s, ls->keepidle,
|
||||
ls->keepintvl, ls->keepcnt) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
|
||||
"ngx_tcp_keepalive(%d, %d, %d, %d) %V failed, ignored",
|
||||
ls->fd, ls->keepidle, ls->keepintvl, ls->keepcnt,
|
||||
&ls->addr_text);
|
||||
}
|
||||
#endif
|
||||
|
||||
c->pool = ngx_create_pool(ls->pool_size, ev->log);
|
||||
if (c->pool == NULL) {
|
||||
ngx_close_accepted_connection(c);
|
||||
|
73
src/event/ngx_event_tcp.c
Normal file
73
src/event/ngx_event_tcp.c
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Andy Pan
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
int
|
||||
ngx_tcp_keepalive(ngx_socket_t s, int idle, int interval, int count)
|
||||
{
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
|
||||
int sockval;
|
||||
|
||||
if (idle < 1 || interval < 1 || count < 1) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
sockval = idle;
|
||||
|
||||
#if (NGX_KEEPALIVE_FACTOR)
|
||||
sockval *= NGX_KEEPALIVE_FACTOR;
|
||||
#endif
|
||||
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
(const void *) &sockval, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#elif defined(TCP_KEEPALIVE)
|
||||
/* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE,
|
||||
(const void *) &sockval, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
sockval = interval;
|
||||
|
||||
#if (NGX_KEEPALIVE_FACTOR)
|
||||
sockval *= NGX_KEEPALIVE_FACTOR;
|
||||
#endif
|
||||
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
(const void *) &sockval, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
sockval = count;
|
||||
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
(const void *) &sockval, sizeof(int))
|
||||
== -1)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else /* !(NGX_HAVE_KEEPALIVE_TUNABLE) */
|
||||
|
||||
return NGX_ERROR;
|
||||
|
||||
#endif
|
||||
}
|
17
src/event/ngx_event_tcp.h
Normal file
17
src/event/ngx_event_tcp.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Andy Pan
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_TCP_H_INCLUDED_
|
||||
#define _NGX_EVENT_TCP_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
int ngx_tcp_keepalive(ngx_socket_t s, int idle, int interval, int count);
|
||||
|
||||
#endif /* _NGX_EVENT_TCP_H_INCLUDED_ */
|
Loading…
Reference in New Issue
Block a user