[distcc] Updated patch
Oscar Esteban
flesteban at mi.madritel.es
Mon Oct 7 19:44:01 GMT 2002
After rolling back the multi-record dns searching, the patch becomes
smaller (as it was). Here it goes:
diff -wur /home/oscar/cvs_working/distcc/src/clinet.c ./src/clinet.c
--- /home/oscar/cvs_working/distcc/src/clinet.c Mon Oct 7 21:38:48 2002
+++ ./src/clinet.c Mon Oct 7 21:29:59 2002
@@ -37,10 +37,12 @@
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
+#include <setjmp.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -71,6 +73,72 @@
**/
+/**
+ * Simulate connect behaviour, but adding a timeout. If the connection is not
+ * ended in this time, return ETIMEDOUT
+ **/
+static int dcc_connect_tout (int fd, struct sockaddr *addr, int size, int time_to_wait)
+{
+ int got_an_error = 0;
+ int fcntl_previous;
+
+ /* Keep flags associated with the fd */
+ fcntl_previous = fcntl(fd, F_GETFL, 0);
+
+ /* Set the fd to be non-blocking */
+ fcntl(fd, F_SETFL, fcntl_previous | O_NONBLOCK);
+
+ if (connect(fd, addr, size)) {
+ /* If got out in a hurry, but hasn't yet finished... */
+ if (EINPROGRESS == errno) {
+ struct timeval tv;
+ fd_set wfds;
+ int valret;
+
+ FD_ZERO(&wfds); /* Clear write filedescriptor set */
+ FD_SET(fd, &wfds); /* Add fd to the set */
+ tv.tv_sec = time_to_wait / 1000; /* Set time to wait */
+ tv.tv_usec = 1000 * (time_to_wait % 1000);
+
+ valret = select(fd+1, NULL, &wfds, NULL, &tv);
+ if (valret) {
+ /* We got a result in time */
+
+ int lbuf = sizeof(valret);
+
+ /* Now, let's obtain the real error */
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &valret, &lbuf);
+ if (valret) {
+ got_an_error = -1;
+
+ errno = valret; /* Do as real connect would have done */
+ }
+ } else {
+ /* Time has passed with no result.
+ TODO: What happens to the pending connection if the fd is
+ closed?
+ */
+ rs_log_error("connect timed out on fd%d\n", fd);
+ /* We'll fake some error code into errno, TIMEOUT seems ok */
+ errno = ETIMEDOUT;
+ got_an_error = -1;
+ }
+ } else {
+ got_an_error = -1;
+ }
+ }
+
+ /* Restore flags saved before */
+ fcntl(fd, F_SETFL, fcntl_previous);
+
+ return got_an_error;
+}
+
+static jmp_buf time_to_wakeup;
+static void dcc_alarm_handler()
+{
+ longjmp(time_to_wakeup, 1);
+}
/**
* Open a socket to a tcp remote host with the specified port.
@@ -83,6 +151,7 @@
struct sockaddr_in sock_out;
int fd;
struct hostent *hp;
+ void *prev_signal;
/* Ignore SIGPIPE; we consistently check error codes and will
* see the EPIPE. */
@@ -94,18 +163,37 @@
return EXIT_CONNECT_FAILED;
}
+ alarm(0); /* Let's be sure we do not get a signal before setjmp */
+
+ prev_signal = signal(SIGALRM, dcc_alarm_handler);
+
+ if (!setjmp(time_to_wakeup)) {
+ /* we came here from the setjmp, proceed normally */
+ alarm(DNS_TIMEOUT / 1000); /* Program the alarm */
hp = gethostbyname(host);
+ alarm(0); /* Finished in time, disconnect the alarm */
+ signal(SIGALRM, prev_signal); /* and restore previous behaviour */
+
if (!hp) {
rs_log_error("unknown host: \"%s\"", host);
(void) close(fd);
return EXIT_CONNECT_FAILED;
}
+ } else {
+ /* we came here from a longjump -> we got the SIGALRM */
+ signal(SIGALRM, prev_signal); /* restore previous behaviour */
+
+ rs_log_error("timeout looking for host: \"%s\"\n", host);
+ (void) close(fd);
+ return EXIT_CONNECT_FAILED;
+ }
memcpy(&sock_out.sin_addr, hp->h_addr, (size_t) hp->h_length);
sock_out.sin_port = htons((in_port_t) port);
sock_out.sin_family = PF_INET;
- if (connect(fd, (struct sockaddr *) &sock_out, (int) sizeof(sock_out))) {
+ if (dcc_connect_tout(fd, (struct sockaddr *) &sock_out,
+ (int) sizeof(sock_out), CONNECT_TIMEOUT)) {
rs_log_error("failed to connect to %s port %d: %s", host, port,
strerror(errno));
(void) close(fd);
diff -wur /home/oscar/cvs_working/distcc/src/clinet.h ./src/clinet.h
--- /home/oscar/cvs_working/distcc/src/clinet.h Mon Oct 7 21:38:48 2002
+++ ./src/clinet.h Mon Oct 7 21:32:17 2002
@@ -21,4 +21,8 @@
* USA
*/
+#define CONNECT_TIMEOUT 2000 /* Time given in milliseconds */
+#define DNS_TIMEOUT 2000 /* Time given in milliseconds, but
+ it'd better be multiple of 1000 */
+
int dcc_open_socket_out(const char *host, int port, int *fd);
diff -wur /home/oscar/cvs_working/distcc/test/testdistcc.py ./test/testdistcc.py
--- /home/oscar/cvs_working/distcc/test/testdistcc.py Mon Oct 7 21:38:48 2002
+++ ./test/testdistcc.py Mon Oct 7 21:11:58 2002
@@ -720,6 +720,79 @@
def tearDown(self):
self.leaveRundir()
+class dcc_connect_timeout(CompileHello_Case):
+ "base for dcc_connect_timeout test cases"
+
+ def setUp(self, host_list):
+ CompileHello_Case.setUp(self)
+
+ os.environ['DISTCC_HOSTS'] = host_list
+ self.distcc_log = 'distcc.log'
+ os.environ['DISTCC_LOG'] = self.distcc_log
+
+ def runTest(self, string_to_match):
+ self.run_cmd("distcc gcc -c -o testtmp.o testtmp.c")
+ msgs = open(self.distcc_log, 'r').read()
+ self.assertReMatch(string_to_match, msgs)
+
+"The case 'got connection' is tested in every other test"
+
+class Connect_Dead_Host_Case(dcc_connect_timeout):
+ """Known host, but it does not answer"""
+
+ def GetHostAddress(self):
+ output = self.run_cmd("/sbin/ifconfig").split('\n')
+
+ skipping = 0
+ for line in output:
+ if re.match(r'^lo\s+', line):
+ skipping = 1
+ continue
+ if skipping:
+ if re.match(r'^$', line):
+ skipping = 0
+ continue
+ "TODO: adapt for IPv6 notation if different"
+ result = re.search(r'addr:(\d+(?:\.\d+)*).*Mask:(\d+(?:\.\d+)*)',
+ line, re.I)
+
+ if result:
+ """Extract address and mask, and make up an address,
+ hoping that it does not exist. Any better idea?"""
+ addr = map(int, result.group(1).split("."))
+ mask = map(int, result.group(2).split("."))
+ for i in xrange(len(addr)):
+ addr[i] ^= (0x85 & ~mask[i])
+
+ return ".".join(map(repr, addr))
+
+ return ""
+
+ def setUp(self):
+ self.host_list = self.GetHostAddress()
+ dcc_connect_timeout.setUp(self, self.host_list)
+
+ def runTest(self):
+ assert self.host_list != "", "Can not find a network interface excluding localhost"
+ dcc_connect_timeout.runTest(self, r'connect timed out')
+
+class Connect_Invalid_Port_Case(dcc_connect_timeout):
+ """Known host, but closed port
+ It should be nice to check for 'connection refused', but due to
+ localization, the message will be different in every case."""
+ def setUp(self):
+ dcc_connect_timeout.setUp(self, 'localhost:9999')
+
+ def runTest(self):
+ dcc_connect_timeout.runTest(self, r'failed to connect')
+
+class Connect_Invalid_Server_Name_Case(dcc_connect_timeout):
+ """Invalid server name"""
+ def setUp(self):
+ dcc_connect_timeout.setUp (self, 'no.such.host.here')
+
+ def runTest(self):
+ dcc_connect_timeout.runTest(self, r'timeout looking for host')
class ImpliedOutput_Case(CompileHello_Case):
"""Test handling absence of -o"""
@@ -908,4 +981,7 @@
ModeBits_Case,
Concurrent_Case,
ThousandFold_Case,
+ Connect_Dead_Host_Case,
+ Connect_Invalid_Port_Case,
+ Connect_Invalid_Server_Name_Case,
BigAssFile_Case])
More information about the distcc
mailing list