Skip to content

Commit 43c67e3

Browse files
committed
Second try at fixing tcp_keepalives_idle option on Solaris.
Buildfarm evidence shows that TCP_KEEPALIVE_THRESHOLD doesn't exist after all on Solaris < 11. This means we need to take positive action to prevent the TCP_KEEPALIVE code path from being taken on that platform. I've chosen to limit it with "&& defined(__darwin__)", since it's unclear that anyone else would follow Apple's precedent of spelling the symbol that way. Also, follow a suggestion from Michael Paquier of eliminating code duplication by defining a couple of intermediate symbols for the socket option. In passing, make some effort to reduce the number of translatable messages by replacing "setsockopt(foo) failed" with "setsockopt(%s) failed", etc, throughout the affected files. And update relevant documentation so that it doesn't claim to provide an exhaustive list of the possible socket option names. Like the previous commit (f0256c7), back-patch to all supported branches. Discussion: https://postgr.es/m/20170627163757.25161.528@wrigleys.postgresql.org
1 parent a2de017 commit 43c67e3

File tree

4 files changed

+86
-106
lines changed

4 files changed

+86
-106
lines changed

doc/src/sgml/config.sgml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -856,8 +856,8 @@ include_dir 'conf.d'
856856
Specifies the number of seconds of inactivity after which TCP
857857
should send a keepalive message to the client. A value of 0 uses
858858
the system default.
859-
This parameter is supported only on systems that support the
860-
<symbol>TCP_KEEPIDLE</> or <symbol>TCP_KEEPALIVE</> symbols, and on
859+
This parameter is supported only on systems that support
860+
<symbol>TCP_KEEPIDLE</> or an equivalent socket option, and on
861861
Windows; on other systems, it must be zero.
862862
In sessions connected via a Unix-domain socket, this parameter is
863863
ignored and always reads as zero.
@@ -882,9 +882,9 @@ include_dir 'conf.d'
882882
Specifies the number of seconds after which a TCP keepalive message
883883
that is not acknowledged by the client should be retransmitted.
884884
A value of 0 uses the system default.
885-
This parameter is supported only on systems that support the
886-
<symbol>TCP_KEEPINTVL</> symbol, and on Windows; on other systems, it
887-
must be zero.
885+
This parameter is supported only on systems that support
886+
<symbol>TCP_KEEPINTVL</> or an equivalent socket option, and on
887+
Windows; on other systems, it must be zero.
888888
In sessions connected via a Unix-domain socket, this parameter is
889889
ignored and always reads as zero.
890890
</para>
@@ -906,10 +906,11 @@ include_dir 'conf.d'
906906
<listitem>
907907
<para>
908908
Specifies the number of TCP keepalives that can be lost before
909-
the server's connection to the client is considered dead. A value of 0
910-
uses the system default. This parameter is
911-
supported only on systems that support the <symbol>TCP_KEEPCNT</>
912-
symbol; on other systems, it must be zero.
909+
the server's connection to the client is considered dead.
910+
A value of 0 uses the system default.
911+
This parameter is supported only on systems that support
912+
<symbol>TCP_KEEPCNT</> or an equivalent socket option;
913+
on other systems, it must be zero.
913914
In sessions connected via a Unix-domain socket, this parameter is
914915
ignored and always reads as zero.
915916
</para>

