From 0b8e21375ce3b55048503c51948c979cd443613c Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Thu, 30 Sep 2021 16:29:53 +0200 Subject: [PATCH] Use tcp_user_timeout in PQcancel PGcancel would not adhere to the timeout specified in the tcp_user_timeout connection option. Which means a call to PGcancel could take much longer than expected. This can especially be an issue because there's no non blocking version of PGcancel. --- src/interfaces/libpq/fe-connect.c | 26 +++++++++++++++++++++++--- src/interfaces/libpq/libpq-int.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 56755f0796..0c1ec9d64d 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -4363,13 +4363,19 @@ PQgetCancel(PGconn *conn) if (conn->sock == PGINVALID_SOCKET) return NULL; - cancel = malloc(sizeof(PGcancel)); + cancel = calloc(1, sizeof(PGcancel)); if (cancel == NULL) return NULL; memcpy(&cancel->raddr, &conn->raddr, sizeof(SockAddr)); cancel->be_pid = conn->be_pid; cancel->be_key = conn->be_key; + if (conn->pgtcp_user_timeout != NULL) { + if (!parse_int_param(conn->pgtcp_user_timeout, &cancel->pgtcp_user_timeout, conn, + "tcp_user_timeout")) { + return NULL; + } + } return cancel; } @@ -4404,7 +4410,7 @@ PQfreeCancel(PGcancel *cancel) * between the two versions of the cancel function possible. */ static int -internal_cancel(SockAddr *raddr, int be_pid, int be_key, +internal_cancel(SockAddr *raddr, int be_pid, int be_key, int pgtcp_user_timeout, char *errbuf, int errbufsize) { int save_errno = SOCK_ERRNO; @@ -4426,6 +4432,19 @@ internal_cancel(SockAddr *raddr, int be_pid, int be_key, strlcpy(errbuf, "PQcancel() -- socket() failed: ", errbufsize); goto cancel_errReturn; } + +#ifdef TCP_USER_TIMEOUT + if (!IS_AF_UNIX(raddr->addr.ss_family)) { + if (pgtcp_user_timeout < 0) { + pgtcp_user_timeout = 0; + } + if (setsockopt(tmpsock, IPPROTO_TCP, TCP_USER_TIMEOUT, + (char *) &pgtcp_user_timeout, sizeof(pgtcp_user_timeout)) < 0) { + goto cancel_errReturn; + } + } +#endif + retry3: if (connect(tmpsock, (struct sockaddr *) &raddr->addr, raddr->salen) < 0) @@ -4517,6 +4536,7 @@ PQcancel(PGcancel *cancel, char *errbuf, int errbufsize) } return internal_cancel(&cancel->raddr, cancel->be_pid, cancel->be_key, + cancel->pgtcp_user_timeout, errbuf, errbufsize); } @@ -4551,7 +4571,7 @@ PQrequestCancel(PGconn *conn) return false; } - r = internal_cancel(&conn->raddr, conn->be_pid, conn->be_key, + r = internal_cancel(&conn->raddr, conn->be_pid, conn->be_key, 0, conn->errorMessage.data, conn->errorMessage.maxlen); if (!r) diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 334aea4b6e..ef27a0bf23 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -581,6 +581,7 @@ struct pg_cancel SockAddr raddr; /* Remote address */ int be_pid; /* PID of backend --- needed for cancels */ int be_key; /* key of backend --- needed for cancels */ + int pgtcp_user_timeout; /* tcp user timeout */ }; -- 2.17.1