From ea49d0e16fbc6f56fc5b8519d266f88d09139187 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Wed, 8 Feb 2006 14:28:51 +0000 Subject: [PATCH] Fix retry key bug for pipe, file, or autoreply deliveries. --- doc/doc-txt/ChangeLog | 6 ++- src/src/deliver.c | 23 +++++++--- src/src/readconf.c | 8 +++- src/src/retry.c | 52 ++++++++++++++++------ test/aux-fixed/setrt | 39 +++++++++++++++++ test/confs/0529 | 44 +++++++++++++++++++ test/log/0529 | 5 +++ test/runtest | 12 ++--- test/scripts/0000-Basic/0529 | 10 +++++ test/stderr/0357 | 6 +-- test/stderr/0358 | 8 ++-- test/stderr/0388 | 4 +- test/stderr/0476 | 1 + test/stderr/0529 | 85 ++++++++++++++++++++++++++++++++++++ test/stderr/5005 | 8 ++-- 15 files changed, 272 insertions(+), 39 deletions(-) create mode 100644 test/aux-fixed/setrt create mode 100644 test/confs/0529 create mode 100644 test/log/0529 create mode 100644 test/scripts/0000-Basic/0529 create mode 100644 test/stderr/0529 diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index d914efb43..f8f046b68 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.286 2006/02/07 16:36:25 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.287 2006/02/08 14:28:51 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -98,6 +98,10 @@ PH/16 As discussed on the list in Nov/Dec: Exim no longer looks at the address records were *not* found in the additional section, the port values from the SRV records were lost. +PH/17 If a delivery to a pipe, file, or autoreply was deferred, Exim was not + using the correct key (the original address) when searching the retry + rules in order to find which one to use for generating the retry hint. + Exim version 4.60 diff --git a/src/src/deliver.c b/src/src/deliver.c index 9351d45d7..dbec42e0e 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/deliver.c,v 1.26 2006/02/07 11:19:00 ph10 Exp $ */ +/* $Cambridge: exim/src/src/deliver.c,v 1.27 2006/02/08 14:28:51 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -2250,10 +2250,12 @@ while (addr_local != NULL) DEBUG(D_retry) { - debug_printf("retry record exists: age=%d (max=%d)\n", - (int)(now - retry_record->time_stamp), retry_data_expire); - debug_printf(" time to retry = %d expired = %d\n", - (int)(now - retry_record->next_try), retry_record->expired); + debug_printf("retry record exists: age=%s ", + readconf_printtime(now - retry_record->time_stamp)); + debug_printf("(max %s)\n", readconf_printtime(retry_data_expire)); + debug_printf(" time to retry = %s expired = %d\n", + readconf_printtime(retry_record->next_try - now), + retry_record->expired); } if (queue_running && !deliver_force) @@ -2282,9 +2284,18 @@ while (addr_local != NULL) for (last_rule = retry->rules; last_rule->next != NULL; last_rule = last_rule->next); + DEBUG(D_deliver|D_retry) + debug_printf("now=%d received_time=%d diff=%d timeout=%d\n", + (int)now, received_time, (int)now - received_time, + last_rule->timeout); if (now - received_time > last_rule->timeout) ok = TRUE; } - else ok = TRUE; /* No rule => timed out */ + else + { + DEBUG(D_deliver|D_retry) + debug_printf("no retry rule found: assume timed out\n"); + ok = TRUE; /* No rule => timed out */ + } DEBUG(D_deliver|D_retry) { diff --git a/src/src/readconf.c b/src/src/readconf.c index b860b96d3..5623b87f4 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/readconf.c,v 1.17 2006/02/07 11:19:00 ph10 Exp $ */ +/* $Cambridge: exim/src/src/readconf.c,v 1.18 2006/02/08 14:28:51 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -2011,6 +2011,12 @@ readconf_printtime(int t) int s, m, h, d, w; uschar *p = time_buffer; +if (t < 0) + { + *p++ = '-'; + t = -t; + } + s = t % 60; t /= 60; m = t % 60; diff --git a/src/src/retry.c b/src/src/retry.c index b54bb7d4a..2a5516003 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/retry.c,v 1.5 2006/02/07 11:19:00 ph10 Exp $ */ +/* $Cambridge: exim/src/src/retry.c,v 1.6 2006/02/08 14:28:51 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -46,8 +46,17 @@ if (retry != NULL && retry->rules != NULL) for (last_rule = retry->rules; last_rule->next != NULL; last_rule = last_rule->next); + DEBUG(D_transport|D_retry) + debug_printf("now=%d received_time=%d diff=%d timeout=%d\n", + (int)now, received_time, (int)(now - received_time), + last_rule->timeout); address_timeout = (now - received_time > last_rule->timeout); } +else + { + DEBUG(D_transport|D_retry) + debug_printf("no retry rule found: assume timed out\n"); + } return address_timeout; } @@ -340,23 +349,38 @@ retry_config * retry_find_config(uschar *key, uschar *alternate, int basic_errno, int more_errno) { -int replace; +int replace = 0; uschar *use_key, *use_alternate; uschar *colon = Ustrchr(key, ':'); retry_config *yield; -/* If there's a colon in the key, temporarily replace it with -a zero to terminate the string there. */ +/* If there's a colon in the key, there are two possibilities: + +(1) This is a key for a host, ip address, and possibly port, in the format + + hostname:ip+port + + In this case, we temporarily replace the colon with a zero, to terminate + the string after the host name. + +(2) This is a key for a pipe, file, or autoreply delivery, in the format + + pipe-or-file-or-auto:x@y + + where x@y is the original address that provoked the delivery. The pipe or + file or auto will start with | or / or >, whereas a host name will start + with a letter or a digit. In this case we want to use the original address + to search for a retry rule. */ if (colon != NULL) { - replace = ':'; - } -else - { - colon = key + Ustrlen(key); - replace = 0; + if (isalnum(*key)) + replace = ':'; + else + key = Ustrrchr(key, ':') + 1; /* Take from the last colon */ } + +if (replace == 0) colon = key + Ustrlen(key); *colon = 0; /* Sort out the keys */ @@ -619,10 +643,12 @@ for (i = 0; i < 3; i++) DEBUG(D_retry) { if ((rti->flags & rf_host) != 0) - debug_printf("retry for %s (%s) = %s\n", rti->key, - addr->domain, retry->pattern); + debug_printf("retry for %s (%s) = %s %d %d\n", rti->key, + addr->domain, retry->pattern, retry->basic_errno, + retry->more_errno); else - debug_printf("retry for %s = %s\n", rti->key, retry->pattern); + debug_printf("retry for %s = %s %d %d\n", rti->key, retry->pattern, + retry->basic_errno, retry->more_errno); } /* Set up the message for the database retry record. Because DBM diff --git a/test/aux-fixed/setrt b/test/aux-fixed/setrt new file mode 100644 index 000000000..85046508e --- /dev/null +++ b/test/aux-fixed/setrt @@ -0,0 +1,39 @@ +# This is a little perl script that adjusts the "received" time in a -H file, +# so that retry timeouts etc can be more easily tested. Its arguments are: +# +# (1) The number of the message on the queue whose time is to be adjusted; 1 +# for the first message, 2 for the second, etc. +# +# (2) A positive or negative number by which to adjust the received time. + +$fileno = $ARGV[0] - 1; +$adjust = $ARGV[1]; + +opendir(DIR, "spool/input"); +while (($_ = readdir(DIR))) { push(@files, $_) if /.*-H$/; } +closedir(DIR); + +@files = sort @files; + +open(IN, "spool/input/$files[$fileno]") || + die "can't open spool/input/$files[$fileno]"; + +open(OUT, ">test-H"); + +$_ = ; print OUT; +$_ = ; print OUT; +$_ = ; print OUT; +$_ = ; +($rtime,$rest) = $_ =~ /^(\d+)(.*)/; +$rtime += $adjust; +print OUT "$rtime$rest\n"; +print OUT while (); + +close(IN); +close(OUT); + +rename("test-H", "spool/input/$files[$fileno]") || die "rename failed\n"; + +exit(0); + +# End diff --git a/test/confs/0529 b/test/confs/0529 new file mode 100644 index 000000000..247f7452a --- /dev/null +++ b/test/confs/0529 @@ -0,0 +1,44 @@ +# Exim test configuration 0529 + +exim_path = EXIM_PATH +host_lookup_order = bydns +primary_hostname = myhost.test.ex +rfc1413_query_timeout = 0s +spool_directory = DIR/spool +log_file_path = DIR/spool/log/%slog +gecos_pattern = "" +gecos_name = CALLER_NAME + +# ----- Main settings ----- + + + +# ----- Routers ----- + +begin routers + +r1: + driver = redirect + data = DIR/test-mail/rmbox + file_transport = t1 + + +# ----- Transports ----- + +begin transports + +t1: + driver = appendfile + quota = 1 + user = CALLER + + +# ----- Retry ----- + +begin retry + +*@test.ex quota_7d +*@test.ex quota F,2h,15m; F,3d,1h +* * F,2h,15m; G,16h,1h,1.5; F,4d,6h + +# End diff --git a/test/log/0529 b/test/log/0529 new file mode 100644 index 000000000..2e56375ce --- /dev/null +++ b/test/log/0529 @@ -0,0 +1,5 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaX-0005vi-00 == TESTSUITE/test-mail/rmbox R=r1 T=t1 defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to TESTSUITE/test-mail/rmbox) +1999-03-02 09:44:33 Start queue run: pid=pppp +1999-03-02 09:44:33 10HmaX-0005vi-00 == TESTSUITE/test-mail/rmbox R=r1 T=t1 defer (-52): Retry time not yet reached +1999-03-02 09:44:33 End queue run: pid=pppp diff --git a/test/runtest b/test/runtest index 92bbe804f..acff149af 100755 --- a/test/runtest +++ b/test/runtest @@ -1,6 +1,6 @@ #! /usr/bin/perl -w -# $Cambridge: exim/test/runtest,v 1.1 2006/02/06 16:07:10 ph10 Exp $ +# $Cambridge: exim/test/runtest,v 1.2 2006/02/08 14:28:51 ph10 Exp $ ############################################################################### # This is the controlling script for the "new" test suite for Exim. It should # @@ -406,16 +406,17 @@ while() # Date/time in mbx mailbox files s/\d\d-\w\w\w-\d\d\d\d\s\d\d:\d\d:\d\d\s[-+]\d\d\d\d,/06-Sep-1999 15:52:48 +0100,/gx; - # Date/time in debugging output for writing retry records + # Dates/times in debugging output for writing retry records if (/^ first failed=(\d+) last try=(\d+) next try=(\d+) (.*)$/) { my($next) = $3 - $2; $_ = " first failed=dddd last try=dddd next try=+$next $4\n"; } + s/^now=\d+ received_time=\d+ diff=\d+ timeout=(\d+)/now=tttt received_time=tttt diff=tttt timeout=$1/; # Time to retry may vary - s/time to retry = -\d+/time to retry = -ddddd/; - s/retry record exists: age=\d/retry record exists: age=d/; + s/time to retry = \S+/time to retry = tttt/; + s/retry record exists: age=\S+/retry record exists: age=ttt/; # Date/time in exim -bV output s/\d\d-[A-Z][a-z]{2}-\d{4}\s\d\d:\d\d:\d\d/07-Mar-2000 12:21:52/g; @@ -1581,7 +1582,8 @@ if (/^(cat)?write\s+(\S+)(?:\s+(.*))?\s*$/) # The "client" and "client-ssl" commands run a script-driven program that plays # the part of an email client. We also have the availability of running Perl -# for doing one-off special things. +# for doing one-off special things. Note that all these commands expect stdin +# data to be supplied. if (/^client/ || /^client-ssl/ || /^(sudo\s+)?perl\b/) { diff --git a/test/scripts/0000-Basic/0529 b/test/scripts/0000-Basic/0529 new file mode 100644 index 000000000..3809cde3a --- /dev/null +++ b/test/scripts/0000-Basic/0529 @@ -0,0 +1,10 @@ +# retries for quota exceeded when routed to a file +# +exim -d-all+retry -odi x@test.ex +**** +# Adjust the received time for the message, then try a queue run. +sudo perl DIR/aux-fixed/setrt 1 -86400 +**** +exim -d-all+retry -q +**** +no_msglog_check diff --git a/test/stderr/0357 b/test/stderr/0357 index 74e375a70..3692e9574 100644 --- a/test/stderr/0357 +++ b/test/stderr/0357 @@ -36,7 +36,7 @@ Failed addresses: Deferred addresses: userx@test.ex locking TESTSUITE/spool/db/retry.lockfile -retry for R:userx@test.ex = * +retry for R:userx@test.ex = * 0 0 Writing retry data for R:userx@test.ex first failed=dddd last try=dddd next try=+1 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error @@ -84,7 +84,7 @@ Deferred addresses: userx@test.ex locking TESTSUITE/spool/db/retry.lockfile deleted retry information for R:test.ex -retry for R:userx@test.ex = * +retry for R:userx@test.ex = * 0 0 Writing retry data for R:userx@test.ex first failed=dddd last try=dddd next try=+1 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error @@ -133,7 +133,7 @@ Deferred addresses: userx@test.ex locking TESTSUITE/spool/db/retry.lockfile deleted retry information for R:test.ex -retry for R:userx@test.ex = * +retry for R:userx@test.ex = * 0 0 Writing retry data for R:userx@test.ex first failed=dddd last try=dddd next try=+2 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error diff --git a/test/stderr/0358 b/test/stderr/0358 index 04029aea0..dd36d0267 100644 --- a/test/stderr/0358 +++ b/test/stderr/0358 @@ -46,12 +46,12 @@ Failed addresses: Deferred addresses: usery@test.ex locking TESTSUITE/spool/db/retry.lockfile -retry for R:usery@test.ex = * +retry for R:usery@test.ex = * 0 0 Writing retry data for R:usery@test.ex first failed=dddd last try=dddd next try=+1 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error userx@test.ex -retry for R:userx@test.ex = * +retry for R:userx@test.ex = * 0 0 Writing retry data for R:userx@test.ex first failed=dddd last try=dddd next try=+1 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error @@ -116,13 +116,13 @@ Deferred addresses: usery@test.ex locking TESTSUITE/spool/db/retry.lockfile deleted retry information for R:test.ex -retry for R:usery@test.ex = * +retry for R:usery@test.ex = * 0 0 Writing retry data for R:usery@test.ex first failed=dddd last try=dddd next try=+2 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error userx@test.ex deleted retry information for R:test.ex -retry for R:userx@test.ex = * +retry for R:userx@test.ex = * 0 0 Writing retry data for R:userx@test.ex first failed=dddd last try=dddd next try=+2 expired=0 errno=-44 more_errno=dd,A SMTP error from remote mail server after RCPT TO:: host 127.0.0.1 [127.0.0.1]: 451 Temporary error diff --git a/test/stderr/0388 b/test/stderr/0388 index 38da06423..fcb73193a 100644 --- a/test/stderr/0388 +++ b/test/stderr/0388 @@ -143,7 +143,7 @@ opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR address match: subject=x@y pattern=* y in "*"? yes (matched "*") x@y in "*"? yes (matched "*") -retry for R:x@y = * +retry for R:x@y = * 0 0 dbfn_read: key=R:x@y on queue longer than maximum retry Writing retry data for R:x@y @@ -153,7 +153,7 @@ dbfn_write: key=R:x@y address match: subject=*@V4NET.0.0.0 pattern=* V4NET.0.0.0 in "*"? yes (matched "*") *@V4NET.0.0.0 in "*"? yes (matched "*") -retry for T:V4NET.0.0.0:V4NET.0.0.0:1224 (y) = * +retry for T:V4NET.0.0.0:V4NET.0.0.0:1224 (y) = * 0 0 dbfn_read: key=T:V4NET.0.0.0:V4NET.0.0.0:1224 on queue longer than maximum retry Writing retry data for T:V4NET.0.0.0:V4NET.0.0.0:1224 diff --git a/test/stderr/0476 b/test/stderr/0476 index 3eb97ae30..c58e72060 100644 --- a/test/stderr/0476 +++ b/test/stderr/0476 @@ -96,6 +96,7 @@ t1 transport entered checking status of 127.0.0.1 no message retry record host retry time not reached: checking ultimate address timeout +now=tttt received_time=tttt diff=tttt timeout=86400 127.0.0.1 [127.0.0.1]:1111 status = unusable all IP addresses skipped or deferred at least one address Leaving t1 transport diff --git a/test/stderr/0529 b/test/stderr/0529 new file mode 100644 index 000000000..bed589de6 --- /dev/null +++ b/test/stderr/0529 @@ -0,0 +1,85 @@ +Exim version x.yz .... +configuration file is TESTSUITE/test-config +admin user +LOG: MAIN + <= CALLER@myhost.test.ex U=CALLER P=local S=sss +created log directory TESTSUITE/spool/log +Exim version x.yz .... +configuration file is TESTSUITE/test-config +trusted user +admin user +locking TESTSUITE/spool/db/retry.lockfile +no retry data available +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +Considering: x@test.ex +no domain retry record +no address retry record +locking TESTSUITE/spool/db/retry.lockfile +no retry data available +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +Considering: TESTSUITE/test-mail/rmbox +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +After routing: + Local deliveries: + TESTSUITE/test-mail/rmbox + Remote deliveries: + Failed addresses: + Deferred addresses: +locking TESTSUITE/spool/db/retry.lockfile +no retry data available +added retry item for T:TESTSUITE/test-mail/rmbox:x@test.ex: errno=-22 more_errno=dd flags=0 +LOG: MAIN + == TESTSUITE/test-mail/rmbox R=r1 T=t1 defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to TESTSUITE/test-mail/rmbox) +Processing retry items +Succeeded addresses: +x@test.ex: no retry items +Failed addresses: +Deferred addresses: +TESTSUITE/test-mail/rmbox +locking TESTSUITE/spool/db/retry.lockfile +retry for T:TESTSUITE/test-mail/rmbox:x@test.ex = *@test.ex -22 0 +Writing retry data for T:TESTSUITE/test-mail/rmbox:x@test.ex + first failed=dddd last try=dddd next try=+900 expired=0 + errno=-22 more_errno=dd mailbox is full (MTA-imposed quota exceeded while writing to TESTSUITE/test-mail/rmbox) +x@test.ex: no retry items +end of retry processing +>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> +>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> +Exim version x.yz .... +configuration file is TESTSUITE/test-config +admin user +LOG: queue_run MAIN + Start queue run: pid=pppp +locking TESTSUITE/spool/db/retry.lockfile +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +Considering: x@test.ex +no domain retry record +no address retry record +locking TESTSUITE/spool/db/retry.lockfile +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +Considering: TESTSUITE/test-mail/rmbox +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +After routing: + Local deliveries: + TESTSUITE/test-mail/rmbox + Remote deliveries: + Failed addresses: + Deferred addresses: +locking TESTSUITE/spool/db/retry.lockfile +retry record exists: age=ttt (max 1w) + time to retry = tttt expired = 0 +retry time not reached for TESTSUITE/test-mail/rmbox: checking ultimate address timeout +now=tttt received_time=tttt diff=tttt timeout=259200 +LOG: retry_defer MAIN + == TESTSUITE/test-mail/rmbox R=r1 T=t1 defer (-52): Retry time not yet reached +Processing retry items +Succeeded addresses: +x@test.ex: no retry items +Failed addresses: +Deferred addresses: +TESTSUITE/test-mail/rmbox: no retry items +x@test.ex: no retry items +end of retry processing +LOG: queue_run MAIN + End queue run: pid=pppp +>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>> diff --git a/test/stderr/5005 b/test/stderr/5005 index 993892dbd..8a8c8ad3b 100644 --- a/test/stderr/5005 +++ b/test/stderr/5005 @@ -484,7 +484,7 @@ opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR address match: subject=userx@test.ex pattern=* test.ex in "*"? yes (matched "*") userx@test.ex in "*"? yes (matched "*") -retry for T:userx@test.ex = * +retry for T:userx@test.ex = * 0 0 dbfn_read: key=T:userx@test.ex Writing retry data for T:userx@test.ex first failed=dddd last try=dddd next try=+86400 expired=0 @@ -600,8 +600,8 @@ EXIM_DBOPEN(TESTSUITE/spool/db/retry) returned from EXIM_DBOPEN opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY dbfn_read: key=T:userx@test.ex -retry record exists: age=d (max=604800) - time to retry = -ddddd expired = 0 +retry record exists: age=ttt (max 1w) + time to retry = tttt expired = 0 search_tidyup called changed uid/gid: local delivery to userx transport=t1 uid=CALLER_UID gid=CALLER_GID pid=pppp @@ -650,7 +650,7 @@ opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR address match: subject=userx@test.ex pattern=* test.ex in "*"? yes (matched "*") userx@test.ex in "*"? yes (matched "*") -retry for T:userx@test.ex = * +retry for T:userx@test.ex = * 0 0 dbfn_read: key=T:userx@test.ex Writing retry data for T:userx@test.ex first failed=dddd last try=dddd next try=+86400 expired=0 -- 2.30.2