From cdf3e5b04eea80e49e8ae5a540ca921f62914e66 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 28 Sep 2020 13:31:38 -0700 Subject: [PATCH] retry isc_nm_udpconnect() if it fails On FreeBSD, we sometimes see spurious transient EADDRINUSE errors when connecting to a UDP socket. We now try a few times to ensure the error is real before giving up. This commit also fixes a memory leak that occurred if an error was encountered in isc__nm_async_udpconnect(). --- bin/dig/dighost.c | 16 ++++++++++++---- lib/isc/netmgr/udp.c | 9 +++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 6edb456940..e28ea8db7e 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -2918,7 +2918,8 @@ static void start_udp(dig_query_t *query) { dig_lookup_t *l = NULL; isc_result_t result; - dig_query_t *next; + dig_query_t *next = NULL; + int i = 0; REQUIRE(DIG_VALID_QUERY(query)); @@ -2971,9 +2972,16 @@ start_udp(dig_query_t *query) { } } - result = isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr, - (isc_nmiface_t *)&query->sockaddr, udp_ready, - query, 0); + do { + /* + * On FreeBSD the UDP connect() call sometimes results + * in a spurious transient EADDRINUSE. Try a few more times + * before giving up. + */ + result = isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr, + (isc_nmiface_t *)&query->sockaddr, + udp_ready, query, 0); + } while (result != ISC_R_SUCCESS && i++ < 2); check_result(result, "isc_nm_udpconnect"); } diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 4e88be7e3f..6ba07098de 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -607,7 +607,6 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { uv_udp_init(&worker->loop, &sock->uv_handle.udp); uv_handle_set_data(&sock->uv_handle.handle, NULL); uv_handle_set_data(&sock->uv_handle.handle, sock); - handle = isc__nmhandle_get(sock, &ievent->peer, &sock->iface->addr); r = uv_udp_open(&sock->uv_handle.udp, sock->fd); if (r != 0) { @@ -654,16 +653,17 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { atomic_store(&sock->connected, true); sock->result = ISC_R_SUCCESS; -done: cb = sock->connect_cb; cbarg = sock->connect_cbarg; + handle = isc__nmhandle_get(sock, &ievent->peer, &sock->iface->addr); cb(handle, sock->result, cbarg); LOCK(&sock->lock); SIGNAL(&sock->cond); UNLOCK(&sock->lock); +done: isc__nmsocket_detach(&sock); } @@ -743,10 +743,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, UNLOCK(&sock->lock); } - if (sock->result != ISC_R_SUCCESS) { - result = sock->result; - isc__nmsocket_detach(&sock); - } + sock->result = result; isc__nmsocket_detach(&tmp);