X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fretry.c;h=dbfd3cee85554b0195d8baf39eefd5fcc4fba3db;hb=ed72ace5f09d07c620b96efaf72d328d6e7439be;hp=9c90f6699affcad795beafeaf21d87dce35da546;hpb=c988f1f4faa9f679f79beddf3c14676c5dcb8e28;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/retry.c b/src/src/retry.c index 9c90f6699..dbfd3cee8 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/retry.c,v 1.2 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/retry.c,v 1.8 2006/02/16 16:37:57 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2006 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions concerned with retrying unsuccessful deliveries. */ @@ -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 @@ -658,6 +684,16 @@ for (i = 0; i < 3; i++) /* Compute how long this destination has been failing */ failing_interval = now - retry_record->first_failed; + DEBUG(D_retry) debug_printf("failing_interval=%d message_age=%d\n", + failing_interval, message_age); + + /* If the message has been on the queue longer than the recorded time + of failure, use the message's age instead. This can happen when some + messages can be delivered and others cannot; a successful delivery will + reset the first_failed time, and this can lead to a failing message + being retried too often. */ + + if (message_age > failing_interval) failing_interval = message_age; /* Search for the current retry rule. The cutoff time of the last rule is handled differently to the others. The rule continues @@ -712,7 +748,14 @@ for (i = 0; i < 3; i++) This implements "timeout this rule if EITHER the host (or routing or directing) has been failing for more than the maximum time, OR if the - message has been on the queue for more than the maximum time." */ + message has been on the queue for more than the maximum time." + + February 2006: It is possible that this code is no longer needed + following the change to the retry calculation to use the message age if + it is larger than the time since first failure. It may be that the + expired flag is always set when the other conditions are met. However, + this is a small bit of code, and it does no harm to leave it in place, + just in case. */ if (received_time <= retry_record->first_failed && addr == endaddr && !retry_record->expired && rule != NULL) @@ -739,15 +782,25 @@ for (i = 0; i < 3; i++) if (rule == NULL) next_try = now; else { if (rule->rule == 'F') next_try = now + rule->p1; - else /* assume rule = 'G' */ + else /* rule = 'G' or 'H' */ { int last_predicted_gap = retry_record->next_try - retry_record->last_try; int last_actual_gap = now - retry_record->last_try; int lastgap = (last_predicted_gap < last_actual_gap)? last_predicted_gap : last_actual_gap; - next_try = now + ((lastgap < rule->p1)? rule->p1 : - (lastgap * rule->p2)/1000); + int next_gap = (lastgap * rule->p2)/1000; + if (rule->rule == 'G') + { + next_try = now + ((lastgap < rule->p1)? rule->p1 : next_gap); + } + else /* The 'H' rule */ + { + next_try = now + rule->p1; + if (next_gap > rule->p1) + next_try += random_number(next_gap - rule->p1)/2 + + (next_gap - rule->p1)/2; + } } } @@ -842,6 +895,9 @@ for (i = 0; i < 3; i++) setflag(addr, af_retry_timedout); addr->message = (addr->message == NULL)? US"retry timeout exceeded" : string_sprintf("%s: retry timeout exceeded", addr->message); + addr->user_message = (addr->user_message == NULL)? + US"retry timeout exceeded" : + string_sprintf("%s: retry timeout exceeded", addr->user_message); log_write(0, LOG_MAIN, "** %s%s%s%s: retry timeout exceeded", addr->address, (addr->parent == NULL)? US"" : US" <",