diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 3aca6479b1..2485e6190d 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -856,8 +856,8 @@ include_dir 'conf.d' Specifies the number of seconds of inactivity after which TCP should send a keepalive message to the client. A value of 0 uses the system default. - This parameter is supported only on systems that support the - TCP_KEEPIDLE or TCP_KEEPALIVE symbols, and on + This parameter is supported only on systems that support + TCP_KEEPIDLE or an equivalent socket option, and on Windows; on other systems, it must be zero. In sessions connected via a Unix-domain socket, this parameter is ignored and always reads as zero. @@ -882,9 +882,9 @@ include_dir 'conf.d' Specifies the number of seconds after which a TCP keepalive message that is not acknowledged by the client should be retransmitted. A value of 0 uses the system default. - This parameter is supported only on systems that support the - TCP_KEEPINTVL symbol, and on Windows; on other systems, it - must be zero. + This parameter is supported only on systems that support + TCP_KEEPINTVL or an equivalent socket option, and on + Windows; on other systems, it must be zero. In sessions connected via a Unix-domain socket, this parameter is ignored and always reads as zero. @@ -906,10 +906,11 @@ include_dir 'conf.d' Specifies the number of TCP keepalives that can be lost before - the server's connection to the client is considered dead. A value of 0 - uses the system default. This parameter is - supported only on systems that support the TCP_KEEPCNT - symbol; on other systems, it must be zero. + the server's connection to the client is considered dead. + A value of 0 uses the system default. + This parameter is supported only on systems that support + TCP_KEEPCNT or an equivalent socket option; + on other systems, it must be zero. In sessions connected via a Unix-domain socket, this parameter is ignored and always reads as zero. diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index c3bd4f9b9b..1b3d55b8b9 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1125,10 +1125,10 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname Controls the number of seconds of inactivity after which TCP should send a keepalive message to the server. A value of zero uses the system default. This parameter is ignored for connections made via a - Unix-domain socket, or if keepalives are disabled. It is only supported - on systems where the TCP_KEEPIDLE or TCP_KEEPALIVE - socket option is available, and on Windows; on other systems, it has no - effect. + Unix-domain socket, or if keepalives are disabled. + It is only supported on systems where TCP_KEEPIDLE or + an equivalent socket option is available, and on Windows; on other + systems, it has no effect. @@ -1141,9 +1141,9 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname that is not acknowledged by the server should be retransmitted. A value of zero uses the system default. This parameter is ignored for connections made via a Unix-domain socket, or if keepalives are disabled. - It is only supported on systems where the TCP_KEEPINTVL - socket option is available, and on Windows; on other systems, it has no - effect. + It is only supported on systems where TCP_KEEPINTVL or + an equivalent socket option is available, and on Windows; on other + systems, it has no effect. @@ -1156,8 +1156,9 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname client's connection to the server is considered dead. A value of zero uses the system default. This parameter is ignored for connections made via a Unix-domain socket, or if keepalives are disabled. - It is only supported on systems where the TCP_KEEPCNT - socket option is available; on other systems, it has no effect. + It is only supported on systems where TCP_KEEPCNT or + an equivalent socket option is available; on other systems, it has no + effect. diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index c62f7e9ab3..4452ea4228 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -96,6 +96,25 @@ #include "utils/guc.h" #include "utils/memutils.h" +/* + * Cope with the various platform-specific ways to spell TCP keepalive socket + * options. This doesn't cover Windows, which as usual does its own thing. + */ +#if defined(TCP_KEEPIDLE) +/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ +#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE +#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE" +#elif defined(TCP_KEEPALIVE_THRESHOLD) +/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */ +#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD +#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD" +#elif defined(TCP_KEEPALIVE) && defined(__darwin__) +/* TCP_KEEPALIVE is the name of this option on macOS */ +/* Caution: Solaris has this symbol but it means something different */ +#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE +#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE" +#endif + /* * Configuration options */ @@ -742,7 +761,7 @@ StreamConnection(pgsocket server_fd, Port *port) if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { - elog(LOG, "setsockopt(TCP_NODELAY) failed: %m"); + elog(LOG, "setsockopt(%s) failed: %m", "TCP_NODELAY"); return STATUS_ERROR; } #endif @@ -750,7 +769,7 @@ StreamConnection(pgsocket server_fd, Port *port) if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { - elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); + elog(LOG, "setsockopt(%s) failed: %m", "SO_KEEPALIVE"); return STATUS_ERROR; } @@ -781,7 +800,7 @@ StreamConnection(pgsocket server_fd, Port *port) if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt, &optlen) < 0) { - elog(LOG, "getsockopt(SO_SNDBUF) failed: %m"); + elog(LOG, "getsockopt(%s) failed: %m", "SO_SNDBUF"); return STATUS_ERROR; } newopt = PQ_SEND_BUFFER_SIZE * 4; @@ -790,7 +809,7 @@ StreamConnection(pgsocket server_fd, Port *port) if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt, sizeof(newopt)) < 0) { - elog(LOG, "setsockopt(SO_SNDBUF) failed: %m"); + elog(LOG, "setsockopt(%s) failed: %m", "SO_SNDBUF"); return STATUS_ERROR; } } @@ -1676,7 +1695,7 @@ pq_setkeepaliveswin32(Port *port, int idle, int interval) int pq_getkeepalivesidle(Port *port) { -#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE_THRESHOLD) || defined(TCP_KEEPALIVE) || defined(WIN32) +#if defined(PG_TCP_KEEPALIVE_IDLE) || defined(SIO_KEEPALIVE_VALS) if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family)) return 0; @@ -1688,34 +1707,13 @@ pq_getkeepalivesidle(Port *port) #ifndef WIN32 ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle); -#if defined(TCP_KEEPIDLE) - /* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ - if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE, + if (getsockopt(port->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE, (char *) &port->default_keepalives_idle, &size) < 0) { - elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m"); + elog(LOG, "getsockopt(%s) failed: %m", PG_TCP_KEEPALIVE_IDLE_STR); port->default_keepalives_idle = -1; /* don't know */ } -#elif defined(TCP_KEEPALIVE_THRESHOLD) - /* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris */ - if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, - (char *) &port->default_keepalives_idle, - &size) < 0) - { - elog(LOG, "getsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %m"); - port->default_keepalives_idle = -1; /* don't know */ - } -#else /* must have TCP_KEEPALIVE */ - /* TCP_KEEPALIVE is the name of this option on macOS */ - if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE, - (char *) &port->default_keepalives_idle, - &size) < 0) - { - elog(LOG, "getsockopt(TCP_KEEPALIVE) failed: %m"); - port->default_keepalives_idle = -1; /* don't know */ - } -#endif /* KEEPIDLE/KEEPALIVE_THRESHOLD/KEEPALIVE */ #else /* WIN32 */ /* We can't get the defaults on Windows, so return "don't know" */ port->default_keepalives_idle = -1; @@ -1735,7 +1733,7 @@ pq_setkeepalivesidle(int idle, Port *port) return STATUS_OK; /* check SIO_KEEPALIVE_VALS here, not just WIN32, as some toolchains lack it */ -#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE_THRESHOLD) || defined(TCP_KEEPALIVE) || defined(SIO_KEEPALIVE_VALS) +#if defined(PG_TCP_KEEPALIVE_IDLE) || defined(SIO_KEEPALIVE_VALS) if (idle == port->keepalives_idle) return STATUS_OK; @@ -1754,43 +1752,25 @@ pq_setkeepalivesidle(int idle, Port *port) if (idle == 0) idle = port->default_keepalives_idle; -#if defined(TCP_KEEPIDLE) - /* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ - if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE, + if (setsockopt(port->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE, (char *) &idle, sizeof(idle)) < 0) { - elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m"); + elog(LOG, "setsockopt(%s) failed: %m", PG_TCP_KEEPALIVE_IDLE_STR); return STATUS_ERROR; } -#elif defined(TCP_KEEPALIVE_THRESHOLD) - /* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris */ - if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, - (char *) &idle, sizeof(idle)) < 0) - { - elog(LOG, "setsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %m"); - return STATUS_ERROR; - } -#else /* must have TCP_KEEPALIVE */ - /* TCP_KEEPALIVE is the name of this option on macOS */ - if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE, - (char *) &idle, sizeof(idle)) < 0) - { - elog(LOG, "setsockopt(TCP_KEEPALIVE) failed: %m"); - return STATUS_ERROR; - } -#endif port->keepalives_idle = idle; #else /* WIN32 */ return pq_setkeepaliveswin32(port, idle, port->keepalives_interval); #endif -#else /* no way to set it */ +#else if (idle != 0) { elog(LOG, "setting the keepalive idle time is not supported"); return STATUS_ERROR; } #endif + return STATUS_OK; } @@ -1813,7 +1793,7 @@ pq_getkeepalivesinterval(Port *port) (char *) &port->default_keepalives_interval, &size) < 0) { - elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); + elog(LOG, "getsockopt(%s) failed: %m", "TCP_KEEPINTVL"); port->default_keepalives_interval = -1; /* don't know */ } #else @@ -1856,7 +1836,7 @@ pq_setkeepalivesinterval(int interval, Port *port) if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &interval, sizeof(interval)) < 0) { - elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m"); + elog(LOG, "setsockopt(%s) failed: %m", "TCP_KEEPINTVL"); return STATUS_ERROR; } @@ -1867,7 +1847,7 @@ pq_setkeepalivesinterval(int interval, Port *port) #else if (interval != 0) { - elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported"); + elog(LOG, "setsockopt(%s) not supported", "TCP_KEEPINTVL"); return STATUS_ERROR; } #endif @@ -1893,7 +1873,7 @@ pq_getkeepalivescount(Port *port) (char *) &port->default_keepalives_count, &size) < 0) { - elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m"); + elog(LOG, "getsockopt(%s) failed: %m", "TCP_KEEPCNT"); port->default_keepalives_count = -1; /* don't know */ } } @@ -1931,7 +1911,7 @@ pq_setkeepalivescount(int count, Port *port) if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT, (char *) &count, sizeof(count)) < 0) { - elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m"); + elog(LOG, "setsockopt(%s) failed: %m", "TCP_KEEPCNT"); return STATUS_ERROR; } @@ -1939,7 +1919,7 @@ pq_setkeepalivescount(int count, Port *port) #else if (count != 0) { - elog(LOG, "setsockopt(TCP_KEEPCNT) not supported"); + elog(LOG, "setsockopt(%s) not supported", "TCP_KEEPCNT"); return STATUS_ERROR; } #endif diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index e32c42b4b6..2f7b4060df 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -94,6 +94,25 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, /* This too */ #define ERRCODE_CANNOT_CONNECT_NOW "57P03" +/* + * Cope with the various platform-specific ways to spell TCP keepalive socket + * options. This doesn't cover Windows, which as usual does its own thing. + */ +#if defined(TCP_KEEPIDLE) +/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ +#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE +#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE" +#elif defined(TCP_KEEPALIVE_THRESHOLD) +/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */ +#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD +#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD" +#elif defined(TCP_KEEPALIVE) && defined(__darwin__) +/* TCP_KEEPALIVE is the name of this option on macOS */ +/* Caution: Solaris has this symbol but it means something different */ +#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE +#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE" +#endif + /* * fall back options if they are not specified by arguments or defined * by environment variables @@ -1470,39 +1489,15 @@ setKeepalivesIdle(PGconn *conn) if (idle < 0) idle = 0; -#if defined(TCP_KEEPIDLE) - /* TCP_KEEPIDLE is the name of this option on Linux and *BSD */ - if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE, +#ifdef PG_TCP_KEEPALIVE_IDLE + if (setsockopt(conn->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE, (char *) &idle, sizeof(idle)) < 0) { char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(TCP_KEEPIDLE) failed: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - return 0; - } -#elif defined(TCP_KEEPALIVE_THRESHOLD) - /* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris */ - if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, - (char *) &idle, sizeof(idle)) < 0) - { - char sebuf[256]; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %s\n"), - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - return 0; - } -#elif defined(TCP_KEEPALIVE) - /* TCP_KEEPALIVE is the name of this option on macOS */ - if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE, - (char *) &idle, sizeof(idle)) < 0) - { - char sebuf[256]; - - appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(TCP_KEEPALIVE) failed: %s\n"), + libpq_gettext("setsockopt(%s) failed: %s\n"), + PG_TCP_KEEPALIVE_IDLE_STR, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } @@ -1533,7 +1528,8 @@ setKeepalivesInterval(PGconn *conn) char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"), + libpq_gettext("setsockopt(%s) failed: %s\n"), + "TCP_KEEPINTVL", SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } @@ -1565,7 +1561,8 @@ setKeepalivesCount(PGconn *conn) char sebuf[256]; appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"), + libpq_gettext("setsockopt(%s) failed: %s\n"), + "TCP_KEEPCNT", SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } @@ -2123,7 +2120,8 @@ keep_going: /* We will come back to here until there is (char *) &on, sizeof(on)) < 0) { appendPQExpBuffer(&conn->errorMessage, - libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"), + libpq_gettext("setsockopt(%s) failed: %s\n"), + "SO_KEEPALIVE", SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); err = 1; }