* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2023 */
+/* Copyright (c) The Exim Maintainers 2020 - 2024 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
{
uschar * action = addr->transport->event_action;
const uschar * save_domain, * save_local;
+uschar * save_rn, * save_tn;
if (!action)
return;
save_domain = deliver_domain;
save_local = deliver_localpart;
+save_rn = router_name;
+save_tn = transport_name;
/*XXX would ip & port already be set up? */
deliver_host_address = string_copy(host->address);
deliver_localpart = save_local;
deliver_domain = save_domain;
-router_name = transport_name = NULL;
+router_name = save_rn;
+router_name = save_tn;
}
#endif
if (!(er = dbfn_read_enforce_length(dbm_file, ehlo_resp_key, sizeof(dbdata_ehlo_resp))))
debug_printf("no ehlo-resp record!\n");
else
- debug_printf("ehlo-resp record is %d seconds old\n", time(NULL) - er->time_stamp);
+ debug_printf("ehlo-resp record is %.0f seconds old\n",
+ difftime(time(NULL), er->time_stamp));
}
dbfn_delete(dbm_file, ehlo_resp_key);
}
/*XXX EXPERIMENTAL_ESMTP_LIMITS ? */
-# ifndef DISABLE_TLS_RESUME
+# if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME)
GET_OPTION("host_name_extract");
s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract;
if (!s) s = HNE_DEFAULT;
if (testflag(addr, af_dr_retry_exists))
{
- uschar *altkey = string_sprintf("%s:<%s>", addr->address_retry_key,
+ uschar * altkey = string_sprintf("%s:<%s>", addr->address_retry_key,
sender_address);
retry_add_item(addr, altkey, rf_delete);
retry_add_item(addr, addr->address_retry_key, rf_delete);
else if (errno == ETIMEDOUT)
{
- uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
+ uschar * message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
transport_rcpt_address(addr, sx->conn_args.tblock->rcpt_include_affixes));
set_errno_nohost(sx->first_addr, ETIMEDOUT, message, DEFER, FALSE, &sx->delivery_start);
retry_add_item(addr, addr->address_retry_key, 0);
}
}
#endif
-#ifndef DISABLE_TLS_RESUME
+#if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME)
GET_OPTION("host_name_extract");
if (!(s = ob->host_name_extract)) s = HNE_DEFAULT;
ehlo_response_lbserver(sx, s);
/* Send MAIL FROM and RCPT TO commands.
See sw_mrc_t definition for return codes.
- */
+*/
sw_mrc_t
smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield)
int rc;
uschar *message = NULL;
-uschar new_message_id[MESSAGE_ID_LENGTH + 1];
smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); /* tainted, for the data buffers */
BOOL pass_message = FALSE;
#ifndef DISABLE_ESMTP_LIMITS
#ifdef SUPPORT_DANE
BOOL dane_held;
#endif
-BOOL tcw_done = FALSE, tcw = FALSE;
+BOOL tcw_done = FALSE, tcw = FALSE, passback_tcw = FALSE;
*message_defer = FALSE;
+continue_next_id[0] = '\0';
memset(sx, 0, sizeof(*sx));
sx->addrlist = addrlist;
&&
#endif
transport_check_waiting(tblock->name, host->name,
- tblock->connection_max_messages, new_message_id,
+ tblock->connection_max_messages, continue_next_id,
(oicf)smtp_are_same_identities, (void*)&t_compare);
if (!tcw)
{
{
DEBUG(D_transport)
debug_printf("reached limit %u for MAILs per conn\n", sx->max_mail);
+ /* We will close the smtp session and connection, and clear
+ continue_hostname. Then if there are further addrs for the message we will
+ loop to the top of this function and make a fresh connection. Any further
+ message found in the wait-tpt hintsdb would then do a transport_pass_socket
+ to get the connection fd back to the delivery process. */
}
else
#endif
smtp_compare_t t_compare =
{.tblock = tblock, .current_sender_address = sender_address};
- if ( sx->first_addr /* more addrs for this message */
- || f.continue_more /* more addrs for continued-host */
- || tcw_done && tcw /* more messages for host */
+ if ( sx->first_addr /* more addrs for this message */
+ || f.continue_more /* more addrs for continued-host */
+ || tcw_done && tcw /* more messages for host */
|| (
#ifndef DISABLE_TLS
( tls_out.active.sock < 0 && !continue_proxy_cipher
&&
#endif
transport_check_waiting(tblock->name, host->name,
- sx->max_mail, new_message_id,
+ sx->max_mail, continue_next_id,
(oicf)smtp_are_same_identities, (void*)&t_compare)
) )
{
goto SEND_MESSAGE;
}
+ /* If there is a next-message-id from the wait-transport hintsdb,
+ pretend caller said it has further message for us. Note that we lose
+ the TLS session (below), and that our caller will pass back the id to
+ the delivery process. If not, remember to later cancel the
+ next-message-id so that the transport-caller code (in deliver.c) does
+ not report it back up the pipe to the delivery process.
+ XXX It would be feasible to also report the other continue_* with the
+ _id - taking out the exec for the first continued-transport. But the
+ actual conn, and it's fd, is a problem. Maybe replace the transport
+ pipe with a unix-domain socket? */
+
+ if (!f.continue_more && continue_hostname && *continue_next_id)
+ f.continue_more = passback_tcw = TRUE;
+
/* Unless caller said it already has more messages listed for this host,
pass the connection on to a new Exim process (below, the call to
transport_pass_socket). If the caller has more ready, just return with
propagate it from the initial
*/
if (sx->ok && transport_pass_socket(tblock->name, host->name,
- host->address, new_message_id, socket_fd
+ host->address, continue_next_id, socket_fd
#ifndef DISABLE_ESMTP_LIMITS
, sx->peer_limit_mail, sx->peer_limit_rcpt, sx->peer_limit_rcptdom
#endif
sx->cctx.tls_ctx = NULL;
(void)close(sx->cctx.sock);
sx->cctx.sock = -1;
- continue_transport = NULL;
- continue_hostname = NULL;
+ continue_transport = continue_hostname = NULL;
goto TIDYUP;
}
log_write(0, LOG_PANIC_DIE, "fork failed");
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
(void)close(sx->cctx.sock);
sx->cctx.sock = -1;
-continue_transport = NULL;
continue_hostname = NULL;
smtp_debug_cmd_report();
continue_sequence = 1; /* for consistency */
clearflag(sx->first_addr, af_cont_conn);
setflag(sx->first_addr, af_new_conn); /* clear * from logging */
- goto REPEAT_CONN;
+ goto REPEAT_CONN; /* open a fresh connection */
}
#endif
-return yield;
+OUT:
+ if (!passback_tcw) continue_next_id[0] = '\0';
+ return yield;
TIDYUP:
#ifdef SUPPORT_DANE
-if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next)
- if (a->transport_return == DANE)
- a->transport_return = PENDING_DEFER;
+ if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next)
+ if (a->transport_return == DANE)
+ a->transport_return = PENDING_DEFER;
#endif
-return yield;
+ goto OUT;
}
BOOL host_is_expired = FALSE, message_defer = FALSE, some_deferred = FALSE;
address_item * first_addr = NULL;
uschar * interface = NULL;
- uschar * retry_host_key = NULL, * retry_message_key = NULL;
+ const uschar * retry_host_key = NULL, * retry_message_key = NULL;
uschar * serialize_key = NULL;
/* Deal slightly better with a possible Linux kernel bug that results
ob->expand_retry_include_ip_address, &incl_ip) != OK)
incl_ip = TRUE; /* error; use most-specific retry record */
- retry_host_key = incl_ip
- ? string_sprintf("T:%S:%s%s", host->name, host->address, pistring)
- : string_sprintf("T:%S%s", host->name, pistring);
+ retry_host_key = retry_host_key_build(host, incl_ip, pistring);
}
/* If a delivery of another message over an existing SMTP connection
ob->expand_retry_include_ip_address, &incl_ip) != OK)
incl_ip = TRUE; /* error; use most-specific retry record */
- retry_message_key = incl_ip
- ? string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring,
- message_id)
- : string_sprintf("T:%S%s:%s", host->name, pistring, message_id);
+ retry_message_key = string_sprintf("%s:%s",
+ retry_host_key_build(host, incl_ip, pistring), message_id);
}
retry_add_item(addrlist, retry_message_key,
rf_message | rf_host | delete_flag);