]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
dispatch: Fix several connect-related issues
authorEvan Hunt <each@isc.org>
Wed, 4 Aug 2021 01:24:27 +0000 (18:24 -0700)
committerEvan Hunt <each@isc.org>
Sat, 2 Oct 2021 18:39:56 +0000 (11:39 -0700)
- startrecv() and getnext() have been rewritten.

- Don't set TCP flag when connecting a UDP dispatch.

- Prevent TCP connections from trying to connect twice.

- dns_dispatch_gettcp() can now find a matching TCP dispatch that has
  not yet fully connected, and attach to it.  when the connection is
  completed, the connect callbacks are run for all of the pending
  entries.

- An atomic 'state' variable is now used for connection state instead of
  attributes.

- When dns_dispatch_cancel() is called on a TCP dispatch entry, only
  that one entry is canceled. the dispatch itself should not be shut
  down until there are no dispatch entries left associated with it.

- Other incidental cleanup, including removing DNS_DISPATCHATTR_IPV4 and
  _IPV6 (they were being set in the dispatch attributes but never used),
  cleaning up dns_requestmgr_create(), and renaming dns_dispatch_read()
  to the more descriptive dns_dispatch_resume().

bin/named/server.c
bin/nsupdate/nsupdate.c
bin/tests/system/pipelined/pipequeries.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/dispatch.h
lib/dns/request.c
lib/dns/resolver.c

index dd929b881bc512eb1b490f2fee545c128a8f9da9..31c9af55724bfa07c7e35bf618023587ee4e2bed 100644 (file)
@@ -1258,7 +1258,6 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
        isc_result_t result = ISC_R_FAILURE;
        dns_dispatch_t *disp = NULL;
        isc_sockaddr_t sa;
-       unsigned int attrs = 0;
        const cfg_obj_t *obj = NULL;
        isc_dscp_t dscp = -1;
 
@@ -1315,7 +1314,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
                }
        }
 
-       result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, attrs, &disp);
+       result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
        if (result != ISC_R_SUCCESS) {
                isc_sockaddr_t any;
                char buf[ISC_SOCKADDR_FORMATSIZE];
@@ -10330,7 +10329,6 @@ named_add_reserved_dispatch(named_server_t *server,
        in_port_t port;
        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
        isc_result_t result;
-       unsigned int attrs = 0;
 
        REQUIRE(NAMED_SERVER_VALID(server));
 
@@ -10358,7 +10356,7 @@ named_add_reserved_dispatch(named_server_t *server,
        dispatch->dispatch = NULL;
 
        result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr,
-                                       attrs, &dispatch->dispatch);
+                                       &dispatch->dispatch);
        if (result != ISC_R_SUCCESS) {
                goto cleanup;
        }
index 320e3812c094897606f1ebc0609dffee2696a6b3..4aa9289cb2521ba11368b318e1502ef7054931fe 100644 (file)
@@ -936,14 +936,14 @@ setup_system(void) {
 
        if (have_ipv6) {
                isc_sockaddr_any6(&bind_any6);
-               result = dns_dispatch_createudp(dispatchmgr, &bind_any6, 0,
+               result = dns_dispatch_createudp(dispatchmgr, &bind_any6,
                                                &dispatchv6);
                check_result(result, "dns_dispatch_createudp (v6)");
        }
 
        if (have_ipv4) {
                isc_sockaddr_any(&bind_any);
-               result = dns_dispatch_createudp(dispatchmgr, &bind_any, 0,
+               result = dns_dispatch_createudp(dispatchmgr, &bind_any,
                                                &dispatchv4);
                check_result(result, "dns_dispatch_createudp (v4)");
        }
index 238e04c0f1f4c1892b4a5c0c56b19c35d062b8f9..342ff1203988b8c496eaba5e5e5b9cba44eebfb2 100644 (file)
@@ -270,7 +270,7 @@ main(int argc, char *argv[]) {
        RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
 
        RUNCHECK(dns_dispatch_createudp(
-               dispatchmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchv4));
+               dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchv4));
        RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4,
                                       NULL, &requestmgr));
 
index ab10793a12df3d12327ea39f187911a080a73e43..79cfdeeb2cf7622989d6e688d659704b875a808e 100644 (file)
@@ -228,8 +228,7 @@ main(int argc, char *argv[]) {
        RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
 
        isc_sockaddr_any(&bind_any);
-       RUNCHECK(
-               dns_dispatch_createudp(dispatchmgr, &bind_any, 0, &dispatchv4));
+       RUNCHECK(dns_dispatch_createudp(dispatchmgr, &bind_any, &dispatchv4));
        RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4,
                                       NULL, &requestmgr));
 
index c81c306a8c387d22e31f4b6a16fb030910884531..f5a2a174728a443cb9424655d08c40edf2101af3 100644 (file)
@@ -171,8 +171,7 @@ main(int argc, char **argv) {
        RUNCHECK(isc_task_create(taskmgr, 0, &task));
        RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
        isc_sockaddr_any(&bind_any);
-       RUNCHECK(
-               dns_dispatch_createudp(dispatchmgr, &bind_any, 0, &dispatchv4));
+       RUNCHECK(dns_dispatch_createudp(dispatchmgr, &bind_any, &dispatchv4));
        RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4,
                                       NULL, &requestmgr));
 
index 5be81925d94f3e2e7f6f3995368f12eba379ad12..2c88c909083e2b980fda3846bdf294129dfeeef2 100644 (file)
@@ -2129,7 +2129,7 @@ main(int argc, char *argv[]) {
                isc_sockaddr_any6(&bind_any);
        }
        RUNCHECK(dns_dispatch_createudp(
-               dispatchmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchvx));
+               dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchvx));
 
        RUNCHECK(dns_requestmgr_create(
                mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL,
index 83b21bb12e502013b03f925b7cbee4e70bae0c91..9902e2d5710968a6da196f0f20a677ae8156effa 100644 (file)
@@ -212,7 +212,7 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
                localaddr = &anyaddr;
        }
 
-       result = dns_dispatch_createudp(dispatchmgr, localaddr, 0, &disp);
+       result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp);
        if (result == ISC_R_SUCCESS) {
                *dispp = disp;
        }
