TFO: even in binary built for modern Linux, handle error returned by old Linux kernel...
[exim.git] / src / src / ip.c
index 108c21d92659edb4ec4a4b4a9b299d28e79ad020..4c543566dd55b0547548d1c732dd2af03eb87cbc 100644 (file)
@@ -254,28 +254,34 @@ if (fastopen_blob && f.tcp_fastopen_ok)
     /*XXX also seen on successful TFO, sigh */
     tcp_out_fastopen = fastopen_blob->len > 0 ?  TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA;
     }
-  else if (errno == EINPROGRESS)       /* expected if we had no cookie for peer */
+  else switch (errno)
+    {
+    case EINPROGRESS:  /* expected if we had no cookie for peer */
        /* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */
        /*  apparently no visibility of the diffference at this point */
        /* seen for with-data, proper TFO opt, cookie-req */
        /*   with netwk delay, post-conn tcp_info sees unacked 1 for R, 2 for C; code in smtp_out.c */
        /* ? older Experimental TFO option behaviour ? */
-    {                                  /* queue unsent data */
-    DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n",
-      fastopen_blob->len > 0 ? "with"  : "no");
-    if (!fastopen_blob->data)
-      {
-      tcp_out_fastopen = TFO_ATTEMPTED_NODATA;         /* we tried; unknown if useful yet */
-      rc = 0;
-      }
-    else
-      rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
-    }
-  else if(errno == EOPNOTSUPP)
-    {
-    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(" TFO mode sendto, %s data: EINPROGRESS\n",
+       fastopen_blob->len > 0 ? "with"  : "no");
+      if (!fastopen_blob->data)
+       {
+       tcp_out_fastopen = TFO_ATTEMPTED_NODATA;                /* we tried; unknown if useful yet */
+       rc = 0;
+       }
+      else                                     /* queue unsent data */
+       rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
+      break;
+
+    case EOPNOTSUPP:
+      DEBUG(D_transport)
+       debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
+      goto legacy_connect;
+
+    case EPIPE:
+      DEBUG(D_transport)
+       debug_printf("Tried TCP Fast Open but kernel too old to support it\n");
+      goto legacy_connect;
     }
 
 # elif defined(EXIM_TFO_FREEBSD)
@@ -482,7 +488,8 @@ bad:
 
 /*XXX TFO? */
 int
-ip_tcpsocket(const uschar * hostport, uschar ** errstr, int tmo)
+ip_tcpsocket(const uschar * hostport, uschar ** errstr, int tmo,
+  host_item * connhost)
 {
 int scan;
 uschar hostname[256];
@@ -501,7 +508,7 @@ if (scan != 3)
   }
 
 return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
-                         tmo, NULL, errstr, NULL);
+                         tmo, connhost, errstr, NULL);
 }
 
 int
@@ -531,11 +538,18 @@ if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
 return sock;
 }
 
+/* spec is either an absolute path (with a leading /), or
+a host (name or IP) and port (whitespace-separated).
+The port can be a range, dash-separated, or a single number.
+
+For a TCP socket, optionally fill in a  host_item.
+*/
 int
-ip_streamsocket(const uschar * spec, uschar ** errstr, int tmo)
+ip_streamsocket(const uschar * spec, uschar ** errstr, int tmo,
+  host_item * connhost)
 {
 return *spec == '/'
-  ? ip_unixsocket(spec, errstr) : ip_tcpsocket(spec, errstr, tmo);
+  ? ip_unixsocket(spec, errstr) : ip_tcpsocket(spec, errstr, tmo, connhost);
 }
 
 /*************************************************