New $callout_address variable to record spamd (etc) address. Bug 1652
[exim.git] / src / src / ip.c
index 9a7444ed86ffce2369e99fc263758d97b293260f..1e3875aef51e388034af1c3f68d3bf805ab9b220 100644 (file)
@@ -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;
 }