Added the hosts_max_try_hardlimit option. (The removed file is left over
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Tue, 4 Jan 2005 16:36:27 +0000 (16:36 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Tue, 4 Jan 2005 16:36:27 +0000 (16:36 +0000)
from a previous update; I screwed up the CVS-ing.)

doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
src/src/transports/smtp.c
src/src/transports/smtp.h

index bf214bce746f3b18af4e1a0ac7c2c711bc46068c..891a3e04e59051c3e86131d18a727b459d653f27 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.63 2005/01/04 13:31:41 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.64 2005/01/04 16:36:27 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -290,6 +290,8 @@ Exim version 4.50
     SMTP connection. (Fix 4.40/11 dealt with the non-cache case, but overlooked
     the caching.)
 
+66. Added hosts_max_try_hardlimit to the smtp transport, default 50.
+
 
 Exim version 4.43
 -----------------
index 30cb58ab512e98edfa11bb6749aea6b05682a0a5..5d6e915d3b5c9d5b531352139664d29bfdf6fe1b 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.24 2004/12/29 10:16:52 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.25 2005/01/04 16:36:27 ph10 Exp $
 
 New Features in Exim
 --------------------
@@ -247,6 +247,14 @@ Version 4.50
       (2) The default for smtp_banner uses $smtp_active_hostname instead
           of $primary_hostname.
 
+22. The hosts_max_try_hardlimit option (default 50) is added to the smtp
+    transport. Exim will never try more than this number of IP addresses; if it
+    hits this limit and they are all timed out, the message is bounced, even
+    though not all IP addresses may have been tried. Compare hosts_max_try,
+    which is a "soft" limit, because Exim will exceed it when hosts time out.
+    The new limit is a protection against lunatic DNS configurations with
+    hundreds of IP addresses.
+
 
 Version 4.43
 ------------
index ae04feb59609ef5a01e127ee161bc94e9c9668bc..ebdae0f51d908cb5f126242e5fa47556fbbf6ed5 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/OptionLists.txt,v 1.4 2004/11/10 10:29:56 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/OptionLists.txt,v 1.5 2005/01/04 16:36:27 ph10 Exp $
 
 LISTS OF EXIM OPTIONS
 ---------------------
@@ -247,6 +247,7 @@ hosts_avoid_esmtp                    host list       unset         smtp
 hosts_avoid_tls                      host list       unset         smtp              3.20
 hosts_connection_nolog               host list       unset         main              4.43
 hosts_max_try                        integer         5             smtp              3.20
+hosts_max_try_hardlimit              integer         50            smtp              4.50
 hosts_nopass_tls                     host list       unset         smtp              4.00
 hosts_override                       boolean         false         smtp              2.11
 hosts_randomize                      boolean         false         manualroute       4.00
index 424f9afa92a394a604a5cd4fe3e5f285cd3385aa..738fd1cc282fffe3d64251a03b485abb76ddf955 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.3 2005/01/04 10:00:45 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.4 2005/01/04 16:36:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -57,6 +57,8 @@ optionlist smtp_transport_options[] = {
   #endif
   { "hosts_max_try",        opt_int,
       (void *)offsetof(smtp_transport_options_block, hosts_max_try) },
+  { "hosts_max_try_hardlimit", opt_int,
+      (void *)offsetof(smtp_transport_options_block, hosts_max_try_hardlimit) },
   #ifdef SUPPORT_TLS
   { "hosts_nopass_tls",     opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, hosts_nopass_tls) },
@@ -138,6 +140,7 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   10*60,               /* final timeout */
   1024,                /* size_addition */
   5,                   /* hosts_max_try */
+  50,                  /* hosts_max_try_hardlimit */ 
   FALSE,               /* allow_localhost */
   FALSE,               /* gethostbyname */
   TRUE,                /* dns_qualify_single */
@@ -1926,6 +1929,7 @@ int hosts_looked_up = 0;
 int hosts_retry = 0;
 int hosts_serial = 0;
 int hosts_total = 0;
+int total_hosts_tried = 0; 
 address_item *addr;
 BOOL expired = TRUE;
 BOOL continuing = continue_hostname != NULL;
@@ -2091,7 +2095,9 @@ if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
 
 .  If there are any addresses whose status is still DEFER, carry on to the
    next host/IPaddress, unless we have tried the number of hosts given
-   by hosts_max_try; otherwise return.
+   by hosts_max_try or hosts_max_try_hardlimit; otherwise return. Note that
+   there is some fancy logic for hosts_max_try that means its limit can be 
+   overstepped in some circumstances. 
 
 If we get to the end of the list, all hosts have deferred at least one address,
 or not reached their retry times. If delay_after_cutoff is unset, it requests a
@@ -2108,7 +2114,9 @@ for (cutoff_retry = 0; expired &&
   int unexpired_hosts_tried = 0;
 
   for (host = hostlist;
-       host != NULL && unexpired_hosts_tried < ob->hosts_max_try;
+       host != NULL && 
+         unexpired_hosts_tried < ob->hosts_max_try &&
+         total_hosts_tried < ob->hosts_max_try_hardlimit;
        host = nexthost)
     {
     int rc;
@@ -2413,13 +2421,16 @@ for (cutoff_retry = 0; expired &&
 
     /* This is for real. If the host is expired, we don't count it for
     hosts_max_retry. This ensures that all hosts must expire before an address
-    is timed out. Otherwise, if we are about to hit the hosts_max_retry limit,
-    check to see if there is a subsequent hosts with a different MX value. If
-    so, make that the next host, and don't count this one. This is a heuristic
-    to make sure that different MXs do get tried. With a normal kind of retry
-    rule, they would get tried anyway when the earlier hosts were delayed, but
-    if the domain has a "retry every time" type of rule - as is often used for
-    the the very large ISPs, that won't happen. */
+    is timed out, unless hosts_max_try_hardlimit (which protects against 
+    lunatic DNS configurations) is reached.
+    
+    If the host is not expired and we are about to hit the hosts_max_retry
+    limit, check to see if there is a subsequent hosts with a different MX
+    value. If so, make that the next host, and don't count this one. This is a
+    heuristic to make sure that different MXs do get tried. With a normal kind
+    of retry rule, they would get tried anyway when the earlier hosts were
+    delayed, but if the domain has a "retry every time" type of rule - as is
+    often used for the the very large ISPs, that won't happen. */
 
     else
       {
@@ -2441,6 +2452,7 @@ for (cutoff_retry = 0; expired &&
 
       /* Attempt the delivery. */
 
+      total_hosts_tried++;
       rc = smtp_deliver(addrlist, host, host_af, port, interface, tblock,
         expanded_hosts != NULL, &message_defer, FALSE);
 
@@ -2606,7 +2618,7 @@ for (cutoff_retry = 0; expired &&
     maximum retry time for this host. This means we may try try all hosts,
     ignoring the limit, when messages have been around for some time. This is
     important because if we don't try all hosts, the address will never time
-    out. */
+    out. NOTE: this does not apply to hosts_max_try_hardlimit. */
 
     if ((rc == DEFER || some_deferred) && nexthost != NULL)
       {
@@ -2671,15 +2683,26 @@ found, we end up here, but can detect these cases and handle them specially. */
 for (addr = addrlist; addr != NULL; addr = addr->next)
   {
   /* If host is not NULL, it means that we stopped processing the host list
-  because of hosts_max_try. This means we need to behave as if some hosts were
-  skipped because their retry time had not come. Specifically, this prevents
-  the address from timing out. */
+  because of hosts_max_try or hosts_max_try_hardlimit. In the former case, this
+  means we need to behave as if some hosts were skipped because their retry
+  time had not come. Specifically, this prevents the address from timing out.
+  However, if we have hit hosts_max_try_hardlimit, we want to behave as if all 
+  hosts were tried. */
 
   if (host != NULL)
     {
-    DEBUG(D_transport)
-      debug_printf("hosts_max_try limit caused some hosts to be skipped\n");
-    setflag(addr, af_retry_skipped);
+    if (total_hosts_tried >= ob->hosts_max_try_hardlimit)
+      {
+      DEBUG(D_transport)
+        debug_printf("hosts_max_try_hardlimit reached: behave as if all "
+          "hosts were tried\n");
+      }
+    else
+      {       
+      DEBUG(D_transport)
+        debug_printf("hosts_max_try limit caused some hosts to be skipped\n");
+      setflag(addr, af_retry_skipped);
+      } 
     }
 
   if (queue_smtp)    /* no deliveries attempted */
index 756da659c4fa7aefa285e4705c94873a2ae14838..99af732284a1fdc850b4a935fbae43f6a366c610 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.h,v 1.2 2005/01/04 10:00:45 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.h,v 1.3 2005/01/04 16:36:28 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -32,6 +32,7 @@ typedef struct {
   int     final_timeout;
   int     size_addition;
   int     hosts_max_try;
+  int     hosts_max_try_hardlimit; 
   BOOL    allow_localhost;
   BOOL    gethostbyname;
   BOOL    dns_qualify_single;