index 0475d670559e731168f7449ec8fba77c3fb11d7c..341ac8630812b0afa634629739262c2499890c0f 100644 (file)
@@ -17,6 +17,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <isc/atomic.h>
 #include <isc/mem.h>
 #include <isc/mutex.h>
 #include <isc/netmgr.h>
@@ -89,6 +90,7 @@ struct dns_dispentry {
        bool canceled;
        ISC_LINK(dns_dispentry_t) link;
        ISC_LINK(dns_dispentry_t) alink;
+       ISC_LINK(dns_dispentry_t) plink;
 };
 
 /*%
@@ -98,6 +100,12 @@ struct dns_dispentry {
 #define DNS_DISPATCH_UDPBUFSIZE 4096
 #endif /* ifndef DNS_DISPATCH_UDPBUFSIZE */
 
+typedef enum {
+       DNS_DISPATCHSTATE_NONE = 0UL,
+       DNS_DISPATCHSTATE_CONNECTING,
+       DNS_DISPATCHSTATE_CONNECTED
+} dns_dispatchstate_t;
+
 struct dns_dispatch {
        /* Unlocked. */
        unsigned int magic;     /*%< magic */
@@ -113,10 +121,11 @@ struct dns_dispatch {
        /* Locked by "lock". */
        isc_mutex_t lock; /*%< locks all below */
        isc_socktype_t socktype;
-       unsigned int attributes;
+       atomic_uint_fast32_t state;
        isc_refcount_t references;
        unsigned int shutdown_out : 1;
 
+       ISC_LIST(dns_dispentry_t) pending;
        ISC_LIST(dns_dispentry_t) active;
        unsigned int nsockets;
 
@@ -193,15 +202,15 @@ static void
 dispatch_free(dns_dispatch_t **dispp);
 static isc_result_t
 dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
-                  unsigned int attributes, dns_dispatch_t **dispp);
+                  dns_dispatch_t **dispp);
 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 inline isc_nmhandle_t *
-getentryhandle(dns_dispentry_t *resp);
 static void
-startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp);
+startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp);
+void
+dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout);
 
 #define LVL(x) ISC_LOG_DEBUG(x)
 
@@ -327,7 +336,13 @@ deactivate_dispentry(dns_dispatch_t *disp, dns_dispentry_t *resp) {
                ISC_LIST_UNLINK(disp->active, resp, alink);
        }
 
+       if (ISC_LINK_LINKED(resp, plink)) {
+               ISC_LIST_UNLINK(disp->pending, resp, plink);
+       }
+
        if (resp->handle != NULL) {
+               INSIST(disp->socktype == isc_socktype_udp);
+
                isc_nm_cancelread(resp->handle);
                isc_nmhandle_detach(&resp->handle);
        }
@@ -418,6 +433,11 @@ dispentry_detach(dns_dispentry_t **respp) {
  *     if event queue is not empty, queue.  else, send.
  *     restart.
  */
+
+/* FIXME: If we read invalid packet, we never receive next that could be valid
+ * and we also don't notify the read callback
+ */
+
 static void
 udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
         void *arg) {
@@ -431,7 +451,6 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
        isc_netaddr_t netaddr;
        int match;
        dispatch_cb_t response = NULL;
-       bool nomore = true;
 
        REQUIRE(VALID_RESPONSE(resp));
        REQUIRE(VALID_DISPATCH(resp->disp));
@@ -461,14 +480,6 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
        peer = isc_nmhandle_peeraddr(handle);
        isc_netaddr_fromsockaddr(&netaddr, &peer);
 
-       /* if (eresult == ISC_R_TIMEDOUT && resp->timedout != NULL) { */
-       /*      resp->timedout(handle, ISC_R_TIMEDOUT, resp->arg); */
-       /*      if (isc_nmhandle_timer_running(handle)) { */
-       /*              nomore = false; */
-       /*              goto unlock; */
-       /*      } */
-       /* } */
-
        if (eresult != ISC_R_SUCCESS) {
                /*
                 * This is most likely a network error on a connected
@@ -547,9 +558,7 @@ unlock:
                response(eresult, region, resp->arg);
        }
 
-       if (nomore) {
-               dispentry_detach(&resp);
-       }
+       dispentry_detach(&resp);
 }
 
 /*
@@ -570,9 +579,8 @@ unlock:
 static void
 tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
         void *arg) {
-       dns_dispentry_t *resp0 = (dns_dispentry_t *)arg;
+       dns_dispatch_t *disp = (dns_dispatch_t *)arg;
        dns_dispentry_t *resp = NULL;
-       dns_dispatch_t *disp = NULL;
        dns_messageid_t id;
        isc_result_t dres;
        unsigned int flags;
@@ -583,10 +591,7 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
        isc_buffer_t source;
        isc_sockaddr_t peer;
 
-       REQUIRE(VALID_RESPONSE(resp0));
-       REQUIRE(VALID_DISPATCH(resp0->disp));
-
-       disp = resp0->disp;
+       REQUIRE(VALID_DISPATCH(disp));
 
        qid = disp->mgr->qid;
 
@@ -597,46 +602,43 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
 
        peer = isc_nmhandle_peeraddr(handle);
 
-       if (eresult != ISC_R_SUCCESS) {
-               switch (eresult) {
-               case ISC_R_CANCELED:
-                       dispatch_log(disp, LVL(90), "shutting down on cancel");
-                       break;
+       switch (eresult) {
+       case ISC_R_SUCCESS:
+               /* got our answer */
+               break;
+       case ISC_R_CANCELED:
+               dispatch_log(disp, LVL(90), "shutting down on cancel");
+               goto unlock;
 
-               case ISC_R_EOF:
-                       dispatch_log(disp, LVL(90), "shutting down on EOF");
-                       break;
+       case ISC_R_EOF:
+               dispatch_log(disp, LVL(90), "shutting down on EOF");
+               goto unlock;
 
-               case ISC_R_TIMEDOUT:
-                       /*
-                        * Time out the first active response for which
-                        * no event has already been sent.
-                        * FIXME: The code doesn't match the description
-                        */
-                       for (resp = ISC_LIST_HEAD(disp->active); resp != NULL;
-                            resp = ISC_LIST_NEXT(resp, alink))
-                       {
-                               ISC_LIST_UNLINK(disp->active, resp, alink);
-                               ISC_LIST_APPEND(disp->active, resp, alink);
-                               break;
-                       }
-                       break;
+       case ISC_R_TIMEDOUT:
+               /*
+                * Time out the first active response for which
+                * no event has already been sent.
+                */
+               resp = ISC_LIST_HEAD(disp->active);
+               INSIST(resp != NULL);
 
-               default:
-                       if (eresult == ISC_R_CONNECTIONRESET) {
-                               level = ISC_LOG_INFO;
-                       } else {
-                               level = ISC_LOG_ERROR;
-                       }
+               ISC_LIST_UNLINK(disp->active, resp, alink);
+               ISC_LIST_APPEND(disp->active, resp, alink);
 
-                       isc_sockaddr_format(&peer, buf, sizeof(buf));
-                       dispatch_log(disp, level,
-                                    "shutting down due to TCP "
-                                    "receive error: %s: %s",
-                                    buf, isc_result_totext(eresult));
-                       break;
+               goto unlock;
+
+       default:
+               if (eresult == ISC_R_CONNECTIONRESET) {
+                       level = ISC_LOG_INFO;
+               } else {
+                       level = ISC_LOG_ERROR;
                }
 
+               isc_sockaddr_format(&peer, buf, sizeof(buf));
+               dispatch_log(disp, level,
+                            "shutting down due to TCP "
+                            "receive error: %s: %s",
+                            buf, isc_result_totext(eresult));
                goto unlock;
        }
 
@@ -684,22 +686,18 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
                     bucket, (resp == NULL ? "not found" : "found"));
        UNLOCK(&qid->lock);
 
