* 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
/* 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. */
else
{
shost.name = string_copy(hostname);
- if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE, NULL,
- FALSE) != HOST_FOUND)
+ if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE,
+ NULL, FALSE) != HOST_FOUND)
{
*errstr = string_sprintf("no IP address found for host %s", shost.name);
return -1;
path, strerror(err));
return -1;
}
+callout_address = string_copy(path);
return sock;
}
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;
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);
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)
{
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;
}