diff --git a/CHANGES b/CHANGES index 17c04181bd..22f8200293 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +5612. [bug] Continued refactoring of the network manager: + - allow recovery from read and connect timeout events + - ensure that calls to isc_nm_*connect() always + return the connection status via a callback + function. + [GL #2401] + 5611. [func] Set "stale-answer-client-timeout" to "off" by default. [GL #2608] diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 9d8a1e5a22..4d2aee207e 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -1541,12 +1541,13 @@ _destroy_lookup(dig_lookup_t *lookup) { dig_server_t *s; void *ptr; + REQUIRE(lookup != NULL); + REQUIRE(ISC_LIST_EMPTY(lookup->q)); + debug("destroy_lookup"); isc_refcount_destroy(&lookup->references); - REQUIRE(ISC_LIST_EMPTY(lookup->q)); - s = ISC_LIST_HEAD(lookup->my_server_list); while (s != NULL) { debug("freeing server %p belonging to %p", s, lookup); @@ -2794,12 +2795,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 +2814,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 */ @@ -2900,13 +2898,15 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { query_detach(&query); return; } else if (eresult != ISC_R_SUCCESS) { + dig_lookup_t *l = query->lookup; + if (eresult != ISC_R_CANCELED) { debug("udp setup failed: %s", isc_result_totext(eresult)); } - if (query->tries == 0) { - query_detach(&query); - } + + lookup_detach(&l); + query_detach(&query); return; } @@ -2993,24 +2993,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/bin/rndc/rndc.c b/bin/rndc/rndc.c index bc3d124328..47c862e24f 100644 --- a/bin/rndc/rndc.c +++ b/bin/rndc/rndc.c @@ -574,7 +574,6 @@ rndc_connected(isc_nmhandle_t *handle, isc_result_t result, void *arg) { static void rndc_startconnect(isc_sockaddr_t *addr) { - isc_result_t result; char socktext[ISC_SOCKADDR_FORMATSIZE]; isc_sockaddr_t *local = NULL; @@ -600,10 +599,8 @@ rndc_startconnect(isc_sockaddr_t *addr) { } atomic_fetch_add_relaxed(&connects, 1); - DO("create connection", - isc_nm_tcpconnect(netmgr, (isc_nmiface_t *)local, - (isc_nmiface_t *)addr, rndc_connected, &rndc_ccmsg, - 10000, 0)); + isc_nm_tcpconnect(netmgr, (isc_nmiface_t *)local, (isc_nmiface_t *)addr, + rndc_connected, &rndc_ccmsg, 10000, 0); } static void diff --git a/bin/tests/test_client.c b/bin/tests/test_client.c index 4056e537f3..c145115af8 100644 --- a/bin/tests/test_client.c +++ b/bin/tests/test_client.c @@ -235,8 +235,6 @@ parse_options(int argc, char **argv) { } } - INSIST(optind < argc); - { struct addrinfo hints = { .ai_family = family, @@ -281,7 +279,7 @@ parse_options(int argc, char **argv) { isc_sockaddr_format(&sockaddr_remote, buf, sizeof(buf)); - printf("to %s, %d workers\n", buf, workers); + printf(" to %s, %d workers\n", buf, workers); } static void @@ -378,16 +376,16 @@ connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { isc_nmhandle_t *readhandle = NULL; REQUIRE(handle != NULL); - REQUIRE(eresult == ISC_R_SUCCESS); UNUSED(cbarg); + fprintf(stderr, "ECHO_CLIENT:%s:%s\n", __func__, + isc_result_totext(eresult)); + if (eresult != ISC_R_SUCCESS) { kill(getpid(), SIGTERM); return; } - fprintf(stderr, "ECHO_CLIENT:%s\n", __func__); - isc_nmhandle_attach(handle, &readhandle); isc_nm_read(handle, read_cb, readhandle); isc_nm_send(handle, &message, send_cb, NULL); @@ -422,28 +420,23 @@ sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf, static void run(void) { - isc_result_t result; - switch (protocol) { case UDP: - result = isc_nm_udpconnect(netmgr, - (isc_nmiface_t *)&sockaddr_local, - (isc_nmiface_t *)&sockaddr_remote, - connect_cb, NULL, timeout, 0); + isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&sockaddr_local, + (isc_nmiface_t *)&sockaddr_remote, connect_cb, + NULL, timeout, 0); break; case TCP: - result = isc_nm_tcpdnsconnect(netmgr, - (isc_nmiface_t *)&sockaddr_local, - (isc_nmiface_t *)&sockaddr_remote, - connect_cb, NULL, timeout, 0); + isc_nm_tcpdnsconnect(netmgr, (isc_nmiface_t *)&sockaddr_local, + (isc_nmiface_t *)&sockaddr_remote, + connect_cb, NULL, timeout, 0); break; case DOT: { isc_tlsctx_createclient(&tls_ctx); - result = isc_nm_tlsdnsconnect( - netmgr, (isc_nmiface_t *)&sockaddr_local, - (isc_nmiface_t *)&sockaddr_remote, connect_cb, NULL, - timeout, 0, tls_ctx); + isc_nm_tlsdnsconnect(netmgr, (isc_nmiface_t *)&sockaddr_local, + (isc_nmiface_t *)&sockaddr_remote, + connect_cb, NULL, timeout, 0, tls_ctx); break; } case HTTP_GET: @@ -460,16 +453,15 @@ run(void) { if (is_https) { isc_tlsctx_createclient(&tls_ctx); } - result = isc_nm_httpconnect( - netmgr, (isc_nmiface_t *)&sockaddr_local, - (isc_nmiface_t *)&sockaddr_remote, req_url, is_post, - connect_cb, NULL, tls_ctx, timeout, 0); + isc_nm_httpconnect(netmgr, (isc_nmiface_t *)&sockaddr_local, + (isc_nmiface_t *)&sockaddr_remote, req_url, + is_post, connect_cb, NULL, tls_ctx, timeout, + 0); } break; default: INSIST(0); ISC_UNREACHABLE(); } - REQUIRE(result == ISC_R_SUCCESS); waitforsignal(); diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index c0e06cf71a..03ccb115a2 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -894,17 +894,17 @@ xfrin_start(dns_xfrin_ctx_t *xfr) { */ switch (transport_type) { case DNS_TRANSPORT_TCP: - CHECK(isc_nm_tcpdnsconnect( - xfr->netmgr, (isc_nmiface_t *)&xfr->sourceaddr, - (isc_nmiface_t *)&xfr->masteraddr, xfrin_connect_done, - connect_xfr, 30000, 0)); + isc_nm_tcpdnsconnect(xfr->netmgr, + (isc_nmiface_t *)&xfr->sourceaddr, + (isc_nmiface_t *)&xfr->masteraddr, + xfrin_connect_done, connect_xfr, 30000, 0); break; case DNS_TRANSPORT_TLS: CHECK(isc_tlsctx_createclient(&xfr->tlsctx)); - CHECK(isc_nm_tlsdnsconnect( + isc_nm_tlsdnsconnect( xfr->netmgr, (isc_nmiface_t *)&xfr->sourceaddr, (isc_nmiface_t *)&xfr->masteraddr, xfrin_connect_done, - connect_xfr, 30000, 0, xfr->tlsctx)); + connect_xfr, 30000, 0, xfr->tlsctx); break; default: INSIST(0); diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 215b0150b0..a89436345f 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -207,7 +207,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, * can then be freed automatically when the handle is destroyed. */ -isc_result_t +void isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize); @@ -318,7 +318,7 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, * */ -isc_result_t +void isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize); @@ -481,16 +481,16 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface, size_t extrahandlesize, int backlog, isc_quota_t *quota, isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp); -isc_result_t +void isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx, unsigned int timeout, size_t extrahandlesize); -isc_result_t +void isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize); -isc_result_t +void isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize, isc_tlsctx_t *sslctx); @@ -508,7 +508,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, * 'cb'. */ -isc_result_t +void isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx, unsigned int timeout, diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 5fbd0ac90f..f1595eee94 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -1058,7 +1058,7 @@ http_call_connect_cb(isc_nmsocket_t *sock, isc_result_t result) { req->handle = isc__nmhandle_get(sock, &sock->peer, &sock->iface->addr); isc__nmsocket_clearcb(sock); - isc__nm_connectcb_force_async(sock, req, result); + isc__nm_connectcb(sock, req, result, true); } static void @@ -1147,12 +1147,11 @@ error: isc__nmsocket_detach(&http_sock); } -isc_result_t +void isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, const char *uri, bool post, isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *tlsctx, unsigned int timeout, size_t extrahandlesize) { - isc_result_t result; isc_nmiface_t local_interface; isc_nmsocket_t *sock = NULL; @@ -1176,12 +1175,34 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->result = ISC_R_DEFAULT; sock->connect_cb = cb; sock->connect_cbarg = cbarg; + atomic_init(&sock->client, true); + + if (isc__nm_closing(sock)) { + isc__nm_uvreq_t *req = isc__nm_uvreq_get(mgr, sock); + + req->cb.connect = cb; + req->cbarg = cbarg; + req->peer = peer->addr; + req->local = local->addr; + req->handle = isc__nmhandle_get(sock, &req->peer, + &sock->iface->addr); + + if (isc__nm_in_netthread()) { + sock->tid = isc_nm_tid(); + } + + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, ISC_R_CANCELED, true); + isc__nmsocket_prep_destroy(sock); + isc__nmsocket_detach(&sock); + return; + } + sock->h2 = (isc_nmsocket_h2_t){ .connect.uri = isc_mem_strdup(mgr->mctx, uri), .connect.post = post, .connect.tlsctx = tlsctx }; ISC_LINK_INIT(&sock->h2, link); - atomic_init(&sock->client, true); /* * We need to prevent the interface object data from going out of @@ -1193,16 +1214,12 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, } if (tlsctx != NULL) { - result = isc_nm_tlsconnect(mgr, local, peer, - transport_connect_cb, sock, tlsctx, - timeout, 0); + isc_nm_tlsconnect(mgr, local, peer, transport_connect_cb, sock, + tlsctx, timeout, 0); } else { - result = isc_nm_tcpconnect(mgr, local, peer, - transport_connect_cb, sock, timeout, - 0); + isc_nm_tcpconnect(mgr, local, peer, transport_connect_cb, sock, + timeout, 0); } - - return (result); } static isc_result_t diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index f625cf8aaf..ed285f8367 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -854,8 +854,6 @@ struct isc_nmsocket { * TCP read/connect timeout timers. */ uv_timer_t timer; - bool timer_initialized; - bool timer_running; uint64_t read_timeout; uint64_t connect_timeout; @@ -1136,6 +1134,13 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG); * if there are no remaining references or active handles. */ +void +isc__nmsocket_shutdown(isc_nmsocket_t *sock); +/*%< + * Initiate the socket shutdown which actively calls the active + * callbacks. + */ + bool isc__nmsocket_active(isc_nmsocket_t *sock); /*%< @@ -1167,17 +1172,15 @@ void isc__nmsocket_timer_start(isc_nmsocket_t *sock); void isc__nmsocket_timer_restart(isc_nmsocket_t *sock); +bool +isc__nmsocket_timer_running(isc_nmsocket_t *sock); /*%< - * Start/stop/restart the read timeout on the socket + * Start/stop/restart/check the timeout on the socket */ void isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, - isc_result_t eresult); - -void -isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, - isc_result_t eresult); + isc_result_t eresult, bool async); void isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0); @@ -1850,7 +1853,8 @@ isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); void isc__nm_tcpdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); void -isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); +isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, + bool async); isc_result_t isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock); @@ -1867,6 +1871,8 @@ void isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags); void +isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); +void isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); void isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); @@ -1880,7 +1886,9 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock); void isc__nm_resume_processing(void *arg); bool -isc__nm_inactive(isc_nmsocket_t *sock); +isc__nmsocket_closing(isc_nmsocket_t *sock); +bool +isc__nm_closing(isc_nmsocket_t *sock); void isc__nm_alloc_dnsbuf(isc_nmsocket_t *sock, size_t len); @@ -1892,8 +1900,11 @@ void isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult); void isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult); + isc_result_t eresult, bool async); void -isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); +isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async); + +void +isc__nmsocket_connecttimeout_cb(uv_timer_t *timer); #define STREAM_CLIENTS_PER_CONN 23 diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index a0b2892555..34828e0c2b 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -827,7 +827,6 @@ NETIEVENT_SOCKET_REQ_DEF(tcpconnect); NETIEVENT_SOCKET_REQ_DEF(tcpsend); NETIEVENT_SOCKET_REQ_DEF(tlssend); NETIEVENT_SOCKET_REQ_DEF(udpconnect); - NETIEVENT_SOCKET_REQ_RESULT_DEF(connectcb); NETIEVENT_SOCKET_REQ_RESULT_DEF(readcb); NETIEVENT_SOCKET_REQ_RESULT_DEF(sendcb); @@ -987,15 +986,6 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) { sock->pquota = NULL; - if (sock->timer_initialized) { - sock->timer_initialized = false; - /* We might be in timer callback */ - if (!uv_is_closing((uv_handle_t *)&sock->timer)) { - uv_timer_stop(&sock->timer); - uv_close((uv_handle_t *)&sock->timer, NULL); - } - } - isc_astack_destroy(sock->inactivehandles); while ((uvreq = isc_astack_pop(sock->inactivereqs)) != NULL) { @@ -1031,6 +1021,9 @@ nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG) { int active_handles; bool destroy = false; + NETMGR_TRACE_LOG("%s():%p->references = %" PRIuFAST32 "\n", __func__, + sock, isc_refcount_current(&sock->references)); + if (sock->parent != NULL) { /* * This is a child socket and cannot be destroyed except @@ -1397,11 +1390,16 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer, #endif UNLOCK(&sock->lock); - if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket || - (sock->type == isc_nm_udpsocket && atomic_load(&sock->client)) || - (sock->type == isc_nm_tcpdnssocket && atomic_load(&sock->client)) || - (sock->type == isc_nm_tlsdnssocket && atomic_load(&sock->client))) - { + switch (sock->type) { + case isc_nm_udpsocket: + case isc_nm_tcpdnssocket: + case isc_nm_tlsdnssocket: + if (!atomic_load(&sock->client)) { + break; + } + /* fallthrough */ + case isc_nm_tcpsocket: + case isc_nm_tlssocket: INSIST(sock->statichandle == NULL); /* @@ -1411,6 +1409,9 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer, * handle and socket would never be freed. */ sock->statichandle = handle; + break; + default: + break; } if (sock->type == isc_nm_httpsocket && sock->h2.session) { @@ -1520,6 +1521,9 @@ isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) { } } +void +isc__nmsocket_shutdown(isc_nmsocket_t *sock); + static void nmhandle_detach_cb(isc_nmhandle_t **handlep FLARG) { isc_nmsocket_t *sock = NULL; @@ -1658,24 +1662,26 @@ isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { void isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { + isc_result_t eresult, bool async) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(VALID_UVREQ(req)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); REQUIRE(req->cb.connect != NULL); - atomic_store(&sock->connecting, false); + isc__nmsocket_timer_stop(sock); + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + + INSIST(atomic_compare_exchange_strong(&sock->connecting, + &(bool){ true }, false)); isc__nmsocket_clearcb(sock); - - isc__nm_connectcb(sock, req, eresult); + isc__nm_connectcb(sock, req, eresult, async); isc__nmsocket_prep_destroy(sock); } void -isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { +isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async) { REQUIRE(VALID_NMSOCK(sock)); switch (sock->type) { case isc_nm_udpsocket: @@ -1688,7 +1694,7 @@ isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { isc__nm_tcpdns_failed_read_cb(sock, result); return; case isc_nm_tlsdnssocket: - isc__nm_tlsdns_failed_read_cb(sock, result); + isc__nm_tlsdns_failed_read_cb(sock, result, async); return; default: INSIST(0); @@ -1696,6 +1702,39 @@ isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { } } +void +isc__nmsocket_connecttimeout_cb(uv_timer_t *timer) { + uv_connect_t *uvreq = uv_handle_get_data((uv_handle_t *)timer); + isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)uvreq->handle); + isc__nm_uvreq_t *req = uv_handle_get_data((uv_handle_t *)uvreq); + + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); + REQUIRE(atomic_load(&sock->connecting)); + REQUIRE(VALID_UVREQ(req)); + REQUIRE(VALID_NMHANDLE(req->handle)); + + isc__nmsocket_timer_stop(sock); + + if (sock->tls.pending_req != NULL) { + REQUIRE(req == sock->tls.pending_req); + sock->tls.pending_req = NULL; + } + + /* Call the connect callback directly */ + + req->cb.connect(req->handle, ISC_R_TIMEDOUT, req->cbarg); + + /* Timer is not running, cleanup and shutdown everything */ + if (!isc__nmsocket_timer_running(sock)) { + INSIST(atomic_compare_exchange_strong(&sock->connecting, + &(bool){ true }, false)); + isc__nm_uvreq_put(&req, sock); + isc__nmsocket_clearcb(sock); + isc__nmsocket_shutdown(sock); + } +} + static void isc__nmsocket_readtimeout_cb(uv_timer_t *timer) { isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer); @@ -1704,27 +1743,62 @@ isc__nmsocket_readtimeout_cb(uv_timer_t *timer) { REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->reading); - isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT); + if (atomic_load(&sock->client)) { + uv_timer_stop(timer); + + if (sock->recv_cb != NULL) { + isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); + isc__nm_readcb(sock, req, ISC_R_TIMEDOUT); + } + + if (!isc__nmsocket_timer_running(sock)) { + isc__nmsocket_clearcb(sock); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } + } else { + isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false); + } } void isc__nmsocket_timer_restart(isc_nmsocket_t *sock) { + int r = 0; + REQUIRE(VALID_NMSOCK(sock)); - if (sock->read_timeout == 0) { - return; + if (atomic_load(&sock->connecting)) { + if (sock->connect_timeout == 0) { + return; + } + + r = uv_timer_start(&sock->timer, + isc__nmsocket_connecttimeout_cb, + sock->connect_timeout + 10, 0); + + } else { + if (sock->read_timeout == 0) { + return; + } + + r = uv_timer_start(&sock->timer, isc__nmsocket_readtimeout_cb, + sock->read_timeout, 0); } - int r = uv_timer_start(&sock->timer, isc__nmsocket_readtimeout_cb, - sock->read_timeout, 0); RUNTIME_CHECK(r == 0); } +bool +isc__nmsocket_timer_running(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + + return (uv_is_active((uv_handle_t *)&sock->timer)); +} + void isc__nmsocket_timer_start(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); - if (uv_is_active((uv_handle_t *)&sock->timer)) { + if (isc__nmsocket_timer_running(sock)) { return; } @@ -1735,9 +1809,7 @@ void isc__nmsocket_timer_stop(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); - if (!uv_is_active((uv_handle_t *)&sock->timer)) { - return; - } + /* uv_timer_stop() is idempotent, no need to check if running */ int r = uv_timer_stop(&sock->timer); RUNTIME_CHECK(r == 0); @@ -1751,13 +1823,21 @@ isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) { req->cb.recv = sock->recv_cb; req->cbarg = sock->recv_cbarg; - if (atomic_load(&sock->client)) { + switch (sock->type) { + case isc_nm_tcpsocket: + case isc_nm_tlssocket: isc_nmhandle_attach(sock->statichandle, &req->handle); - } else { - req->handle = isc__nmhandle_get(sock, sockaddr, NULL); + break; + default: + if (atomic_load(&sock->client)) { + isc_nmhandle_attach(sock->statichandle, &req->handle); + } else { + req->handle = isc__nmhandle_get(sock, sockaddr, NULL); + } + break; } - return req; + return (req); } /*%< @@ -1779,6 +1859,7 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE); size = ISC_NETMGR_RECVBUF_SIZE; break; + case isc_nm_tcpsocket: case isc_nm_tcpdnssocket: break; case isc_nm_tlsdnssocket: @@ -1797,7 +1878,7 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { } worker = &sock->mgr->workers[sock->tid]; - INSIST(!worker->recvbuf_inuse); + INSIST(!worker->recvbuf_inuse || sock->type == isc_nm_udpsocket); buf->base = worker->recvbuf; buf->len = size; @@ -1817,6 +1898,10 @@ isc__nm_start_reading(isc_nmsocket_t *sock) { r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb, isc__nm_udp_read_cb); break; + case isc_nm_tcpsocket: + r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, + isc__nm_tcp_read_cb); + break; case isc_nm_tcpdnssocket: r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, isc__nm_tcpdns_read_cb); @@ -1845,6 +1930,7 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) { case isc_nm_udpsocket: r = uv_udp_recv_stop(&sock->uv_handle.udp); break; + case isc_nm_tcpsocket: case isc_nm_tcpdnssocket: case isc_nm_tlsdnssocket: r = uv_read_stop(&sock->uv_handle.stream); @@ -1858,7 +1944,12 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) { } bool -isc__nm_inactive(isc_nmsocket_t *sock) { +isc__nm_closing(isc_nmsocket_t *sock) { + return (atomic_load(&sock->mgr->closing)); +} + +bool +isc__nmsocket_closing(isc_nmsocket_t *sock) { return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || atomic_load(&sock->mgr->closing) || (sock->server != NULL && !isc__nmsocket_active(sock->server))); @@ -1945,7 +2036,7 @@ isc__nm_resume_processing(void *arg) { REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(!atomic_load(&sock->client)); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { return; } @@ -1987,9 +2078,7 @@ isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { return; default: handle->sock->read_timeout = timeout; - if (uv_is_active((uv_handle_t *)&handle->sock->timer)) { - isc__nmsocket_timer_restart(handle->sock); - } + isc__nmsocket_timer_restart(handle->sock); } } @@ -2241,38 +2330,27 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) { } } -static void -nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, isc_result_t eresult, - bool force_async) { - isc__netievent_connectcb_t *ievent = NULL; - +void +isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, + isc_result_t eresult, bool async) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(VALID_UVREQ(uvreq)); REQUIRE(VALID_NMHANDLE(uvreq->handle)); - ievent = isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq, - eresult); - if (force_async) { + if (!async) { + isc__netievent_connectcb_t ievent = { .sock = sock, + .req = uvreq, + .result = eresult }; + isc__nm_async_connectcb(NULL, (isc__netievent_t *)&ievent); + } else { + isc__netievent_connectcb_t *ievent = + isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq, + eresult); isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], (isc__netievent_t *)ievent); - } else { - isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); } } -void -isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, - isc_result_t eresult) { - nm_connectcb(sock, uvreq, eresult, false); -} - -void -isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, - isc_result_t eresult) { - nm_connectcb(sock, uvreq, eresult, true); -} - void isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_connectcb_t *ievent = (isc__netievent_connectcb_t *)ev0; @@ -2403,23 +2481,8 @@ isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0) { nmhandle_detach_cb(&ievent->handle FLARG_PASS); } -static void -shutdown_walk_cb(uv_handle_t *handle, void *arg) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - UNUSED(arg); - - if (uv_is_closing(handle)) { - return; - } - - switch (handle->type) { - case UV_UDP: - case UV_TCP: - break; - default: - return; - } - +void +isc__nmsocket_shutdown(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); switch (sock->type) { case isc_nm_udpsocket: @@ -2445,6 +2508,26 @@ shutdown_walk_cb(uv_handle_t *handle, void *arg) { } } +static void +shutdown_walk_cb(uv_handle_t *handle, void *arg) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + UNUSED(arg); + + if (uv_is_closing(handle)) { + return; + } + + switch (handle->type) { + case UV_UDP: + case UV_TCP: + break; + default: + return; + } + + isc__nmsocket_shutdown(sock); +} + void isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0) { UNUSED(ev0); diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index ad80a4b76f..e4d7182999 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -63,9 +63,6 @@ tcp_connect_cb(uv_connect_t *uvreq, int status); static void tcp_connection_cb(uv_stream_t *server, int status); -static void -read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); - static void tcp_close_cb(uv_handle_t *uvhandle); @@ -86,25 +83,6 @@ stop_tcp_parent(isc_nmsocket_t *sock); static void stop_tcp_child(isc_nmsocket_t *sock); -static void -start_reading(isc_nmsocket_t *sock); - -static void -stop_reading(isc_nmsocket_t *sock); - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock); - -static void -tcp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf); - -static bool -inactive(isc_nmsocket_t *sock) { - return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || - (sock->server != NULL && !isc__nmsocket_active(sock->server))); -} - static void failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { REQUIRE(sock->accepting); @@ -135,23 +113,6 @@ failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { } } -static void -failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); - REQUIRE(req->cb.connect != NULL); - - atomic_store(&sock->connecting, false); - - isc__nmsocket_clearcb(sock); - isc__nm_connectcb(sock, req, eresult); - - isc__nmsocket_prep_destroy(sock); -} - static isc_result_t tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; @@ -164,21 +125,20 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { REQUIRE(isc__nm_in_netthread()); REQUIRE(sock->tid == isc_nm_tid()); - result = isc__nm_socket_connectiontimeout(sock->fd, - sock->connect_timeout); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - worker = &sock->mgr->workers[sock->tid]; atomic_store(&sock->connecting, true); + /* 2 minute timeout */ + result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp); RUNTIME_CHECK(r == 0); uv_handle_set_data(&sock->uv_handle.handle, sock); r = uv_timer_init(&worker->loop, &sock->timer); RUNTIME_CHECK(r == 0); - uv_handle_set_data((uv_handle_t *)&sock->timer, sock); r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd); if (r != 0) { @@ -207,11 +167,13 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { } isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]); + uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect); + isc__nmsocket_timer_start(sock); + atomic_store(&sock->connected, true); done: result = isc__nm_uverr2result(r); - LOCK(&sock->lock); sock->result = result; SIGNAL(&sock->cond); @@ -246,7 +208,7 @@ isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { if (sock->fd != (uv_os_sock_t)(-1)) { isc__nm_tcp_close(sock); } - isc__nm_uvreq_put(&req, sock); + isc__nm_connectcb(sock, req, result, true); } /* @@ -265,20 +227,35 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); + + isc__nmsocket_timer_stop(sock); + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + + if (!atomic_load(&sock->connecting)) { + return; + } req = uv_handle_get_data((uv_handle_t *)uvreq); REQUIRE(VALID_UVREQ(req)); REQUIRE(VALID_NMHANDLE(req->handle)); - /* Socket was closed midflight by isc__nm_tcp_shutdown() */ - if (!isc__nmsocket_active(sock)) { + if (!atomic_load(&sock->connecting)) { + /* + * The connect was cancelled from timeout; just clean up + * the req. + */ + isc__nm_uvreq_put(&req, sock); + return; + } else if (isc__nmsocket_closing(sock)) { + /* Socket was closed midflight by isc__nm_tcp_shutdown() */ result = ISC_R_CANCELED; goto error; - } - - if (status != 0) { + } else if (status == UV_ETIMEDOUT) { + /* Timeout status code here indicates hard error */ + result = ISC_R_TIMEDOUT; + goto error; + } else if (status != 0) { result = isc__nm_uverr2result(status); goto error; } @@ -296,15 +273,15 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) { result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc__nm_connectcb(sock, req, ISC_R_SUCCESS); + isc__nm_connectcb(sock, req, ISC_R_SUCCESS, false); return; error: - failed_connect_cb(sock, req, result); + isc__nm_failed_connect_cb(sock, req, result, false); } -isc_result_t +void isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize) { @@ -313,7 +290,6 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc__netievent_tcpconnect_t *ievent = NULL; isc__nm_uvreq_t *req = NULL; sa_family_t sa_family; - uv_os_sock_t fd; REQUIRE(VALID_NM(mgr)); REQUIRE(local != NULL); @@ -321,22 +297,13 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sa_family = peer->addr.type.sa.sa_family; - /* - * The socket() call can fail spuriously on FreeBSD 12, so we need to - * handle the failure early and gracefully. - */ - result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd); - if (result != ISC_R_SUCCESS) { - return (result); - } - sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_tcpsocket, local); sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; sock->result = ISC_R_DEFAULT; - sock->fd = fd; + sock->fd = (uv_os_sock_t)-1; atomic_init(&sock->client, true); req = isc__nm_uvreq_get(mgr, sock); @@ -346,6 +313,18 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, req->local = local->addr; req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr); + result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd); + if (result != ISC_R_SUCCESS) { + if (isc__nm_in_netthread()) { + sock->tid = isc_nm_tid(); + } + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, false); + atomic_store(&sock->closed, true); + isc__nmsocket_detach(&sock); + return; + } + ievent = isc__nm_get_netievent_tcpconnect(mgr, sock, req); if (isc__nm_in_netthread()) { @@ -361,17 +340,12 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (isc__netievent_t *)ievent); } LOCK(&sock->lock); - result = sock->result; - while (result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_DEFAULT) { WAIT(&sock->cond, &sock->lock); - result = sock->result; } atomic_store(&sock->active, true); BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); - - return (result); } static uv_os_sock_t @@ -613,7 +587,7 @@ tcp_connection_cb(uv_stream_t *server, int status) { REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (inactive(ssock)) { + if (isc__nmsocket_closing(ssock)) { result = ISC_R_CANCELED; goto done; } @@ -693,7 +667,8 @@ failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->statichandle != NULL); - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); if (!sock->recv_read) { goto destroy; @@ -701,7 +676,7 @@ failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { sock->recv_read = false; if (sock->recv_cb != NULL) { - isc__nm_uvreq_t *req = get_read_req(sock); + isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nmsocket_clearcb(sock); isc__nm_readcb(sock, req, result); } @@ -734,42 +709,6 @@ failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, } } -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock) { - isc__nm_uvreq_t *req = NULL; - - req = isc__nm_uvreq_get(sock->mgr, sock); - req->cb.recv = sock->recv_cb; - req->cbarg = sock->recv_cbarg; - isc_nmhandle_attach(sock->statichandle, &req->handle); - - return req; -} - -static void -start_reading(isc_nmsocket_t *sock) { - if (sock->reading) { - return; - } - - int r = uv_read_start(&sock->uv_handle.stream, tcp_alloc_cb, read_cb); - REQUIRE(r == 0); - sock->reading = true; -} - -static void -stop_reading(isc_nmsocket_t *sock) { - if (!sock->reading) { - return; - } - - int r = uv_read_stop(&sock->uv_handle.stream); - REQUIRE(r == 0); - sock->reading = false; - - isc__nmsocket_timer_stop(sock); -} - void isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(VALID_NMHANDLE(handle)); @@ -807,32 +746,6 @@ isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { return; } -/*%< - * Allocator for TCP read operations. Limited to size 2^16. - * - * Note this doesn't actually allocate anything, it just assigns the - * worker's receive buffer to a socket, and marks it as "in use". - */ -static void -tcp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - isc__networker_t *worker = NULL; - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->type == isc_nm_tcpsocket); - REQUIRE(isc__nm_in_netthread()); - if (size > 65536) { - size = 65536; - } - - worker = &sock->mgr->workers[sock->tid]; - INSIST(!worker->recvbuf_inuse); - - buf->base = worker->recvbuf; - buf->len = size; - worker->recvbuf_inuse = true; -} - void isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_tcpstartread_t *ievent = @@ -843,13 +756,13 @@ isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); UNUSED(worker); - if (inactive(sock)) { + if (isc__nmsocket_closing(sock)) { sock->reading = true; failed_read_cb(sock, ISC_R_CANCELED); return; } - start_reading(sock); + isc__nm_start_reading(sock); isc__nmsocket_timer_start(sock); } @@ -886,7 +799,8 @@ isc__nm_async_tcppauseread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); UNUSED(worker); - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); } void @@ -921,8 +835,8 @@ isc__nm_tcp_resumeread(isc_nmhandle_t *handle) { (isc__netievent_t *)ievent); } -static void -read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { +void +isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream); isc__nm_uvreq_t *req = NULL; @@ -931,7 +845,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { REQUIRE(sock->reading); REQUIRE(buf != NULL); - if (inactive(sock)) { + if (isc__nmsocket_closing(sock)) { failed_read_cb(sock, ISC_R_CANCELED); goto free; } @@ -947,7 +861,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { goto free; } - req = get_read_req(sock); + req = isc__nm_get_read_req(sock, NULL); /* * The callback will be called synchronously because the @@ -1030,7 +944,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (inactive(ssock)) { + if (isc__nmsocket_closing(ssock)) { if (quota != NULL) { isc_quota_detach("a); } @@ -1160,11 +1074,11 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region, static void tcp_send_cb(uv_write_t *req, int status) { isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data; - isc_nmsocket_t *sock = uvreq->sock; - REQUIRE(VALID_UVREQ(uvreq)); REQUIRE(VALID_NMHANDLE(uvreq->handle)); + isc_nmsocket_t *sock = uvreq->sock; + if (status < 0) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); failed_send_cb(sock, uvreq, isc__nm_uverr2result(status)); @@ -1204,7 +1118,7 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { int r; - if (inactive(sock)) { + if (isc__nmsocket_closing(sock)) { return (ISC_R_CANCELED); } @@ -1240,10 +1154,7 @@ tcp_stop_cb(uv_handle_t *handle) { } static void -tcp_close_cb(uv_handle_t *handle) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - uv_handle_set_data(handle, NULL); - +tcp_close_sock(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(atomic_load(&sock->closing)); @@ -1265,6 +1176,14 @@ tcp_close_cb(uv_handle_t *handle) { isc__nmsocket_prep_destroy(sock); } +static void +tcp_close_cb(uv_handle_t *handle) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + uv_handle_set_data(handle, NULL); + + tcp_close_sock(sock); +} + static void timer_close_cb(uv_handle_t *handle) { isc_nmsocket_t *sock = uv_handle_get_data(handle); @@ -1272,6 +1191,8 @@ timer_close_cb(uv_handle_t *handle) { if (sock->parent) { uv_close(&sock->uv_handle.handle, tcp_stop_cb); + } else if (uv_is_closing(&sock->uv_handle.handle)) { + tcp_close_sock(sock); } else { uv_close(&sock->uv_handle.handle, tcp_close_cb); } @@ -1347,7 +1268,10 @@ tcp_close_direct(isc_nmsocket_t *sock) { isc_quota_detach(&sock->quota); } - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); + + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); uv_close((uv_handle_t *)&sock->timer, timer_close_cb); } @@ -1389,6 +1313,19 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0) { tcp_close_direct(sock); } +static void +tcp_close_connect_cb(uv_handle_t *handle) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + + REQUIRE(VALID_NMSOCK(sock)); + + REQUIRE(isc__nm_in_netthread()); + REQUIRE(sock->tid == isc_nm_tid()); + + isc__nmsocket_prep_destroy(sock); + isc__nmsocket_detach(&sock); +} + void isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); @@ -1403,11 +1340,18 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { return; } - if (atomic_load(&sock->connecting) || sock->accepting) { + if (sock->accepting) { return; } - if (sock->statichandle) { + if (atomic_load(&sock->connecting)) { + isc_nmsocket_t *tsock = NULL; + isc__nmsocket_attach(sock, &tsock); + uv_close(&sock->uv_handle.handle, tcp_close_connect_cb); + return; + } + + if (sock->statichandle != NULL) { failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -1459,5 +1403,5 @@ isc__nm_tcp_listener_nactive(isc_nmsocket_t *listener) { nactive = atomic_load(&listener->active_child_connections); INSIST(nactive >= 0); - return nactive; + return (nactive); } diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index 276e5e8c6c..7b2efa419e 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -104,7 +104,11 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { r = uv_timer_init(&worker->loop, &sock->timer); RUNTIME_CHECK(r == 0); - uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + + if (isc__nm_closing(sock)) { + result = ISC_R_CANCELED; + goto error; + } r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd); if (r != 0) { @@ -137,11 +141,14 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { } isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]); + uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect); + isc__nmsocket_timer_start(sock); + atomic_store(&sock->connected, true); done: result = isc__nm_uverr2result(r); - +error: LOCK(&sock->lock); sock->result = result; SIGNAL(&sock->cond); @@ -172,9 +179,10 @@ isc__nm_async_tcpdnsconnect(isc__networker_t *worker, isc__netievent_t *ev0) { result = tcpdns_connect_direct(sock, req); if (result != ISC_R_SUCCESS) { + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, true); atomic_store(&sock->active, false); isc__nm_tcpdns_close(sock); - isc__nm_uvreq_put(&req, sock); } /* @@ -193,20 +201,28 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); + + isc__nmsocket_timer_stop(sock); + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + + if (!atomic_load(&sock->connecting)) { + return; + } req = uv_handle_get_data((uv_handle_t *)uvreq); REQUIRE(VALID_UVREQ(req)); REQUIRE(VALID_NMHANDLE(req->handle)); - /* Socket was closed midflight by isc__nm_tcpdns_shutdown() */ - if (!isc__nmsocket_active(sock)) { + if (isc__nmsocket_closing(sock)) { + /* Socket was closed midflight by isc__nm_tcpdns_shutdown() */ result = ISC_R_CANCELED; goto error; - } - - if (status != 0) { + } else if (status == UV_ETIMEDOUT) { + /* Timeout status code here indicates hard error */ + result = ISC_R_CANCELED; + goto error; + } else if (status != 0) { result = isc__nm_uverr2result(status); goto error; } @@ -224,15 +240,15 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) { result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc__nm_connectcb(sock, req, ISC_R_SUCCESS); + isc__nm_connectcb(sock, req, ISC_R_SUCCESS, false); return; error: - isc__nm_failed_connect_cb(sock, req, result); + isc__nm_failed_connect_cb(sock, req, result, false); } -isc_result_t +void isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize) { @@ -241,7 +257,6 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc__netievent_tcpdnsconnect_t *ievent = NULL; isc__nm_uvreq_t *req = NULL; sa_family_t sa_family; - uv_os_sock_t fd; REQUIRE(VALID_NM(mgr)); REQUIRE(local != NULL); @@ -249,27 +264,14 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sa_family = peer->addr.type.sa.sa_family; - /* - * The socket() call can fail spuriously on FreeBSD 12, so we need to - * handle the failure early and gracefully. - */ - result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd); - if (result != ISC_R_SUCCESS) { - return (result); - } - sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_tcpdnssocket, local); sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; sock->result = ISC_R_DEFAULT; - sock->fd = fd; atomic_init(&sock->client, true); - result = isc__nm_socket_connectiontimeout(fd, timeout); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - req = isc__nm_uvreq_get(mgr, sock); req->cb.connect = cb; req->cbarg = cbarg; @@ -277,6 +279,22 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, req->local = local->addr; req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr); + result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd); + if (result != ISC_R_SUCCESS) { + if (isc__nm_in_netthread()) { + sock->tid = isc_nm_tid(); + } + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, true); + atomic_store(&sock->closed, true); + isc__nmsocket_detach(&sock); + return; + } + + /* 2 minute timeout */ + result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ievent = isc__nm_get_netievent_tcpdnsconnect(mgr, sock, req); if (isc__nm_in_netthread()) { @@ -291,18 +309,14 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc__nm_enqueue_ievent(&mgr->workers[sock->tid], (isc__netievent_t *)ievent); } + LOCK(&sock->lock); - result = sock->result; - while (result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_DEFAULT) { WAIT(&sock->cond, &sock->lock); - result = sock->result; } atomic_store(&sock->active, true); BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); - - return (result); } static uv_os_sock_t @@ -546,7 +560,7 @@ tcpdns_connection_cb(uv_stream_t *server, int status) { REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (isc__nm_inactive(ssock)) { + if (isc__nmsocket_closing(ssock)) { result = ISC_R_CANCELED; goto done; } @@ -700,9 +714,9 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { sock->reading = true; - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -727,7 +741,7 @@ isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { return (ISC_R_CANCELED); } @@ -804,8 +818,8 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, REQUIRE(sock->reading); REQUIRE(buf != NULL); - if (isc__nm_inactive(sock)) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + if (isc__nmsocket_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, true); goto free; } @@ -815,7 +829,7 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, sock->statsindex[STATID_RECVFAIL]); } - isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread)); + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread), true); goto free; } @@ -903,7 +917,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (isc__nm_inactive(ssock)) { + if (isc__nmsocket_closing(ssock)) { if (quota != NULL) { isc_quota_detach("a); } @@ -1097,7 +1111,7 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) { UNUSED(worker); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { result = ISC_R_CANCELED; goto fail; } @@ -1167,11 +1181,7 @@ tcpdns_stop_cb(uv_handle_t *handle) { } static void -tcpdns_close_cb(uv_handle_t *handle) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - - uv_handle_set_data(handle, NULL); - +tcpdns_close_sock(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(atomic_load(&sock->closing)); @@ -1194,12 +1204,25 @@ tcpdns_close_cb(uv_handle_t *handle) { } static void -timer_close_cb(uv_handle_t *handle) { +tcpdns_close_cb(uv_handle_t *handle) { isc_nmsocket_t *sock = uv_handle_get_data(handle); + uv_handle_set_data(handle, NULL); + tcpdns_close_sock(sock); +} + +static void +timer_close_cb(uv_handle_t *timer) { + isc_nmsocket_t *sock = uv_handle_get_data(timer); + uv_handle_set_data(timer, NULL); + + REQUIRE(VALID_NMSOCK(sock)); + if (sock->parent) { uv_close(&sock->uv_handle.handle, tcpdns_stop_cb); + } else if (uv_is_closing(&sock->uv_handle.handle)) { + tcpdns_close_sock(sock); } else { uv_close(&sock->uv_handle.handle, tcpdns_close_cb); } @@ -1271,6 +1294,8 @@ tcpdns_close_direct(isc_nmsocket_t *sock) { isc__nmsocket_timer_stop(sock); isc__nm_stop_reading(sock); + + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); uv_close((uv_handle_t *)&sock->timer, timer_close_cb); } @@ -1313,6 +1338,19 @@ isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) { tcpdns_close_direct(sock); } +static void +tcpdns_close_connect_cb(uv_handle_t *handle) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + + REQUIRE(VALID_NMSOCK(sock)); + + REQUIRE(isc__nm_in_netthread()); + REQUIRE(sock->tid == isc_nm_tid()); + + isc__nmsocket_prep_destroy(sock); + isc__nmsocket_detach(&sock); +} + void isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); @@ -1327,12 +1365,19 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) { return; } - if (atomic_load(&sock->connecting) || sock->accepting) { + if (sock->accepting) { return; } - if (sock->statichandle) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + if (atomic_load(&sock->connecting)) { + isc_nmsocket_t *tsock = NULL; + isc__nmsocket_attach(sock, &tsock); + uv_close(&sock->uv_handle.handle, tcpdns_close_connect_cb); + return; + } + + if (sock->statichandle != NULL) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -1372,7 +1417,7 @@ isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - isc__nm_failed_read_cb(sock, ISC_R_EOF); + isc__nm_failed_read_cb(sock, ISC_R_EOF, false); } void diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index db75b30d1c..7b80dcc43a 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -110,6 +110,10 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { atomic_store(&sock->connecting, true); + /* 2 minute timeout */ + result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp); RUNTIME_CHECK(r == 0); uv_handle_set_data(&sock->uv_handle.handle, sock); @@ -118,6 +122,11 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { RUNTIME_CHECK(r == 0); uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + if (isc__nm_closing(sock)) { + result = ISC_R_CANCELED; + goto error; + } + r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd); if (r != 0) { isc__nm_closesocket(sock->fd); @@ -149,11 +158,14 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { } isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]); + uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect); + isc__nmsocket_timer_start(sock); + atomic_store(&sock->connected, true); done: result = isc__nm_uverr2result(r); - +error: LOCK(&sock->lock); sock->result = result; SIGNAL(&sock->cond); @@ -184,9 +196,12 @@ isc__nm_async_tlsdnsconnect(isc__networker_t *worker, isc__netievent_t *ev0) { result = tlsdns_connect_direct(sock, req); if (result != ISC_R_SUCCESS) { + INSIST(atomic_compare_exchange_strong(&sock->connecting, + &(bool){ true }, false)); + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, true); atomic_store(&sock->active, false); isc__nm_tlsdns_close(sock); - isc__nm_uvreq_put(&req, sock); } /* @@ -205,20 +220,25 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); + + if (!atomic_load(&sock->connecting)) { + return; + } req = uv_handle_get_data((uv_handle_t *)uvreq); REQUIRE(VALID_UVREQ(req)); REQUIRE(VALID_NMHANDLE(req->handle)); - /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ - if (!isc__nmsocket_active(sock)) { + if (isc__nmsocket_closing(sock)) { + /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ result = ISC_R_CANCELED; goto error; - } - - if (status != 0) { + } else if (status == UV_ETIMEDOUT) { + /* Timeout status code here indicates hard error */ + result = ISC_R_CANCELED; + goto error; + } else if (status != 0) { result = isc__nm_uverr2result(status); goto error; } @@ -248,10 +268,11 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) { #if HAVE_SSL_SET0_RBIO && HAVE_SSL_SET0_WBIO /* - * Note that if the rbio and wbio are the same then SSL_set0_rbio() and - * SSL_set0_wbio() each take ownership of one reference. Therefore it - * may be necessary to increment the number of references available - * using BIO_up_ref(3) before calling the set0 functions. + * Note that if the rbio and wbio are the same then + * SSL_set0_rbio() and SSL_set0_wbio() each take ownership of + * one reference. Therefore it may be necessary to increment the + * number of references available using BIO_up_ref(3) before + * calling the set0 functions. */ SSL_set0_rbio(sock->tls.tls, sock->tls.ssl_rbio); SSL_set0_wbio(sock->tls.tls, sock->tls.ssl_wbio); @@ -264,23 +285,24 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) { result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss); RUNTIME_CHECK(result == ISC_R_SUCCESS); + /* Setting pending req */ sock->tls.pending_req = req; isc__nm_process_sock_buffer(sock); result = tls_cycle(sock); if (result != ISC_R_SUCCESS) { + sock->tls.pending_req = NULL; goto error; } return; error: - sock->tls.pending_req = NULL; - isc__nm_failed_connect_cb(sock, req, result); + isc__nm_failed_connect_cb(sock, req, result, false); } -isc_result_t +void isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize, isc_tlsctx_t *sslctx) { @@ -289,7 +311,6 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc__netievent_tlsdnsconnect_t *ievent = NULL; isc__nm_uvreq_t *req = NULL; sa_family_t sa_family; - uv_os_sock_t fd; REQUIRE(VALID_NM(mgr)); REQUIRE(local != NULL); @@ -298,28 +319,15 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sa_family = peer->addr.type.sa.sa_family; - /* - * The socket() call can fail spuriously on FreeBSD 12, so we need to - * handle the failure early and gracefully. - */ - result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd); - if (result != ISC_R_SUCCESS) { - return (result); - } - sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_tlsdnssocket, local); sock->extrahandlesize = extrahandlesize; sock->connect_timeout = timeout; sock->result = ISC_R_DEFAULT; - sock->fd = fd; sock->tls.ctx = sslctx; - atomic_init(&sock->client, true); - - result = isc__nm_socket_connectiontimeout(fd, timeout); - RUNTIME_CHECK(result == ISC_R_SUCCESS); + atomic_init(&sock->connecting, true); req = isc__nm_uvreq_get(mgr, sock); req->cb.connect = cb; @@ -328,6 +336,19 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, req->local = local->addr; req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr); + result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd); + if (result != ISC_R_SUCCESS) { + goto failure; + } + + if (isc__nm_closing(sock)) { + goto failure; + } + + /* 2 minute timeout */ + result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ievent = isc__nm_get_netievent_tlsdnsconnect(mgr, sock, req); if (isc__nm_in_netthread()) { @@ -343,17 +364,24 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (isc__netievent_t *)ievent); } LOCK(&sock->lock); - result = sock->result; - while (result == ISC_R_DEFAULT) { + while (sock->result == ISC_R_DEFAULT) { WAIT(&sock->cond, &sock->lock); - result = sock->result; } atomic_store(&sock->active, true); BROADCAST(&sock->scond); UNLOCK(&sock->lock); - INSIST(result != ISC_R_DEFAULT); + return; +failure: + if (isc__nm_in_netthread()) { + sock->tid = isc_nm_tid(); + } - return (result); + INSIST(atomic_compare_exchange_strong(&sock->connecting, + &(bool){ true }, false)); + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, true); + atomic_store(&sock->closed, true); + isc__nmsocket_detach(&sock); } static uv_os_sock_t @@ -552,8 +580,9 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) { #endif /* - * The callback will run in the same thread uv_listen() was called - * from, so a race with tlsdns_connection_cb() isn't possible. + * The callback will run in the same thread uv_listen() was + * called from, so a race with tlsdns_connection_cb() isn't + * possible. */ r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog, tlsdns_connection_cb); @@ -600,7 +629,7 @@ tlsdns_connection_cb(uv_stream_t *server, int status) { REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (isc__nm_inactive(ssock)) { + if (isc__nmsocket_closing(ssock)) { result = ISC_R_CANCELED; goto done; } @@ -742,7 +771,8 @@ isc__nm_async_tlsdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) { } /* - * If network manager is interlocked, re-enqueue the event for later. + * If network manager is interlocked, re-enqueue the event for + * later. */ if (!isc__nm_acquire_interlocked(sock->mgr)) { enqueue_stoplistening(sock); @@ -753,7 +783,8 @@ isc__nm_async_tlsdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) { } void -isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { +isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, + bool async) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(result != ISC_R_SUCCESS); @@ -763,7 +794,7 @@ isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { if (sock->tls.pending_req != NULL) { isc__nm_uvreq_t *req = sock->tls.pending_req; sock->tls.pending_req = NULL; - isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED); + isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED, async); } if (!sock->recv_read) { @@ -780,8 +811,8 @@ isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { destroy: isc__nmsocket_prep_destroy(sock); - /* We need to detach from quota after the read callback function had a - * chance to be executed. */ + /* We need to detach from quota after the read callback function + * had a chance to be executed. */ if (sock->quota) { isc_quota_detach(&sock->quota); } @@ -813,10 +844,11 @@ isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { ievent = isc__nm_get_netievent_tlsdnsread(sock->mgr, sock); /* - * This MUST be done asynchronously, no matter which thread we're - * in. The callback function for isc_nm_read() often calls + * This MUST be done asynchronously, no matter which thread + * we're in. The callback function for isc_nm_read() often calls * isc_nm_read() again; if we tried to do that synchronously - * we'd clash in processbuffer() and grow the stack indefinitely. + * we'd clash in processbuffer() and grow the stack + * indefinitely. */ isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], (isc__netievent_t *)ievent); @@ -836,15 +868,15 @@ isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { sock->reading = true; - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } result = tls_cycle(sock); if (result != ISC_R_SUCCESS) { - isc__nm_failed_read_cb(sock, result); + isc__nm_failed_read_cb(sock, result, false); } } @@ -866,7 +898,7 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { return (ISC_R_CANCELED); } @@ -892,7 +924,8 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { /* * We need to launch the resume_processing after the buffer has - * been consumed, thus we need to delay the detaching the handle. + * been consumed, thus we need to delay the detaching the + * handle. */ isc_nmhandle_attach(req->handle, &handle); @@ -905,15 +938,16 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { req->uvbuf.len = len; /* - * If isc__nm_tlsdns_read() was called, it will be satisfied by single - * DNS message in the next call. + * If isc__nm_tlsdns_read() was called, it will be satisfied by + * single DNS message in the next call. */ sock->recv_read = false; /* - * The assertion failure here means that there's a errnoneous extra - * nmhandle detach happening in the callback and resume_processing gets - * called while we are still processing the buffer. + * The assertion failure here means that there's a errnoneous + * extra nmhandle detach happening in the callback and + * resume_processing gets called while we are still processing + * the buffer. */ REQUIRE(sock->processing == false); sock->processing = true; @@ -958,14 +992,19 @@ tls_cycle_input(isc_nmsocket_t *sock) { sock->buf + sock->buf_len, sock->buf_size - sock->buf_len, &len); if (rv != 1) { - /* Process what's in the buffer so far */ + /* + * Process what's in the buffer so far + */ isc__nm_process_sock_buffer(sock); - /* FIXME: Should we call failed_read_cb()? */ + /* + * FIXME: Should we call + * isc__nm_failed_read_cb()? + */ break; } - REQUIRE((size_t)pending == len); + INSIST((size_t)pending == len); sock->buf_len += len; @@ -1030,9 +1069,12 @@ tls_cycle_input(isc_nmsocket_t *sock) { isc__nm_uvreq_t *req = sock->tls.pending_req; sock->tls.pending_req = NULL; - atomic_store(&sock->connecting, false); + isc__nmsocket_timer_stop(sock); + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); - isc__nm_connectcb(sock, req, ISC_R_SUCCESS); + INSIST(atomic_compare_exchange_strong( + &sock->connecting, &(bool){ true }, false)); + isc__nm_connectcb(sock, req, ISC_R_SUCCESS, true); } async_tlsdns_cycle(sock); } @@ -1045,7 +1087,14 @@ tls_error(isc_nmsocket_t *sock, isc_result_t result) { switch (sock->tls.state) { case TLS_STATE_HANDSHAKE: case TLS_STATE_IO: - isc__nm_tlsdns_failed_read_cb(sock, result); + if (atomic_load(&sock->connecting)) { + isc__nm_uvreq_t *req = sock->tls.pending_req; + sock->tls.pending_req = NULL; + + isc__nm_failed_connect_cb(sock, req, result, false); + } else { + isc__nm_tlsdns_failed_read_cb(sock, result, false); + } break; case TLS_STATE_ERROR: return; @@ -1056,7 +1105,7 @@ tls_error(isc_nmsocket_t *sock, isc_result_t result) { sock->tls.state = TLS_STATE_ERROR; sock->tls.pending_error = result; - /* tlsdns_close_direct(sock); */ + isc__nmsocket_shutdown(sock); } static void @@ -1141,7 +1190,8 @@ tls_cycle_output(isc_nmsocket_t *sock) { req->uvbuf.len - err); req->uvbuf.len = req->uvbuf.len - err; } else if (err == UV_ENOSYS || err == UV_EAGAIN) { - /* uv_try_write is not supported, send asynchronously */ + /* uv_try_write is not supported, send + * asynchronously */ } else { result = isc__nm_uverr2result(err); isc__nm_uvreq_put(&req, sock); @@ -1182,6 +1232,10 @@ static isc_result_t tls_cycle(isc_nmsocket_t *sock) { isc_result_t result; + if (isc__nmsocket_closing(sock)) { + return (ISC_R_CANCELED); + } + result = tls_pop_error(sock); if (result != ISC_R_SUCCESS) { goto done; @@ -1212,7 +1266,7 @@ async_tlsdns_cycle(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ - if (!isc__nmsocket_active(sock)) { + if (isc__nmsocket_closing(sock)) { return; } @@ -1255,8 +1309,8 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, REQUIRE(sock->reading); REQUIRE(buf != NULL); - if (isc__nm_inactive(sock)) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + if (isc__nmsocket_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, true); goto free; } @@ -1266,7 +1320,7 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, sock->statsindex[STATID_RECVFAIL]); } - isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread)); + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread), true); goto free; } @@ -1281,13 +1335,13 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, rv = BIO_write_ex(sock->tls.app_wbio, buf->base, (size_t)nread, &len); if (rv <= 0 || (size_t)nread != len) { - isc__nm_failed_read_cb(sock, ISC_R_TLSERROR); + isc__nm_failed_read_cb(sock, ISC_R_TLSERROR, true); goto free; } result = tls_cycle(sock); if (result != ISC_R_SUCCESS) { - isc__nm_failed_read_cb(sock, result); + isc__nm_failed_read_cb(sock, result, true); } free: async_tlsdns_cycle(sock); @@ -1301,7 +1355,8 @@ quota_accept_cb(isc_quota_t *quota, void *sock0) { REQUIRE(VALID_NMSOCK(sock)); /* - * Create a tlsdnsaccept event and pass it using the async channel. + * Create a tlsdnsaccept event and pass it using the async + * channel. */ isc__netievent_tlsdnsaccept_t *ievent = @@ -1351,7 +1406,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (isc__nm_inactive(ssock)) { + if (isc__nmsocket_closing(ssock)) { if (quota != NULL) { isc_quota_detach("a); } @@ -1418,8 +1473,8 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { } /* - * The handle will be either detached on acceptcb failure or in the - * readcb. + * The handle will be either detached on acceptcb failure or in + * the readcb. */ handle = isc__nmhandle_get(csock, NULL, &local); @@ -1444,10 +1499,11 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { #if HAVE_SSL_SET0_RBIO && HAVE_SSL_SET0_WBIO /* - * Note that if the rbio and wbio are the same then SSL_set0_rbio() and - * SSL_set0_wbio() each take ownership of one reference. Therefore it - * may be necessary to increment the number of references available - * using BIO_up_ref(3) before calling the set0 functions. + * Note that if the rbio and wbio are the same then + * SSL_set0_rbio() and SSL_set0_wbio() each take ownership of + * one reference. Therefore it may be necessary to increment the + * number of references available using BIO_up_ref(3) before + * calling the set0 functions. */ SSL_set0_rbio(csock->tls.tls, csock->tls.ssl_rbio); SSL_set0_wbio(csock->tls.tls, csock->tls.ssl_wbio); @@ -1468,15 +1524,15 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->closehandle_cb = isc__nm_resume_processing; /* - * We need to keep the handle alive until we fail to read or connection - * is closed by the other side, it will be detached via - * prep_destroy()->tlsdns_close_direct(). + * We need to keep the handle alive until we fail to read or + * connection is closed by the other side, it will be detached + * via prep_destroy()->tlsdns_close_direct(). */ isc_nmhandle_attach(handle, &csock->recv_handle); /* - * The initial timer has been set, update the read timeout for the next - * reads. + * The initial timer has been set, update the read timeout for + * the next reads. */ csock->read_timeout = (atomic_load(&csock->keepalive) ? atomic_load(&csock->mgr->keepalive) @@ -1583,7 +1639,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { return (result); } - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { return (ISC_R_CANCELED); } @@ -1593,8 +1649,8 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { } /* - * There's no SSL_writev(), so we need to use a local buffer to assemble - * the whole message + * There's no SSL_writev(), so we need to use a local buffer to + * assemble the whole message */ worker = &sock->mgr->workers[sock->tid]; sendlen = req->uvbuf.len + sizeof(uint16_t); @@ -1664,10 +1720,7 @@ tlsdns_stop_cb(uv_handle_t *handle) { } static void -tlsdns_close_cb(uv_handle_t *handle) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - uv_handle_set_data(handle, NULL); - +tlsdns_close_sock(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(atomic_load(&sock->closing)); @@ -1698,14 +1751,25 @@ tlsdns_close_cb(uv_handle_t *handle) { isc__nmsocket_prep_destroy(sock); } +static void +tlsdns_close_cb(uv_handle_t *handle) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + uv_handle_set_data(handle, NULL); + + tlsdns_close_sock(sock); +} + static void timer_close_cb(uv_handle_t *handle) { isc_nmsocket_t *sock = uv_handle_get_data(handle); - uv_handle_set_data(handle, NULL); + REQUIRE(VALID_NMSOCK(sock)); + if (sock->parent) { uv_close(&sock->uv_handle.handle, tlsdns_stop_cb); + } else if (uv_is_closing(&sock->uv_handle.handle)) { + tlsdns_close_sock(sock); } else { uv_close(&sock->uv_handle.handle, tlsdns_close_cb); } @@ -1780,6 +1844,8 @@ tlsdns_close_direct(isc_nmsocket_t *sock) { isc__nmsocket_timer_stop(sock); isc__nm_stop_reading(sock); + + uv_handle_set_data((uv_handle_t *)&sock->timer, sock); uv_close((uv_handle_t *)&sock->timer, timer_close_cb); } @@ -1798,7 +1864,8 @@ isc__nm_tlsdns_close(isc_nmsocket_t *sock) { tlsdns_close_direct(sock); } else { /* - * We need to create an event and pass it using async channel + * We need to create an event and pass it using async + * channel */ isc__netievent_tlsdnsclose_t *ievent = isc__nm_get_netievent_tlsdnsclose(sock->mgr, sock); @@ -1822,6 +1889,19 @@ isc__nm_async_tlsdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) { tlsdns_close_direct(sock); } +static void +tlsdns_close_connect_cb(uv_handle_t *handle) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + + REQUIRE(VALID_NMSOCK(sock)); + + REQUIRE(isc__nm_in_netthread()); + REQUIRE(sock->tid == isc_nm_tid()); + + isc__nmsocket_prep_destroy(sock); + isc__nmsocket_detach(&sock); +} + void isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); @@ -1836,18 +1916,39 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) { return; } - if (sock->tls.pending_req != NULL) { - isc__nm_uvreq_t *req = sock->tls.pending_req; - sock->tls.pending_req = NULL; - isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED); + if (sock->tls.tls) { + /* Shutdown any active TLS connections */ + (void)SSL_shutdown(sock->tls.tls); } - if (atomic_load(&sock->connecting) || sock->accepting) { + if (sock->accepting) { return; } - if (sock->statichandle) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + /* TLS handshake hasn't been completed yet */ + if (atomic_load(&sock->connecting)) { + /* + * TCP connection has been established, now waiting on + * TLS handshake to complete + */ + if (sock->tls.pending_req != NULL) { + isc__nm_uvreq_t *req = sock->tls.pending_req; + sock->tls.pending_req = NULL; + + isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED, + false); + return; + } + + /* The TCP connection hasn't been established yet */ + isc_nmsocket_t *tsock = NULL; + isc__nmsocket_attach(sock, &tsock); + uv_close(&sock->uv_handle.handle, tlsdns_close_connect_cb); + return; + } + + if (sock->statichandle != NULL) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -1887,7 +1988,7 @@ isc__nm_async_tlsdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - isc__nm_failed_read_cb(sock, ISC_R_EOF); + isc__nm_failed_read_cb(sock, ISC_R_EOF, false); } void diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index bf9c5f9ce5..27a6bfcadb 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -835,13 +835,12 @@ isc__nm_tls_stoplistening(isc_nmsocket_t *sock) { } } -isc_result_t +void isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx, unsigned int timeout, size_t extrahandlesize) { isc_nmsocket_t *nsock = NULL, *tsock = NULL; isc__netievent_tlsconnect_t *ievent = NULL; - isc_result_t result = ISC_R_DEFAULT; #if defined(NETMGR_TRACE) && defined(NETMGR_TRACE_VERBOSE) fprintf(stderr, "TLS: isc_nm_tlsconnect(): in net thread: %s\n", isc__nm_in_netthread() ? "yes" : "no"); @@ -880,20 +879,14 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, } LOCK(&nsock->lock); - result = nsock->result; - while (result == ISC_R_DEFAULT) { + while (nsock->result == ISC_R_DEFAULT) { WAIT(&nsock->cond, &nsock->lock); - result = nsock->result; } atomic_store(&nsock->active, true); BROADCAST(&nsock->scond); UNLOCK(&nsock->lock); INSIST(VALID_NMSOCK(nsock)); isc__nmsocket_detach(&tsock); - - INSIST(result != ISC_R_DEFAULT); - - return (result); } static void @@ -936,6 +929,11 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) { UNUSED(worker); + if (isc__nm_closing(tlssock)) { + result = ISC_R_CANCELED; + goto error; + } + /* * We need to initialize SSL now to reference SSL_CTX properly. */ @@ -948,20 +946,11 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) { tlssock->tid = isc_nm_tid(); tlssock->tlsstream.state = TLS_INIT; - result = isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local, - (isc_nmiface_t *)&ievent->peer, - tcp_connected, tlssock, - tlssock->connect_timeout, 0); + isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local, + (isc_nmiface_t *)&ievent->peer, tcp_connected, + tlssock, tlssock->connect_timeout, 0); - /* - * Sometimes on Linux, socket creation might fail if there are - * already too many socket descriptors. In such a case the - * connect callback is not going to be called. - */ - if (result != ISC_R_SUCCESS) { - goto error; - } - update_result(tlssock, result); + update_result(tlssock, ISC_R_SUCCESS); return; error: diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 869d7d301b..b7bbe6598e 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -383,7 +383,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, * we can free the buffer and bail. */ if (addr == NULL) { - isc__nm_failed_read_cb(sock, ISC_R_EOF); + isc__nm_failed_read_cb(sock, ISC_R_EOF, false); goto free; } @@ -391,12 +391,13 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, * - If the socket is no longer active. */ if (!isc__nmsocket_active(sock)) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); goto free; } if (nrecv < 0) { - isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv)); + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv), + false); goto free; } @@ -523,7 +524,7 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); UNUSED(worker); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { isc__nm_failed_send_cb(sock, uvreq, ISC_R_CANCELED); return; } @@ -567,7 +568,7 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->type == isc_nm_udpsocket); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { return (ISC_R_CANCELED); } @@ -597,6 +598,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()); @@ -616,7 +618,6 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { r = uv_udp_open(&sock->uv_handle.udp, sock->fd); if (r != 0) { - isc__nm_closesocket(sock->fd); isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]); goto done; } @@ -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]); @@ -693,13 +702,13 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { if (result != ISC_R_SUCCESS) { atomic_store(&sock->active, false); isc__nm_udp_close(sock); - isc__nm_uvreq_put(&req, sock); + isc__nm_connectcb(sock, req, result, true); } else { /* * The callback has to be called after the socket has been * initialized */ - isc__nm_connectcb(sock, req, ISC_R_SUCCESS); + isc__nm_connectcb(sock, req, ISC_R_SUCCESS, true); } /* @@ -708,7 +717,7 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { isc__nmsocket_detach(&sock); } -isc_result_t +void isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize) { @@ -717,7 +726,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc__netievent_udpconnect_t *event = NULL; isc__nm_uvreq_t *req = NULL; sa_family_t sa_family; - uv_os_sock_t fd; REQUIRE(VALID_NM(mgr)); REQUIRE(local != NULL); @@ -725,15 +733,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sa_family = peer->addr.type.sa.sa_family; - /* - * The socket() call can fail spuriously on FreeBSD 12, so we - * need to handle the failure early and gracefully. - */ - result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &fd); - if (result != ISC_R_SUCCESS) { - return (result); - } - sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t)); isc__nmsocket_init(sock, mgr, isc_nm_udpsocket, local); @@ -742,10 +741,27 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, sock->read_timeout = timeout; sock->extrahandlesize = extrahandlesize; sock->peer = peer->addr; - sock->fd = fd; sock->result = ISC_R_DEFAULT; atomic_init(&sock->client, true); + req = isc__nm_uvreq_get(mgr, sock); + req->cb.connect = cb; + req->cbarg = cbarg; + req->peer = peer->addr; + req->local = local->addr; + + result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &sock->fd); + if (result != ISC_R_SUCCESS) { + if (isc__nm_in_netthread()) { + sock->tid = isc_nm_tid(); + } + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, true); + atomic_store(&sock->closed, true); + isc__nmsocket_detach(&sock); + return; + } + result = isc__nm_socket_reuse(sock->fd); RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_NOTIMPLEMENTED); @@ -758,12 +774,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (void)isc__nm_socket_dontfrag(sock->fd, sa_family); - req = isc__nm_uvreq_get(mgr, sock); - req->cb.connect = cb; - req->cbarg = cbarg; - req->peer = peer->addr; - req->local = local->addr; - event = isc__nm_get_netievent_udpconnect(mgr, sock, req); if (isc__nm_in_netthread()) { @@ -779,17 +789,12 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, (isc__netievent_t *)event); } LOCK(&sock->lock); - result = sock->result; while (sock->result == ISC_R_DEFAULT) { WAIT(&sock->cond, &sock->lock); - result = sock->result; } atomic_store(&sock->active, true); BROADCAST(&sock->scond); UNLOCK(&sock->lock); - ENSURE(result != ISC_R_DEFAULT); - - return (result); } void @@ -868,9 +873,9 @@ isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nm_inactive(sock)) { + if (isc__nmsocket_closing(sock)) { sock->reading = true; - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -1084,8 +1089,8 @@ isc__nm_udp_shutdown(isc_nmsocket_t *sock) { * sock->statichandle would be NULL, in that case, nobody is * interested in the callback. */ - if (sock->statichandle) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED); + if (sock->statichandle != NULL) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -1129,5 +1134,5 @@ isc__nm_async_udpcancel(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(atomic_load(&sock->client)); - isc__nm_failed_read_cb(sock, ISC_R_EOF); + isc__nm_failed_read_cb(sock, ISC_R_EOF, false); } diff --git a/lib/isc/tests/doh_test.c b/lib/isc/tests/doh_test.c index 9c22c11a0f..d27b1f7b9b 100644 --- a/lib/isc/tests/doh_test.c +++ b/lib/isc/tests/doh_test.c @@ -55,7 +55,7 @@ static uint64_t stop_magic = 0; static uv_buf_t send_msg = { .base = (char *)&send_magic, .len = sizeof(send_magic) }; -static atomic_uint_fast64_t nsends; +static atomic_int_fast64_t nsends; static atomic_uint_fast64_t ssends; static atomic_uint_fast64_t sreads; @@ -71,6 +71,8 @@ static bool reuse_supported = true; static atomic_bool POST = ATOMIC_VAR_INIT(true); +static atomic_bool slowdown = ATOMIC_VAR_INIT(false); + static atomic_bool use_TLS = ATOMIC_VAR_INIT(false); static isc_tlsctx_t *server_tlsctx = NULL; static isc_tlsctx_t *client_tlsctx = NULL; @@ -117,6 +119,7 @@ connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) { memmove(&data, arg, sizeof(data)); isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data)); if (result != ISC_R_SUCCESS) { + atomic_store(&slowdown, true); goto error; } @@ -135,11 +138,10 @@ error: data.region.length); } -static isc_result_t +static void connect_send_request(isc_nm_t *mgr, const char *uri, bool post, isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg, bool tls, unsigned int timeout) { - isc_result_t result; isc_region_t copy; csdata_t *data = NULL; isc_tlsctx_t *ctx = NULL; @@ -153,10 +155,8 @@ connect_send_request(isc_nm_t *mgr, const char *uri, bool post, ctx = client_tlsctx; } - result = isc_nm_httpconnect( - mgr, NULL, (isc_nmiface_t *)&tcp_listen_addr, uri, post, - connect_send_cb, data, ctx, timeout, 0); - return (result); + isc_nm_httpconnect(mgr, NULL, (isc_nmiface_t *)&tcp_listen_addr, uri, + post, connect_send_cb, data, ctx, timeout, 0); } static int @@ -372,28 +372,18 @@ sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf, static void doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, void *cbarg) { - uint_fast64_t sends = atomic_load(&nsends); assert_non_null(handle); UNUSED(cbarg); UNUSED(region); + (void)atomic_fetch_sub(&nsends, 1); + if (eresult == ISC_R_SUCCESS) { atomic_fetch_add(&csends, 1); atomic_fetch_add(&creads, 1); - if (sends > 0) { - atomic_fetch_sub(&nsends, 1); - } isc_nm_resumeread(handle); } else { /* We failed to connect; try again */ - while (sends > 0) { - /* Continue until we subtract or we are done */ - if (atomic_compare_exchange_weak(&nsends, &sends, - sends - 1)) { - sends--; - break; - } - } atomic_store(&was_error, true); } } @@ -486,11 +476,10 @@ doh_noop(void **state) { sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url), DOH_PATH); - (void)connect_send_request( - connect_nm, req_url, atomic_load(&POST), - &(isc_region_t){ .base = (uint8_t *)send_msg.base, - .length = send_msg.len }, - noop_read_cb, NULL, atomic_load(&use_TLS), 30000); + connect_send_request(connect_nm, req_url, atomic_load(&POST), + &(isc_region_t){ .base = (uint8_t *)send_msg.base, + .length = send_msg.len }, + noop_read_cb, NULL, atomic_load(&use_TLS), 30000); isc_nm_closedown(connect_nm); @@ -531,11 +520,10 @@ doh_noresponse(void **state) { sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url), DOH_PATH); - (void)connect_send_request( - connect_nm, req_url, atomic_load(&POST), - &(isc_region_t){ .base = (uint8_t *)send_msg.base, - .length = send_msg.len }, - noop_read_cb, NULL, atomic_load(&use_TLS), 30000); + connect_send_request(connect_nm, req_url, atomic_load(&POST), + &(isc_region_t){ .base = (uint8_t *)send_msg.base, + .length = send_msg.len }, + noop_read_cb, NULL, atomic_load(&use_TLS), 30000); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); @@ -558,7 +546,7 @@ doh_noresponse_GET(void **state) { static void doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, void *cbarg) { - uint_fast64_t sends = atomic_load(&nsends); + int_fast64_t sends = atomic_fetch_sub(&nsends, 1); assert_non_null(handle); UNUSED(region); @@ -567,7 +555,6 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult, atomic_fetch_add(&creads, 1); if (sends > 0) { size_t i; - atomic_fetch_sub(&nsends, 1); for (i = 0; i < NWRITES / 2; i++) { eresult = isc__nm_http_request( handle, @@ -579,15 +566,6 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult, } } } else { - /* We failed to connect; try again */ - while (sends > 0) { - /* Continue until we subtract or we are done */ - if (atomic_compare_exchange_weak(&nsends, &sends, - sends - 1)) { - sends--; - break; - } - } atomic_store(&was_error, true); } } @@ -596,25 +574,27 @@ static isc_threadresult_t doh_connect_thread(isc_threadarg_t arg) { isc_nm_t *connect_nm = (isc_nm_t *)arg; char req_url[256]; - isc_result_t result; + int64_t sends = atomic_load(&nsends); sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url, sizeof(req_url), DOH_PATH); - while (atomic_load(&nsends) > 0) { - result = connect_send_request( + while (sends > 0) { + /* + * We need to back off and slow down if we start getting + * errors, to prevent a thundering herd problem. + */ + if (atomic_load(&slowdown)) { + usleep(1000 * workers); + atomic_store(&slowdown, false); + } + connect_send_request( connect_nm, req_url, atomic_load(&POST), &(isc_region_t){ .base = (uint8_t *)send_msg.base, .length = send_msg.len }, doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS), 30000); - /* protection against "too many open files" */ -#ifndef _WIN32 - if (result != ISC_R_SUCCESS) { - INSIST(result == ISC_R_TOOMANYOPENFILES); - usleep(1000 * workers); - } -#endif + sends = atomic_load(&nsends); } return ((isc_threadresult_t)0); @@ -642,13 +622,11 @@ doh_recv_one(void **state) { sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url, sizeof(req_url), DOH_PATH); - result = connect_send_request( - connect_nm, req_url, atomic_load(&POST), - &(isc_region_t){ .base = (uint8_t *)send_msg.base, - .length = send_msg.len }, - doh_receive_reply_cb, NULL, atomic_load(&use_TLS), 30000); - - assert_int_equal(result, ISC_R_SUCCESS); + connect_send_request(connect_nm, req_url, atomic_load(&POST), + &(isc_region_t){ .base = (uint8_t *)send_msg.base, + .length = send_msg.len }, + doh_receive_reply_cb, NULL, atomic_load(&use_TLS), + 30000); while (atomic_load(&nsends) > 0) { if (atomic_load(&was_error)) { @@ -766,12 +744,10 @@ doh_recv_two(void **state) { ctx = client_tlsctx; } - result = isc_nm_httpconnect( - connect_nm, NULL, (isc_nmiface_t *)&tcp_listen_addr, req_url, - atomic_load(&POST), doh_connect_send_two_requests_cb, NULL, ctx, - 5000, 0); - - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_httpconnect(connect_nm, NULL, (isc_nmiface_t *)&tcp_listen_addr, + req_url, atomic_load(&POST), + doh_connect_send_two_requests_cb, NULL, ctx, 5000, + 0); while (atomic_load(&nsends) > 0) { if (atomic_load(&was_error)) { diff --git a/lib/isc/tests/netmgr_test.c b/lib/isc/tests/netmgr_test.c index 2657a94864..7193be2cc5 100644 --- a/lib/isc/tests/netmgr_test.c +++ b/lib/isc/tests/netmgr_test.c @@ -99,7 +99,8 @@ static bool skip_long_tests = false; #define T_ADVERTISED 120 * 1000 #define T_CONNECT 30 * 1000 -#define WAIT_REPEATS 100 +/* Wait for 1 second (1000 * 1000 microseconds) */ +#define WAIT_REPEATS 1000 #define T_WAIT 1000 /* In microseconds */ #define WAIT_FOR(v, op, val) \ @@ -191,18 +192,29 @@ _setup(void **state __attribute__((unused))) { signal(SIGPIPE, SIG_IGN); - if (getenv("CI_ENABLE_ALL_TESTS") != NULL) { + if (getenv("CI") == NULL || getenv("CI_ENABLE_ALL_TESTS") != NULL) { esends = NSENDS * workers; } else { esends = workers; skip_long_tests = true; } + if (isc_tlsctx_createserver(NULL, NULL, &tcp_listen_tlsctx) != + ISC_R_SUCCESS) { + return (-1); + } + if (isc_tlsctx_createclient(&tcp_connect_tlsctx) != ISC_R_SUCCESS) { + return (-1); + } + return (0); } static int _teardown(void **state __attribute__((unused))) { + isc_tlsctx_free(&tcp_connect_tlsctx); + isc_tlsctx_free(&tcp_listen_tlsctx); + isc_test_end(); return (0); @@ -279,14 +291,6 @@ nm_setup(void **state __attribute__((unused))) { isc__nm_closesocket(tcp_listen_sock); tcp_listen_sock = -1; - if (isc_tlsctx_createserver(NULL, NULL, &tcp_listen_tlsctx) != - ISC_R_SUCCESS) { - return (-1); - } - if (isc_tlsctx_createclient(&tcp_connect_tlsctx) != ISC_R_SUCCESS) { - return (-1); - } - atomic_store(&do_send, true); atomic_store(&nsends, esends); @@ -330,27 +334,24 @@ static int nm_teardown(void **state __attribute__((unused))) { UNUSED(state); - WAIT_FOR_EQ(active_cconnects, 0); - WAIT_FOR_EQ(active_csends, 0); - WAIT_FOR_EQ(active_csends, 0); - WAIT_FOR_EQ(active_ssends, 0); - WAIT_FOR_EQ(active_sreads, 0); - isc_nm_destroy(&connect_nm); assert_null(connect_nm); isc_nm_destroy(&listen_nm); assert_null(listen_nm); + WAIT_FOR_EQ(active_cconnects, 0); + WAIT_FOR_EQ(active_csends, 0); + WAIT_FOR_EQ(active_csends, 0); + WAIT_FOR_EQ(active_ssends, 0); + WAIT_FOR_EQ(active_sreads, 0); + isc_refcount_destroy(&active_cconnects); isc_refcount_destroy(&active_csends); isc_refcount_destroy(&active_creads); isc_refcount_destroy(&active_ssends); isc_refcount_destroy(&active_sreads); - isc_tlsctx_free(&tcp_connect_tlsctx); - isc_tlsctx_free(&tcp_listen_tlsctx); - return (0); } @@ -456,12 +457,15 @@ unref: static void connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { isc_nmhandle_t *readhandle = NULL; + UNUSED(cbarg); F(); + isc_refcount_decrement(&active_cconnects); + if (eresult != ISC_R_SUCCESS) { - goto unref; + return; } atomic_fetch_add(&cconnects, 1); @@ -471,9 +475,6 @@ connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { isc_nm_read(handle, connect_read_cb, NULL); connect_send(handle); - -unref: - isc_refcount_decrement(&active_cconnects); } static void @@ -564,12 +565,11 @@ stream_accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { return (ISC_R_SUCCESS); } -typedef isc_result_t (*connect_func)(isc_nm_t *); +typedef void (*connect_func)(isc_nm_t *); static isc_threadresult_t connect_thread(isc_threadarg_t arg) { connect_func connect = (connect_func)arg; - isc_result_t result; isc_sockaddr_t connect_addr; connect_addr = (isc_sockaddr_t){ .length = 0 }; @@ -578,26 +578,15 @@ connect_thread(isc_threadarg_t arg) { while (atomic_load(&do_send)) { uint_fast32_t active = isc_refcount_increment0(&active_cconnects); - if (active >= workers) { + if (active > workers) { /* - * If we have more active connections than workers start - * slowing down the connections to prevent the + * If we have more active connections than workers, + * start slowing down the connections to prevent the * thundering herd problem. */ usleep((active - workers) * 1000); } - result = connect(connect_nm); - if (result != ISC_R_SUCCESS) { - /* - * Also back-off and slow down if we start getting - * errors to prevent the thundering herd problem. This - * could especially happen on FreeBSD where socket() - * call can fail because of system limits and in such - * case it's not such good idea to try again quickly. - */ - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } + connect(connect_nm); } return ((isc_threadresult_t)0); @@ -605,11 +594,11 @@ connect_thread(isc_threadarg_t arg) { /* UDP */ -static isc_result_t +static void udp_connect(isc_nm_t *nm) { - return (isc_nm_udpconnect(nm, (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - connect_connect_cb, NULL, T_CONNECT, 0)); + isc_nm_udpconnect(nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); } static void @@ -659,20 +648,12 @@ mock_listenudp_uv_udp_recv_start(void **state __attribute__((unused))) { static void mock_udpconnect_uv_udp_open(void **state __attribute__((unused))) { - isc_result_t result = ISC_R_SUCCESS; - WILL_RETURN(uv_udp_open, UV_ENOMEM); isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect(connect_nm, - (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - assert_int_not_equal(result, ISC_R_SUCCESS); - + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); RESET_RETURN; @@ -680,20 +661,12 @@ mock_udpconnect_uv_udp_open(void **state __attribute__((unused))) { static void mock_udpconnect_uv_udp_bind(void **state __attribute__((unused))) { - isc_result_t result = ISC_R_SUCCESS; - WILL_RETURN(uv_udp_bind, UV_ENOMEM); isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect(connect_nm, - (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - assert_int_not_equal(result, ISC_R_SUCCESS); - + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); RESET_RETURN; @@ -702,20 +675,12 @@ mock_udpconnect_uv_udp_bind(void **state __attribute__((unused))) { #if HAVE_UV_UDP_CONNECT static void mock_udpconnect_uv_udp_connect(void **state __attribute__((unused))) { - isc_result_t result = ISC_R_SUCCESS; - WILL_RETURN(uv_udp_connect, UV_ENOMEM); isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect(connect_nm, - (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - assert_int_not_equal(result, ISC_R_SUCCESS); - + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); RESET_RETURN; @@ -724,20 +689,12 @@ mock_udpconnect_uv_udp_connect(void **state __attribute__((unused))) { static void mock_udpconnect_uv_recv_buffer_size(void **state __attribute__((unused))) { - isc_result_t result = ISC_R_SUCCESS; - WILL_RETURN(uv_recv_buffer_size, UV_ENOMEM); isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect(connect_nm, - (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - assert_int_equal(result, ISC_R_SUCCESS); /* FIXME: should fail */ - + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); RESET_RETURN; @@ -745,20 +702,12 @@ mock_udpconnect_uv_recv_buffer_size(void **state __attribute__((unused))) { static void mock_udpconnect_uv_send_buffer_size(void **state __attribute__((unused))) { - isc_result_t result = ISC_R_SUCCESS; - WILL_RETURN(uv_send_buffer_size, UV_ENOMEM); isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect(connect_nm, - (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - assert_int_equal(result, ISC_R_SUCCESS); /* FIXME: should fail */ - + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); RESET_RETURN; @@ -777,17 +726,10 @@ udp_noop(void **state __attribute__((unused))) { isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect(connect_nm, - (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); - + isc_refcount_increment0(&active_cconnects); + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); atomic_assert_int_eq(cconnects, 0); @@ -806,16 +748,10 @@ udp_noresponse(void **state __attribute__((unused))) { noop_recv_cb, NULL, 0, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect( - connect_nm, (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_EQ(csends, 1); @@ -849,16 +785,10 @@ udp_recv_one(void **state __attribute__((unused))) { listen_read_cb, NULL, 0, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect( - connect_nm, (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_LE(nsends, 0); @@ -896,29 +826,17 @@ udp_recv_two(void **state __attribute__((unused))) { listen_read_cb, NULL, 0, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect( - connect_nm, (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_udpconnect( - connect_nm, (isc_nmiface_t *)&udp_connect_addr, - (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr, + (isc_nmiface_t *)&udp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 2); WAIT_FOR_LE(nsends, 0); @@ -1135,11 +1053,11 @@ udp_half_recv_half_send(void **state __attribute__((unused))) { static isc_quota_t * tcp_listener_init_quota(size_t nthreads); -static isc_result_t +static void tcp_connect(isc_nm_t *nm) { - return (isc_nm_tcpconnect(nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - connect_connect_cb, NULL, 1, 0)); + isc_nm_tcpconnect(nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); } static void @@ -1156,17 +1074,10 @@ tcp_noop(void **state __attribute__((unused))) { isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpconnect(connect_nm, - (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - noop_connect_cb, NULL, 1, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); - + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); atomic_assert_int_eq(cconnects, 0); @@ -1186,16 +1097,10 @@ tcp_noresponse(void **state __attribute__((unused))) { &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpconnect(connect_nm, - (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - connect_connect_cb, NULL, 1, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_EQ(csends, 1); @@ -1231,16 +1136,10 @@ tcp_recv_one(void **state __attribute__((unused))) { &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_LE(nsends, 0); @@ -1280,29 +1179,17 @@ tcp_recv_two(void **state __attribute__((unused))) { &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, + NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 2); WAIT_FOR_LE(nsends, 0); @@ -1532,7 +1419,7 @@ tcp_listener_init_quota(size_t nthreads) { isc_quota_max(&listener_quota, max_quota); quotap = &listener_quota; } - return quotap; + return (quotap); } static void @@ -1577,11 +1464,11 @@ tcp_half_recv_half_send_quota(void **state) { /* TCPDNS */ -static isc_result_t +static void tcpdns_connect(isc_nm_t *nm) { - return (isc_nm_tcpdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - connect_connect_cb, NULL, T_CONNECT, 0)); + isc_nm_tcpdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0); } static void @@ -1599,15 +1486,9 @@ tcpdns_noop(void **state __attribute__((unused))) { assert_null(listen_sock); isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpdnsconnect(connect_nm, - (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - noop_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0); isc_nm_closedown(connect_nm); atomic_assert_int_eq(cconnects, 0); @@ -1632,11 +1513,9 @@ tcpdns_noresponse(void **state __attribute__((unused))) { } assert_int_equal(result, ISC_R_SUCCESS); - result = isc_nm_tcpdnsconnect(connect_nm, - (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - connect_connect_cb, NULL, T_CONNECT, 0); - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_EQ(csends, 1); @@ -1672,14 +1551,9 @@ tcpdns_recv_one(void **state __attribute__((unused))) { assert_int_equal(result, ISC_R_SUCCESS); isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpdnsconnect(connect_nm, - (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - connect_connect_cb, NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_LE(nsends, 0); @@ -1718,31 +1592,17 @@ tcpdns_recv_two(void **state __attribute__((unused))) { NULL, listen_accept_cb, NULL, 0, 0, NULL, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpdnsconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); - assert_int_equal(result, ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 1); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tcpdnsconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - } - } while (result != ISC_R_SUCCESS); - assert_int_equal(result, ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0); WAIT_FOR_EQ(cconnects, 2); @@ -1961,12 +1821,12 @@ tcpdns_half_recv_half_send(void **state __attribute__((unused))) { /* TLSDNS */ -static isc_result_t +static void tlsdns_connect(isc_nm_t *nm) { - return (isc_nm_tlsdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, - connect_connect_cb, NULL, T_CONNECT, 0, - tcp_connect_tlsctx)); + isc_nm_tlsdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0, + tcp_connect_tlsctx); } static void @@ -1984,17 +1844,10 @@ tlsdns_noop(void **state __attribute__((unused))) { isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tlsdnsconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb, - NULL, T_CONNECT, 0, tcp_connect_tlsctx); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb, + NULL, T_CONNECT, 0, tcp_connect_tlsctx); isc_nm_closedown(connect_nm); @@ -2020,17 +1873,11 @@ tlsdns_noresponse(void **state __attribute__((unused))) { &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - do { - isc_refcount_increment0(&active_cconnects); - result = isc_nm_tlsdnsconnect( - connect_nm, (isc_nmiface_t *)&connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, - NULL, T_CONNECT, 0, tcp_connect_tlsctx); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } - } while (result != ISC_R_SUCCESS); + isc_refcount_increment0(&active_cconnects); + isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0, + tcp_connect_tlsctx); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_EQ(csends, 1); @@ -2067,15 +1914,10 @@ tlsdns_recv_one(void **state __attribute__((unused))) { assert_int_equal(result, ISC_R_SUCCESS); isc_refcount_increment0(&active_cconnects); - result = isc_nm_tlsdnsconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL, - T_CONNECT, 0, tcp_connect_tlsctx); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0, + tcp_connect_tlsctx); WAIT_FOR_EQ(cconnects, 1); WAIT_FOR_LE(nsends, 0); @@ -2116,28 +1958,18 @@ tlsdns_recv_two(void **state __attribute__((unused))) { assert_int_equal(result, ISC_R_SUCCESS); isc_refcount_increment0(&active_cconnects); - result = isc_nm_tlsdnsconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL, - T_CONNECT, 0, tcp_connect_tlsctx); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0, + tcp_connect_tlsctx); WAIT_FOR_EQ(cconnects, 1); isc_refcount_increment0(&active_cconnects); - result = isc_nm_tlsdnsconnect( - connect_nm, (isc_nmiface_t *)&tcp_connect_addr, - (isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL, - T_CONNECT, 0, tcp_connect_tlsctx); - if (result != ISC_R_SUCCESS) { - isc_refcount_decrement(&active_cconnects); - usleep(1000); - } - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr, + (isc_nmiface_t *)&tcp_listen_addr, + connect_connect_cb, NULL, T_CONNECT, 0, + tcp_connect_tlsctx); WAIT_FOR_EQ(cconnects, 2); diff --git a/lib/isc/tests/tls_test.c b/lib/isc/tests/tls_test.c index 3bfff77719..800caad24b 100644 --- a/lib/isc/tests/tls_test.c +++ b/lib/isc/tests/tls_test.c @@ -66,13 +66,23 @@ static atomic_uint_fast64_t csends; static atomic_uint_fast64_t creads; static atomic_uint_fast64_t ctimeouts; -static unsigned int workers = 0; +static atomic_bool slowdown = ATOMIC_VAR_INIT(false); -static bool reuse_supported = true; +static unsigned int workers = 0; static isc_tlsctx_t *server_tlsctx = NULL; static isc_tlsctx_t *client_tlsctx = NULL; +static atomic_bool was_error = ATOMIC_VAR_INIT(false); + +static bool skip_long_tests = false; + +#define SKIP_IN_CI \ + if (skip_long_tests) { \ + skip(); \ + return; \ + } + #define NSENDS 100 #define NWRITES 10 @@ -145,9 +155,6 @@ setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { close(fd); return (-1); } - if (result == ISC_R_NOTIMPLEMENTED) { - reuse_supported = false; - } #if IPV6_RECVERR #define setsockopt_on(socket, level, name) \ @@ -185,6 +192,10 @@ _setup(void **state) { signal(SIGPIPE, SIG_IGN); + if (getenv("CI") != NULL && getenv("CI_ENABLE_ALL_TESTS") == NULL) { + skip_long_tests = true; + } + return (0); } @@ -241,6 +252,8 @@ nm_setup(void **state) { atomic_store(&ctimeouts, 0); atomic_store(&cconnects, 0); + atomic_store(&was_error, false); + isc_nonce_buf(&send_magic, sizeof(send_magic)); isc_nonce_buf(&stop_magic, sizeof(stop_magic)); if (send_magic == stop_magic) { @@ -389,6 +402,8 @@ tls_connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, if (eresult != ISC_R_SUCCESS) { uint_fast64_t sends = atomic_load(&nsends); + atomic_store(&slowdown, true); + atomic_store(&was_error, true); /* We failed to connect; try again */ while (sends > 0) { @@ -431,10 +446,9 @@ tls_noop(void **state) { isc_nmsocket_close(&listen_sock); assert_null(listen_sock); - (void)isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, - (isc_nmiface_t *)&tls_listen_addr, - noop_connect_cb, NULL, client_tlsctx, 1, 0); - + isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, + (isc_nmiface_t *)&tls_listen_addr, noop_connect_cb, + NULL, client_tlsctx, 1, 0); isc_nm_closedown(connect_nm); assert_int_equal(0, atomic_load(&cconnects)); @@ -462,10 +476,9 @@ tls_noresponse(void **state) { server_tlsctx, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - (void)isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, - (isc_nmiface_t *)&tls_listen_addr, - noop_connect_cb, NULL, client_tlsctx, 1, 0); - + isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, + (isc_nmiface_t *)&tls_listen_addr, noop_connect_cb, + NULL, client_tlsctx, 1, 0); isc_nm_stoplistening(listen_sock); isc_nmsocket_close(&listen_sock); assert_null(listen_sock); @@ -479,21 +492,23 @@ static isc_threadresult_t tls_connect_thread(isc_threadarg_t arg) { isc_nm_t *connect_nm = (isc_nm_t *)arg; isc_sockaddr_t tls_connect_addr; - isc_result_t result; tls_connect_addr = (isc_sockaddr_t){ .length = 0 }; isc_sockaddr_fromin6(&tls_connect_addr, &in6addr_loopback, 0); while (atomic_load(&nsends) > 0) { - result = isc_nm_tlsconnect( + /* + * We need to back off and slow down if we start getting + * errors, to prevent a thundering herd problem. + */ + if (atomic_load(&slowdown)) { + usleep(1000 * workers); + atomic_store(&slowdown, false); + } + isc_nm_tlsconnect( connect_nm, (isc_nmiface_t *)&tls_connect_addr, (isc_nmiface_t *)&tls_listen_addr, tls_connect_connect_cb, NULL, client_tlsctx, 1, 0); - /* protection against "too many open files" */ - if (result != ISC_R_SUCCESS) { - atomic_fetch_sub(&nsends, 1); - usleep(1000 * workers); - } } return ((isc_threadresult_t)0); @@ -518,12 +533,14 @@ tls_recv_one(void **state) { server_tlsctx, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - (void)isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, - (isc_nmiface_t *)&tls_listen_addr, - tls_connect_connect_cb, NULL, client_tlsctx, - 1000, 0); + isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, + (isc_nmiface_t *)&tls_listen_addr, + tls_connect_connect_cb, NULL, client_tlsctx, 1000, 0); while (atomic_load(&nsends) > 0) { + if (atomic_load(&was_error)) { + break; + } isc_thread_yield(); } @@ -531,6 +548,9 @@ tls_recv_one(void **state) { atomic_load(&sreads) != 1 || atomic_load(&creads) != 0 || atomic_load(&csends) != 1) { + if (atomic_load(&was_error)) { + break; + } isc_thread_yield(); } @@ -573,19 +593,24 @@ tls_recv_two(void **state) { server_tlsctx, &listen_sock); assert_int_equal(result, ISC_R_SUCCESS); - result = isc_nm_tlsconnect( - connect_nm, (isc_nmiface_t *)&tls_connect_addr, - (isc_nmiface_t *)&tls_listen_addr, tls_connect_connect_cb, NULL, - client_tlsctx, 100000, 0); - assert_int_equal(result, ISC_R_SUCCESS); + isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr, + (isc_nmiface_t *)&tls_listen_addr, + tls_connect_connect_cb, NULL, client_tlsctx, 100000, + 0); while (atomic_load(&nsends) > 0) { + if (atomic_load(&was_error)) { + break; + } isc_thread_yield(); } while (atomic_load(&sreads) < 2 || atomic_load(&ssends) < 1 || atomic_load(&csends) < 2 || atomic_load(&creads) < 1) { + if (atomic_load(&was_error)) { + break; + } isc_thread_yield(); } @@ -619,10 +644,7 @@ tls_recv_send(void **state) { size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); isc_thread_t threads[32] = { 0 }; - if (!reuse_supported) { - skip(); - return; - } + SKIP_IN_CI; result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr, tls_listen_accept_cb, NULL, 0, 0, NULL, @@ -665,10 +687,7 @@ tls_recv_half_send(void **state) { size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); isc_thread_t threads[32] = { 0 }; - if (!reuse_supported) { - skip(); - return; - } + SKIP_IN_CI; result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr, tls_listen_accept_cb, NULL, 0, 0, NULL, @@ -716,10 +735,7 @@ tls_half_recv_send(void **state) { size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); isc_thread_t threads[32] = { 0 }; - if (!reuse_supported) { - skip(); - return; - } + SKIP_IN_CI; result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr, tls_listen_accept_cb, NULL, 0, 0, NULL, @@ -767,10 +783,7 @@ tls_half_recv_half_send(void **state) { size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1); isc_thread_t threads[32] = { 0 }; - if (!reuse_supported) { - skip(); - return; - } + SKIP_IN_CI; result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr, tls_listen_accept_cb, NULL, 0, 0, NULL, diff --git a/lib/isc/tests/uv_wrap.h b/lib/isc/tests/uv_wrap.h index b1b0e3369f..46d41d2d45 100644 --- a/lib/isc/tests/uv_wrap.h +++ b/lib/isc/tests/uv_wrap.h @@ -111,7 +111,9 @@ __wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr, return (atomic_load(&__state_uv_udp_bind)); } -static atomic_int __state_uv_udp_connect = ATOMIC_VAR_INIT(0); +static atomic_int __state_uv_udp_connect + __attribute__((unused)) = ATOMIC_VAR_INIT(0); + #if HAVE_UV_UDP_CONNECT int __wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) { @@ -122,7 +124,9 @@ __wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) { } #endif /* HAVE_UV_UDP_CONNECT */ -static atomic_int __state_uv_udp_getpeername = ATOMIC_VAR_INIT(0); +static atomic_int __state_uv_udp_getpeername + __attribute__((unused)) = ATOMIC_VAR_INIT(0); + #if HAVE_UV_UDP_CONNECT int __wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,