From a70cd026df05d4085545860f05f6b93618f594ad Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 1 Apr 2021 14:02:03 -0700 Subject: [PATCH] move UDP connect retries from dig into isc_nm_udpconnect() dig previously ran isc_nm_udpconnect() three times before giving up, to work around a freebsd bug that caused connect() to return a spurious transient EADDRINUSE. this commit moves the retry code into the network manager itself, so that isc_nm_udpconnect() no longer needs to return a result code. --- bin/dig/dighost.c | 50 +++++++++++++------------------------------- bin/dig/dighost.h | 1 - lib/isc/netmgr/udp.c | 11 +++++++++- 3 files changed, 25 insertions(+), 37 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 9d8a1e5a22..3ec72f96f7 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -2794,12 +2794,11 @@ start_tcp(dig_query_t *query) { if (query->lookup->tls_mode) { result = isc_tlsctx_createclient(&query->tlsctx); RUNTIME_CHECK(result == ISC_R_SUCCESS); - result = isc_nm_tlsdnsconnect( - netmgr, (isc_nmiface_t *)&localaddr, - (isc_nmiface_t *)&query->sockaddr, - tcp_connected, query, local_timeout, 0, - query->tlsctx); - check_result(result, "isc_nm_tlsdnsconnect"); + isc_nm_tlsdnsconnect(netmgr, + (isc_nmiface_t *)&localaddr, + (isc_nmiface_t *)&query->sockaddr, + tcp_connected, query, + local_timeout, 0, query->tlsctx); } else if (query->lookup->https_mode) { char uri[4096] = { 0 }; snprintf(uri, sizeof(uri), "https://%s:%u%s", @@ -2814,18 +2813,16 @@ start_tcp(dig_query_t *query) { query->tlsctx); } - result = isc_nm_httpconnect( - netmgr, (isc_nmiface_t *)&localaddr, - (isc_nmiface_t *)&query->sockaddr, uri, - !query->lookup->https_get, tcp_connected, query, - query->tlsctx, local_timeout, 0); - check_result(result, "isc_nm_httpconnect"); + isc_nm_httpconnect(netmgr, (isc_nmiface_t *)&localaddr, + (isc_nmiface_t *)&query->sockaddr, + uri, !query->lookup->https_get, + tcp_connected, query, query->tlsctx, + local_timeout, 0); } else { - result = isc_nm_tcpdnsconnect( + isc_nm_tcpdnsconnect( netmgr, (isc_nmiface_t *)&localaddr, (isc_nmiface_t *)&query->sockaddr, tcp_connected, query, local_timeout, 0); - check_result(result, "isc_nm_tcpdnsconnect"); } /* XXX: set DSCP */ @@ -2904,9 +2901,7 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { debug("udp setup failed: %s", isc_result_totext(eresult)); } - if (query->tries == 0) { - query_detach(&query); - } + query_detach(&query); return; } @@ -2993,24 +2988,9 @@ start_udp(dig_query_t *query) { } } - query->tries = 3; - do { - int local_timeout = timeout * 1000; - if (local_timeout == 0) { - local_timeout = UDP_TIMEOUT * 1000; - } - - /* - * On FreeBSD the UDP connect() call sometimes results - * in a spurious transient EADDRINUSE. Try a few more times - * before giving up. - */ - debug("isc_nm_udpconnect(): %d tries left", --query->tries); - result = isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr, - (isc_nmiface_t *)&query->sockaddr, - udp_ready, query, local_timeout, 0); - } while (result != ISC_R_SUCCESS && query->tries > 0); - check_result(result, "isc_nm_udpconnect"); + isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr, + (isc_nmiface_t *)&query->sockaddr, udp_ready, query, + (timeout ? timeout : UDP_TIMEOUT) * 1000, 0); } /*% diff --git a/bin/dig/dighost.h b/bin/dig/dighost.h index 0dfeb56da5..8da437625b 100644 --- a/bin/dig/dighost.h +++ b/bin/dig/dighost.h @@ -208,7 +208,6 @@ struct dig_query { isc_time_t time_recv; uint64_t byte_count; isc_timer_t *timer; - uint8_t tries; isc_tlsctx_t *tlsctx; }; diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 843be0b6ac..9485fb76d5 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -597,6 +597,7 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; int uv_bind_flags = UV_UDP_REUSEADDR; isc_result_t result = ISC_R_DEFAULT; + int tries = 3; int r; REQUIRE(isc__nm_in_netthread()); @@ -642,7 +643,15 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { &(int){ ISC_SEND_BUFFER_SIZE }); #endif - r = isc_uv_udp_connect(&sock->uv_handle.udp, &req->peer.type.sa); + /* + * On FreeBSD the UDP connect() call sometimes results in a + * spurious transient EADDRINUSE. Try a few more times before + * giving up. + */ + do { + r = isc_uv_udp_connect(&sock->uv_handle.udp, + &req->peer.type.sa); + } while (r == UV_EADDRINUSE && --tries > 0); if (r != 0) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECTFAIL]);