summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-txt/ChangeLog6
-rw-r--r--src/src/transports/smtp.c46
2 files changed, 44 insertions, 8 deletions
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 7d1d526d7..a30c71ae3 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -37,6 +37,12 @@ JH/05 Bug 2215: Fix crash associated with dnsdb lookup done from DKIM ACL.
active in the testsuite.
Problem spotted, and debugging aided, by Wolfgang Breyha.
+JH/06 Fix issue with continued-connections when the DNS shifts unreliably.
+ When none of the hosts presented to a transport match an already-open
+ connection, close it and proceed with the list. Previously we would
+ queue the message. Spotted by Lena with Yahoo, probably involving
+ round-robin DNS.
+
Exim version 4.90
-----------------
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 01aa4190f..77b3eb818 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -3925,7 +3925,9 @@ for (cutoff_retry = 0;
{
host_item *nexthost = NULL;
int unexpired_hosts_tried = 0;
+ BOOL continue_host_tried = FALSE;
+retry_non_continued:
for (host = hostlist;
host
&& unexpired_hosts_tried < ob->hosts_max_try
@@ -4058,14 +4060,16 @@ for (cutoff_retry = 0;
result of the lookup. Set expired FALSE, to save the outer loop executing
twice. */
- if ( continue_hostname
- && ( Ustrcmp(continue_hostname, host->name) != 0
- || Ustrcmp(continue_host_address, host->address) != 0
- ) )
- {
- expired = FALSE;
- continue; /* With next host */
- }
+ if (continue_hostname)
+ if ( Ustrcmp(continue_hostname, host->name) != 0
+ || Ustrcmp(continue_host_address, host->address) != 0
+ )
+ {
+ expired = FALSE;
+ continue; /* With next host */
+ }
+ else
+ continue_host_tried = TRUE;
/* Reset the default next host in case a multihomed host whose addresses
are not looked up till just above added to the host list. */
@@ -4523,6 +4527,32 @@ for (cutoff_retry = 0;
}
} /* End of loop for trying multiple hosts. */
+ /* If we failed to find a matching host in the list, for an already-open
+ connection, just close it and start over with the list. This can happen
+ for routing that changes from run to run, or big multi-IP sites with
+ round-robin DNS. */
+
+ if (continue_hostname && !continue_host_tried)
+ {
+ int fd = cutthrough.fd >= 0 ? cutthrough.fd : 0;
+
+ DEBUG(D_transport) debug_printf("no hosts match already-open connection\n");
+#ifdef SUPPORT_TLS
+ if (tls_out.active == fd)
+ {
+ (void) tls_write(FALSE, US"QUIT\r\n", 6, FALSE);
+ tls_close(FALSE, TRUE);
+ }
+ else
+#else
+ (void) write(fd, US"QUIT\r\n", 6);
+#endif
+ (void) close(fd);
+ cutthrough.fd = -1;
+ continue_hostname = NULL;
+ goto retry_non_continued;
+ }
+
/* This is the end of the loop that repeats iff expired is TRUE and
ob->delay_after_cutoff is FALSE. The second time round we will
try those hosts that haven't been tried since the message arrived. */