-       if (resp == NULL) {
-               goto unlock;
-       }
-
 next:
-       startrecv(disp, resp0);
+       /* Restart the reading from the TCP socket */
+       dispatch_getnext(disp, resp, -1);
 
 unlock:
-       isc_nmhandle_detach(&handle);
        UNLOCK(&disp->lock);
 
-       dispentry_detach(&resp0);
-
        if (resp != NULL) {
                resp->response(eresult, region, resp->arg);
        }
+
+       dns_dispatch_detach(&disp);
 }
 
 /*%
@@ -936,8 +934,8 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
  * Allocate and set important limits.
  */
 static void
-dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf,
-                 unsigned int attributes, dns_dispatch_t **dispp) {
+dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type,
+                 dns_dispatch_t **dispp) {
        dns_dispatch_t *disp = NULL;
 
        REQUIRE(VALID_DISPATCHMGR(mgr));
@@ -955,38 +953,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf,
        isc_refcount_init(&disp->references, 1);
        ISC_LINK_INIT(disp, link);
        ISC_LIST_INIT(disp->active);
-
-       switch (type) {
-       case isc_socktype_tcp:
-               disp->attributes |= DNS_DISPATCHATTR_TCP;
-               break;
-       case isc_socktype_udp:
-               disp->attributes |= DNS_DISPATCHATTR_UDP;
-               break;
-       default:
-               INSIST(0);
-               ISC_UNREACHABLE();
-       }
-
-       switch (pf) {
-       case PF_INET:
-               disp->attributes |= DNS_DISPATCHATTR_IPV4;
-               break;
-       case PF_INET6:
-               disp->attributes |= DNS_DISPATCHATTR_IPV6;
-               break;
-       default:
-               INSIST(0);
-               ISC_UNREACHABLE();
-       }
-
-       /*
-        * Set whatever attributes were passed in that haven't been
-        * reset automatically by the code above.
-        */
-       attributes &= ~(DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP |
-                       DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6);
-       disp->attributes |= attributes;
+       ISC_LIST_INIT(disp->pending);
 
        isc_mutex_init(&disp->lock);
 
@@ -1022,10 +989,9 @@ dispatch_free(dns_dispatch_t **dispp) {
 
 isc_result_t
 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
-                      const isc_sockaddr_t *destaddr, unsigned int attributes,
-                      isc_dscp_t dscp, dns_dispatch_t **dispp) {
+                      const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
+                      dns_dispatch_t **dispp) {
        dns_dispatch_t *disp = NULL;
-       int pf;
 
        REQUIRE(VALID_DISPATCHMGR(mgr));
        REQUIRE(destaddr != NULL);
@@ -1034,14 +1000,15 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
 
        LOCK(&mgr->lock);
 
-       pf = isc_sockaddr_pf(destaddr);
-       dispatch_allocate(mgr, isc_socktype_tcp, pf, attributes, &disp);
+       dispatch_allocate(mgr, isc_socktype_tcp, &disp);
 
        disp->peer = *destaddr;
 
        if (localaddr != NULL) {
                disp->local = *localaddr;
        } else {
+               int pf;
+               pf = isc_sockaddr_pf(destaddr);
                isc_sockaddr_anyofpf(&disp->local, pf);
                isc_sockaddr_setport(&disp->local, 0);
        }
@@ -1049,6 +1016,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
        /*
         * Append it to the dispatcher list.
         */
+
+       /* FIXME: There should be a lookup hashtable here */
        ISC_LIST_APPEND(mgr->list, disp, link);
        UNLOCK(&mgr->lock);
 
@@ -1062,28 +1031,25 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
        return (ISC_R_SUCCESS);
 }
 
-#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
-
 isc_result_t
 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;
-       unsigned int attributes, mask;
 
        REQUIRE(VALID_DISPATCHMGR(mgr));
        REQUIRE(destaddr != NULL);
+       REQUIRE(connected != NULL);
        REQUIRE(dispp != NULL && *dispp == NULL);
 
-       /* First pass  */
-       attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
-       mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
-              DNS_DISPATCHATTR_CONNECTED;
+       /* First pass, look for connected TCP dispatches */
+       *connected = true;
 
        LOCK(&mgr->lock);
 again:
-       disp = ISC_LIST_HEAD(mgr->list);
-       while (disp != NULL && *dispp == NULL) {
+       for (disp = ISC_LIST_HEAD(mgr->list); disp != NULL && *dispp == NULL;
+            disp = ISC_LIST_NEXT(disp, link))
+       {
                isc_sockaddr_t sockname;
                isc_sockaddr_t peeraddr;
 
@@ -1097,23 +1063,41 @@ again:
                        peeraddr = disp->peer;
                }
 
-               if (ATTRMATCH(disp->attributes, attributes, mask) &&
-                   (localaddr == NULL ||
-                    isc_sockaddr_eqaddr(localaddr, &disp->local)))
+               if (*connected == true &&
+                   atomic_load(&disp->state) != DNS_DISPATCHSTATE_CONNECTED)
                {
-                       if (isc_sockaddr_equal(destaddr, &peeraddr) &&
-                           (localaddr == NULL ||
-                            isc_sockaddr_eqaddr(localaddr, &sockname)))
+                       goto unlock;
+               }
+
+               /* We don't reuse UDP sockets */
+               if (disp->socktype != isc_socktype_tcp) {
+                       goto unlock;
+               }
+
+               /* Different destination address */
+               if (!isc_sockaddr_equal(destaddr, &peeraddr)) {
+                       goto unlock;
+               }
+
+               /* Different local addr */
+               if (localaddr != NULL) {
+                       /* FIXME: This is weird as sockname == disp-local */
+                       if (!isc_sockaddr_eqaddr(localaddr, &disp->local) ||
+                           !isc_sockaddr_eqaddr(localaddr, &sockname))
                        {
-                               /* attach */
-                               dns_dispatch_attach(disp, dispp);
-                               if (connected != NULL) {
-                                       *connected = true;
-                               }
+                               goto unlock;
                        }
                }
+
+               /*
+                * The conditions match:
+                * 1. socktype is TCP
+                * 2. destination address is same
+                * 3. local address is either NULL or same
+                */
+               dns_dispatch_attach(disp, dispp);
+       unlock:
                UNLOCK(&disp->lock);
-               disp = ISC_LIST_NEXT(disp, link);
        }
 
        if (*dispp != NULL) {
@@ -1121,10 +1105,9 @@ again:
                return (ISC_R_SUCCESS);
        }
 
-       if (connected != NULL) {
-               /* Second pass, only if connected != NULL */
-               attributes = DNS_DISPATCHATTR_TCP;
-               connected = NULL;
+       if (*connected) {
+               /* Second pass, look also for not-yet-connected dispatch */
+               *connected = false;
                goto again;
        }
 
@@ -1134,7 +1117,7 @@ again:
 
 isc_result_t
 dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
-                      unsigned int attributes, dns_dispatch_t **dispp) {
+                      dns_dispatch_t **dispp) {
        isc_result_t result;
        dns_dispatch_t *disp = NULL;
 
@@ -1143,7 +1126,7 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
        REQUIRE(dispp != NULL && *dispp == NULL);
 
        LOCK(&mgr->lock);
-       result = dispatch_createudp(mgr, localaddr, attributes, &disp);
+       result = dispatch_createudp(mgr, localaddr, &disp);
        if (result == ISC_R_SUCCESS) {
                *dispp = disp;
        }
@@ -1154,19 +1137,17 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
 
 static isc_result_t
 dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
-                  unsigned int attributes, dns_dispatch_t **dispp) {
+                  dns_dispatch_t **dispp) {
        isc_result_t result = ISC_R_SUCCESS;
        dns_dispatch_t *disp = NULL;
        isc_sockaddr_t sa_any;
-       int pf;
 
-       pf = isc_sockaddr_pf(localaddr);
-       dispatch_allocate(mgr, isc_socktype_udp, pf, attributes, &disp);
+       dispatch_allocate(mgr, isc_socktype_udp, &disp);
 
        /*
         * Check whether this address/port is available locally.
         */
-       isc_sockaddr_anyofpf(&sa_any, pf);
+       isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
        if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
                result = isc_nm_checkaddr(localaddr, isc_socktype_udp);
                if (result != ISC_R_SUCCESS) {
@@ -1207,7 +1188,7 @@ cleanup:
 }
 
 static void
-dns_dispatch_destroy(dns_dispatch_t *disp) {
+dispatch_destroy(dns_dispatch_t *disp) {
        dns_dispatchmgr_t *mgr = disp->mgr;
 
        LOCK(&mgr->lock);
@@ -1223,8 +1204,9 @@ dns_dispatch_destroy(dns_dispatch_t *disp) {
 
        dispatch_free(&disp);
 
-       /* Because dispatch uses mgr->mctx, we must detach after freeing
-        * dispatch, not before
+       /*
+        * Because dispatch uses mgr->mctx, we must detach after freeing
+        * dispatch, not before.
         */
        dns_dispatchmgr_detach(&mgr);
 }
@@ -1253,10 +1235,11 @@ dns_dispatch_detach(dns_dispatch_t **dispp) {
        dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1);
        if (ref == 1) {
                LOCK(&disp->lock);
-               REQUIRE(ISC_LIST_EMPTY(disp->active));
+               INSIST(ISC_LIST_EMPTY(disp->pending));
+               INSIST(ISC_LIST_EMPTY(disp->active));
                UNLOCK(&disp->lock);
 
-               dns_dispatch_destroy(disp);
+               dispatch_destroy(disp);
        }
 }
 
@@ -1321,6 +1304,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
 
        ISC_LINK_INIT(res, link);
        ISC_LINK_INIT(res, alink);
+       ISC_LINK_INIT(res, plink);
 
        if (disp->socktype == isc_socktype_udp) {
                isc_result_t result = setup_socket(disp, res, dest, &localport);
@@ -1393,6 +1377,40 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
        return (ISC_R_SUCCESS);
 }
 
+void
+dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) {
+       REQUIRE(timeout <= UINT16_MAX);
+
+       /*
+        * FIXME: Since there's no global timeout now, any call to getnext will
+        * always restart the read timer, so it's possible to keep the client
+        * connecting until end of times by just feeding it with invalid
+        * packets.
+        */
+       switch (disp->socktype) {
+       case isc_socktype_udp:
+               dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
+
+               if (timeout > 0) {
+                       isc_nmhandle_settimeout(resp->handle, timeout);
+               }
+               isc_nm_read(resp->handle, udp_recv, resp);
+
+               break;
+       case isc_socktype_tcp:
+               dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
+
+               if (timeout > 0) {
+                       isc_nmhandle_settimeout(disp->handle, timeout);
+               }
+               isc_nm_read(disp->handle, tcp_recv, disp);
+               break;
+       default:
+               INSIST(0);
+               ISC_UNREACHABLE();
+       }
+}
+
 isc_result_t
 dns_dispatch_getnext(dns_dispentry_t *resp) {
        dns_dispatch_t *disp = NULL;
@@ -1404,7 +1422,7 @@ dns_dispatch_getnext(dns_dispentry_t *resp) {
 
        LOCK(&disp->lock);
 
-       startrecv(disp, resp);
+       dispatch_getnext(disp, resp, resp->timeout);
 
        UNLOCK(&disp->lock);
 
@@ -1456,27 +1474,23 @@ dns_dispatch_removeresponse(dns_dispentry_t **respp) {
  * disp must be locked.
  */
 static void
-startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) {
+startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp) {
        switch (disp->socktype) {
        case isc_socktype_udp:
-               REQUIRE(resp != NULL && resp->handle != NULL);
+               REQUIRE(resp != NULL && resp->handle == NULL);
 
+               isc_nmhandle_attach(handle, &resp->handle);
                dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
                isc_nm_read(resp->handle, udp_recv, resp);
                break;
 
        case isc_socktype_tcp:
                REQUIRE(resp != NULL && resp->handle == NULL);
-               REQUIRE(disp->handle != NULL);
-
-               if (isc_nmhandle_timer_running(disp->handle)) {
-                       isc_nmhandle_settimeout(disp->handle, resp->timeout);
-                       break;
-               }
+               REQUIRE(disp != NULL && disp->handle == NULL);
 
-               isc_nmhandle_attach(disp->handle, &(isc_nmhandle_t *){ NULL });
-               dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
-               isc_nm_read(disp->handle, tcp_recv, resp);
+               isc_nmhandle_attach(handle, &disp->handle);
+               dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
+               isc_nm_read(disp->handle, tcp_recv, disp);
                break;
 
        default:
@@ -1485,34 +1499,30 @@ startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) {
        }
 }
 
+/*
+ * FIXME: Split into tcp_connected() and udp_connected()
+ */
+
 static void
 disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
        dns_dispentry_t *resp = (dns_dispentry_t *)arg;
+       dns_dispentry_t *pending = NULL, *next = NULL;
        dns_dispatch_t *disp = resp->disp;
 
-       if (resp->canceled && eresult == ISC_R_SUCCESS) {
-               eresult = ISC_R_CANCELED;
-               goto detach;
-       }
-
        if (eresult == ISC_R_SUCCESS) {
-               switch (disp->socktype) {
-               case isc_socktype_udp:
-                       isc_nmhandle_attach(handle, &resp->handle);
-                       startrecv(disp, resp);
-                       break;
-               case isc_socktype_tcp:
-                       REQUIRE(disp->handle == NULL);
-                       LOCK(&disp->lock);
-                       isc_nmhandle_attach(handle, &disp->handle);
-                       disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
-                       UNLOCK(&disp->lock);
-                       startrecv(disp, resp);
-                       break;
-               default:
-                       INSIST(0);
-                       ISC_UNREACHABLE();
+               if (resp->canceled) {
+                       dispentry_detach(&resp);
+                       return;
                }
+
+               if (disp->socktype == isc_socktype_tcp) {
+                       REQUIRE(atomic_compare_exchange_strong(
+                               &disp->state,
+                               &(uint_fast32_t){ DNS_DISPATCHSTATE_CONNECTING },
+                               DNS_DISPATCHSTATE_CONNECTED));
+               }
+
+               startrecv(handle, disp, resp);
        }
 
        if (MGR_IS_SHUTTINGDOWN(disp->mgr)) {
@@ -1523,26 +1533,64 @@ disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
                resp->connected(eresult, NULL, resp->arg);
        }
 
-detach:
+       for (pending = ISC_LIST_HEAD(disp->pending); pending != NULL;
+            pending = next) {
+               next = ISC_LIST_NEXT(pending, plink);
+               ISC_LIST_UNLINK(disp->pending, pending, plink);
+
+               if (pending->connected != NULL) {
+                       pending->connected(eresult, NULL, pending->arg);
+               }
+               dispentry_detach(&pending);
+       }
+
        dispentry_detach(&resp);
 }
 
 isc_result_t
 dns_dispatch_connect(dns_dispentry_t *resp) {
        dns_dispatch_t *disp = NULL;
-       dns_dispentry_t *tmp = NULL;
+       uint_fast32_t state = DNS_DISPATCHSTATE_NONE;
 
        REQUIRE(VALID_RESPONSE(resp));
 
        disp = resp->disp;
 
-       dispentry_attach(resp, &tmp); /* detached in disp_connected */
+       /* This will be detached in disp_connected() */
+       dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
 
        switch (disp->socktype) {
        case isc_socktype_tcp:
-               INSIST(disp->handle == NULL);
-               isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer,
-                                    disp_connected, resp, resp->timeout, 0);
+               /*
+                * Check whether the dispatch was already connecting.
+                * If so, add resp to the pending responses.
+                */
+               atomic_compare_exchange_strong(&disp->state,
+                                              (uint_fast32_t *)&state,
+                                              DNS_DISPATCHSTATE_CONNECTING);
+
+               switch (state) {
+               case DNS_DISPATCHSTATE_NONE:
+                       /* First connection, continue with connecting */
+                       INSIST(disp->handle == NULL);
+                       isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local,
+                                            &disp->peer, disp_connected, resp,
+                                            resp->timeout, 0);
+                       break;
+               case DNS_DISPATCHSTATE_CONNECTING:
+                       ISC_LIST_APPEND(disp->pending, resp, plink);
+                       return (ISC_R_SUCCESS);
+               case DNS_DISPATCHSTATE_CONNECTED:
+                       /* We are already connected, call the connected cb */
+                       if (resp->connected != NULL) {
+                               resp->connected(ISC_R_SUCCESS, NULL, resp->arg);
+                       }
+                       return (ISC_R_SUCCESS);
+               default:
+                       INSIST(0);
+                       ISC_UNREACHABLE();
+               }
+
                break;
        case isc_socktype_udp:
                isc_nm_udpconnect(disp->mgr->nm, &resp->local, &resp->peer,
@@ -1571,31 +1619,15 @@ send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
 }
 
 void
-dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout) {
-       REQUIRE(resp != NULL);
-
-       dns_dispatch_t *disp = resp->disp;
-       isc_nmhandle_t *handle = NULL;
-
-       switch (disp->socktype) {
-       case isc_socktype_udp:
-               REQUIRE(resp->handle != NULL);
-
-               handle = resp->handle;
+dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout) {
+       dns_dispatch_t *disp = NULL;
+       REQUIRE(VALID_RESPONSE(resp));
 
-               break;
-       case isc_socktype_tcp:
-               REQUIRE(disp != NULL && disp->handle == NULL);
+       disp = resp->disp;
 
-               handle = disp->handle;
-               break;
-       default:
-               INSIST(0);
-               ISC_UNREACHABLE();
-       }
+       REQUIRE(VALID_DISPATCH(disp));
 
-       isc_nmhandle_settimeout(handle, timeout);
-       startrecv(disp, resp);
+       dispatch_getnext(disp, resp, timeout);
 }
 
 void
@@ -1606,8 +1638,6 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) {
 
        UNUSED(dscp);
 
-       handle = getentryhandle(resp);
-
 #if 0
        /* XXX: no DSCP support */
        if (dscp == -1) {
@@ -1622,6 +1652,12 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) {
        }
 #endif
 
+       if (resp->disp->socktype == isc_socktype_tcp) {
+               handle = resp->disp->handle;
+       } else {
+               handle = resp->handle;
+       }
+
        dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
        isc_nm_send(handle, r, send_done, resp);
 }
@@ -1632,28 +1668,30 @@ dns_dispatch_cancel(dns_dispentry_t *resp) {
 
        resp->canceled = true;
 
-       if (resp->handle) {
+       /* UDP case. */
+       if (resp->handle != NULL) {
                isc_nm_cancelread(resp->handle);
-       } else if (resp->disp->handle != NULL) {
-               isc_nm_cancelread(resp->disp->handle);
+               return;
        }
-}
 
-static inline isc_nmhandle_t *
-getentryhandle(dns_dispentry_t *resp) {
-       isc_nmhandle_t *handle = NULL;
-
-       REQUIRE(VALID_RESPONSE(resp));
-
-       if (resp->disp->socktype == isc_socktype_tcp) {
-               handle = resp->disp->handle;
-       } else {
-               handle = resp->handle;
+       /*
+        * TCP case. We only want to cancel if this is the last resp
+        * listening on this TCP connection.
+        */
+       if (ISC_LINK_LINKED(resp, plink)) {
+               ISC_LIST_UNLINK(resp->disp->pending, resp, plink);
+               if (resp->connected != NULL) {
+                       resp->connected(ISC_R_CANCELED, NULL, resp->arg);
+               }
+       } else if (ISC_LINK_LINKED(resp, alink)) {
+               ISC_LIST_UNLINK(resp->disp->active, resp, alink);
+               if (ISC_LIST_EMPTY(resp->disp->active) &&
+                   resp->disp->handle != NULL) {
+                       isc_nm_cancelread(resp->disp->handle);
+               } else if (resp->response != NULL) {
+                       resp->response(ISC_R_CANCELED, NULL, resp->arg);
+               }
        }
-
-       INSIST(handle != NULL);
-
-       return (handle);
 }
 
 isc_result_t
@@ -1686,29 +1724,6 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) {
        return (ISC_R_NOTIMPLEMENTED);
 }
 
-unsigned int
-dns_dispatch_getattributes(dns_dispatch_t *disp) {
-       REQUIRE(VALID_DISPATCH(disp));
-
-       /*
-        * We don't bother locking disp here; it's the caller's
-        * responsibility to use only non volatile flags.
-        */
-       return (disp->attributes);
-}
-
-void
-dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes,
-                             unsigned int mask) {
-       REQUIRE(VALID_DISPATCH(disp));
-
-       LOCK(&disp->lock);
-
-       disp->attributes &= ~mask;
-       disp->attributes |= (attributes & mask);
-       UNLOCK(&disp->lock);
-}
-
 dns_dispatch_t *
 dns_dispatchset_get(dns_dispatchset_t *dset) {
        dns_dispatch_t *disp = NULL;
@@ -1738,7 +1753,7 @@ dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
        int i, j;
 
        REQUIRE(VALID_DISPATCH(source));
-       REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0);
+       REQUIRE(source->socktype == isc_socktype_udp);
        REQUIRE(dsetp != NULL && *dsetp == NULL);
 
        mgr = source->mgr;
@@ -1759,7 +1774,6 @@ dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
        for (i = 1; i < n; i++) {
                dset->dispatches[i] = NULL;
                result = dispatch_createudp(mgr, &source->local,
-                                           source->attributes,
                                            &dset->dispatches[i]);
                if (result != ISC_R_SUCCESS) {
                        goto fail;
index a4686724fa86695d21972e5089e44094b77f9ff5..93f676f5f94bbeed9b12242c2a21924fd46d3d7b 100644 (file)
@@ -9,10 +9,9 @@
  * information regarding copyright ownership.
  */
 
-#include <isc/netmgr.h>
+#pragma once
 
-#ifndef DNS_DISPATCH_H
-#define DNS_DISPATCH_H 1
+#include <isc/netmgr.h>
 
 /*****
 ***** Module Info
 /*! \file dns/dispatch.h
  * \brief
  * DNS Dispatch Management
- *     Shared UDP and single-use TCP dispatches for queries and responses.
+ *     Shared UDP and single-use TCP dispatches for queries and responses.
  *
  * MP:
  *
- *\li          All locking is performed internally to each dispatch.
- *     Restrictions apply to dns_dispatch_removeresponse().
+ *\li  All locking is performed internally to each dispatch.
+ *     Restrictions apply to dns_dispatch_removeresponse().
  *
  * Reliability:
  *
@@ -72,33 +71,6 @@ struct dns_dispatchset {
        isc_mutex_t      lock;
 };
 
-/*@{*/
-/*%
- * Attributes for added dispatchers.
- *
- * Values with the mask 0xffff0000 are application defined.
- * Values with the mask 0x0000ffff are library defined.
- *
- * Insane values (like setting both TCP and UDP) are not caught.  Don't
- * do that.
- *
- * _PRIVATE
- *     The dispatcher cannot be shared.
- *
- * _TCP, _UDP
- *     The dispatcher is a TCP or UDP socket.
- *
- * _IPV4, _IPV6
- *     The dispatcher uses an IPv4 or IPv6 socket.
- */
-#define DNS_DISPATCHATTR_PRIVATE   0x00000001U
-#define DNS_DISPATCHATTR_TCP      0x00000002U
-#define DNS_DISPATCHATTR_UDP      0x00000004U
-#define DNS_DISPATCHATTR_IPV4     0x00000008U
-#define DNS_DISPATCHATTR_IPV6     0x00000010U
-#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
-/*@}*/
-
 /*
  */
 #define DNS_DISPATCHOPT_FIXEDID 0x00000001U
@@ -161,7 +133,7 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr);
  * without incrementing its reference count.
  *
  * Requires:
- *\li  mgr is a valid dispatchmgr
+ *\li  mgr is a valid dispatchmgr
  * Returns:
  *\li  A pointer to the current blackhole list, or NULL.
  */
@@ -195,7 +167,7 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats);
 
 isc_result_t
 dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
-                      unsigned int attributes, dns_dispatch_t **dispp);
+                      dns_dispatch_t **dispp);
 /*%<
  * Create a new UDP dispatch.
  *
@@ -212,8 +184,8 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
 
 isc_result_t
 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
-                      const isc_sockaddr_t *destaddr, unsigned int attributes,
-                      isc_dscp_t dscp, dns_dispatch_t **dispp);
+                      const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
+                      dns_dispatch_t **dispp);
 /*%<
  * Create a new dns_dispatch and attach it to the provided isc_socket_t.
  *
@@ -280,7 +252,14 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp);
  */
 
 void
-dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout);
+dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout);
+/*%<
+ * Reset the read timeout in the socket associated with 'resp' and
+ * continue reading.
+ *
+ * Requires:
+ *\li  'resp' is valid.
+ */
 
 isc_result_t
 dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
@@ -375,41 +354,6 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp);
  *\li  ISC_R_NOTIMPLEMENTED
  */
 
-unsigned int
-dns_dispatch_getattributes(dns_dispatch_t *disp);
-/*%<
- * Return the attributes (DNS_DISPATCHATTR_xxx) of this dispatch.  Only the
- * non-changeable attributes are expected to be referenced by the caller.
- *
- * Requires:
- *\li  disp is valid.
- */
-
-void
-dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes,
-                             unsigned int mask);
-/*%<
- * Set the bits described by "mask" to the corresponding values in
- * "attributes".
- *
- * That is:
- *
- * \code
- *     new = (old & ~mask) | (attributes & mask)
- * \endcode
- *
- * This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes.
- * When the flag becomes off, the dispatch will start receiving on the
- * corresponding socket.  When the flag becomes on, receive events on the
- * corresponding socket will be canceled.
- *
- * Requires:
- *\li  disp is valid.
- *
- *\li  attributes are reasonable for the dispatch.  That is, setting the UDP
- *     attribute on a TCP socket isn't reasonable.
- */
-
 dns_dispatch_t *
 dns_dispatchset_get(dns_dispatchset_t *dset);
 /*%<
@@ -417,7 +361,7 @@ dns_dispatchset_get(dns_dispatchset_t *dset);
  * the round-robin counter.
  *
  * Requires:
- *\li  dset != NULL
+ *\li  dset != NULL
  */
 
 isc_result_t
