Support tcp_keepalives_idle option on Solaris.
authorTom Lane <[email protected]>
Tue, 27 Jun 2017 22:47:57 +0000 (18:47 -0400)
committerTom Lane <[email protected]>
Tue, 27 Jun 2017 22:47:57 +0000 (18:47 -0400)
Turns out that the socket option for this is named TCP_KEEPALIVE_THRESHOLD,
at least according to the tcp(7P) man page for Solaris 11.  (But since that
text refers to "SunOS", it's likely pretty ancient.)  It appears that the
symbol TCP_KEEPALIVE does get defined on that platform, but it doesn't
seem to represent a valid protocol-level socket option.  This leads to
bleats in the postmaster log, and no tcp_keepalives_idle functionality.

Per bug #14720 from Andrey Lizenko, as well as an earlier report from
Dhiraj Chawla that nobody had followed up on.  The issue's been there
since we added the TCP_KEEPALIVE code path in commit 5acd417c8, so
back-patch to all supported branches.

Discussion: https://postgr.es/m/20170627163757[email protected]

src/backend/libpq/pqcomm.c
src/interfaces/libpq/fe-connect.c

index 261e9be8281dda96cab73400388b09cc484b1e0c..c62f7e9ab330845d6c0bffed100f641d61bc4a7d 100644 (file)
@@ -1676,7 +1676,7 @@ pq_setkeepaliveswin32(Port *port, int idle, int interval)
 int
 pq_getkeepalivesidle(Port *port)
 {
-#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) || defined(WIN32)
+#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE_THRESHOLD) || defined(TCP_KEEPALIVE) || defined(WIN32)
    if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
        return 0;
 
@@ -1688,7 +1688,8 @@ pq_getkeepalivesidle(Port *port)
 #ifndef WIN32
        ACCEPT_TYPE_ARG3 size = sizeof(port->default_keepalives_idle);
 
-#ifdef TCP_KEEPIDLE
+#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)
@@ -1696,7 +1697,17 @@ pq_getkeepalivesidle(Port *port)
            elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m");
            port->default_keepalives_idle = -1; /* don't know */
        }
-#else
+#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)
@@ -1704,7 +1715,7 @@ pq_getkeepalivesidle(Port *port)
            elog(LOG, "getsockopt(TCP_KEEPALIVE) failed: %m");
            port->default_keepalives_idle = -1; /* don't know */
        }
-#endif                         /* TCP_KEEPIDLE */
+#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;
@@ -1723,7 +1734,8 @@ pq_setkeepalivesidle(int idle, Port *port)
    if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
        return STATUS_OK;
 
-#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPALIVE) || defined(SIO_KEEPALIVE_VALS)
+/* 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 (idle == port->keepalives_idle)
        return STATUS_OK;
 
@@ -1742,14 +1754,24 @@ pq_setkeepalivesidle(int idle, Port *port)
    if (idle == 0)
        idle = port->default_keepalives_idle;
 
-#ifdef TCP_KEEPIDLE
+#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;
    }
-#else
+#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)
    {
@@ -1762,7 +1784,7 @@ pq_setkeepalivesidle(int idle, Port *port)
 #else                          /* WIN32 */
    return pq_setkeepaliveswin32(port, idle, port->keepalives_interval);
 #endif
-#else                          /* TCP_KEEPIDLE || SIO_KEEPALIVE_VALS */
+#else                          /* no way to set it */
    if (idle != 0)
    {
        elog(LOG, "setting the keepalive idle time is not supported");
@@ -1812,7 +1834,7 @@ pq_setkeepalivesinterval(int interval, Port *port)
    if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
        return STATUS_OK;
 
-#if defined(TCP_KEEPINTVL) || defined (SIO_KEEPALIVE_VALS)
+#if defined(TCP_KEEPINTVL) || defined(SIO_KEEPALIVE_VALS)
    if (interval == port->keepalives_interval)
        return STATUS_OK;
 
index 764e9601fe9b8185f5c347a531d71aa18f2e54e7..e32c42b4b6b0401dcef6e4c3a9d4c41b81bbff2f 100644 (file)
@@ -1470,7 +1470,8 @@ setKeepalivesIdle(PGconn *conn)
    if (idle < 0)
        idle = 0;
 
-#ifdef TCP_KEEPIDLE
+#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)
    {
@@ -1481,9 +1482,20 @@ setKeepalivesIdle(PGconn *conn)
                          SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
        return 0;
    }
-#else
-#ifdef TCP_KEEPALIVE
-   /* macOS uses TCP_KEEPALIVE rather than TCP_KEEPIDLE */
+#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)
    {
@@ -1494,7 +1506,6 @@ setKeepalivesIdle(PGconn *conn)
                          SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
        return 0;
    }
-#endif
 #endif
 
    return 1;
@@ -1562,7 +1573,7 @@ setKeepalivesCount(PGconn *conn)
 
    return 1;
 }
-#else                          /* Win32 */
+#else                          /* WIN32 */
 #ifdef SIO_KEEPALIVE_VALS
 /*
  * Enable keepalives and set the keepalive values on Win32,