]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Convert dispatch to netmgr
authorEvan Hunt <each@isc.org>
Thu, 14 Jan 2021 21:02:57 +0000 (13:02 -0800)
committerEvan Hunt <each@isc.org>
Sat, 2 Oct 2021 18:39:56 +0000 (11:39 -0700)
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.

28 files changed:
bin/delv/delv.c
bin/named/server.c
bin/nsupdate/nsupdate.c
bin/tests/system/pipelined/pipequeries.c
bin/tests/system/resolve.c
bin/tests/system/tkey/keycreate.c
bin/tests/system/tkey/keydelete.c
bin/tools/mdig.c
lib/dns/client.c
lib/dns/dispatch.c
lib/dns/include/dns/client.h
lib/dns/include/dns/dispatch.h
lib/dns/include/dns/request.h
lib/dns/include/dns/resolver.h
lib/dns/include/dns/view.h
lib/dns/request.c
lib/dns/resolver.c
lib/dns/tests/dispatch_test.c
lib/dns/tests/dnstest.c
lib/dns/tests/dnstest.h
lib/dns/tests/resolver_test.c
lib/dns/view.c
lib/dns/zt.c
lib/isc/include/isc/netmgr.h
lib/isc/managers.c
lib/isc/socket.c
lib/ns/interfacemgr.c
lib/ns/tests/nstest.c

index dd1181076b3b6ac22e1c8b96f388c323cbd3353b..3559f1bf63e3518fcc28a0086e9e4d1b745d4110 100644 (file)
@@ -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);
        }
index e70cba366277b94810d1a0fcdc029a0b7924dc36..0abefe840710a5d3a08c9043fce96f68b120fca2 100644 (file)
@@ -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;
index be39164216928ed4b29c2b39498c79b32cebb71b..a3bb130a7eadfe20af888d72e1d1964eb5d478aa 100644 (file)
@@ -31,6 +31,7 @@
 #include <isc/log.h>
 #include <isc/managers.h>
 #include <isc/mem.h>
+#include <isc/netmgr.h>
 #include <isc/nonce.h>
 #include <isc/parseint.h>
 #include <isc/portset.h>
 #include <isc/random.h>
 #include <isc/region.h>
 #include <isc/sockaddr.h>
-#include <isc/socket.h>
 #include <isc/stdio.h>
 #include <isc/string.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/types.h>
 #include <isc/util.h>
 
@@ -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);
index 6466771ff209cb0a6547bb09c90ed5020a04c05b..6b34dd808c98b4c10b6b334f03134153b165a194 100644 (file)
 #include <isc/managers.h>
 #include <isc/mem.h>
 #include <isc/net.h>
+#include <isc/netmgr.h>
 #include <isc/parseint.h>
 #include <isc/print.h>
 #include <isc/sockaddr.h>
-#include <isc/socket.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/util.h>
 
 #include <dns/dispatch.h>
@@ -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();
 
index c13cb5bee4160c7349573b5498c9a426ea31ecd4..6508b6e9fffe6c1b2577b2f4c9a80e00371767df 100644 (file)
@@ -27,9 +27,9 @@
 #include <isc/commandline.h>
 #include <isc/managers.h>
 #include <isc/mem.h>
+#include <isc/netmgr.h>
 #include <isc/print.h>
 #include <isc/sockaddr.h>
-#include <isc/socket.h>
 #include <isc/task.h>
 #include <isc/timer.h>
 #include <isc/util.h>
@@ -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,
index 6904c1998a5713501265d0a1d5ceac57c5c649c2..9ede9a65b5067e751f319d5266161c8cfa439677 100644 (file)
 #include <isc/log.h>
 #include <isc/managers.h>
 #include <isc/mem.h>
+#include <isc/netmgr.h>
 #include <isc/nonce.h>
 #include <isc/print.h>
 #include <isc/random.h>
 #include <isc/sockaddr.h>
-#include <isc/socket.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/util.h>
 
 #include <dns/dispatch.h>
@@ -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);
index 1b8d3dc336b837779fa97dc2bd011edf9431c7b1..c76d81613252557f312d00a8a5d8cb51447edb09 100644 (file)
@@ -22,9 +22,7 @@
 #include <isc/print.h>
 #include <isc/random.h>
 #include <isc/sockaddr.h>
-#include <isc/socket.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/util.h>
 
 #include <dns/dispatch.h>
@@ -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);
 
index 9c58a337cdfe43309250e36f824903bc52b1ac0b..f3d37da52c592c23a599e52f9ef42a4f2070ca9e 100644 (file)
 #include <isc/managers.h>
 #include <isc/mem.h>
 #include <isc/net.h>
