UDP write may fail indicating host isn't reachable (#821)

UDP is connectionless, but systems use ICMP unreachable messages to
indicate there is no ability to reach the host or port, which can result
in a `send()` returning an error like `ECONNREFUSED`. We need to handle
non-retryable codes like that to treat it as a connection failure so we
requeue any queries on that connection to another connection/server
immediately. Otherwise what happens is we just wait on the timeout to
expire which can greatly increase the time required to get a definitive
message.

This also adds a test case to verify the behavior.

Fixes #819
Fix By: Brad Houes (@bradh352)
v1.23
Brad House 4 months ago
parent aa86f52cea
commit 20d84ed244
  1. 23
      src/lib/ares_process.c

@ -996,9 +996,28 @@ ares_status_t ares__send_query(struct query *query, struct timeval *now)
}
conn = ares__llist_node_val(node);
if (ares__socket_write(channel, conn->fd, query->qbuf, query->qlen) == -1) {
/* FIXME: Handle EAGAIN here since it likely can happen. */
status = ARES_ESERVFAIL;
if (try_again(SOCKERRNO)) {
status = ARES_ESERVFAIL;
} else {
status = ARES_ECONNREFUSED;
}
if (status == ARES_ECONNREFUSED) {
handle_conn_error(conn, ARES_TRUE, status);
/* This query wasn't yet bound to the connection, need to manually
* requeue it and return an appropriate error */
status = ares__requeue_query(query, now, status);
if (status == ARES_ETIMEOUT) {
status = ARES_ECONNREFUSED;
}
return status;
}
/* FIXME: Handle EAGAIN here since it likely can happen. Right now we
* just requeue to a different server/connection. */
server_increment_failures(server);
status = ares__requeue_query(query, now, status);

Loading…
Cancel
Save