doc/src/sgml/libpq.sgml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,10 +1073,10 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
10731073
Controls the number of seconds of inactivity after which TCP should
10741074
send a keepalive message to the server. A value of zero uses the
10751075
system default. This parameter is ignored for connections made via a
1076-
Unix-domain socket, or if keepalives are disabled. It is only supported
1077-
on systems where the <symbol>TCP_KEEPIDLE</> or <symbol>TCP_KEEPALIVE</>
1078-
socket option is available, and on Windows; on other systems, it has no
1079-
effect.
1076+
Unix-domain socket, or if keepalives are disabled.
1077+
It is only supported on systems where <symbol>TCP_KEEPIDLE</> or
1078+
an equivalent socket option is available, and on Windows; on other
1079+
systems, it has no effect.
10801080
</para>
10811081
</listitem>
10821082
</varlistentry>
@@ -1089,9 +1089,9 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
10891089
that is not acknowledged by the server should be retransmitted. A
10901090
value of zero uses the system default. This parameter is ignored for
10911091
connections made via a Unix-domain socket, or if keepalives are disabled.
1092-
It is only supported on systems where the <symbol>TCP_KEEPINTVL</>
1093-
socket option is available, and on Windows; on other systems, it has no
1094-
effect.
1092+
It is only supported on systems where <symbol>TCP_KEEPINTVL</> or
1093+
an equivalent socket option is available, and on Windows; on other
1094+
systems, it has no effect.
10951095
</para>
10961096
</listitem>
10971097
</varlistentry>
@@ -1104,8 +1104,9 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
11041104
client's connection to the server is considered dead. A value of
11051105
zero uses the system default. This parameter is ignored for
11061106
connections made via a Unix-domain socket, or if keepalives are disabled.
1107-
It is only supported on systems where the <symbol>TCP_KEEPCNT</>
1108-
socket option is available; on other systems, it has no effect.
1107+
It is only supported on systems where <symbol>TCP_KEEPCNT</> or
1108+
an equivalent socket option is available; on other systems, it has no
1109+
effect.
11091110
</para>
11101111
</listitem>
11111112
</varlistentry>

src/backend/libpq/pqcomm.c

Lines changed: 37 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,25 @@
9696
#include "utils/guc.h"
9797
#include "utils/memutils.h"
9898

99+
/*
100+
* Cope with the various platform-specific ways to spell TCP keepalive socket
101+
* options. This doesn't cover Windows, which as usual does its own thing.
102+
*/
103+
#if defined(TCP_KEEPIDLE)
104+
/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */
105+
#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE
106+
#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE"
107+
#elif defined(TCP_KEEPALIVE_THRESHOLD)
108+
/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */
109+
#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD
110+
#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD"
111+
#elif defined(TCP_KEEPALIVE) && defined(__darwin__)
112+
/* TCP_KEEPALIVE is the name of this option on macOS */
113+
/* Caution: Solaris has this symbol but it means something different */
114+
#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE
115+
#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE"
116+
#endif
117+
99118
/*
100119
* Configuration options
101120
*/
@@ -719,15 +738,15 @@ StreamConnection(pgsocket server_fd, Port *port)
719738
if (setsockopt(port->sock, IPPROTO_TCP, TCP_NODELAY,
720739
(char *) &on, sizeof(on)) < 0)
721740
{
722-
elog(LOG, "setsockopt(TCP_NODELAY) failed: %m");
741+
elog(LOG, "setsockopt(%s) failed: %m", "TCP_NODELAY");
723742
return STATUS_ERROR;
724743
}
725744
#endif
726745
on = 1;
727746
if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE,
728747
(char *) &on, sizeof(on)) < 0)
729748
{
730-
elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m");
749+
elog(LOG, "setsockopt(%s) failed: %m", "SO_KEEPALIVE");
731750
return STATUS_ERROR;
732751
}
733752

