Avoid bare TCP ACKs during TLS-on-connect startup.
[exim.git] / src / src / smtp_out.c
index c4c409677689f5ffaa74b55721640997fe72cc83..2d2fd21802c88d063405fc23dac8bdfc61f64257 100644 (file)
@@ -67,6 +67,7 @@ if (is_tainted(expint))
 Uskip_whitespace(&expint);
 if (!*expint) return TRUE;
 
+/* we just tested to ensure no taint, so big_buffer is ok */
 while ((iface = string_nextinlist(&expint, &sep, big_buffer,
           big_buffer_size)))
   {
@@ -158,20 +159,32 @@ tfo_out_check(int sock)
 {
 # ifdef __FreeBSD__
 struct tcp_info tinfo;
-int val;
-socklen_t len = sizeof(val);
+socklen_t len = sizeof(tinfo);
 
-/* The observability as of 12.1 is not useful as a client, only telling us that
-a TFO option was used on SYN.  It could have been a TFO-R, or ignored by the
-server. */
+/* A getsockopt TCP_FASTOPEN unfortunately returns "was-used" for a TFO/R as
+well as a TFO/C.  Use what we can of the Linux hack below; reliability issues ditto. */
+switch (tcp_out_fastopen)
+  {
+  case TFO_ATTEMPTED_NODATA:
+    if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
+       && tinfo.tcpi_state == TCPS_SYN_SENT
+       && tinfo.__tcpi_unacked > 0
+       )
+      {
+      DEBUG(D_transport|D_v)
+       debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.__tcpi_unacked);
+      tcp_out_fastopen = TFO_USED_NODATA;
+      }
+    break;
+  /*
+  case TFO_ATTEMPTED_DATA:
+  case TFO_ATTEMPTED_DATA:
+       if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA)   XXX no equvalent as of 12.2
+  */
+  }
 
-/*
-if (tcp_out_fastopen == TFO_ATTEMPTED_NODATA || tcp_out_fastopen == TFO_ATTEMPTED_DATA)
-  if (getsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &val, &len) == 0 && val != 0) {}
-*/
 switch (tcp_out_fastopen)
   {
-  case TFO_ATTEMPTED_NODATA:   tcp_out_fastopen = TFO_USED_NODATA; break;
   case TFO_ATTEMPTED_DATA:     tcp_out_fastopen = TFO_USED_DATA; break;
   default: break; /* compiler quietening */
   }
@@ -316,12 +329,12 @@ else
     HDEBUG(D_transport|D_acl|D_v)
       debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
 
-#ifdef TCP_QUICKACK
-    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
-#endif
     if (send(sock, early_data->data, early_data->len, 0) < 0)
       save_errno = errno;
     }
+#ifdef TCP_QUICKACK
+    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
+#endif
   }
 
 /* Either bind() or connect() failed */
@@ -609,7 +622,7 @@ if (format)
       while (!isspace(*p)) p++;
       while (isspace(*p)) p++;
       }
-    while (*p != 0) *p++ = '*';
+    while (*p) *p++ = '*';
     }
 
   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> %s\n", big_buffer);