+#include <isc/netmgr.h>
 #include <isc/nonce.h>
 #include <isc/parseint.h>
 #include <isc/print.h>
 #include <isc/random.h>
 #include <isc/sockaddr.h>
-#include <isc/socket.h>
 #include <isc/string.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/util.h>
 
 #include <dns/byaddr.h>
@@ -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();
 
index 1d113972b8493d8ce72567ea4cff0975eae196ab..70a1adb8594003aa1fd087a60bc07c3e3399ca68 100644 (file)
@@ -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;
 
index e8f78d5550a756ba8b299d9087003e83bb18e4c6..a159e79c557ad5d8030aad1c8ed3f9dc103ca5fb 100644 (file)
 
 #include <isc/mem.h>
 #include <isc/mutex.h>
+#include <isc/netmgr.h>
 #include <isc/portset.h>
 #include <isc/print.h>
 #include <isc/random.h>
-#include <isc/socket.h>
 #include <isc/stats.h>
 #include <isc/string.h>
 #include <isc/task.h>
 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;
-
-       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->local = disp->local;
+       dispsock->peer = *dest;
 
-       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;
-
-       disp->tcpbuffers++;
-       rev->result = ISC_R_SUCCESS;
-       rev->id = id;
-       rev->addr = tcpmsg->address;
+       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);
+       }
+
        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, &region, 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, &region, 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, &region, 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,46 +1123,10 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
                isc_mem_put(mgr->mctx, mgr->v6ports,
                            mgr->nv6ports * sizeof(in_port_t));
        }
-       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);
-       }
+       isc_nm_detach(&mgr->nm);
 
-       *sockp = sock;
-       return (ISC_R_SUCCESS);
+       isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t));
 }
 
 /*%
@@ -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;
-               }
-       }
-
-       disp->ntasks = 1;
-       disp->task[0] = NULL;
-       result = isc_task_create(taskmgr, 50, &disp->task[0]);
-       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;
+               isc_sockaddr_anyofpf(&disp->local, pf);
+               isc_sockaddr_setport(&disp->local, 0);
        }
 
-       if (localaddr == NULL) {
-               isc_sockaddr_anyofpf(&src, pf);
-       } else {
-               src = *localaddr;
-               isc_sockaddr_setport(&src, 0);
-       }
-
-       result = isc_socket_bind(disp->socket, &src, 0);
+       result = isc_task_create(taskmgr, 50, &disp->task);
        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));
+
+       dns_dispatch_detach(&disp);
+}
+
+/*
+ * disp must be locked.
+ */
+static void
+startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket) {
+       isc_nmhandle_t *handle = NULL;
+
        if (disp->shutting_down == 1) {
-               do_cancel(disp);
-       } else {
-               (void)startrecv(disp, NULL);
+               return;
        }
 
-       killit = destroy_disp_ok(disp);
-       UNLOCK(&disp->lock);
-       if (killit) {
-               isc_task_send(disp->task[0], &disp->ctlevent);
+       if (dispsocket == NULL) {
+               if (disp->socktype == isc_socktype_udp ||
+                   disp->recv_pending != 0) {
+                       return;
+               }
+               isc_nmhandle_attach(disp->handle, &handle);
+       } else {
+               handle = dispsocket->handle;
        }
-}
 
-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;
+       switch (disp->socktype) {
+       case isc_socktype_udp:
+               isc_nm_read(handle, udp_recv, dispsocket);
+               break;
 
-       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;
-       } else {
+       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();
        }
+}
+
+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);
+       }
 
-       return (isc_socket_connect(sock, address, task, action, arg));
+       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;
+
+       switch (disp->socktype) {
+       case isc_socktype_tcp:
+               if (disp->handle != NULL) {
+                       break;
+               }
 
-       sock = getentrysocket(resp);
+               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;
index d8fcfd3c9e9ba492e3942f3e1d3a83e9f6619433..9c3114dbd0a9d7b64560d39d2ed4cf47e83abf13 100644 (file)
@@ -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.
  *
index 0ff11844fffb8756dc9c0ea665dc45bbaeaf2bd7..aea71f9bd563bdd7aa8ac66fc230a88459ccaefd 100644 (file)
@@ -9,6 +9,8 @@
  * information regarding copyright ownership.
  */
 
+#include <isc/netmgr.h>
+
 #ifndef DNS_DISPATCH_H
 #define DNS_DISPATCH_H 1
 
@@ -50,6 +52,7 @@
 #include <isc/buffer.h>
 #include <isc/lang.h>
 #include <isc/mutex.h>
+#include <isc/netmgr.h>
 #include <isc/socket.h>
 #include <isc/types.h>
 
@@ -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  &lt;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
index 98afe5a4ae84412cd3824f3f89c4c2e809221383..9554603b50b1ce69814bd55c649f479f8cf28320 100644 (file)
@@ -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.
index 07b94fdcd1a7d519fb8d43cc5570fd33e7c4e0ae..aeda97dd38ea49d806551f8e282ca7f5a4e672f9 100644 (file)
@@ -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);
 
