From 6db4271ee8b5934c81e815747544519935f7650d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 31 May 2026 10:25:00 -0700 Subject: [PATCH] Ignore SO_RCVTIMEO errors in emacsclient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lib-src/emacsclient.c: Include (timeout): Now signed, and initially -1. All uses changed. (decode_options): Do not worry about ERANGE or ranges, as other code now deal with this; the old code was wrong anyway as it mixed uintmax_t with INTMAX_MAX and INTMAX_MIN. But do check for syntax errors and negative values. (set_socket_timeout): Don’t time out if the timeout is 0 or enormous. Silently ignore errors (Bug#81160). (main): Allow --timeout=0, as per documentation. --- lib-src/emacsclient.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index cb8e045d6f3..381481c7fbd 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -74,6 +74,7 @@ char *w32_getenv (const char *); #include #include #include +#include #include #include #include @@ -146,8 +147,9 @@ static char const *socket_name; /* If non-NULL, the filename of the authentication file. */ static char const *server_file; -/* Seconds to wait before timing out (0 means wait forever). */ -static uintmax_t timeout; +/* Seconds to wait before timing out. Negative means no --timeout so + use DEFAULT_TIMEOUT, 0 means wait forever. */ +static intmax_t timeout = -1; /* If non-NULL, the tramp prefix emacs must use to find the files. */ static char const *tramp_prefix; @@ -539,10 +541,8 @@ decode_options (int argc, char **argv) break; case 'w': - timeout = strtoumax (optarg, &endptr, 10); - if (timeout <= 0 || - ((timeout == INTMAX_MAX || timeout == INTMAX_MIN) - && errno == ERANGE)) + timeout = strtoimax (optarg, &endptr, 10); + if (timeout < 0 || endptr == optarg || *endptr) { fprintf (stderr, "Invalid timeout: \"%s\"\n", optarg); exit (EXIT_FAILURE); @@ -1952,28 +1952,30 @@ start_daemon_and_retry_set_socket (void) return emacs_socket; } +/* Set SOCKET's timeout to SECONDS. + If SECONDS is zero or out of range, do not set the timeout. + Silently ignore errors, as POSIX says it is implementation-defined as + to whether SO_RCVTIMEO works. Although we could fall back on + non-blocking I/O if setsockopt fails, it's not worth the trouble. */ static void -set_socket_timeout (HSOCKET socket, int seconds) +set_socket_timeout (HSOCKET socket, intmax_t seconds) { - int ret; + if (seconds <= 0) + return; #ifndef WINDOWSNT struct timeval timeout; - timeout.tv_sec = seconds; + if (ckd_add (&timeout.tv_sec, seconds, 0)) + return; timeout.tv_usec = 0; - ret = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout); + setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout); #else DWORD timeout; - if (seconds > INT_MAX / 1000) - timeout = INT_MAX; - else - timeout = seconds * 1000; - ret = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof timeout); + if (ckd_mul (&timeout, seconds, 1000)) + return; + setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof timeout); #endif - - if (ret < 0) - sock_err_message ("setsockopt"); } static bool @@ -2210,7 +2212,7 @@ main (int argc, char **argv) } fflush (stdout); - set_socket_timeout (emacs_socket, timeout > 0 ? timeout : DEFAULT_TIMEOUT); + set_socket_timeout (emacs_socket, timeout < 0 ? DEFAULT_TIMEOUT : timeout); bool saw_response = false; ptrdiff_t nrecv = 0; @@ -2236,7 +2238,7 @@ main (int argc, char **argv) if (timeout > 0) { /* Don't retry if we were given a --timeout flag. */ - fprintf (stderr, "\nServer not responding; timed out after %ju seconds", + fprintf (stderr, "\nServer not responding; timed out after %jd seconds", timeout); retry = false; }