@@ -758,7 +777,7 @@ StreamConnection(pgsocket server_fd, Port *port)
758777
if (getsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &oldopt,
759778
&optlen) < 0)
760779
{
761-
elog(LOG, "getsockopt(SO_SNDBUF) failed: %m");
780+
elog(LOG, "getsockopt(%s) failed: %m", "SO_SNDBUF");
762781
return STATUS_ERROR;
763782
}
764783
newopt = PQ_SEND_BUFFER_SIZE * 4;
@@ -767,7 +786,7 @@ StreamConnection(pgsocket server_fd, Port *port)
767786
if (setsockopt(port->sock, SOL_SOCKET, SO_SNDBUF, (char *) &newopt,
768787
sizeof(newopt)) < 0)
769788
{
770-
elog(LOG, "setsockopt(SO_SNDBUF) failed: %m");
789+
elog(LOG, "setsockopt(%s) failed: %m", "SO_SNDBUF");
771790
return STATUS_ERROR;
772791
}
773792
}
@@ -1653,7 +1672,7 @@ pq_setkeepaliveswin32(Port *port, int idle, int interval)
16531672
int
16541673
pq_getkeepalivesidle(Port *port)
16551674
{
1656-
#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE_THRESHOLD) || defined(TCP_KEEPALIVE) || defined(WIN32)
1675+
#if defined(PG_TCP_KEEPALIVE_IDLE) || defined(SIO_KEEPALIVE_VALS)
16571676
if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
16581677
return 0;
16591678

@@ -1665,34 +1684,13 @@ pq_getkeepalivesidle(Port *port)
16651684
#ifndef WIN32
16661685
ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle);
16671686

1668-
#if defined(TCP_KEEPIDLE)
1669-
/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */
1670-
if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
1671-
(char *) &port->default_keepalives_idle,
1672-
&size) < 0)
1673-
{
1674-
elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m");
1675-
port->default_keepalives_idle = -1; /* don't know */
1676-
}
1677-
#elif defined(TCP_KEEPALIVE_THRESHOLD)
1678-
/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris */
1679-
if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
1687+
if (getsockopt(port->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
16801688
(char *) &port->default_keepalives_idle,
16811689
&size) < 0)
16821690
{
1683-
elog(LOG, "getsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %m");
1691+
elog(LOG, "getsockopt(%s) failed: %m", PG_TCP_KEEPALIVE_IDLE_STR);
16841692
port->default_keepalives_idle = -1; /* don't know */
16851693
}
1686-
#else /* must have TCP_KEEPALIVE */
1687-
/* TCP_KEEPALIVE is the name of this option on macOS */
1688-
if (getsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE,
1689-
(char *) &port->default_keepalives_idle,
1690-
&size) < 0)
1691-
{
1692-
elog(LOG, "getsockopt(TCP_KEEPALIVE) failed: %m");
1693-
port->default_keepalives_idle = -1; /* don't know */
1694-
}
1695-
#endif /* KEEPIDLE/KEEPALIVE_THRESHOLD/KEEPALIVE */
16961694
#else /* WIN32 */
16971695
/* We can't get the defaults on Windows, so return "don't know" */
16981696
port->default_keepalives_idle = -1;
@@ -1712,7 +1710,7 @@ pq_setkeepalivesidle(int idle, Port *port)
17121710
return STATUS_OK;
17131711

17141712
/* check SIO_KEEPALIVE_VALS here, not just WIN32, as some toolchains lack it */
1715-
#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE_THRESHOLD) || defined(TCP_KEEPALIVE) || defined(SIO_KEEPALIVE_VALS)
1713+
#if defined(PG_TCP_KEEPALIVE_IDLE) || defined(SIO_KEEPALIVE_VALS)
17161714
if (idle == port->keepalives_idle)
17171715
return STATUS_OK;
17181716

@@ -1731,43 +1729,25 @@ pq_setkeepalivesidle(int idle, Port *port)
17311729
if (idle == 0)
17321730
idle = port->default_keepalives_idle;
17331731