index bfe9abd763fbd696a97efe2e76977fdffd579b3e..5e777229e83092969411c7f7513624309d458c76 100644 (file)
@@ -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:
index 367a716d2091880ebdda1a66ea1d9cc82115f354..c629997c026120eac5e5979e8e27cd8b8f11cfa0 100644 (file)
@@ -17,7 +17,6 @@
 #include <isc/magic.h>
 #include <isc/mem.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/util.h>
 
 #include <dns/acl.h>
@@ -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),
index febec16482f61c6c67679b9665269b75011ddba0..b987b888cb29abe4dc795978bab23d7bede8c3ef 100644 (file)
@@ -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));
index aa92f4ed87a2b5bf1c17c742e46a8ecdded1f217..65a2f3d441eedf35f2c8e7a5bec385ff45b1322e 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <uv.h>
 
 #define UNIT_TESTING
 #include <cmocka.h>
 
 #include <isc/app.h>
 #include <isc/buffer.h>
+#include <isc/managers.h>
 #include <isc/refcount.h>
 #include <isc/socket.h>
 #include <isc/task.h>
-#include <isc/timer.h>
 #include <isc/util.h>
 
 #include <dns/dispatch.h>
 
 #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();
 }
 
-static void
-senddone(isc_task_t *task, isc_event_t *event) {
-       isc_socket_t *sock = event->ev_arg;
+struct {
+       isc_nmhandle_t *handle;
+       atomic_uint_fast32_t responses;
+} testdata;
 
-       UNUSED(task);
+static dns_dispatch_t *dispatch = NULL;
+static dns_dispentry_t *dispentry = NULL;
+static atomic_bool first = ATOMIC_VAR_INIT(true);
 
-       isc_socket_detach(&sock);
-       isc_event_free(&event);
+static void
+server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
+       UNUSED(handle);
+       UNUSED(eresult);
+       UNUSED(cbarg);
+
+       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, &region, 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, &region, 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, &region, 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, &region, &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, &region);
+
+       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);
 
        /*
index 5a16027e48fc1204eb8f8fae647eab8b91c72c18..fac3f25725954d901088835a7567b50ee135c12b 100644 (file)
@@ -34,6 +34,7 @@
 #include <isc/lex.h>
 #include <isc/managers.h>
 #include <isc/mem.h>
+#include <isc/netmgr.h>
 #include <isc/os.h>
 #include <isc/print.h>
 #include <isc/socket.h>
@@ -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();
        }
index 53c7c6529fa8043cf153afc3b05b5d658bf99ae5..a2c32cc1462c0198ed26351278d7aa9ba023a69b 100644 (file)
@@ -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;
index 1a6e0f6143c1b883385cc545b113e561945860ab..2989af3041a2cd75ce9ef1c80873da1ff71107a0 100644 (file)
@@ -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);
 }
 
index 27df70381103d1285b23c4ecc1c3ccc5c022728d..ed2045f1310d0c764db402288b2c2e5be29733b8 100644 (file)
@@ -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);
index 8ca9cd65aa2834a639b5905fd71ac263e1bf1f45..da4f222ab6d16bb654ecb008b108b73894b10839 100644 (file)
@@ -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
index 19cc946bc3242d9a13299f67c3d188317e897fd2..c14607f81d92a751fcbbf7a1daf39c6d04284601 100644 (file)
@@ -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,
index f86d4c8485ffd6deba5c10fdf804f9ccb134f971..628dd33fa9e1833424a80812c632dc596ea97525 100644 (file)
@@ -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:
index c28b32165c33b6f76ba21c24546ec7c87d08808c..1f3b107bf975a2b113116617c0ba760143a23b93 100644 (file)
@@ -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);
index 045c74f9cc4045bb2f99bac96f110e4349bf759e..25907942855a428f6aaa20f3b678610c910f54da 100644 (file)
@@ -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) {
index ffcf23adfaa1523142c6f3994a9a157964f6f64c..8ece586163ee7082f6a95495230d117bb5007351 100644 (file)
@@ -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,