* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* A number of functions for driving outgoing SMTP calls. */
if (!(expint = expand_string(istring)))
{
- if (expand_string_forcedfail) return TRUE;
+ if (f.expand_string_forcedfail) return TRUE;
addr->transport_return = PANIC;
addr->message = string_sprintf("failed to expand \"interface\" "
"option for %s: %s", msg, expand_string_message);
+#ifdef TCP_FASTOPEN
+static void
+tfo_out_check(int sock)
+{
+# if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
+struct tcp_info tinfo;
+socklen_t len = sizeof(tinfo);
+
+if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0)
+ {
+ switch (tcp_out_fastopen)
+ {
+ /* This is a somewhat dubious detection method; totally undocumented so likely
+ to fail in future kernels. There seems to be no documented way. What we really
+ want to know is if the server sent smtp-banner data before our ACK of his SYN,ACK
+ hit him. What this (possibly?) detects is whether we sent a TFO cookie with our
+ SYN, as distinct from a TFO request. This gets a false-positive when the server
+ key is rotated; we send the old one (which this test sees) but the server returns
+ the new one and does not send its SMTP banner before we ACK his SYN,ACK.
+ To force that rotation case:
+ '# echo -n "00000000-00000000-00000000-0000000" >/proc/sys/net/ipv4/tcp_fastopen_key'
+ The kernel seems to be counting unack'd packets. */
+
+ case 1:
+ if (tinfo.tcpi_unacked > 1)
+ {
+ DEBUG(D_transport|D_v)
+ debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.tcpi_unacked);
+ tcp_out_fastopen = 2;
+ }
+ break;
+
+#ifdef notdef /* This seems to always fire, meaning that we cannot tell
+ whether the server accepted data we sent. For now assume
+ that it did. */
+
+ /* If there was data-on-SYN but we had to retrasnmit it, declare no TFO */
+
+ case 2:
+ if (!(tinfo.tcpi_options & TCPI_OPT_SYN_DATA))
+ {
+ DEBUG(D_transport|D_v) debug_printf("TFO: had to retransmit\n");
+ tcp_out_fastopen = 0;
+ }
+ break;
+#endif
+ }
+
+ }
+# endif
+}
+#endif
+
+
/* Arguments as for smtp_connect(), plus
early_data if non-NULL, data to be sent - preferably in the TCP SYN segment
int dscp_option;
int sock;
int save_errno = 0;
+const blob * fastopen_blob = NULL;
+
#ifndef DISABLE_EVENT
deliver_host_address = host->address;
else
{
- const blob * fastopen = NULL;
-
#ifdef TCP_FASTOPEN
if (verify_check_given_host(&ob->hosts_try_fastopen, host) == OK)
- fastopen = early_data ? early_data : &tcp_fastopen_nodata;
+ fastopen_blob = early_data ? early_data : &tcp_fastopen_nodata;
#endif
- if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
+ if (ip_connect(sock, host_af, host->address, port, timeout, fastopen_blob) < 0)
save_errno = errno;
- else if (early_data && !fastopen && early_data->data && early_data->len)
+ else if (early_data && !fastopen_blob && early_data->data && early_data->len)
if (send(sock, early_data->data, early_data->len, 0) < 0)
save_errno = errno;
}
return -1;
}
if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
+#ifdef TCP_FASTOPEN
+ if (fastopen_blob) tfo_out_check(sock);
+#endif
return sock;
}
}
more ? " (more expected)" : "");
#ifdef SUPPORT_TLS
-if (tls_out.active == outblock->sock)
- rc = tls_write(FALSE, outblock->buffer, n, more);
+if (outblock->cctx->tls_ctx)
+ rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more);
else
#endif
- rc = send(outblock->sock, outblock->buffer, n,
+ rc = send(outblock->cctx->sock, outblock->buffer, n,
#ifdef MSG_MORE
more ? MSG_MORE : 0
#else
any error message.
Arguments:
- outblock contains buffer for pipelining, and socket
+ sx SMTP connection, contains buffer for pipelining, and socket
mode buffer, write-with-more-likely, write
format a format, starting with one of
of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT.
*/
int
-smtp_write_command(smtp_outblock * outblock, int mode, const char *format, ...)
+smtp_write_command(void * sx, int mode, const char *format, ...)
{
+smtp_outblock * outblock = &((smtp_context *)sx)->outblock;
int count;
int rc = 0;
va_list ap;
uschar *p = buffer;
uschar *ptr = inblock->ptr;
uschar *ptrend = inblock->ptrend;
-int sock = inblock->sock;
+client_conn_ctx * cctx = inblock->cctx;
/* Loop for reading multiple packets or reading another packet after emptying
a previously-read one. */
/* Need to read a new input packet. */
- if((rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout)) <= 0)
+ if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timeout)) <= 0)
{
DEBUG(D_deliver|D_transport|D_acl)
debug_printf_indent(errno ? " SMTP(%s)<<\n" : " SMTP(closed)<<\n",
the error code will be in errno.
Arguments:
- inblock the SMTP input block (contains holding buffer, socket, etc.)
+ sx the SMTP connection (contains input block with holding buffer,
+ socket, etc.)
buffer where to put the response
size the size of the buffer
okdigit the expected first digit of the response
*/
BOOL
-smtp_read_response(smtp_inblock *inblock, uschar *buffer, int size, int okdigit,
+smtp_read_response(void * sx, uschar *buffer, int size, int okdigit,
int timeout)
{
+smtp_inblock * inblock = &((smtp_context *)sx)->inblock;
uschar *ptr = buffer;
int count;