X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/1f155f8e69b44ee7678dd1009ae0348e5c8d768e..d57d474fe88b3c9837f8516779c87f3a76f682f2:/src/src/ip.c diff --git a/src/src/ip.c b/src/src/ip.c index 9a7444ed8..1e3875aef 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2014 */ +/* Copyright (c) University of Cambridge 1995 - 2015 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for doing things with sockets. With the advent of IPv6 this has @@ -237,7 +237,11 @@ if (running_in_test_harness && save_errno == ECONNREFUSED && timeout == 999999) /* Success */ -if (rc >= 0) return 0; +if (rc >= 0) + { + callout_address = string_sprintf("[%s]:%d", address, port); + return 0; + } /* A failure whose error code is "Interrupted system call" is in fact an externally applied timeout if the signal handler has been run. */ @@ -400,6 +404,7 @@ if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) path, strerror(err)); return -1; } +callout_address = string_copy(path); return sock; } @@ -451,11 +456,11 @@ BOOL fd_ready(int fd, int timeout) { fd_set select_inset; -struct timeval tv; time_t start_recv = time(NULL); +int time_left = timeout; int rc; -if (timeout <= 0) +if (time_left <= 0) { errno = ETIMEDOUT; return FALSE; @@ -464,10 +469,9 @@ if (timeout <= 0) do { + struct timeval tv = { time_left, 0 }; FD_ZERO (&select_inset); FD_SET (fd, &select_inset); - tv.tv_sec = timeout; - tv.tv_usec = 0; /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/ rc = select(fd + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv); @@ -479,17 +483,17 @@ do Aug 2004: Somebody set up a cron job that ran exiwhat every 2 minutes, making the interrupt not at all rare. Since the timeout is typically more than 2 minutes, the effect was to block the timeout completely. To prevent this - happening again, we do an explicit time test. */ + happening again, we do an explicit time test and adjust the timeout + accordingly */ if (rc < 0 && errno == EINTR) { DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n"); - if (time(NULL) - start_recv < timeout) continue; - DEBUG(D_transport) debug_printf("total wait time exceeds timeout\n"); - } - /* Handle a timeout, and treat any other select error as a timeout, including - an EINTR when we have been in this loop for longer than timeout. */ + /* Watch out, 'continue' jumps to the condition, not to the loops top */ + time_left = timeout - (time(NULL) - start_recv); + if (time_left > 0) continue; + } if (rc <= 0) { @@ -497,9 +501,10 @@ do return FALSE; } - /* If the socket is ready, break out of the loop. */ + /* Checking the FD_ISSET is not enough, if we're interrupted, the + select_inset may still contain the 'input'. */ } -while (!FD_ISSET(fd, &select_inset)); +while (rc < 0 || !FD_ISSET(fd, &select_inset)); return TRUE; }