X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/e97957bc478f60d32649b329659d4b72748745c1..93a6fce2ebf117f490d7ee11f066f75280d32386:/src/src/retry.c diff --git a/src/src/retry.c b/src/src/retry.c index ca61e5c0c..62677c1ca 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/retry.c,v 1.9 2006/03/09 15:10:16 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2006 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions concerned with retrying unsuccessful deliveries. */ @@ -19,26 +17,34 @@ *************************************************/ /* This function tests whether a message has been on the queue longer than -the maximum retry time for a particular host. +the maximum retry time for a particular host or address. Arguments: - host_key the key to look up a host retry rule + retry_key the key to look up a retry rule domain the domain to look up a domain retry rule - basic_errno a specific error number, or zero if none - more_errno additional data for the error + retry_record contains error information for finding rule now the time Returns: TRUE if the ultimate timeout has been reached */ -static BOOL -ultimate_address_timeout(uschar *host_key, uschar *domain, int basic_errno, - int more_errno, time_t now) +BOOL +retry_ultimate_address_timeout(uschar *retry_key, const uschar *domain, + dbdata_retry *retry_record, time_t now) { -BOOL address_timeout = TRUE; /* no rule => timed out */ +BOOL address_timeout; + +DEBUG(D_retry) + { + debug_printf("retry time not reached: checking ultimate address timeout\n"); + debug_printf(" now=%d first_failed=%d next_try=%d expired=%d\n", + (int)now, (int)retry_record->first_failed, + (int)retry_record->next_try, retry_record->expired); + } retry_config *retry = - retry_find_config(host_key+2, domain, basic_errno, more_errno); + retry_find_config(retry_key+2, domain, + retry_record->basic_errno, retry_record->more_errno); if (retry != NULL && retry->rules != NULL) { @@ -46,18 +52,23 @@ 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); + DEBUG(D_retry) + debug_printf(" received_time=%d diff=%d timeout=%d\n", + received_time, (int)(now - received_time), last_rule->timeout); address_timeout = (now - received_time > last_rule->timeout); } else { - DEBUG(D_transport|D_retry) + DEBUG(D_retry) debug_printf("no retry rule found: assume timed out\n"); + address_timeout = TRUE; } +DEBUG(D_retry) + if (address_timeout) + debug_printf("on queue longer than maximum retry for address - " + "allowing delivery\n"); + return address_timeout; } @@ -111,7 +122,7 @@ Returns: TRUE if the host has expired but is usable because */ BOOL -retry_check_address(uschar *domain, host_item *host, uschar *portstring, +retry_check_address(const uschar *domain, host_item *host, uschar *portstring, BOOL include_ip_address, uschar **retry_host_key, uschar **retry_message_key) { BOOL yield = FALSE; @@ -209,19 +220,10 @@ if (host_retry_record != NULL) if (now < host_retry_record->next_try && !deliver_force) { - DEBUG(D_transport|D_retry) - debug_printf("host retry time not reached: checking ultimate address " - "timeout\n"); - if (!host_retry_record->expired && - ultimate_address_timeout(host_key, domain, - host_retry_record->basic_errno, host_retry_record->more_errno, now)) - { - DEBUG(D_transport|D_retry) - debug_printf("on queue longer than maximum retry for " - "address - allowing delivery\n"); + retry_ultimate_address_timeout(host_key, domain, + host_retry_record, now)) return FALSE; - } /* We have not hit the ultimate address timeout; host is unusable. */ @@ -246,20 +248,12 @@ if (message_retry_record != NULL) *retry_message_key = message_key; if (now < message_retry_record->next_try && !deliver_force) { - DEBUG(D_transport|D_retry) - debug_printf("host+message retry time not reached: checking ultimate " - "address timeout\n"); - if (!ultimate_address_timeout(host_key, domain, 0, 0, now)) + if (!retry_ultimate_address_timeout(host_key, domain, + message_retry_record, now)) { host->status = hstatus_unusable; host->why = hwhy_retry; } - else - { - DEBUG(D_transport|D_retry) - debug_printf("on queue longer than maximum retry for " - "address - allowing delivery\n"); - } return FALSE; } } @@ -300,12 +294,15 @@ void retry_add_item(address_item *addr, uschar *key, int flags) { retry_item *rti = store_get(sizeof(retry_item)); +host_item * host = addr->host_used; rti->next = addr->retries; addr->retries = rti; rti->key = key; rti->basic_errno = addr->basic_errno; rti->more_errno = addr->more_errno; -rti->message = addr->message; +rti->message = host + ? string_sprintf("H=%s [%s]: %s", host->name, host->address, addr->message) + : addr->message; rti->flags = flags; DEBUG(D_transport|D_retry) @@ -346,12 +343,10 @@ Returns: pointer to retry rule, or NULL */ retry_config * -retry_find_config(uschar *key, uschar *alternate, int basic_errno, +retry_find_config(const uschar *key, const uschar *alternate, int basic_errno, int more_errno) { -int replace = 0; -uschar *use_key, *use_alternate; -uschar *colon = Ustrchr(key, ':'); +const uschar *colon = Ustrchr(key, ':'); retry_config *yield; /* If there's a colon in the key, there are two possibilities: @@ -360,8 +355,7 @@ retry_config *yield; hostname:ip+port - In this case, we temporarily replace the colon with a zero, to terminate - the string after the host name. + In this case, we copy the host name. (2) This is a key for a pipe, file, or autoreply delivery, in the format @@ -372,28 +366,22 @@ retry_config *yield; 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) - { - if (isalnum(*key)) - replace = ':'; - else - key = Ustrrchr(key, ':') + 1; /* Take from the last colon */ - } - -if (replace == 0) colon = key + Ustrlen(key); -*colon = 0; +if (colon) + key = isalnum(*key) + ? string_copyn(key, colon-key) /* the hostname */ + : Ustrrchr(key, ':') + 1; /* Take from the last colon */ /* Sort out the keys */ -use_key = (Ustrchr(key, '@') != NULL)? key : string_sprintf("*@%s", key); -use_alternate = (alternate == NULL)? NULL : string_sprintf("*@%s", alternate); +if (!Ustrchr(key, '@')) key = string_sprintf("*@%s", key); +if (alternate) alternate = string_sprintf("*@%s", alternate); /* Scan the configured retry items. */ for (yield = retries; yield != NULL; yield = yield->next) { - uschar *plist = yield->pattern; - uschar *slist = yield->senders; + const uschar *plist = yield->pattern; + const uschar *slist = yield->senders; /* If a specific error is set for this item, check that we are handling that specific error, and if so, check any additional error information if @@ -492,15 +480,14 @@ for (yield = retries; yield != NULL; yield = yield->next) /* Check for a match between the address list item at the start of this retry rule and either the main or alternate keys. */ - if (match_address_list(use_key, TRUE, TRUE, &plist, NULL, -1, UCHAR_MAX+1, + if (match_address_list(key, TRUE, TRUE, &plist, NULL, -1, UCHAR_MAX+1, NULL) == OK || - (use_alternate != NULL && - match_address_list(use_alternate, TRUE, TRUE, &plist, NULL, -1, + (alternate != NULL && + match_address_list(alternate, TRUE, TRUE, &plist, NULL, -1, UCHAR_MAX+1, NULL) == OK)) break; } -*colon = replace; return yield; } @@ -668,7 +655,7 @@ for (i = 0; i < 3; i++) message = (rti->basic_errno > 0)? US strerror(rti->basic_errno) : (rti->message == NULL)? - US"unknown error" : string_printing(rti->message); + US"unknown error" : US string_printing(rti->message); message_length = Ustrlen(message); if (message_length > 150) message_length = 150; @@ -698,13 +685,14 @@ for (i = 0; i < 3; i++) 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. */ + /* For a non-host error, 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; + if ((rti->flags & rf_host) == 0 && 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