@@ -429,8 +373,8 @@ dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
  * source.
  *
  * Requires:
- *\li  source is a valid UDP dispatcher
- *\li  dsetp != NULL, *dsetp == NULL
+ *\li  source is a valid UDP dispatcher
+ *\li  dsetp != NULL, *dsetp == NULL
  */
 
 void
@@ -440,7 +384,7 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp);
  * memory, and set *dsetp to NULL.
  *
  * Requires:
- *\li  dset is valid
+ *\li  dset is valid
  */
 
 isc_result_t
@@ -453,5 +397,3 @@ dns_dispatch_getnext(dns_dispentry_t *resp);
  */
 
 ISC_LANG_ENDDECLS
-
-#endif /* DNS_DISPATCH_H */
index 513ffcbbad3bb2c5bd1ac0a65363077ed867b23f..b2b569ddf1912454b8fe56af907278b7e19b9079 100644 (file)
@@ -137,7 +137,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
                      dns_requestmgr_t **requestmgrp) {
        dns_requestmgr_t *requestmgr;
        int i;
-       unsigned int dispattr;
 
        req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
 
@@ -145,39 +144,31 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
        REQUIRE(taskmgr != NULL);
        REQUIRE(dispatchmgr != NULL);
 
-       if (dispatchv4 != NULL) {
-               dispattr = dns_dispatch_getattributes(dispatchv4);
-               REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
-       }
-       if (dispatchv6 != NULL) {
-               dispattr = dns_dispatch_getattributes(dispatchv6);
-               REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
-       }
-
        requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
+       *requestmgr = (dns_requestmgr_t){ 0 };
 
+       isc_taskmgr_attach(taskmgr, &requestmgr->taskmgr);
+       dns_dispatchmgr_attach(dispatchmgr, &requestmgr->dispatchmgr);
        isc_mutex_init(&requestmgr->lock);
 
        for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
                isc_mutex_init(&requestmgr->locks[i]);
        }
