git: d53af4112273 - main - libfetch: Apply timeout to connection attempts

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Mon, 29 Jun 2026 15:52:15 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=d53af4112273f7b234a1cdd6694b3a7ca0aae0eb

commit d53af4112273f7b234a1cdd6694b3a7ca0aae0eb
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-06-27 15:34:53 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-06-29 13:49:19 +0000

    libfetch: Apply timeout to connection attempts
    
    Mark the socket non-blocking before connecting and poll for completion,
    applying fetchTimeout if set.
    
    MFC after:      1 week
---
 lib/libfetch/common.c | 47 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index c1888a1518a0..d1a897b98827 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -593,10 +593,13 @@ fetch_socks5_getenv(char **host, int *port)
 conn_t *
 fetch_connect(const char *host, int port, int af, int verbose)
 {
+	struct timeval now, timeout, delta;
+	struct pollfd pfd;
 	struct addrinfo *cais = NULL, *sais = NULL, *cai, *sai;
 	const char *bindaddr;
 	conn_t *conn = NULL;
 	int err = 0, sd = -1;
+	int deltams;
 	char *sockshost;
 	int socksport;
 
@@ -654,15 +657,47 @@ fetch_connect(const char *host, int port, int af, int verbose)
 			fetch_verbose("failed to bind to %s", bindaddr);
 			goto syserr;
 		}
+		/* make the socket non-blocking */
+		(void)fcntl(sd, F_SETFL, O_NONBLOCK);
+		/* start the clock */
+		if (fetchTimeout > 0) {
+			gettimeofday(&timeout, NULL);
+			timeout.tv_sec += fetchTimeout;
+			deltams = fetchTimeout * 1000;
+		}
 		/* attempt to connect to server address */
-		while ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) < 0) {
-			if (errno == EINTR && fetchRestartCalls)
-				continue;
+		if ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) == 0)
 			break;
+		/* wait for connection */
+		if (errno == EINPROGRESS) {
+			deltams = INFTIM;
+			pfd.fd = sd;
+			pfd.events = POLLOUT;
+			for (;;) {
+				/* wait for something to happen */
+				if (poll(&pfd, 1, deltams) >= 0)
+					break;
+				if (errno == EINTR && !fetchRestartCalls)
+					break;
+				/* check the clock */
+				if (fetchTimeout > 0) {
+					gettimeofday(&now, NULL);
+					if (!timercmp(&timeout, &now, >)) {
+						errno = ETIMEDOUT;
+						pfd.revents = POLLERR;
+						break;
+					}
+					timersub(&timeout, &now, &delta);
+					deltams = delta.tv_sec * 1000 +
+					    delta.tv_usec / 1000;
+				}
+			}
+			if (pfd.revents == POLLOUT) {
+				/* connection established */
+				err = 0;
+				break;
+			}
 		}
-		/* success? */
-		if (err == 0)
-			break;
 		/* clean up before next attempt */
 		close(sd);
 		sd = -1;