From 34eb35abdfdc660d90f104544f40331d659718a9 Mon Sep 17 00:00:00 2001 From: Francesco Canovai Date: Fri, 31 Jan 2025 13:39:51 +0100 Subject: [PATCH] Support TCP_SYNCNT in libpq Add a tcp_syn_count parameter to libpq. This will allow the user to define the maximum amount of retransmission that TCP will send before aborting the attempt to establish a connection. This can be used only on systems where TCP_SYNCNT is available. --- doc/src/sgml/libpq.sgml | 15 ++++++++++ src/interfaces/libpq/fe-connect.c | 49 +++++++++++++++++++++++++++++++ src/interfaces/libpq/libpq-int.h | 1 + 3 files changed, 65 insertions(+) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 8fa0515c6a0..8029819a25e 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1576,6 +1576,21 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + tcp_syn_count + + + Controls the maximum number of SYN retransmissions that TCP + will send before aborting the attempt to establish a connection. + A higher value increases the number of retries before giving up, + while a lower value results in faster failure detection. + This parameter is only effective on systems where + TCP_SYNCNT is available; on other systems, + it has no effect. + + + + replication diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index d5051f5e820..889c1c771d4 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -267,6 +267,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "TCP-User-Timeout", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, pgtcp_user_timeout)}, + {"tcp_syn_count", NULL, NULL, NULL, + "TCP-SYN-Count", "", 10, /* strlen(INT32_MAX) == 10 */ + offsetof(struct pg_conn, tcp_syn_count)}, + /* * ssl options are allowed even without client SSL support because the * client can still handle SSL modes "disable" and "allow". Other @@ -2627,6 +2631,41 @@ setTCPUserTimeout(PGconn *conn) return 1; } +/* +* Set the maximum number of SYN retransmissions. +*/ +static int +setTCPSynCnt(PGconn *conn) +{ + int count; + + if (conn->tcp_syn_count == NULL) + return 1; + + if (!pqParseIntParam(conn->tcp_syn_count, &count, conn, + "tcp_syn_count")) + return 0; + + if (count < 0) + count = 0; + +#ifdef TCP_SYNCNT + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_SYNCNT, + (char *) &count, sizeof(count)) < 0) + { + char sebuf[PG_STRERROR_R_BUFLEN]; + + libpq_append_conn_error(conn, "%s(%s) failed: %s", + "setsockopt", + "TCP_SYNCNT", + SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); + return 0; + } +#endif + + return 1; +} + /* ---------- * pqConnectDBStart - * Begin the process of making a connection to the backend. @@ -3368,6 +3407,15 @@ keep_going: /* We will come back to here until there is } } + if (addr_cur->family != AF_UNIX) + { + if (!setTCPSynCnt(conn)) + { + conn->try_next_addr = true; + goto keep_going; + } + } + /*---------- * We have three methods of blocking SIGPIPE during * send() calls to this socket: @@ -5008,6 +5056,7 @@ freePGconn(PGconn *conn) free(conn->keepalives_idle); free(conn->keepalives_interval); free(conn->keepalives_count); + free(conn->tcp_syn_count); free(conn->sslmode); free(conn->sslnegotiation); free(conn->sslcert); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index f36f7f19d58..d25f440a940 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -408,6 +408,7 @@ struct pg_conn * retransmits */ char *keepalives_count; /* maximum number of TCP keepalive * retransmits */ + char *tcp_syn_count; /* maximum number of TCP SYN retransmits */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ char *sslnegotiation; /* SSL initiation style (postgres,direct) */ char *sslcompression; /* SSL compression (0 or 1) */ -- 2.48.1