-       requestmgr->taskmgr = taskmgr;
-       requestmgr->dispatchmgr = dispatchmgr;
-       requestmgr->dispatchv4 = NULL;
        if (dispatchv4 != NULL) {
                dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
        }
-       requestmgr->dispatchv6 = NULL;
        if (dispatchv6 != NULL) {
                dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
        }
-       requestmgr->mctx = NULL;
        isc_mem_attach(mctx, &requestmgr->mctx);
+
        isc_refcount_init(&requestmgr->references, 1);
+
        ISC_LIST_INIT(requestmgr->whenshutdown);
        ISC_LIST_INIT(requestmgr->requests);
+
        atomic_init(&requestmgr->exiting, false);
-       requestmgr->hash = 0;
+
        requestmgr->magic = REQUESTMGR_MAGIC;
 
        req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
@@ -325,6 +316,12 @@ mgr_destroy(dns_requestmgr_t *requestmgr) {
        if (requestmgr->dispatchv6 != NULL) {
                dns_dispatch_detach(&requestmgr->dispatchv6);
        }
+       if (requestmgr->dispatchmgr != NULL) {
+               dns_dispatchmgr_detach(&requestmgr->dispatchmgr);
+       }
+       if (requestmgr->taskmgr != NULL) {
+               isc_taskmgr_detach(&requestmgr->taskmgr);
+       }
        requestmgr->magic = 0;
        isc_mem_putanddetach(&requestmgr->mctx, requestmgr,
                             sizeof(*requestmgr));
@@ -417,7 +414,7 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
        }
 
        result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
