From ac0dcd3f05a8821d7ce042646472be1995a08042 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 19 Sep 2017 15:10:21 +0100 Subject: [PATCH] TFO: better detection of client fast-open connections --- src/OS/os.h-Linux | 1 - src/src/ip.c | 40 +++++++++++++++++----------- src/src/smtp_out.c | 27 ------------------- test/log/4027 | 4 +-- test/scripts/1990-TCP-Fast-Open/1990 | 12 ++++++--- 5 files changed, 36 insertions(+), 48 deletions(-) diff --git a/src/OS/os.h-Linux b/src/OS/os.h-Linux index f6d35772b..cc1f3cab2 100644 --- a/src/OS/os.h-Linux +++ b/src/OS/os.h-Linux @@ -79,7 +79,6 @@ then change the 0 to 1 in the next block. */ #if defined(TCP_FASTOPEN) && !defined(MSG_FASTOPEN) # define MSG_FASTOPEN 0x20000000 #endif -#define EXIM_HAVE_TCPI_UNACKED /* End */ diff --git a/src/src/ip.c b/src/src/ip.c index 872745144..258ab5c23 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -229,27 +229,37 @@ if (timeout > 0) alarm(timeout); /* TCP Fast Open, if the system has a cookie from a previous call to this peer, can send data in the SYN packet. The peer can send data before it gets our ACK of its SYN,ACK - the latter is useful for -the SMTP banner. Is there any usage where the former might be? -We might extend the ip_connect() args for data if so. For now, -connect in FASTOPEN mode but with zero data. -*/ +the SMTP banner. Other (than SMTP) cases of TCP connections can +possibly use the data-on-syn, so support that too. */ if (fastopen) { if ((rc = sendto(sock, fastopen->data, fastopen->len, - MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) < 0) - if (errno == EINPROGRESS) /* expected for nonready peer */ - { /* queue the data */ - if ( (rc = send(sock, fastopen->data, fastopen->len, 0)) < 0 - && errno == EINPROGRESS) /* expected for nonready peer */ - rc = 0; - } - else if(errno == EOPNOTSUPP) + MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0) + { + DEBUG(D_transport|D_v) + debug_printf("TCP_FASTOPEN mode connection, with data\n"); + tcp_out_fastopen = TRUE; + } + else if (errno == EINPROGRESS) /* expected for nonready peer */ + { + if (!fastopen->data) { - DEBUG(D_transport) - debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); - goto legacy_connect; + DEBUG(D_transport|D_v) + debug_printf("TCP_FASTOPEN mode connection, no data\n"); + tcp_out_fastopen = TRUE; + rc = 0; } + else if ( (rc = send(sock, fastopen->data, fastopen->len, 0)) < 0 + && errno == EINPROGRESS) /* expected for nonready peer */ + rc = 0; + } + else if(errno == EOPNOTSUPP) + { + DEBUG(D_transport) + debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); + goto legacy_connect; + } } else #endif diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 9221aa868..db33ac66e 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -140,30 +140,6 @@ return TRUE; -#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) - { - /* This is a somewhat dubious detection method; totally undocumented so likely - to fail in future kernels. There seems to be no documented way. */ - - if (tinfo.tcpi_unacked > 1) - { - DEBUG(D_transport|D_v) debug_printf("TCP_FASTOPEN mode connection\n"); - tcp_out_fastopen = TRUE; - } - } -# endif -} -#endif - - /* Arguments as for smtp_connect(), plus early_data if non-NULL, data to be sent - preferably in the TCP SYN segment @@ -278,9 +254,6 @@ else return -1; } if (ob->keepalive) ip_keepalive(sock, host->address, TRUE); -#ifdef TCP_FASTOPEN - tfo_out_check(sock); -#endif return sock; } } diff --git a/test/log/4027 b/test/log/4027 index ed6b92611..3af3f325b 100644 --- a/test/log/4027 +++ b/test/log/4027 @@ -1,6 +1,6 @@ 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -1999-03-02 09:44:33 10HmaX-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 C="250 accepted OK" +1999-03-02 09:44:33 10HmaX-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 TFO C="250 accepted OK" 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss -1999-03-02 09:44:33 10HmaY-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 C="250 accepted OK" +1999-03-02 09:44:33 10HmaY-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 TFO C="250 accepted OK" 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/scripts/1990-TCP-Fast-Open/1990 b/test/scripts/1990-TCP-Fast-Open/1990 index 47b77af0e..cbedd3622 100644 --- a/test/scripts/1990-TCP-Fast-Open/1990 +++ b/test/scripts/1990-TCP-Fast-Open/1990 @@ -14,10 +14,13 @@ # (currently on a separate packet after the server SYN,ACK but before # the client ACK). # -# The log <= line should have a "TFO" element. +# The client log => lint.ex should have a "TFO" element. +# Assuming this is the first run since boot, the a@test recipient will not. +# +# The server log <= line for b@test.ex should have a "TFO" element, but +# this will only be obtained when the above delay is inserted into the +# loopback net path. # -# If the client-side is disabled in the kernel, Exim logs -# will become noisy. # # # FreeBSD: it looks like you have to compile a custom kernel, with @@ -27,13 +30,16 @@ # exim -DSERVER=server -bd -oX PORT_D **** +# exim a@test.ex Testing **** sleep 3 +# exim b@test.ex Testing **** sleep 3 +# killdaemon no_msglog_check -- 2.25.1