TFO: better detection of client fast-open connections
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 19 Sep 2017 14:10:21 +0000 (15:10 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 19 Sep 2017 14:10:21 +0000 (15:10 +0100)
src/OS/os.h-Linux
src/src/ip.c
src/src/smtp_out.c
test/log/4027
test/scripts/1990-TCP-Fast-Open/1990

index f6d35772b73ddc666b5e694861d4f3c55994f586..cc1f3cab2df2544983f3fc42aac851c107fe971b 100644 (file)
@@ -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 */
index 8727451445898cf3f5eb0797d3399fe16636eaa4..258ab5c230039d8d256a9d6bb7d0f608df81dbe1 100644 (file)
@@ -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
index 9221aa8680dd5985987574abf0d84424dbf7671d..db33ac66e26990c7ba0be6222ff0dd58106ee604 100644 (file)
@@ -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;
   }
 }
index ed6b92611836940666d03a62ef081a22c5c3da67..3af3f325bc95cec8cc209e1aa99ba7c8e6dc70ad 100644 (file)
@@ -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
index 47b77af0ee43107fd627156c69edeee504d40377..cbedd3622eeeed6bfd505b17dad793865f0c6dbf 100644 (file)
 # (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
 #
 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