-                                       destaddr, 0, dscp, dispatchp);
+                                       destaddr, dscp, dispatchp);
        return (result);
 }
 
@@ -446,7 +443,7 @@ udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
                return (ISC_R_SUCCESS);
        }
 
-       return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr, 0,
+       return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr,
                                       dispatchp));
 }
 
@@ -589,15 +586,19 @@ again:
        UNLOCK(&requestmgr->lock);
 
        request->destaddr = *destaddr;
-       if (!tcp || !connected) {
+       if (tcp && connected) {
+               req_send(request);
+               req_detach(&rclone);
+       } else {
                result = dns_dispatch_connect(request->dispentry);
                if (result != ISC_R_SUCCESS) {
                        goto unlink;
                }
-               request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP;
-       } else {
-               req_send(request);
-               req_detach(&rclone);
+               request->flags |= DNS_REQUEST_F_CONNECTING;
+
+               if (tcp) {
+                       request->flags |= DNS_REQUEST_F_TCP;
+               }
        }
 
        req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request);
@@ -613,6 +614,9 @@ cleanup:
        if (tclone != NULL) {
                isc_task_detach(&tclone);
        }
+       if (rclone != NULL) {
+               req_detach(&rclone);
+       }
        req_detach(&request);
        req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
                dns_result_totext(result));