1734-
#if defined(TCP_KEEPIDLE)
1735-
/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */
1736-
if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPIDLE,
1737-
(char *) &idle, sizeof(idle)) < 0)
1738-
{
1739-
elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m");
1740-
return STATUS_ERROR;
1741-
}
1742-
#elif defined(TCP_KEEPALIVE_THRESHOLD)
1743-
/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris */
1744-
if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
1732+
if (setsockopt(port->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
17451733
(char *) &idle, sizeof(idle)) < 0)
17461734
{
1747-
elog(LOG, "setsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %m");
1735+
elog(LOG, "setsockopt(%s) failed: %m", PG_TCP_KEEPALIVE_IDLE_STR);
17481736
return STATUS_ERROR;
17491737
}
1750-
#else /* must have TCP_KEEPALIVE */
1751-
/* TCP_KEEPALIVE is the name of this option on macOS */
1752-
if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPALIVE,
1753-
(char *) &idle, sizeof(idle)) < 0)
1754-
{
1755-
elog(LOG, "setsockopt(TCP_KEEPALIVE) failed: %m");
1756-
return STATUS_ERROR;
1757-
}
1758-
#endif
17591738

17601739
port->keepalives_idle = idle;
17611740
#else /* WIN32 */
17621741
return pq_setkeepaliveswin32(port, idle, port->keepalives_interval);
17631742
#endif
1764-
#else /* no way to set it */
1743+
#else
17651744
if (idle != 0)
17661745
{
17671746
elog(LOG, "setting the keepalive idle time is not supported");
17681747
return STATUS_ERROR;
17691748
}
17701749
#endif
1750+
17711751
return STATUS_OK;
17721752
}
17731753

@@ -1790,7 +1770,7 @@ pq_getkeepalivesinterval(Port *port)
17901770
(char *) &port->default_keepalives_interval,
17911771
&size) < 0)
17921772
{
1793-
elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m");
1773+
elog(LOG, "getsockopt(%s) failed: %m", "TCP_KEEPINTVL");
17941774
port->default_keepalives_interval = -1; /* don't know */
17951775
}
17961776
#else
@@ -1833,7 +1813,7 @@ pq_setkeepalivesinterval(int interval, Port *port)
18331813
if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPINTVL,
18341814
(char *) &interval, sizeof(interval)) < 0)
18351815
{
1836-
elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m");
1816+
elog(LOG, "setsockopt(%s) failed: %m", "TCP_KEEPINTVL");
18371817
return STATUS_ERROR;
18381818
}
18391819

@@ -1844,7 +1824,7 @@ pq_setkeepalivesinterval(int interval, Port *port)
18441824
#else
18451825
if (interval != 0)
18461826
{
1847-
elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported");
1827+
elog(LOG, "setsockopt(%s) not supported", "TCP_KEEPINTVL");
18481828
return STATUS_ERROR;
18491829
}
18501830
#endif
@@ -1870,7 +1850,7 @@ pq_getkeepalivescount(Port *port)
18701850
(char *) &port->default_keepalives_count,
18711851
&size) < 0)
18721852
{
1873-
elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m");
1853+
elog(LOG, "getsockopt(%s) failed: %m", "TCP_KEEPCNT");
18741854
port->default_keepalives_count = -1; /* don't know */
18751855
}
18761856
}
@@ -1908,15 +1888,15 @@ pq_setkeepalivescount(int count, Port *port)
19081888
if (setsockopt(port->sock, IPPROTO_TCP, TCP_KEEPCNT,
19091889
(char *) &count, sizeof(count)) < 0)
19101890
{
1911-
elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m");
1891+
elog(LOG, "setsockopt(%s) failed: %m", "TCP_KEEPCNT");
19121892
return STATUS_ERROR;
19131893
}
19141894

19151895
port->keepalives_count = count;
19161896
#else
19171897
if (count != 0)
19181898
{
1919-
elog(LOG, "setsockopt(TCP_KEEPCNT) not supported");
1899+
elog(LOG, "setsockopt(%s) not supported", "TCP_KEEPCNT");
19201900
return STATUS_ERROR;
19211901
}
19221902
#endif

src/interfaces/libpq/fe-connect.c

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,25 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
9999
/* This too */
100100
#define ERRCODE_CANNOT_CONNECT_NOW "57P03"
101101

