This fixes the FreeSBD no-kernel-support issues (it succeded the sendto for the
connect-with-data, but dod not queue the data). Having checked dynamically, do
not claim support-for TFO either.
/* TCP_FASTOPEN support. There does not seems to be a
MSG_FASTOPEN defined yet... */
/* TCP_FASTOPEN support. There does not seems to be a
MSG_FASTOPEN defined yet... */
#include <netinet/tcp.h> /* for TCP_FASTOPEN */
#include <sys/socket.h> /* for MSG_FASTOPEN */
#include <netinet/tcp.h> /* for TCP_FASTOPEN */
#include <sys/socket.h> /* for MSG_FASTOPEN */
void
deliver_init(void)
{
void
deliver_init(void)
{
+#ifdef EXIM_TFO_PROBE
+tfo_probe();
+#else
+tcp_fastopen_ok = TRUE;
+#endif
+
+
if (!regex_PIPELINING) regex_PIPELINING =
regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
if (!regex_PIPELINING) regex_PIPELINING =
regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
fprintf(f, " SOCKS");
#endif
#ifdef TCP_FASTOPEN
fprintf(f, " SOCKS");
#endif
#ifdef TCP_FASTOPEN
- fprintf(f, " TCP_Fast_Open");
+ deliver_init();
+ if (tcp_fastopen_ok) fprintf(f, " TCP_Fast_Open");
#endif
#ifdef EXPERIMENTAL_LMDB
fprintf(f, " Experimental_LMDB");
#endif
#ifdef EXPERIMENTAL_LMDB
fprintf(f, " Experimental_LMDB");
extern int strncmpic(const uschar *, const uschar *, int);
extern uschar *strstric(uschar *, uschar *, BOOL);
extern int strncmpic(const uschar *, const uschar *, int);
extern uschar *strstric(uschar *, uschar *, BOOL);
+#ifdef EXIM_TFO_PROBE
+extern void tfo_probe(void);
+#endif
extern void timesince(struct timeval * diff, struct timeval * then);
extern void tls_modify_variables(tls_support *);
extern uschar *tod_stamp(int);
extern void timesince(struct timeval * diff, struct timeval * then);
extern void tls_modify_variables(tls_support *);
extern uschar *tod_stamp(int);
+/*************************************************
+*************************************************/
+
+#ifdef EXIM_TFO_PROBE
+void
+tfo_probe(void)
+{
+# ifdef TCP_FASTOPEN
+int sock, backlog = 5;
+
+if ( (sock = socket(SOCK_STREAM, AF_INET, 0)) < 0
+ && setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN,
+ &connect_backlog, sizeof(smtp_connect_backlog))
+ )
+ tcp_fastopen_ok = TRUE;
+close(sock);
+# endif
+}
+#endif
+
+
/*************************************************
* Connect socket to remote host *
*************************************************/
/*************************************************
* Connect socket to remote host *
*************************************************/
address the remote address, in text form
port the remote port
timeout a timeout (zero for indefinite timeout)
address the remote address, in text form
port the remote port
timeout a timeout (zero for indefinite timeout)
- fastopen non-null iff TCP_FASTOPEN can be used; may indicate early-data to
+ fastopen_blob non-null iff TCP_FASTOPEN can be used; may indicate early-data to
be sent in SYN segment
Returns: 0 on success; -1 on failure, with errno set
be sent in SYN segment
Returns: 0 on success; -1 on failure, with errno set
int
ip_connect(int sock, int af, const uschar *address, int port, int timeout,
int
ip_connect(int sock, int af, const uschar *address, int port, int timeout,
+ const blob * fastopen_blob)
{
struct sockaddr_in s_in4;
struct sockaddr *s_ptr;
{
struct sockaddr_in s_in4;
struct sockaddr *s_ptr;
the SMTP banner. Other (than SMTP) cases of TCP connections can
possibly use the data-on-syn, so support that too. */
the SMTP banner. Other (than SMTP) cases of TCP connections can
possibly use the data-on-syn, so support that too. */
+if (fastopen_blob && tcp_fastopen_ok)
- if ((rc = sendto(sock, fastopen->data, fastopen->len,
+ if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len,
MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
/* seen for with-data, experimental TFO option, with-cookie case */
/* seen for with-data, proper TFO opt, with-cookie case */
{
MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
/* seen for with-data, experimental TFO option, with-cookie case */
/* seen for with-data, proper TFO opt, with-cookie case */
{
- DEBUG(D_transport|D_v) debug_printf("TFO mode connection attempt, %s data\n",
- fastopen->len > 0 ? "with" : "no");
- tcp_out_fastopen = fastopen->len > 0 ? 2 : 1;
+ DEBUG(D_transport|D_v)
+ debug_printf("non-TFO mode connection attempt to %s, %d data\n",
+ address, fastopen_blob->len);
+ tcp_out_fastopen = fastopen_blob->len > 0 ? 2 : 1;
}
else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */
/* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */
}
else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */
/* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */
/* ? older Experimental TFO option behaviour ? */
{ /* queue unsent data */
DEBUG(D_transport|D_v) debug_printf("TFO mode sendto, %s data: EINPROGRESS\n",
/* ? older Experimental TFO option behaviour ? */
{ /* queue unsent data */
DEBUG(D_transport|D_v) debug_printf("TFO mode sendto, %s data: EINPROGRESS\n",
- fastopen->len > 0 ? "with" : "no");
- if (!fastopen->data)
+ fastopen_blob->len > 0 ? "with" : "no");
+ if (!fastopen_blob->data)
{
tcp_out_fastopen = 1; /* we tried; unknown if useful yet */
rc = 0;
}
else
{
tcp_out_fastopen = 1; /* we tried; unknown if useful yet */
rc = 0;
}
else
- rc = send(sock, fastopen->data, fastopen->len, 0);
+ rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
}
else if(errno == EOPNOTSUPP)
{
}
else if(errno == EOPNOTSUPP)
{
+ DEBUG(D_transport|D_v) if (fastopen_blob)
+ debug_printf("non-TFO mode connection attempt to %s, %d data\n",
+ address, fastopen_blob->len);
if ((rc = connect(sock, s_ptr, s_len)) >= 0)
if ((rc = connect(sock, s_ptr, s_len)) >= 0)
- if ( fastopen && fastopen->data && fastopen->len
- && send(sock, fastopen->data, fastopen->len, 0) < 0)
+ if ( fastopen_blob && fastopen_blob->data && fastopen_blob->len
+ && send(sock, fastopen_blob->data, fastopen_blob->len, 0) < 0)
timeout a timeout
connhost if not NULL, host_item to be filled in with connection details
errstr pointer for allocated string on error
timeout a timeout
connhost if not NULL, host_item to be filled in with connection details
errstr pointer for allocated string on error
- fastopen with SOCK_STREAM, if non-null, request TCP Fast Open.
+ fastopen_blob with SOCK_STREAM, if non-null, request TCP Fast Open.
Additionally, optional early-data to send
Return:
Additionally, optional early-data to send
Return:
*/
int
ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
*/
int
ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
- int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen)
+ int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen_blob)
{
int namelen, port;
host_item shost;
{
int namelen, port;
host_item shost;
}
for(port = portlo; port <= porthi; port++)
}
for(port = portlo; port <= porthi; port++)
- if (ip_connect(fd, af, h->address, port, timeout, fastopen) == 0)
+ if (ip_connect(fd, af, h->address, port, timeout, fastopen_blob) == 0)
{
if (fd != fd6) close(fd6);
if (fd != fd4) close(fd4);
{
if (fd != fd6) close(fd6);
if (fd != fd4) close(fd4);
*/
static inline int
m_tcpsocket(const uschar * hostname, unsigned int port,
*/
static inline int
m_tcpsocket(const uschar * hostname, unsigned int port,
- host_item * host, uschar ** errstr, const blob * fastopen)
+ host_item * host, uschar ** errstr, const blob * fastopen_blob)
{
return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
{
return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
- host, errstr, fastopen);
+ host, errstr, fastopen_blob);
int dscp_option;
int sock;
int save_errno = 0;
int dscp_option;
int sock;
int save_errno = 0;
-const blob * fastopen = NULL;
+const blob * fastopen_blob = NULL;
{
#ifdef TCP_FASTOPEN
if (verify_check_given_host(&ob->hosts_try_fastopen, host) == OK)
{
#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;
- 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)
- 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;
}
if (send(sock, early_data->data, early_data->len, 0) < 0)
save_errno = errno;
}
}
if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
#ifdef TCP_FASTOPEN
}
if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
#ifdef TCP_FASTOPEN
- if (fastopen) tfo_out_check(sock);
+ if (fastopen_blob) tfo_out_check(sock);