@@ -755,15 +759,18 @@ use_tcp:
        UNLOCK(&requestmgr->lock);
 
        request->destaddr = *destaddr;
-       if (!tcp || !connected) {
+       if (tcp && connected) {
+               req_send(request);
+               req_detach(&rclone);
+       } else {
                result = dns_dispatch_connect(request->dispentry);
                if (result != ISC_R_SUCCESS) {
                        goto unlink;
                }
-               request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP;
-       } else {
-               req_send(request);
-               req_detach(&rclone);
+               request->flags |= DNS_REQUEST_F_CONNECTING;
+               if (tcp) {
+                       request->flags |= DNS_REQUEST_F_TCP;
+               }
        }
 
        req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request);
@@ -1080,7 +1087,8 @@ req_response(isc_result_t result, isc_region_t *region, void *arg) {
 
                LOCK(&request->requestmgr->locks[request->hash]);
                if (--request->udpcount != 0) {
-                       dns_dispatch_read(request->dispentry, request->timeout);
+                       dns_dispatch_resume(request->dispentry,
+                                           request->timeout);
                        if (!DNS_REQUEST_SENDING(request)) {
                                req_send(request);
                        }
index 72387fdfcb2d3a709886af36ea515b0850556240..1643b3c0d6f31a919d82a4176590bf917555984c 100644 (file)
@@ -1123,12 +1123,14 @@ munge:
 
 static inline void
 resquery_destroy(resquery_t *query) {
-       dns_resolver_t *res;
+       fetchctx_t *fctx = query->fctx;
+       dns_resolver_t *res = fctx->res;
+       unsigned int bucket = fctx->bucketnum;
        bool empty;
-       fetchctx_t *fctx;
-       unsigned int bucket;
 
-       REQUIRE(!ISC_LINK_LINKED(query, link));
+       if (ISC_LINK_LINKED(query, link)) {
+               ISC_LIST_UNLINK(fctx->queries, query, link);
+       }
 
        if (query->tsig != NULL) {
                isc_buffer_free(&query->tsig);
@@ -1148,10 +1150,6 @@ resquery_destroy(resquery_t *query) {
 
        isc_refcount_destroy(&query->references);
 
-       fctx = query->fctx;
-       res = fctx->res;
-       bucket = fctx->bucketnum;
-
        LOCK(&res->buckets[bucket].lock);
        fctx->nqueries--;
        empty = fctx_decreference(query->fctx);
@@ -1935,7 +1933,7 @@ resquery_timeout(resquery_t *query) {
         */
        timeleft = isc_time_microdiff(&fctx->next_timeout, &now);
        if (timeleft >= US_PER_MSEC) {
-               dns_dispatch_read(query->dispentry, (timeleft / US_PER_MSEC));
+               dns_dispatch_resume(query->dispentry, (timeleft / US_PER_MSEC));
                return (ISC_R_COMPLETE);
        }
 
@@ -2061,7 +2059,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
                }
 
                result = dns_dispatch_createtcp(res->dispatchmgr, &addr,
-                                               &addrinfo->sockaddr, 0,
+                                               &addrinfo->sockaddr,
                                                query->dscp, &query->dispatch);
                if (result != ISC_R_SUCCESS) {
                        goto cleanup_query;
@@ -2082,7 +2080,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
                                goto cleanup_query;
                        }
                        result = dns_dispatch_createudp(res->dispatchmgr, &addr,
-                                                       0, &query->dispatch);
+                                                       &query->dispatch);
                        if (result != ISC_R_SUCCESS) {
                                goto cleanup_query;
                        }
@@ -2795,12 +2793,8 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) {
        switch (eresult) {
        case ISC_R_SUCCESS:
                /*
-                * We are connected. Update the dispatcher and
-                * send the query.
+                * We are connected. Send the query.
                 */
-               dns_dispatch_changeattributes(query->dispatch,
-                                             DNS_DISPATCHATTR_CONNECTED,
-                                             DNS_DISPATCHATTR_CONNECTED);
 
                result = resquery_send(query);
                if (result != ISC_R_SUCCESS) {