102+
/*
103+
* Cope with the various platform-specific ways to spell TCP keepalive socket
104+
* options. This doesn't cover Windows, which as usual does its own thing.
105+
*/
106+
#if defined(TCP_KEEPIDLE)
107+
/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */
108+
#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE
109+
#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE"
110+
#elif defined(TCP_KEEPALIVE_THRESHOLD)
111+
/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */
112+
#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD
113+
#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD"
114+
#elif defined(TCP_KEEPALIVE) && defined(__darwin__)
115+
/* TCP_KEEPALIVE is the name of this option on macOS */
116+
/* Caution: Solaris has this symbol but it means something different */
117+
#define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE
118+
#define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE"
119+
#endif
120+
102121
/*
103122
* fall back options if they are not specified by arguments or defined
104123
* by environment variables
@@ -1280,39 +1299,15 @@ setKeepalivesIdle(PGconn *conn)
12801299
if (idle < 0)
12811300
idle = 0;
12821301

1283-
#if defined(TCP_KEEPIDLE)
1284-
/* TCP_KEEPIDLE is the name of this option on Linux and *BSD */
1285-
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE,
1286-
(char *) &idle, sizeof(idle)) < 0)
1287-
{
1288-
char sebuf[256];
1289-
1290-
appendPQExpBuffer(&conn->errorMessage,
1291-
libpq_gettext("setsockopt(TCP_KEEPIDLE) failed: %s\n"),
1292-
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1293-
return 0;
1294-
}
1295-
#elif defined(TCP_KEEPALIVE_THRESHOLD)
1296-
/* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris */
1297-
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
1298-
(char *) &idle, sizeof(idle)) < 0)
1299-
{
1300-
char sebuf[256];
1301-
1302-
appendPQExpBuffer(&conn->errorMessage,
1303-
libpq_gettext("setsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %s\n"),
1304-
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1305-
return 0;
1306-
}
1307-
#elif defined(TCP_KEEPALIVE)
1308-
/* TCP_KEEPALIVE is the name of this option on macOS */
1309-
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPALIVE,
1302+
#ifdef PG_TCP_KEEPALIVE_IDLE
1303+
if (setsockopt(conn->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
13101304
(char *) &idle, sizeof(idle)) < 0)
13111305
{
13121306
char sebuf[256];
13131307

13141308
appendPQExpBuffer(&conn->errorMessage,
1315-
libpq_gettext("setsockopt(TCP_KEEPALIVE) failed: %s\n"),
1309+
libpq_gettext("setsockopt(%s) failed: %s\n"),
1310+
PG_TCP_KEEPALIVE_IDLE_STR,
13161311
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
13171312
return 0;
13181313
}
@@ -1343,7 +1338,8 @@ setKeepalivesInterval(PGconn *conn)
13431338
char sebuf[256];
13441339

13451340
appendPQExpBuffer(&conn->errorMessage,
1346-
libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"),
1341+
libpq_gettext("setsockopt(%s) failed: %s\n"),
1342+
"TCP_KEEPINTVL",
13471343
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
13481344
return 0;
13491345
}
@@ -1375,7 +1371,8 @@ setKeepalivesCount(PGconn *conn)
13751371
char sebuf[256];
13761372

13771373
appendPQExpBuffer(&conn->errorMessage,
1378-
libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"),
1374+
libpq_gettext("setsockopt(%s) failed: %s\n"),
1375+
"TCP_KEEPCNT",
13791376
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
13801377
return 0;
13811378
}
@@ -1841,7 +1838,8 @@ PQconnectPoll(PGconn *conn)
18411838
(char *) &on, sizeof(on)) < 0)
18421839
{
18431840
appendPQExpBuffer(&conn->errorMessage,
1844-
libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"),
1841+
libpq_gettext("setsockopt(%s) failed: %s\n"),
1842+
"SO_KEEPALIVE",
18451843
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
18461844
err = 1;
18471845
}

0 commit comments

Comments
 (0)