summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2015-01-13 11:19:32 +0000
committerJeremy Harris <jgh146exb@wizmail.org>2015-01-20 13:39:22 +0000
commit5032d1cf500b102849d9a47867fbb7b34d871683 (patch)
treeff63b3bfaac155f1c502b01dbdf5c3065a440f1d /src
parent7f3555b3d8e1fccfe8f5d450bdde367018a5e764 (diff)
Multi-recipient cutthrough delivery. Bug 1542
Testing and fixes by: Heiko Schlittermann <hs@schlittermann.de>
Diffstat (limited to 'src')
-rw-r--r--src/src/acl.c36
-rw-r--r--src/src/globals.c7
-rw-r--r--src/src/globals.h12
-rw-r--r--src/src/receive.c74
-rw-r--r--src/src/smtp_in.c2
-rw-r--r--src/src/verify.c261
6 files changed, 271 insertions, 121 deletions
diff --git a/src/src/acl.c b/src/src/acl.c
index 8fdae0390..06c1c494c 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -3354,19 +3354,27 @@ for (; cb != NULL; cb = cb->next)
break;
case CONTROL_CUTTHROUGH_DELIVERY:
- if (deliver_freeze)
- *log_msgptr = US"frozen";
- else if (queue_only_policy)
- *log_msgptr = US"queue-only";
- else if (fake_response == FAIL)
- *log_msgptr = US"fakereject";
+ if (prdr_requested)
+ /* Too hard to think about for now. We might in future cutthrough
+ the case where both sides handle prdr and this-node prdr acl
+ is "accept" */
+ *log_msgptr = string_sprintf(US"PRDR on %s reception\n", arg);
else
{
- cutthrough_delivery = TRUE;
- break;
+ if (deliver_freeze)
+ *log_msgptr = US"frozen";
+ else if (queue_only_policy)
+ *log_msgptr = US"queue-only";
+ else if (fake_response == FAIL)
+ *log_msgptr = US"fakereject";
+ else
+ {
+ if (rcpt_count == 1) cutthrough.delivery = TRUE;
+ break;
+ }
+ *log_msgptr = string_sprintf("\"control=%s\" on %s item",
+ arg, *log_msgptr);
}
- *log_msgptr = string_sprintf("\"control=%s\" on %s item",
- arg, *log_msgptr);
return ERROR;
}
break;
@@ -4351,9 +4359,9 @@ ratelimiters_cmd = NULL;
log_reject_target = LOG_MAIN|LOG_REJECT;
#ifndef DISABLE_PRDR
-if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR )
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR)
#else
-if (where == ACL_WHERE_RCPT )
+if (where == ACL_WHERE_RCPT)
#endif
{
adb = address_defaults;
@@ -4397,9 +4405,7 @@ case ACL_WHERE_RCPT:
#ifndef DISABLE_PRDR
case ACL_WHERE_PRDR:
#endif
- if( rcpt_count > 1 )
- cancel_cutthrough_connection("more than one recipient");
- else if (rc == OK && cutthrough_delivery && cutthrough_fd < 0)
+ if (rc == OK && cutthrough.delivery && rcpt_count > cutthrough.nrcpt)
open_cutthrough_connection(addr);
break;
diff --git a/src/src/globals.c b/src/src/globals.c
index a8670e414..a066f3595 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -506,8 +506,11 @@ int continue_sequence = 1;
uschar *continue_transport = NULL;
uschar *csa_status = NULL;
-BOOL cutthrough_delivery = FALSE;
-int cutthrough_fd = -1;
+cut_t cutthrough = {
+ FALSE, /* delivery: when to attempt */
+ -1, /* fd: open connection */
+ 0, /* nrcpt: number of addresses */
+};
BOOL daemon_listen = FALSE;
uschar *daemon_smtp_port = US"smtp";
diff --git a/src/src/globals.h b/src/src/globals.h
index 5495f54db..b5ea8a49b 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -291,8 +291,16 @@ extern int continue_sequence; /* Sequence num for continued delivery */
extern uschar *continue_transport; /* Transport for continued delivery */
extern uschar *csa_status; /* Client SMTP Authorization result */
-extern BOOL cutthrough_delivery; /* Deliver in foreground */
-extern int cutthrough_fd; /* Connection for ditto */
+
+typedef struct {
+ BOOL delivery; /* When to attempt */
+ int fd; /* Open connection */
+ int nrcpt; /* Count of addresses */
+ uschar * interface; /* (address of) */
+ host_item host; /* Host used */
+ address_item addr; /* (Chain of) addresses */
+} cut_t;
+extern cut_t cutthrough; /* Deliver-concurrently */
extern BOOL daemon_listen; /* True if listening required */
extern uschar *daemon_smtp_port; /* Can be a list of ports */
diff --git a/src/src/receive.c b/src/src/receive.c
index 8ab3166d0..977150c1d 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -997,7 +997,7 @@ switch(where)
case ACL_WHERE_DKIM:
case ACL_WHERE_MIME:
case ACL_WHERE_DATA:
- if (cutthrough_fd >= 0 && (acl_removed_headers || acl_added_headers))
+ if (cutthrough.fd >= 0 && (acl_removed_headers || acl_added_headers))
{
log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs"
" will not take effect on cutthrough deliveries");
@@ -2807,12 +2807,11 @@ if (filter_test != FTEST_NONE)
}
/* Cutthrough delivery:
- We have to create the Received header now rather than at the end of reception,
- so the timestamp behaviour is a change to the normal case.
- XXX Ensure this gets documented XXX.
- Having created it, send the headers to the destination.
-*/
-if (cutthrough_fd >= 0)
+We have to create the Received header now rather than at the end of reception,
+so the timestamp behaviour is a change to the normal case.
+XXX Ensure this gets documented XXX.
+Having created it, send the headers to the destination. */
+if (cutthrough.fd >= 0)
{
if (received_count > received_headers_max)
{
@@ -3184,56 +3183,61 @@ else
rc = OK;
while ((item = string_nextinlist(&ptr, &sep,
itembuf,
- sizeof(itembuf))) != NULL)
+ sizeof(itembuf))))
{
/* Prevent running ACL for an empty item */
if (!item || (item[0] == '\0')) continue;
- /* Only run ACL once for each domain or identity, no matter how often it
- appears in the expanded list. */
- if (seen_items != NULL)
+
+ /* Only run ACL once for each domain or identity,
+ no matter how often it appears in the expanded list. */
+ if (seen_items)
{
uschar *seen_item = NULL;
uschar seen_item_buf[256];
uschar *seen_items_list = seen_items;
- int seen_this_item = 0;
+ BOOL seen_this_item = FALSE;
while ((seen_item = string_nextinlist(&seen_items_list, &sep,
seen_item_buf,
- sizeof(seen_item_buf))) != NULL)
- {
- if (Ustrcmp(seen_item,item) == 0)
- {
- seen_this_item = 1;
- break;
- }
- }
-
- if (seen_this_item > 0)
+ sizeof(seen_item_buf))))
+ if (Ustrcmp(seen_item,item) == 0)
+ {
+ seen_this_item = TRUE;
+ break;
+ }
+
+ if (seen_this_item)
{
DEBUG(D_receive)
- debug_printf("acl_smtp_dkim: skipping signer %s, already seen\n", item);
+ debug_printf("acl_smtp_dkim: skipping signer %s, "
+ "already seen\n", item);
continue;
}
- seen_items = string_append(seen_items,&seen_items_size,&seen_items_offset,1,":");
+ seen_items = string_append(seen_items, &seen_items_size,
+ &seen_items_offset, 1, ":");
}
- seen_items = string_append(seen_items,&seen_items_size,&seen_items_offset,1,item);
+ seen_items = string_append(seen_items, &seen_items_size,
+ &seen_items_offset, 1, item);
seen_items[seen_items_offset] = '\0';
DEBUG(D_receive)
- debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n", item);
+ debug_printf("calling acl_smtp_dkim for dkim_cur_signer=%s\n",
+ item);
dkim_exim_acl_setup(item);
- rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim, &user_msg, &log_msg);
+ rc = acl_check(ACL_WHERE_DKIM, NULL, acl_smtp_dkim,
+ &user_msg, &log_msg);
if (rc != OK)
- {
- DEBUG(D_receive)
- debug_printf("acl_smtp_dkim: acl_check returned %d on %s, skipping remaining items\n", rc, item);
- cancel_cutthrough_connection("dkim acl not ok");
- break;
- }
+ {
+ DEBUG(D_receive)
+ debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
+ "skipping remaining items\n", rc, item);
+ cancel_cutthrough_connection("dkim acl not ok");
+ break;
+ }
}
add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
if (rc == DISCARD)
@@ -3957,7 +3961,7 @@ for this message. */
XXX We do not handle queue-only, freezing, or blackholes.
*/
-if(cutthrough_fd >= 0)
+if(cutthrough.fd >= 0)
{
uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the messsage */
/* Logging was done in finaldot() */
@@ -4103,7 +4107,7 @@ if (smtp_input)
case TMP_REJ: message_id[0] = 0; /* Prevent a delivery from starting */
default:break;
}
- cutthrough_delivery = FALSE;
+ cutthrough.delivery = FALSE;
}
/* For batched SMTP, generate an error message on failure, and do
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index 4fc2cfd41..4e4cdb825 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -4448,7 +4448,7 @@ while (done <= 0)
ACL may have delayed. To handle cutthrough delivery enforce a dummy call
to get the DATA command sent. */
- if (acl_smtp_predata == NULL && cutthrough_fd < 0) rc = OK; else
+ if (acl_smtp_predata == NULL && cutthrough.fd < 0) rc = OK; else
{
uschar * acl= acl_smtp_predata ? acl_smtp_predata : US"accept";
enable_dollar_recipients = TRUE;
diff --git a/src/src/verify.c b/src/src/verify.c
index 96740f8f3..4474f2c5b 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -14,7 +14,6 @@ caching was contributed by Kevin Fleming (but I hacked it around a bit). */
#define CUTTHROUGH_CMD_TIMEOUT 30 /* timeout for cutthrough-routing calls */
#define CUTTHROUGH_DATA_TIMEOUT 60 /* timeout for cutthrough-routing calls */
-address_item cutthrough_addr;
static smtp_outblock ctblock;
uschar ctbuffer[8192];
@@ -39,6 +38,7 @@ static tree_node *dnsbl_cache = NULL;
#define MT_NOT 1
#define MT_ALL 2
+static uschar cutthrough_response(char, uschar **);
/*************************************************
@@ -189,12 +189,12 @@ from_address = US"";
if (is_recipient)
{
- if ((options & vopt_callout_recipsender) != 0)
+ if (options & vopt_callout_recipsender)
{
address_key = string_sprintf("%s/<%s>", addr->address, sender_address);
from_address = sender_address;
}
- else if ((options & vopt_callout_recippmaster) != 0)
+ else if (options & vopt_callout_recippmaster)
{
address_key = string_sprintf("%s/<postmaster@%s>", addr->address,
qualify_domain_sender);
@@ -410,6 +410,113 @@ else
if (smtp_out != NULL && !disable_callout_flush) mac_smtp_fflush();
+/* cutthrough-multi: if a nonfirst rcpt has the same routing as the first,
+and we are holding a cutthrough conn open, we can just append the rcpt to
+that conn for verification purposes (and later delivery also). Simplest
+coding means skipping this whole loop and doing the append separately.
+
+We will need to remember it has been appended so that rcpt-acl tail code
+can do it there for the non-rcpt-verify case. For this we keep an addresscount.
+*/
+
+ /* Can we re-use an open cutthrough connection? */
+ if ( cutthrough.fd >= 0
+ && (options & (vopt_callout_recipsender | vopt_callout_recippmaster))
+ == vopt_callout_recipsender
+ && !random_local_part
+ && !pm_mailfrom
+ )
+ {
+ if (addr->transport == cutthrough.addr.transport)
+ for (host = host_list; host; host = host->next)
+ if (Ustrcmp(host->address, cutthrough.host.address) == 0)
+ {
+ int host_af;
+ uschar *interface = NULL; /* Outgoing interface to use; NULL => any */
+ int port = 25;
+
+ deliver_host = host->name;
+ deliver_host_address = host->address;
+ deliver_host_port = host->port;
+ deliver_domain = addr->domain;
+ transport_name = addr->transport->name;
+
+ host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
+
+ if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
+ US"callout") ||
+ !smtp_get_port(tf->port, addr, &port, US"callout"))
+ log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
+ addr->message);
+
+ if ( ( interface == cutthrough.interface
+ || ( interface
+ && cutthrough.interface
+ && Ustrcmp(interface, cutthrough.interface) == 0
+ ) )
+ && port == cutthrough.host.port
+ )
+ {
+ uschar * resp;
+
+ /* Match! Send the RCPT TO, append the addr, set done */
+ done =
+ smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n",
+ transport_rcpt_address(addr,
+ (addr->transport == NULL)? FALSE :
+ addr->transport->rcpt_include_affixes)) >= 0 &&
+ cutthrough_response('2', &resp) == '2';
+
+ /* This would go horribly wrong if a callout fail was ignored by ACL.
+ We punt by abandoning cutthrough on a reject, like the
+ first-rcpt does. */
+
+ if (done)
+ {
+ address_item * na = store_get(sizeof(address_item));
+ *na = cutthrough.addr;
+ cutthrough.addr = *addr;
+ cutthrough.addr.host_used = &cutthrough.host;
+ cutthrough.addr.next = na;
+
+ cutthrough.nrcpt++;
+ }
+ else
+ {
+ cancel_cutthrough_connection("recipient rejected");
+ if (errno == ETIMEDOUT)
+ {
+ HDEBUG(D_verify) debug_printf("SMTP timeout\n");
+ }
+ else if (errno == 0)
+ {
+ if (*resp == 0)
+ Ustrcpy(resp, US"connection dropped");
+
+ addr->message =
+ string_sprintf("response to \"%s\" from %s [%s] was: %s",
+ big_buffer, host->name, host->address,
+ string_printing(resp));
+
+ addr->user_message =
+ string_sprintf("Callout verification failed:\n%s", resp);
+
+ /* Hard rejection ends the process */
+
+ if (resp[0] == '5') /* Address rejected */
+ {
+ yield = FAIL;
+ done = TRUE;
+ }
+ }
+ }
+ }
+ break;
+ }
+ if (!done)
+ cancel_cutthrough_connection("incompatible connection");
+ }
+
/* Now make connections to the hosts and do real callouts. The list of hosts
is passed in as an argument. */
@@ -692,9 +799,9 @@ else
ob->command_timeout = callout;
rc = tls_client_start(inblock.sock, host, addr, addr->transport
-#ifdef EXPERIMENTAL_DANE
+# ifdef EXPERIMENTAL_DANE
, dane ? &tlsa_dnsa : NULL
-#endif
+# endif
);
ob->command_timeout = oldtimeout;
@@ -709,10 +816,10 @@ else
)
{
(void)close(inblock.sock);
-#ifdef EXPERIMENTAL_EVENT
+# ifdef EXPERIMENTAL_EVENT
(void) event_raise(addr->transport->event_action,
US"tcp:close", NULL);
-#endif
+# endif
log_write(0, LOG_MAIN, "TLS session failure: delivering unencrypted "
"to %s [%s] (not in hosts_require_tls)", host->name, host->address);
suppress_tls = TRUE;
@@ -741,9 +848,9 @@ else
/* If the host is required to use a secure channel, ensure that we have one. */
if (tls_out.active < 0)
if (
-#ifdef EXPERIMENTAL_DANE
+# ifdef EXPERIMENTAL_DANE
dane ||
-#endif
+# endif
verify_check_given_host(&ob->hosts_require_tls, host) == OK
)
{
@@ -757,7 +864,7 @@ else
goto TLS_FAILED;
}
- #endif /*SUPPORT_TLS*/
+#endif /*SUPPORT_TLS*/
done = TRUE; /* so far so good; have response to HELO */
@@ -765,17 +872,17 @@ else
/* For now, transport_filter by cutthrough-delivery is not supported */
/* Need proper integration with the proper transport mechanism. */
- if (cutthrough_delivery)
+ if (cutthrough.delivery)
{
if (addr->transport->filter_command)
{
- cutthrough_delivery= FALSE;
+ cutthrough.delivery = FALSE;
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n");
}
#ifndef DISABLE_DKIM
if (ob->dkim_domain)
{
- cutthrough_delivery= FALSE;
+ cutthrough.delivery = FALSE;
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n");
}
#endif
@@ -887,6 +994,8 @@ else
else if (errno == 0)
{
+ cancel_cutthrough_connection("random-recipient");
+
if (randombuffer[0] == '5')
new_domain_record.random_result = ccache_reject;
@@ -932,8 +1041,9 @@ else
if (done && pm_mailfrom != NULL)
{
- /*XXX not suitable for cutthrough - sequencing problems */
- cutthrough_delivery= FALSE;
+ /*XXX not suitable for cutthrough - we cannot afford to do an RSET
+ and lose the original mail-from */
+ cancel_cutthrough_connection("postmaster verify");
HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of postmaster verify\n");
done =
@@ -1028,30 +1138,34 @@ else
/* End the SMTP conversation and close the connection. */
- /* Cutthrough - on a successfull connect and recipient-verify with use-sender
- and we have no cutthrough conn so far
+ /* Cutthrough - on a successfull connect and recipient-verify with
+ use-sender and we are 1st rcpt and have no cutthrough conn so far
here is where we want to leave the conn open */
- if ( cutthrough_delivery
+ if ( cutthrough.delivery
+ && rcpt_count == 1
&& done
&& yield == OK
&& (options & (vopt_callout_recipsender|vopt_callout_recippmaster)) == vopt_callout_recipsender
&& !random_local_part
&& !pm_mailfrom
- && cutthrough_fd < 0
+ && cutthrough.fd < 0
)
{
- cutthrough_fd= outblock.sock; /* We assume no buffer in use in the outblock */
- cutthrough_addr = *addr; /* Save the address_item for later logging */
- cutthrough_addr.next = NULL;
- cutthrough_addr.host_used = store_get(sizeof(host_item));
- *(cutthrough_addr.host_used) = *host;
+ cutthrough.fd = outblock.sock; /* We assume no buffer in use in the outblock */
+ cutthrough.nrcpt = 1;
+ cutthrough.interface = interface;
+ cutthrough.host = *host;
+ cutthrough.addr = *addr; /* Save the address_item for later logging */
+ cutthrough.addr.next = NULL;
+ cutthrough.addr.host_used = &cutthrough.host;
if (addr->parent)
- *(cutthrough_addr.parent = store_get(sizeof(address_item)))= *addr->parent;
+ *(cutthrough.addr.parent = store_get(sizeof(address_item))) =
+ *addr->parent;
ctblock.buffer = ctbuffer;
ctblock.buffersize = sizeof(ctbuffer);
ctblock.ptr = ctbuffer;
/* ctblock.cmd_count = 0; ctblock.authenticating = FALSE; */
- ctblock.sock = cutthrough_fd;
+ ctblock.sock = cutthrough.fd;
}
else
{
@@ -1176,7 +1290,8 @@ address_item addr2;
get rewritten. */
addr2 = *addr;
-HDEBUG(D_acl) debug_printf("----------- start cutthrough setup ------------\n");
+HDEBUG(D_acl) debug_printf("----------- %s cutthrough setup ------------\n",
+ rcpt_count > 1 ? "more" : "start");
(void) verify_address(&addr2, NULL,
vopt_is_recipient | vopt_callout_recipsender | vopt_callout_no_cache,
CUTTHROUGH_CMD_TIMEOUT, -1, -1,
@@ -1191,14 +1306,14 @@ return;
static BOOL
cutthrough_send(int n)
{
-if(cutthrough_fd < 0)
+if(cutthrough.fd < 0)
return TRUE;
if(
#ifdef SUPPORT_TLS
- (tls_out.active == cutthrough_fd) ? tls_write(FALSE, ctblock.buffer, n) :
+ (tls_out.active == cutthrough.fd) ? tls_write(FALSE, ctblock.buffer, n) :
#endif
- send(cutthrough_fd, ctblock.buffer, n, 0) > 0
+ send(cutthrough.fd, ctblock.buffer, n, 0) > 0
)
{
transport_count += n;
@@ -1230,7 +1345,7 @@ return TRUE;
BOOL
cutthrough_puts(uschar * cp, int n)
{
-if (cutthrough_fd < 0) return TRUE;
+if (cutthrough.fd < 0) return TRUE;
if (_cutthrough_puts(cp, n)) return TRUE;
cancel_cutthrough_connection("transmit failed");
return FALSE;
@@ -1238,7 +1353,7 @@ return FALSE;
static BOOL
-_cutthrough_flush_send( void )
+_cutthrough_flush_send(void)
{
int n= ctblock.ptr-ctblock.buffer;
@@ -1251,7 +1366,7 @@ return TRUE;
/* Send out any bufferred output. Return boolean success. */
BOOL
-cutthrough_flush_send( void )
+cutthrough_flush_send(void)
{
if (_cutthrough_flush_send()) return TRUE;
cancel_cutthrough_connection("transmit failed");
@@ -1260,7 +1375,7 @@ return FALSE;
BOOL
-cutthrough_put_nl( void )
+cutthrough_put_nl(void)
{
return cutthrough_puts(US"\r\n", 2);
}
@@ -1278,7 +1393,7 @@ inblock.buffer = inbuffer;
inblock.buffersize = sizeof(inbuffer);
inblock.ptr = inbuffer;
inblock.ptrend = inbuffer;
-inblock.sock = cutthrough_fd;
+inblock.sock = cutthrough.fd;
/* this relies on (inblock.sock == tls_out.active) */
if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, CUTTHROUGH_DATA_TIMEOUT))
cancel_cutthrough_connection("target timeout on read");
@@ -1286,7 +1401,7 @@ if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect,
if(copy != NULL)
{
uschar * cp;
- *copy= cp= string_copy(responsebuffer);
+ *copy = cp = string_copy(responsebuffer);
/* Trim the trailing end of line */
cp += Ustrlen(responsebuffer);
if(cp > *copy && cp[-1] == '\n') *--cp = '\0';
@@ -1299,9 +1414,9 @@ return responsebuffer[0];
/* Negotiate dataphase with the cutthrough target, returning success boolean */
BOOL
-cutthrough_predata( void )
+cutthrough_predata(void)
{
-if(cutthrough_fd < 0)
+if(cutthrough.fd < 0)
return FALSE;
HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>> DATA\n");
@@ -1332,9 +1447,9 @@ return TRUE;
/* Expands newlines to wire format (CR,NL). */
/* Also sends header-terminating blank line. */
BOOL
-cutthrough_headers_send( void )
+cutthrough_headers_send(void)
{
-if(cutthrough_fd < 0)
+if(cutthrough.fd < 0)
return FALSE;
/* We share a routine with the mainline transport to handle header add/remove/rewrites,
@@ -1342,10 +1457,12 @@ if(cutthrough_fd < 0)
*/
HDEBUG(D_acl) debug_printf("----------- start cutthrough headers send -----------\n");
-if (!transport_headers_send(&cutthrough_addr, cutthrough_fd,
- cutthrough_addr.transport->add_headers, cutthrough_addr.transport->remove_headers,
+if (!transport_headers_send(&cutthrough.addr, cutthrough.fd,
+ cutthrough.addr.transport->add_headers,
+ cutthrough.addr.transport->remove_headers,
&cutthrough_write_chunk, TRUE,
- cutthrough_addr.transport->rewrite_rules, cutthrough_addr.transport->rewrite_existflags))
+ cutthrough.addr.transport->rewrite_rules,
+ cutthrough.addr.transport->rewrite_existflags))
return FALSE;
HDEBUG(D_acl) debug_printf("----------- done cutthrough headers send ------------\n");
@@ -1354,9 +1471,9 @@ return TRUE;
static void
-close_cutthrough_connection( const char * why )
+close_cutthrough_connection(const char * why)
{
-if(cutthrough_fd >= 0)
+if(cutthrough.fd >= 0)
{
/* We could be sending this after a bunch of data, but that is ok as
the only way to cancel the transfer in dataphase is to drop the tcp
@@ -1371,18 +1488,18 @@ if(cutthrough_fd >= 0)
#ifdef SUPPORT_TLS
tls_close(FALSE, TRUE);
#endif
- (void)close(cutthrough_fd);
- cutthrough_fd= -1;
+ (void)close(cutthrough.fd);
+ cutthrough.fd = -1;
HDEBUG(D_acl) debug_printf("----------- cutthrough shutdown (%s) ------------\n", why);
}
ctblock.ptr = ctbuffer;
}
void
-cancel_cutthrough_connection( const char * why )
+cancel_cutthrough_connection(const char * why)
{
close_cutthrough_connection(why);
-cutthrough_delivery= FALSE;
+cutthrough.delivery = FALSE;
}
@@ -1394,33 +1511,45 @@ cutthrough_delivery= FALSE;
Return smtp response-class digit.
*/
uschar *
-cutthrough_finaldot( void )
+cutthrough_finaldot(void)
{
+uschar res;
+address_item * addr;
HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>> .\n");
/* Assume data finshed with new-line */
-if(!cutthrough_puts(US".", 1) || !cutthrough_put_nl() || !cutthrough_flush_send())
- return cutthrough_addr.message;
+if( !cutthrough_puts(US".", 1)
+ || !cutthrough_put_nl()
+ || !cutthrough_flush_send()
+ )
+ return cutthrough.addr.message;
-switch(cutthrough_response('2', &cutthrough_addr.message))
+res = cutthrough_response('2', &cutthrough.addr.message);
+for (addr = &cutthrough.addr; addr; addr = addr->next)
{
- case '2':
- delivery_log(LOG_MAIN, &cutthrough_addr, (int)'>', NULL);
- close_cutthrough_connection("delivered");
- break;
+ addr->message = cutthrough.addr.message;
+ switch(res)
+ {
+ case '2':
+ delivery_log(LOG_MAIN, addr, (int)'>', NULL);
+ close_cutthrough_connection("delivered");
+ break;
- case '4':
- delivery_log(LOG_MAIN, &cutthrough_addr, 0, US"tmp-reject from cutthrough after DATA:");
- break;
+ case '4':
+ delivery_log(LOG_MAIN, addr, 0,
+ US"tmp-reject from cutthrough after DATA:");
+ break;
- case '5':
- delivery_log(LOG_MAIN|LOG_REJECT, &cutthrough_addr, 0, US"rejected after DATA:");
- break;
+ case '5':
+ delivery_log(LOG_MAIN|LOG_REJECT, addr, 0,
+ US"rejected after DATA:");
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
- return cutthrough_addr.message;
+return cutthrough.addr.message;
}