X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/0768462dc5830cde5ae7a3659577fb557926db28..de6f74f297d040a34746bc8e1829ad4b867441c9:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index 6c6e6f7d1..664d00452 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -761,10 +761,9 @@ d_log_interface(gstring * g) if (LOGGING(incoming_interface) && LOGGING(outgoing_interface) && sending_ip_address) { - g = string_append(g, 2, US" I=[", sending_ip_address); - g = LOGGING(outgoing_port) - ? string_append(g, 2, US"]:", string_sprintf("%d", sending_port)) - : string_catn(g, US"]", 1); + g = string_fmt_append(g, " I=[%s]", sending_ip_address); + if (LOGGING(outgoing_port)) + g = string_fmt_append(g, "%d", sending_port); } return g; } @@ -784,21 +783,21 @@ if (LOGGING(dnssec) && h->dnssec == DS_YES) g = string_append(g, 3, US" [", h->address, US"]"); if (LOGGING(outgoing_port)) - g = string_append(g, 2, US":", string_sprintf("%d", h->port)); + g = string_fmt_append(g, ":%d", h->port); #ifdef SUPPORT_SOCKS if (LOGGING(proxy) && proxy_local_address) { g = string_append(g, 3, US" PRX=[", proxy_local_address, US"]"); if (LOGGING(outgoing_port)) - g = string_append(g, 2, US":", string_sprintf("%d", proxy_local_port)); + g = string_fmt_append(g, ":%d", proxy_local_port); } #endif g = d_log_interface(g); if (testflag(addr, af_tcp_fastopen)) - g = string_catn(g, US" TFO", 4); + g = string_catn(g, US" TFO*", testflag(addr, af_tcp_fastopen_data) ? 5 : 4); return g; } @@ -1196,8 +1195,7 @@ if (addr->router) g = string_append(g, 2, US" T=", addr->transport->name); if (LOGGING(delivery_size)) - g = string_append(g, 2, US" S=", - string_sprintf("%d", transport_count)); + g = string_fmt_append(g, " S=%d", transport_count); /* Local delivery */ @@ -1247,8 +1245,15 @@ else } } - if (LOGGING(pipelining) && testflag(addr, af_pipelining)) - g = string_catn(g, US" L", 2); + if (LOGGING(pipelining)) + { + if (testflag(addr, af_pipelining)) + g = string_catn(g, US" L", 2); +#ifdef EXPERIMENTAL_PIPE_CONNECT + if (testflag(addr, af_early_pipe)) + g = string_catn(g, US"*", 1); +#endif + } #ifndef DISABLE_PRDR if (testflag(addr, af_prdr_used)) @@ -1338,13 +1343,12 @@ if (driver_name) { if (driver_kind[1] == 't' && addr->router) g = string_append(g, 2, US" R=", addr->router->name); - g = string_cat(g, string_sprintf(" %c=%s", toupper(driver_kind[1]), driver_name)); + g = string_fmt_append(g, " %c=%s", toupper(driver_kind[1]), driver_name); } else if (driver_kind) g = string_append(g, 2, US" ", driver_kind); -/*XXX need an s+s+p sprintf */ -g = string_cat(g, string_sprintf(" defer (%d)", addr->basic_errno)); +g = string_fmt_append(g, " defer (%d)", addr->basic_errno); if (addr->basic_errno > 0) g = string_append(g, 2, US": ", @@ -1358,8 +1362,7 @@ if (addr->host_used) if (LOGGING(outgoing_port)) { int port = addr->host_used->port; - g = string_append(g, 2, - US":", port == PORT_NONE ? US"25" : string_sprintf("%d", port)); + g = string_fmt_append(g, ":%d", port == PORT_NONE ? 25 : port); } } @@ -1785,13 +1788,12 @@ addr->basic_errno = code; if (format) { va_list ap; - uschar buffer[512]; + gstring * g; + va_start(ap, format); - if (!string_vformat(buffer, sizeof(buffer), CS format, ap)) - log_write(0, LOG_MAIN|LOG_PANIC_DIE, - "common_error expansion was longer than " SIZE_T_FMT, sizeof(buffer)); + g = string_vformat(NULL, TRUE, CS format, ap); va_end(ap); - addr->message = string_copy(buffer); + addr->message = string_from_gstring(g); } for (addr2 = addr->next; addr2; addr2 = addr2->next) @@ -3576,6 +3578,9 @@ while (!done) case 'L': switch (*subid) { +#ifdef EXPERIMENTAL_PIPE_CONNECT + case 2: setflag(addr, af_early_pipe); /*FALLTHROUGH*/ +#endif case 1: setflag(addr, af_pipelining); break; } break; @@ -3587,6 +3592,7 @@ while (!done) case 'T': setflag(addr, af_tcp_fastopen_conn); if (*subid > '0') setflag(addr, af_tcp_fastopen); + if (*subid > '1') setflag(addr, af_tcp_fastopen_data); break; case 'D': @@ -4884,6 +4890,11 @@ all pipes, so I do not see a reason to use non-blocking IO here #endif if (testflag(addr, af_pipelining)) +#ifdef EXPERIMENTAL_PIPE_CONNECT + if (testflag(addr, af_early_pipe)) + rmt_dlv_checked_write(fd, 'L', '2', NULL, 0); + else +#endif rmt_dlv_checked_write(fd, 'L', '1', NULL, 0); if (testflag(addr, af_chunking_used)) @@ -4891,7 +4902,9 @@ all pipes, so I do not see a reason to use non-blocking IO here if (testflag(addr, af_tcp_fastopen_conn)) rmt_dlv_checked_write(fd, 'T', - testflag(addr, af_tcp_fastopen) ? '1' : '0', NULL, 0); + testflag(addr, af_tcp_fastopen) ? testflag(addr, af_tcp_fastopen_data) + ? '2' : '1' : '0', + NULL, 0); memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware)); rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware)); @@ -5365,7 +5378,7 @@ static void print_address_error(address_item *addr, FILE *f, uschar *t) { int count = Ustrlen(t); -uschar *s = testflag(addr, af_pass_message)? addr->message : NULL; +uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL; if (!s && !(s = addr->user_message)) return; @@ -5586,7 +5599,8 @@ message size. This use of strcpy() is OK because the length id is checked when it is obtained from a command line (the -M or -q options), and otherwise it is known to be a valid message id. */ -Ustrcpy(message_id, id); +if (id != message_id) + Ustrcpy(message_id, id); f.deliver_force = forced; return_count = 0; message_size = 0; @@ -5871,9 +5885,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) ugid.uid_set = ugid.gid_set = TRUE; } else - { ugid.uid_set = ugid.gid_set = FALSE; - } return_path = sender_address; f.enable_dollar_recipients = TRUE; /* Permit $recipients in system filter */ @@ -6596,13 +6608,21 @@ while (addr_new) /* Loop until all addresses dealt with */ if ( domain_retry_record && now - domain_retry_record->time_stamp > retry_data_expire ) + { + DEBUG(D_deliver|D_retry) + debug_printf("domain retry record present but expired\n"); domain_retry_record = NULL; /* Ignore if too old */ + } address_retry_record = dbfn_read(dbm_file, addr->address_retry_key); if ( address_retry_record && now - address_retry_record->time_stamp > retry_data_expire ) + { + DEBUG(D_deliver|D_retry) + debug_printf("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ + } if (!address_retry_record) { @@ -6611,7 +6631,11 @@ while (addr_new) /* Loop until all addresses dealt with */ address_retry_record = dbfn_read(dbm_file, altkey); if ( address_retry_record && now - address_retry_record->time_stamp > retry_data_expire) + { + DEBUG(D_deliver|D_retry) + debug_printf("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ + } } } else @@ -6620,9 +6644,18 @@ while (addr_new) /* Loop until all addresses dealt with */ DEBUG(D_deliver|D_retry) { if (!domain_retry_record) - debug_printf("no domain retry record\n"); + debug_printf("no domain retry record\n"); + else + debug_printf("have domain retry record; next_try = now%+d\n", + f.running_in_test_harness ? 0 : + (int)(domain_retry_record->next_try - now)); + if (!address_retry_record) - debug_printf("no address retry record\n"); + debug_printf("no address retry record\n"); + else + debug_printf("have address retry record; next_try = now%+d\n", + f.running_in_test_harness ? 0 : + (int)(address_retry_record->next_try - now)); } /* If we are sending a message down an existing SMTP connection, we must @@ -6644,6 +6677,9 @@ while (addr_new) /* Loop until all addresses dealt with */ addr->message = US"reusing SMTP connection skips previous routing defer"; addr->basic_errno = ERRNO_RRETRY; (void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); + + addr->message = domain_retry_record->text; + setflag(addr, af_pass_message); } /* If we are in a queue run, defer routing unless there is no retry data or @@ -6697,6 +6733,16 @@ while (addr_new) /* Loop until all addresses dealt with */ addr->message = US"retry time not reached"; addr->basic_errno = ERRNO_RRETRY; (void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); + + /* For remote-retry errors (here and just above) that we've not yet + hit the rery time, use the error recorded in the retry database + as info in the warning message. This lets us send a message even + when we're not failing on a fresh attempt. We assume that this + info is not sensitive. */ + + addr->message = domain_retry_record + ? domain_retry_record->text : address_retry_record->text; + setflag(addr, af_pass_message); } /* The domain is OK for routing. Remember if retry data exists so it @@ -7027,7 +7073,7 @@ if ( f.header_rewritten } -/* If there are any deliveries to be and we do not already have the journal +/* If there are any deliveries to do and we do not already have the journal file, create it. This is used to record successful deliveries as soon as possible after each delivery is known to be complete. A file opened with O_APPEND is used so that several processes can run simultaneously. @@ -7304,7 +7350,7 @@ if (addr_senddsn) } else /* Creation of child succeeded */ { - FILE *f = fdopen(fd, "wb"); + FILE * f = fdopen(fd, "wb"); /* header only as required by RFC. only failure DSN needs to honor RET=FULL */ uschar * bound; transport_ctx tctx = {{0}}; @@ -7385,8 +7431,10 @@ if (addr_senddsn) /* Write the original email out */ - tctx.u.fd = fileno(f); + tctx.u.fd = fd; tctx.options = topt_add_return_path | topt_no_body; + /*XXX hmm, retval ignored. + Could error for any number of reasons, and they are not handled. */ transport_write_message(&tctx, 0); fflush(f); @@ -7854,6 +7902,7 @@ wording. */ tctx.options = topt; tb.add_headers = dsnnotifyhdr; + /*XXX no checking for failure! buggy! */ transport_write_message(&tctx, 0); } fflush(fp); @@ -7995,6 +8044,8 @@ the parent's domain. If all the deferred addresses have an error number that indicates "retry time not reached", skip sending the warning message, because it won't contain the reason for the delay. It will get sent at the next real delivery attempt. + Exception: for retries caused by a remote peer we use the error message + store in the retry DB as the reason. However, if at least one address has tried, we'd better include all of them in the message. @@ -8014,7 +8065,7 @@ else if (addr_defer != (address_item *)(+1)) { address_item *addr; uschar *recipients = US""; - BOOL delivery_attempted = FALSE; + BOOL want_warning_msg = FALSE; deliver_domain = testflag(addr_defer, af_pfr) ? addr_defer->parent->domain : addr_defer->domain; @@ -8023,7 +8074,7 @@ else if (addr_defer != (address_item *)(+1)) { address_item *otaddr; - if (addr->basic_errno > ERRNO_RETRY_BASE) delivery_attempted = TRUE; + if (addr->basic_errno > ERRNO_WARN_BASE) want_warning_msg = TRUE; if (deliver_domain) { @@ -8095,7 +8146,7 @@ else if (addr_defer != (address_item *)(+1)) it also defers). */ if ( !f.queue_2stage - && delivery_attempted + && want_warning_msg && ( !(addr_defer->dsn_flags & rf_dsnflags) || addr_defer->dsn_flags & rf_notify_delay ) @@ -8146,7 +8197,7 @@ else if (addr_defer != (address_item *)(+1)) DEBUG(D_deliver) { - debug_printf("time on queue = %s\n", readconf_printtime(queue_time)); + debug_printf("time on queue = %s id %s addr %s\n", readconf_printtime(queue_time), message_id, addr_defer->address); debug_printf("warning counts: required %d done %d\n", count, warning_count); } @@ -8320,6 +8371,7 @@ else if (addr_defer != (address_item *)(+1)) return_path = sender_address; /* In case not previously set */ /* Write the original email out */ + /*XXX no checking for failure! buggy! */ transport_write_message(&tctx, 0); fflush(f); @@ -8483,8 +8535,7 @@ if (!regex_SIZE) regex_SIZE = regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE); if (!regex_AUTH) regex_AUTH = - regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)", - FALSE, TRUE); + regex_must_compile(AUTHS_REGEX, FALSE, TRUE); #ifdef SUPPORT_TLS if (!regex_STARTTLS) regex_STARTTLS = @@ -8514,6 +8565,11 @@ if (!regex_DSN) regex_DSN = if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE); + +#ifdef EXPERIMENTAL_PIPE_CONNECT +if (!regex_EARLY_PIPE) regex_EARLY_PIPE = + regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE); +#endif }