This patch lets the user set the environment variable DISTCC_TIMEOUT to
control how long distcc will wait for the dns lookup and connection.
Without this patch, distcc would wait for several minutes when a host or
a dns server was down.
I've made the patch as unintrusive as I could (it falls back to the old
behavior when DISTCC_TIMEOUT isn't set), so perhaps you want to change
it to set a default timeout that's shorter than what the system provies.
Do we really want to trust our compile jobs to a host that it takes e.g.
20 seconds to connect to?
Timing out the connect call could be done easier than this, just by
interrupting it with a SIGALRM, but that's not enough to abort
gethostbyname. This method of longjmp'ing from a signal handler is what
they use in curl, so it should be ok.
/Jonas Jensen
diff -ur distcc/src/clinet.c distcc-timeout/src/clinet.c
--- distcc/src/clinet.c 2002-10-07 03:35:19.000000000 +0200
+++ distcc-timeout/src/clinet.c 2002-10-26 20:45:16.000000000 +0200
@@ -37,6 +37,7 @@
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
+#include <setjmp.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -74,8 +75,6 @@
/**
* Open a socket to a tcp remote host with the specified port.
- *
- * @todo Don't try for too long to connect.
**/
int dcc_open_socket_out(const char *host, int port, int *p_fd)
{
@@ -94,10 +93,29 @@
return EXIT_CONNECT_FAILED;
}
+ /* Limit the time the entire connect/resolve operation can take */
+ {
+ int timeout;
+ char *tmp;
+ jmp_buf env;
+
+ tmp = getenv("DISTCC_TIMEOUT");
+
+ if (tmp && (timeout = atoi(tmp)) > 0) {
+ if (setjmp(env)) {
+ rs_log_error("timed out connecting to %s", host);
+ (void) close(fd);
+ return EXIT_CONNECT_FAILED;
+ }
+ timeout_operation(timeout, &env);
+ }
+ }
+
hp = gethostbyname(host);
if (!hp) {
rs_log_error("unknown host: \"%s\"", host);
(void) close(fd);
+ alarm(0);
return EXIT_CONNECT_FAILED;
}
@@ -109,8 +127,10 @@
rs_log_error("failed to connect to %s port %d: %s", host, port,
strerror(errno));
(void) close(fd);
+ alarm(0);
return EXIT_CONNECT_FAILED;
}
+ alarm(0);
rs_trace("client got connection to %s port %d on fd%d", host, port, fd);
diff -ur distcc/src/distcc.c distcc-timeout/src/distcc.c
--- distcc/src/distcc.c 2002-10-18 02:36:05.000000000 +0200
+++ distcc-timeout/src/distcc.c 2002-10-26 20:18:11.000000000 +0200
@@ -117,6 +117,7 @@
" DISTCC_VERBOSE=1 give debug messages\n"
" DISTCC_LOG=LOGFILE send messages here, not stderr\n"
" DISTCC_TCP_CORK=0 disable TCP corks\n"
+" DISTCC_TIMEOUT=0 TCP connection timeout, in seconds\n"
"\n"
"Host specifications:\n"
" localhost run in place\n"
diff -ur distcc/src/util.c distcc-timeout/src/util.c
--- distcc/src/util.c 2002-09-14 01:51:53.000000000 +0200
+++ distcc-timeout/src/util.c 2002-10-26 20:43:10.000000000 +0200
@@ -31,6 +31,7 @@
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
+#include <setjmp.h>
#include <sys/stat.h>
#include <sys/resource.h>
@@ -48,6 +49,8 @@
* Ophir.
* -- Isaiah 13:12 */
+static void timeout_operation_handler(int number);
+static jmp_buf jmpbuf;
int dcc_exit(int exitcode)
{
@@ -217,3 +220,19 @@
}
return 0;
}
+
+static void timeout_operation_handler(int UNUSED(whatsig))
+{
+ longjmp(jmpbuf, 1);
+}
+
+/**
+ * Starts a timer that will longjmp back to @p buf when it expires
+ **/
+void timeout_operation(int seconds, jmp_buf *buf)
+{
+ memcpy(&jmpbuf, buf, sizeof(jmpbuf));
+ signal(SIGALRM, timeout_operation_handler);
+ alarm(seconds);
+}
+
diff -ur distcc/src/util.h distcc-timeout/src/util.h
--- distcc/src/util.h 2002-09-11 07:37:51.000000000 +0200
+++ distcc-timeout/src/util.h 2002-10-26 20:42:25.000000000 +0200
@@ -21,6 +21,8 @@
* USA
*/
+#include <setjmp.h>
+
/* util.c */
int argv_contains(char **argv, const char *s);
int dcc_redirect_fd(int, const char *fname, int);
@@ -31,6 +33,7 @@
int set_cloexec_flag (int desc, int value);
int dcc_ignore_sigpipe(int val);
int dcc_remove_if_exists(const char *fname);
+void timeout_operation(int seconds, jmp_buf *buf);
#define str_equal(a, b) (!strcmp((a), (b)))