diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index c1d1b6b2db..c432599f05 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1249,6 +1249,20 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + tcp_user_timeout + + + Controls the number of milliseconds that transmitted data may + remain unacknowledged before a connection is forcefully closed. + A value of zero uses the system default. This parameter is + ignored for connections made via a Unix-domain socket. + It is only supported on systems where TCP_USER_TIMEOUT + is available; on other systems, it has no effect. + + + + tty diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index e3bf6a7449..ee46881c50 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -264,6 +264,11 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, keepalives_count)}, + /* TCP USER TIMEOUT */ + {"tcp_user_timeout", NULL, NULL, NULL, + "TCP_user_timeout", "", 10, /* strlen(INT32_MAX) == 10 */ + offsetof(struct pg_conn, pgtcp_user_timeout)}, + /* * ssl options are allowed even without client SSL support because the * client can still handle SSL modes "disable" and "allow". Other @@ -1786,6 +1791,40 @@ setKeepalivesWin32(PGconn *conn) #endif /* SIO_KEEPALIVE_VALS */ #endif /* WIN32 */ +/* + * Set the TCP user timeout. + */ +static int +setTCPUserTimeout(PGconn *conn) +{ + int timeout; + + if (conn->pgtcp_user_timeout == NULL) + return 1; + + if (!parse_int_param(conn->pgtcp_user_timeout, + &timeout, conn, "tcp_user_timeout")) + return 0; + + if (timeout < 0) + timeout = 0; + +#ifdef TCP_USER_TIMEOUT + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_USER_TIMEOUT, + (char *) &timeout, sizeof(timeout)) < 0) + { + char sebuf[256]; + + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("setsockopt(TCP_USER_TIMEOUT) failed: %s\n"), + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + return 0; + } +#endif + + return 1; +} + /* ---------- * connectDBStart - * Begin the process of making a connection to the backend. @@ -2428,6 +2467,9 @@ keep_going: /* We will come back to here until there is #endif /* SIO_KEEPALIVE_VALS */ #endif /* WIN32 */ + if (!setTCPUserTimeout(conn)) + err = 1; + if (err) { conn->try_next_addr = true; @@ -3655,6 +3697,8 @@ freePGconn(PGconn *conn) free(conn->pgtty); if (conn->connect_timeout) free(conn->connect_timeout); + if (conn->pgtcp_user_timeout) + free(conn->pgtcp_user_timeout); if (conn->pgoptions) free(conn->pgoptions); if (conn->appname) diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index dbe0f7e5c0..19068473fd 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -336,6 +336,7 @@ struct pg_conn char *pgtty; /* tty on which the backend messages is * displayed (OBSOLETE, NOT USED) */ char *connect_timeout; /* connection timeout (numeric string) */ + char *pgtcp_user_timeout; /* tcp user timeout (numeric string) */ char *client_encoding_initial; /* encoding to use */ char *pgoptions; /* options to start the backend with */ char *appname; /* application name */