diff options
Diffstat (limited to 'src/backend/libpq/pqcomm.c')
-rw-r--r-- | src/backend/libpq/pqcomm.c | 213 |
1 files changed, 211 insertions, 2 deletions
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index ce321af4b13..43c2a88a451 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -30,7 +30,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.176 2005/02/22 04:35:57 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.177 2005/07/30 15:17:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -87,7 +87,7 @@ #include "libpq/libpq.h" #include "miscadmin.h" #include "storage/ipc.h" - +#include "utils/guc.h" /* * Configuration options @@ -594,6 +594,19 @@ StreamConnection(int server_fd, Port *port) elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); return STATUS_ERROR; } + + /* Set default keepalive parameters. This should also catch + * misconfigurations (non-zero values when socket options aren't + * supported) + */ + if (pq_setkeepalivesidle(tcp_keepalives_idle, port) != STATUS_OK) + return STATUS_ERROR; + + if (pq_setkeepalivesinterval(tcp_keepalives_interval, port) != STATUS_OK) + return STATUS_ERROR; + + if (pq_setkeepalivescount(tcp_keepalives_count, port) != STATUS_OK) + return STATUS_ERROR; } return STATUS_OK; @@ -1158,3 +1171,199 @@ pq_endcopyout(bool errorAbort) /* in non-error case, copy.c will have emitted the terminator line */ DoingCopyOut = false; } + +int +pq_getkeepalivesidle(Port *port) +{ +#ifdef TCP_KEEPIDLE + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return 0; + + if (port->keepalives_idle != 0) + return port->keepalives_idle; + + if (port->default_keepalives_idle == 0) + { + socklen_t size = sizeof(port->default_keepalives_idle); + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPIDLE, + (char *) &port->default_keepalives_idle, + &size) < 0) + { + elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m"); + return -1; + } + } + + return port->default_keepalives_idle; +#else + return 0; +#endif +} + +int +pq_setkeepalivesidle(int idle, Port *port) +{ + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + +#ifdef TCP_KEEPIDLE + if (idle == port->keepalives_idle) + return STATUS_OK; + + if (port->default_keepalives_idle == 0) + { + if (pq_getkeepalivesidle(port) < 0) + return STATUS_ERROR; + } + + if (idle == 0) + idle = port->default_keepalives_idle; + + if (setsockopt(port->sock, SOL_TCP, TCP_KEEPIDLE, + (char *) &idle, sizeof(idle)) < 0) + { + elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m"); + return STATUS_ERROR; + } + + port->keepalives_idle = idle; +#else + if (idle != 0) + { + elog(LOG, "setsockopt(TCP_KEEPIDLE) not supported"); + return STATUS_ERROR; + } +#endif + + return STATUS_OK; +} + +int +pq_getkeepalivesinterval(Port *port) +{ +#ifdef TCP_KEEPINTVL + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return 0; + + if (port->keepalives_interval != 0) + return port->keepalives_interval; + + if (port->default_keepalives_interval == 0) + { + socklen_t size = sizeof(port->default_keepalives_interval); + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPINTVL, + (char *) &port->default_keepalives_interval, + &size) < 0) + { + elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); + return -1; + } + } + + return port->default_keepalives_interval; +#else + return 0; +#endif +} + +int +pq_setkeepalivesinterval(int interval, Port *port) +{ + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + +#ifdef TCP_KEEPINTVL + if (interval == port->keepalives_interval) + return STATUS_OK; + + if (port->default_keepalives_interval == 0) { + if (pq_getkeepalivesinterval(port) < 0) + return STATUS_ERROR; + } + + if (interval == 0) + interval = port->default_keepalives_interval; + + if (setsockopt(port->sock, SOL_TCP, TCP_KEEPINTVL, + (char *) &interval, sizeof(interval)) < 0) + { + elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m"); + return STATUS_ERROR; + } + + port->keepalives_interval = interval; +#else + if (interval != 0) + { + elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported"); + return STATUS_ERROR; + } +#endif + + return STATUS_OK; +} + +int +pq_getkeepalivescount(Port *port) +{ +#ifdef TCP_KEEPCNT + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return 0; + + if (port->keepalives_count != 0) + return port->keepalives_count; + + if (port->default_keepalives_count == 0) + { + socklen_t size = sizeof(port->default_keepalives_count); + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPCNT, + (char *) &port->default_keepalives_count, + &size) < 0) + { + elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m"); + return -1; + } + } + + return port->default_keepalives_count; +#else + return 0; +#endif +} + +int +pq_setkeepalivescount(int count, Port *port) +{ + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + +#ifdef TCP_KEEPCNT + if (count == port->keepalives_count) + return STATUS_OK; + + if (port->default_keepalives_count == 0) { + if (pq_getkeepalivescount(port) < 0) + return STATUS_ERROR; + } + + if (count == 0) + count = port->default_keepalives_count; + + if (setsockopt(port->sock, SOL_TCP, TCP_KEEPCNT, + (char *) &count, sizeof(count)) < 0) + { + elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m"); + return STATUS_ERROR; + } + + port->keepalives_count = count; +#else + if (count != 0) + { + elog(LOG, "setsockopt(TCP_KEEPCNT) not supported"); + return STATUS_ERROR; + } +#endif + + return STATUS_OK; +} |