]> granicus.if.org Git - postgresql/commitdiff
Second try at fixing tcp_keepalives_idle option on Solaris.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 28 Jun 2017 16:30:16 +0000 (12:30 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 28 Jun 2017 16:30:16 +0000 (12:30 -0400)
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 (f0256c774), back-patch to all supported branches.

Discussion: https://postgr.es/m/20170627163757.25161.528@wrigleys.postgresql.org

doc/src/sgml/config.sgml
doc/src/sgml/libpq.sgml
src/backend/libpq/pqcomm.c
src/interfaces/libpq/fe-connect.c

index fc15b33ba478ca488bec58ad71da881e43e0a101..0baa79bb806fbdb308612217d614e479d488d400 100644 (file)
@@ -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
-        <symbol>TCP_KEEPIDLE</> or <symbol>TCP_KEEPALIVE</> symbols, and on
+        This parameter is supported only on systems that support
+        <symbol>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
-        <symbol>TCP_KEEPINTVL</> symbol, and on Windows; on other systems, it
-        must be zero.
+        This parameter is supported only on systems that support
+        <symbol>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.
        </para>
@@ -906,10 +906,11 @@ include_dir 'conf.d'
       <listitem>
        <para>
         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 <symbol>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
+        <symbol>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.
        </para>
index 983cf0d386b8b7733271025110156f00ea4b17b2..84590a0a6fa3e955bbd636bede77754e604b1dfb 100644 (file)
@@ -1073,10 +1073,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 <symbol>TCP_KEEPIDLE</> or <symbol>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 <symbol>TCP_KEEPIDLE</> or
+        an equivalent socket option is available, and on Windows; on other
+        systems, it has no effect.
        </para>
       </listitem>
      </varlistentry>
@@ -1089,9 +1089,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 <symbol>TCP_KEEPINTVL</>
-        socket option is available, and on Windows; on other systems, it has no
-        effect.
+        It is only supported on systems where <symbol>TCP_KEEPINTVL</> or
+        an equivalent socket option is available, and on Windows; on other
+        systems, it has no effect.
        </para>
       </listitem>
      </varlistentry>
@@ -1104,8 +1104,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 <symbol>TCP_KEEPCNT</>
-        socket option is available; on other systems, it has no effect.
+        It is only supported on systems where <symbol>TCP_KEEPCNT</> or
+        an equivalent socket option is available; on other systems, it has no
+        effect.
        </para>
       </listitem>
      </varlistentry>
index 65b02060383e5124c2192bca524b79e64c686d23..6a870b897303eb8247367995901ccf76e4a2335d 100644 (file)
 #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
  */
@@ -719,7 +738,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
@@ -727,7 +746,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;
                }
 
@@ -758,7 +777,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;
@@ -767,7 +786,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;
                        }
                }
@@ -1653,7 +1672,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;
 
@@ -1665,34 +1684,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,
-                                          (char *) &port->default_keepalives_idle,
-                                          &size) < 0)
-               {
-                       elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m");
-                       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,
+               if (getsockopt(port->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
                                           (char *) &port->default_keepalives_idle,
                                           &size) < 0)
                {
-                       elog(LOG, "getsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %m");
+                       elog(LOG, "getsockopt(%s) failed: %m", PG_TCP_KEEPALIVE_IDLE_STR);
                        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;
@@ -1712,7 +1710,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;
 
@@ -1731,43 +1729,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,
-                                  (char *) &idle, sizeof(idle)) < 0)
-       {
-               elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m");
-               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,
+       if (setsockopt(port->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
                                   (char *) &idle, sizeof(idle)) < 0)
        {
-               elog(LOG, "setsockopt(TCP_KEEPALIVE_THRESHOLD) failed: %m");
+               elog(LOG, "setsockopt(%s) failed: %m", PG_TCP_KEEPALIVE_IDLE_STR);
                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;
 }
 
@@ -1790,7 +1770,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
@@ -1833,7 +1813,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;
        }
 
@@ -1844,7 +1824,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
@@ -1870,7 +1850,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 */
                }
        }
@@ -1908,7 +1888,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;
        }
 
@@ -1916,7 +1896,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
index 443b4fb3e2be42eb540508afa0376b5103e41ca8..e61ed7dc28c5decd6a2cf5045d8b3ac7ddddfabf 100644 (file)
@@ -99,6 +99,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
@@ -1280,39 +1299,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,
-                                  (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,
+#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_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;
        }
@@ -1343,7 +1338,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;
        }
@@ -1375,7 +1371,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;
        }
@@ -1841,7 +1838,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;
                                                }