X-Git-Url: https://git.exim.org/users/heiko/exim.git/blobdiff_plain/01603eec64d42431f182b33008206facfc7f800e..677481d4fcf4811e193603d0e9970d1f62c74567:/src/src/ip.c diff --git a/src/src/ip.c b/src/src/ip.c index fb42f0051..bf332b160 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -14,6 +14,12 @@ different places in the code where sockets are used. */ #include "exim.h" +#if defined(TCP_FASTOPEN) +# if defined(MSG_FASTOPEN) || defined(EXIM_TFO_CONNECTX) || defined(EXIM_TFO_FREEBSD) +# define EXIM_SUPPORT_TFO +# endif +#endif + /************************************************* * Create a socket * *************************************************/ @@ -160,26 +166,6 @@ return bind(sock, (struct sockaddr *)&sin, s_len); -/************************************************* -*************************************************/ - -#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, &backlog, sizeof(backlog)) - ) - f.tcp_fastopen_ok = TRUE; -close(sock); -# endif -} -#endif - - /************************************************* * Connect socket to remote host * *************************************************/ @@ -245,7 +231,7 @@ callout_address = string_sprintf("[%s]:%d", address, port); sigalrm_seen = FALSE; if (timeout > 0) ALARM(timeout); -#ifdef TCP_FASTOPEN +#ifdef EXIM_SUPPORT_TFO /* 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 @@ -255,8 +241,7 @@ possibly use the data-on-syn, so support that too. */ if (fastopen_blob && f.tcp_fastopen_ok) { # ifdef MSG_FASTOPEN - /* This is a Linux implementation. It might be useable on FreeBSD; I have - not checked. */ + /* This is a Linux implementation. */ if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len, MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0) @@ -264,7 +249,7 @@ if (fastopen_blob && f.tcp_fastopen_ok) /* seen for with-data, proper TFO opt, with-cookie case */ { DEBUG(D_transport|D_v) - debug_printf("TFO mode connection attempt to %s, %lu data\n", + debug_printf(" TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); /*XXX also seen on successful TFO, sigh */ tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA; @@ -276,7 +261,7 @@ if (fastopen_blob && f.tcp_fastopen_ok) /* 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", + DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n", fastopen_blob->len > 0 ? "with" : "no"); if (!fastopen_blob->data) { @@ -292,8 +277,26 @@ if (fastopen_blob && f.tcp_fastopen_ok) debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); goto legacy_connect; } -# endif -# ifdef EXIM_TFO_CONNECTX + +# elif defined(EXIM_TFO_FREEBSD) + /* Re: https://people.freebsd.org/~pkelsey/tfo-tools/tfo-client.c */ + + if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on)) < 0) + { + DEBUG(D_transport) + debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); + goto legacy_connect; + } + if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len, 0, + s_ptr, s_len)) >= 0) + { + DEBUG(D_transport|D_v) + debug_printf(" TFO mode connection attempt to %s, %lu data\n", + address, (unsigned long)fastopen_blob->len); + tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA; + } + +# elif defined(EXIM_TFO_CONNECTX) /* MacOS */ sa_endpoints_t ends = { .sae_srcif = 0, .sae_srcaddr = NULL, .sae_srcaddrlen = 0, @@ -306,7 +309,7 @@ if (fastopen_blob && f.tcp_fastopen_ok) CONNECT_DATA_IDEMPOTENT, &iov, 1, &len, NULL)) == 0) { DEBUG(D_transport|D_v) - debug_printf("TFO mode connection attempt to %s, %lu data\n", + debug_printf(" TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA; @@ -316,7 +319,7 @@ if (fastopen_blob && f.tcp_fastopen_ok) } else if (errno == EINPROGRESS) { - DEBUG(D_transport|D_v) debug_printf("TFO mode sendto, %s data: EINPROGRESS\n", + DEBUG(D_transport|D_v) debug_printf(" TFO mode connectx, %s data: EINPROGRESS\n", fastopen_blob->len > 0 ? "with" : "no"); if (!fastopen_blob->data) { @@ -329,14 +332,14 @@ if (fastopen_blob && f.tcp_fastopen_ok) # endif } else -#endif /*TCP_FASTOPEN*/ +#endif /*EXIM_SUPPORT_TFO*/ { -#if defined(TCP_FASTOPEN) && defined(MSG_FASTOPEN) +#if defined(EXIM_SUPPORT_TFO) && !defined(EXIM_TFO_CONNECTX) legacy_connect: #endif DEBUG(D_transport|D_v) if (fastopen_blob) - debug_printf("non-TFO mode connection attempt to %s, %lu data\n", + debug_printf(" non-TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); if ((rc = connect(sock, s_ptr, s_len)) >= 0) if ( fastopen_blob && fastopen_blob->data && fastopen_blob->len @@ -515,7 +518,7 @@ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) callout_address = string_copy(path); server.sun_family = AF_UNIX; -Ustrncpy(server.sun_path, path, sizeof(server.sun_path)-1); +Ustrncpy(US server.sun_path, path, sizeof(server.sun_path)-1); server.sun_path[sizeof(server.sun_path)-1] = '\0'; if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { @@ -528,6 +531,10 @@ 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. +*/ int ip_streamsocket(const uschar * spec, uschar ** errstr, int tmo) { @@ -568,16 +575,15 @@ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, /* Arguments: fd the file descriptor - timeout the timeout, seconds + timelimit the timeout endpoint, seconds-since-epoch Returns: TRUE => ready for i/o FALSE => timed out, or other error */ BOOL -fd_ready(int fd, int timeout) +fd_ready(int fd, time_t timelimit) { fd_set select_inset; -time_t start_recv = time(NULL); -int time_left = timeout; +int time_left = timelimit - time(NULL); int rc; if (time_left <= 0) @@ -611,8 +617,7 @@ do DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n"); /* Watch out, 'continue' jumps to the condition, not to the loops top */ - time_left = timeout - (time(NULL) - start_recv); - if (time_left > 0) continue; + if ((time_left = timelimit - time(NULL)) > 0) continue; } if (rc <= 0) @@ -636,18 +641,18 @@ Arguments: cctx the connection context (socket fd, possibly TLS context) buffer to read into bufsize the buffer size - timeout the timeout + timelimit the timeout endpoint, seconds-since-epoch Returns: > 0 => that much data read <= 0 on error or EOF; errno set - zero for EOF */ int -ip_recv(client_conn_ctx * cctx, uschar * buffer, int buffsize, int timeout) +ip_recv(client_conn_ctx * cctx, uschar * buffer, int buffsize, time_t timelimit) { int rc; -if (!fd_ready(cctx->sock, timeout)) +if (!fd_ready(cctx->sock, timelimit)) return -1; /* The socket is ready, read from it (via TLS if it's active). On EOF (i.e.