* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for doing things with sockets. With the advent of IPv6 this has
/* If no connection timeout is set, just call connect() without setting a
timer, thereby allowing the inbuilt OS timeout to operate. */
+callout_address = string_sprintf("[%s]:%d", address, port);
sigalrm_seen = FALSE;
if (timeout > 0) alarm(timeout);
rc = connect(sock, s_ptr, s_len);
/* Success */
-if (rc >= 0) return 0;
+if (rc >= 0)
+ 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. */
if (hostname[0] == '[' &&
hostname[namelen - 1] == ']')
{
- uschar * host = string_copy(hostname);
- host[namelen - 1] = 0;
- host++;
+ uschar * host = string_copyn(hostname+1, namelen-2);
if (string_is_ip_address(host, NULL) == 0)
{
*errstr = string_sprintf("malformed IP address \"%s\"", hostname);
/* Otherwise check for an unadorned IP address */
else if (string_is_ip_address(hostname, NULL) != 0)
- shost.name = shost.address = string_copy(hostname);
+ shost.name = shost.address = string_copyn(hostname, namelen);
/* Otherwise lookup IP address(es) from the name */
else
{
- shost.name = string_copy(hostname);
+ shost.name = string_copyn(hostname, namelen);
if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE,
NULL, FALSE) != HOST_FOUND)
{
for (h = &shost; h != NULL; h = h->next)
{
- fd = (Ustrchr(h->address, ':') != 0)
- ? (fd6 < 0) ? (fd6 = ip_socket(type, af = AF_INET6)) : fd6
- : (fd4 < 0) ? (fd4 = ip_socket(type, af = AF_INET )) : fd4;
+ fd = Ustrchr(h->address, ':') != 0
+ ? fd6 < 0 ? (fd6 = ip_socket(type, af = AF_INET6)) : fd6
+ : fd4 < 0 ? (fd4 = ip_socket(type, af = AF_INET )) : fd4;
if (fd < 0)
{
return -1;
}
+callout_address = string_copy(path);
server.sun_family = AF_UNIX;
Ustrncpy(server.sun_path, path, sizeof(server.sun_path)-1);
server.sun_path[sizeof(server.sun_path)-1] = '\0';
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;
}