diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 182 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-int.h | 6 |
2 files changed, 186 insertions, 2 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 3a1465457e0..795b64e55bf 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.393 2010/05/26 21:39:27 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.394 2010/06/23 21:54:13 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -183,6 +183,18 @@ static const PQconninfoOption PQconninfoOptions[] = { {"fallback_application_name", NULL, NULL, NULL, "Fallback-Application-Name", "", 64}, + {"keepalives", NULL, NULL, NULL, + "TCP-Keepalives", "", 1}, /* should be just '0' or '1' */ + + {"keepalives_idle", NULL, NULL, NULL, + "TCP-Keepalives-Idle", "", 10}, /* strlen(INT32_MAX) == 10 */ + + {"keepalives_interval", NULL, NULL, NULL, + "TCP-Keepalives-Interval", "", 10}, /* strlen(INT32_MAX) == 10 */ + + {"keepalives_count", NULL, NULL, NULL, + "TCP-Keepalives-Count", "", 10}, /* strlen(INT32_MAX) == 10 */ + #ifdef USE_SSL /* @@ -552,6 +564,14 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions) conn->pgpass = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "connect_timeout"); conn->connect_timeout = tmp ? strdup(tmp) : NULL; + tmp = conninfo_getval(connOptions, "keepalives"); + conn->keepalives = tmp ? strdup(tmp) : NULL; + tmp = conninfo_getval(connOptions, "keepalives_idle"); + conn->keepalives_idle = tmp ? strdup(tmp) : NULL; + tmp = conninfo_getval(connOptions, "keepalives_interval"); + conn->keepalives_interval = tmp ? strdup(tmp) : NULL; + tmp = conninfo_getval(connOptions, "keepalives_count"); + conn->keepalives_count = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslmode"); conn->sslmode = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "sslkey"); @@ -943,6 +963,119 @@ connectFailureMessage(PGconn *conn, int errorno) } } +/* + * Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if + * conn->keepalives is set to a value which is not parseable as an + * integer. + */ +static int +useKeepalives(PGconn *conn) +{ + char *ep; + int val; + + if (conn->keepalives == NULL) + return 1; + val = strtol(conn->keepalives, &ep, 10); + if (*ep) + return -1; + return val != 0 ? 1 : 0; +} + +/* + * Set the keepalive idle timer. + */ +static int +setKeepalivesIdle(PGconn *conn) +{ + int idle; + + if (conn->keepalives_idle == NULL) + return 1; + + idle = atoi(conn->keepalives_idle); + if (idle < 0) + idle = 0; + +#ifdef TCP_KEEPIDLE + 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; + } +#endif + + return 1; +} + +/* + * Set the keepalive interval. + */ +static int +setKeepalivesInterval(PGconn *conn) +{ + int interval; + + if (conn->keepalives_interval == NULL) + return 1; + + interval = atoi(conn->keepalives_interval); + if (interval < 0) + interval = 0; + +#ifdef TCP_KEEPINTVL + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL, + (char *) &interval, sizeof(interval)) < 0) + { + char sebuf[256]; + + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"), + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + return 0; + } +#endif + + return 1; +} + +/* + * Set the count of lost keepalive packets that will trigger a connection + * break. + */ +static int +setKeepalivesCount(PGconn *conn) +{ + int count; + + if (conn->keepalives_count == NULL) + return 1; + + count = atoi(conn->keepalives_count); + if (count < 0) + count = 0; + +#ifdef TCP_KEEPCNT + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT, + (char *) &count, sizeof(count)) < 0) + { + char sebuf[256]; + + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"), + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + return 0; + } +#endif + + return 1; +} + /* ---------- * connectDBStart - @@ -1329,6 +1462,45 @@ keep_going: /* We will come back to here until there is } #endif /* F_SETFD */ + if (!IS_AF_UNIX(addr_cur->ai_family)) + { + int on = 1; + int usekeepalives = useKeepalives(conn); + int err = 0; + + if (usekeepalives < 0) + { + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("keepalives parameter must be an integer\n")); + err = 1; + } + else if (usekeepalives == 0) + { + /* Do nothing */ + } + else if (setsockopt(conn->sock, + SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)) < 0) + { + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"), + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + err = 1; + } + else if (!setKeepalivesIdle(conn) + || !setKeepalivesInterval(conn) + || !setKeepalivesCount(conn)) + err = 1; + + if (err) + { + closesocket(conn->sock); + conn->sock = -1; + conn->addr_cur = addr_cur->ai_next; + continue; + } + } + /*---------- * We have three methods of blocking SIGPIPE during * send() calls to this socket: @@ -2290,6 +2462,14 @@ freePGconn(PGconn *conn) free(conn->pguser); if (conn->pgpass) free(conn->pgpass); + if (conn->keepalives) + free(conn->keepalives); + if (conn->keepalives_idle) + free(conn->keepalives_idle); + if (conn->keepalives_interval) + free(conn->keepalives_interval); + if (conn->keepalives_count) + free(conn->keepalives_count); if (conn->sslmode) free(conn->sslmode); if (conn->sslcert) diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 6fe96ab1684..23b914abbc5 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.150 2010/03/13 14:55:57 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.151 2010/06/23 21:54:13 rhaas Exp $ * *------------------------------------------------------------------------- */ @@ -300,6 +300,10 @@ struct pg_conn char *replication; /* connect as the replication standby? */ char *pguser; /* Postgres username and password, if any */ char *pgpass; + char *keepalives; /* use TCP keepalives? */ + char *keepalives_idle; /* time between TCP keepalives */ + char *keepalives_interval; /* time between TCP keepalive retransmits */ + char *keepalives_count; /* maximum number of TCP keepalive retransmits */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ char *sslkey; /* client key filename */ char *sslcert; /* client certificate filename */ |