From 308bc46a59302c88ecff11d4831475ecfa8b8fb0 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 14 Jan 2021 13:02:57 -0800 Subject: [PATCH] Convert dispatch to netmgr The flow of operations in dispatch is changing and will now be similar for both UDP and TCP queries: 1) Call dns_dispatch_addresponse() to assign a query ID and register that we'll be listening for a response with that ID soon. the parameters for this function include callback functions to inform the caller when the socket is connected and when the message has been sent, as well as a task action that will be sent when the response arrives. (later this could become a netmgr callback, but at this stage to minimize disruption to the calling code, we continue to use isc_task for the response event.) on successful completion of this function, a dispatch entry object will be instantiated. 2) Call dns_dispatch_connect() on the dispatch entry. this runs isc_nm_udpconnect() or isc_nm_tcpdnsconnect(), as needed, and begins listening for responses. the caller is informed via a callback function when the connection is established. 3) Call dns_dispatch_send() on the dispatch entry. this runs isc_nm_send() to send a request. 4) Call dns_dispatch_removeresponse() to terminate listening and close the connection. Implementation comments below: - As we will be using netmgr buffers now. code to send the length in TCP queries has also been removed as that is handled by the netmgr. - TCP dispatches can be used by multiple simultaneous queries, so dns_dispatch_connect() now checks whether the dispatch is already connected before calling isc_nm_tcpdnsconnect() again. - Running dns_dispatch_getnext() from a non-network thread caused a crash due to assertions in the netmgr read functions that appear to be unnecessary now. the assertions have been removed. - fctx->nqueries was formerly incremented when the connection was successful, but is now incremented when the query is started and decremented if the connection fails. - It's no longer necessary for each dispatch to have a pool of tasks, so there's now a single task per dispatch. - Dispatch code to avoid UDP ports already in use has been removed. - dns_resolver and dns_request have been modified to use netmgr callback functions instead of task events. some additional changes were needed to handle shutdown processing correctly. - Timeout processing is not yet fully converted to use netmgr timeouts. - Fixed a lock order cycle reported by TSAN (view -> zone-> adb -> view) by by calling dns_zt functions without holding the view lock. --- bin/delv/delv.c | 11 +- bin/named/server.c | 13 +- bin/nsupdate/nsupdate.c | 27 +- bin/tests/system/pipelined/pipequeries.c | 23 +- bin/tests/system/resolve.c | 16 +- bin/tests/system/tkey/keycreate.c | 27 +- bin/tests/system/tkey/keydelete.c | 25 +- bin/tools/mdig.c | 20 +- lib/dns/client.c | 53 +- lib/dns/dispatch.c | 1283 +++++++--------------- lib/dns/include/dns/client.h | 7 +- lib/dns/include/dns/dispatch.h | 90 +- lib/dns/include/dns/request.h | 5 +- lib/dns/include/dns/resolver.h | 14 +- lib/dns/include/dns/view.h | 8 +- lib/dns/request.c | 203 +--- lib/dns/resolver.c | 397 +++---- lib/dns/tests/dispatch_test.c | 234 ++-- lib/dns/tests/dnstest.c | 3 + lib/dns/tests/dnstest.h | 1 + lib/dns/tests/resolver_test.c | 10 +- lib/dns/view.c | 40 +- lib/dns/zt.c | 2 + lib/isc/include/isc/netmgr.h | 10 + lib/isc/managers.c | 2 +- lib/isc/socket.c | 2 +- lib/ns/interfacemgr.c | 2 +- lib/ns/tests/nstest.c | 2 +- 28 files changed, 924 insertions(+), 1606 deletions(-) diff --git a/bin/delv/delv.c b/bin/delv/delv.c index dd1181076b..3559f1bf63 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -1725,7 +1725,6 @@ main(int argc, char *argv[]) { isc_appctx_t *actx = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_socketmgr_t *socketmgr = NULL; isc_timermgr_t *timermgr = NULL; dns_master_style_t *style = NULL; struct sigaction sa; @@ -1744,8 +1743,8 @@ main(int argc, char *argv[]) { isc_mem_create(&mctx); CHECK(isc_appctx_create(mctx, &actx)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, NULL); parse_args(argc, argv); @@ -1763,7 +1762,7 @@ main(int argc, char *argv[]) { } /* Create client */ - result = dns_client_create(mctx, actx, taskmgr, socketmgr, timermgr, 0, + result = dns_client_create(mctx, actx, taskmgr, netmgr, timermgr, 0, &client, srcaddr4, srcaddr6); if (result != ISC_R_SUCCESS) { delv_log(ISC_LOG_ERROR, "dns_client_create: %s", @@ -1846,7 +1845,9 @@ cleanup: if (client != NULL) { dns_client_detach(&client); } - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, NULL); + if (actx != NULL) { isc_appctx_destroy(&actx); } diff --git a/bin/named/server.c b/bin/named/server.c index e70cba3662..0abefe8407 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1315,8 +1315,8 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, } } - result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &sa, attrs, &disp); + result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_taskmgr, + &sa, attrs, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -4716,7 +4716,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH); CHECK(dns_view_createresolver( view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus, - ndisp, named_g_socketmgr, named_g_timermgr, resopts, + ndisp, named_g_netmgr, named_g_timermgr, resopts, named_g_dispatchmgr, dispatch4, dispatch6)); if (dscp4 == -1) { @@ -9862,7 +9862,8 @@ run_server(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); - CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr), + CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr, + &named_g_dispatchmgr), "creating dispatch manager"); dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats); @@ -10357,8 +10358,8 @@ named_add_reserved_dispatch(named_server_t *server, dispatch->dispatchgen = server->dispatchgen; dispatch->dispatch = NULL; - result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &dispatch->addr, attrs, + result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_taskmgr, + &dispatch->addr, attrs, &dispatch->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index be39164216..a3bb130a7e 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -38,11 +39,9 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -131,8 +130,6 @@ static isc_log_t *glctx = NULL; static isc_mem_t *gmctx = NULL; static dns_dispatchmgr_t *dispatchmgr = NULL; static dns_requestmgr_t *requestmgr = NULL; -static isc_socketmgr_t *socketmgr = NULL; -static isc_timermgr_t *timermgr = NULL; static dns_dispatch_t *dispatchv4 = NULL; static dns_dispatch_t *dispatchv6 = NULL; static dns_message_t *updatemsg = NULL; @@ -917,11 +914,12 @@ setup_system(void) { irs_resconf_destroy(&resconf); - result = dns_dispatchmgr_create(gmctx, &dispatchmgr); - check_result(result, "dns_dispatchmgr_create"); + result = isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, NULL, + NULL); + check_result(result, "isc_managers_create"); - isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + result = dns_dispatchmgr_create(gmctx, netmgr, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); result = isc_task_create(taskmgr, 0, &global_task); check_result(result, "isc_task_create"); @@ -937,21 +935,20 @@ setup_system(void) { if (have_ipv6) { isc_sockaddr_any6(&bind_any6); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any6, 0, &dispatchv6); check_result(result, "dns_dispatch_createudp (v6)"); } if (have_ipv4) { isc_sockaddr_any(&bind_any); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 0, &dispatchv4); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, + 0, &dispatchv4); check_result(result, "dns_dispatch_createudp (v4)"); } - result = dns_requestmgr_create(gmctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, dispatchv6, - &requestmgr); + result = dns_requestmgr_create(gmctx, taskmgr, dispatchmgr, dispatchv4, + dispatchv6, &requestmgr); check_result(result, "dns_requestmgr_create"); if (keystr != NULL) { @@ -3322,7 +3319,7 @@ cleanup(void) { } ddebug("Shutting down managers"); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); ddebug("Destroying event"); isc_event_free(&global_event); diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 6466771ff2..6b34dd808c 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -23,12 +23,11 @@ #include #include #include +#include #include #include #include -#include #include -#include #include #include @@ -70,7 +69,8 @@ static void recvresponse(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query = NULL, *response = NULL; + dns_message_t *query = NULL; + dns_message_t *response = NULL; isc_buffer_t outbuf; char output[1024]; @@ -203,8 +203,6 @@ main(int argc, char *argv[]) { isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; dns_view_t *view = NULL; @@ -267,18 +265,15 @@ main(int argc, char *argv[]) { RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); - + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchv4)); - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); RUNCHECK(isc_app_onrun(mctx, task, sendqueries, NULL)); @@ -296,7 +291,7 @@ main(int argc, char *argv[]) { isc_task_shutdown(task); isc_task_detach(&task); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_lib_destroy(); diff --git a/bin/tests/system/resolve.c b/bin/tests/system/resolve.c index c13cb5bee4..6508b6e9ff 100644 --- a/bin/tests/system/resolve.c +++ b/bin/tests/system/resolve.c @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -58,13 +58,11 @@ isc_mem_t *ctxs_mctx = NULL; isc_appctx_t *ctxs_actx = NULL; isc_nm_t *ctxs_netmgr = NULL; isc_taskmgr_t *ctxs_taskmgr = NULL; -isc_socketmgr_t *ctxs_socketmgr = NULL; isc_timermgr_t *ctxs_timermgr = NULL; static void ctxs_destroy(void) { - isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, - &ctxs_socketmgr); + isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, NULL); if (ctxs_actx != NULL) { isc_appctx_destroy(&ctxs_actx); @@ -87,7 +85,7 @@ ctxs_init(void) { } isc_managers_create(ctxs_mctx, 1, 0, 0, &ctxs_netmgr, &ctxs_taskmgr, - &ctxs_timermgr, &ctxs_socketmgr); + &ctxs_timermgr, NULL); result = isc_app_ctxstart(ctxs_actx); if (result != ISC_R_SUCCESS) { @@ -102,7 +100,7 @@ fail: return (result); } -static char *algname; +static char *algname = NULL; static isc_result_t printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { @@ -281,9 +279,9 @@ main(int argc, char *argv[]) { isc_buffer_t b; dns_fixedname_t qname0; unsigned int namelen; - dns_name_t *qname, *name; + dns_name_t *qname = NULL, *name = NULL; dns_rdatatype_t type = dns_rdatatype_a; - dns_rdataset_t *rdataset; + dns_rdataset_t *rdataset = NULL; dns_namelist_t namelist; unsigned int clientopt, resopt = 0; bool is_sep = false; @@ -406,7 +404,7 @@ main(int argc, char *argv[]) { clientopt = 0; result = dns_client_create(ctxs_mctx, ctxs_actx, ctxs_taskmgr, - ctxs_socketmgr, ctxs_timermgr, clientopt, + ctxs_netmgr, ctxs_timermgr, clientopt, &client, addr4, addr6); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_client_create failed: %u, %s\n", result, diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 6904c1998a..9ede9a65b5 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -18,13 +18,12 @@ #include #include #include +#include #include #include #include #include -#include #include -#include #include #include @@ -86,7 +85,6 @@ recvquery(isc_task_t *task, isc_event_t *event) { query = reqev->ev_arg; - response = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); result = dns_request_getresponse(reqev->request, response, @@ -190,9 +188,6 @@ main(int argc, char *argv[]) { char *ourkeyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; - isc_socket_t *sock = NULL; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -227,18 +222,16 @@ main(int argc, char *argv[]) { RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 0, &dispatchv4)); - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, 0, + &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); @@ -247,9 +240,6 @@ main(int argc, char *argv[]) { dns_view_setkeyring(view, ring); dns_tsigkeyring_detach(&ring); - RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, - &sock)); - RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; @@ -268,8 +258,7 @@ main(int argc, char *argv[]) { dns_dispatchmgr_destroy(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_socket_detach(&sock); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_key_free(&ourkey); dns_tsigkey_detach(&initialkey); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index 1b8d3dc336..c76d816132 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include @@ -134,9 +132,6 @@ main(int argc, char **argv) { char *keyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; - isc_socket_t *sock = NULL; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -171,17 +166,15 @@ main(int argc, char **argv) { RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 0, &dispatchv4)); - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, 0, + &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); @@ -189,9 +182,6 @@ main(int argc, char **argv) { RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); dns_view_setkeyring(view, ring); - RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, - &sock)); - RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; @@ -211,8 +201,7 @@ main(int argc, char **argv) { dns_dispatchmgr_destroy(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_socket_detach(&sock); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dns_tsigkeyring_detach(&ring); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index 9c58a337cd..f3d37da52c 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -24,15 +24,14 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include -#include #include #include @@ -2068,8 +2067,6 @@ main(int argc, char *argv[]) { isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchvx = NULL; dns_view_t *view = NULL; @@ -2122,25 +2119,22 @@ main(int argc, char *argv[]) { fatal("can't choose between IPv4 and IPv6"); } - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); - + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); if (have_ipv4) { isc_sockaddr_any(&bind_any); } else { isc_sockaddr_any6(&bind_any); } - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchvx)); RUNCHECK(dns_requestmgr_create( - mctx, timermgr, socketmgr, taskmgr, dispatchmgr, - have_ipv4 ? dispatchvx : NULL, have_ipv6 ? dispatchvx : NULL, - &requestmgr)); + mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL, + have_ipv6 ? dispatchvx : NULL, &requestmgr)); RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); @@ -2186,7 +2180,7 @@ main(int argc, char *argv[]) { isc_task_shutdown(task); isc_task_detach(&task); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_lib_destroy(); diff --git a/lib/dns/client.c b/lib/dns/client.c index 1d113972b8..70a1adb859 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -86,7 +86,7 @@ struct dns_client { isc_appctx_t *actx; isc_taskmgr_t *taskmgr; isc_task_t *task; - isc_socketmgr_t *socketmgr; + isc_nm_t *nm; isc_timermgr_t *timermgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; @@ -202,8 +202,8 @@ cleanup: static isc_result_t getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, - dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { + isc_taskmgr_t *taskmgr, dns_dispatch_t **dispp, + const isc_sockaddr_t *localaddr) { dns_dispatch_t *disp = NULL; isc_result_t result; isc_sockaddr_t anyaddr; @@ -213,8 +213,8 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, localaddr = &anyaddr; } - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - localaddr, 0, &disp); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, localaddr, 0, + &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -224,10 +224,9 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, static isc_result_t createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, - unsigned int ntasks, isc_socketmgr_t *socketmgr, - isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_view_t **viewp) { + unsigned int ntasks, isc_nm_t *nm, isc_timermgr_t *timermgr, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_view_t **viewp) { isc_result_t result; dns_view_t *view = NULL; @@ -243,8 +242,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, return (result); } - result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr, - timermgr, 0, dispatchmgr, dispatchv4, + result = dns_view_createresolver(view, taskmgr, ntasks, 1, nm, timermgr, + 0, dispatchmgr, dispatchv4, dispatchv6); if (result != ISC_R_SUCCESS) { dns_view_detach(&view); @@ -264,9 +263,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, isc_result_t dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_client_t **clientp, - const isc_sockaddr_t *localaddr4, + isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, const isc_sockaddr_t *localaddr4, const isc_sockaddr_t *localaddr6) { isc_result_t result; dns_client_t *client = NULL; @@ -278,27 +276,24 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, REQUIRE(mctx != NULL); REQUIRE(taskmgr != NULL); REQUIRE(timermgr != NULL); - REQUIRE(socketmgr != NULL); + REQUIRE(nm != NULL); REQUIRE(clientp != NULL && *clientp == NULL); UNUSED(options); client = isc_mem_get(mctx, sizeof(*client)); + *client = (dns_client_t){ + .actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm + }; isc_mutex_init(&client->lock); - client->actx = actx; - client->taskmgr = taskmgr; - client->socketmgr = socketmgr; - client->timermgr = timermgr; - - client->task = NULL; result = isc_task_create(client->taskmgr, 0, &client->task); if (result != ISC_R_SUCCESS) { goto cleanup_lock; } - result = dns_dispatchmgr_create(mctx, &dispatchmgr); + result = dns_dispatchmgr_create(mctx, nm, &dispatchmgr); if (result != ISC_R_SUCCESS) { goto cleanup_task; } @@ -311,8 +306,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, */ client->dispatchv4 = NULL; if (localaddr4 != NULL || localaddr6 == NULL) { - result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, - taskmgr, &dispatchv4, localaddr4); + result = getudpdispatch(AF_INET, dispatchmgr, taskmgr, + &dispatchv4, localaddr4); if (result == ISC_R_SUCCESS) { client->dispatchv4 = dispatchv4; } @@ -320,8 +315,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, client->dispatchv6 = NULL; if (localaddr6 != NULL || localaddr4 == NULL) { - result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, - taskmgr, &dispatchv6, localaddr6); + result = getudpdispatch(AF_INET6, dispatchmgr, taskmgr, + &dispatchv6, localaddr6); if (result == ISC_R_SUCCESS) { client->dispatchv6 = dispatchv6; } @@ -337,8 +332,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, /* Create the default view for class IN */ result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS, - socketmgr, timermgr, dispatchmgr, dispatchv4, - dispatchv6, &view); + nm, timermgr, dispatchmgr, dispatchv4, dispatchv6, + &view); if (result != ISC_R_SUCCESS) { goto cleanup_references; } @@ -350,12 +345,10 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, ISC_LIST_INIT(client->resctxs); - client->mctx = NULL; isc_mem_attach(mctx, &client->mctx); client->find_timeout = DEF_FIND_TIMEOUT; client->find_udpretries = DEF_FIND_UDPRETRIES; - client->attributes = 0; client->magic = DNS_CLIENT_MAGIC; diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index e8f78d5550..a159e79c55 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -19,10 +19,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -40,15 +40,13 @@ typedef ISC_LIST(dns_dispentry_t) dns_displist_t; typedef struct dispsocket dispsocket_t; -typedef ISC_LIST(dispsocket_t) dispsocketlist_t; typedef struct dns_qid { unsigned int magic; + isc_mutex_t lock; unsigned int qid_nbuckets; /*%< hash table size */ unsigned int qid_increment; /*%< id increment on collision */ - isc_mutex_t lock; - dns_displist_t *qid_table; /*%< the table itself */ - dispsocketlist_t *sock_table; /*%< socket table */ + dns_displist_t *qid_table; /*%< the table itself */ } dns_qid_t; struct dns_dispatchmgr { @@ -57,6 +55,7 @@ struct dns_dispatchmgr { isc_mem_t *mctx; dns_acl_t *blackhole; isc_stats_t *stats; + isc_nm_t *nm; /* Locked by "lock". */ isc_mutex_t lock; @@ -66,8 +65,7 @@ struct dns_dispatchmgr { /* locked by buffer_lock */ dns_qid_t *qid; isc_mutex_t buffer_lock; - unsigned int buffers; /*%< allocated buffers */ - unsigned int buffersize; /*%< size of each buffer */ + unsigned int buffers; isc_refcount_t irefs; @@ -86,9 +84,13 @@ struct dns_dispentry { dns_messageid_t id; in_port_t port; unsigned int bucket; - isc_sockaddr_t host; + unsigned int timeout; + isc_sockaddr_t peer; isc_task_t *task; + isc_nm_cb_t connected; + isc_nm_cb_t sent; isc_taskaction_t action; + isc_taskaction_t timeout_action; void *arg; bool item_out; dispsocket_t *dispsocket; @@ -105,51 +107,24 @@ struct dns_dispentry { struct dispsocket { unsigned int magic; - isc_socket_t *socket; + isc_nmhandle_t *handle; dns_dispatch_t *disp; - isc_sockaddr_t host; + isc_sockaddr_t local; + isc_sockaddr_t peer; dns_dispentry_t *resp; - isc_task_t *task; in_port_t port; ISC_LINK(dispsocket_t) link; - unsigned int bucket; - ISC_LINK(dispsocket_t) blink; }; -typedef struct tcpmsg { - uint16_t size; - dns_dispatch_t *disp; - isc_buffer_t buffer; - isc_task_t *task; - isc_taskaction_t action; - void *arg; - isc_event_t event; - isc_result_t result; - isc_sockaddr_t address; -} tcpmsg_t; - -/*% - * Number of tasks for each dispatch that use separate sockets for different - * transactions. This must be a power of 2 as it will divide 32 bit numbers - * to get an uniformly random tasks selection. See get_dispsocket(). - */ -#define MAX_INTERNAL_TASKS 64 - struct dns_dispatch { /* Unlocked. */ unsigned int magic; /*%< magic */ dns_dispatchmgr_t *mgr; /*%< dispatch manager */ - int ntasks; - /*% - * internal task buckets. We use multiple tasks to distribute various - * socket events well when using separate dispatch sockets. We use the - * 1st task (task[0]) for internal control events. - */ - isc_task_t *task[MAX_INTERNAL_TASKS]; - isc_socket_t *socket; /*%< isc socket attached to */ - isc_sockaddr_t local; /*%< local address */ - in_port_t localport; /*%< local UDP port */ - isc_sockaddr_t peer; /*%< peer address (TCP) */ + isc_task_t *task; + isc_nmhandle_t *handle; /*%< netmgr handle for TCP connection */ + isc_sockaddr_t local; /*%< local address */ + in_port_t localport; /*%< local UDP port */ + isc_sockaddr_t peer; /*%< peer address (TCP) */ isc_event_t *ctlevent; isc_mem_t *sepool; /*%< pool for socket events */ @@ -159,19 +134,17 @@ struct dns_dispatch { /* Locked by "lock". */ isc_mutex_t lock; /*%< locks all below */ - isc_sockettype_t socktype; + isc_socktype_t socktype; unsigned int attributes; isc_refcount_t refcount; dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ - unsigned int shutting_down : 1, shutdown_out : 1, recv_pending : 1, - tcpmsg_valid : 1; + unsigned int shutting_down : 1, shutdown_out : 1, recv_pending : 1; isc_result_t shutdown_why; ISC_LIST(dispsocket_t) activesockets; ISC_LIST(dispsocket_t) inactivesockets; unsigned int nsockets; unsigned int requests; /*%< how many requests we have */ unsigned int tcpbuffers; /*%< allocated buffers */ - tcpmsg_t tcpmsg; }; #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') @@ -212,11 +185,11 @@ struct dns_dispatch { #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ /*% - * Number of buffers available for all dispatches in the buffery memory - * pool. + * Number of buffers available for all dispatches in the buffer + * memory pool. */ #ifndef DNS_DISPATCH_MAXBUFFERS -#define DNS_DISPATCH_MAXBUFFERS 32768 +#define DNS_DISPATCH_MAXBUFFERS 37268 #endif /* ifndef DNS_DISPATCH_MAXBUFFERS */ /*% @@ -264,17 +237,13 @@ destroy_dispsocket(dns_dispatch_t *, dispsocket_t **); static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *); static void -udp_recv(isc_task_t *, isc_event_t *); +udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg); static void -tcp_recv(isc_task_t *, isc_event_t *); -static isc_result_t -startrecv(dns_dispatch_t *, dispsocket_t *); +tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg); static uint32_t dns_hash(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t); -static void -free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); -static void * -allocate_udp_buffer(dns_dispatch_t *disp); static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); static inline dns_dispatchevent_t * @@ -288,9 +257,9 @@ linear_next(dns_qid_t *disp, dns_dispentry_t *resp); static void dispatch_free(dns_dispatch_t **dispp); static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp); +dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp); static bool destroy_mgr_ok(dns_dispatchmgr_t *mgr); static void @@ -299,13 +268,12 @@ static void qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp); static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp); -static isc_result_t -open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp); -static isc_socket_t * -getentrysocket(dns_dispentry_t *resp); -static isc_socket_t * -getsocket(dns_dispatch_t *disp); +static isc_nmhandle_t * +gethandle(dns_dispatch_t *disp); +static isc_nmhandle_t * +getentryhandle(dns_dispentry_t *resp); +static void +startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket); #define LVL(x) ISC_LOG_DEBUG(x) @@ -387,7 +355,7 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, va_end(ap); if (VALID_RESPONSE(resp)) { - isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf)); + isc_sockaddr_format(&resp->peer, peerbuf, sizeof(peerbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH, level, "dispatch %p response %p %s: %s", disp, resp, @@ -498,7 +466,6 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { dns_dispatchmgr_t *mgr = NULL; bool killmgr; dispsocket_t *dispsocket = NULL; - int i; INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL); @@ -510,23 +477,21 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { LOCK(&mgr->lock); ISC_LIST_UNLINK(mgr->list, disp, link); - dispatch_log(disp, LVL(90), "shutting down; detaching from sock %p", - disp->socket); + dispatch_log(disp, LVL(90), "shutting down; detaching from handle %p", + disp->handle); if (disp->sepool != NULL) { isc_mem_destroy(&disp->sepool); } - if (disp->socket != NULL) { - isc_socket_detach(&disp->socket); + if (disp->handle != NULL) { + isc_nmhandle_detach(&disp->handle); } while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) { ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link); destroy_dispsocket(disp, &dispsocket); } - for (i = 0; i < disp->ntasks; i++) { - isc_task_detach(&disp->task[i]); - } + isc_task_detach(&disp->task); isc_event_free(&event); dispatch_free(&disp); @@ -538,47 +503,15 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { } } -/*% - * Find a dispsocket for socket address 'dest', and port number 'port'. - * Return NULL if no such entry exists. Requires qid->lock to be held. - */ -static dispsocket_t * -socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port, - unsigned int bucket) { - dispsocket_t *dispsock = NULL; - - REQUIRE(VALID_QID(qid)); - REQUIRE(bucket < qid->qid_nbuckets); - - dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); - - while (dispsock != NULL) { - if (dispsock->port == port && - isc_sockaddr_equal(dest, &dispsock->host)) { - return (dispsock); - } - dispsock = ISC_LIST_NEXT(dispsock, blink); - } - - return (NULL); -} - /*% * Make a new socket for a single dispatch with a random port number. * The caller must hold the disp->lock */ static isc_result_t get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, - isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp, - in_port_t *portp) { - int i; + dispsocket_t **dispsockp, in_port_t *portp) { dns_dispatchmgr_t *mgr = disp->mgr; - dns_qid_t *qid = mgr->qid; - isc_socket_t *sock = NULL; - isc_result_t result = ISC_R_FAILURE; in_port_t port; - isc_sockaddr_t localaddr; - unsigned int bucket = 0; dispsocket_t *dispsock = NULL; unsigned int nports; in_port_t *ports = NULL; @@ -597,71 +530,23 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, dispsock = ISC_LIST_HEAD(disp->inactivesockets); if (dispsock != NULL) { ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link); - sock = dispsock->socket; - dispsock->socket = NULL; } else { dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock)); - disp->nsockets++; *dispsock = (dispsocket_t){ .disp = disp }; - isc_task_attach(disp->task[isc_random_uniform(disp->ntasks)], - &dispsock->task); ISC_LINK_INIT(dispsock, link); - ISC_LINK_INIT(dispsock, blink); dispsock->magic = DISPSOCK_MAGIC; } - /* - * Pick up a random UDP port and open a new socket with it. Avoid - * choosing ports that share the same destination because it will be - * very likely to fail in bind(2) or connect(2). - */ - localaddr = disp->local; + dispsock->local = disp->local; + dispsock->peer = *dest; - for (i = 0; i < 64; i++) { - port = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&localaddr, port); - - LOCK(&qid->lock); - bucket = dns_hash(qid, dest, 0, port); - if (socket_search(qid, dest, port, bucket) != NULL) { - UNLOCK(&qid->lock); - continue; - } - UNLOCK(&qid->lock); - - result = open_socket(sockmgr, &localaddr, - ISC_SOCKET_REUSEADDRESS, &sock); - if (result == ISC_R_SUCCESS) { - break; - } else if (result == ISC_R_NOPERM) { - char buf[ISC_SOCKADDR_FORMATSIZE]; - isc_sockaddr_format(&localaddr, buf, sizeof(buf)); - dispatch_log(disp, ISC_LOG_WARNING, - "open_socket(%s) -> %s: continuing", buf, - isc_result_totext(result)); - } else if (result != ISC_R_ADDRINUSE) { - break; - } - } - - if (result != ISC_R_SUCCESS) { - if (sock != NULL) { - isc_socket_detach(&sock); - } - destroy_dispsocket(disp, &dispsock); - return (result); - } - - dispsock->socket = sock; - dispsock->host = *dest; - dispsock->bucket = bucket; + /* Pick a random UDP port */ + port = ports[isc_random_uniform(nports)]; + isc_sockaddr_setport(&dispsock->local, port); dispsock->port = port; - LOCK(&qid->lock); - ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); - UNLOCK(&qid->lock); *dispsockp = dispsock; *portp = port; @@ -670,77 +555,52 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, /*% * Destroy a dedicated dispatch socket. + * The dispatch must be locked. */ static void destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { dispsocket_t *dispsock = NULL; - dns_qid_t *qid = disp->mgr->qid; - - /* - * The dispatch must be locked. - */ REQUIRE(dispsockp != NULL && *dispsockp != NULL); + dispsock = *dispsockp; *dispsockp = NULL; + REQUIRE(!ISC_LINK_LINKED(dispsock, link)); disp->nsockets--; dispsock->magic = 0; - if (dispsock->socket != NULL) { - isc_socket_detach(&dispsock->socket); - } - if (ISC_LINK_LINKED(dispsock, blink)) { - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, - blink); - UNLOCK(&qid->lock); - } - if (dispsock->task != NULL) { - isc_task_detach(&dispsock->task); + if (dispsock->handle != NULL) { + isc_nm_cancelread(dispsock->handle); + isc_nmhandle_detach(&dispsock->handle); } + isc_mem_put(disp->mgr->mctx, dispsock, sizeof(*dispsock)); } /*% * Deactivate a dedicated dispatch socket. Move it to the inactive list for * future reuse unless the total number of sockets are exceeding the maximum. + * The dispatch must be locked. */ static void deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_result_t result; - dns_qid_t *qid = disp->mgr->qid; - - /* - * The dispatch must be locked. - */ ISC_LIST_UNLINK(disp->activesockets, dispsock, link); if (dispsock->resp != NULL) { INSIST(dispsock->resp->dispsocket == dispsock); dispsock->resp->dispsocket = NULL; + dispsock->resp = NULL; } if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) { destroy_dispsocket(disp, &dispsock); } else { - result = isc_socket_close(dispsock->socket); - - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, - blink); - UNLOCK(&qid->lock); - - if (result == ISC_R_SUCCESS) { - ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); - } else { - /* - * If the underlying system does not allow this - * optimization, destroy this temporary structure (and - * create a new one for a new transaction). - */ - INSIST(result == ISC_R_NOTIMPLEMENTED); - destroy_dispsocket(disp, &dispsock); + if (dispsock->handle != NULL) { + isc_nm_cancelread(dispsock->handle); + isc_nmhandle_detach(&dispsock->handle); } + + ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); } } @@ -760,7 +620,7 @@ entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, res = ISC_LIST_HEAD(qid->qid_table[bucket]); while (res != NULL) { - if (res->id == id && isc_sockaddr_equal(dest, &res->host) && + if (res->id == id && isc_sockaddr_equal(dest, &res->peer) && res->port == port) { return (res); } @@ -775,12 +635,12 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { REQUIRE(buf != NULL && len != 0); switch (disp->socktype) { - case isc_sockettype_tcp: + case isc_socktype_tcp: INSIST(disp->tcpbuffers > 0); disp->tcpbuffers--; isc_mem_put(disp->mgr->mctx, buf, len); break; - case isc_sockettype_udp: + case isc_socktype_udp: LOCK(&disp->mgr->buffer_lock); INSIST(disp->mgr->buffers > 0); INSIST(len == DNS_DISPATCH_UDPBUFSIZE); @@ -807,33 +667,6 @@ allocate_udp_buffer(dns_dispatch_t *disp) { return (isc_mem_get(disp->mgr->mctx, DNS_DISPATCH_UDPBUFSIZE)); } -static inline void -free_sevent(isc_event_t *ev) { - isc_mem_t *pool = ev->ev_destroy_arg; - isc_socketevent_t *sev = (isc_socketevent_t *)ev; - isc_mem_put(pool, sev, sizeof(*sev)); -} - -static inline isc_socketevent_t * -allocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock, isc_eventtype_t type, - isc_taskaction_t action, const void *arg) { - isc_socketevent_t *ev = NULL; - void *deconst_arg; - - ev = isc_mem_get(disp->sepool, sizeof(*ev)); - DE_CONST(arg, deconst_arg); - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type, action, deconst_arg, - sock, free_sevent, disp->sepool); - ev->result = ISC_R_UNSET; - ISC_LINK_INIT(ev, ev_link); - ev->region.base = NULL; - ev->n = 0; - ev->offset = 0; - ev->attributes = 0; - - return (ev); -} - static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { if (disp->failsafe_ev == ev) { @@ -843,6 +676,12 @@ free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { return; } + if (ev->region.base != NULL) { + free_buffer(disp, ev->region.base, ev->region.length); + ev->region.base = NULL; + ev->region.length = 0; + } + isc_refcount_decrement(&disp->mgr->irefs); isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev)); } @@ -853,6 +692,8 @@ allocate_devent(dns_dispatch_t *disp) { ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); isc_refcount_increment0(&disp->mgr->irefs); + + *ev = (dns_dispatchevent_t){ 0 }; ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, NULL); return (ev); @@ -873,9 +714,9 @@ allocate_devent(dns_dispatch_t *disp) { * restart. */ static void -udp_recv(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - dispsocket_t *dispsock = NULL; +udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg) { + dispsocket_t *dispsock = (dispsocket_t *)arg; dns_dispatch_t *disp = NULL; dns_messageid_t id; isc_result_t dres; @@ -886,15 +727,10 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { bool killit; bool queue_response; dns_dispatchmgr_t *mgr = NULL; + isc_sockaddr_t peer; isc_netaddr_t netaddr; + isc_taskaction_t action; int match; - int result; - - UNUSED(task); - - REQUIRE(ev->ev_type == ISC_SOCKEVENT_RECVDONE); - - dispsock = ev_in->ev_arg; REQUIRE(VALID_DISPSOCK(dispsock)); @@ -905,44 +741,32 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { mgr = disp->mgr; LOCK(&disp->mgr->buffer_lock); - dispatch_log(disp, LVL(90), - "got packet: requests %d, buffers %d, recvs %d", - disp->requests, disp->mgr->buffers, disp->recv_pending); + dispatch_log(disp, LVL(90), "got packet: requests %d, recvs %d", + disp->requests, disp->recv_pending); UNLOCK(&disp->mgr->buffer_lock); - if (ev->result == ISC_R_CANCELED || dispsock->resp == NULL) { + if (eresult == ISC_R_CANCELED || dispsock->resp == NULL) { /* * dispsock->resp can be NULL if this transaction was canceled - * just after receiving a response. Since this socket is - * exclusively used and there should be at most one receive - * event the canceled event should have no effect. So - * we can (and should) deactivate the socket right now. + * just after receiving a response. So we can just move on. */ - deactivate_dispsocket(disp, dispsock); dispsock = NULL; } - if (disp->shutting_down) { + if (disp->shutting_down == 1) { /* * This dispatcher is shutting down. */ - free_buffer(disp, ev->region.base, ev->region.length); - - isc_event_free(&ev_in); - ev = NULL; - killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + isc_task_send(disp->task, &disp->ctlevent); } return; } if (dispsock == NULL) { - free_buffer(disp, ev->region.base, ev->region.length); - isc_event_free(&ev_in); UNLOCK(&disp->lock); return; } @@ -950,20 +774,22 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { resp = dispsock->resp; id = resp->id; - if (ev->result != ISC_R_SUCCESS) { + peer = isc_nmhandle_peeraddr(handle); + isc_netaddr_fromsockaddr(&netaddr, &peer); + + if (eresult != ISC_R_SUCCESS) { /* - * This is most likely a network error on a - * connected socket. It makes no sense to + * This is most likely either a timeout or a network + * error on a connected socket. It makes no sense to * check the address or parse the packet, but it * will help to return the error to the caller. */ - goto sendresponse; + goto sendevent; } /* * If this is from a blackholed address, drop it. */ - isc_netaddr_fromsockaddr(&netaddr, &ev->address); if (disp->mgr->blackhole != NULL && dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match, NULL) == ISC_R_SUCCESS && @@ -976,20 +802,18 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { dispatch_log(disp, LVL(10), "blackholed packet from %s", netaddrstr); } - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } /* * Peek into the buffer to see what we can see. */ - isc_buffer_init(&source, ev->region.base, ev->region.length); - isc_buffer_add(&source, ev->n); + isc_buffer_init(&source, region->base, region->length); + isc_buffer_add(&source, region->length); dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { - free_buffer(disp, ev->region.base, ev->region.length); dispatch_log(disp, LVL(10), "got garbage packet"); - goto restart; + goto next; } dispatch_log(disp, LVL(92), @@ -1002,105 +826,55 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* query */ - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } /* * The QID and the address must match the expected ones. */ - if (resp->id != id || !isc_sockaddr_equal(&ev->address, &resp->host)) { + if (resp->id != id || !isc_sockaddr_equal(&peer, &resp->peer)) { dispatch_log(disp, LVL(90), "response doesn't match"); inc_stats(mgr, dns_resstatscounter_mismatch); - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } - /* - * Now that we have the original dispatch the query was sent - * from check that the address and port the response was - * sent to make sense. - */ - if (disp != resp->disp) { - isc_sockaddr_t a1; - isc_sockaddr_t a2; - - /* - * Check that the socket types and ports match. - */ - if (disp->socktype != resp->disp->socktype || - isc_sockaddr_getport(&disp->local) != - isc_sockaddr_getport(&resp->disp->local)) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; - } - - /* - * If each dispatch is bound to a different address - * then fail. - * - * Note under Linux a packet can be sent out via IPv4 socket - * and the response be received via a IPv6 socket. - * - * Requests sent out via IPv6 should always come back in - * via IPv6. - */ - if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 && - isc_sockaddr_pf(&disp->local) != PF_INET6) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; - } - isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); - isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); - if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) && - !isc_sockaddr_eqaddr(&a1, &resp->disp->local) && - !isc_sockaddr_eqaddr(&a2, &disp->local)) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; - } - } - -sendresponse: +sendevent: + rev = allocate_devent(disp); queue_response = resp->item_out; - rev = allocate_devent(resp->disp); /* * At this point, rev contains the event we want to fill in, and * resp contains the information on the place to send it to. * Send the event off. */ - isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length); - isc_buffer_add(&rev->buffer, ev->n); - rev->result = ev->result; - rev->id = id; - rev->addr = ev->address; - rev->pktinfo = ev->pktinfo; - rev->attributes = ev->attributes; + rev->result = eresult; + resp->item_out = true; + if (region != NULL) { + rev->region.base = allocate_udp_buffer(disp); + rev->region.length = DNS_DISPATCH_UDPBUFSIZE; + memmove(rev->region.base, region->base, region->length); + isc_buffer_init(&rev->buffer, rev->region.base, + rev->region.length); + isc_buffer_add(&rev->buffer, rev->region.length); + } + + rev->result = eresult; if (queue_response) { ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); + action, resp->arg, resp, NULL, NULL); request_log(disp, resp, LVL(90), "[a] Sent event %p buffer %p len %d to task %p", rev, rev->buffer.base, rev->buffer.length, resp->task); - resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } - /* - * Restart recv() to get the next packet. - */ -restart: - result = startrecv(disp, dispsock); - if (result != ISC_R_SUCCESS) { - deactivate_dispsocket(disp, dispsock); - } - isc_event_free(&ev_in); + UNLOCK(&disp->lock); + return; + +next: UNLOCK(&disp->lock); } @@ -1120,9 +894,9 @@ restart: * restart. */ static void -tcp_recv(isc_task_t *task, isc_event_t *ev_in) { - dns_dispatch_t *disp = ev_in->ev_arg; - tcpmsg_t *tcpmsg = &disp->tcpmsg; +tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg) { + dns_dispatch_t *disp = (dns_dispatch_t *)arg; dns_messageid_t id; isc_result_t dres; unsigned int flags; @@ -1134,8 +908,9 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { dns_qid_t *qid = NULL; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; - - UNUSED(task); + isc_buffer_t source; + isc_sockaddr_t peer; + isc_taskaction_t action; REQUIRE(VALID_DISPATCH(disp)); @@ -1154,11 +929,16 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { /* * This dispatcher is shutting down. Force cancellation. */ - tcpmsg->result = ISC_R_CANCELED; + eresult = ISC_R_CANCELED; } - if (tcpmsg->result != ISC_R_SUCCESS) { - switch (tcpmsg->result) { + peer = isc_nmhandle_peeraddr(handle); + isc_nmhandle_detach(&handle); + + if (eresult != ISC_R_SUCCESS) { + disp->shutdown_why = eresult; + + switch (eresult) { case ISC_R_CANCELED: break; @@ -1171,27 +951,23 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { level = ISC_LOG_INFO; goto logit; + case ISC_R_TIMEDOUT: + id = 0; /* XXX this is broken */ + goto sendevent; + default: level = ISC_LOG_ERROR; logit: - isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf)); + isc_sockaddr_format(&peer, buf, sizeof(buf)); dispatch_log(disp, level, "shutting down due to TCP " "receive error: %s: %s", - buf, isc_result_totext(tcpmsg->result)); + buf, isc_result_totext(eresult)); do_cancel(disp); break; } - /* - * The event is statically allocated in the tcpmsg - * structure, and destroy_disp() frees the tcpmsg, so we must - * free the event *before* calling destroy_disp(). - */ - isc_event_free(&ev_in); - disp->shutting_down = 1; - disp->shutdown_why = tcpmsg->result; /* * If the recv() was canceled pass the word on. @@ -1199,22 +975,23 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + isc_task_send(disp->task, &disp->ctlevent); } return; } dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", - tcpmsg->result, disp->tcpmsg.buffer.length, - disp->tcpmsg.buffer.base); + eresult, region->length, region->base); /* * Peek into the buffer to see what we can see. */ - dres = dns_message_peekheader(&disp->tcpmsg.buffer, &id, &flags); + isc_buffer_init(&source, region->base, region->length); + isc_buffer_add(&source, region->length); + dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { dispatch_log(disp, LVL(10), "got garbage packet"); - goto restart; + goto next; } dispatch_log(disp, LVL(92), @@ -1234,19 +1011,21 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { /* * Query. */ - goto restart; + goto next; } +sendevent: /* * Response. */ - bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport); + bucket = dns_hash(qid, &peer, id, disp->localport); LOCK(&qid->lock); - resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket); + resp = entry_search(qid, &peer, id, disp->localport, bucket); dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); if (resp == NULL) { - goto unlock; + UNLOCK(&qid->lock); + goto next; } queue_response = resp->item_out; @@ -1257,212 +1036,36 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { * resp contains the information on the place to send it to. * Send the event off. */ - rev->buffer = disp->tcpmsg.buffer; - disp->tcpmsg.buffer.base = NULL; - disp->tcpmsg.buffer.length = 0; + rev->result = eresult; + resp->item_out = true; + if (region != NULL) { + disp->tcpbuffers++; + rev->region.base = isc_mem_get(disp->mgr->mctx, region->length); + rev->region.length = region->length; + memmove(rev->region.base, region->base, region->length); + isc_buffer_init(&rev->buffer, rev->region.base, + rev->region.length); + isc_buffer_add(&rev->buffer, rev->region.length); + } - disp->tcpbuffers++; - rev->result = ISC_R_SUCCESS; - rev->id = id; - rev->addr = tcpmsg->address; if (queue_response) { ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); + action, resp->arg, resp, NULL, NULL); request_log(disp, resp, LVL(90), "[b] Sent event %p buffer %p len %d to task %p", rev, rev->buffer.base, rev->buffer.length, resp->task); - resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } -unlock: UNLOCK(&qid->lock); - /* - * Restart recv() to get the next packet. - */ -restart: - (void)startrecv(disp, NULL); - - isc_event_free(&ev_in); +next: + startrecv(disp, NULL); UNLOCK(&disp->lock); } -static void -recv_tcpmsg(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - tcpmsg_t *tcpmsg = ev_in->ev_arg; - isc_event_t *dev = &tcpmsg->event; - - UNUSED(task); - - tcpmsg->address = ev->address; - - if (ev->result != ISC_R_SUCCESS) { - tcpmsg->result = ev->result; - goto send_and_free; - } - - tcpmsg->result = ISC_R_SUCCESS; - isc_buffer_add(&tcpmsg->buffer, ev->n); - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); -} - -static void -recv_tcplen(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - tcpmsg_t *tcpmsg = ev_in->ev_arg; - isc_event_t *dev = &tcpmsg->event; - isc_region_t region; - isc_result_t result; - - tcpmsg->address = ev->address; - - if (ev->result != ISC_R_SUCCESS) { - tcpmsg->result = ev->result; - goto send_and_free; - } - - /* - * Success. - */ - tcpmsg->size = ntohs(tcpmsg->size); - if (tcpmsg->size == 0) { - tcpmsg->result = ISC_R_UNEXPECTEDEND; - goto send_and_free; - } - - region.base = isc_mem_get(tcpmsg->disp->mgr->mctx, tcpmsg->size); - region.length = tcpmsg->size; - if (region.base == NULL) { - tcpmsg->result = ISC_R_NOMEMORY; - goto send_and_free; - } - - isc_buffer_init(&tcpmsg->buffer, region.base, region.length); - result = isc_socket_recv(tcpmsg->disp->socket, ®ion, 0, task, - recv_tcpmsg, tcpmsg); - if (result != ISC_R_SUCCESS) { - tcpmsg->result = result; - goto send_and_free; - } - - isc_event_free(&ev_in); - return; - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); - return; -} - -static isc_result_t -tcp_readmessage(tcpmsg_t *tcpmsg, isc_task_t *task, isc_taskaction_t action, - void *arg) { - isc_result_t result; - isc_region_t region; - - REQUIRE(task != NULL); - REQUIRE(tcpmsg->task == NULL); /* not currently in use */ - - if (tcpmsg->buffer.base != NULL) { - isc_mem_put(tcpmsg->disp->mgr->mctx, tcpmsg->buffer.base, - tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - } - - tcpmsg->task = task; - tcpmsg->action = action; - tcpmsg->arg = arg; - tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */ - - ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0, - DNS_EVENT_TCPMSG, action, arg, tcpmsg, NULL, NULL); - - region.base = (unsigned char *)&tcpmsg->size; - region.length = 2; /* uint16_t */ - result = isc_socket_recv(tcpmsg->disp->socket, ®ion, 0, tcpmsg->task, - recv_tcplen, tcpmsg); - - if (result != ISC_R_SUCCESS) { - tcpmsg->task = NULL; - } - - return (result); -} - -/* - * disp must be locked. - */ -static isc_result_t -startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_result_t res; - isc_region_t region; - isc_socket_t *sock = NULL; - isc_socketevent_t *sev = NULL; - - if (disp->shutting_down == 1) { - return (ISC_R_SUCCESS); - } - - if (dispsock == NULL) { - if (disp->socktype == isc_sockettype_udp || - disp->recv_pending != 0) { - return (ISC_R_SUCCESS); - } - sock = disp->socket; - } else { - sock = dispsock->socket; - } - - switch (disp->socktype) { - /* - * UDP reads are always maximal. - */ - case isc_sockettype_udp: - region.length = DNS_DISPATCH_UDPBUFSIZE; - region.base = allocate_udp_buffer(disp); - if (region.base == NULL) { - return (ISC_R_NOMEMORY); - } - sev = allocate_sevent(disp, sock, ISC_SOCKEVENT_RECVDONE, - udp_recv, dispsock); - res = isc_socket_recv2(sock, ®ion, 1, dispsock->task, sev, - 0); - if (res != ISC_R_SUCCESS) { - free_buffer(disp, region.base, region.length); - return (res); - } - break; - - case isc_sockettype_tcp: - res = tcp_readmessage(&disp->tcpmsg, disp->task[0], tcp_recv, - disp); - if (res != ISC_R_SUCCESS) { - disp->shutdown_why = res; - disp->shutting_down = 1; - do_cancel(disp); - return (ISC_R_SUCCESS); /* recover by cancel */ - } - INSIST(disp->recv_pending == 0); - disp->recv_pending = 1; - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } - - return (ISC_R_SUCCESS); -} - /* * Mgr must be locked when calling this function. */ @@ -1520,48 +1123,12 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { isc_mem_put(mgr->mctx, mgr->v6ports, mgr->nv6ports * sizeof(in_port_t)); } + + isc_nm_detach(&mgr->nm); + isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); } -static isc_result_t -open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp) { - isc_socket_t *sock = NULL; - isc_result_t result; - - sock = *sockp; - if (sock != NULL) { - result = isc_socket_open(sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - } else { - result = isc_socket_create(mgr, isc_sockaddr_pf(local), - isc_sockettype_udp, &sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - } - - isc_socket_setname(sock, "dispatcher", NULL); - -#ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(sock, true); -#endif /* ifndef ISC_ALLOW_MAPPED */ - result = isc_socket_bind(sock, local, options); - if (result != ISC_R_SUCCESS) { - if (*sockp == NULL) { - isc_socket_detach(&sock); - } else { - isc_socket_close(sock); - } - return (result); - } - - *sockp = sock; - return (ISC_R_SUCCESS); -} - /*% * Create a temporary port list to set the initial default set of dispatch * ports: [1024, 65535]. This is almost meaningless as the application will @@ -1626,7 +1193,8 @@ setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, */ isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { +dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, + dns_dispatchmgr_t **mgrp) { dns_dispatchmgr_t *mgr = NULL; isc_portset_t *v4portset = NULL; isc_portset_t *v6portset = NULL; @@ -1635,15 +1203,16 @@ dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { REQUIRE(mgrp != NULL && *mgrp == NULL); mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); - *mgr = (dns_dispatchmgr_t){ 0 }; + *mgr = (dns_dispatchmgr_t){ .magic = 0 }; + + isc_refcount_init(&mgr->irefs, 0); isc_mem_attach(mctx, &mgr->mctx); + isc_nm_attach(nm, &mgr->nm); isc_mutex_init(&mgr->lock); isc_mutex_init(&mgr->buffer_lock); - isc_refcount_init(&mgr->irefs, 0); - ISC_LIST_INIT(mgr->list); create_default_portset(mctx, &v4portset); @@ -1728,16 +1297,11 @@ qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp) { qid->qid_table = isc_mem_get(mgr->mctx, DNS_QID_BUCKETS * sizeof(dns_displist_t)); - qid->sock_table = isc_mem_get( - mgr->mctx, DNS_QID_BUCKETS * sizeof(dispsocketlist_t)); - - isc_mutex_init(&qid->lock); - for (i = 0; i < qid->qid_nbuckets; i++) { ISC_LIST_INIT(qid->qid_table[i]); - ISC_LIST_INIT(qid->sock_table[i]); } + isc_mutex_init(&qid->lock); qid->magic = QID_MAGIC; *qidp = qid; } @@ -1755,8 +1319,6 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { qid->magic = 0; isc_mem_put(mctx, qid->qid_table, qid->qid_nbuckets * sizeof(dns_displist_t)); - isc_mem_put(mctx, qid->sock_table, - qid->qid_nbuckets * sizeof(dispsocketlist_t)); isc_mutex_destroy(&qid->lock); isc_mem_put(mctx, qid, sizeof(*qid)); } @@ -1765,7 +1327,7 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { * Allocate and set important limits. */ static void -dispatch_allocate(dns_dispatchmgr_t *mgr, isc_sockettype_t type, int pf, +dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf, unsigned int attributes, dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; @@ -1789,10 +1351,10 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_sockettype_t type, int pf, ISC_LIST_INIT(disp->inactivesockets); switch (type) { - case isc_sockettype_tcp: + case isc_socktype_tcp: disp->attributes |= DNS_DISPATCHATTR_TCP; break; - case isc_sockettype_udp: + case isc_socktype_udp: disp->attributes |= DNS_DISPATCHATTR_UDP; break; default: @@ -1842,25 +1404,18 @@ dispatch_free(dns_dispatch_t **dispp) { mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); - if (disp->tcpmsg_valid) { - if (disp->tcpmsg.buffer.base != NULL) { - isc_mem_put(disp->mgr->mctx, disp->tcpmsg.buffer.base, - disp->tcpmsg.buffer.length); - disp->tcpmsg.buffer.base = NULL; - disp->tcpmsg.buffer.length = 0; - } - disp->tcpmsg_valid = 0; - } - - INSIST(disp->tcpbuffers == 0); INSIST(disp->requests == 0); INSIST(disp->recv_pending == 0); INSIST(ISC_LIST_EMPTY(disp->activesockets)); INSIST(ISC_LIST_EMPTY(disp->inactivesockets)); isc_refcount_decrement(&mgr->irefs); - isc_mem_put(mgr->mctx, disp->failsafe_ev, sizeof(*disp->failsafe_ev)); - disp->failsafe_ev = NULL; + + if (disp->failsafe_ev != NULL) { + isc_mem_put(mgr->mctx, disp->failsafe_ev, + sizeof(*disp->failsafe_ev)); + disp->failsafe_ev = NULL; + } disp->mgr = NULL; isc_mutex_destroy(&disp->lock); @@ -1870,74 +1425,43 @@ dispatch_free(dns_dispatch_t **dispp) { } isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, const isc_sockaddr_t *destaddr, unsigned int attributes, isc_dscp_t dscp, dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; - isc_sockaddr_t src; int pf; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(sockmgr != NULL); REQUIRE(destaddr != NULL); + UNUSED(dscp); + LOCK(&mgr->lock); pf = isc_sockaddr_pf(destaddr); - dispatch_allocate(mgr, isc_sockettype_tcp, pf, attributes, &disp); + dispatch_allocate(mgr, isc_socktype_tcp, pf, attributes, &disp); disp->peer = *destaddr; if (localaddr != NULL) { disp->local = *localaddr; } else { - switch (pf) { - case AF_INET: - isc_sockaddr_any(&disp->local); - break; - case AF_INET6: - isc_sockaddr_any6(&disp->local); - break; - } + isc_sockaddr_anyofpf(&disp->local, pf); + isc_sockaddr_setport(&disp->local, 0); } - disp->ntasks = 1; - disp->task[0] = NULL; - result = isc_task_create(taskmgr, 50, &disp->task[0]); + result = isc_task_create(taskmgr, 50, &disp->task); if (result != ISC_R_SUCCESS) { goto cleanup; } - result = isc_socket_create(sockmgr, isc_sockaddr_pf(destaddr), - isc_sockettype_tcp, &disp->socket); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - if (localaddr == NULL) { - isc_sockaddr_anyofpf(&src, pf); - } else { - src = *localaddr; - isc_sockaddr_setport(&src, 0); - } - - result = isc_socket_bind(disp->socket, &src, 0); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - isc_socket_dscp(disp->socket, dscp); - disp->ctlevent = isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, destroy_disp, disp, sizeof(isc_event_t)); - isc_task_setname(disp->task[0], "tcpdispatch", disp); - - disp->tcpmsg = (tcpmsg_t){ .disp = disp, .result = ISC_R_UNEXPECTED }; - disp->tcpmsg_valid = 1; + isc_task_setname(disp->task, "tcpdispatch", disp); /* * Append it to the dispatcher list. @@ -1949,14 +1473,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, mgr_log(mgr, LVL(90), "dns_dispatch_createtcp: created TCP dispatch %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); + dispatch_log(disp, LVL(90), "created task %p", disp->task); } *dispp = disp; return (ISC_R_SUCCESS); cleanup: - isc_socket_detach(&disp->socket); dispatch_free(&disp); UNLOCK(&mgr->lock); @@ -1971,7 +1494,6 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, const isc_sockaddr_t *localaddr, bool *connected, dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; - isc_result_t result; isc_sockaddr_t peeraddr; isc_sockaddr_t sockname; unsigned int attributes, mask; @@ -1995,14 +1517,9 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, (localaddr == NULL || isc_sockaddr_eqaddr(localaddr, &disp->local))) { - result = isc_socket_getsockname(disp->socket, - &sockname); - if (result == ISC_R_SUCCESS) { - result = isc_socket_getpeername(disp->socket, - &peeraddr); - } - if (result == ISC_R_SUCCESS && - isc_sockaddr_equal(destaddr, &peeraddr) && + sockname = isc_nmhandle_localaddr(disp->handle); + peeraddr = isc_nmhandle_peeraddr(disp->handle); + if (isc_sockaddr_equal(destaddr, &peeraddr) && (localaddr == NULL || isc_sockaddr_eqaddr(localaddr, &sockname))) { @@ -2049,21 +1566,19 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, } isc_result_t -dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp) { +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(sockmgr != NULL); REQUIRE(localaddr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(dispp != NULL && *dispp == NULL); LOCK(&mgr->lock); - result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, - attributes, &disp); + result = dispatch_createudp(mgr, taskmgr, localaddr, attributes, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -2073,32 +1588,25 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, } static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp) { +dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp) { isc_result_t result = ISC_R_SUCCESS; dns_dispatch_t *disp = NULL; - isc_socket_t *sock = NULL; isc_sockaddr_t sa_any; - int pf, i = 0; + int pf; pf = isc_sockaddr_pf(localaddr); - dispatch_allocate(mgr, isc_sockettype_udp, pf, attributes, &disp); + dispatch_allocate(mgr, isc_socktype_udp, pf, attributes, &disp); /* - * For dispatches with a specified source address, we open a - * socket to make sure that address is available on the system, - * but we don't keep it open; sockets used for sending requests - * will be created later on demand. + * Check whether this address/port is available locally. */ isc_sockaddr_anyofpf(&sa_any, pf); if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock); - if (sock != NULL) { - isc_socket_detach(&sock); - } + result = isc_nm_checkaddr(localaddr, isc_socktype_udp); if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; + goto cleanup; } } @@ -2112,21 +1620,10 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, addrbuf); } - disp->socket = sock; disp->local = *localaddr; - disp->ntasks = MAX_INTERNAL_TASKS; - - for (i = 0; i < disp->ntasks; i++) { - disp->task[i] = NULL; - result = isc_task_create(taskmgr, 0, &disp->task[i]); - if (result != ISC_R_SUCCESS) { - while (--i >= 0) { - isc_task_shutdown(disp->task[i]); - isc_task_detach(&disp->task[i]); - } - goto kill_socket; - } - isc_task_setname(disp->task[i], "udpdispatch", disp); + result = isc_task_create(taskmgr, 0, &disp->task); + if (result != ISC_R_SUCCESS) { + goto cleanup; } disp->ctlevent = @@ -2143,10 +1640,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, ISC_LIST_APPEND(mgr->list, disp, link); mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */ - if (disp->socket != NULL) { - dispatch_log(disp, LVL(90), "created socket %p", disp->socket); - } + dispatch_log(disp, LVL(90), "created task %p", disp->task); *dispp = disp; @@ -2155,11 +1649,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, /* * Error returns. */ -kill_socket: - if (disp->socket != NULL) { - isc_socket_detach(&disp->socket); - } -deallocate_dispatch: +cleanup: dispatch_free(&disp); return (result); @@ -2178,60 +1668,67 @@ void dns_dispatch_detach(dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; dispsocket_t *dispsock = NULL; - bool killit; + bool killit = false; REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); disp = *dispp; *dispp = NULL; - LOCK(&disp->lock); if (isc_refcount_decrement(&disp->refcount) == 1) { - if (disp->recv_pending > 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); + LOCK(&disp->lock); + if (disp->recv_pending != 0 && disp->handle != NULL) { + isc_nm_cancelread(disp->handle); + } + if (disp->handle != NULL) { + isc_nmhandle_detach(&disp->handle); } for (dispsock = ISC_LIST_HEAD(disp->activesockets); dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) { - isc_socket_cancel(dispsock->socket, dispsock->task, - ISC_SOCKCANCEL_RECV); + if (dispsock->handle != NULL) { + isc_nmhandle_detach(&dispsock->handle); + } } disp->shutting_down = 1; + do_cancel(disp); + + killit = destroy_disp_ok(disp); + UNLOCK(&disp->lock); } dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, isc_refcount_current(&disp->refcount)); - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + isc_task_send(disp->task, &disp->ctlevent); } } isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, - const isc_sockaddr_t *dest, isc_task_t *task, - isc_taskaction_t action, void *arg, - dns_messageid_t *idp, dns_dispentry_t **resp, - isc_socketmgr_t *sockmgr) { + unsigned int timeout, const isc_sockaddr_t *dest, + isc_task_t *task, isc_nm_cb_t connected, + isc_nm_cb_t sent, isc_taskaction_t action, + isc_taskaction_t timeout_action, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp) { + isc_result_t result; dns_dispentry_t *res = NULL; - unsigned int bucket; + dispsocket_t *dispsocket = NULL; + dns_qid_t *qid = NULL; in_port_t localport = 0; dns_messageid_t id; - int i = 0; + unsigned int bucket; bool ok = false; - dns_qid_t *qid = NULL; - dispsocket_t *dispsocket = NULL; - isc_result_t result; + int i = 0; REQUIRE(VALID_DISPATCH(disp)); REQUIRE(task != NULL); REQUIRE(dest != NULL); REQUIRE(resp != NULL && *resp == NULL); REQUIRE(idp != NULL); - REQUIRE(disp->socktype == isc_sockettype_tcp || sockmgr != NULL); + REQUIRE(disp->socktype == isc_socktype_tcp || + disp->socktype == isc_socktype_udp); LOCK(&disp->lock); @@ -2247,7 +1744,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, qid = disp->mgr->qid; - if (disp->socktype == isc_sockettype_udp && + if (disp->socktype == isc_socktype_udp && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { dispsocket_t *oldestsocket = NULL; @@ -2264,7 +1761,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, rev = allocate_devent(oldestresp->disp); rev->buffer.base = NULL; rev->result = ISC_R_CANCELED; - rev->id = oldestresp->id; ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, oldestresp->action, oldestresp->arg, oldestresp, NULL, NULL); @@ -2281,12 +1777,11 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ISC_LIST_APPEND(disp->activesockets, oldestsocket, link); } - if (disp->socktype == isc_sockettype_udp) { + if (disp->socktype == isc_socktype_udp) { /* * Get a separate UDP socket with a random port number. */ - result = get_dispsocket(disp, dest, sockmgr, &dispsocket, - &localport); + result = get_dispsocket(disp, dest, &dispsocket, &localport); if (result != ISC_R_SUCCESS) { UNLOCK(&disp->lock); inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); @@ -2326,20 +1821,26 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); isc_refcount_increment0(&disp->mgr->irefs); - *res = (dns_dispentry_t){ .disp = disp, - .id = id, + + *res = (dns_dispentry_t){ .id = id, .port = localport, .bucket = bucket, - .host = *dest, + .timeout = timeout, + .peer = *dest, + .connected = connected, + .sent = sent, .action = action, + .timeout_action = timeout_action, .arg = arg, .dispsocket = dispsocket }; + + dns_dispatch_attach(disp, &res->disp); isc_task_attach(task, &res->task); + ISC_LIST_INIT(res->items); ISC_LINK_INIT(res, link); res->magic = RESPONSE_MAGIC; - isc_refcount_increment(&disp->refcount); disp->requests++; if (dispsocket != NULL) { @@ -2350,40 +1851,11 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); - inc_stats(disp->mgr, (disp->socktype == isc_sockettype_udp) - ? dns_resstatscounter_disprequdp - : dns_resstatscounter_dispreqtcp); - request_log(disp, res, LVL(90), "attached to task %p", res->task); - if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) || - ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) - { - result = startrecv(disp, dispsocket); - if (result != ISC_R_SUCCESS) { - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); - UNLOCK(&qid->lock); - - if (dispsocket != NULL) { - destroy_dispsocket(disp, &dispsocket); - } - - isc_refcount_decrement(&disp->refcount); - disp->requests--; - - dec_stats(disp->mgr, - (disp->socktype == isc_sockettype_udp) - ? dns_resstatscounter_disprequdp - : dns_resstatscounter_dispreqtcp); - - UNLOCK(&disp->lock); - isc_task_detach(&res->task); - isc_refcount_decrement(&disp->mgr->irefs); - isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - return (result); - } - } + inc_stats(disp->mgr, (disp->socktype == isc_socktype_udp) + ? dns_resstatscounter_disprequdp + : dns_resstatscounter_dispreqtcp); if (dispsocket != NULL) { ISC_LIST_APPEND(disp->activesockets, dispsocket, link); @@ -2391,7 +1863,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, UNLOCK(&disp->lock); - INSIST(disp->socktype == isc_sockettype_tcp || res->dispsocket != NULL); + INSIST(disp->socktype == isc_socktype_tcp || res->dispsocket != NULL); *idp = id; *resp = res; @@ -2399,20 +1871,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, return (ISC_R_SUCCESS); } -void -dns_dispatch_starttcp(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - - dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]); - - LOCK(&disp->lock); - if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) { - disp->attributes |= DNS_DISPATCHATTR_CONNECTED; - (void)startrecv(disp, NULL); - } - UNLOCK(&disp->lock); -} - isc_result_t dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { dns_dispatch_t *disp = NULL; @@ -2432,15 +1890,13 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { REQUIRE(resp->item_out); resp->item_out = false; - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } free_devent(disp, ev); if (disp->shutting_down == 1) { UNLOCK(&disp->lock); return (ISC_R_SHUTTINGDOWN); } + ev = ISC_LIST_HEAD(resp->items); if (ev != NULL) { ISC_LIST_UNLINK(resp->items, ev, ev_link); @@ -2452,7 +1908,11 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); } + + startrecv(disp, resp->dispsocket); + UNLOCK(&disp->lock); + return (ISC_R_SUCCESS); } @@ -2462,11 +1922,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, dns_dispatchmgr_t *mgr = NULL; dns_dispatch_t *disp = NULL; dns_dispentry_t *res = NULL; - dispsocket_t *dispsock = NULL; dns_dispatchevent_t *ev = NULL; unsigned int bucket; - bool killit; - unsigned int n; isc_eventlist_t events; dns_qid_t *qid = NULL; @@ -2477,7 +1934,9 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, *resp = NULL; disp = res->disp; + res->disp = NULL; REQUIRE(VALID_DISPATCH(disp)); + mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); qid = mgr->qid; @@ -2491,26 +1950,16 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, } LOCK(&disp->lock); - INSIST(disp->requests > 0); disp->requests--; - dec_stats(disp->mgr, (disp->socktype == isc_sockettype_udp) + dec_stats(disp->mgr, (disp->socktype == isc_socktype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - if (isc_refcount_decrement(&disp->refcount) == 1) { - if (disp->recv_pending > 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } - for (dispsock = ISC_LIST_HEAD(disp->activesockets); - dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) - { - isc_socket_cancel(dispsock->socket, dispsock->task, - ISC_SOCKCANCEL_RECV); - } - disp->shutting_down = 1; + if (res->dispsocket != NULL) { + deactivate_dispsocket(disp, res->dispsocket); } + UNLOCK(&disp->lock); bucket = res->bucket; @@ -2519,6 +1968,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, UNLOCK(&qid->lock); if (ev == NULL && res->item_out) { + unsigned int n; + /* * We've posted our event, but the caller hasn't gotten it * yet. Take it back. @@ -2536,88 +1987,130 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, if (ev != NULL) { REQUIRE(res->item_out); res->item_out = false; - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } free_devent(disp, ev); } request_log(disp, res, LVL(90), "detaching from task %p", res->task); isc_task_detach(&res->task); - if (res->dispsocket != NULL) { - isc_socket_cancel(res->dispsocket->socket, - res->dispsocket->task, ISC_SOCKCANCEL_RECV); - res->dispsocket->resp = NULL; - } - /* * Free any buffered responses as well */ ev = ISC_LIST_HEAD(res->items); while (ev != NULL) { ISC_LIST_UNLINK(res->items, ev, ev_link); - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } free_devent(disp, ev); ev = ISC_LIST_HEAD(res->items); } res->magic = 0; isc_refcount_decrement(&disp->mgr->irefs); isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - if (disp->shutting_down == 1) { - do_cancel(disp); - } else { - (void)startrecv(disp, NULL); - } - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); - } + dns_dispatch_detach(&disp); } -isc_result_t -dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, - isc_task_t *task, isc_taskaction_t action, void *arg) { - isc_socket_t *sock = NULL; - isc_sockaddr_t *address = NULL; +/* + * disp must be locked. + */ +static void +startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket) { + isc_nmhandle_t *handle = NULL; - if (resp != NULL) { - REQUIRE(VALID_RESPONSE(resp)); - sock = resp->dispsocket->socket; - address = &resp->host; - } else if (disp != NULL) { - REQUIRE(VALID_DISPATCH(disp)); - sock = disp->socket; - address = &disp->peer; + if (disp->shutting_down == 1) { + return; + } + + if (dispsocket == NULL) { + if (disp->socktype == isc_socktype_udp || + disp->recv_pending != 0) { + return; + } + isc_nmhandle_attach(disp->handle, &handle); } else { + handle = dispsocket->handle; + } + + switch (disp->socktype) { + case isc_socktype_udp: + isc_nm_read(handle, udp_recv, dispsocket); + break; + + case isc_socktype_tcp: + isc_nm_read(handle, tcp_recv, disp); + INSIST(disp->recv_pending == 0); + disp->recv_pending = 1; + break; + + default: INSIST(0); ISC_UNREACHABLE(); } +} - return (isc_socket_connect(sock, address, task, action, arg)); +static void +disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_dispentry_t *resp = (dns_dispentry_t *)arg; + dns_dispatch_t *disp = resp->disp; + dispsocket_t *dispsocket = NULL; + + if (eresult == ISC_R_SUCCESS) { + if (disp->socktype == isc_socktype_udp) { + dispsocket = resp->dispsocket; + isc_nmhandle_attach(handle, &dispsocket->handle); + } else if (disp->handle == NULL) { + disp->attributes |= DNS_DISPATCHATTR_CONNECTED; + isc_nmhandle_attach(handle, &disp->handle); + } + + startrecv(disp, dispsocket); + } + + if (resp->connected != NULL) { + resp->connected(handle, eresult, resp->arg); + } } isc_result_t -dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, - isc_socketevent_t *sendevent, isc_region_t *r, - const isc_sockaddr_t *address, isc_dscp_t dscp, - isc_taskaction_t action, void *arg) { - isc_result_t result; - isc_socket_t *sock = NULL; +dns_dispatch_connect(dns_dispentry_t *resp) { + dns_dispatch_t *disp = NULL; REQUIRE(VALID_RESPONSE(resp)); - REQUIRE(sendevent != NULL); - memset(sendevent, 0, sizeof(isc_socketevent_t)); - ISC_EVENT_INIT(sendevent, sizeof(isc_socketevent_t), 0, NULL, - ISC_SOCKEVENT_SENDDONE, action, arg, NULL, NULL, NULL); + disp = resp->disp; - sock = getentrysocket(resp); + switch (disp->socktype) { + case isc_socktype_tcp: + if (disp->handle != NULL) { + break; + } + isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer, + disp_connected, resp, resp->timeout, 0); + break; + case isc_socktype_udp: + isc_nm_udpconnect(disp->mgr->nm, &resp->dispsocket->local, + &resp->dispsocket->peer, disp_connected, resp, + resp->timeout, 0); + break; + default: + return (ISC_R_NOTIMPLEMENTED); + } + + return (ISC_R_SUCCESS); +} + +void +dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { + isc_nmhandle_t *handle = NULL; + + REQUIRE(VALID_RESPONSE(resp)); + + UNUSED(dscp); + + handle = getentryhandle(resp); + +#if 0 + /* XXX: no DSCP support */ if (dscp == -1) { sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; sendevent->dscp = 0; @@ -2628,43 +2121,39 @@ dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, isc_socket_dscp(sock, dscp); } } +#endif - if (tcp) { - address = NULL; - } - - result = isc_socket_sendto2(sock, r, task, address, NULL, sendevent, 0); - return (result); + isc_nm_send(handle, r, resp->sent, resp->arg); } void dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, bool connecting) { - isc_socket_t *sock = NULL; + isc_nmhandle_t *handle = NULL; REQUIRE(disp != NULL || resp != NULL); if (resp != NULL) { REQUIRE(VALID_RESPONSE(resp)); - sock = getentrysocket(resp); + handle = getentryhandle(resp); } else if (disp != NULL) { REQUIRE(VALID_DISPATCH(disp)); - sock = getsocket(disp); + handle = gethandle(disp); } else { INSIST(0); ISC_UNREACHABLE(); } - if (sock == NULL) { + if (handle == NULL) { return; } if (connecting) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); + // isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); } if (sending) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); + // isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); } } @@ -2703,6 +2192,7 @@ do_cancel(dns_dispatch_t *disp) { * Send the shutdown failsafe event to this resp. */ ev = disp->failsafe_ev; + disp->failsafe_ev = NULL; ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, resp->action, resp->arg, resp, NULL, NULL); ev->result = disp->shutdown_why; @@ -2717,21 +2207,21 @@ unlock: UNLOCK(&qid->lock); } -static isc_socket_t * -getsocket(dns_dispatch_t *disp) { +static isc_nmhandle_t * +gethandle(dns_dispatch_t *disp) { REQUIRE(VALID_DISPATCH(disp)); - return (disp->socket); + return (disp->handle); } -static isc_socket_t * -getentrysocket(dns_dispentry_t *resp) { +static isc_nmhandle_t * +getentryhandle(dns_dispentry_t *resp) { REQUIRE(VALID_RESPONSE(resp)); - if (resp->disp->socktype == isc_sockettype_tcp) { - return (resp->disp->socket); + if (resp->disp->socktype == isc_socktype_tcp) { + return (resp->disp->handle); } else if (resp->dispsocket != NULL) { - return (resp->dispsocket->socket); + return (resp->dispsocket->handle); } else { return (NULL); } @@ -2742,7 +2232,7 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) { REQUIRE(VALID_DISPATCH(disp)); REQUIRE(addrp != NULL); - if (disp->socktype == isc_sockettype_udp) { + if (disp->socktype == isc_socktype_udp) { *addrp = disp->local; return (ISC_R_SUCCESS); } @@ -2754,13 +2244,14 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) { REQUIRE(VALID_RESPONSE(resp)); REQUIRE(addrp != NULL); - if (resp->disp->socktype == isc_sockettype_tcp) { - return (isc_socket_getsockname(resp->disp->socket, addrp)); + if (resp->disp->socktype == isc_socktype_tcp) { + *addrp = resp->disp->local; + return (ISC_R_SUCCESS); } - if (resp->dispsocket != NULL) { - return (isc_socket_getsockname(resp->dispsocket->socket, - addrp)); + if (resp->dispsocket != NULL && resp->dispsocket->handle != NULL) { + *addrp = isc_nmhandle_localaddr(resp->dispsocket->handle); + return (ISC_R_SUCCESS); } return (ISC_R_NOTIMPLEMENTED); @@ -2810,9 +2301,9 @@ dns_dispatchset_get(dns_dispatchset_t *dset) { } isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t *source, - dns_dispatchset_t **dsetp, int n) { +dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + dns_dispatch_t *source, dns_dispatchset_t **dsetp, + int n) { isc_result_t result; dns_dispatchset_t *dset = NULL; dns_dispatchmgr_t *mgr = NULL; @@ -2839,8 +2330,8 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, LOCK(&mgr->lock); for (i = 1; i < n; i++) { dset->dispatches[i] = NULL; - result = dispatch_createudp(mgr, sockmgr, taskmgr, - &source->local, source->attributes, + result = dispatch_createudp(mgr, taskmgr, &source->local, + source->attributes, &dset->dispatches[i]); if (result != ISC_R_SUCCESS) { goto fail; diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index d8fcfd3c9e..9c3114dbd0 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -89,9 +89,8 @@ typedef struct dns_clientresevent { isc_result_t dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_client_t **clientp, - const isc_sockaddr_t *localaddr4, + isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, const isc_sockaddr_t *localaddr4, const isc_sockaddr_t *localaddr6); /*%< * Create a DNS client object with minimal internal resources, such as @@ -113,7 +112,7 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, * *\li 'taskmgr' is a valid task manager. * - *\li 'socketmgr' is a valid socket manager. + *\li 'nm' is a valid network manager. * *\li 'timermgr' is a valid timer manager. * diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 0ff11844ff..aea71f9bd5 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -9,6 +9,8 @@ * information regarding copyright ownership. */ +#include + #ifndef DNS_DISPATCH_H #define DNS_DISPATCH_H 1 @@ -50,6 +52,7 @@ #include #include #include +#include #include #include @@ -76,12 +79,9 @@ ISC_LANG_BEGINDECLS struct dns_dispatchevent { ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */ - isc_result_t result; /*%< result code */ - int32_t id; /*%< message id */ - isc_sockaddr_t addr; /*%< address recv'd from */ - struct in6_pktinfo pktinfo; /*%< reply info for v6 */ - isc_buffer_t buffer; /*%< data buffer */ - uint32_t attributes; /*%< mirrored from socket.h */ + isc_result_t result; /*%< result code */ + isc_region_t region; /*%< data region */ + isc_buffer_t buffer; /*%< data buffer */ }; /*% @@ -128,14 +128,16 @@ struct dns_dispatchset { #define DNS_DISPATCHOPT_FIXEDID 0x00000001U isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp); +dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, dns_dispatchmgr_t **mgrp); /*%< * Creates a new dispatchmgr object, and sets the available ports * to the default range (1024-65535). * * Requires: - *\li "mctx" be a valid memory context. + *\li 'mctx' be a valid memory context. * + *\li 'nm' is a valid network manager. + *\li mgrp != NULL && *mgrp == NULL * * Returns: @@ -205,9 +207,9 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); */ isc_result_t -dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp); +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp); /*%< * Create a new UDP dispatch. * @@ -223,8 +225,8 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, */ isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, const isc_sockaddr_t *destaddr, unsigned int attributes, isc_dscp_t dscp, dns_dispatch_t **dispp); /*%< @@ -265,15 +267,13 @@ dns_dispatch_detach(dns_dispatch_t **dispp); */ isc_result_t -dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, - isc_task_t *task, isc_taskaction_t action, void *arg); +dns_dispatch_connect(dns_dispentry_t *resp); /*%< - * Connect the UDP socket in 'resp' or the TCP socket in 'disp' to the - * remote server, and run the specified callback. + * Connect to the remote server configured in 'resp' and run the + * connect callback that was set up via dns_dispatch_addresponse(). * * Requires: - *\li 'resp' is NULL and 'disp' is valid, or - *\li 'disp' is NULL and 'resp' is valid. + *\li 'resp' is valid. */ void @@ -288,29 +288,16 @@ dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, *\li 'disp' is NULL and 'resp' is valid. */ -isc_result_t -dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, - isc_socketevent_t *sendevent, isc_region_t *r, - const isc_sockaddr_t *address, isc_dscp_t dscp, - isc_taskaction_t action, void *arg); +void +dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp); /*%< * Send region 'r' using the socket in 'resp', then run the specified - * callback. 'sendevent' must point to enough memory to hold an - * isc_socketevent; it will be overwritten. + * callback. * * Requires: *\li 'resp' is valid. */ -void -dns_dispatch_starttcp(dns_dispatch_t *disp); -/*%< - * Start processing of a TCP dispatch once the socket connects. - * - * Requires: - *\li 'disp' is valid. - */ - isc_result_t dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, const isc_sockaddr_t *localaddr, bool *connected, @@ -322,18 +309,29 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, - const isc_sockaddr_t *dest, isc_task_t *task, - isc_taskaction_t action, void *arg, uint16_t *idp, - dns_dispentry_t **resp, isc_socketmgr_t *sockmgr); + unsigned int timeout, const isc_sockaddr_t *dest, + isc_task_t *task, isc_nm_cb_t connected, + isc_nm_cb_t sent, isc_taskaction_t action, + isc_taskaction_t timeout_action, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp); /*%< * Add a response entry for this dispatch. * * "*idp" is filled in with the assigned message ID, and *resp is filled in * to contain the magic token used to request event flow stop. * - * Arranges for the given task to get a callback for response packets. When - * the event is delivered, it must be returned using dns_dispatch_freeevent() - * or through dns_dispatch_removeresponse() for another to be delivered. + * The 'connected' and 'sent' callbacks are run to inform the caller when + * the connection and send functions are complete. + * + * The specified 'task' is sent the 'action' callback for response packets. + * (Later, this should be updated to a network manager callback function, + * but for now we still use isc_task for this.) When the event is delivered, + * it must be returned using dns_dispatch_freeevent() or through + * dns_dispatch_removeresponse() for another to be delivered. + * + * On timeout, 'timeout_action' will be sent to the task. + * + * All three callback functions are sent 'arg' as a parameter. * * Requires: *\li "idp" be non-NULL. @@ -344,10 +342,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, * *\li "resp" be non-NULL and *resp be NULL * - *\li "sockmgr" be NULL or a valid socket manager. If 'disp' has - * the DNS_DISPATCHATTR_EXCLUSIVE attribute, this must not be NULL, - * which also means dns_dispatch_addresponse() cannot be used. - * * Ensures: * *\li <id, dest> is a unique tuple. That means incoming messages @@ -452,9 +446,9 @@ dns_dispatchset_get(dns_dispatchset_t *dset); */ isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t *source, - dns_dispatchset_t **dsetp, int n); +dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + dns_dispatch_t *source, dns_dispatchset_t **dsetp, + int n); /*%< * Given a valid dispatch 'source', create a dispatch set containing * 'n' UDP dispatches, with the remainder filled out by clones of the diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 98afe5a4ae..9554603b50 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -53,8 +53,7 @@ typedef struct dns_requestevent { ISC_LANG_BEGINDECLS isc_result_t -dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, +dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_requestmgr_t **requestmgrp); @@ -65,8 +64,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, * *\li 'mctx' is a valid memory context. * - *\li 'timermgr' is a valid timer manager. - * *\li 'socketmgr' is a valid socket manager. * *\li 'taskmgr' is a valid task manager. diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 07b94fdcd1..aeda97dd38 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -163,11 +163,10 @@ typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t; isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_resolver_t **resp); + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_resolver_t **resp); /*%< * Create a resolver. @@ -185,7 +184,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, * *\li 'ntasks' > 0. * - *\li 'socketmgr' is a valid socket manager. + *\li 'nm' is a valid network manager. * *\li 'timermgr' is a valid timer manager. * @@ -413,9 +412,6 @@ dns_resolver_dispatchv4(dns_resolver_t *resolver); dns_dispatch_t * dns_resolver_dispatchv6(dns_resolver_t *resolver); -isc_socketmgr_t * -dns_resolver_socketmgr(dns_resolver_t *resolver); - isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver); diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index bfe9abd763..5e777229e8 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -393,9 +393,9 @@ dns_view_createzonetable(dns_view_t *view); isc_result_t dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6); /*%< * Create a resolver and address database for the view. @@ -407,7 +407,7 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, *\li 'view' does not have a resolver already. * *\li The requirements of dns_resolver_create() apply to 'taskmgr', - * 'ntasks', 'socketmgr', 'timermgr', 'options', 'dispatchv4', and + * 'ntasks', 'nm', 'timermgr', 'options', 'dispatchv4', and * 'dispatchv6'. * * Returns: diff --git a/lib/dns/request.c b/lib/dns/request.c index 367a716d20..c629997c02 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -50,8 +49,6 @@ struct dns_requestmgr { /* locked */ int32_t eref; int32_t iref; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; isc_taskmgr_t *taskmgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; @@ -74,7 +71,6 @@ struct dns_request { dns_requestevent_t *event; dns_dispatch_t *dispatch; dns_dispentry_t *dispentry; - isc_timer_t *timer; dns_requestmgr_t *requestmgr; isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; @@ -115,16 +111,16 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, isc_mem_t *mctx); static void -req_senddone(isc_task_t *task, isc_event_t *event); -static void req_response(isc_task_t *task, isc_event_t *event); static void req_timeout(isc_task_t *task, isc_event_t *event); static void -req_connected(isc_task_t *task, isc_event_t *event); +req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void req_sendevent(dns_request_t *request, isc_result_t result); static void +req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); +static void req_cancel(dns_request_t *request); static void req_destroy(dns_request_t *request); @@ -138,8 +134,7 @@ do_cancel(isc_task_t *task, isc_event_t *event); ***/ isc_result_t -dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, +dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_requestmgr_t **requestmgrp) { @@ -150,8 +145,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create"); REQUIRE(requestmgrp != NULL && *requestmgrp == NULL); - REQUIRE(timermgr != NULL); - REQUIRE(socketmgr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(dispatchmgr != NULL); @@ -171,8 +164,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { isc_mutex_init(&requestmgr->locks[i]); } - requestmgr->timermgr = timermgr; - requestmgr->socketmgr = socketmgr; requestmgr->taskmgr = taskmgr; requestmgr->dispatchmgr = dispatchmgr; requestmgr->dispatchv4 = NULL; @@ -410,12 +401,9 @@ mgr_gethash(dns_requestmgr_t *requestmgr) { return (requestmgr->hash % DNS_REQUEST_NLOCKS); } -static inline isc_result_t -req_send(dns_request_t *request, isc_task_t *task, - const isc_sockaddr_t *address) { - isc_result_t result; +static inline void +req_send(dns_request_t *request) { isc_region_t r; - bool tcp; req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); @@ -423,14 +411,8 @@ req_send(dns_request_t *request, isc_task_t *task, isc_buffer_usedregion(request->query, &r); - tcp = dns_request_usedtcp(request); - request->flags |= DNS_REQUEST_F_SENDING; - result = dns_dispatch_send(request->dispentry, tcp, task, - &request->sendevent, &r, address, - request->dscp, req_senddone, request); - INSIST(result == ISC_R_SUCCESS); - return (result); + dns_dispatch_send(request->dispentry, &r, request->dscp); } static isc_result_t @@ -497,9 +479,9 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, } } - result = dns_dispatch_createtcp( - requestmgr->dispatchmgr, requestmgr->socketmgr, - requestmgr->taskmgr, srcaddr, destaddr, 0, dscp, dispatchp); + result = dns_dispatch_createtcp(requestmgr->dispatchmgr, + requestmgr->taskmgr, srcaddr, destaddr, + 0, dscp, dispatchp); return (result); } @@ -528,9 +510,9 @@ udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, return (ISC_R_SUCCESS); } - return (dns_dispatch_createudp( - requestmgr->dispatchmgr, requestmgr->socketmgr, - requestmgr->taskmgr, srcaddr, 0, dispatchp)); + return (dns_dispatch_createudp(requestmgr->dispatchmgr, + requestmgr->taskmgr, srcaddr, 0, + dispatchp)); } static isc_result_t @@ -548,25 +530,6 @@ get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr, return (result); } -static isc_result_t -set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) { - isc_time_t expires; - isc_interval_t interval; - isc_result_t result; - isc_timertype_t timertype; - - isc_interval_set(&interval, timeout, 0); - result = isc_time_nowplusinterval(&expires, &interval); - isc_interval_set(&interval, udpresend, 0); - - timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once; - if (result == ISC_R_SUCCESS) { - result = isc_timer_reset(timer, timertype, &expires, &interval, - false); - } - return (result); -} - isc_result_t dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, const isc_sockaddr_t *srcaddr, @@ -617,19 +580,13 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, udptimeout = 1; } } + + timeout *= 1000; + udptimeout *= 1000; + request->udpcount = udpretries; request->dscp = dscp; - /* - * Create timer now. We will set it below once. - */ - result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, - NULL, NULL, task, req_timeout, request, - &request->timer); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - request->event = (dns_requestevent_t *)isc_event_allocate( mctx, task, DNS_EVENT_REQUESTDONE, action, arg, sizeof(dns_requestevent_t)); @@ -661,8 +618,9 @@ again: } result = dns_dispatch_addresponse( - request->dispatch, dispopt, destaddr, task, req_response, - request, &id, &request->dispentry, requestmgr->socketmgr); + request->dispatch, dispopt, tcp ? timeout : udptimeout, + destaddr, task, req_connected, req_senddone, req_response, + req_timeout, request, &id, &request->dispentry); if (result != ISC_R_SUCCESS) { if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) { newtcp = true; @@ -674,9 +632,6 @@ again: } isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); - if (tcp) { - isc_buffer_putuint16(request->query, (uint16_t)r.length); - } result = isc_buffer_copyregion(request->query, &r); if (result != ISC_R_SUCCESS) { goto cleanup; @@ -684,9 +639,6 @@ again: /* Add message ID. */ isc_buffer_usedregion(request->query, &r); - if (tcp) { - isc_region_consume(&r, 2); - } r.base[0] = (id >> 8) & 0xff; r.base[1] = id & 0xff; @@ -701,24 +653,15 @@ again: ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->destaddr = *destaddr; - if (tcp && !connected) { - result = dns_dispatch_connect(request->dispatch, NULL, task, - req_connected, request); + if (!tcp || !connected) { + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; } else { - result = req_send(request, task, connected ? NULL : destaddr); - if (result != ISC_R_SUCCESS) { - goto unlink; - } + req_send(request); } req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request); @@ -790,7 +733,6 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, return (DNS_R_BLACKHOLED); } - request = NULL; result = new_request(mctx, &request); if (result != ISC_R_SUCCESS) { return (result); @@ -802,19 +744,13 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, udptimeout = 1; } } + + timeout *= 1000; + udptimeout *= 1000; + request->udpcount = udpretries; request->dscp = dscp; - /* - * Create timer now. We will set it below once. - */ - result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, - NULL, NULL, task, req_timeout, request, - &request->timer); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - request->event = (dns_requestevent_t *)isc_event_allocate( mctx, task, DNS_EVENT_REQUESTDONE, action, arg, sizeof(dns_requestevent_t)); @@ -835,8 +771,9 @@ use_tcp: } result = dns_dispatch_addresponse( - request->dispatch, 0, destaddr, task, req_response, request, - &id, &request->dispentry, requestmgr->socketmgr); + request->dispatch, 0, tcp ? timeout : udptimeout, destaddr, + task, req_connected, req_senddone, req_response, req_timeout, + request, &id, &request->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -880,24 +817,15 @@ use_tcp: ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->destaddr = *destaddr; - if (tcp && !connected) { - result = dns_dispatch_connect(request->dispatch, NULL, task, - req_connected, request); + if (!tcp || !connected) { + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; } else { - result = req_send(request, task, connected ? NULL : destaddr); - if (result != ISC_R_SUCCESS) { - goto unlink; - } + req_send(request); } req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request); @@ -926,7 +854,6 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, isc_buffer_t *buf2 = NULL; isc_result_t result; isc_region_t r; - bool tcp = false; dns_compress_t cctx; bool cleanup_cctx = false; @@ -984,16 +911,11 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, * Copy rendered message to exact sized buffer. */ isc_buffer_usedregion(buf1, &r); - if ((options & DNS_REQUESTOPT_TCP) != 0) { - tcp = true; - } else if (r.length > 512) { + if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) { result = DNS_R_USETCP; goto cleanup; } - isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0)); - if (tcp) { - isc_buffer_putuint16(buf2, (uint16_t)r.length); - } + isc_buffer_allocate(mctx, &buf2, r.length); result = isc_buffer_copyregion(buf2, &r); if (result != ISC_R_SUCCESS) { goto cleanup; @@ -1138,7 +1060,6 @@ dns_request_destroy(dns_request_t **requestp) { INSIST(!ISC_LINK_LINKED(request, link)); INSIST(request->dispentry == NULL); INSIST(request->dispatch == NULL); - INSIST(request->timer == NULL); req_destroy(request); } @@ -1147,12 +1068,11 @@ dns_request_destroy(dns_request_t **requestp) { *** Private: request. ***/ static void -req_connected(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - isc_result_t result; - dns_request_t *request = event->ev_arg; +req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_request_t *request = (dns_request_t *)arg; + + UNUSED(handle); - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_CONNECTING(request)); @@ -1171,53 +1091,42 @@ req_connected(isc_task_t *task, isc_event_t *event) { send_if_done(request, ISC_R_CANCELED); } } else { - dns_dispatch_starttcp(request->dispatch); - result = sevent->result; - if (result == ISC_R_SUCCESS) { - result = req_send(request, task, NULL); - } - - if (result != ISC_R_SUCCESS) { + if (eresult == ISC_R_SUCCESS) { + req_send(request); + } else { req_cancel(request); send_if_done(request, ISC_R_CANCELED); } } UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); } static void -req_senddone(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - dns_request_t *request = event->ev_arg; +req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_request_t *request = (dns_request_t *)arg; - REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_SENDING(request)); - req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); + UNUSED(handle); - UNUSED(task); + req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_SENDING; if (DNS_REQUEST_CANCELED(request)) { - /* - * Send delayed event. - */ if (DNS_REQUEST_TIMEDOUT(request)) { send_if_done(request, ISC_R_TIMEDOUT); } else { send_if_done(request, ISC_R_CANCELED); } - } else if (sevent->result != ISC_R_SUCCESS) { + } else if (eresult != ISC_R_SUCCESS) { req_cancel(request); send_if_done(request, ISC_R_CANCELED); } - UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); + UNLOCK(&request->requestmgr->locks[request->hash]); } static void @@ -1266,7 +1175,6 @@ done: static void req_timeout(isc_task_t *task, isc_event_t *event) { dns_request_t *request = event->ev_arg; - isc_result_t result; REQUIRE(VALID_REQUEST(request)); @@ -1274,13 +1182,9 @@ req_timeout(isc_task_t *task, isc_event_t *event) { UNUSED(task); LOCK(&request->requestmgr->locks[request->hash]); - if (event->ev_type == ISC_TIMEREVENT_TICK && request->udpcount-- != 0) { + if (request->udpcount-- != 0) { if (!DNS_REQUEST_SENDING(request)) { - result = req_send(request, task, &request->destaddr); - if (result != ISC_R_SUCCESS) { - req_cancel(request); - send_if_done(request, result); - } + req_send(request); } } else { request->flags |= DNS_REQUEST_F_TIMEDOUT; @@ -1330,9 +1234,6 @@ req_destroy(dns_request_t *request) { if (request->dispatch != NULL) { dns_dispatch_detach(&request->dispatch); } - if (request->timer != NULL) { - isc_timer_detach(&request->timer); - } if (request->tsig != NULL) { isc_buffer_free(&request->tsig); } @@ -1359,10 +1260,6 @@ req_cancel(dns_request_t *request) { */ request->flags |= DNS_REQUEST_F_CANCELED; - if (request->timer != NULL) { - isc_timer_detach(&request->timer); - } - if (request->dispentry != NULL) { dns_dispatch_cancel(NULL, request->dispentry, DNS_REQUEST_SENDING(request), diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index febec16482..b987b888cb 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -496,7 +496,7 @@ struct dns_resolver { isc_mutex_t lock; isc_mutex_t primelock; dns_rdataclass_t rdclass; - isc_socketmgr_t *socketmgr; + isc_nm_t *nm; isc_timermgr_t *timermgr; isc_taskmgr_t *taskmgr; dns_view_t *view; @@ -604,7 +604,7 @@ resquery_send(resquery_t *query); static void resquery_response(isc_task_t *task, isc_event_t *event); static void -resquery_connected(isc_task_t *task, isc_event_t *event); +resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void fctx_try(fetchctx_t *fctx, bool retrying, bool badcache); static isc_result_t @@ -1354,10 +1354,11 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, } dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor); - } - if ((query->options & DNS_FETCHOPT_TCP) == 0) { - /* Inform the ADB that we're ending a UDP fetch */ - dns_adb_endudpfetch(fctx->adb, query->addrinfo); + + if ((query->options & DNS_FETCHOPT_TCP) == 0) { + /* Inform the ADB that we're ending a UDP fetch */ + dns_adb_endudpfetch(fctx->adb, query->addrinfo); + } } /* @@ -1428,7 +1429,9 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, dns_dispatch_removeresponse(&query->dispentry, deventp); } - ISC_LIST_UNLINK(fctx->queries, query, link); + if (ISC_LINK_LINKED(query, link)) { + ISC_LIST_UNLINK(fctx->queries, query, link); + } if (query->tsig != NULL) { isc_buffer_free(&query->tsig); @@ -1796,13 +1799,20 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { } static void -process_sendevent(resquery_t *query, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; +resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + resquery_t *query = (resquery_t *)arg; bool destroy_query = false; - bool retry = false; isc_result_t result; fetchctx_t *fctx = NULL; + QTRACE("senddone"); + + UNUSED(handle); + + INSIST(RESQUERY_SENDING(query)); + + query->sends--; + fctx = query->fctx; if (RESQUERY_CANCELED(query)) { @@ -1810,7 +1820,7 @@ process_sendevent(resquery_t *query, isc_event_t *event) { destroy_query = true; } } else { - switch (sevent->result) { + switch (eresult) { case ISC_R_SUCCESS: break; @@ -1819,94 +1829,44 @@ process_sendevent(resquery_t *query, isc_event_t *event) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNREFUSED: - FCTXTRACE3("query canceled in sendevent(): " + FCTXTRACE3("query canceled in resquery_senddone(): " "no route to host; no response", - sevent->result); + eresult); /* * No route to remote. */ - add_bad(fctx, query->rmessage, query->addrinfo, - sevent->result, badns_unreachable); + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); fctx_cancelquery(&query, NULL, NULL, true, false); - retry = true; + + /* + * Behave as if the idle timer has expired. For TCP + * this may not actually reflect the latest timer. + */ + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) { + fctx_done(fctx, result, __LINE__); + } else { + fctx_try(fctx, true, false); + } break; default: - FCTXTRACE3("query canceled in sendevent() due to " - "unexpected event result; responding", - sevent->result); - + FCTXTRACE3("query canceled in resquery_senddone() " + "due to unexpected result; responding", + eresult); fctx_cancelquery(&query, NULL, NULL, false, false); break; } } - if (event->ev_type == ISC_SOCKEVENT_CONNECT) { - isc_event_free(&event); - } - - if (retry) { - /* - * Behave as if the idle timer has expired. For TCP - * this may not actually reflect the latest timer. - */ - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, true, false); - } - } - if (destroy_query) { resquery_destroy(&query); } } -static void -resquery_udpconnected(isc_task_t *task, isc_event_t *event) { - resquery_t *query = event->ev_arg; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); - - QTRACE("udpconnected"); - - UNUSED(task); - - INSIST(RESQUERY_CONNECTING(query)); - - query->connects--; - - process_sendevent(query, event); -} - -static void -resquery_senddone(isc_task_t *task, isc_event_t *event) { - resquery_t *query = event->ev_arg; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); - - QTRACE("senddone"); - - /* - * XXXRTH - * - * Currently we don't wait for the senddone event before retrying - * a query. This means that if we get really behind, we may end - * up doing extra work! - */ - - UNUSED(task); - - INSIST(RESQUERY_SENDING(query)); - - query->sends--; - - process_sendevent(query, event); -} - static inline isc_result_t fctx_addopt(dns_message_t *message, unsigned int version, uint16_t udpsize, dns_ednsopt_t *ednsopts, size_t count) { @@ -1972,15 +1932,14 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { static isc_result_t fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, unsigned int options) { + isc_result_t result; dns_resolver_t *res = NULL; isc_task_t *task = NULL; - isc_result_t result; resquery_t *query = NULL; isc_sockaddr_t addr; bool have_addr = false; unsigned int srtt; isc_dscp_t dscp = -1; - unsigned int bucketnum; FCTXTRACE("query"); @@ -2088,9 +2047,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->dscp = dscp; } - result = dns_dispatch_createtcp( - res->dispatchmgr, res->socketmgr, res->taskmgr, &addr, - &addrinfo->sockaddr, 0, query->dscp, &query->dispatch); + result = dns_dispatch_createtcp(res->dispatchmgr, res->taskmgr, + &addr, &addrinfo->sockaddr, 0, + query->dscp, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2107,9 +2066,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } - result = dns_dispatch_createudp( - res->dispatchmgr, res->socketmgr, res->taskmgr, - &addr, 0, &query->dispatch); + result = dns_dispatch_createudp(res->dispatchmgr, + res->taskmgr, &addr, 0, + &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2150,49 +2109,34 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; - if ((query->options & DNS_FETCHOPT_TCP) != 0) { - /* - * Connect to the remote server. - */ - result = dns_dispatch_connect(query->dispatch, NULL, task, - resquery_connected, query); - if (result != ISC_R_SUCCESS) { - goto cleanup_dispatch; - } - query->connects++; - QTRACE("connecting via TCP"); - } else { + if ((query->options & DNS_FETCHOPT_TCP) == 0) { if (dns_adbentry_overquota(addrinfo->entry)) { goto cleanup_dispatch; } /* Inform the ADB that we're starting a UDP fetch */ dns_adb_beginudpfetch(fctx->adb, addrinfo); - - result = resquery_send(query); - if (result != ISC_R_SUCCESS) { - goto cleanup_dispatch; - } } - fctx->querysent++; - - ISC_LIST_APPEND(fctx->queries, query, link); - bucketnum = fctx->bucketnum; - LOCK(&res->buckets[bucketnum].lock); + LOCK(&res->buckets[fctx->bucketnum].lock); fctx->nqueries++; - UNLOCK(&res->buckets[bucketnum].lock); - if (isc_sockaddr_pf(&addrinfo->sockaddr) == PF_INET) { - inc_stats(res, dns_resstatscounter_queryv4); - } else { - inc_stats(res, dns_resstatscounter_queryv6); - } - if (res->view->resquerystats != NULL) { - dns_rdatatypestats_increment(res->view->resquerystats, - fctx->type); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + + /* Set up the dispatch and set the query ID */ + /* XXX: timeout hard-coded to 10 seconds */ + result = dns_dispatch_addresponse( + query->dispatch, 0, 10000, &query->addrinfo->sockaddr, task, + resquery_connected, resquery_senddone, resquery_response, NULL, + query, &query->id, &query->dispentry); + if (result != ISC_R_SUCCESS) { + goto cleanup_dispatch; } - return (ISC_R_SUCCESS); + /* Connect the socket */ + query->connects++; + fctx_increference(fctx); + result = dns_dispatch_connect(query->dispentry); + return (result); cleanup_dispatch: if (query->dispatch != NULL) { @@ -2349,21 +2293,19 @@ issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type, static isc_result_t resquery_send(resquery_t *query) { - fetchctx_t *fctx = NULL; isc_result_t result; + fetchctx_t *fctx = query->fctx; + dns_resolver_t *res = fctx->res; + isc_buffer_t buffer; dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_region_t r; - dns_resolver_t *res = NULL; - isc_task_t *task = NULL; - isc_buffer_t tcpbuffer; - isc_buffer_t *buffer = NULL; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; dns_peer_t *peer = NULL; - bool useedns; dns_compress_t cctx; bool cleanup_cctx = false; + bool useedns; bool secure_domain; bool tcp = ((query->options & DNS_FETCHOPT_TCP) != 0); dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; @@ -2377,24 +2319,11 @@ resquery_send(resquery_t *query) { isc_buffer_t zb; #endif /* HAVE_DNSTAP */ - fctx = query->fctx; QTRACE("send"); - res = fctx->res; - task = res->buckets[fctx->bucketnum].task; - - if (tcp) { - /* - * Reserve space for the TCP message length. - */ - isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data)); - isc_buffer_init(&query->buffer, query->data + 2, - sizeof(query->data) - 2); - buffer = &tcpbuffer; - } else { - isc_buffer_init(&query->buffer, query->data, - sizeof(query->data)); - buffer = &query->buffer; + if (atomic_load_acquire(&res->exiting)) { + FCTXTRACE("resquery_send: resolver shutting down"); + return (ISC_R_SHUTTINGDOWN); } result = dns_message_gettempname(fctx->qmessage, &qname); @@ -2406,17 +2335,6 @@ resquery_send(resquery_t *query) { goto cleanup_temps; } - /* - * Get a query id from the dispatch. - */ - result = dns_dispatch_addresponse(query->dispatch, 0, - &query->addrinfo->sockaddr, task, - resquery_response, query, &query->id, - &query->dispentry, res->socketmgr); - if (result != ISC_R_SUCCESS) { - goto cleanup_temps; - } - fctx->qmessage->opcode = dns_opcode_query; /* @@ -2479,7 +2397,8 @@ resquery_send(resquery_t *query) { } cleanup_cctx = true; - result = dns_message_renderbegin(fctx->qmessage, &cctx, &query->buffer); + isc_buffer_init(&buffer, query->data, sizeof(query->data)); + result = dns_message_renderbegin(fctx->qmessage, &cctx, &buffer); if (result != ISC_R_SUCCESS) { goto cleanup_message; } @@ -2490,7 +2409,6 @@ resquery_send(resquery_t *query) { goto cleanup_message; } - peer = NULL; isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr); (void)dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer); @@ -2757,16 +2675,6 @@ resquery_send(resquery_t *query) { } } - /* - * If using TCP, write the length of the message at the beginning - * of the buffer. - */ - if (tcp) { - isc_buffer_usedregion(&query->buffer, &r); - isc_buffer_putuint16(&tcpbuffer, (uint16_t)r.length); - isc_buffer_add(&tcpbuffer, r.length); - } - /* * Log the outgoing packet. */ @@ -2780,23 +2688,9 @@ resquery_send(resquery_t *query) { */ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER); - if (!tcp) { - /* Connect the UDP socket */ - result = dns_dispatch_connect(NULL, query->dispentry, task, - resquery_udpconnected, query); - if (result != ISC_R_SUCCESS) { - goto cleanup_message; - } - query->connects++; - } + isc_buffer_usedregion(&buffer, &r); - isc_buffer_usedregion(buffer, &r); - - result = dns_dispatch_send(query->dispentry, tcp, task, - &query->sendevent, &r, - &query->addrinfo->sockaddr, query->dscp, - resquery_senddone, query); - INSIST(result == ISC_R_SUCCESS); + dns_dispatch_send(query->dispentry, &r, query->dscp); query->sends++; QTRACE("sent"); @@ -2817,7 +2711,7 @@ resquery_send(resquery_t *query) { } dns_dt_send(fctx->res->view, dtmsgtype, la, &query->addrinfo->sockaddr, - tcp, &zr, &query->start, NULL, &query->buffer); + tcp, &zr, &query->start, NULL, &buffer); #endif /* HAVE_DNSTAP */ return (ISC_R_SUCCESS); @@ -2846,40 +2740,40 @@ cleanup_temps: } static void -resquery_connected(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - resquery_t *query = event->ev_arg; - bool retry = false; +resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + resquery_t *query = (resquery_t *)arg; isc_interval_t interval; isc_result_t result; - fetchctx_t *fctx; + fetchctx_t *fctx = NULL; + dns_resolver_t *res = NULL; + unsigned int bucketnum; + bool bucket_empty; + int pf; - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_QUERY(query)); QTRACE("connected"); - UNUSED(task); - - /* - * XXXRTH - * - * Currently we don't wait for the connect event before retrying - * a query. This means that if we get really behind, we may end - * up doing extra work! - */ + UNUSED(handle); query->connects--; fctx = query->fctx; + res = fctx->res; + + bucketnum = fctx->bucketnum; + + if (atomic_load_acquire(&res->exiting)) { + eresult = ISC_R_SHUTTINGDOWN; + } if (RESQUERY_CANCELED(query)) { /* - * This query was canceled while the connect() was in - * progress. + * This query was canceled while the connect() was + * in progress. */ resquery_destroy(&query); } else { - switch (sevent->result) { + switch (eresult) { case ISC_R_SUCCESS: /* @@ -2890,8 +2784,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { * received. */ isc_interval_set(&interval, - fctx->res->query_timeout / 1000 / 2, - 0); + res->query_timeout / 1000 / 2, 0); result = fctx_startidletimer(query->fctx, &interval); if (result != ISC_R_SUCCESS) { FCTXTRACE("query canceled: idle timer failed; " @@ -2904,7 +2797,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { } /* - * We are connected. Update the dispatcher and + * We are connected. Update the dispatcher and * send the query. */ dns_dispatch_changeattributes( @@ -2920,6 +2813,20 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { false); fctx_done(fctx, result, __LINE__); } + + fctx->querysent++; + + ISC_LIST_APPEND(fctx->queries, query, link); + pf = isc_sockaddr_pf(&query->addrinfo->sockaddr); + if (pf == PF_INET) { + inc_stats(res, dns_resstatscounter_queryv4); + } else { + inc_stats(res, dns_resstatscounter_queryv6); + } + if (res->view->resquerystats != NULL) { + dns_rdatatypestats_increment( + res->view->resquerystats, fctx->type); + } break; case ISC_R_NETUNREACH: @@ -2928,45 +2835,46 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNECTIONRESET: - FCTXTRACE3("query canceled in connected(): " + FCTXTRACE3("query canceled in resquery_connected(): " "no route to host; no response", - sevent->result); + eresult); /* * Do not query this server again in this fetch context * if the server is unavailable over TCP. */ - add_bad(fctx, query->rmessage, query->addrinfo, - sevent->result, badns_unreachable); + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); fctx_cancelquery(&query, NULL, NULL, true, false); - retry = true; + + /* + * Behave as if the idle timer has expired. For + * TCP connections this may not actually reflect + * the latest timer. + */ + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) { + fctx_done(fctx, result, __LINE__); + } else { + fctx_try(fctx, true, false); + } break; default: - FCTXTRACE3("query canceled in connected() due to " - "unexpected event result; responding", - sevent->result); + FCTXTRACE3("query canceled in resquery_connected() " + "due to unexpected result; responding", + eresult); - dns_dispatch_detach(&query->dispatch); fctx_cancelquery(&query, NULL, NULL, false, false); - break; } } - isc_event_free(&event); - - if (retry) { - /* - * Behave as if the idle timer has expired. For TCP - * connections this may not actually reflect the latest timer. - */ - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, true, false); - } + LOCK(&res->buckets[bucketnum].lock); + bucket_empty = fctx_decreference(fctx); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) { + empty_bucket(res); } } @@ -4140,7 +4048,6 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { } fctx_increference(fctx); - result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) { fctx_done(fctx, result, __LINE__); @@ -5033,8 +4940,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, (res->query_timeout - 1000)); /* * Compute an expiration time after which stale data will - * attempted to be served, if stale answers are enabled and - * target RRset is available in cache. + * be served, if stale answers are enabled and target RRset is + * available in cache. */ isc_interval_set( &interval, res->view->staleanswerclienttimeout / 1000, @@ -7521,6 +7428,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if (atomic_load_acquire(&fctx->res->exiting)) { result = ISC_R_SHUTTINGDOWN; FCTXTRACE("resolver shutting down"); + rctx.finish = NULL; rctx_done(&rctx, result); return; } @@ -9689,13 +9597,13 @@ rctx_done(respctx_t *rctx, isc_result_t result) { /* * Need to attach to the message until the scope * of this function ends, since there are many places - * where te message is used and/or may be destroyed + * where the message is used and/or may be destroyed * before this function ends. */ dns_message_t *message = NULL; dns_message_attach(query->rmessage, &message); - FCTXTRACE4("query canceled in response(); ", + FCTXTRACE4("query canceled in rctx_done(); ", rctx->no_response ? "no response" : "responding", result); /* @@ -10128,11 +10036,10 @@ spillattimer_countdown(isc_task_t *task, isc_event_t *event) { isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_resolver_t **resp) { + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_resolver_t **resp) { dns_resolver_t *res = NULL; isc_result_t result = ISC_R_SUCCESS; unsigned int i, buckets_created = 0, dbuckets_created = 0; @@ -10154,7 +10061,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, res = isc_mem_get(view->mctx, sizeof(*res)); *res = (dns_resolver_t){ .mctx = view->mctx, .rdclass = view->rdclass, - .socketmgr = socketmgr, + .nm = nm, .timermgr = timermgr, .taskmgr = taskmgr, .dispatchmgr = dispatchmgr, @@ -10230,13 +10137,13 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, } if (dispatchv4 != NULL) { - dns_dispatchset_create(view->mctx, socketmgr, taskmgr, - dispatchv4, &res->dispatches4, ndisp); + dns_dispatchset_create(view->mctx, taskmgr, dispatchv4, + &res->dispatches4, ndisp); } if (dispatchv6 != NULL) { - dns_dispatchset_create(view->mctx, socketmgr, taskmgr, - dispatchv6, &res->dispatches6, ndisp); + dns_dispatchset_create(view->mctx, taskmgr, dispatchv6, + &res->dispatches6, ndisp); } isc_mutex_init(&res->lock); @@ -10951,12 +10858,6 @@ dns_resolver_dispatchv6(dns_resolver_t *resolver) { return (dns_dispatchset_get(resolver->dispatches6)); } -isc_socketmgr_t * -dns_resolver_socketmgr(dns_resolver_t *resolver) { - REQUIRE(VALID_RESOLVER(resolver)); - return (resolver->socketmgr); -} - isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index aa92f4ed87..65a2f3d441 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -20,16 +20,17 @@ #include #include #include +#include #define UNIT_TESTING #include #include #include +#include #include #include #include -#include #include #include @@ -38,18 +39,91 @@ #include "dnstest.h" +/* Timeouts in miliseconds */ +#define T_INIT 120 * 1000 +#define T_IDLE 120 * 1000 +#define T_KEEPALIVE 120 * 1000 +#define T_ADVERTISED 120 * 1000 +#define T_CONNECT 30 * 1000 + dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatchset_t *dset = NULL; +isc_nm_t *connect_nm = NULL; +static isc_sockaddr_t server_addr; +static isc_sockaddr_t connect_addr; + +static int +setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { + socklen_t addrlen = sizeof(*addr); + uv_os_sock_t fd; + int r; + + isc_sockaddr_fromin6(addr, &in6addr_loopback, 0); + + fd = socket(AF_INET6, family, 0); + if (fd < 0) { + perror("setup_ephemeral_port: socket()"); + return (-1); + } + + r = bind(fd, (const struct sockaddr *)&addr->type.sa, + sizeof(addr->type.sin6)); + if (r != 0) { + perror("setup_ephemeral_port: bind()"); + close(fd); + return (r); + } + + r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen); + if (r != 0) { + perror("setup_ephemeral_port: getsockname()"); + close(fd); + return (r); + } + +#if IPV6_RECVERR +#define setsockopt_on(socket, level, name) \ + setsockopt(socket, level, name, &(int){ 1 }, sizeof(int)) + + r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR); + if (r != 0) { + perror("setup_ephemeral_port"); + close(fd); + return (r); + } +#endif + + return (fd); +} static int _setup(void **state) { isc_result_t result; + uv_os_sock_t sock = -1; UNUSED(state); result = dns_test_begin(NULL, true); assert_int_equal(result, ISC_R_SUCCESS); + connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0); + + server_addr = (isc_sockaddr_t){ .length = 0 }; + sock = setup_ephemeral_port(&server_addr, SOCK_DGRAM); + if (sock < 0) { + return (-1); + } + close(sock); + + /* Create a secondary network manager */ + isc_managers_create(dt_mctx, ncpus, 0, 0, &connect_nm, NULL, NULL, + NULL); + + isc_nm_settimeouts(netmgr, T_INIT, T_IDLE, T_KEEPALIVE, T_ADVERTISED); + isc_nm_settimeouts(connect_nm, T_INIT, T_IDLE, T_KEEPALIVE, + T_ADVERTISED); + return (0); } @@ -57,6 +131,9 @@ static int _teardown(void **state) { UNUSED(state); + isc_managers_destroy(&connect_nm, NULL, NULL, NULL); + assert_null(connect_nm); + dns_test_end(); return (0); @@ -68,20 +145,18 @@ make_dispatchset(unsigned int ndisps) { isc_sockaddr_t any; dns_dispatch_t *disp = NULL; - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, netmgr, &dispatchmgr); if (result != ISC_R_SUCCESS) { return (result); } isc_sockaddr_any(&any); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &any, - 0, &disp); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &any, 0, &disp); if (result != ISC_R_SUCCESS) { return (result); } - result = dns_dispatchset_create(dt_mctx, socketmgr, taskmgr, disp, - &dset, ndisps); + result = dns_dispatchset_create(dt_mctx, taskmgr, disp, &dset, ndisps); dns_dispatch_detach(&disp); return (result); @@ -155,68 +230,57 @@ dispatchset_get(void **state) { reset(); } +struct { + isc_nmhandle_t *handle; + atomic_uint_fast32_t responses; +} testdata; + +static dns_dispatch_t *dispatch = NULL; +static dns_dispentry_t *dispentry = NULL; +static atomic_bool first = ATOMIC_VAR_INIT(true); + static void -senddone(isc_task_t *task, isc_event_t *event) { - isc_socket_t *sock = event->ev_arg; +server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(cbarg); - UNUSED(task); - - isc_socket_detach(&sock); - isc_event_free(&event); + return; } static void -nameserver(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - isc_region_t region; - isc_socket_t *dummy; - isc_socket_t *sock = event->ev_arg; - isc_socketevent_t *ev = (isc_socketevent_t *)event; +nameserver(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *cbarg) { + isc_region_t response; static unsigned char buf1[16]; static unsigned char buf2[16]; - memmove(buf1, ev->region.base, 12); + UNUSED(eresult); + UNUSED(cbarg); + + memmove(buf1, region->base, 12); memset(buf1 + 12, 0, 4); buf1[2] |= 0x80; /* qr=1 */ - memmove(buf2, ev->region.base, 12); + memmove(buf2, region->base, 12); memset(buf2 + 12, 1, 4); buf2[2] |= 0x80; /* qr=1 */ /* * send message to be discarded. */ - region.base = buf1; - region.length = sizeof(buf1); - dummy = NULL; - isc_socket_attach(sock, &dummy); - result = isc_socket_sendto(sock, ®ion, task, senddone, sock, - &ev->address, NULL); - if (result != ISC_R_SUCCESS) { - isc_socket_detach(&dummy); - } + response.base = buf1; + response.length = sizeof(buf1); + isc_nm_send(handle, &response, server_senddone, NULL); /* * send nextitem message. */ - region.base = buf2; - region.length = sizeof(buf2); - dummy = NULL; - isc_socket_attach(sock, &dummy); - result = isc_socket_sendto(sock, ®ion, task, senddone, sock, - &ev->address, NULL); - if (result != ISC_R_SUCCESS) { - isc_socket_detach(&dummy); - } - isc_event_free(&event); + response.base = buf2; + response.length = sizeof(buf2); + isc_nm_send(handle, &response, server_senddone, NULL); } -static dns_dispatch_t *dispatch = NULL; -static dns_dispentry_t *dispentry = NULL; -static atomic_bool first = ATOMIC_VAR_INIT(true); -static isc_sockaddr_t local; -static atomic_uint_fast32_t responses; - static void response(isc_task_t *task, isc_event_t *event) { dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; @@ -224,78 +288,81 @@ response(isc_task_t *task, isc_event_t *event) { UNUSED(task); - atomic_fetch_add_relaxed(&responses, 1); + atomic_fetch_add_relaxed(&testdata.responses, 1); if (atomic_compare_exchange_strong(&first, &exp_true, false)) { isc_result_t result = dns_dispatch_getnext(dispentry, &devent); assert_int_equal(result, ISC_R_SUCCESS); } else { dns_dispatch_removeresponse(&dispentry, &devent); + isc_nmhandle_detach(&testdata.handle); isc_app_shutdown(); } } static void -startit(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - isc_socket_t *sock = NULL; +connected(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + isc_region_t *r = (isc_region_t *)cbarg; - isc_socket_attach(dns_dispatch_getentrysocket(dispentry), &sock); - result = isc_socket_sendto(sock, event->ev_arg, task, senddone, sock, - &local, NULL); - assert_int_equal(result, ISC_R_SUCCESS); + UNUSED(eresult); + + isc_nmhandle_attach(handle, &testdata.handle); + dns_dispatch_send(dispentry, r, -1); +} + +static void +client_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(cbarg); + + return; +} + +static void +startit(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + dns_dispatch_connect(dispentry); isc_event_free(&event); } /* test dispatch getnext */ static void dispatch_getnext(void **state) { - isc_region_t region; isc_result_t result; - isc_socket_t *sock = NULL; + isc_region_t region; + isc_nmsocket_t *sock = NULL; isc_task_t *task = NULL; - uint16_t id; - struct in_addr ina; unsigned char message[12]; unsigned char rbuf[12]; + uint16_t id; UNUSED(state); - atomic_init(&responses, 0); + testdata.handle = NULL; + atomic_init(&testdata.responses, 0); result = isc_task_create(taskmgr, 0, &task); assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); - ina.s_addr = htonl(INADDR_LOOPBACK); - isc_sockaddr_fromin(&local, &ina, 0); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, - 0, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &connect_addr, 0, + &dispatch); assert_int_equal(result, ISC_R_SUCCESS); /* * Create a local udp nameserver on the loopback. */ - result = isc_socket_create(socketmgr, AF_INET, isc_sockettype_udp, - &sock); - assert_int_equal(result, ISC_R_SUCCESS); - - ina.s_addr = htonl(INADDR_LOOPBACK); - isc_sockaddr_fromin(&local, &ina, 0); - result = isc_socket_bind(sock, &local, 0); - assert_int_equal(result, ISC_R_SUCCESS); - - result = isc_socket_getsockname(sock, &local); + result = isc_nm_listenudp(netmgr, &server_addr, nameserver, NULL, 0, + &sock); assert_int_equal(result, ISC_R_SUCCESS); region.base = rbuf; region.length = sizeof(rbuf); - result = isc_socket_recv(sock, ®ion, 1, task, nameserver, sock); - assert_int_equal(result, ISC_R_SUCCESS); - - result = dns_dispatch_addresponse(dispatch, 0, &local, task, response, - NULL, &id, &dispentry, socketmgr); + result = dns_dispatch_addresponse( + dispatch, 0, 10000, &server_addr, task, connected, + client_senddone, response, NULL, ®ion, &id, &dispentry); assert_int_equal(result, ISC_R_SUCCESS); memset(message, 0, sizeof(message)); @@ -304,19 +371,22 @@ dispatch_getnext(void **state) { region.base = message; region.length = sizeof(message); - result = isc_app_onrun(dt_mctx, task, startit, ®ion); + + result = isc_app_onrun(dt_mctx, task, startit, NULL); assert_int_equal(result, ISC_R_SUCCESS); result = isc_app_run(); assert_int_equal(result, ISC_R_SUCCESS); - assert_int_equal(atomic_load_acquire(&responses), 2); + assert_int_equal(atomic_load_acquire(&testdata.responses), 2); + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); /* * Shutdown nameserver. */ - isc_socket_cancel(sock, task, ISC_SOCKCANCEL_RECV); - isc_socket_detach(&sock); isc_task_detach(&task); /* diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 5a16027e48..fac3f25725 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -96,10 +97,12 @@ cleanup_managers(void) { isc_task_shutdown(maintask); isc_task_destroy(&maintask); } + isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, taskmgr == NULL ? NULL : &taskmgr, timermgr == NULL ? NULL : &timermgr, socketmgr == NULL ? NULL : &socketmgr); + if (app_running) { isc_app_finish(); } diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index 53c7c6529f..a2c32cc146 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -46,6 +46,7 @@ extern isc_taskmgr_t *taskmgr; extern isc_task_t *maintask; extern isc_timermgr_t *timermgr; extern isc_socketmgr_t *socketmgr; +extern isc_nm_t *netmgr; extern dns_zonemgr_t *zonemgr; extern bool app_running; extern int ncpus; diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index 1a6e0f6143..2989af3041 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -50,15 +50,15 @@ _setup(void **state) { result = dns_test_begin(NULL, true); assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, netmgr, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_makeview("view", &view); assert_int_equal(result, ISC_R_SUCCESS); isc_sockaddr_any(&local); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, - 0, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &local, 0, + &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); @@ -80,8 +80,8 @@ static void mkres(dns_resolver_t **resolverp) { isc_result_t result; - result = dns_resolver_create(view, taskmgr, 1, 1, socketmgr, timermgr, - 0, dispatchmgr, dispatch, NULL, resolverp); + result = dns_resolver_create(view, taskmgr, 1, 1, netmgr, timermgr, 0, + dispatchmgr, dispatch, NULL, resolverp); assert_int_equal(result, ISC_R_SUCCESS); } diff --git a/lib/dns/view.c b/lib/dns/view.c index 27df703811..ed2045f131 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -634,6 +634,7 @@ view_flushanddetach(dns_view_t **viewp, bool flush) { dns_zone_t *mkzone = NULL, *rdzone = NULL; isc_refcount_destroy(&view->references); + if (!RESSHUTDOWN(view)) { dns_resolver_shutdown(view->resolver); } @@ -643,14 +644,14 @@ view_flushanddetach(dns_view_t **viewp, bool flush) { if (!REQSHUTDOWN(view)) { dns_requestmgr_shutdown(view->requestmgr); } - LOCK(&view->lock); - if (view->zonetable != NULL) { - if (view->flush) { - dns_zt_flushanddetach(&view->zonetable); - } else { - dns_zt_detach(&view->zonetable); - } + + if (view->zonetable != NULL && view->flush) { + dns_zt_flushanddetach(&view->zonetable); + } else if (view->zonetable != NULL) { + dns_zt_detach(&view->zonetable); } + + LOCK(&view->lock); if (view->managed_keys != NULL) { mkzone = view->managed_keys; view->managed_keys = NULL; @@ -796,9 +797,9 @@ dns_view_createzonetable(dns_view_t *view) { isc_result_t dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6) { isc_result_t result; @@ -815,8 +816,8 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, } isc_task_setname(view->task, "view", view); - result = dns_resolver_create(view, taskmgr, ntasks, ndisp, socketmgr, - timermgr, options, dispatchmgr, dispatchv4, + result = dns_resolver_create(view, taskmgr, ntasks, ndisp, nm, timermgr, + options, dispatchmgr, dispatchv4, dispatchv6, &view->resolver); if (result != ISC_R_SUCCESS) { isc_task_detach(&view->task); @@ -841,11 +842,10 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, atomic_fetch_and(&view->attributes, ~DNS_VIEWATTR_ADBSHUTDOWN); isc_refcount_increment(&view->weakrefs); - result = dns_requestmgr_create(view->mctx, timermgr, socketmgr, - dns_resolver_taskmgr(view->resolver), - dns_resolver_dispatchmgr(view->resolver), - dispatchv4, dispatchv6, - &view->requestmgr); + result = dns_requestmgr_create( + view->mctx, dns_resolver_taskmgr(view->resolver), + dns_resolver_dispatchmgr(view->resolver), dispatchv4, + dispatchv6, &view->requestmgr); if (result != ISC_R_SUCCESS) { dns_adb_shutdown(view->adb); dns_resolver_shutdown(view->resolver); @@ -2502,12 +2502,12 @@ dns_view_setviewcommit(dns_view_t *view) { if (view->managed_keys != NULL) { dns_zone_attach(view->managed_keys, &managed_keys); } - if (view->zonetable != NULL) { - dns_zt_setviewcommit(view->zonetable); - } UNLOCK(&view->lock); + if (view->zonetable != NULL) { + dns_zt_setviewcommit(view->zonetable); + } if (redirect != NULL) { dns_zone_setviewcommit(redirect); dns_zone_detach(&redirect); diff --git a/lib/dns/zt.c b/lib/dns/zt.c index 8ca9cd65aa..da4f222ab6 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -483,6 +483,7 @@ dns_zt_setviewcommit(dns_zt_t *zt) { REQUIRE(VALID_ZT(zt)); + RWLOCK(&zt->rwlock, isc_rwlocktype_read); dns_rbtnodechain_init(&chain); result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); @@ -496,6 +497,7 @@ dns_zt_setviewcommit(dns_zt_t *zt) { } dns_rbtnodechain_invalidate(&chain); + RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); } void diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 19cc946bc3..c14607f81d 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -450,6 +450,16 @@ isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats); * full range of socket-related stats counter numbers. */ +isc_result_t +isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type); +/*%< + * Check whether the specified address is available on the local system + * by opening a socket and immediately closing it. + * + * Requires: + *\li 'addr' is not NULL. + */ + void isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, diff --git a/lib/isc/managers.c b/lib/isc/managers.c index f86d4c8485..628dd33fa9 100644 --- a/lib/isc/managers.c +++ b/lib/isc/managers.c @@ -91,7 +91,7 @@ isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp, /* * If we have a taskmgr to clean up, then we must also have a netmgr. */ - REQUIRE(taskmgrp != NULL || netmgrp == NULL); + REQUIRE(taskmgrp == NULL || netmgrp != NULL); /* * The sequence of operations here is important: diff --git a/lib/isc/socket.c b/lib/isc/socket.c index c28b32165c..1f3b107bf9 100644 --- a/lib/isc/socket.c +++ b/lib/isc/socket.c @@ -2593,7 +2593,7 @@ isc_socket_close(isc_socket_t *sock) { int fd; isc_socketmgr_t *manager; isc__socketthread_t *thread; - fflush(stdout); + REQUIRE(VALID_SOCKET(sock)); LOCK(&sock->lock); diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 045c74f9cc..2590794285 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -482,7 +482,7 @@ ns_interface_listentcp(ns_interface_t *ifp) { #if 0 #ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(ifp->tcpsocket,true); + isc_socket_ipv6only(ifp->tcpsocket, true); #endif /* ifndef ISC_ALLOW_MAPPED */ if (ifp->dscp != -1) { diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index ffcf23adfa..8ece586163 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -233,7 +233,7 @@ create_managers(void) { CHECK(ns_server_create(mctx, matchview, &sctx)); - CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + CHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, socketmgr, netmgr, dispatchmgr, maintask, NULL, ncpus,