"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/ip.c" between
exim-4.91.tar.xz and exim-4.92.tar.xz

About: Exim is a message transfer agent (MTA).

ip.c  (exim-4.91.tar.xz):ip.c  (exim-4.92.tar.xz)
skipping to change at line 166 skipping to change at line 166
#ifdef EXIM_TFO_PROBE #ifdef EXIM_TFO_PROBE
void void
tfo_probe(void) tfo_probe(void)
{ {
# ifdef TCP_FASTOPEN # ifdef TCP_FASTOPEN
int sock, backlog = 5; int sock, backlog = 5;
if ( (sock = socket(SOCK_STREAM, AF_INET, 0)) < 0 if ( (sock = socket(SOCK_STREAM, AF_INET, 0)) < 0
&& setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog)) && setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog))
) )
tcp_fastopen_ok = TRUE; f.tcp_fastopen_ok = TRUE;
close(sock); close(sock);
# endif # endif
} }
#endif #endif
/************************************************* /*************************************************
* Connect socket to remote host * * Connect socket to remote host *
*************************************************/ *************************************************/
/* This function connects a socket to a remote address and port. The socket may /* This function connects a socket to a remote address and port. The socket may
skipping to change at line 188 skipping to change at line 188
closed, even in cases of error. It is expected that the calling function, which closed, even in cases of error. It is expected that the calling function, which
created the socket, will be the one that closes it. created the socket, will be the one that closes it.
Arguments: Arguments:
sock the socket sock the socket
af AF_INET6 or AF_INET for the socket type af AF_INET6 or AF_INET for the socket type
address the remote address, in text form address the remote address, in text form
port the remote port port the remote port
timeout a timeout (zero for indefinite timeout) timeout a timeout (zero for indefinite timeout)
fastopen_blob non-null iff TCP_FASTOPEN can be used; may indicate early-dat a to fastopen_blob non-null iff TCP_FASTOPEN can be used; may indicate early-dat a to
be sent in SYN segment be sent in SYN segment. Any such data must be idempotent.
Returns: 0 on success; -1 on failure, with errno set Returns: 0 on success; -1 on failure, with errno set
*/ */
int int
ip_connect(int sock, int af, const uschar *address, int port, int timeout, ip_connect(int sock, int af, const uschar *address, int port, int timeout,
const blob * fastopen_blob) const blob * fastopen_blob)
{ {
struct sockaddr_in s_in4; struct sockaddr_in s_in4;
struct sockaddr *s_ptr; struct sockaddr *s_ptr;
skipping to change at line 235 skipping to change at line 235
s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CCS address); s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CCS address);
s_ptr = (struct sockaddr *)&s_in4; s_ptr = (struct sockaddr *)&s_in4;
s_len = sizeof(s_in4); s_len = sizeof(s_in4);
} }
/* If no connection timeout is set, just call connect() without setting a /* If no connection timeout is set, just call connect() without setting a
timer, thereby allowing the inbuilt OS timeout to operate. */ timer, thereby allowing the inbuilt OS timeout to operate. */
callout_address = string_sprintf("[%s]:%d", address, port); callout_address = string_sprintf("[%s]:%d", address, port);
sigalrm_seen = FALSE; sigalrm_seen = FALSE;
if (timeout > 0) alarm(timeout); if (timeout > 0) ALARM(timeout);
#if defined(TCP_FASTOPEN) && defined(MSG_FASTOPEN) #ifdef TCP_FASTOPEN
/* TCP Fast Open, if the system has a cookie from a previous call to /* 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 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 before it gets our ACK of its SYN,ACK - the latter is useful for
the SMTP banner. Other (than SMTP) cases of TCP connections can the SMTP banner. Other (than SMTP) cases of TCP connections can
possibly use the data-on-syn, so support that too. */ possibly use the data-on-syn, so support that too. */
if (fastopen_blob && tcp_fastopen_ok) 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. */
if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len, if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len,
MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0) MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
/* seen for with-data, experimental TFO option, with-cookie case */ /* seen for with-data, experimental TFO option, with-cookie case */
/* seen for with-data, proper TFO opt, with-cookie case */ /* seen for with-data, proper TFO opt, with-cookie case */
{ {
DEBUG(D_transport|D_v) DEBUG(D_transport|D_v)
debug_printf("non-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); address, (unsigned long)fastopen_blob->len);
tcp_out_fastopen = fastopen_blob->len > 0 ? 2 : 1; /*XXX also seen on successful TFO, sigh */
tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMP
TED_NODATA;
} }
else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */ else if (errno == EINPROGRESS) /* expected if we had no cookie for peer */
/* seen for no-data, proper TFO option, both cookie-request and with-cook ie cases */ /* seen for no-data, proper TFO option, both cookie-request and with-cook ie cases */
/* apparently no visibility of the diffference at this point */ /* apparently no visibility of the diffference at this point */
/* seen for with-data, proper TFO opt, cookie-req */ /* 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 */ /* 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 ? */ /* ? older Experimental TFO option behaviour ? */
{ /* queue unsent data */ { /* 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"); fastopen_blob->len > 0 ? "with" : "no");
if (!fastopen_blob->data) if (!fastopen_blob->data)
{ {
tcp_out_fastopen = 1; /* we tried; unknown if useful yet */ tcp_out_fastopen = TFO_ATTEMPTED_NODATA; /* we tried; unknown if u seful yet */
rc = 0; rc = 0;
} }
else else
rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0); rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
} }
else if(errno == EOPNOTSUPP) else if(errno == EOPNOTSUPP)
{ {
DEBUG(D_transport) DEBUG(D_transport)
debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n") ; debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n") ;
goto legacy_connect; goto legacy_connect;
} }
# endif
# ifdef EXIM_TFO_CONNECTX
/* MacOS */
sa_endpoints_t ends = {
.sae_srcif = 0, .sae_srcaddr = NULL, .sae_srcaddrlen = 0,
.sae_dstaddr = s_ptr, .sae_dstaddrlen = s_len };
struct iovec iov = {
.iov_base = fastopen_blob->data, .iov_len = fastopen_blob->len };
size_t len;
if ((rc = connectx(sock, &ends, SAE_ASSOCID_ANY,
CONNECT_DATA_IDEMPOTENT, &iov, 1, &len, NULL)) == 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_ATTEMP
TED_NODATA;
if (len != fastopen_blob->len)
DEBUG(D_transport|D_v)
debug_printf(" only queued %lu data!\n", (unsigned long)len);
}
else if (errno == EINPROGRESS)
{
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 u
seful yet */
rc = 0;
}
else /* assume that no data was queued; block in send */
rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
}
# endif
} }
else else
#endif #endif /*TCP_FASTOPEN*/
{ {
legacy_connect: legacy_connect:
DEBUG(D_transport|D_v) if (fastopen_blob) 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); address, (unsigned long)fastopen_blob->len);
if ((rc = connect(sock, s_ptr, s_len)) >= 0) if ((rc = connect(sock, s_ptr, s_len)) >= 0)
if ( fastopen_blob && fastopen_blob->data && fastopen_blob->len if ( fastopen_blob && fastopen_blob->data && fastopen_blob->len
&& send(sock, fastopen_blob->data, fastopen_blob->len, 0) < 0) && send(sock, fastopen_blob->data, fastopen_blob->len, 0) < 0)
rc = -1; rc = -1;
} }
save_errno = errno; save_errno = errno;
alarm(0); ALARM_CLR(0);
/* There is a testing facility for simulating a connection timeout, as I /* There is a testing facility for simulating a connection timeout, as I
can't think of any other way of doing this. It converts a connection refused can't think of any other way of doing this. It converts a connection refused
into a timeout if the timeout is set to 999999. */ into a timeout if the timeout is set to 999999. */
if (running_in_test_harness && save_errno == ECONNREFUSED && timeout == 999999) if (f.running_in_test_harness && save_errno == ECONNREFUSED && timeout == 99999 9)
{ {
rc = -1; rc = -1;
save_errno = EINTR; save_errno = EINTR;
sigalrm_seen = TRUE; sigalrm_seen = TRUE;
} }
/* Success */ /* Success */
if (rc >= 0) if (rc >= 0)
return 0; return 0;
skipping to change at line 329 skipping to change at line 369
/************************************************* /*************************************************
* Create connected socket to remote host * * Create connected socket to remote host *
*************************************************/ *************************************************/
/* Create a socket and connect to host (name or number, ipv6 ok) /* Create a socket and connect to host (name or number, ipv6 ok)
at one of port-range. at one of port-range.
Arguments: Arguments:
type SOCK_DGRAM or SOCK_STREAM type SOCK_DGRAM or SOCK_STREAM
af AF_INET6 or AF_INET for the socket type af AF_INET6 or AF_INET for the socket type
address the remote address, in text form hostname host name, or ip address (as text)
portlo,porthi the remote port range portlo,porthi the remote port range
timeout a timeout timeout a timeout
connhost if not NULL, host_item to be filled in with connection details connhost if not NULL, host_item to be filled in with connection details
errstr pointer for allocated string on error errstr pointer for allocated string on error
fastopen_blob 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 Additionally, optional idempotent early-data to send
Return: Return:
socket fd, or -1 on failure (having allocated an error string) socket fd, or -1 on failure (having allocated an error string)
*/ */
int int
ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi, ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen _blob) int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen _blob)
{ {
int namelen, port; int namelen, port;
host_item shost; host_item shost;
skipping to change at line 578 skipping to change at line 618
} }
while (rc < 0 || !FD_ISSET(fd, &select_inset)); while (rc < 0 || !FD_ISSET(fd, &select_inset));
return TRUE; return TRUE;
} }
/* The timeout is implemented using select(), and we loop to cover select() /* The timeout is implemented using select(), and we loop to cover select()
getting interrupted, and the possibility of select() returning with a positive getting interrupted, and the possibility of select() returning with a positive
result but no ready descriptor. Is this in fact possible? result but no ready descriptor. Is this in fact possible?
Arguments: Arguments:
sock the socket cctx the connection context (socket fd, possibly TLS context)
buffer to read into buffer to read into
bufsize the buffer size bufsize the buffer size
timeout the timeout timeout the timeout
Returns: > 0 => that much data read Returns: > 0 => that much data read
<= 0 on error or EOF; errno set - zero for EOF <= 0 on error or EOF; errno set - zero for EOF
*/ */
int int
ip_recv(int sock, uschar *buffer, int buffsize, int timeout) ip_recv(client_conn_ctx * cctx, uschar * buffer, int buffsize, int timeout)
{ {
int rc; int rc;
if (!fd_ready(sock, timeout)) if (!fd_ready(cctx->sock, timeout))
return -1; return -1;
/* The socket is ready, read from it (via TLS if it's active). On EOF (i.e. /* The socket is ready, read from it (via TLS if it's active). On EOF (i.e.
close down of the connection), set errno to zero; otherwise leave it alone. */ close down of the connection), set errno to zero; otherwise leave it alone. */
#ifdef SUPPORT_TLS #ifdef SUPPORT_TLS
if (tls_out.active == sock) if (cctx->tls_ctx) /* client TLS */
rc = tls_read(FALSE, buffer, buffsize); rc = tls_read(cctx->tls_ctx, buffer, buffsize);
else if (tls_in.active == sock) else if (tls_in.active.sock == cctx->sock) /* server TLS */
rc = tls_read(TRUE, buffer, buffsize); rc = tls_read(NULL, buffer, buffsize);
else else
#endif #endif
rc = recv(sock, buffer, buffsize, 0); rc = recv(cctx->sock, buffer, buffsize, 0);
if (rc > 0) return rc; if (rc > 0) return rc;
if (rc == 0) errno = 0; if (rc == 0) errno = 0;
return -1; return -1;
} }
/************************************************* /*************************************************
* Lookup address family of potential socket * * Lookup address family of potential socket *
*************************************************/ *************************************************/
 End of changes. 21 change blocks. 
22 lines changed or deleted 66 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)