Behave better when attempting to contact unresponsive TCP servers.

By default TCP connect takes minutes to fail when trying to
connect a server which is not responding and for which the
network layer doesn't generate HOSTUNREACH errors.

This is doubled because having failed to connect in FASTOPEN
mode, the code then tries again with a call to connect().

We set TCP_SYNCNT to 2, which make the timeout about 10 seconds.
This in an unportable Linux feature, so it doesn't work on other
platforms.

No longer try connect() if sendmsg in fastopen mode fails with
ETIMEDOUT or EHOSTUNREACH since the story will just be the same.
This commit is contained in:
Simon Kelley
2023-05-26 17:55:35 +01:00
parent 1d6fe0ea84
commit 50adf82199

View File

@@ -1899,7 +1899,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
while (1) while (1)
{ {
int data_sent = 0; int data_sent = 0, timedout = 0;
struct server *serv; struct server *serv;
if (firstsendto == -1) if (firstsendto == -1)
@@ -1938,14 +1938,26 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
continue; continue;
} }
#ifdef TCP_SYNCNT
/* TCP connections by default take ages to time out.
At least on Linux, we can reduce that to only two attempts
to get a reply. For DNS, that's more sensible. */
mark = 2;
setsockopt(serv->tcpfd, IPPROTO_TCP, TCP_SYNCNT, &mark, sizeof(unsigned int));
#endif
#ifdef MSG_FASTOPEN #ifdef MSG_FASTOPEN
server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN); server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN);
if (errno == 0) if (errno == 0)
data_sent = 1; data_sent = 1;
else if (errno = ETIMEDOUT || errno == EHOSTUNREACH)
timedout = 1;
#endif #endif
if (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1) /* If fastopen failed due to lack of reply, then there's no point in
trying again in non-FASTOPEN mode. */
if (timedout || (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1))
{ {
close(serv->tcpfd); close(serv->tcpfd);
serv->tcpfd = -1; serv->tcpfd = -1;