From c69f2018a3b1fb6e115e21b2a1827d74bda5a6f9 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 9 Dec 2020 12:52:31 -0800 Subject: [PATCH 01/28] Remove unused code in dispatch.c Some routines in dispatch.c are obsolete and unused; clean them up before porting to netmgr. --- lib/dns/dispatch.c | 92 +--------------------------------- lib/dns/include/dns/dispatch.h | 41 --------------- lib/dns/include/dns/events.h | 2 +- 3 files changed, 3 insertions(+), 132 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 177695184e..86db2ef589 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -208,10 +208,8 @@ struct dns_dispatch { unsigned int refcount; /*%< number of users */ dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ unsigned int shutting_down : 1, shutdown_out : 1, connected : 1, - tcpmsg_valid : 1, recv_pending : 1; /*%< is a - * recv() - * pending? - * */ + tcpmsg_valid : 1, recv_pending : 1; /*%< is a recv() pending? * + */ isc_result_t shutdown_why; ISC_LIST(dispsocket_t) activesockets; ISC_LIST(dispsocket_t) inactivesockets; @@ -2385,10 +2383,8 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { REQUIRE(isc_sockaddr_getport(localaddr) == 0); - goto createudp; } -createudp: /* * Nope, create one. */ @@ -3178,26 +3174,6 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) { return (ISC_R_NOTIMPLEMENTED); } -void -dns_dispatch_cancel(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - - LOCK(&disp->lock); - - if (disp->shutting_down == 1) { - UNLOCK(&disp->lock); - return; - } - - disp->shutdown_why = ISC_R_CANCELED; - disp->shutting_down = 1; - do_cancel(disp); - - UNLOCK(&disp->lock); - - return; -} - unsigned int dns_dispatch_getattributes(dns_dispatch_t *disp) { REQUIRE(VALID_DISPATCH(disp)); @@ -3248,43 +3224,6 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, UNLOCK(&disp->lock); } -void -dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { - void *buf; - isc_socketevent_t *sevent, *newsevent; - - REQUIRE(VALID_DISPATCH(disp)); - REQUIRE(event != NULL); - - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) { - return; - } - - sevent = (isc_socketevent_t *)event; - INSIST(sevent->n <= disp->mgr->buffersize); - - newsevent = (isc_socketevent_t *)isc_event_allocate( - disp->mgr->mctx, NULL, DNS_EVENT_IMPORTRECVDONE, udp_shrecv, - disp, sizeof(isc_socketevent_t)); - - buf = allocate_udp_buffer(disp); - if (buf == NULL) { - isc_event_free(ISC_EVENT_PTR(&newsevent)); - return; - } - memmove(buf, sevent->region.base, sevent->n); - newsevent->region.base = buf; - newsevent->region.length = disp->mgr->buffersize; - newsevent->n = sevent->n; - newsevent->result = sevent->result; - newsevent->address = sevent->address; - newsevent->timestamp = sevent->timestamp; - newsevent->pktinfo = sevent->pktinfo; - newsevent->attributes = sevent->attributes; - - isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent)); -} - dns_dispatch_t * dns_dispatchset_get(dns_dispatchset_t *dset) { dns_dispatch_t *disp; @@ -3397,30 +3336,3 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { isc_mutex_destroy(&dset->lock); isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t)); } - -void -dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) { - REQUIRE(VALID_DISPATCH(disp)); - disp->dscp = dscp; -} - -isc_dscp_t -dns_dispatch_getdscp(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - return (disp->dscp); -} - -#if 0 -void -dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) { - dns_dispatch_t *disp; - char foo[1024]; - - disp = ISC_LIST_HEAD(mgr->list); - while (disp != NULL) { - isc_sockaddr_format(&disp->local, foo, sizeof(foo)); - printf("\tdispatch %p, addr %s\n", disp, foo); - disp = ISC_LIST_NEXT(disp, link); - } -} -#endif /* if 0 */ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 8ed9601d16..68c6dab91f 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -122,11 +122,6 @@ struct dns_dispatchset { * The dispatcher can be used to issue queries to other servers, and * accept replies from them. * - * _RANDOMPORT - * Previously used to indicate that the port of a dispatch UDP must be - * chosen randomly. This behavior now always applies and the attribute - * is obsoleted. - * * _EXCLUSIVE * A separate socket will be used on-demand for each transaction. */ @@ -429,15 +424,6 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); *\li ISC_R_NOTIMPLEMENTED */ -void -dns_dispatch_cancel(dns_dispatch_t *disp); -/*%< - * cancel outstanding clients - * - * Requires: - *\li disp is valid. - */ - unsigned int dns_dispatch_getattributes(dns_dispatch_t *disp); /*%< @@ -473,21 +459,6 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, * attribute on a TCP socket isn't reasonable. */ -void -dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event); -/*%< - * Inform the dispatcher of a socket receive. This is used for sockets - * shared between dispatchers and clients. If the dispatcher fails to copy - * or send the event, nothing happens. - * - * If the attribute DNS_DISPATCHATTR_NOLISTEN is not set, then - * the dispatch is already handling a recv; return immediately. - * - * Requires: - *\li disp is valid, and the attribute DNS_DISPATCHATTR_NOLISTEN is set. - * event != NULL - */ - dns_dispatch_t * dns_dispatchset_get(dns_dispatchset_t *dset); /*%< @@ -528,18 +499,6 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp); *\li dset is valid */ -void -dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp); -isc_dscp_t -dns_dispatch_getdscp(dns_dispatch_t *disp); -/*%< - * Set/get the DSCP value to be used when sending responses to clients, - * as defined in the "listen-on" or "listen-on-v6" statements. - * - * Requires: - *\li disp is valid. - */ - isc_result_t dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent); /*%< diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index 7d93637268..32af3d954c 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -54,7 +54,7 @@ #define DNS_EVENT_DISPATCHCONTROL (ISC_EVENTCLASS_DNS + 32) #define DNS_EVENT_REQUESTCONTROL (ISC_EVENTCLASS_DNS + 33) #define DNS_EVENT_DUMPQUANTUM (ISC_EVENTCLASS_DNS + 34) -#define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35) +/* #define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35) */ #define DNS_EVENT_FREESTORAGE (ISC_EVENTCLASS_DNS + 36) #define DNS_EVENT_VIEWACACHESHUTDOWN (ISC_EVENTCLASS_DNS + 37) #define DNS_EVENT_ACACHECONTROL (ISC_EVENTCLASS_DNS + 38) From 57fce0e8956aa70c5558f1e25ece6fbf7de4b01b Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 9 Dec 2020 13:00:25 -0800 Subject: [PATCH 02/28] Remove some DNS_DISPATCHATTR flags - DNS_DISPATCHATTR_CANREUSE was never set. the code that implements it has been removed. - DNS_DISPATCHOPT_FIXEDID and DNS_DISPATCHATTR_FIXEDID were both defined, but only the DISPATCHOPT was ever set; it appears the DISPATCHATTR was added accidentally. - DNS_DISPATCHATTR_NOLISTEN was set but never used. --- lib/dns/dispatch.c | 44 ++++++---------------------------- lib/dns/include/dns/dispatch.h | 6 ----- lib/ns/interfacemgr.c | 3 --- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 86db2ef589..080407e0ba 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -299,7 +299,7 @@ dispatch_free(dns_dispatch_t **dispp); static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, - isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly); + isc_socket_t **sockp, isc_socket_t *dup_socket); static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, @@ -1499,10 +1499,6 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { return (ISC_R_SUCCESS); } - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) { - return (ISC_R_SUCCESS); - } - if (disp->recv_pending != 0 && dispsock == NULL) { return (ISC_R_SUCCESS); } @@ -2413,7 +2409,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, - isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly) { + isc_socket_t **sockp, isc_socket_t *dup_socket) { unsigned int i, j; isc_socket_t *held[DNS_DISPATCH_HELD]; isc_sockaddr_t localaddr_bound; @@ -2473,7 +2469,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, /* Allow to reuse address for non-random ports. */ result = open_socket(sockmgr, localaddr, ISC_SOCKET_REUSEADDRESS, &sock, dup_socket, - duponly); + true); if (result == ISC_R_SUCCESS) { *sockp = sock; @@ -2530,10 +2526,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, dns_dispatch_t *disp; isc_socket_t *sock = NULL; int i = 0; - bool duponly = ((attributes & DNS_DISPATCHATTR_CANREUSE) == 0); - /* This is an attribute needed only at creation time */ - attributes &= ~DNS_DISPATCHATTR_CANREUSE; /* * dispatch_allocate() checks mgr for us. */ @@ -2547,7 +2540,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) { result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock, - dup_socket, duponly); + dup_socket); if (result != ISC_R_SUCCESS) { goto deallocate_dispatch; } @@ -2803,8 +2796,9 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, } /* - * Try somewhat hard to find an unique ID unless FIXEDID is set - * in which case we use the id passed in via *idp. + * Try somewhat hard to find a unique ID, unless + * DNS_DISPATCHOPT_FIXEDID is set, in which case we + * use the ID passed in via *idp. */ LOCK(&qid->lock); if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) { @@ -2820,9 +2814,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ok = true; break; } - if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0) { - break; - } id += qid->qid_increment; id &= 0x0000ffff; } while (i++ < 64); @@ -3191,9 +3182,6 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, REQUIRE(VALID_DISPATCH(disp)); /* Exclusive attribute can only be set on creation */ REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0); - /* Also, a dispatch with randomport specified cannot start listening */ - REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 || - (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0); /* XXXMLG * Should check for valid attributes here! @@ -3201,24 +3189,6 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, LOCK(&disp->lock); - if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) { - if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 && - (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) - { - disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN; - (void)startrecv(disp, NULL); - } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == - 0 && - (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) - { - disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; - if (disp->recv_pending != 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } - } - } - disp->attributes &= ~mask; disp->attributes |= (attributes & mask); UNLOCK(&disp->lock); diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 68c6dab91f..e2d910e28f 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -115,9 +115,6 @@ struct dns_dispatchset { * _IPV4, _IPV6 * The dispatcher uses an IPv4 or IPv6 socket. * - * _NOLISTEN - * The dispatcher should not listen on the socket. - * * _MAKEQUERY * The dispatcher can be used to issue queries to other servers, and * accept replies from them. @@ -130,12 +127,9 @@ struct dns_dispatchset { #define DNS_DISPATCHATTR_UDP 0x00000004U #define DNS_DISPATCHATTR_IPV4 0x00000008U #define DNS_DISPATCHATTR_IPV6 0x00000010U -#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U #define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U #define DNS_DISPATCHATTR_CONNECTED 0x00000080U -#define DNS_DISPATCHATTR_FIXEDID 0x00000100U #define DNS_DISPATCHATTR_EXCLUSIVE 0x00000200U -#define DNS_DISPATCHATTR_CANREUSE 0x00000400U /*@}*/ /* diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 649dbc8ef8..6f94d39173 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -707,9 +707,6 @@ ns_interface_destroy(ns_interface_t *ifp) { for (int disp = 0; disp < ifp->nudpdispatch; disp++) { if (ifp->udpdispatch[disp] != NULL) { - dns_dispatch_changeattributes( - ifp->udpdispatch[disp], 0, - DNS_DISPATCHATTR_NOLISTEN); dns_dispatch_detach(&(ifp->udpdispatch[disp])); } } From ca11f68d61dd2dfc9140ac24d41ba8e48e322f47 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 9 Dec 2020 15:45:13 -0800 Subject: [PATCH 03/28] Simplify dns_dispatchmgr_create with fixed buffersize - UDP buffersize is now established when creating dispatch manager and is always set to 4096. - Set up the default port range in dispatchmgr before setting the magic number. - Magic is not set until dispatchmgr is fully created. --- bin/named/server.c | 8 +- bin/nsupdate/nsupdate.c | 9 +- bin/tests/system/pipelined/pipequeries.c | 4 +- bin/tests/system/tkey/keycreate.c | 2 +- bin/tests/system/tkey/keydelete.c | 2 +- bin/tools/mdig.c | 6 +- lib/dns/client.c | 7 +- lib/dns/dispatch.c | 244 ++++++++++------------- lib/dns/include/dns/dispatch.h | 10 +- lib/dns/request.c | 4 +- lib/dns/resolver.c | 2 +- lib/dns/tests/dispatch_test.c | 8 +- lib/dns/tests/resolver_test.c | 2 +- lib/dns/zone.c | 3 +- 14 files changed, 138 insertions(+), 173 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index e9d3bdc59e..c7638f8fb1 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1334,9 +1334,9 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, } disp = NULL; - result = dns_dispatch_getudp( - named_g_dispatchmgr, named_g_socketmgr, named_g_taskmgr, &sa, - 4096, maxdispatchbuffers, 32768, 16411, 16433, attrs, &disp); + result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, + named_g_taskmgr, &sa, maxdispatchbuffers, + 32768, 16411, 16433, attrs, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -10394,7 +10394,7 @@ named_add_reserved_dispatch(named_server_t *server, } result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &dispatch->addr, 4096, + named_g_taskmgr, &dispatch->addr, UDPBUFFERS, 32768, 16411, 16433, attrs, &dispatch->dispatch); if (result != ISC_R_SUCCESS) { diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index fc46a85ce0..bc39de6725 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -97,7 +97,6 @@ #define MAXCMD (128 * 1024) #define MAXWIRE (64 * 1024) -#define PACKETSIZE ((64 * 1024) - 1) #define INITTEXT (2 * 1024) #define MAXTEXT (128 * 1024) #define FIND_TIMEOUT 5 @@ -943,8 +942,8 @@ setup_system(void) { attrs |= DNS_DISPATCHATTR_IPV6; isc_sockaddr_any6(&bind_any6); result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - &bind_any6, PACKETSIZE, 4, 2, 3, 5, - attrs, &dispatchv6); + &bind_any6, 4, 2, 3, 5, attrs, + &dispatchv6); check_result(result, "dns_dispatch_getudp (v6)"); } @@ -954,8 +953,8 @@ setup_system(void) { attrs |= DNS_DISPATCHATTR_IPV4; isc_sockaddr_any(&bind_any); result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, PACKETSIZE, 4, 2, 3, 5, - attrs, &dispatchv4); + &bind_any, 4, 2, 3, 5, attrs, + &dispatchv4); check_result(result, "dns_dispatch_getudp (v4)"); } diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index b4595c7eff..3fe14e2794 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -286,8 +286,8 @@ main(int argc, char *argv[]) { DNS_DISPATCHATTR_IPV4; dispatchv4 = NULL; RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 4096, 4, - 2, 3, 5, attrs, &dispatchv4)); + have_src ? &srcaddr : &bind_any, 4, 2, 3, + 5, attrs, &dispatchv4)); requestmgr = NULL; RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 13da1f6117..14fb88857b 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -245,7 +245,7 @@ main(int argc, char *argv[]) { DNS_DISPATCHATTR_IPV4; dispatchv4 = NULL; RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, - 4096, 4, 2, 3, 5, attrs, &dispatchv4)); + 4, 2, 3, 5, attrs, &dispatchv4)); requestmgr = NULL; RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index 92f37fb1c1..605be6ecc0 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -188,7 +188,7 @@ main(int argc, char **argv) { DNS_DISPATCHATTR_IPV4; dispatchv4 = NULL; RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, - 4096, 4, 2, 3, 5, attrs, &dispatchv4)); + 4, 2, 3, 5, attrs, &dispatchv4)); requestmgr = NULL; RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index e2ca8ca0f0..df039afe90 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -759,7 +759,7 @@ sendquery(struct query *query, isc_task_t *task) { requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, dscp, options, NULL, query->timeout, query->udptimeout, query->udpretries, task, recvresponse, message, &request); - CHECK("dns_request_createvia4", result); + CHECK("dns_request_createvia", result); return (ISC_R_SUCCESS); } @@ -2141,8 +2141,8 @@ main(int argc, char *argv[]) { } dispatchvx = NULL; RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 4096, 100, - 100, 17, 19, attrs, &dispatchvx)); + have_src ? &srcaddr : &bind_any, 100, 100, + 17, 19, attrs, &dispatchvx)); RUNCHECK(dns_requestmgr_create( mctx, timermgr, socketmgr, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL, have_ipv6 ? dispatchvx : NULL, diff --git a/lib/dns/client.c b/lib/dns/client.c index 78b1efcf4e..ce2c7e325c 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -207,7 +207,7 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *localaddr) { unsigned int attrs; dns_dispatch_t *disp; - unsigned buffersize, maxbuffers, maxrequests, buckets, increment; + unsigned maxbuffers, maxrequests, buckets, increment; isc_result_t result; isc_sockaddr_t anyaddr; @@ -230,7 +230,6 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, localaddr = &anyaddr; } - buffersize = 4096; maxbuffers = is_shared ? 1000 : 8; maxrequests = 32768; buckets = is_shared ? 16411 : 3; @@ -238,8 +237,8 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, disp = NULL; result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, localaddr, - buffersize, maxbuffers, maxrequests, - buckets, increment, attrs, &disp); + maxbuffers, maxrequests, buckets, + increment, attrs, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 080407e0ba..e8de005bc5 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -139,6 +139,13 @@ struct dns_dispentry { #define DNS_DISPATCH_SOCKSQUOTA 3072 #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ +/*% + * Fixed UDP buffer size. + */ +#ifndef DNS_DISPATCH_UDPBUFSIZE +#define DNS_DISPATCH_UDPBUFSIZE 4096 +#endif /* ifndef DNS_DISPATCH_UDPBUFSIZE */ + struct dispsocket { unsigned int magic; isc_socket_t *socket; @@ -587,7 +594,6 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { REQUIRE(disp->port_table != NULL); portentry = isc_mem_get(disp->mgr->mctx, sizeof(*portentry)); - portentry->port = port; isc_refcount_init(&portentry->refs, 1); ISC_LINK_INIT(portentry, link); @@ -730,10 +736,6 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, if (result == ISC_R_SUCCESS) { if (portentry == NULL) { portentry = new_portentry(disp, port); - if (portentry == NULL) { - result = ISC_R_NOMEMORY; - break; - } } else { isc_refcount_increment(&portentry->refs); } @@ -794,7 +796,6 @@ destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { disp->nsockets--; dispsock->magic = 0; if (dispsock->portentry != NULL) { - /* socket_search() tests and dereferences portentry. */ LOCK(&qid->lock); deref_portentry(disp, &dispsock->portentry); UNLOCK(&qid->lock); @@ -833,7 +834,7 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { } INSIST(dispsock->portentry != NULL); - /* socket_search() tests and dereferences portentry. */ + LOCK(&qid->lock); deref_portentry(disp, &dispsock->portentry); UNLOCK(&qid->lock); @@ -890,8 +891,7 @@ entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { - unsigned int buffersize; - INSIST(buf != NULL && len != 0); + REQUIRE(buf != NULL && len != 0); switch (disp->socktype) { case isc_sockettype_tcp: @@ -902,11 +902,10 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { case isc_sockettype_udp: LOCK(&disp->mgr->buffer_lock); INSIST(disp->mgr->buffers > 0); - INSIST(len == disp->mgr->buffersize); + INSIST(len == DNS_DISPATCH_UDPBUFSIZE); disp->mgr->buffers--; - buffersize = disp->mgr->buffersize; UNLOCK(&disp->mgr->buffer_lock); - isc_mem_put(disp->mgr->mctx, buf, buffersize); + isc_mem_put(disp->mgr->mctx, buf, len); break; default: INSIST(0); @@ -916,18 +915,15 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { static void * allocate_udp_buffer(dns_dispatch_t *disp) { - unsigned int buffersize; - LOCK(&disp->mgr->buffer_lock); if (disp->mgr->buffers >= disp->mgr->maxbuffers) { UNLOCK(&disp->mgr->buffer_lock); return (NULL); } - buffersize = disp->mgr->buffersize; disp->mgr->buffers++; UNLOCK(&disp->mgr->buffer_lock); - return (isc_mem_get(disp->mgr->mctx, buffersize)); + return (isc_mem_get(disp->mgr->mctx, DNS_DISPATCH_UDPBUFSIZE)); } static inline void @@ -1520,7 +1516,7 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { * UDP reads are always maximal. */ case isc_sockettype_udp: - region.length = disp->mgr->buffersize; + region.length = DNS_DISPATCH_UDPBUFSIZE; region.base = allocate_udp_buffer(disp); if (region.base == NULL) { return (ISC_R_NOMEMORY); @@ -1699,98 +1695,17 @@ open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, * normally set the ports explicitly, but is provided to fill some minor corner * cases. */ -static isc_result_t +static void create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) { - isc_result_t result; - - result = isc_portset_create(mctx, portsetp); - if (result != ISC_R_SUCCESS) { - return (result); - } + isc_portset_create(mctx, portsetp); isc_portset_addrange(*portsetp, 1024, 65535); - - return (ISC_R_SUCCESS); } -/* - * Publics. - */ - -isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr; - isc_result_t result; - isc_portset_t *v4portset = NULL; - isc_portset_t *v6portset = NULL; - - REQUIRE(mctx != NULL); - REQUIRE(mgrp != NULL && *mgrp == NULL); - - mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); - *mgr = (dns_dispatchmgr_t){ 0 }; - - isc_mem_attach(mctx, &mgr->mctx); - - isc_mutex_init(&mgr->lock); - isc_mutex_init(&mgr->buffer_lock); - - isc_refcount_init(&mgr->irefs, 0); - - ISC_LIST_INIT(mgr->list); - - mgr->magic = DNS_DISPATCHMGR_MAGIC; - - result = create_default_portset(mctx, &v4portset); - if (result == ISC_R_SUCCESS) { - result = create_default_portset(mctx, &v6portset); - if (result == ISC_R_SUCCESS) { - result = dns_dispatchmgr_setavailports(mgr, v4portset, - v6portset); - } - } - if (v4portset != NULL) { - isc_portset_destroy(mctx, &v4portset); - } - if (v6portset != NULL) { - isc_portset_destroy(mctx, &v6portset); - } - if (result != ISC_R_SUCCESS) { - goto kill_dpool; - } - - *mgrp = mgr; - return (ISC_R_SUCCESS); - -kill_dpool: - isc_mutex_destroy(&mgr->buffer_lock); - isc_mutex_destroy(&mgr->lock); - isc_mem_putanddetach(&mctx, mgr, sizeof(dns_dispatchmgr_t)); - - return (result); -} - -void -dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) { - REQUIRE(VALID_DISPATCHMGR(mgr)); - if (mgr->blackhole != NULL) { - dns_acl_detach(&mgr->blackhole); - } - dns_acl_attach(blackhole, &mgr->blackhole); -} - -dns_acl_t * -dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) { - REQUIRE(VALID_DISPATCHMGR(mgr)); - return (mgr->blackhole); -} - -isc_result_t -dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, - isc_portset_t *v6portset) { - in_port_t *v4ports, *v6ports, p; - unsigned int nv4ports, nv6ports, i4, i6; - - REQUIRE(VALID_DISPATCHMGR(mgr)); +static isc_result_t +setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, + isc_portset_t *v6portset) { + in_port_t *v4ports, *v6ports, p = 0; + unsigned int nv4ports, nv6ports, i4 = 0, i6 = 0; nv4ports = isc_portset_nports(v4portset); nv6ports = isc_portset_nports(v6portset); @@ -1804,9 +1719,6 @@ dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports); } - p = 0; - i4 = 0; - i6 = 0; do { if (isc_portset_isset(v4portset, p)) { INSIST(i4 < nv4ports); @@ -1838,14 +1750,74 @@ dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, return (ISC_R_SUCCESS); } +/* + * Publics. + */ + +isc_result_t +dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { + dns_dispatchmgr_t *mgr = NULL; + isc_portset_t *v4portset = NULL; + isc_portset_t *v6portset = NULL; + + REQUIRE(mctx != NULL); + REQUIRE(mgrp != NULL && *mgrp == NULL); + + mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); + *mgr = (dns_dispatchmgr_t){ .maxbuffers = 20000 }; + + isc_mem_attach(mctx, &mgr->mctx); + + 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); + create_default_portset(mctx, &v6portset); + + setavailports(mgr, v4portset, v6portset); + + isc_portset_destroy(mctx, &v4portset); + isc_portset_destroy(mctx, &v6portset); + + mgr->magic = DNS_DISPATCHMGR_MAGIC; + + *mgrp = mgr; + return (ISC_R_SUCCESS); +} + +void +dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + if (mgr->blackhole != NULL) { + dns_acl_detach(&mgr->blackhole); + } + dns_acl_attach(blackhole, &mgr->blackhole); +} + +dns_acl_t * +dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + return (mgr->blackhole); +} + +isc_result_t +dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, + isc_portset_t *v6portset) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + return (setavailports(mgr, v4portset, v6portset)); +} + static isc_result_t -dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment) { +dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int maxbuffers, + unsigned int maxrequests, unsigned int buckets, + unsigned int increment) { isc_result_t result; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); REQUIRE(maxbuffers > 0); REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ REQUIRE(increment > buckets); @@ -1868,31 +1840,29 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize, maxbuffers = 8; } + /* Adjust buffer pool if needed + * + * We only increase maxbuffers to avoid accidental buffer + * shortage. Ideally we'd separate the manager-wide maximum + * from per-dispatch limits and respect the latter within the + * global limit. But at this moment that's deemed to be + * overkilling and isn't worth additional implementation + * complexity. + */ LOCK(&mgr->buffer_lock); - if (maxbuffers > mgr->maxbuffers) { mgr->maxbuffers = maxbuffers; } - - /* Create or adjust socket pool */ - if (mgr->qid != NULL) { - UNLOCK(&mgr->buffer_lock); - return (ISC_R_SUCCESS); - } - - result = qid_allocate(mgr, buckets, increment, &mgr->qid, true); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - mgr->buffersize = buffersize; - mgr->maxbuffers = maxbuffers; UNLOCK(&mgr->buffer_lock); + + if (mgr->qid == NULL) { + result = qid_allocate(mgr, buckets, increment, &mgr->qid, true); + if (result != ISC_R_SUCCESS) { + return (result); + } + } + return (ISC_R_SUCCESS); - -cleanup: - UNLOCK(&mgr->buffer_lock); - return (result); } void @@ -2351,10 +2321,9 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, isc_result_t dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int buffersize, unsigned int maxbuffers, - unsigned int maxrequests, unsigned int buckets, - unsigned int increment, unsigned int attributes, - dns_dispatch_t **dispp) { + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int buckets, unsigned int increment, + unsigned int attributes, dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; @@ -2362,15 +2331,14 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, REQUIRE(sockmgr != NULL); REQUIRE(localaddr != NULL); REQUIRE(taskmgr != NULL); - REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); REQUIRE(maxbuffers > 0); REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ REQUIRE(increment > buckets); REQUIRE(dispp != NULL && *dispp == NULL); REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0); - result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers, - maxrequests, buckets, increment); + result = dispatchmgr_setudp(mgr, maxbuffers, maxrequests, buckets, + increment); if (result != ISC_R_SUCCESS) { return (result); } diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index e2d910e28f..ddedac07b5 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -139,7 +139,8 @@ struct dns_dispatchset { isc_result_t dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp); /*%< - * Creates a new dispatchmgr object. + * Creates a new dispatchmgr object, and sets the available ports + * to the default range (1024-65535). * * Requires: *\li "mctx" be a valid memory context. @@ -215,10 +216,9 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); isc_result_t dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int buffersize, unsigned int maxbuffers, - unsigned int maxrequests, unsigned int buckets, - unsigned int increment, unsigned int attributes, - dns_dispatch_t **dispp); + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int buckets, unsigned int increment, + unsigned int attributes, dns_dispatch_t **dispp); /*%< * Attach to existing dns_dispatch_t if one is found with dns_dispatchmgr_find, * otherwise create a new UDP dispatch. diff --git a/lib/dns/request.c b/lib/dns/request.c index 1311de4027..fc6a1c8965 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -630,8 +630,8 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, } return (dns_dispatch_getudp(requestmgr->dispatchmgr, requestmgr->socketmgr, requestmgr->taskmgr, - srcaddr, 4096, 32768, 32768, 16411, 16433, - attrs, dispatchp)); + srcaddr, 32768, 32768, 16411, 16433, attrs, + dispatchp)); } static isc_result_t diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 0358241d95..4652f04370 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2175,7 +2175,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } result = dns_dispatch_getudp( res->dispatchmgr, res->socketmgr, res->taskmgr, - &addr, 4096, 20000, 32768, 16411, 16433, attrs, + &addr, 20000, 32768, 16411, 16433, attrs, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index a425091bf6..5bc81a2cd5 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -76,8 +76,8 @@ make_dispatchset(unsigned int ndisps) { isc_sockaddr_any(&any); attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &any, 512, - 6, 1024, 17, 19, attrs, &disp); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &any, 6, + 1024, 17, 19, attrs, &disp); if (result != ISC_R_SUCCESS) { return (result); } @@ -274,8 +274,8 @@ dispatch_getnext(void **state) { ina.s_addr = htonl(INADDR_LOOPBACK); isc_sockaddr_fromin(&local, &ina, 0); attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, - 512, 6, 1024, 17, 19, attrs, &dispatch); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, 6, + 1024, 17, 19, attrs, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); /* diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index c115c34d8c..b144e09f84 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -58,7 +58,7 @@ _setup(void **state) { isc_sockaddr_any(&local); result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, - 4096, 100, 100, 100, 500, 0, &dispatch); + 100, 100, 100, 500, 0, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 7bd8c05c9b..9b26c61ffe 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -14603,8 +14603,7 @@ again: zone->task, refresh_callback, zone, &zone->request); if (result != ISC_R_SUCCESS) { zone_idetach(&dummy); - zone_debuglog(zone, me, 1, - "dns_request_createvia4() failed: %s", + zone_debuglog(zone, me, 1, "dns_request_createvia() failed: %s", dns_result_totext(result)); goto skip_master; } else { From 5863acc907ec550db8e2bb29e8b87440d13abe71 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 11 Dec 2020 15:20:33 -0800 Subject: [PATCH 04/28] Make sharing of pending TCP dispatches nonoptional The DNS_REQUESTOPT_SHARE flag was added when client-side pipelining of TCP queries was implemented. there was no need to make it optional; forcing it to be in effect for all requests simplfiies the code. --- bin/tests/system/pipelined/pipequeries.c | 8 +++--- bin/tools/mdig.c | 2 +- lib/dns/include/dns/request.h | 1 - lib/dns/request.c | 34 ++++++------------------ 4 files changed, 13 insertions(+), 32 deletions(-) diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 3fe14e2794..f9371e7c0d 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -173,10 +173,10 @@ sendquery(isc_task_t *task) { dns_message_addname(message, qname, DNS_SECTION_QUESTION); request = NULL; - result = dns_request_createvia( - requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, -1, - DNS_REQUESTOPT_TCP | DNS_REQUESTOPT_SHARE, NULL, TIMEOUT, 0, 0, - task, recvresponse, message, &request); + result = dns_request_createvia(requestmgr, message, + have_src ? &srcaddr : NULL, &dstaddr, -1, + DNS_REQUESTOPT_TCP, NULL, TIMEOUT, 0, 0, + task, recvresponse, message, &request); CHECK("dns_request_create", result); return (ISC_R_SUCCESS); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index df039afe90..c07e64b032 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -752,7 +752,7 @@ sendquery(struct query *query, isc_task_t *task) { options = 0; if (tcp_mode) { - options |= DNS_REQUESTOPT_TCP | DNS_REQUESTOPT_SHARE; + options |= DNS_REQUESTOPT_TCP; } request = NULL; result = dns_request_createvia( diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 6ec7395ae2..98afe5a4ae 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -43,7 +43,6 @@ #define DNS_REQUESTOPT_TCP 0x00000001U #define DNS_REQUESTOPT_CASE 0x00000002U #define DNS_REQUESTOPT_FIXEDID 0x00000004U -#define DNS_REQUESTOPT_SHARE 0x00000008U typedef struct dns_requestevent { ISC_EVENT_COMMON(struct dns_requestevent); diff --git a/lib/dns/request.c b/lib/dns/request.c index fc6a1c8965..bbff2d6b0e 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -512,7 +512,7 @@ isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) { } static isc_result_t -create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr, +create_tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { @@ -522,7 +522,7 @@ create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr, unsigned int attrs; isc_sockaddr_t bind_any; - if (!newtcp && share) { + if (!newtcp) { result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, srcaddr, connected, dispatchp); if (result == ISC_R_SUCCESS) { @@ -535,20 +535,6 @@ create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr, *connected ? "existing" : "pending", peer); return (result); } - } else if (!newtcp) { - result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, - srcaddr, NULL, dispatchp); - if (result == ISC_R_SUCCESS) { - char peer[ISC_SOCKADDR_FORMATSIZE]; - - *connected = true; - isc_sockaddr_format(destaddr, peer, sizeof(peer)); - req_log(ISC_LOG_DEBUG(1), - "attached to existing TCP " - "connection to %s", - peer); - return (result); - } } result = isc_socket_create(requestmgr->socketmgr, @@ -635,13 +621,13 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, } static isc_result_t -get_dispatch(bool tcp, bool newtcp, bool share, dns_requestmgr_t *requestmgr, +get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { isc_result_t result; if (tcp) { - result = create_tcp_dispatch(newtcp, share, requestmgr, srcaddr, + result = create_tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr, dscp, connected, dispatchp); } else { @@ -686,7 +672,6 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, dns_messageid_t id; bool tcp = false; bool newtcp = false; - bool share = false; isc_region_t r; bool connected = false; unsigned int dispopt = 0; @@ -752,11 +737,10 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) { tcp = true; } - share = (options & DNS_REQUESTOPT_SHARE); again: - result = get_dispatch(tcp, newtcp, share, requestmgr, srcaddr, destaddr, - dscp, &connected, &request->dispatch); + result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr, dscp, + &connected, &request->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -876,7 +860,6 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_mem_t *mctx; dns_messageid_t id; bool tcp; - bool share; bool settsigkey = true; bool connected = false; @@ -939,9 +922,8 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, use_tcp: tcp = ((options & DNS_REQUESTOPT_TCP) != 0); - share = ((options & DNS_REQUESTOPT_SHARE) != 0); - result = get_dispatch(tcp, false, share, requestmgr, srcaddr, destaddr, - dscp, &connected, &request->dispatch); + result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr, dscp, + &connected, &request->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } From 300392ae2faed4e84a99746a385c5760c44a94b9 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 9 Dec 2020 19:44:41 -0800 Subject: [PATCH 05/28] General code refactoring - style cleanup - removed NULL checks in places where they are not currently needed - use isc_refcount for dispatch reference counting - revised code flow for readability - remove some #ifdefs that are no longer relevant - remove unused struct members - removed unnecessary function parameters - use C99 struct initialization --- bin/named/server.c | 8 +- lib/dns/dispatch.c | 462 +++++++++++++------------------ lib/dns/request.c | 6 +- lib/dns/resolver.c | 248 +++++------------ lib/ns/include/ns/interfacemgr.h | 36 ++- lib/ns/interfacemgr.c | 19 +- lib/ns/tests/nstest.c | 4 +- 7 files changed, 283 insertions(+), 500 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index c7638f8fb1..857609dd5a 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -4708,8 +4708,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, /* * Resolver. - * - * XXXRTH Hardwired number of tasks. */ CHECK(get_view_querysource_dispatch( maps, AF_INET, &dispatch4, &dscp4, @@ -4719,7 +4717,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, (ISC_LIST_PREV(view, link) == NULL))); if (dispatch4 == NULL && dispatch6 == NULL) { UNEXPECTED_ERROR(__FILE__, __LINE__, - "unable to obtain neither an IPv4 nor" + "unable to obtain either an IPv4 or" " an IPv6 dispatch"); result = ISC_R_UNEXPECTED; goto cleanup; @@ -9898,8 +9896,8 @@ run_server(isc_task_t *task, isc_event_t *event) { CHECKFATAL(ns_interfacemgr_create( named_g_mctx, server->sctx, named_g_taskmgr, named_g_timermgr, named_g_socketmgr, named_g_netmgr, - named_g_dispatchmgr, server->task, named_g_udpdisp, - geoip, named_g_cpus, &server->interfacemgr), + named_g_dispatchmgr, server->task, geoip, + named_g_cpus, &server->interfacemgr), "creating interface manager"); CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive, diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index e8de005bc5..1bbff39504 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -79,6 +79,7 @@ struct dns_dispatchmgr { /*% * Locked by qid->lock if qid exists; otherwise, can be used without * being locked. + * * Memory footprint considerations: this is a simple implementation of * available ports, i.e., an ordered array of the actual port numbers. * This will require about 256KB of memory in the worst case (128KB for @@ -151,7 +152,6 @@ struct dispsocket { isc_socket_t *socket; dns_dispatch_t *disp; isc_sockaddr_t host; - in_port_t localport; /* XXX: should be removed later */ dispportentry_t *portentry; dns_dispentry_t *resp; isc_task_t *task; @@ -199,7 +199,6 @@ struct dns_dispatch { isc_sockaddr_t local; /*%< local address */ in_port_t localport; /*%< local UDP port */ isc_sockaddr_t peer; /*%< peer address (TCP) */ - isc_dscp_t dscp; /*%< "listen-on" DSCP value */ unsigned int maxrequests; /*%< max requests */ isc_event_t *ctlevent; @@ -212,7 +211,7 @@ struct dns_dispatch { isc_mutex_t lock; /*%< locks all below */ isc_sockettype_t socktype; unsigned int attributes; - unsigned int refcount; /*%< number of users */ + isc_refcount_t refcount; dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ unsigned int shutting_down : 1, shutdown_out : 1, connected : 1, tcpmsg_valid : 1, recv_pending : 1; /*%< is a recv() pending? * @@ -324,7 +323,7 @@ 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, - isc_socket_t *dup_socket, bool duponly); + isc_socket_t *dup_socket); static bool portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_sockaddr_t *sockaddrp); @@ -444,7 +443,7 @@ dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, */ static dns_dispentry_t * linear_first(dns_qid_t *qid) { - dns_dispentry_t *ret; + dns_dispentry_t *ret = NULL; unsigned int bucket; bucket = 0; @@ -466,7 +465,7 @@ linear_first(dns_qid_t *qid) { */ static dns_dispentry_t * linear_next(dns_qid_t *qid, dns_dispentry_t *resp) { - dns_dispentry_t *ret; + dns_dispentry_t *ret = NULL; unsigned int bucket; ret = ISC_LIST_NEXT(resp, link); @@ -492,7 +491,7 @@ linear_next(dns_qid_t *qid, dns_dispentry_t *resp) { */ static bool destroy_disp_ok(dns_dispatch_t *disp) { - if (disp->refcount != 0) { + if (isc_refcount_current(&disp->refcount) != 0) { return (false); } @@ -519,10 +518,10 @@ destroy_disp_ok(dns_dispatch_t *disp) { */ static void destroy_disp(isc_task_t *task, isc_event_t *event) { - dns_dispatch_t *disp; - dns_dispatchmgr_t *mgr; + dns_dispatch_t *disp = NULL; + dns_dispatchmgr_t *mgr = NULL; bool killmgr; - dispsocket_t *dispsocket; + dispsocket_t *dispsocket = NULL; int i; INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL); @@ -570,7 +569,7 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { */ static dispportentry_t * port_search(dns_dispatch_t *disp, in_port_t port) { - dispportentry_t *portentry; + dispportentry_t *portentry = NULL; REQUIRE(disp->port_table != NULL); @@ -588,8 +587,8 @@ port_search(dns_dispatch_t *disp, in_port_t port) { static dispportentry_t * new_portentry(dns_dispatch_t *disp, in_port_t port) { - dispportentry_t *portentry; - dns_qid_t *qid; + dispportentry_t *portentry = NULL; + dns_qid_t *qid = NULL; REQUIRE(disp->port_table != NULL); @@ -632,7 +631,7 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { static dispsocket_t * socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port, unsigned int bucket) { - dispsocket_t *dispsock; + dispsocket_t *dispsock = NULL; REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); @@ -667,19 +666,19 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, in_port_t port; isc_sockaddr_t localaddr; unsigned int bucket = 0; - dispsocket_t *dispsock; + dispsocket_t *dispsock = NULL; unsigned int nports; - in_port_t *ports; + in_port_t *ports = NULL; isc_socket_options_t bindoptions; dispportentry_t *portentry = NULL; - dns_qid_t *qid; + dns_qid_t *qid = NULL; if (isc_sockaddr_pf(&disp->local) == AF_INET) { - nports = disp->mgr->nv4ports; - ports = disp->mgr->v4ports; + nports = mgr->nv4ports; + ports = mgr->v4ports; } else { - nports = disp->mgr->nv6ports; - ports = disp->mgr->v6ports; + nports = mgr->nv6ports; + ports = mgr->v6ports; } if (nports == 0) { return (ISC_R_ADDRNOTAVAIL); @@ -694,11 +693,8 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock)); disp->nsockets++; - dispsock->socket = NULL; - dispsock->disp = disp; - dispsock->resp = NULL; - dispsock->portentry = NULL; - dispsock->task = NULL; + + *dispsock = (dispsocket_t){ .disp = disp }; isc_task_attach(disp->task[isc_random_uniform(disp->ntasks)], &dispsock->task); ISC_LINK_INIT(dispsock, link); @@ -732,7 +728,7 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, bindoptions |= ISC_SOCKET_REUSEADDRESS; } result = open_socket(sockmgr, &localaddr, bindoptions, &sock, - NULL, false); + NULL); if (result == ISC_R_SUCCESS) { if (portentry == NULL) { portentry = new_portentry(disp, port); @@ -781,7 +777,7 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, */ static void destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { - dispsocket_t *dispsock; + dispsocket_t *dispsock = NULL; dns_qid_t *qid = DNS_QID(disp); /* @@ -871,7 +867,7 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { static dns_dispentry_t * entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, in_port_t port, unsigned int bucket) { - dns_dispentry_t *res; + dns_dispentry_t *res = NULL; REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); @@ -936,7 +932,7 @@ free_sevent(isc_event_t *ev) { 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; + isc_socketevent_t *ev = NULL; void *deconst_arg; ev = isc_mem_get(disp->sepool, sizeof(*ev)); @@ -968,13 +964,12 @@ free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { static inline dns_dispatchevent_t * allocate_devent(dns_dispatch_t *disp) { - dns_dispatchevent_t *ev; + dns_dispatchevent_t *ev = NULL; ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); isc_refcount_increment0(&disp->mgr->irefs); ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, NULL); - return (ev); } @@ -1020,12 +1015,12 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_buffer_t source; unsigned int flags; dns_dispentry_t *resp = NULL; - dns_dispatchevent_t *rev; + dns_dispatchevent_t *rev = NULL; unsigned int bucket; bool killit; bool queue_response; - dns_dispatchmgr_t *mgr; - dns_qid_t *qid; + dns_dispatchmgr_t *mgr = NULL; + dns_qid_t *qid = NULL; isc_netaddr_t netaddr; int match; int result; @@ -1085,25 +1080,25 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { } if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - if (dispsock != NULL) { - resp = dispsock->resp; - id = resp->id; - if (ev->result != ISC_R_SUCCESS) { - /* - * This is most likely 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; - } - } else { + if (dispsock == NULL) { free_buffer(disp, ev->region.base, ev->region.length); isc_event_free(&ev_in); UNLOCK(&disp->lock); return; } + + resp = dispsock->resp; + id = resp->id; + if (ev->result != ISC_R_SUCCESS) { + /* + * This is most likely 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; + } } else if (ev->result != ISC_R_SUCCESS) { free_buffer(disp, ev->region.base, ev->region.length); @@ -1244,10 +1239,6 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { sendresponse: queue_response = resp->item_out; rev = allocate_devent(resp->disp); - if (rev == NULL) { - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; - } /* * At this point, rev contains the event we want to fill in, and @@ -1318,12 +1309,12 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { dns_messageid_t id; isc_result_t dres; unsigned int flags; - dns_dispentry_t *resp; - dns_dispatchevent_t *rev; + dns_dispentry_t *resp = NULL; + dns_dispatchevent_t *rev = NULL; unsigned int bucket; bool killit; bool queue_response; - dns_qid_t *qid; + dns_qid_t *qid = NULL; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -1342,7 +1333,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { INSIST(disp->recv_pending != 0); disp->recv_pending = 0; - if (disp->refcount == 0) { + if (isc_refcount_current(&disp->refcount) == 0) { /* * This dispatcher is shutting down. Force cancellation. */ @@ -1437,15 +1428,12 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { resp = entry_search(qid, &tcpmsg->address, 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; } + queue_response = resp->item_out; rev = allocate_devent(disp); - if (rev == NULL) { - goto unlock; - } /* * At this point, rev contains the event we want to fill in, and @@ -1489,7 +1477,7 @@ static isc_result_t startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_result_t res; isc_region_t region; - isc_socket_t *sock; + isc_socket_t *sock = NULL; if (disp->shutting_down == 1) { return (ISC_R_SUCCESS); @@ -1526,10 +1514,6 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_socketevent_t *sev = allocate_sevent( disp, sock, ISC_SOCKEVENT_RECVDONE, udp_exrecv, dispsock); - if (sev == NULL) { - free_buffer(disp, region.base, region.length); - return (ISC_R_NOMEMORY); - } res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); if (res != ISC_R_SUCCESS) { @@ -1541,10 +1525,6 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_socketevent_t *sev = allocate_sevent( disp, sock, ISC_SOCKEVENT_RECVDONE, udp_shrecv, disp); - if (sev == NULL) { - free_buffer(disp, region.base, region.length); - return (ISC_R_NOMEMORY); - } res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); if (res != ISC_R_SUCCESS) { @@ -1605,7 +1585,7 @@ destroy_mgr_ok(dns_dispatchmgr_t *mgr) { */ static void destroy_mgr(dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr; + dns_dispatchmgr_t *mgr = NULL; mgr = *mgrp; *mgrp = NULL; @@ -1642,8 +1622,8 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { 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 *dup_socket, bool duponly) { - isc_socket_t *sock; + isc_socket_t *dup_socket) { + isc_socket_t *sock = NULL; isc_result_t result; sock = *sockp; @@ -1652,8 +1632,7 @@ open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, if (result != ISC_R_SUCCESS) { return (result); } - } else if (dup_socket != NULL && - (!isc_socket_hasreuseport() || duponly)) { + } else if (dup_socket != NULL && !isc_socket_hasreuseport()) { result = isc_socket_dup(dup_socket, &sock); if (result != ISC_R_SUCCESS) { return (result); @@ -1867,7 +1846,7 @@ dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int maxbuffers, void dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr; + dns_dispatchmgr_t *mgr = NULL; bool killit; REQUIRE(mgrp != NULL); @@ -1953,12 +1932,10 @@ unlock: return (available); } -#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask))) - static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, unsigned int increment, dns_qid_t **qidp, bool needsocktable) { - dns_qid_t *qid; + dns_qid_t *qid = NULL; unsigned int i; REQUIRE(VALID_DISPATCHMGR(mgr)); @@ -1995,7 +1972,7 @@ qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { - dns_qid_t *qid; + dns_qid_t *qid = NULL; REQUIRE(qidp != NULL); qid = *qidp; @@ -2020,8 +1997,7 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { static isc_result_t dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - isc_result_t result; + dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(dispp != NULL && *dispp == NULL); @@ -2034,52 +2010,20 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, disp = isc_mem_get(mgr->mctx, sizeof(*disp)); isc_refcount_increment0(&mgr->irefs); - disp->magic = 0; - disp->mgr = mgr; - disp->maxrequests = maxrequests; - disp->attributes = 0; + *disp = (dns_dispatch_t){ .mgr = mgr, + .maxrequests = maxrequests, + .shutdown_why = ISC_R_UNEXPECTED }; + isc_refcount_init(&disp->refcount, 1); ISC_LINK_INIT(disp, link); - disp->refcount = 1; - disp->recv_pending = 0; - memset(&disp->local, 0, sizeof(disp->local)); - memset(&disp->peer, 0, sizeof(disp->peer)); - disp->localport = 0; - disp->shutting_down = 0; - disp->shutdown_out = 0; - disp->connected = 0; - disp->tcpmsg_valid = 0; - disp->shutdown_why = ISC_R_UNEXPECTED; - disp->requests = 0; - disp->tcpbuffers = 0; - disp->qid = NULL; ISC_LIST_INIT(disp->activesockets); ISC_LIST_INIT(disp->inactivesockets); - disp->nsockets = 0; - disp->port_table = NULL; - disp->dscp = -1; isc_mutex_init(&disp->lock); - disp->failsafe_ev = allocate_devent(disp); - if (disp->failsafe_ev == NULL) { - result = ISC_R_NOMEMORY; - goto kill_lock; - } - disp->magic = DISPATCH_MAGIC; *dispp = disp; return (ISC_R_SUCCESS); - - /* - * error returns - */ -kill_lock: - isc_mutex_destroy(&disp->lock); - isc_refcount_decrement(&mgr->irefs); - isc_mem_put(mgr->mctx, disp, sizeof(*disp)); - - return (result); } /* @@ -2087,8 +2031,8 @@ kill_lock: */ static void dispatch_free(dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - dns_dispatchmgr_t *mgr; + dns_dispatch_t *disp = NULL; + dns_dispatchmgr_t *mgr = NULL; REQUIRE(VALID_DISPATCH(*dispp)); disp = *dispp; @@ -2140,7 +2084,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, unsigned int buckets, unsigned int increment, unsigned int attributes, dns_dispatch_t **dispp) { isc_result_t result; - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; UNUSED(maxbuffers); UNUSED(buffersize); @@ -2221,8 +2165,12 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, ISC_LIST_APPEND(mgr->list, disp, link); UNLOCK(&mgr->lock); - mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); + if (isc_log_wouldlog(dns_lctx, 90)) { + mgr_log(mgr, LVL(90), + "dns_dispatch_createtcp: created TCP dispatch %p", + disp); + dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); + } *dispp = disp; return (ISC_R_SUCCESS); @@ -2237,11 +2185,13 @@ deallocate_dispatch: return (result); } +#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; + dns_dispatch_t *disp = NULL; isc_result_t result; isc_sockaddr_t peeraddr; isc_sockaddr_t sockname; @@ -2278,7 +2228,7 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, isc_sockaddr_eqaddr(localaddr, &sockname))) { /* attach */ - disp->refcount++; + isc_refcount_increment(&disp->refcount); *dispp = disp; match = true; if (connected != NULL) { @@ -2307,7 +2257,7 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, isc_sockaddr_equal(destaddr, &disp->peer)) { /* attach */ - disp->refcount++; + isc_refcount_increment(&disp->refcount); *dispp = disp; match = true; } @@ -2350,11 +2300,11 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, } /* - * Nope, create one. + * We need an exclusive-socket dispatch, or else we didn't + * find a suitable shared one and need to create it. */ result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, maxrequests, attributes, &disp, NULL); - if (result != ISC_R_SUCCESS) { UNLOCK(&mgr->lock); return (result); @@ -2383,62 +2333,16 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, isc_sockaddr_t localaddr_bound; isc_socket_t *sock = NULL; isc_result_t result = ISC_R_SUCCESS; - bool anyport; + unsigned int nports; + in_port_t *ports = NULL; - INSIST(sockp != NULL && *sockp == NULL); + REQUIRE(sockp != NULL && *sockp == NULL); - localaddr_bound = *localaddr; - anyport = (isc_sockaddr_getport(localaddr) == 0); - - if (anyport) { - unsigned int nports; - in_port_t *ports; - - /* - * If no port is specified, we first try to pick up a random - * port by ourselves. - */ - if (isc_sockaddr_pf(localaddr) == AF_INET) { - nports = disp->mgr->nv4ports; - ports = disp->mgr->v4ports; - } else { - nports = disp->mgr->nv6ports; - ports = disp->mgr->v6ports; - } - if (nports == 0) { - return (ISC_R_ADDRNOTAVAIL); - } - - for (i = 0; i < 1024; i++) { - in_port_t prt; - - prt = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&localaddr_bound, prt); - result = open_socket(sockmgr, &localaddr_bound, 0, - &sock, NULL, false); - /* - * Continue if the port chosen is already in use - * or the OS has reserved it. - */ - if (result == ISC_R_NOPERM || result == ISC_R_ADDRINUSE) - { - continue; - } - disp->localport = prt; - *sockp = sock; - return (result); - } - - /* - * If this fails 1024 times, we then ask the kernel for - * choosing one. - */ - } else { + if (isc_sockaddr_getport(localaddr) != 0) { /* Allow to reuse address for non-random ports. */ result = open_socket(sockmgr, localaddr, - ISC_SOCKET_REUSEADDRESS, &sock, dup_socket, - true); - + ISC_SOCKET_REUSEADDRESS, &sock, + dup_socket); if (result == ISC_R_SUCCESS) { *sockp = sock; } @@ -2446,11 +2350,50 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, return (result); } + /* + * If no port is specified, we first try to pick up a random + * port by ourselves. + */ + if (isc_sockaddr_pf(localaddr) == AF_INET) { + nports = mgr->nv4ports; + ports = mgr->v4ports; + } else { + nports = mgr->nv6ports; + ports = mgr->v6ports; + } + if (nports == 0) { + return (ISC_R_ADDRNOTAVAIL); + } + + localaddr_bound = *localaddr; + + for (i = 0; i < 1024; i++) { + in_port_t prt; + + prt = ports[isc_random_uniform(nports)]; + isc_sockaddr_setport(&localaddr_bound, prt); + result = open_socket(sockmgr, &localaddr_bound, 0, &sock, NULL); + /* + * If the port chosen is already in use or the OS has + * reserved it, try again. + */ + if (result == ISC_R_NOPERM || result == ISC_R_ADDRINUSE) { + continue; + } + disp->localport = prt; + *sockp = sock; + return (result); + } + + /* + * If this fails 1024 times, we then ask the kernel for + * help choosing one. + */ memset(held, 0, sizeof(held)); i = 0; for (j = 0; j < 0xffffU; j++) { - result = open_socket(sockmgr, localaddr, 0, &sock, NULL, false); + result = open_socket(sockmgr, localaddr, 0, &sock, NULL); if (result != ISC_R_SUCCESS) { goto end; } else if (portavailable(mgr, sock, NULL)) { @@ -2465,6 +2408,7 @@ get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, i = 0; } } + if (j == 0xffffU) { mgr_log(mgr, ISC_LOG_ERROR, "avoid-v%s-udp-ports: unable to allocate " @@ -2491,7 +2435,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, unsigned int maxrequests, unsigned int attributes, dns_dispatch_t **dispp, isc_socket_t *dup_socket) { isc_result_t result; - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; isc_socket_t *sock = NULL; int i = 0; @@ -2519,8 +2463,8 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_sockaddr_format(localaddr, addrbuf, ISC_SOCKADDR_FORMATSIZE); mgr_log(mgr, LVL(90), - "dns_dispatch_createudp: Created" - " UDP dispatch for %s with socket fd %d", + "dispatch_createudp: created shared " + "UDP dispatch for %s with socket fd %d", addrbuf, isc_socket_getfd(sock)); } } else { @@ -2534,8 +2478,8 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, */ isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock, NULL, - false); + result = open_socket(sockmgr, localaddr, 0, &sock, + NULL); if (sock != NULL) { isc_socket_detach(&sock); } @@ -2617,10 +2561,7 @@ dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { REQUIRE(VALID_DISPATCH(disp)); REQUIRE(dispp != NULL && *dispp == NULL); - LOCK(&disp->lock); - disp->refcount++; - UNLOCK(&disp->lock); - + isc_refcount_increment(&disp->refcount); *dispp = disp; } @@ -2633,8 +2574,8 @@ dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { */ void dns_dispatch_detach(dns_dispatch_t **dispp) { - dns_dispatch_t *disp; - dispsocket_t *dispsock; + dns_dispatch_t *disp = NULL; + dispsocket_t *dispsock = NULL; bool killit; REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); @@ -2643,10 +2584,7 @@ dns_dispatch_detach(dns_dispatch_t **dispp) { *dispp = NULL; LOCK(&disp->lock); - - INSIST(disp->refcount > 0); - disp->refcount--; - if (disp->refcount == 0) { + if (isc_refcount_decrement(&disp->refcount) == 1) { if (disp->recv_pending > 0) { isc_socket_cancel(disp->socket, disp->task[0], ISC_SOCKCANCEL_RECV); @@ -2660,7 +2598,8 @@ dns_dispatch_detach(dns_dispatch_t **dispp) { disp->shutting_down = 1; } - dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount); + dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, + isc_refcount_current(&disp->refcount)); killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); @@ -2675,13 +2614,13 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, isc_taskaction_t action, void *arg, dns_messageid_t *idp, dns_dispentry_t **resp, isc_socketmgr_t *sockmgr) { - dns_dispentry_t *res; + dns_dispentry_t *res = NULL; unsigned int bucket; in_port_t localport = 0; dns_messageid_t id; - int i; - bool ok; - dns_qid_t *qid; + int i = 0; + bool ok = false; + dns_qid_t *qid = NULL; dispsocket_t *dispsocket = NULL; isc_result_t result; @@ -2709,9 +2648,9 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { - dispsocket_t *oldestsocket; - dns_dispentry_t *oldestresp; - dns_dispatchevent_t *rev; + dispsocket_t *oldestsocket = NULL; + dns_dispentry_t *oldestresp = NULL; + dns_dispatchevent_t *rev = NULL; /* * Kill oldest outstanding query if the number of sockets @@ -2721,21 +2660,15 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, oldestresp = oldestsocket->resp; if (oldestresp != NULL && !oldestresp->item_out) { rev = allocate_devent(oldestresp->disp); - if (rev != NULL) { - 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); - oldestresp->item_out = true; - isc_task_send(oldestresp->task, - ISC_EVENT_PTR(&rev)); - inc_stats(disp->mgr, - dns_resstatscounter_dispabort); - } + 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); + oldestresp->item_out = true; + isc_task_send(oldestresp->task, ISC_EVENT_PTR(&rev)); + inc_stats(disp->mgr, dns_resstatscounter_dispabort); } /* @@ -2764,21 +2697,22 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, } /* - * Try somewhat hard to find a unique ID, unless - * DNS_DISPATCHOPT_FIXEDID is set, in which case we - * use the ID passed in via *idp. + * Try somewhat hard to find a unique ID. Start with + * a random number unless DNS_DISPATCHOPT_FIXEDID is set, + * in which case we start with the ID passed in via *idp. */ - LOCK(&qid->lock); if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) { id = *idp; } else { id = (dns_messageid_t)isc_random16(); } - ok = false; - i = 0; + + LOCK(&qid->lock); do { + dns_dispentry_t *entry = NULL; bucket = dns_hash(qid, dest, id, localport); - if (entry_search(qid, dest, id, localport, bucket) == NULL) { + entry = entry_search(qid, dest, id, localport, bucket); + if (entry == NULL) { ok = true; break; } @@ -2794,27 +2728,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); - - disp->refcount++; - disp->requests++; - res->task = NULL; + *res = (dns_dispentry_t){ .disp = disp, + .id = id, + .port = localport, + .bucket = bucket, + .host = *dest, + .action = action, + .arg = arg, + .dispsocket = dispsocket }; isc_task_attach(task, &res->task); - res->disp = disp; - res->id = id; - res->port = localport; - res->bucket = bucket; - res->host = *dest; - res->action = action; - res->arg = arg; - res->dispsocket = dispsocket; - if (dispsocket != NULL) { - dispsocket->resp = res; - } - res->item_out = false; ISC_LIST_INIT(res->items); ISC_LINK_INIT(res, link); res->magic = RESPONSE_MAGIC; + isc_refcount_increment(&disp->refcount); + disp->requests++; + + if (dispsocket != NULL) { + dispsocket->resp = res; + } + LOCK(&qid->lock); ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); @@ -2838,7 +2771,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, destroy_dispsocket(disp, &dispsocket); } - disp->refcount--; + isc_refcount_decrement(&disp->refcount); disp->requests--; dec_stats(disp->mgr, @@ -2886,8 +2819,8 @@ dns_dispatch_starttcp(dns_dispatch_t *disp) { isc_result_t dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { - dns_dispatch_t *disp; - dns_dispatchevent_t *ev; + dns_dispatch_t *disp = NULL; + dns_dispatchevent_t *ev = NULL; REQUIRE(VALID_RESPONSE(resp)); REQUIRE(sockevent != NULL && *sockevent != NULL); @@ -2930,16 +2863,16 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { void dns_dispatch_removeresponse(dns_dispentry_t **resp, dns_dispatchevent_t **sockevent) { - dns_dispatchmgr_t *mgr; - dns_dispatch_t *disp; - dns_dispentry_t *res; - dispsocket_t *dispsock; - dns_dispatchevent_t *ev; + 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; + dns_qid_t *qid = NULL; REQUIRE(resp != NULL); REQUIRE(VALID_RESPONSE(*resp)); @@ -2969,9 +2902,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, dec_stats(disp->mgr, (qid == disp->mgr->qid) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - INSIST(disp->refcount > 0); - disp->refcount--; - if (disp->refcount == 0) { + + if (isc_refcount_decrement(&disp->refcount) == 1) { if (disp->recv_pending > 0) { isc_socket_cancel(disp->socket, disp->task[0], ISC_SOCKCANCEL_RECV); @@ -3057,9 +2989,9 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, */ static void do_cancel(dns_dispatch_t *disp) { - dns_dispatchevent_t *ev; - dns_dispentry_t *resp; - dns_qid_t *qid; + dns_dispatchevent_t *ev = NULL; + dns_dispentry_t *resp = NULL; + dns_qid_t *qid = NULL; if (disp->shutdown_out == 1) { return; @@ -3151,10 +3083,6 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, /* Exclusive attribute can only be set on creation */ REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0); - /* XXXMLG - * Should check for valid attributes here! - */ - LOCK(&disp->lock); disp->attributes &= ~mask; @@ -3164,7 +3092,7 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, dns_dispatch_t * dns_dispatchset_get(dns_dispatchset_t *dset) { - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; /* check that dispatch set is configured */ if (dset == NULL || dset->ndisp == 0) { @@ -3187,8 +3115,8 @@ 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) { isc_result_t result; - dns_dispatchset_t *dset; - dns_dispatchmgr_t *mgr; + dns_dispatchset_t *dset = NULL; + dns_dispatchmgr_t *mgr = NULL; int i, j; REQUIRE(VALID_DISPATCH(source)); @@ -3198,15 +3126,13 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, mgr = source->mgr; dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t)); - memset(dset, 0, sizeof(*dset)); + *dset = (dns_dispatchset_t){ .ndisp = n }; isc_mutex_init(&dset->lock); dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n); isc_mem_attach(mctx, &dset->mctx); - dset->ndisp = n; - dset->cur = 0; dset->dispatches[0] = NULL; dns_dispatch_attach(source, &dset->dispatches[0]); @@ -3251,7 +3177,7 @@ dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) { REQUIRE(dset != NULL); for (i = 0; i < dset->ndisp; i++) { - isc_socket_t *sock; + isc_socket_t *sock = NULL; sock = dns_dispatch_getsocket(dset->dispatches[i]); isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); } @@ -3259,7 +3185,7 @@ dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) { void dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { - dns_dispatchset_t *dset; + dns_dispatchset_t *dset = NULL; int i; REQUIRE(dsetp != NULL && *dsetp != NULL); diff --git a/lib/dns/request.c b/lib/dns/request.c index bbff2d6b0e..953023a22e 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -543,7 +543,6 @@ create_tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, if (result != ISC_R_SUCCESS) { return (result); } -#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT if (srcaddr == NULL) { isc_sockaddr_anyofpf(&bind_any, isc_sockaddr_pf(destaddr)); result = isc_socket_bind(sock, &bind_any, 0); @@ -555,16 +554,13 @@ create_tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, if (result != ISC_R_SUCCESS) { goto cleanup; } -#endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */ - attrs = 0; - attrs |= DNS_DISPATCHATTR_TCP; + attrs = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_MAKEQUERY; if (isc_sockaddr_pf(destaddr) == AF_INET) { attrs |= DNS_DISPATCHATTR_IPV4; } else { attrs |= DNS_DISPATCHATTR_IPV6; } - attrs |= DNS_DISPATCHATTR_MAKEQUERY; isc_socket_dscp(sock, dscp); result = dns_dispatch_createtcp( diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 4652f04370..a47edf9ab2 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -518,14 +518,8 @@ struct dns_resolver { uint32_t lame_ttl; ISC_LIST(alternate_t) alternates; uint16_t udpsize; -#if USE_ALGLOCK - isc_rwlock_t alglock; -#endif /* if USE_ALGLOCK */ dns_rbt_t *algorithms; dns_rbt_t *digests; -#if USE_MBSLOCK - isc_rwlock_t mbslock; -#endif /* if USE_MBSLOCK */ dns_rbt_t *mustbesecure; unsigned int spillatmax; unsigned int spillatmin; @@ -2060,21 +2054,19 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, INSIST(ISC_LIST_EMPTY(fctx->validators)); query = isc_mem_get(fctx->mctx, sizeof(*query)); - query->rmessage = NULL; - dns_message_create(fctx->mctx, DNS_MESSAGE_INTENTPARSE, - &query->rmessage); - query->mctx = fctx->mctx; - query->options = options; - query->attributes = 0; - query->sends = 0; - query->connects = 0; - query->dscp = addrinfo->dscp; - query->udpsize = 0; + *query = (resquery_t){ .mctx = fctx->mctx, + .options = options, + .dscp = addrinfo->dscp, + .addrinfo = addrinfo, + .dispatchmgr = res->dispatchmgr }; + /* * Note that the caller MUST guarantee that 'addrinfo' will remain * valid until this query is canceled. */ - query->addrinfo = addrinfo; + + dns_message_create(fctx->mctx, DNS_MESSAGE_INTENTPARSE, + &query->rmessage); TIME_NOW(&query->start); /* @@ -2083,9 +2075,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, * shared dispatch. */ query->dispatchmgr = res->dispatchmgr; - query->dispatch = NULL; - query->exclusivesocket = false; - query->tcpsocket = NULL; if (res->view->peers != NULL) { dns_peer_t *peer = NULL; isc_netaddr_t dstip; @@ -2146,12 +2135,10 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, goto cleanup_query; } -#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT result = isc_socket_bind(query->tcpsocket, &addr, 0); if (result != ISC_R_SUCCESS) { goto cleanup_socket; } -#endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */ /* * A dispatch will be created once the connect succeeds. @@ -2215,10 +2202,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, INSIST(query->dispatch != NULL); } - query->dispentry = NULL; query->fctx = fctx; /* reference added by caller */ - query->tsig = NULL; - query->tsigkey = NULL; ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; @@ -4971,13 +4955,13 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, const isc_sockaddr_t *client, unsigned int options, unsigned int bucketnum, unsigned int depth, isc_counter_t *qc, fetchctx_t **fctxp) { - fetchctx_t *fctx; + fetchctx_t *fctx = NULL; isc_result_t result; isc_result_t iresult; isc_interval_t interval; unsigned int findoptions = 0; char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1]; - isc_mem_t *mctx; + isc_mem_t *mctx = NULL; size_t p; bool try_stale; @@ -4988,8 +4972,23 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, mctx = res->buckets[bucketnum].mctx; fctx = isc_mem_get(mctx, sizeof(*fctx)); + *fctx = (fetchctx_t){ + .res = res, + .type = type, + .qmintype = type, + .options = options, + .bucketnum = bucketnum, + .dbucketnum = RES_NOBUCKET, + .state = fetchstate_init, + .depth = depth, + .qmin_labels = 1, + .fwdpolicy = dns_fwdpolicy_none, + .result = ISC_R_FAILURE, + .exitline = -1 /* sentinel */ + }; + + FCTXTRACE("create"); - fctx->qc = NULL; if (qc != NULL) { isc_counter_attach(qc, &fctx->qc); } else { @@ -5010,7 +5009,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_format(type, buf + p, sizeof(buf) - p); fctx->info = isc_mem_strdup(mctx, buf); - FCTXTRACE("create"); dns_name_init(&fctx->name, NULL); dns_name_dup(name, mctx, &fctx->name); dns_name_init(&fctx->qminname, NULL); @@ -5018,28 +5016,12 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, dns_name_init(&fctx->domain, NULL); dns_rdataset_init(&fctx->nameservers); - fctx->type = type; - fctx->qmintype = type; - fctx->options = options; /* * Note! We do not attach to the task. We are relying on the * resolver to ensure that this task doesn't go away while we are * using it. */ - fctx->res = res; isc_refcount_init(&fctx->references, 0); - fctx->bucketnum = bucketnum; - fctx->dbucketnum = RES_NOBUCKET; - fctx->state = fetchstate_init; - fctx->want_shutdown = false; - fctx->cloned = false; - fctx->depth = depth; - fctx->minimized = false; - fctx->ip6arpaskip = false; - fctx->forwarding = false; - fctx->qmin_labels = 1; - fctx->qmin_warning = ISC_R_SUCCESS; - fctx->qminfetch = NULL; dns_rdataset_init(&fctx->qminrrset); dns_name_init(&fctx->qmindcname, NULL); isc_stdtime_get(&fctx->now); @@ -5049,49 +5031,21 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, ISC_LIST_INIT(fctx->forwaddrs); ISC_LIST_INIT(fctx->altaddrs); ISC_LIST_INIT(fctx->forwarders); - fctx->fwdpolicy = dns_fwdpolicy_none; ISC_LIST_INIT(fctx->bad); ISC_LIST_INIT(fctx->edns); ISC_LIST_INIT(fctx->bad_edns); ISC_LIST_INIT(fctx->validators); - fctx->validator = NULL; - fctx->find = NULL; - fctx->altfind = NULL; - fctx->pending = 0; - fctx->restarts = 0; - fctx->querysent = 0; - fctx->referrals = 0; TIME_NOW(&fctx->start); - fctx->timeouts = 0; - fctx->lamecount = 0; - fctx->quotacount = 0; - fctx->adberr = 0; - fctx->neterr = 0; - fctx->badresp = 0; - fctx->findfail = 0; - fctx->valfail = 0; - fctx->result = ISC_R_FAILURE; - fctx->vresult = ISC_R_SUCCESS; - fctx->exitline = -1; /* sentinel */ - fctx->logged = false; atomic_init(&fctx->attributes, 0); - fctx->spilled = false; - fctx->nqueries = 0; - fctx->rand_buf = 0; - fctx->rand_bits = 0; - fctx->timeout = false; - fctx->addrinfo = NULL; + if (client != NULL) { isc_sockaddr_format(client, fctx->clientstr, sizeof(fctx->clientstr)); } else { strlcpy(fctx->clientstr, "", sizeof(fctx->clientstr)); } - fctx->ns_ttl = 0; - fctx->ns_ttl_ok = false; dns_name_init(&fctx->nsname, NULL); - fctx->nsfetch = NULL; dns_rdataset_init(&fctx->nsrrset); if (domain == NULL) { @@ -10235,12 +10189,6 @@ destroy(dns_resolver_t *res) { dns_resolver_reset_ds_digests(res); dns_badcache_destroy(&res->badcache); dns_resolver_resetmustbesecure(res); -#if USE_ALGLOCK - isc_rwlock_destroy(&res->alglock); -#endif /* if USE_ALGLOCK */ -#if USE_MBSLOCK - isc_rwlock_destroy(&res->mbslock); -#endif /* if USE_MBSLOCK */ isc_timer_detach(&res->spillattimer); res->magic = 0; isc_mem_put(res->mctx, res, sizeof(*res)); @@ -10322,7 +10270,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, unsigned int options, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_resolver_t **resp) { - dns_resolver_t *res; + dns_resolver_t *res = NULL; isc_result_t result = ISC_R_SUCCESS; unsigned int i, buckets_created = 0, dbuckets_created = 0; isc_task_t *task = NULL; @@ -10340,46 +10288,51 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, REQUIRE(dispatchmgr != NULL); REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL); - res = isc_mem_get(view->mctx, sizeof(*res)); RTRACE("create"); - res->mctx = view->mctx; - res->rdclass = view->rdclass; - res->socketmgr = socketmgr; - res->timermgr = timermgr; - res->taskmgr = taskmgr; - res->dispatchmgr = dispatchmgr; - res->view = view; - res->options = options; - res->lame_ttl = 0; + res = isc_mem_get(view->mctx, sizeof(*res)); + *res = (dns_resolver_t){ .mctx = view->mctx, + .rdclass = view->rdclass, + .socketmgr = socketmgr, + .timermgr = timermgr, + .taskmgr = taskmgr, + .dispatchmgr = dispatchmgr, + .view = view, + .options = options, + .udpsize = DEFAULT_EDNS_BUFSIZE, + .spillatmin = 10, + .spillat = 10, + .spillatmax = 100, + .retryinterval = 30000, + .nonbackofftries = 3, + .query_timeout = DEFAULT_QUERY_TIMEOUT, + .maxdepth = DEFAULT_RECURSION_DEPTH, + .maxqueries = DEFAULT_MAX_QUERIES, + .nbuckets = ntasks, + .activebuckets = ntasks, + .querydscp4 = -1, + .querydscp6 = -1 }; + + res->quotaresp[dns_quotatype_zone] = DNS_R_DROP; + res->quotaresp[dns_quotatype_server] = DNS_R_SERVFAIL; + isc_refcount_init(&res->references, 1); + atomic_init(&res->exiting, false); + atomic_init(&res->priming, false); + atomic_init(&res->zspill, 0); + atomic_init(&res->nfctx, 0); + ISC_LIST_INIT(res->whenshutdown); ISC_LIST_INIT(res->alternates); - res->udpsize = DEFAULT_EDNS_BUFSIZE; - res->algorithms = NULL; - res->digests = NULL; - res->badcache = NULL; + result = dns_badcache_init(res->mctx, DNS_RESOLVER_BADCACHESIZE, &res->badcache); if (result != ISC_R_SUCCESS) { goto cleanup_res; } - res->mustbesecure = NULL; - res->spillatmin = res->spillat = 10; - res->spillatmax = 100; - res->spillattimer = NULL; - atomic_init(&res->zspill, 0); - res->zero_no_soa_ttl = false; - res->retryinterval = 30000; - res->nonbackofftries = 3; - res->query_timeout = DEFAULT_QUERY_TIMEOUT; - res->maxdepth = DEFAULT_RECURSION_DEPTH; - res->maxqueries = DEFAULT_MAX_QUERIES; - res->quotaresp[dns_quotatype_zone] = DNS_R_DROP; - res->quotaresp[dns_quotatype_server] = DNS_R_SERVFAIL; - res->nbuckets = ntasks; + if (view->resstats != NULL) { isc_stats_set(view->resstats, ntasks, dns_resstatscounter_buckets); } - res->activebuckets = ntasks; + res->buckets = isc_mem_get(view->mctx, ntasks * sizeof(fctxbucket_t)); for (i = 0; i < ntasks; i++) { isc_mutex_init(&res->buckets[i].lock); @@ -10414,7 +10367,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, dbuckets_created++; } - res->dispatches4 = NULL; if (dispatchv4 != NULL) { dns_dispatchset_create(view->mctx, socketmgr, taskmgr, dispatchv4, &res->dispatches4, ndisp); @@ -10422,7 +10374,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, res->exclusivev4 = (dispattr & DNS_DISPATCHATTR_EXCLUSIVE); } - res->dispatches6 = NULL; if (dispatchv6 != NULL) { dns_dispatchset_create(view->mctx, socketmgr, taskmgr, dispatchv6, &res->dispatches6, ndisp); @@ -10430,21 +10381,9 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, res->exclusivev6 = (dispattr & DNS_DISPATCHATTR_EXCLUSIVE); } - res->querydscp4 = -1; - res->querydscp6 = -1; - isc_refcount_init(&res->references, 1); - atomic_init(&res->exiting, false); - res->frozen = false; - ISC_LIST_INIT(res->whenshutdown); - atomic_init(&res->priming, false); - res->primefetch = NULL; - - atomic_init(&res->nfctx, 0); - isc_mutex_init(&res->lock); isc_mutex_init(&res->primelock); - task = NULL; result = isc_task_create(taskmgr, 0, &task); if (result != ISC_R_SUCCESS) { goto cleanup_primelock; @@ -10459,13 +10398,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, goto cleanup_primelock; } -#if USE_ALGLOCK - isc_rwlock_init(&res->alglock, 0, 0); -#endif /* if USE_ALGLOCK */ -#if USE_MBSLOCK - isc_rwlock_init(&res->mbslock, 0, 0); -#endif /* if USE_MBSLOCK */ - res->magic = RES_MAGIC; *resp = res; @@ -11279,15 +11211,9 @@ void dns_resolver_reset_algorithms(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->algorithms != NULL) { dns_rbt_destroy(&resolver->algorithms); } -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ } isc_result_t @@ -11310,9 +11236,6 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, return (ISC_R_RANGE); } -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->algorithms == NULL) { result = dns_rbt_create(resolver->mctx, free_algorithm, resolver->mctx, &resolver->algorithms); @@ -11359,9 +11282,6 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, } result = ISC_R_SUCCESS; cleanup: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ return (result); } @@ -11383,9 +11303,6 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, return (false); } -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (resolver->algorithms == NULL) { goto unlock; } @@ -11399,9 +11316,6 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, } } unlock: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (found) { return (false); } @@ -11421,15 +11335,9 @@ void dns_resolver_reset_ds_digests(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->digests != NULL) { dns_rbt_destroy(&resolver->digests); } -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ } isc_result_t @@ -11451,9 +11359,6 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name, return (ISC_R_RANGE); } -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ if (resolver->digests == NULL) { result = dns_rbt_create(resolver->mctx, free_digest, resolver->mctx, &resolver->digests); @@ -11496,9 +11401,6 @@ dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name, } result = ISC_R_SUCCESS; cleanup: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); -#endif /* if USE_ALGLOCK */ return (result); } @@ -11514,9 +11416,6 @@ dns_resolver_ds_digest_supported(dns_resolver_t *resolver, REQUIRE(VALID_RESOLVER(resolver)); -#if USE_ALGLOCK - RWLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (resolver->digests == NULL) { goto unlock; } @@ -11530,9 +11429,6 @@ dns_resolver_ds_digest_supported(dns_resolver_t *resolver, } } unlock: -#if USE_ALGLOCK - RWUNLOCK(&resolver->alglock, isc_rwlocktype_read); -#endif /* if USE_ALGLOCK */ if (found) { return (false); } @@ -11543,15 +11439,9 @@ void dns_resolver_resetmustbesecure(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_MBSLOCK - RWLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ if (resolver->mustbesecure != NULL) { dns_rbt_destroy(&resolver->mustbesecure); } -#if USE_MBSLOCK - RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ } static bool yes = true, no = false; @@ -11563,9 +11453,6 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name, REQUIRE(VALID_RESOLVER(resolver)); -#if USE_MBSLOCK - RWLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ if (resolver->mustbesecure == NULL) { result = dns_rbt_create(resolver->mctx, NULL, NULL, &resolver->mustbesecure); @@ -11576,9 +11463,6 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name, result = dns_rbt_addname(resolver->mustbesecure, name, value ? &yes : &no); cleanup: -#if USE_MBSLOCK - RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write); -#endif /* if USE_MBSLOCK */ return (result); } @@ -11590,9 +11474,6 @@ dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name) { REQUIRE(VALID_RESOLVER(resolver)); -#if USE_MBSLOCK - RWLOCK(&resolver->mbslock, isc_rwlocktype_read); -#endif /* if USE_MBSLOCK */ if (resolver->mustbesecure == NULL) { goto unlock; } @@ -11601,9 +11482,6 @@ dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name) { value = *(bool *)data; } unlock: -#if USE_MBSLOCK - RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read); -#endif /* if USE_MBSLOCK */ return (value); } diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 9a975c6eb5..9dbde5f76c 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -74,23 +74,21 @@ struct ns_interface { isc_sockaddr_t addr; /*%< Address and port. */ unsigned int flags; /*%< Interface flags */ char name[32]; /*%< Null terminated. */ - dns_dispatch_t * udpdispatch[MAX_UDP_DISPATCH]; - /*%< UDP dispatchers. */ - isc_socket_t * tcpsocket; /*%< TCP socket. */ - isc_nmsocket_t *udplistensocket; - isc_nmsocket_t *tcplistensocket; - isc_nmsocket_t *http_listensocket; - isc_nmsocket_t *http_secure_listensocket; - isc_dscp_t dscp; /*%< "listen-on" DSCP value */ - isc_refcount_t ntcpaccepting; /*%< Number of clients - * ready to accept new - * TCP connections on this - * interface */ - isc_refcount_t ntcpactive; /*%< Number of clients - * servicing TCP queries - * (whether accepting or - * connected) */ - int nudpdispatch; /*%< Number of UDP dispatches */ + isc_socket_t * tcpsocket; /*%< TCP socket. */ + isc_nmsocket_t * udplistensocket; + isc_nmsocket_t * tcplistensocket; + isc_nmsocket_t * http_listensocket; + isc_nmsocket_t * http_secure_listensocket; + isc_dscp_t dscp; /*%< "listen-on" DSCP value */ + isc_refcount_t ntcpaccepting; /*%< Number of clients + * ready to accept new + * TCP connections on this + * interface */ + isc_refcount_t ntcpactive; /*%< Number of clients + * servicing TCP queries + * (whether accepting or + * connected) */ + ns_clientmgr_t *clientmgr; /*%< Client manager. */ ISC_LINK(ns_interface_t) link; }; @@ -103,8 +101,8 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr, isc_task_t *task, - unsigned int udpdisp, dns_geoip_databases_t *geoip, - int ncpus, ns_interfacemgr_t **mgrp); + dns_geoip_databases_t *geoip, int ncpus, + ns_interfacemgr_t **mgrp); /*%< * Create a new interface manager. * diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 6f94d39173..045c74f9cc 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -86,7 +86,6 @@ struct ns_interfacemgr { ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces */ ISC_LIST(isc_sockaddr_t) listenon; int backlog; /*%< Listen queue size */ - unsigned int udpdisp; /*%< UDP dispatch count */ atomic_bool shuttingdown; /*%< Interfacemgr shutting down */ ns_clientmgr_t **clientmgrs; /*%< Client managers */ #ifdef USE_ROUTE_SOCKET @@ -183,8 +182,8 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr, isc_task_t *task, - unsigned int udpdisp, dns_geoip_databases_t *geoip, - int ncpus, ns_interfacemgr_t **mgrp) { + dns_geoip_databases_t *geoip, int ncpus, + ns_interfacemgr_t **mgrp) { isc_result_t result; ns_interfacemgr_t *mgr; @@ -220,7 +219,6 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx, mgr->generation = 1; mgr->listenon4 = NULL; mgr->listenon6 = NULL; - mgr->udpdisp = udpdisp; mgr->ncpus = ncpus; atomic_init(&mgr->shuttingdown, false); @@ -404,8 +402,7 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { static isc_result_t ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, ns_interface_t **ifpret) { - ns_interface_t *ifp; - int disp; + ns_interface_t *ifp = NULL; REQUIRE(NS_INTERFACEMGR_VALID(mgr)); @@ -418,10 +415,6 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, isc_mutex_init(&ifp->lock); - for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) { - ifp->udpdispatch[disp] = NULL; - } - /* * Create a single TCP client object. It will replace itself * with a new one as soon as it gets a connection, so the actual @@ -705,12 +698,6 @@ ns_interface_destroy(ns_interface_t *ifp) { ns_interface_shutdown(ifp); - for (int disp = 0; disp < ifp->nudpdispatch; disp++) { - if (ifp->udpdispatch[disp] != NULL) { - dns_dispatch_detach(&(ifp->udpdispatch[disp])); - } - } - if (ifp->tcpsocket != NULL) { isc_socket_detach(&ifp->tcpsocket); } diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 50f6e2ad3c..ffcf23adfa 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -236,8 +236,8 @@ create_managers(void) { CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, socketmgr, - netmgr, dispatchmgr, maintask, ncpus, NULL, - ncpus, &interfacemgr)); + netmgr, dispatchmgr, maintask, NULL, ncpus, + &interfacemgr)); CHECK(ns_listenlist_default(mctx, port, -1, true, &listenon)); ns_interfacemgr_setlistenon4(interfacemgr, listenon); From 5dcf55da03d707d2b1ea763308fa995292bb3d55 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 16 Dec 2020 01:32:06 -0800 Subject: [PATCH 06/28] Remove support for shared UDP dispatch sockets Currently the netmgr doesn't support unconnected, shared UDP sockets, so there's no reason to retain that functionality in the dispatcher prior to porting to the netmgr. In this commit, the DNS_DISPATCHATTR_EXCLUSIVE attribute has been removed as it is now non-optional; UDP dispatches are alwasy exclusive. Code implementing non-exclusive UDP dispatches has been removed. dns_dispatch_getentrysocket() now always returns the dispsocket for UDP dispatches and the dispatch socket for TCP dispatches. There is no longer any need to search for existing dispatches from dns_dispatch_getudp(), so the 'mask' option has been removed, and the function renamed to the more descriptive dns_dispatch_createudp(). --- bin/named/server.c | 32 +- bin/nsupdate/nsupdate.c | 26 +- bin/tests/system/pipelined/pipequeries.c | 38 +- bin/tests/system/tkey/keycreate.c | 6 +- bin/tests/system/tkey/keydelete.c | 6 +- bin/tools/mdig.c | 13 +- lib/dns/client.c | 12 +- lib/dns/dispatch.c | 591 +++++------------------ lib/dns/include/dns/dispatch.h | 25 +- lib/dns/request.c | 45 +- lib/dns/resolver.c | 70 +-- lib/dns/tests/dispatch_test.c | 12 +- lib/dns/tests/resolver_test.c | 4 +- 13 files changed, 235 insertions(+), 645 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 857609dd5a..57930b5040 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -161,11 +161,9 @@ #ifdef TUNE_LARGE #define RESOLVER_NTASKS_PERCPU 32 #define UDPBUFFERS 32768 -#define EXCLBUFFERS 32768 #else #define RESOLVER_NTASKS_PERCPU 8 -#define UDPBUFFERS 1000 -#define EXCLBUFFERS 4096 +#define UDPBUFFERS 4096 #endif /* TUNE_LARGE */ /* RFC7828 defines timeout as 16-bit value specified in units of 100 @@ -1260,7 +1258,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, dns_dispatch_t **dispatchp, isc_dscp_t *dscpp, bool is_firstview) { isc_result_t result = ISC_R_FAILURE; - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; isc_sockaddr_t sa; unsigned int attrs; const cfg_obj_t *obj = NULL; @@ -1310,8 +1308,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, /* * Try to find a dispatcher that we can share. */ - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; + attrs = DNS_DISPATCHATTR_UDP; switch (af) { case AF_INET: attrs |= DNS_DISPATCHATTR_IPV4; @@ -1320,10 +1317,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, attrs |= DNS_DISPATCHATTR_IPV6; break; } - if (isc_sockaddr_getport(&sa) == 0) { - attrs |= DNS_DISPATCHATTR_EXCLUSIVE; - maxdispatchbuffers = EXCLBUFFERS; - } else { + if (isc_sockaddr_getport(&sa) != 0) { INSIST(obj != NULL); if (is_firstview) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO, @@ -1333,10 +1327,9 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, } } - disp = NULL; - result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &sa, maxdispatchbuffers, - 32768, 16411, 16433, attrs, &disp); + result = dns_dispatch_createudp( + named_g_dispatchmgr, named_g_socketmgr, named_g_taskmgr, &sa, + maxdispatchbuffers, 32768, 16411, 16433, attrs, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -10377,8 +10370,7 @@ named_add_reserved_dispatch(named_server_t *server, dispatch->dispatchgen = server->dispatchgen; dispatch->dispatch = NULL; - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; + attrs = DNS_DISPATCHATTR_UDP; switch (isc_sockaddr_pf(addr)) { case AF_INET: attrs |= DNS_DISPATCHATTR_IPV4; @@ -10391,10 +10383,10 @@ named_add_reserved_dispatch(named_server_t *server, goto cleanup; } - result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &dispatch->addr, - UDPBUFFERS, 32768, 16411, 16433, attrs, - &dispatch->dispatch); + result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, + named_g_taskmgr, &dispatch->addr, + UDPBUFFERS, 32768, 16411, 16433, attrs, + &dispatch->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index bc39de6725..ce2a48c4d0 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -937,25 +937,23 @@ setup_system(void) { set_source_ports(dispatchmgr); if (have_ipv6) { - attrs = DNS_DISPATCHATTR_UDP; - attrs |= DNS_DISPATCHATTR_MAKEQUERY; - attrs |= DNS_DISPATCHATTR_IPV6; + attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | + DNS_DISPATCHATTR_IPV6); isc_sockaddr_any6(&bind_any6); - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - &bind_any6, 4, 2, 3, 5, attrs, - &dispatchv6); - check_result(result, "dns_dispatch_getudp (v6)"); + result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + &bind_any6, 4, 2, 3, 5, attrs, + &dispatchv6); + check_result(result, "dns_dispatch_createudp (v6)"); } if (have_ipv4) { - attrs = DNS_DISPATCHATTR_UDP; - attrs |= DNS_DISPATCHATTR_MAKEQUERY; - attrs |= DNS_DISPATCHATTR_IPV4; + attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | + DNS_DISPATCHATTR_IPV4); isc_sockaddr_any(&bind_any); - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 4, 2, 3, 5, attrs, - &dispatchv4); - check_result(result, "dns_dispatch_getudp (v4)"); + result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + &bind_any, 4, 2, 3, 5, attrs, + &dispatchv4); + check_result(result, "dns_dispatch_createudp (v4)"); } result = dns_requestmgr_create(gmctx, timermgr, socketmgr, taskmgr, diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index f9371e7c0d..e8aa99dbd1 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -59,8 +59,8 @@ #define PORT 5300 #define TIMEOUT 30 -static isc_mem_t *mctx; -static dns_requestmgr_t *requestmgr; +static isc_mem_t *mctx = NULL; +static dns_requestmgr_t *requestmgr = NULL; static bool have_src = false; static isc_sockaddr_t srcaddr; static isc_sockaddr_t dstaddr; @@ -126,10 +126,10 @@ recvresponse(isc_task_t *task, isc_event_t *event) { static isc_result_t sendquery(isc_task_t *task) { - dns_request_t *request; - dns_message_t *message; - dns_name_t *qname; - dns_rdataset_t *qrdataset; + dns_request_t *request = NULL; + dns_message_t *message = NULL; + dns_name_t *qname = NULL; + dns_rdataset_t *qrdataset = NULL; isc_result_t result; dns_fixedname_t queryname; isc_buffer_t buf; @@ -150,7 +150,6 @@ sendquery(isc_task_t *task) { dns_rootname, 0, NULL); CHECK("dns_name_fromtext", result); - message = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message); message->opcode = dns_opcode_query; @@ -158,11 +157,9 @@ sendquery(isc_task_t *task) { message->rdclass = dns_rdataclass_in; message->id = (unsigned short)(random() & 0xFFFF); - qname = NULL; result = dns_message_gettempname(message, &qname); CHECK("dns_message_gettempname", result); - qrdataset = NULL; result = dns_message_gettemprdataset(message, &qrdataset); CHECK("dns_message_gettemprdataset", result); @@ -172,7 +169,6 @@ sendquery(isc_task_t *task) { ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(message, qname, DNS_SECTION_QUESTION); - request = NULL; result = dns_request_createvia(requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, -1, DNS_REQUESTOPT_TCP, NULL, TIMEOUT, 0, 0, @@ -203,8 +199,8 @@ main(int argc, char *argv[]) { isc_sockaddr_t bind_any; struct in_addr inaddr; isc_result_t result; - isc_log_t *lctx; - isc_logconfig_t *lcfg; + isc_log_t *lctx = NULL; + isc_logconfig_t *lcfg = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; @@ -212,8 +208,8 @@ main(int argc, char *argv[]) { isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; unsigned int attrs; - dns_dispatch_t *dispatchv4; - dns_view_t *view; + dns_dispatch_t *dispatchv4 = NULL; + dns_view_t *view = NULL; uint16_t port = PORT; int c; @@ -267,11 +263,8 @@ main(int argc, char *argv[]) { } isc_sockaddr_fromin(&dstaddr, &inaddr, port); - mctx = NULL; isc_mem_create(&mctx); - lctx = NULL; - lcfg = NULL; isc_log_create(mctx, &lctx, &lcfg); RUNCHECK(dst_lib_init(mctx, NULL)); @@ -284,18 +277,15 @@ main(int argc, char *argv[]) { attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | DNS_DISPATCHATTR_IPV4; - dispatchv4 = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 4, 2, 3, - 5, attrs, &dispatchv4)); - requestmgr = NULL; + + RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + have_src ? &srcaddr : &bind_any, 4, 2, + 3, 5, attrs, &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); - view = NULL; RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); - RUNCHECK(isc_app_onrun(mctx, task, sendqueries, NULL)); (void)isc_app_run(); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 14fb88857b..1b9d500893 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -243,9 +243,9 @@ main(int argc, char *argv[]) { isc_sockaddr_any(&bind_any); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | DNS_DISPATCHATTR_IPV4; - dispatchv4 = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, - 4, 2, 3, 5, attrs, &dispatchv4)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + &bind_any, 4, 2, 3, 5, attrs, + &dispatchv4)); requestmgr = NULL; RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index 605be6ecc0..eabb3f0c7e 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -186,9 +186,9 @@ main(int argc, char **argv) { isc_sockaddr_any(&bind_any); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | DNS_DISPATCHATTR_IPV4; - dispatchv4 = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any, - 4, 2, 3, 5, attrs, &dispatchv4)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + &bind_any, 4, 2, 3, 5, attrs, + &dispatchv4)); requestmgr = NULL; RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index c07e64b032..d379285ed7 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -2071,11 +2071,10 @@ main(int argc, char *argv[]) { isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; - unsigned int attrs; dns_dispatch_t *dispatchvx = NULL; dns_view_t *view = NULL; + unsigned int attrs, i; int ns; - unsigned int i; RUNCHECK(isc_app_start()); @@ -2094,7 +2093,6 @@ main(int argc, char *argv[]) { preparse_args(argc, argv); isc_mem_create(&mctx); - isc_log_create(mctx, &lctx, &lcfg); RUNCHECK(dst_lib_init(mctx, NULL)); @@ -2128,7 +2126,6 @@ main(int argc, char *argv[]) { &socketmgr); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY; @@ -2139,10 +2136,10 @@ main(int argc, char *argv[]) { isc_sockaddr_any6(&bind_any); attrs |= DNS_DISPATCHATTR_IPV6; } - dispatchvx = NULL; - RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 100, 100, - 17, 19, attrs, &dispatchvx)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + have_src ? &srcaddr : &bind_any, 100, + 100, 17, 19, attrs, &dispatchvx)); + RUNCHECK(dns_requestmgr_create( mctx, timermgr, socketmgr, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL, have_ipv6 ? dispatchvx : NULL, diff --git a/lib/dns/client.c b/lib/dns/client.c index ce2c7e325c..3547d3cc81 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -206,13 +206,12 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, bool is_shared, dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { unsigned int attrs; - dns_dispatch_t *disp; + dns_dispatch_t *disp = NULL; unsigned maxbuffers, maxrequests, buckets, increment; isc_result_t result; isc_sockaddr_t anyaddr; - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; + attrs = DNS_DISPATCHATTR_UDP; switch (family) { case AF_INET: attrs |= DNS_DISPATCHATTR_IPV4; @@ -235,10 +234,9 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, buckets = is_shared ? 16411 : 3; increment = is_shared ? 16433 : 5; - disp = NULL; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, localaddr, - maxbuffers, maxrequests, buckets, - increment, attrs, &disp); + result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + localaddr, maxbuffers, maxrequests, + buckets, increment, attrs, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 1bbff39504..5a3bbad899 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -275,11 +275,7 @@ destroy_dispsocket(dns_dispatch_t *, dispsocket_t **); static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *); static void -udp_exrecv(isc_task_t *, isc_event_t *); -static void -udp_shrecv(isc_task_t *, isc_event_t *); -static void -udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *); +udp_recv(isc_task_t *, isc_event_t *); static void tcp_recv(isc_task_t *, isc_event_t *); static isc_result_t @@ -303,14 +299,10 @@ linear_next(dns_qid_t *disp, dns_dispentry_t *resp); static void dispatch_free(dns_dispatch_t **dispp); static isc_result_t -get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, - isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, - isc_socket_t **sockp, isc_socket_t *dup_socket); -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 maxrequests, unsigned int attributes, - dns_dispatch_t **dispp, isc_socket_t *dup_socket); + dns_dispatch_t **dispp); static bool destroy_mgr_ok(dns_dispatchmgr_t *mgr); static void @@ -324,9 +316,6 @@ 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 *dup_socket); -static bool -portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, - isc_sockaddr_t *sockaddrp); #define LVL(x) ISC_LOG_DEBUG(x) @@ -534,9 +523,8 @@ 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, task %p", - disp->socket, disp->task[0]); /* XXXX */ + dispatch_log(disp, LVL(90), "shutting down; detaching from sock %p", + disp->socket); if (disp->sepool != NULL) { isc_mem_destroy(&disp->sepool); @@ -747,29 +735,25 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, } } - if (result == ISC_R_SUCCESS) { - dispsock->socket = sock; - dispsock->host = *dest; - dispsock->bucket = bucket; - LOCK(&qid->lock); - dispsock->portentry = portentry; - ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); - UNLOCK(&qid->lock); - *dispsockp = dispsock; - *portp = port; - } else { - /* - * We could keep it in the inactive list, but since this should - * be an exceptional case and might be resource shortage, we'd - * rather destroy it. - */ + if (result != ISC_R_SUCCESS) { if (sock != NULL) { isc_socket_detach(&sock); } destroy_dispsocket(disp, &dispsock); + return (result); } - return (result); + dispsock->socket = sock; + dispsock->host = *dest; + dispsock->bucket = bucket; + LOCK(&qid->lock); + dispsock->portentry = portentry; + ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); + UNLOCK(&qid->lock); + *dispsockp = dispsock; + *portp = port; + + return (ISC_R_SUCCESS); } /*% @@ -973,26 +957,6 @@ allocate_devent(dns_dispatch_t *disp) { return (ev); } -static void -udp_exrecv(isc_task_t *task, isc_event_t *ev) { - dispsocket_t *dispsock = ev->ev_arg; - - UNUSED(task); - - REQUIRE(VALID_DISPSOCK(dispsock)); - udp_recv(ev, dispsock->disp, dispsock); -} - -static void -udp_shrecv(isc_task_t *task, isc_event_t *ev) { - dns_dispatch_t *disp = ev->ev_arg; - - UNUSED(task); - - REQUIRE(VALID_DISPATCH(disp)); - udp_recv(ev, disp, NULL); -} - /* * General flow: * @@ -1008,28 +972,36 @@ udp_shrecv(isc_task_t *task, isc_event_t *ev) { * restart. */ static void -udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { +udp_recv(isc_task_t *task, isc_event_t *ev_in) { isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; + dispsocket_t *dispsock = NULL; + dns_dispatch_t *disp = NULL; dns_messageid_t id; isc_result_t dres; isc_buffer_t source; unsigned int flags; dns_dispentry_t *resp = NULL; dns_dispatchevent_t *rev = NULL; - unsigned int bucket; bool killit; bool queue_response; dns_dispatchmgr_t *mgr = NULL; - dns_qid_t *qid = NULL; isc_netaddr_t netaddr; int match; int result; - bool qidlocked = false; + + UNUSED(task); + + REQUIRE(ev->ev_type == ISC_SOCKEVENT_RECVDONE); + + dispsock = ev_in->ev_arg; + + REQUIRE(VALID_DISPSOCK(dispsock)); + + disp = dispsock->disp; LOCK(&disp->lock); mgr = disp->mgr; - qid = mgr->qid; LOCK(&disp->mgr->buffer_lock); dispatch_log(disp, LVL(90), @@ -1037,24 +1009,12 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { disp->requests, disp->mgr->buffers, disp->recv_pending); UNLOCK(&disp->mgr->buffer_lock); - if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) { - /* - * Unless the receive event was imported from a listening - * interface, in which case the event type is - * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending. - */ - INSIST(disp->recv_pending != 0); - disp->recv_pending = 0; - } - - if (dispsock != NULL && - (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) - { + if (ev->result == 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 been no effect. So + * event the canceled event should have no effect. So * we can (and should) deactivate the socket right now. */ deactivate_dispsocket(disp, dispsock); @@ -1079,40 +1039,26 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { return; } - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - if (dispsock == NULL) { - free_buffer(disp, ev->region.base, ev->region.length); - - isc_event_free(&ev_in); - UNLOCK(&disp->lock); - return; - } - - resp = dispsock->resp; - id = resp->id; - if (ev->result != ISC_R_SUCCESS) { - /* - * This is most likely 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; - } - } else if (ev->result != ISC_R_SUCCESS) { + if (dispsock == NULL) { free_buffer(disp, ev->region.base, ev->region.length); - - if (ev->result != ISC_R_CANCELED) { - dispatch_log(disp, ISC_LOG_ERROR, - "odd socket result in udp_recv(): %s", - isc_result_totext(ev->result)); - } - isc_event_free(&ev_in); UNLOCK(&disp->lock); return; } + resp = dispsock->resp; + id = resp->id; + + if (ev->result != ISC_R_SUCCESS) { + /* + * This is most likely 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; + } + /* * If this is from a blackholed address, drop it. */ @@ -1160,33 +1106,13 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { } /* - * Search for the corresponding response. If we are using an exclusive - * socket, we've already identified it and we can skip the search; but - * the ID and the address must match the expected ones. + * The QID and the address must match the expected ones. */ - if (resp == NULL) { - bucket = dns_hash(qid, &ev->address, id, disp->localport); - LOCK(&qid->lock); - qidlocked = true; - resp = entry_search(qid, &ev->address, id, disp->localport, - bucket); - dispatch_log(disp, LVL(90), - "search for response in bucket %d: %s", bucket, - (resp == NULL ? "not found" : "found")); - - } else if (resp->id != id || - !isc_sockaddr_equal(&ev->address, &resp->host)) { - dispatch_log(disp, LVL(90), - "response to an exclusive socket doesn't match"); + if (resp->id != id || !isc_sockaddr_equal(&ev->address, &resp->host)) { + 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 unlock; - } - - if (resp == NULL) { - inc_stats(mgr, dns_resstatscounter_mismatch); - free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; + goto restart; } /* @@ -1206,7 +1132,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_sockaddr_getport(&resp->disp->local)) { free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; + goto restart; } /* @@ -1223,7 +1149,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_sockaddr_pf(&disp->local) != PF_INET6) { free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; + goto restart; } isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); @@ -1232,7 +1158,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { !isc_sockaddr_eqaddr(&a2, &disp->local)) { free_buffer(disp, ev->region.base, ev->region.length); - goto unlock; + goto restart; } } @@ -1264,23 +1190,13 @@ sendresponse: resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } -unlock: - if (qidlocked) { - UNLOCK(&qid->lock); - } /* * Restart recv() to get the next packet. */ restart: result = startrecv(disp, dispsock); - if (result != ISC_R_SUCCESS && dispsock != NULL) { - /* - * XXX: wired. There seems to be no recovery process other than - * deactivate this socket anyway (since we cannot start - * receiving, we won't be able to receive a cancel event - * from the user). - */ + if (result != ISC_R_SUCCESS) { deactivate_dispsocket(disp, dispsock); } isc_event_free(&ev_in); @@ -1478,26 +1394,21 @@ 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 (disp->recv_pending != 0 && dispsock == NULL) { - return (ISC_R_SUCCESS); - } - - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && - dispsock == NULL) { - return (ISC_R_SUCCESS); - } - - if (dispsock != NULL) { - sock = dispsock->socket; - } else { + if (dispsock == NULL) { + if (disp->socktype == isc_sockettype_udp || + disp->recv_pending != 0) { + return (ISC_R_SUCCESS); + } sock = disp->socket; + } else { + sock = dispsock->socket; } - INSIST(sock != NULL); switch (disp->socktype) { /* @@ -1509,33 +1420,13 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { if (region.base == NULL) { return (ISC_R_NOMEMORY); } - if (dispsock != NULL) { - isc_task_t *dt = dispsock->task; - isc_socketevent_t *sev = allocate_sevent( - disp, sock, ISC_SOCKEVENT_RECVDONE, udp_exrecv, - dispsock); - - res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); - if (res != ISC_R_SUCCESS) { - free_buffer(disp, region.base, region.length); - return (res); - } - } else { - isc_task_t *dt = disp->task[0]; - isc_socketevent_t *sev = allocate_sevent( - disp, sock, ISC_SOCKEVENT_RECVDONE, udp_shrecv, - disp); - - res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); - if (res != ISC_R_SUCCESS) { - free_buffer(disp, region.base, region.length); - 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; + sev = allocate_sevent(disp, sock, ISC_SOCKEVENT_RECVDONE, + udp_recv, dispsock); + res = isc_socket_recv2(sock, ®ion, 1, dispsock->task, sev, + 0); + if (res != ISC_R_SUCCESS) { + free_buffer(disp, region.base, region.length); + return (res); } break; @@ -1876,62 +1767,6 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) { isc_stats_attach(stats, &mgr->stats); } -static int -port_cmp(const void *key, const void *ent) { - in_port_t p1 = *(const in_port_t *)key; - in_port_t p2 = *(const in_port_t *)ent; - - if (p1 < p2) { - return (-1); - } else if (p1 == p2) { - return (0); - } else { - return (1); - } -} - -static bool -portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, - isc_sockaddr_t *sockaddrp) { - isc_sockaddr_t sockaddr; - isc_result_t result; - in_port_t *ports, port; - unsigned int nports; - bool available = false; - - REQUIRE(sock != NULL || sockaddrp != NULL); - - PORTBUFLOCK(mgr); - if (sock != NULL) { - sockaddrp = &sockaddr; - result = isc_socket_getsockname(sock, sockaddrp); - if (result != ISC_R_SUCCESS) { - goto unlock; - } - } - - if (isc_sockaddr_pf(sockaddrp) == AF_INET) { - ports = mgr->v4ports; - nports = mgr->nv4ports; - } else { - ports = mgr->v6ports; - nports = mgr->nv6ports; - } - if (ports == NULL) { - goto unlock; - } - - port = isc_sockaddr_getport(sockaddrp); - if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL) - { - available = true; - } - -unlock: - PORTBUFUNLOCK(mgr); - return (available); -} - static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, unsigned int increment, dns_qid_t **qidp, bool needsocktable) { @@ -2120,8 +1955,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, disp->socket = NULL; isc_socket_attach(sock, &disp->socket); - disp->sepool = NULL; - disp->ntasks = 1; disp->task[0] = NULL; result = isc_task_create(taskmgr, 50, &disp->task[0]); @@ -2140,6 +1973,12 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, disp->attributes = attributes; + if (destaddr == NULL) { + (void)isc_socket_getpeername(sock, &disp->peer); + } else { + disp->peer = *destaddr; + } + if (localaddr == NULL) { if (destaddr != NULL) { switch (isc_sockaddr_pf(destaddr)) { @@ -2150,15 +1989,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_sockaddr_any6(&disp->local); break; } + } else { + (void)isc_socket_getsockname(sock, &disp->local); } } else { disp->local = *localaddr; } - if (destaddr != NULL) { - disp->peer = *destaddr; - } - /* * Append it to the dispatcher list. */ @@ -2205,7 +2042,7 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, /* First pass */ attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED; mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE | - DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED; + DNS_DISPATCHATTR_CONNECTED; LOCK(&mgr->lock); disp = ISC_LIST_HEAD(mgr->list); @@ -2269,11 +2106,11 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, } isc_result_t -dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, - unsigned int attributes, dns_dispatch_t **dispp) { +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int buckets, unsigned int increment, + unsigned int attributes, dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; @@ -2294,149 +2131,26 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, } LOCK(&mgr->lock); - - if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - REQUIRE(isc_sockaddr_getport(localaddr) == 0); - } - - /* - * We need an exclusive-socket dispatch, or else we didn't - * find a suitable shared one and need to create it. - */ result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, - maxrequests, attributes, &disp, NULL); - if (result != ISC_R_SUCCESS) { - UNLOCK(&mgr->lock); - return (result); + maxrequests, attributes, &disp); + + if (result == ISC_R_SUCCESS) { + *dispp = disp; } UNLOCK(&mgr->lock); - *dispp = disp; - return (ISC_R_SUCCESS); } -/* - * mgr should be locked. - */ - -#ifndef DNS_DISPATCH_HELD -#define DNS_DISPATCH_HELD 20U -#endif /* ifndef DNS_DISPATCH_HELD */ - -static isc_result_t -get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, - isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, - isc_socket_t **sockp, isc_socket_t *dup_socket) { - unsigned int i, j; - isc_socket_t *held[DNS_DISPATCH_HELD]; - isc_sockaddr_t localaddr_bound; - isc_socket_t *sock = NULL; - isc_result_t result = ISC_R_SUCCESS; - unsigned int nports; - in_port_t *ports = NULL; - - REQUIRE(sockp != NULL && *sockp == NULL); - - if (isc_sockaddr_getport(localaddr) != 0) { - /* Allow to reuse address for non-random ports. */ - result = open_socket(sockmgr, localaddr, - ISC_SOCKET_REUSEADDRESS, &sock, - dup_socket); - if (result == ISC_R_SUCCESS) { - *sockp = sock; - } - - return (result); - } - - /* - * If no port is specified, we first try to pick up a random - * port by ourselves. - */ - if (isc_sockaddr_pf(localaddr) == AF_INET) { - nports = mgr->nv4ports; - ports = mgr->v4ports; - } else { - nports = mgr->nv6ports; - ports = mgr->v6ports; - } - if (nports == 0) { - return (ISC_R_ADDRNOTAVAIL); - } - - localaddr_bound = *localaddr; - - for (i = 0; i < 1024; i++) { - in_port_t prt; - - prt = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&localaddr_bound, prt); - result = open_socket(sockmgr, &localaddr_bound, 0, &sock, NULL); - /* - * If the port chosen is already in use or the OS has - * reserved it, try again. - */ - if (result == ISC_R_NOPERM || result == ISC_R_ADDRINUSE) { - continue; - } - disp->localport = prt; - *sockp = sock; - return (result); - } - - /* - * If this fails 1024 times, we then ask the kernel for - * help choosing one. - */ - memset(held, 0, sizeof(held)); - i = 0; - - for (j = 0; j < 0xffffU; j++) { - result = open_socket(sockmgr, localaddr, 0, &sock, NULL); - if (result != ISC_R_SUCCESS) { - goto end; - } else if (portavailable(mgr, sock, NULL)) { - break; - } - if (held[i] != NULL) { - isc_socket_detach(&held[i]); - } - held[i++] = sock; - sock = NULL; - if (i == DNS_DISPATCH_HELD) { - i = 0; - } - } - - if (j == 0xffffU) { - mgr_log(mgr, ISC_LOG_ERROR, - "avoid-v%s-udp-ports: unable to allocate " - "an available port", - isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6"); - result = ISC_R_FAILURE; - goto end; - } - *sockp = sock; - -end: - for (i = 0; i < DNS_DISPATCH_HELD; i++) { - if (held[i] != NULL) { - isc_socket_detach(&held[i]); - } - } - - return (result); -} - 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 maxrequests, unsigned int attributes, - dns_dispatch_t **dispp, isc_socket_t *dup_socket) { + dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; isc_socket_t *sock = NULL; + isc_sockaddr_t sa_any; int i = 0; /* @@ -2450,59 +2164,44 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, disp->socktype = isc_sockettype_udp; - if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) { - result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock, - dup_socket); + /* + * 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. + */ + isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); + if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { + result = open_socket(sockmgr, localaddr, 0, &sock, NULL); + if (sock != NULL) { + isc_socket_detach(&sock); + } if (result != ISC_R_SUCCESS) { goto deallocate_dispatch; } - - if (isc_log_wouldlog(dns_lctx, 90)) { - char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - - isc_sockaddr_format(localaddr, addrbuf, - ISC_SOCKADDR_FORMATSIZE); - mgr_log(mgr, LVL(90), - "dispatch_createudp: created shared " - "UDP dispatch for %s with socket fd %d", - addrbuf, isc_socket_getfd(sock)); - } - } else { - isc_sockaddr_t sa_any; - - /* - * For dispatches using exclusive sockets with a specific - * source address, we only check if the specified address is - * available on the system. Query sockets will be created later - * on demand. - */ - isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); - if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock, - NULL); - if (sock != NULL) { - isc_socket_detach(&sock); - } - if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; - } - } - - disp->port_table = isc_mem_get( - mgr->mctx, sizeof(disp->port_table[0]) * - DNS_DISPATCH_PORTTABLESIZE); - for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { - ISC_LIST_INIT(disp->port_table[i]); - } } + + disp->port_table = isc_mem_get(mgr->mctx, + sizeof(disp->port_table[0]) * + DNS_DISPATCH_PORTTABLESIZE); + for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { + ISC_LIST_INIT(disp->port_table[i]); + } + + if (isc_log_wouldlog(dns_lctx, 90)) { + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + isc_sockaddr_format(localaddr, addrbuf, + ISC_SOCKADDR_FORMATSIZE); + mgr_log(mgr, LVL(90), + "dispatch_createudp: created UDP dispatch for %s", + addrbuf); + } + disp->socket = sock; disp->local = *localaddr; + disp->ntasks = MAX_INTERNAL_TASKS; - if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - disp->ntasks = MAX_INTERNAL_TASKS; - } else { - disp->ntasks = 1; - } for (i = 0; i < disp->ntasks; i++) { disp->task[i] = NULL; result = isc_task_create(taskmgr, 0, &disp->task[i]); @@ -2565,13 +2264,6 @@ dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { *dispp = disp; } -/* - * It is important to lock the manager while we are deleting the dispatch, - * since dns_dispatch_getudp will call dispatch_find, which returns to - * the caller a dispatch but does not attach to it until later. _getudp - * locks the manager, however, so locking it here will keep us from attaching - * to a dispatcher that is in the process of going away. - */ void dns_dispatch_detach(dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; @@ -2629,9 +2321,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, REQUIRE(dest != NULL); REQUIRE(resp != NULL && *resp == NULL); REQUIRE(idp != NULL); - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - REQUIRE(sockmgr != NULL); - } + REQUIRE(disp->socktype == isc_sockettype_tcp || sockmgr != NULL); LOCK(&disp->lock); @@ -2645,7 +2335,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, return (ISC_R_QUOTA); } - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && + if (disp->socktype == isc_sockettype_udp && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { dispsocket_t *oldestsocket = NULL; @@ -2681,7 +2371,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, qid = DNS_QID(disp); - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { + if (disp->socktype == isc_sockettype_udp) { /* * Get a separate UDP socket with a random port number. */ @@ -2692,8 +2382,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); return (result); } - } else { - localport = disp->localport; } /* @@ -2793,13 +2481,11 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, UNLOCK(&disp->lock); + INSIST(disp->socktype == isc_sockettype_tcp || res->dispsocket != NULL); + *idp = id; *resp = res; - if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - INSIST(res->dispsocket != NULL); - } - return (ISC_R_SUCCESS); } @@ -3046,7 +2732,9 @@ isc_socket_t * dns_dispatch_getentrysocket(dns_dispentry_t *resp) { REQUIRE(VALID_RESPONSE(resp)); - if (resp->dispsocket != NULL) { + if (resp->disp->socktype == isc_sockettype_tcp) { + return (resp->disp->socket); + } else if (resp->dispsocket != NULL) { return (resp->dispsocket->socket); } else { return (NULL); @@ -3080,8 +2768,6 @@ void dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, unsigned int mask) { REQUIRE(VALID_DISPATCH(disp)); - /* Exclusive attribute can only be set on creation */ - REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0); LOCK(&disp->lock); @@ -3140,10 +2826,10 @@ 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->maxrequests, source->attributes, - &dset->dispatches[i], source->socket); + result = dispatch_createudp(mgr, sockmgr, taskmgr, + &source->local, source->maxrequests, + source->attributes, + &dset->dispatches[i]); if (result != ISC_R_SUCCESS) { goto fail; } @@ -3170,19 +2856,6 @@ fail: return (result); } -void -dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) { - int i; - - REQUIRE(dset != NULL); - - for (i = 0; i < dset->ndisp; i++) { - isc_socket_t *sock = NULL; - sock = dns_dispatch_getsocket(dset->dispatches[i]); - isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); - } -} - void dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { dns_dispatchset_t *dset = NULL; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index ddedac07b5..e4fc0cc727 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -118,9 +118,6 @@ struct dns_dispatchset { * _MAKEQUERY * The dispatcher can be used to issue queries to other servers, and * accept replies from them. - * - * _EXCLUSIVE - * A separate socket will be used on-demand for each transaction. */ #define DNS_DISPATCHATTR_PRIVATE 0x00000001U #define DNS_DISPATCHATTR_TCP 0x00000002U @@ -129,7 +126,6 @@ struct dns_dispatchset { #define DNS_DISPATCHATTR_IPV6 0x00000010U #define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U #define DNS_DISPATCHATTR_CONNECTED 0x00000080U -#define DNS_DISPATCHATTR_EXCLUSIVE 0x00000200U /*@}*/ /* @@ -214,14 +210,13 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); */ isc_result_t -dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, - unsigned int attributes, dns_dispatch_t **dispp); +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int buckets, unsigned int increment, + unsigned int attributes, dns_dispatch_t **dispp); /*%< - * Attach to existing dns_dispatch_t if one is found with dns_dispatchmgr_find, - * otherwise create a new UDP dispatch. + * Create a new UDP dispatch. * * Requires: *\li All pointer parameters be valid for their respective types. @@ -394,7 +389,7 @@ dns_dispatch_getentrysocket(dns_dispentry_t *resp); isc_socket_t * dns_dispatch_getsocket(dns_dispatch_t *disp); /*%< - * Return the socket associated with this dispatcher. + * Return the socket associated with dispatcher or dispatch entry. * * Requires: *\li disp is valid. @@ -477,12 +472,6 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, *\li dsetp != NULL, *dsetp == NULL */ -void -dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task); -/*%< - * Cancel socket operations for the dispatches in 'dset'. - */ - void dns_dispatchset_destroy(dns_dispatchset_t **dsetp); /*%< diff --git a/lib/dns/request.c b/lib/dns/request.c index 953023a22e..a4ca668e18 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -415,13 +415,14 @@ static inline isc_result_t req_send(dns_request_t *request, isc_task_t *task, const isc_sockaddr_t *address) { isc_region_t r; - isc_socket_t *sock; - isc_socketevent_t *sendevent; + isc_socket_t *sock = NULL; + isc_socketevent_t *sendevent = NULL; isc_result_t result; req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); REQUIRE(VALID_REQUEST(request)); + sock = req_getsocket(request); isc_buffer_usedregion(request->query, &r); /* @@ -596,8 +597,7 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, dns_dispatch_attach(disp, dispatchp); return (ISC_R_SUCCESS); } - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; + attrs = DNS_DISPATCHATTR_UDP; switch (isc_sockaddr_pf(srcaddr)) { case PF_INET: attrs |= DNS_DISPATCHATTR_IPV4; @@ -610,10 +610,11 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, default: return (ISC_R_NOTIMPLEMENTED); } - return (dns_dispatch_getudp(requestmgr->dispatchmgr, - requestmgr->socketmgr, requestmgr->taskmgr, - srcaddr, 32768, 32768, 16411, 16433, attrs, - dispatchp)); + + return (dns_dispatch_createudp(requestmgr->dispatchmgr, + requestmgr->socketmgr, + requestmgr->taskmgr, srcaddr, 32768, + 32768, 16411, 16433, attrs, dispatchp)); } static isc_result_t @@ -1242,18 +1243,7 @@ dns_request_destroy(dns_request_t **requestp) { static isc_socket_t * req_getsocket(dns_request_t *request) { - unsigned int dispattr; - isc_socket_t *sock; - - dispattr = dns_dispatch_getattributes(request->dispatch); - if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - INSIST(request->dispentry != NULL); - sock = dns_dispatch_getentrysocket(request->dispentry); - } else { - sock = dns_dispatch_getsocket(request->dispatch); - } - - return (sock); + return (dns_dispatch_getentrysocket(request->dispentry)); } static void @@ -1460,8 +1450,7 @@ req_destroy(dns_request_t *request) { */ static void req_cancel(dns_request_t *request) { - isc_socket_t *sock; - unsigned int dispattr; + isc_socket_t *sock = NULL; REQUIRE(VALID_REQUEST(request)); @@ -1475,16 +1464,10 @@ req_cancel(dns_request_t *request) { if (request->timer != NULL) { isc_timer_detach(&request->timer); } - dispattr = dns_dispatch_getattributes(request->dispatch); - sock = NULL; + if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) { - if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { - if (request->dispentry != NULL) { - sock = dns_dispatch_getentrysocket( - request->dispentry); - } - } else { - sock = dns_dispatch_getsocket(request->dispatch); + if (request->dispentry != NULL) { + sock = dns_dispatch_getentrysocket(request->dispentry); } if (DNS_REQUEST_CONNECTING(request) && sock != NULL) { isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index a47edf9ab2..66bebaaa6f 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -227,7 +227,6 @@ typedef struct query { isc_mem_t *mctx; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatch; - bool exclusivesocket; dns_adbaddrinfo_t *addrinfo; isc_socket_t *tcpsocket; isc_time_t start; @@ -507,11 +506,9 @@ struct dns_resolver { unsigned int options; dns_dispatchmgr_t *dispatchmgr; dns_dispatchset_t *dispatches4; - bool exclusivev4; dns_dispatchset_t *dispatches6; isc_dscp_t querydscp4; isc_dscp_t querydscp6; - bool exclusivev6; unsigned int nbuckets; fctxbucket_t *buckets; zonebucket_t *dbuckets; @@ -1434,7 +1431,6 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, isc_socket_cancel(query->tcpsocket, NULL, ISC_SOCKCANCEL_CONNECT); } else if (query->dispentry != NULL) { - INSIST(query->exclusivesocket); sock = dns_dispatch_getentrysocket(query->dispentry); if (sock != NULL) { isc_socket_cancel(sock, NULL, @@ -1446,7 +1442,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, /* * Cancel the pending send. */ - if (query->exclusivesocket && query->dispentry != NULL) { + if (query->dispentry != NULL) { sock = dns_dispatch_getentrysocket(query->dispentry); } else { sock = dns_dispatch_getsocket(query->dispatch); @@ -2074,7 +2070,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, * a dispatch for it here. Otherwise we use the resolver's * shared dispatch. */ - query->dispatchmgr = res->dispatchmgr; if (res->view->peers != NULL) { dns_peer_t *peer = NULL; isc_netaddr_t dstip; @@ -2160,7 +2155,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } - result = dns_dispatch_getudp( + result = dns_dispatch_createudp( res->dispatchmgr, res->socketmgr, res->taskmgr, &addr, 20000, 32768, 16411, 16433, attrs, &query->dispatch); @@ -2173,14 +2168,12 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_dispatch_attach( dns_resolver_dispatchv4(res), &query->dispatch); - query->exclusivesocket = res->exclusivev4; dscp = dns_resolver_getquerydscp4(fctx->res); break; case PF_INET6: dns_dispatch_attach( dns_resolver_dispatchv6(res), &query->dispatch); - query->exclusivesocket = res->exclusivev6; dscp = dns_resolver_getquerydscp6(fctx->res); break; default: @@ -2364,11 +2357,7 @@ addr2buf(void *buf, const size_t bufsize, const isc_sockaddr_t *sockaddr) { static inline isc_socket_t * query2sock(const resquery_t *query) { - if (query->exclusivesocket) { - return (dns_dispatch_getentrysocket(query->dispentry)); - } else { - return (dns_dispatch_getsocket(query->dispatch)); - } + return (dns_dispatch_getentrysocket(query->dispentry)); } static inline size_t @@ -2864,15 +2853,12 @@ resquery_send(resquery_t *query) { */ if (!tcp) { address = &query->addrinfo->sockaddr; - if (query->exclusivesocket) { - result = isc_socket_connect(sock, address, task, - resquery_udpconnected, - query); - if (result != ISC_R_SUCCESS) { - goto cleanup_message; - } - query->connects++; + result = isc_socket_connect(sock, address, task, + resquery_udpconnected, query); + if (result != ISC_R_SUCCESS) { + goto cleanup_message; } + query->connects++; } isc_buffer_usedregion(buffer, &r); @@ -3011,17 +2997,16 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { * We are connected. Create a dispatcher and * send the query. */ - attrs = 0; - attrs |= DNS_DISPATCHATTR_TCP; - attrs |= DNS_DISPATCHATTR_PRIVATE; - attrs |= DNS_DISPATCHATTR_CONNECTED; + attrs = DNS_DISPATCHATTR_TCP | + DNS_DISPATCHATTR_PRIVATE | + DNS_DISPATCHATTR_CONNECTED | + DNS_DISPATCHATTR_MAKEQUERY; if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == AF_INET) { attrs |= DNS_DISPATCHATTR_IPV4; } else { attrs |= DNS_DISPATCHATTR_IPV6; } - attrs |= DNS_DISPATCHATTR_MAKEQUERY; result = dns_dispatch_createtcp( query->dispatchmgr, query->tcpsocket, @@ -8129,17 +8114,15 @@ rctx_dispfail(respctx_t *rctx) { rctx->next_server = true; /* - * If this is a network error on an exclusive query - * socket, mark the server as bad so that we won't try - * it for this fetch again. Also adjust finish and - * no_response so that we penalize this address in SRTT - * adjustment later. + * If this is a network error, mark the server as bad so + * that we won't try it for this fetch again. Also adjust + * finish and no_response so that we penalize this address + * in SRTT adjustment later. */ - if (query->exclusivesocket && - (devent->result == ISC_R_HOSTUNREACH || - devent->result == ISC_R_NETUNREACH || - devent->result == ISC_R_CONNREFUSED || - devent->result == ISC_R_CANCELED)) + if (devent->result == ISC_R_HOSTUNREACH || + devent->result == ISC_R_NETUNREACH || + devent->result == ISC_R_CONNREFUSED || + devent->result == ISC_R_CANCELED) { rctx->broken_server = devent->result; rctx->broken_type = badns_unreachable; @@ -10275,7 +10258,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, unsigned int i, buckets_created = 0, dbuckets_created = 0; isc_task_t *task = NULL; char name[16]; - unsigned dispattr; /* * Create a resolver. @@ -10370,15 +10352,11 @@ 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); - dispattr = dns_dispatch_getattributes(dispatchv4); - res->exclusivev4 = (dispattr & DNS_DISPATCHATTR_EXCLUSIVE); } if (dispatchv6 != NULL) { dns_dispatchset_create(view->mctx, socketmgr, taskmgr, dispatchv6, &res->dispatches6, ndisp); - dispattr = dns_dispatch_getattributes(dispatchv6); - res->exclusivev6 = (dispattr & DNS_DISPATCHATTR_EXCLUSIVE); } isc_mutex_init(&res->lock); @@ -10617,14 +10595,6 @@ dns_resolver_shutdown(dns_resolver_t *res) { { fctx_shutdown(fctx); } - if (res->dispatches4 != NULL && !res->exclusivev4) { - dns_dispatchset_cancelall(res->dispatches4, - res->buckets[i].task); - } - if (res->dispatches6 != NULL && !res->exclusivev6) { - dns_dispatchset_cancelall(res->dispatches6, - res->buckets[i].task); - } atomic_store(&res->buckets[i].exiting, true); if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) { INSIST(res->activebuckets > 0); diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index 5bc81a2cd5..fb79fcf40b 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -76,8 +76,8 @@ make_dispatchset(unsigned int ndisps) { isc_sockaddr_any(&any); attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &any, 6, - 1024, 17, 19, attrs, &disp); + result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &any, + 6, 1024, 17, 19, attrs, &disp); if (result != ISC_R_SUCCESS) { return (result); } @@ -241,7 +241,7 @@ startit(isc_task_t *task, isc_event_t *event) { isc_result_t result; isc_socket_t *sock = NULL; - isc_socket_attach(dns_dispatch_getsocket(dispatch), &sock); + 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); @@ -274,8 +274,8 @@ dispatch_getnext(void **state) { ina.s_addr = htonl(INADDR_LOOPBACK); isc_sockaddr_fromin(&local, &ina, 0); attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, 6, - 1024, 17, 19, attrs, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, + 6, 1024, 17, 19, attrs, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); /* @@ -299,7 +299,7 @@ dispatch_getnext(void **state) { assert_int_equal(result, ISC_R_SUCCESS); result = dns_dispatch_addresponse(dispatch, 0, &local, task, response, - NULL, &id, &dispentry, NULL); + NULL, &id, &dispentry, socketmgr); assert_int_equal(result, ISC_R_SUCCESS); memset(message, 0, sizeof(message)); diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index b144e09f84..5b4b7e8b81 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -57,8 +57,8 @@ _setup(void **state) { assert_int_equal(result, ISC_R_SUCCESS); isc_sockaddr_any(&local); - result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &local, - 100, 100, 100, 500, 0, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, + 100, 100, 100, 500, 0, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); From 9fd375217d3ada22068992daf8d12076fcf063a7 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 16 Dec 2020 23:33:42 -0800 Subject: [PATCH 07/28] Remove DNS_DISPATCHATTR_MAKEQUERY This attribute was set but was no longer being used. --- bin/nsupdate/nsupdate.c | 6 ++---- bin/tests/system/pipelined/pipequeries.c | 4 +--- bin/tests/system/tkey/keycreate.c | 3 +-- bin/tests/system/tkey/keydelete.c | 3 +-- bin/tools/mdig.c | 2 +- lib/dns/include/dns/dispatch.h | 5 ----- lib/dns/request.c | 2 +- lib/dns/resolver.c | 3 +-- 8 files changed, 8 insertions(+), 20 deletions(-) diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index ce2a48c4d0..d0a2895d01 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -937,8 +937,7 @@ setup_system(void) { set_source_ports(dispatchmgr); if (have_ipv6) { - attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV6); + attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV6); isc_sockaddr_any6(&bind_any6); result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &bind_any6, 4, 2, 3, 5, attrs, @@ -947,8 +946,7 @@ setup_system(void) { } if (have_ipv4) { - attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4); + attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4); isc_sockaddr_any(&bind_any); result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &bind_any, 4, 2, 3, 5, attrs, diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index e8aa99dbd1..0adf5036ff 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -275,9 +275,7 @@ main(int argc, char *argv[]) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4; - + attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4; RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, have_src ? &srcaddr : &bind_any, 4, 2, 3, 5, attrs, &dispatchv4)); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 1b9d500893..b5ca6fdb48 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -241,8 +241,7 @@ main(int argc, char *argv[]) { RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); isc_sockaddr_any(&bind_any); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4; + attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4; RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &bind_any, 4, 2, 3, 5, attrs, &dispatchv4)); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index eabb3f0c7e..d4caf2940d 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -184,8 +184,7 @@ main(int argc, char **argv) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); isc_sockaddr_any(&bind_any); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY | - DNS_DISPATCHATTR_IPV4; + attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4; RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &bind_any, 4, 2, 3, 5, attrs, &dispatchv4)); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index d379285ed7..4578fd9472 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -2128,7 +2128,7 @@ main(int argc, char *argv[]) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY; + attrs = DNS_DISPATCHATTR_UDP; if (have_ipv4) { isc_sockaddr_any(&bind_any); attrs |= DNS_DISPATCHATTR_IPV4; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index e4fc0cc727..dfae6ff87e 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -114,17 +114,12 @@ struct dns_dispatchset { * * _IPV4, _IPV6 * The dispatcher uses an IPv4 or IPv6 socket. - * - * _MAKEQUERY - * The dispatcher can be used to issue queries to other servers, and - * accept replies from them. */ #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_MAKEQUERY 0x00000040U #define DNS_DISPATCHATTR_CONNECTED 0x00000080U /*@}*/ diff --git a/lib/dns/request.c b/lib/dns/request.c index a4ca668e18..c9256377d3 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -556,7 +556,7 @@ create_tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, goto cleanup; } - attrs = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_MAKEQUERY; + attrs = DNS_DISPATCHATTR_TCP; if (isc_sockaddr_pf(destaddr) == AF_INET) { attrs |= DNS_DISPATCHATTR_IPV4; } else { diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 66bebaaa6f..14f82f3a73 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2999,8 +2999,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { */ attrs = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE | - DNS_DISPATCHATTR_CONNECTED | - DNS_DISPATCHATTR_MAKEQUERY; + DNS_DISPATCHATTR_CONNECTED; if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == AF_INET) { attrs |= DNS_DISPATCHATTR_IPV4; From f439eb5d99f6ac6650de3c0719e870c31acddd8c Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 17 Dec 2020 00:43:00 -0800 Subject: [PATCH 08/28] Dispatch API simplification - Many dispatch attributes can be set implicitly instead of being passed in. we can infer whether to set DNS_DISPATCHATTR_TCP or _UDP from whether we're calling dns_dispatch_createtcp() or _createudp(). we can also infer DNS_DISPATCHATTR_IPV4 or _IPV6 from the addresses or the socket that were passed in. - We no longer use dup'd sockets in UDP dispatches, so the 'dup_socket' parameter has been removed from dns_dispatch_createudp(), along with the code implementing it. also removed isc_socket_dup() since it no longer has any callers. - The 'buffersize' parameter was ignored and has now been removed; buffersize is now fixed at 4096. - Maxbuffers and maxrequests don't need to be passed in on every call to dns_dispatch_createtcp() and _createudp(). In all current uses, the value for mgr->maxbuffers will either be raised once from its default of 20000 to 32768, or else left alone. (passing in a value lower than 20000 does not lower it.) there isn't enough difference between these values for there to be any need to configure this. The value for disp->maxrequests controls both the quota of concurrent requests for a dispatch and also the size of the dispatch socket memory pool. it's not clear that this quota is necessary at all. the memory pool size currently starts at 32768, but is sometimes lowered to 4096, which is definitely unnecessary. This commit sets both values permanently to 32768. - Previously TCP dispatches allocated their own separate QID table, which didn't incorporate a port table. this commit removes per-dispatch QID tables and shares the same table between all dispatches. since dispatches are created for each TCP socket, this may speed up the dispatch allocation process. there may be a slight increase in lock contention since all dispatches are sharing a single QID table, but since TCP sockets are used less often than UDP sockets (which were already sharing a QID table), it should not be a substantial change. - The dispatch port table was being used to determine whether a port was already in use; if so, then a UDP socket would be bound with REUSEADDR. this commit removes the port table, and always binds UDP sockets that way. --- bin/named/server.c | 37 +- bin/nsupdate/nsupdate.c | 9 +- bin/tests/system/pipelined/pipequeries.c | 9 +- bin/tests/system/tkey/keycreate.c | 33 +- bin/tests/system/tkey/keydelete.c | 33 +- bin/tools/mdig.c | 9 +- lib/dns/client.c | 30 +- lib/dns/dispatch.c | 510 +++++++---------------- lib/dns/include/dns/dispatch.h | 43 +- lib/dns/request.c | 90 +--- lib/dns/resolver.c | 25 +- lib/dns/tests/dispatch_test.c | 8 +- lib/dns/tests/resolver_test.c | 2 +- lib/isc/include/isc/socket.h | 6 - lib/isc/socket.c | 140 +++---- lib/isc/tests/socket_test.c | 85 ---- 16 files changed, 273 insertions(+), 796 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 57930b5040..e70cba3662 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -160,10 +160,8 @@ #ifdef TUNE_LARGE #define RESOLVER_NTASKS_PERCPU 32 -#define UDPBUFFERS 32768 #else #define RESOLVER_NTASKS_PERCPU 8 -#define UDPBUFFERS 4096 #endif /* TUNE_LARGE */ /* RFC7828 defines timeout as 16-bit value specified in units of 100 @@ -1260,9 +1258,8 @@ 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; + unsigned int attrs = 0; const cfg_obj_t *obj = NULL; - unsigned int maxdispatchbuffers = UDPBUFFERS; isc_dscp_t dscp = -1; switch (af) { @@ -1308,15 +1305,6 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, /* * Try to find a dispatcher that we can share. */ - attrs = DNS_DISPATCHATTR_UDP; - switch (af) { - case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - } if (isc_sockaddr_getport(&sa) != 0) { INSIST(obj != NULL); if (is_firstview) { @@ -1327,9 +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, - maxdispatchbuffers, 32768, 16411, 16433, attrs, &disp); + result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, + named_g_taskmgr, &sa, attrs, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -10343,7 +10330,7 @@ named_add_reserved_dispatch(named_server_t *server, in_port_t port; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; isc_result_t result; - unsigned int attrs; + unsigned int attrs = 0; REQUIRE(NAMED_SERVER_VALID(server)); @@ -10370,22 +10357,8 @@ named_add_reserved_dispatch(named_server_t *server, dispatch->dispatchgen = server->dispatchgen; dispatch->dispatch = NULL; - attrs = DNS_DISPATCHATTR_UDP; - switch (isc_sockaddr_pf(addr)) { - case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - default: - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } - result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &dispatch->addr, - UDPBUFFERS, 32768, 16411, 16433, attrs, + named_g_taskmgr, &dispatch->addr, attrs, &dispatch->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index d0a2895d01..be39164216 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -801,7 +801,6 @@ static void setup_system(void) { isc_result_t result; isc_sockaddr_t bind_any, bind_any6; - unsigned int attrs; isc_sockaddrlist_t *nslist; isc_logconfig_t *logconfig = NULL; irs_resconf_t *resconf = NULL; @@ -937,20 +936,16 @@ setup_system(void) { set_source_ports(dispatchmgr); if (have_ipv6) { - attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV6); isc_sockaddr_any6(&bind_any6); result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any6, 4, 2, 3, 5, attrs, - &dispatchv6); + &bind_any6, 0, &dispatchv6); check_result(result, "dns_dispatch_createudp (v6)"); } if (have_ipv4) { - attrs = (DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4); isc_sockaddr_any(&bind_any); result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 4, 2, 3, 5, attrs, - &dispatchv4); + &bind_any, 0, &dispatchv4); check_result(result, "dns_dispatch_createudp (v4)"); } diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 0adf5036ff..6466771ff2 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -70,7 +70,7 @@ 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, *response; + dns_message_t *query = NULL, *response = NULL; isc_buffer_t outbuf; char output[1024]; @@ -86,7 +86,6 @@ recvresponse(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, @@ -207,7 +206,6 @@ main(int argc, char *argv[]) { isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; - unsigned int attrs; dns_dispatch_t *dispatchv4 = NULL; dns_view_t *view = NULL; uint16_t port = PORT; @@ -275,10 +273,9 @@ main(int argc, char *argv[]) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4; RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 4, 2, - 3, 5, attrs, &dispatchv4)); + have_src ? &srcaddr : &bind_any, 0, + &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index b5ca6fdb48..6904c1998a 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -56,20 +56,20 @@ static char *ip_address = NULL; static int port = 0; -static dst_key_t *ourkey; -static isc_mem_t *mctx; -static dns_tsigkey_t *tsigkey, *initialkey; -static dns_tsig_keyring_t *ring; +static dst_key_t *ourkey = NULL; +static isc_mem_t *mctx = NULL; +static dns_tsigkey_t *tsigkey = NULL, *initialkey = NULL; +static dns_tsig_keyring_t *ring = NULL; static unsigned char noncedata[16]; static isc_buffer_t nonce; -static dns_requestmgr_t *requestmgr; +static dns_requestmgr_t *requestmgr = NULL; static const char *ownername_str = "."; static void recvquery(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query, *response; + dns_message_t *query = NULL, *response = NULL; char keyname[256]; isc_buffer_t keynamebuf; int type; @@ -134,8 +134,8 @@ sendquery(isc_task_t *task, isc_event_t *event) { dns_fixedname_t ownername; isc_buffer_t namestr, keybuf; unsigned char keydata[9]; - dns_message_t *query; - dns_request_t *request; + dns_message_t *query = NULL; + dns_request_t *request = NULL; static char keystr[] = "0123456789ab"; isc_event_free(&event); @@ -166,14 +166,12 @@ sendquery(isc_task_t *task, isc_event_t *event) { isc_buffer_usedregion(&keybuf, &r); - initialkey = NULL; result = dns_tsigkey_create( dns_fixedname_name(&keyname), DNS_TSIG_HMACMD5_NAME, isc_buffer_base(&keybuf), isc_buffer_usedlength(&keybuf), false, NULL, 0, 0, mctx, ring, &initialkey); CHECK("dns_tsigkey_create", result); - query = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); result = dns_tkey_builddhquery(query, ourkey, @@ -181,7 +179,6 @@ sendquery(isc_task_t *task, isc_event_t *event) { DNS_TSIG_HMACMD5_NAME, &nonce, 3600); CHECK("dns_tkey_builddhquery", result); - request = NULL; result = dns_request_create(requestmgr, query, &address, DNS_REQUESTOPT_TCP, initialkey, TIMEOUT, task, recvquery, query, &request); @@ -196,7 +193,6 @@ main(int argc, char *argv[]) { isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; isc_socket_t *sock = NULL; - unsigned int attrs; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -224,12 +220,9 @@ main(int argc, char *argv[]) { dns_result_register(); - mctx = NULL; isc_mem_debugging = ISC_MEM_DEBUGRECORD; isc_mem_create(&mctx); - log = NULL; - logconfig = NULL; isc_log_create(mctx, &log, &logconfig); RUNCHECK(dst_lib_init(mctx, NULL)); @@ -241,32 +234,24 @@ main(int argc, char *argv[]) { RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); isc_sockaddr_any(&bind_any); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4; RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 4, 2, 3, 5, attrs, - &dispatchv4)); - requestmgr = NULL; + &bind_any, 0, &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); - ring = NULL; RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); - tctx = NULL; RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); - view = NULL; RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); dns_view_setkeyring(view, ring); dns_tsigkeyring_detach(&ring); - sock = NULL; RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &sock)); RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); - ourkey = NULL; type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; result = dst_key_fromnamedfile(ourkeyname, NULL, type, mctx, &ourkey); CHECK("dst_key_fromnamedfile", result); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index d4caf2940d..1b8d3dc336 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -53,18 +53,18 @@ #define TIMEOUT 30 -static char *ip_address; +static char *ip_address = NULL; static int port; -static isc_mem_t *mctx; -static dns_tsigkey_t *tsigkey; -static dns_tsig_keyring_t *ring; -static dns_requestmgr_t *requestmgr; +static isc_mem_t *mctx = NULL; +static dns_tsigkey_t *tsigkey = NULL; +static dns_tsig_keyring_t *ring = NULL; +static dns_requestmgr_t *requestmgr = NULL; static void recvquery(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query, *response; + dns_message_t *query = NULL, *response = NULL; UNUSED(task); @@ -78,7 +78,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, @@ -108,8 +107,8 @@ sendquery(isc_task_t *task, isc_event_t *event) { struct in_addr inaddr; isc_sockaddr_t address; isc_result_t result; - dns_message_t *query; - dns_request_t *request; + dns_message_t *query = NULL; + dns_request_t *request = NULL; isc_event_free(&event); @@ -119,13 +118,11 @@ sendquery(isc_task_t *task, isc_event_t *event) { } isc_sockaddr_fromin(&address, &inaddr, port); - query = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query); result = dns_tkey_builddeletequery(query, tsigkey); CHECK("dns_tkey_builddeletequery", result); - request = NULL; result = dns_request_create(requestmgr, query, &address, DNS_REQUESTOPT_TCP, tsigkey, TIMEOUT, task, recvquery, query, &request); @@ -140,7 +137,6 @@ main(int argc, char **argv) { isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; isc_socket_t *sock = NULL; - unsigned int attrs; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -169,11 +165,8 @@ main(int argc, char **argv) { dns_result_register(); - mctx = NULL; isc_mem_create(&mctx); - log = NULL; - logconfig = NULL; isc_log_create(mctx, &log, &logconfig); RUNCHECK(dst_lib_init(mctx, NULL)); @@ -184,31 +177,23 @@ main(int argc, char **argv) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); isc_sockaddr_any(&bind_any); - attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_IPV4; RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 4, 2, 3, 5, attrs, - &dispatchv4)); - requestmgr = NULL; + &bind_any, 0, &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); - ring = NULL; RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); - tctx = NULL; RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); - view = NULL; RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); dns_view_setkeyring(view, ring); - sock = NULL; RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &sock)); RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); - dstkey = NULL; type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; result = dst_key_fromnamedfile(keyname, NULL, type, mctx, &dstkey); CHECK("dst_key_fromnamedfile", result); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index 4578fd9472..9c58a337cd 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -2073,7 +2073,7 @@ main(int argc, char *argv[]) { dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchvx = NULL; dns_view_t *view = NULL; - unsigned int attrs, i; + unsigned int i; int ns; RUNCHECK(isc_app_start()); @@ -2128,17 +2128,14 @@ main(int argc, char *argv[]) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); - attrs = DNS_DISPATCHATTR_UDP; if (have_ipv4) { isc_sockaddr_any(&bind_any); - attrs |= DNS_DISPATCHATTR_IPV4; } else { isc_sockaddr_any6(&bind_any); - attrs |= DNS_DISPATCHATTR_IPV6; } RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 100, - 100, 17, 19, attrs, &dispatchvx)); + have_src ? &srcaddr : &bind_any, 0, + &dispatchvx)); RUNCHECK(dns_requestmgr_create( mctx, timermgr, socketmgr, taskmgr, dispatchmgr, diff --git a/lib/dns/client.c b/lib/dns/client.c index 3547d3cc81..1d113972b8 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -203,40 +203,18 @@ cleanup: static isc_result_t getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, - bool is_shared, dns_dispatch_t **dispp, - const isc_sockaddr_t *localaddr) { - unsigned int attrs; + dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { dns_dispatch_t *disp = NULL; - unsigned maxbuffers, maxrequests, buckets, increment; isc_result_t result; isc_sockaddr_t anyaddr; - attrs = DNS_DISPATCHATTR_UDP; - switch (family) { - case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } - if (localaddr == NULL) { isc_sockaddr_anyofpf(&anyaddr, family); localaddr = &anyaddr; } - maxbuffers = is_shared ? 1000 : 8; - maxrequests = 32768; - buckets = is_shared ? 16411 : 3; - increment = is_shared ? 16433 : 5; - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - localaddr, maxbuffers, maxrequests, - buckets, increment, attrs, &disp); + localaddr, 0, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -334,7 +312,7 @@ 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, true, &dispatchv4, localaddr4); + taskmgr, &dispatchv4, localaddr4); if (result == ISC_R_SUCCESS) { client->dispatchv4 = dispatchv4; } @@ -343,7 +321,7 @@ 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, true, &dispatchv6, localaddr6); + taskmgr, &dispatchv6, localaddr6); if (result == ISC_R_SUCCESS) { client->dispatchv6 = dispatchv6; } diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 5a3bbad899..cbb84220ee 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -43,9 +43,6 @@ typedef ISC_LIST(dns_dispentry_t) dns_displist_t; typedef struct dispsocket dispsocket_t; typedef ISC_LIST(dispsocket_t) dispsocketlist_t; -typedef struct dispportentry dispportentry_t; -typedef ISC_LIST(dispportentry_t) dispportlist_t; - typedef struct dns_qid { unsigned int magic; unsigned int qid_nbuckets; /*%< hash table size */ @@ -72,7 +69,6 @@ struct dns_dispatchmgr { isc_mutex_t buffer_lock; unsigned int buffers; /*%< allocated buffers */ unsigned int buffersize; /*%< size of each buffer */ - unsigned int maxbuffers; /*%< max buffers */ isc_refcount_t irefs; @@ -101,8 +97,6 @@ struct dns_dispatchmgr { #define MGR_SHUTTINGDOWN 0x00000001U #define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0) -#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0) - struct dns_dispentry { unsigned int magic; dns_dispatch_t *disp; @@ -119,27 +113,6 @@ struct dns_dispentry { ISC_LINK(dns_dispentry_t) link; }; -/*% - * Maximum number of dispatch sockets that can be pooled for reuse. The - * appropriate value may vary, but experiments have shown a busy caching server - * may need more than 1000 sockets concurrently opened. The maximum allowable - * number of dispatch sockets (per manager) will be set to the double of this - * value. - */ -#ifndef DNS_DISPATCH_POOLSOCKS -#define DNS_DISPATCH_POOLSOCKS 2048 -#endif /* ifndef DNS_DISPATCH_POOLSOCKS */ - -/*% - * Quota to control the number of dispatch sockets. If a dispatch has more - * than the quota of sockets, new queries will purge oldest ones, so that - * a massive number of outstanding queries won't prevent subsequent queries - * (especially if the older ones take longer time and result in timeout). - */ -#ifndef DNS_DISPATCH_SOCKSQUOTA -#define DNS_DISPATCH_SOCKSQUOTA 3072 -#endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ - /*% * Fixed UDP buffer size. */ @@ -152,31 +125,14 @@ struct dispsocket { isc_socket_t *socket; dns_dispatch_t *disp; isc_sockaddr_t host; - dispportentry_t *portentry; 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; }; -/*% - * A port table entry. We remember every port we first open in a table with a - * reference counter so that we can 'reuse' the same port (with different - * destination addresses) using the SO_REUSEADDR socket option. - */ -struct dispportentry { - in_port_t port; - isc_refcount_t refs; - ISC_LINK(struct dispportentry) link; -}; - -#ifndef DNS_DISPATCH_PORTTABLESIZE -#define DNS_DISPATCH_PORTTABLESIZE 1024 -#endif /* ifndef DNS_DISPATCH_PORTTABLESIZE */ - -#define INVALID_BUCKET (0xffffdead) - /*% * 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 @@ -195,11 +151,10 @@ struct dns_dispatch { * 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) */ - unsigned int maxrequests; /*%< max requests */ + 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_event_t *ctlevent; isc_mem_t *sepool; /*%< pool for socket events */ @@ -214,8 +169,7 @@ struct dns_dispatch { isc_refcount_t refcount; dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ unsigned int shutting_down : 1, shutdown_out : 1, connected : 1, - tcpmsg_valid : 1, recv_pending : 1; /*%< is a recv() pending? * - */ + tcpmsg_valid : 1, recv_pending : 1; isc_result_t shutdown_why; ISC_LIST(dispsocket_t) activesockets; ISC_LIST(dispsocket_t) inactivesockets; @@ -223,8 +177,6 @@ struct dns_dispatch { unsigned int requests; /*%< how many requests we have */ unsigned int tcpbuffers; /*%< allocated buffers */ dns_tcpmsg_t tcpmsg; /*%< for tcp streams */ - dns_qid_t *qid; - dispportlist_t *port_table; /*%< hold ports 'owned' by us */ }; #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') @@ -242,23 +194,65 @@ struct dns_dispatch { #define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r') #define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC) -#define DNS_QID(disp) \ - ((disp)->socktype == isc_sockettype_tcp) ? (disp)->qid \ - : (disp)->mgr->qid +/*% + * Maximum number of dispatch sockets that can be pooled for reuse. The + * appropriate value may vary, but experiments have shown a busy caching server + * may need more than 1000 sockets concurrently opened. The maximum allowable + * number of dispatch sockets (per manager) will be set to the double of this + * value. + */ +#ifndef DNS_DISPATCH_POOLSOCKS +#define DNS_DISPATCH_POOLSOCKS 2048 +#endif /* ifndef DNS_DISPATCH_POOLSOCKS */ /*% - * Locking a query port buffer is a bit tricky. We access the buffer without - * locking until qid is created. Technically, there is a possibility of race - * between the creation of qid and access to the port buffer; in practice, - * however, this should be safe because qid isn't created until the first - * dispatch is created and there should be no contending situation until then. + * Quota to control the number of UDP dispatch sockets. If a dispatch has + * more than the quota of sockets, new queries will purge oldest ones, so + * that a massive number of outstanding queries won't prevent subsequent + * queries (especially if the older ones take longer time and result in + * timeout). */ -#define PORTBUFLOCK(mgr) \ - if ((mgr)->qid != NULL) \ - LOCK(&((mgr)->qid->lock)) -#define PORTBUFUNLOCK(mgr) \ - if ((mgr)->qid != NULL) \ - UNLOCK((&(mgr)->qid->lock)) +#ifndef DNS_DISPATCH_SOCKSQUOTA +#define DNS_DISPATCH_SOCKSQUOTA 3072 +#endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ + +/*% + * Number of buffers available for all dispatches in the buffery memory + * pool. + */ +#ifndef DNS_DISPATCH_MAXBUFFERS +#define DNS_DISPATCH_MAXBUFFERS 32768 +#endif /* ifndef DNS_DISPATCH_MAXBUFFERS */ + +/*% + * Number of dispatch sockets available for all dispatches in the + * socket memory pool. + */ +#ifndef DNS_DISPATCH_MAXSOCKETS +#define DNS_DISPATCH_MAXSOCKETS 32768 +#endif /* ifndef DNS_DISPATCH_MAXSOCKETS */ + +/*% + * Quota to control the number of concurrent requests that can be handled + * by each TCP dispatch. (UDP dispatches do not currently support socket + * sharing.) + */ +#ifndef DNS_DISPATCH_MAXREQUESTS +#define DNS_DISPATCH_MAXREQUESTS 32768 +#endif /* ifndef DNS_DISPATCH_MAXREQUESTS */ + +/*% + * Number of buckets in the QID hash table, and the value to + * increment the QID by when attempting to avoid collisions. + * The number of buckets should be prime, and the increment + * should be the next higher prime number. + */ +#ifndef DNS_QID_BUCKETS +#define DNS_QID_BUCKETS 16411 +#endif /* ifndef DNS_QID_BUCKETS */ +#ifndef DNS_QID_INCREMENT +#define DNS_QID_INCREMENT 16433 +#endif /* ifndef DNS_QID_INCREMENT */ /* * Statics. @@ -301,21 +295,18 @@ 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 maxrequests, unsigned int attributes, - dns_dispatch_t **dispp); + unsigned int attributes, dns_dispatch_t **dispp); static bool destroy_mgr_ok(dns_dispatchmgr_t *mgr); static void destroy_mgr(dns_dispatchmgr_t **mgrp); -static isc_result_t -qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, - unsigned int increment, dns_qid_t **qidp, bool needaddrtable); +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, - isc_socket_t *dup_socket); + unsigned int options, isc_socket_t **sockp); #define LVL(x) ISC_LOG_DEBUG(x) @@ -433,9 +424,7 @@ dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, static dns_dispentry_t * linear_first(dns_qid_t *qid) { dns_dispentry_t *ret = NULL; - unsigned int bucket; - - bucket = 0; + unsigned int bucket = 0; while (bucket < qid->qid_nbuckets) { ret = ISC_LIST_HEAD(qid->qid_table[bucket]); @@ -462,8 +451,7 @@ linear_next(dns_qid_t *qid, dns_dispentry_t *resp) { return (ret); } - bucket = resp->bucket; - bucket++; + bucket = resp->bucket + 1; while (bucket < qid->qid_nbuckets) { ret = ISC_LIST_HEAD(qid->qid_table[bucket]); if (ret != NULL) { @@ -551,67 +539,6 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { } } -/*% - * Manipulate port table per dispatch: find an entry for a given port number, - * create a new entry, and decrement a given entry with possible clean-up. - */ -static dispportentry_t * -port_search(dns_dispatch_t *disp, in_port_t port) { - dispportentry_t *portentry = NULL; - - REQUIRE(disp->port_table != NULL); - - portentry = ISC_LIST_HEAD( - disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE]); - while (portentry != NULL) { - if (portentry->port == port) { - return (portentry); - } - portentry = ISC_LIST_NEXT(portentry, link); - } - - return (NULL); -} - -static dispportentry_t * -new_portentry(dns_dispatch_t *disp, in_port_t port) { - dispportentry_t *portentry = NULL; - dns_qid_t *qid = NULL; - - REQUIRE(disp->port_table != NULL); - - portentry = isc_mem_get(disp->mgr->mctx, sizeof(*portentry)); - portentry->port = port; - isc_refcount_init(&portentry->refs, 1); - ISC_LINK_INIT(portentry, link); - qid = DNS_QID(disp); - LOCK(&qid->lock); - ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE], - portentry, link); - UNLOCK(&qid->lock); - - return (portentry); -} - -/*% - * The caller must hold the qid->lock. - */ -static void -deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { - dispportentry_t *portentry = *portentryp; - *portentryp = NULL; - - REQUIRE(disp->port_table != NULL); - REQUIRE(portentry != NULL); - - if (isc_refcount_decrement(&portentry->refs) == 1) { - ISC_LIST_UNLINK(disp->port_table[portentry->port % - DNS_DISPATCH_PORTTABLESIZE], - portentry, link); - isc_mem_put(disp->mgr->mctx, portentry, sizeof(*portentry)); - } -} - /*% * Find a dispsocket for socket address 'dest', and port number 'port'. * Return NULL if no such entry exists. Requires qid->lock to be held. @@ -627,10 +554,8 @@ socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port, dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); while (dispsock != NULL) { - if (dispsock->portentry != NULL && - dispsock->portentry->port == port && - isc_sockaddr_equal(dest, &dispsock->host)) - { + if (dispsock->port == port && + isc_sockaddr_equal(dest, &dispsock->host)) { return (dispsock); } dispsock = ISC_LIST_NEXT(dispsock, blink); @@ -649,6 +574,7 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, in_port_t *portp) { int i; 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; @@ -657,9 +583,6 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, dispsocket_t *dispsock = NULL; unsigned int nports; in_port_t *ports = NULL; - isc_socket_options_t bindoptions; - dispportentry_t *portentry = NULL; - dns_qid_t *qid = NULL; if (isc_sockaddr_pf(&disp->local) == AF_INET) { nports = mgr->nv4ports; @@ -696,7 +619,6 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, * very likely to fail in bind(2) or connect(2). */ localaddr = disp->local; - qid = DNS_QID(disp); for (i = 0; i < 64; i++) { port = ports[isc_random_uniform(nports)]; @@ -709,20 +631,9 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, continue; } UNLOCK(&qid->lock); - bindoptions = 0; - portentry = port_search(disp, port); - - if (portentry != NULL) { - bindoptions |= ISC_SOCKET_REUSEADDRESS; - } - result = open_socket(sockmgr, &localaddr, bindoptions, &sock, - NULL); + result = open_socket(sockmgr, &localaddr, + ISC_SOCKET_REUSEADDRESS, &sock); if (result == ISC_R_SUCCESS) { - if (portentry == NULL) { - portentry = new_portentry(disp, port); - } else { - isc_refcount_increment(&portentry->refs); - } break; } else if (result == ISC_R_NOPERM) { char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -746,8 +657,9 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, dispsock->socket = sock; dispsock->host = *dest; dispsock->bucket = bucket; + dispsock->port = port; + LOCK(&qid->lock); - dispsock->portentry = portentry; ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); UNLOCK(&qid->lock); *dispsockp = dispsock; @@ -762,7 +674,7 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, static void destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { dispsocket_t *dispsock = NULL; - dns_qid_t *qid = DNS_QID(disp); + dns_qid_t *qid = disp->mgr->qid; /* * The dispatch must be locked. @@ -775,11 +687,6 @@ destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { disp->nsockets--; dispsock->magic = 0; - if (dispsock->portentry != NULL) { - LOCK(&qid->lock); - deref_portentry(disp, &dispsock->portentry); - UNLOCK(&qid->lock); - } if (dispsock->socket != NULL) { isc_socket_detach(&dispsock->socket); } @@ -802,7 +709,7 @@ destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { static void deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { isc_result_t result; - dns_qid_t *qid = DNS_QID(disp); + dns_qid_t *qid = disp->mgr->qid; /* * The dispatch must be locked. @@ -813,12 +720,6 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { dispsock->resp->dispsocket = NULL; } - INSIST(dispsock->portentry != NULL); - - LOCK(&qid->lock); - deref_portentry(disp, &dispsock->portentry); - UNLOCK(&qid->lock); - if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) { destroy_dispsocket(disp, &dispsock); } else { @@ -896,7 +797,7 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { static void * allocate_udp_buffer(dns_dispatch_t *disp) { LOCK(&disp->mgr->buffer_lock); - if (disp->mgr->buffers >= disp->mgr->maxbuffers) { + if (disp->mgr->buffers >= DNS_DISPATCH_MAXBUFFERS) { UNLOCK(&disp->mgr->buffer_lock); return (NULL); } @@ -1238,7 +1139,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { REQUIRE(VALID_DISPATCH(disp)); - qid = disp->qid; + qid = disp->mgr->qid; LOCK(&disp->lock); @@ -1512,8 +1413,7 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { 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 *dup_socket) { + unsigned int options, isc_socket_t **sockp) { isc_socket_t *sock = NULL; isc_result_t result; @@ -1523,15 +1423,6 @@ open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, if (result != ISC_R_SUCCESS) { return (result); } - } else if (dup_socket != NULL && !isc_socket_hasreuseport()) { - result = isc_socket_dup(dup_socket, &sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - - isc_socket_setname(sock, "dispatcher", NULL); - *sockp = sock; - return (ISC_R_SUCCESS); } else { result = isc_socket_create(mgr, isc_sockaddr_pf(local), isc_sockettype_udp, &sock); @@ -1601,7 +1492,6 @@ setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, } while (p++ < 65535); INSIST(i4 == nv4ports && i6 == nv6ports); - PORTBUFLOCK(mgr); if (mgr->v4ports != NULL) { isc_mem_put(mgr->mctx, mgr->v4ports, mgr->nv4ports * sizeof(in_port_t)); @@ -1615,7 +1505,6 @@ setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, } mgr->v6ports = v6ports; mgr->nv6ports = nv6ports; - PORTBUFUNLOCK(mgr); return (ISC_R_SUCCESS); } @@ -1634,7 +1523,7 @@ 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){ .maxbuffers = 20000 }; + *mgr = (dns_dispatchmgr_t){ 0 }; isc_mem_attach(mctx, &mgr->mctx); @@ -1653,6 +1542,7 @@ dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { isc_portset_destroy(mctx, &v4portset); isc_portset_destroy(mctx, &v6portset); + qid_allocate(mgr, &mgr->qid); mgr->magic = DNS_DISPATCHMGR_MAGIC; *mgrp = mgr; @@ -1681,60 +1571,6 @@ dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, return (setavailports(mgr, v4portset, v6portset)); } -static isc_result_t -dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int maxbuffers, - unsigned int maxrequests, unsigned int buckets, - unsigned int increment) { - isc_result_t result; - - REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(maxbuffers > 0); - REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ - REQUIRE(increment > buckets); - UNUSED(maxrequests); - - /* - * Keep some number of items around. This should be a config - * option. For now, keep 8, but later keep at least two even - * if the caller wants less. This allows us to ensure certain - * things, like an event can be "freed" and the next allocation - * will always succeed. - * - * Note that if limits are placed on anything here, we use one - * event internally, so the actual limit should be "wanted + 1." - * - * XXXMLG - */ - - if (maxbuffers < 8) { - maxbuffers = 8; - } - - /* Adjust buffer pool if needed - * - * We only increase maxbuffers to avoid accidental buffer - * shortage. Ideally we'd separate the manager-wide maximum - * from per-dispatch limits and respect the latter within the - * global limit. But at this moment that's deemed to be - * overkilling and isn't worth additional implementation - * complexity. - */ - LOCK(&mgr->buffer_lock); - if (maxbuffers > mgr->maxbuffers) { - mgr->maxbuffers = maxbuffers; - } - UNLOCK(&mgr->buffer_lock); - - if (mgr->qid == NULL) { - result = qid_allocate(mgr, buckets, increment, &mgr->qid, true); - if (result != ISC_R_SUCCESS) { - return (result); - } - } - - return (ISC_R_SUCCESS); -} - void dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { dns_dispatchmgr_t *mgr = NULL; @@ -1767,42 +1603,31 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) { isc_stats_attach(stats, &mgr->stats); } -static isc_result_t -qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, - unsigned int increment, dns_qid_t **qidp, bool needsocktable) { +static void +qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp) { dns_qid_t *qid = NULL; unsigned int i; - REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ - REQUIRE(increment > buckets); REQUIRE(qidp != NULL && *qidp == NULL); qid = isc_mem_get(mgr->mctx, sizeof(*qid)); + *qid = (dns_qid_t){ .qid_nbuckets = DNS_QID_BUCKETS, + .qid_increment = DNS_QID_INCREMENT }; qid->qid_table = isc_mem_get(mgr->mctx, - buckets * sizeof(dns_displist_t)); - - qid->sock_table = NULL; - if (needsocktable) { - qid->sock_table = isc_mem_get( - mgr->mctx, buckets * sizeof(dispsocketlist_t)); - } + 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 < buckets; i++) { + for (i = 0; i < qid->qid_nbuckets; i++) { ISC_LIST_INIT(qid->qid_table[i]); - if (qid->sock_table != NULL) { - ISC_LIST_INIT(qid->sock_table[i]); - } + ISC_LIST_INIT(qid->sock_table[i]); } - qid->qid_nbuckets = buckets; - qid->qid_increment = increment; qid->magic = QID_MAGIC; *qidp = qid; - return (ISC_R_SUCCESS); } static void @@ -1818,10 +1643,8 @@ 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)); - if (qid->sock_table != NULL) { - isc_mem_put(mctx, qid->sock_table, - qid->qid_nbuckets * sizeof(dispsocketlist_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)); } @@ -1830,8 +1653,7 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { * Allocate and set important limits. */ static isc_result_t -dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, - dns_dispatch_t **dispp) { +dispatch_allocate(dns_dispatchmgr_t *mgr, dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); @@ -1846,7 +1668,6 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, isc_refcount_increment0(&mgr->irefs); *disp = (dns_dispatch_t){ .mgr = mgr, - .maxrequests = maxrequests, .shutdown_why = ISC_R_UNEXPECTED }; isc_refcount_init(&disp->refcount, 1); ISC_LINK_INIT(disp, link); @@ -1891,19 +1712,6 @@ dispatch_free(dns_dispatch_t **dispp) { isc_mem_put(mgr->mctx, disp->failsafe_ev, sizeof(*disp->failsafe_ev)); disp->failsafe_ev = NULL; - if (disp->qid != NULL) { - qid_destroy(mgr->mctx, &disp->qid); - } - - if (disp->port_table != NULL) { - for (int i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { - INSIST(ISC_LIST_EMPTY(disp->port_table[i])); - } - isc_mem_put(mgr->mctx, disp->port_table, - sizeof(disp->port_table[0]) * - DNS_DISPATCH_PORTTABLESIZE); - } - disp->mgr = NULL; isc_mutex_destroy(&disp->lock); disp->magic = 0; @@ -1914,52 +1722,34 @@ dispatch_free(dns_dispatch_t **dispp) { isc_result_t dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - const isc_sockaddr_t *destaddr, unsigned int buffersize, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, - unsigned int attributes, dns_dispatch_t **dispp) { + const isc_sockaddr_t *destaddr, unsigned int attributes, + dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; - - UNUSED(maxbuffers); - UNUSED(buffersize); + int pf; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp); - REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0); - REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0); - if (destaddr == NULL) { - attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */ - } + attributes |= DNS_DISPATCHATTR_TCP; + attributes &= ~DNS_DISPATCHATTR_UDP; LOCK(&mgr->lock); - /* - * dispatch_allocate() checks mgr for us. - * qid_allocate() checks buckets and increment for us. - */ - disp = NULL; - result = dispatch_allocate(mgr, maxrequests, &disp); + result = dispatch_allocate(mgr, &disp); if (result != ISC_R_SUCCESS) { UNLOCK(&mgr->lock); return (result); } - result = qid_allocate(mgr, buckets, increment, &disp->qid, false); - if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; - } - disp->socktype = isc_sockettype_tcp; - disp->socket = NULL; isc_socket_attach(sock, &disp->socket); disp->ntasks = 1; disp->task[0] = NULL; result = isc_task_create(taskmgr, 50, &disp->task[0]); if (result != ISC_R_SUCCESS) { - goto kill_socket; + goto cleanup; } disp->ctlevent = @@ -1971,17 +1761,18 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg); disp->tcpmsg_valid = 1; - disp->attributes = attributes; - if (destaddr == NULL) { (void)isc_socket_getpeername(sock, &disp->peer); + attributes |= DNS_DISPATCHATTR_PRIVATE; } else { disp->peer = *destaddr; } + pf = isc_sockaddr_pf(&disp->peer); + if (localaddr == NULL) { if (destaddr != NULL) { - switch (isc_sockaddr_pf(destaddr)) { + switch (pf) { case AF_INET: isc_sockaddr_any(&disp->local); break; @@ -1996,6 +1787,22 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, disp->local = *localaddr; } + switch (pf) { + case PF_INET: + attributes |= DNS_DISPATCHATTR_IPV4; + break; + + case PF_INET6: + attributes |= DNS_DISPATCHATTR_IPV6; + break; + + default: + result = ISC_R_NOTIMPLEMENTED; + goto cleanup; + } + + disp->attributes = attributes; + /* * Append it to the dispatcher list. */ @@ -2012,9 +1819,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, return (ISC_R_SUCCESS); -kill_socket: +cleanup: isc_socket_detach(&disp->socket); -deallocate_dispatch: dispatch_free(&disp); UNLOCK(&mgr->lock); @@ -2108,8 +1914,6 @@ 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 maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, unsigned int attributes, dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; @@ -2118,21 +1922,14 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, REQUIRE(sockmgr != NULL); REQUIRE(localaddr != NULL); REQUIRE(taskmgr != NULL); - REQUIRE(maxbuffers > 0); - REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ - REQUIRE(increment > buckets); REQUIRE(dispp != NULL && *dispp == NULL); - REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0); - result = dispatchmgr_setudp(mgr, maxbuffers, maxrequests, buckets, - increment); - if (result != ISC_R_SUCCESS) { - return (result); - } + attributes |= DNS_DISPATCHATTR_UDP; + attributes &= ~DNS_DISPATCHATTR_TCP; LOCK(&mgr->lock); result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, - maxrequests, attributes, &disp); + attributes, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; @@ -2145,23 +1942,24 @@ 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 maxrequests, unsigned int attributes, - dns_dispatch_t **dispp) { + unsigned int attributes, dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; isc_socket_t *sock = NULL; isc_sockaddr_t sa_any; - int i = 0; + int pf, i = 0; /* * dispatch_allocate() checks mgr for us. */ disp = NULL; - result = dispatch_allocate(mgr, maxrequests, &disp); + result = dispatch_allocate(mgr, &disp); if (result != ISC_R_SUCCESS) { return (result); } + pf = isc_sockaddr_pf(localaddr); + disp->socktype = isc_sockettype_udp; /* @@ -2170,9 +1968,9 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, * but we don't keep it open; sockets used for sending requests * will be created later on demand. */ - isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); + isc_sockaddr_anyofpf(&sa_any, pf); if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock, NULL); + result = open_socket(sockmgr, localaddr, 0, &sock); if (sock != NULL) { isc_socket_detach(&sock); } @@ -2181,13 +1979,6 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, } } - disp->port_table = isc_mem_get(mgr->mctx, - sizeof(disp->port_table[0]) * - DNS_DISPATCH_PORTTABLESIZE); - for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { - ISC_LIST_INIT(disp->port_table[i]); - } - if (isc_log_wouldlog(dns_lctx, 90)) { char addrbuf[ISC_SOCKADDR_FORMATSIZE]; @@ -2225,6 +2016,21 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, attributes &= ~DNS_DISPATCHATTR_TCP; attributes |= DNS_DISPATCHATTR_UDP; + + switch (pf) { + case PF_INET: + attributes |= DNS_DISPATCHATTR_IPV4; + break; + + case PF_INET6: + attributes |= DNS_DISPATCHATTR_IPV6; + break; + + default: + result = ISC_R_NOTIMPLEMENTED; + goto kill_socket; + } + disp->attributes = attributes; /* @@ -2330,11 +2136,13 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, return (ISC_R_SHUTTINGDOWN); } - if (disp->requests >= disp->maxrequests) { + if (disp->requests >= DNS_DISPATCH_MAXREQUESTS) { UNLOCK(&disp->lock); return (ISC_R_QUOTA); } + qid = disp->mgr->qid; + if (disp->socktype == isc_sockettype_udp && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { @@ -2369,8 +2177,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ISC_LIST_APPEND(disp->activesockets, oldestsocket, link); } - qid = DNS_QID(disp); - if (disp->socktype == isc_sockettype_udp) { /* * Get a separate UDP socket with a random port number. @@ -2440,7 +2246,7 @@ 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, (qid == disp->mgr->qid) + inc_stats(disp->mgr, (disp->socktype == isc_sockettype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); @@ -2463,7 +2269,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, disp->requests--; dec_stats(disp->mgr, - (qid == disp->mgr->qid) + (disp->socktype == isc_sockettype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); @@ -2570,8 +2376,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, REQUIRE(VALID_DISPATCH(disp)); mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); - - qid = DNS_QID(disp); + qid = mgr->qid; if (sockevent != NULL) { REQUIRE(*sockevent != NULL); @@ -2585,7 +2390,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, INSIST(disp->requests > 0); disp->requests--; - dec_stats(disp->mgr, (qid == disp->mgr->qid) + dec_stats(disp->mgr, (disp->socktype == isc_sockettype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); @@ -2677,14 +2482,12 @@ static void do_cancel(dns_dispatch_t *disp) { dns_dispatchevent_t *ev = NULL; dns_dispentry_t *resp = NULL; - dns_qid_t *qid = NULL; + dns_qid_t *qid = disp->mgr->qid; if (disp->shutdown_out == 1) { return; } - qid = DNS_QID(disp); - /* * Search for the first response handler without packets outstanding * unless a specific handler is given. @@ -2827,8 +2630,7 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, for (i = 1; i < n; i++) { dset->dispatches[i] = NULL; result = dispatch_createudp(mgr, sockmgr, taskmgr, - &source->local, source->maxrequests, - source->attributes, + &source->local, source->attributes, &dset->dispatches[i]); if (result != ISC_R_SUCCESS) { goto fail; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index dfae6ff87e..c9bdc42954 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -207,8 +207,6 @@ 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 maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, unsigned int attributes, dns_dispatch_t **dispp); /*%< * Create a new UDP dispatch. @@ -218,16 +216,6 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, * *\li dispp != NULL && *disp == NULL * - *\li 512 <= buffersize <= 64k - * - *\li maxbuffers > 0 - * - *\li buckets < 2097169 - * - *\li increment > buckets - * - *\li (attributes & DNS_DISPATCHATTR_TCP) == 0 - * * Returns: *\li ISC_R_SUCCESS -- success. * @@ -237,25 +225,11 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_result_t dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - const isc_sockaddr_t *destaddr, unsigned int buffersize, - unsigned int maxbuffers, unsigned int maxrequests, - unsigned int buckets, unsigned int increment, - unsigned int attributes, dns_dispatch_t **dispp); + const isc_sockaddr_t *destaddr, unsigned int attributes, + dns_dispatch_t **dispp); /*%< * Create a new dns_dispatch and attach it to the provided isc_socket_t. * - * For all dispatches, "buffersize" is the maximum packet size we will - * accept. - * - * "maxbuffers" and "maxrequests" control the number of buffers in the - * overall system and the number of buffers which can be allocated to - * requests. - * - * "buckets" is the number of buckets to use, and should be prime. - * - * "increment" is used in a collision avoidance function, and needs to be - * a prime > buckets, and not 2. - * * Requires: * *\li mgr is a valid dispatch manager. @@ -264,19 +238,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, * *\li task is a valid task that can be used internally to this dispatcher. * - * \li 512 <= buffersize <= 64k - * - *\li maxbuffers > 0. - * - *\li maxrequests <= maxbuffers. - * - *\li buckets < 2097169 (the next prime after 65536 * 32) - * - *\li increment > buckets (and prime). - * - *\li attributes includes #DNS_DISPATCHATTR_TCP and does not include - * #DNS_DISPATCHATTR_UDP. - * * Returns: *\li ISC_R_SUCCESS -- success. * diff --git a/lib/dns/request.c b/lib/dns/request.c index c9256377d3..fed16798ee 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -119,8 +119,6 @@ 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 isc_socket_t * -req_getsocket(dns_request_t *request); static void req_connected(isc_task_t *task, isc_event_t *event); static void @@ -423,8 +421,9 @@ req_send(dns_request_t *request, isc_task_t *task, REQUIRE(VALID_REQUEST(request)); - sock = req_getsocket(request); + sock = dns_dispatch_getentrysocket(request->dispentry); isc_buffer_usedregion(request->query, &r); + /* * We could connect the socket when we are using an exclusive dispatch * as we do in resolver.c, but we prefer implementation simplicity @@ -456,29 +455,11 @@ new_request(isc_mem_t *mctx, dns_request_t **requestp) { dns_request_t *request; request = isc_mem_get(mctx, sizeof(*request)); - - /* - * Zero structure. - */ - request->magic = 0; - request->mctx = NULL; - request->flags = 0; + *request = (dns_request_t){ .dscp = -1 }; ISC_LINK_INIT(request, link); - request->query = NULL; - request->answer = NULL; - request->event = NULL; - request->dispatch = NULL; - request->dispentry = NULL; - request->timer = NULL; - request->requestmgr = NULL; - request->tsig = NULL; - request->tsigkey = NULL; - request->dscp = -1; ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL, DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL, NULL); - request->canceling = false; - request->udpcount = 0; isc_mem_attach(mctx, &request->mctx); @@ -513,14 +494,12 @@ isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) { } static isc_result_t -create_tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, - const isc_sockaddr_t *srcaddr, - const isc_sockaddr_t *destaddr, isc_dscp_t dscp, - bool *connected, dns_dispatch_t **dispatchp) { +tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, + const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, + isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { isc_result_t result; isc_socket_t *sock = NULL; isc_sockaddr_t src; - unsigned int attrs; isc_sockaddr_t bind_any; if (!newtcp) { @@ -556,27 +535,20 @@ create_tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, goto cleanup; } - attrs = DNS_DISPATCHATTR_TCP; - if (isc_sockaddr_pf(destaddr) == AF_INET) { - attrs |= DNS_DISPATCHATTR_IPV4; - } else { - attrs |= DNS_DISPATCHATTR_IPV6; - } - isc_socket_dscp(sock, dscp); - result = dns_dispatch_createtcp( - requestmgr->dispatchmgr, sock, requestmgr->taskmgr, srcaddr, - destaddr, 4096, 32768, 32768, 16411, 16433, attrs, dispatchp); + result = dns_dispatch_createtcp(requestmgr->dispatchmgr, sock, + requestmgr->taskmgr, srcaddr, destaddr, + 0, dispatchp); + cleanup: isc_socket_detach(&sock); return (result); } static isc_result_t -find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, - const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) { +udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, + const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) { dns_dispatch_t *disp = NULL; - unsigned int attrs; if (srcaddr == NULL) { switch (isc_sockaddr_pf(destaddr)) { @@ -597,24 +569,10 @@ find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, dns_dispatch_attach(disp, dispatchp); return (ISC_R_SUCCESS); } - attrs = DNS_DISPATCHATTR_UDP; - switch (isc_sockaddr_pf(srcaddr)) { - case PF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; - break; - case PF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; - break; - - default: - return (ISC_R_NOTIMPLEMENTED); - } - - return (dns_dispatch_createudp(requestmgr->dispatchmgr, - requestmgr->socketmgr, - requestmgr->taskmgr, srcaddr, 32768, - 32768, 16411, 16433, attrs, dispatchp)); + return (dns_dispatch_createudp( + requestmgr->dispatchmgr, requestmgr->socketmgr, + requestmgr->taskmgr, srcaddr, 0, dispatchp)); } static isc_result_t @@ -624,12 +582,10 @@ get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr, isc_result_t result; if (tcp) { - result = create_tcp_dispatch(newtcp, requestmgr, srcaddr, - destaddr, dscp, connected, - dispatchp); + result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr, + dscp, connected, dispatchp); } else { - result = find_udp_dispatch(requestmgr, srcaddr, destaddr, - dispatchp); + result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp); } return (result); } @@ -760,7 +716,7 @@ again: goto cleanup; } - sock = req_getsocket(request); + sock = dns_dispatch_getentrysocket(request->dispentry); INSIST(sock != NULL); isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); @@ -931,7 +887,7 @@ use_tcp: if (result != ISC_R_SUCCESS) { goto cleanup; } - sock = req_getsocket(request); + sock = dns_dispatch_getentrysocket(request->dispentry); INSIST(sock != NULL); message->id = id; @@ -1240,12 +1196,6 @@ dns_request_destroy(dns_request_t **requestp) { /*** *** Private: request. ***/ - -static isc_socket_t * -req_getsocket(dns_request_t *request) { - return (dns_dispatch_getentrysocket(request->dispentry)); -} - static void req_connected(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 14f82f3a73..9a39175319 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2140,15 +2140,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, */ } else { if (have_addr) { - unsigned int attrs; - attrs = DNS_DISPATCHATTR_UDP; switch (isc_sockaddr_pf(&addr)) { case AF_INET: - attrs |= DNS_DISPATCHATTR_IPV4; dscp = dns_resolver_getquerydscp4(fctx->res); break; case AF_INET6: - attrs |= DNS_DISPATCHATTR_IPV6; dscp = dns_resolver_getquerydscp6(fctx->res); break; default: @@ -2157,8 +2153,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } result = dns_dispatch_createudp( res->dispatchmgr, res->socketmgr, res->taskmgr, - &addr, 20000, 32768, 16411, 16433, attrs, - &query->dispatch); + &addr, 0, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2941,7 +2936,6 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { bool retry = false; isc_interval_t interval; isc_result_t result; - unsigned int attrs; fetchctx_t *fctx; REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); @@ -2970,6 +2964,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } else { + int attrs = 0; + switch (sevent->result) { case ISC_R_SUCCESS: @@ -2997,20 +2993,11 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { * We are connected. Create a dispatcher and * send the query. */ - attrs = DNS_DISPATCHATTR_TCP | - DNS_DISPATCHATTR_PRIVATE | - DNS_DISPATCHATTR_CONNECTED; - if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == - AF_INET) { - attrs |= DNS_DISPATCHATTR_IPV4; - } else { - attrs |= DNS_DISPATCHATTR_IPV6; - } - + attrs = DNS_DISPATCHATTR_CONNECTED; result = dns_dispatch_createtcp( query->dispatchmgr, query->tcpsocket, - query->fctx->res->taskmgr, NULL, NULL, 4096, 2, - 1, 1, 3, attrs, &query->dispatch); + query->fctx->res->taskmgr, NULL, NULL, attrs, + &query->dispatch); /* * Regardless of whether dns_dispatch_create() diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index fb79fcf40b..aa92f4ed87 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -66,7 +66,6 @@ static isc_result_t make_dispatchset(unsigned int ndisps) { isc_result_t result; isc_sockaddr_t any; - unsigned int attrs; dns_dispatch_t *disp = NULL; result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); @@ -75,9 +74,8 @@ make_dispatchset(unsigned int ndisps) { } isc_sockaddr_any(&any); - attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &any, - 6, 1024, 17, 19, attrs, &disp); + 0, &disp); if (result != ISC_R_SUCCESS) { return (result); } @@ -258,7 +256,6 @@ dispatch_getnext(void **state) { uint16_t id; struct in_addr ina; unsigned char message[12]; - unsigned int attrs; unsigned char rbuf[12]; UNUSED(state); @@ -273,9 +270,8 @@ dispatch_getnext(void **state) { ina.s_addr = htonl(INADDR_LOOPBACK); isc_sockaddr_fromin(&local, &ina, 0); - attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP; result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, - 6, 1024, 17, 19, attrs, &dispatch); + 0, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); /* diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index 5b4b7e8b81..1a6e0f6143 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -58,7 +58,7 @@ _setup(void **state) { isc_sockaddr_any(&local); result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, - 100, 100, 100, 500, 0, &dispatch); + 0, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index ad6cf29603..23630bdaa5 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -225,12 +225,6 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, *\li #ISC_R_UNEXPECTED */ -isc_result_t -isc_socket_dup(isc_socket_t *sock0, isc_socket_t **socketp); -/*%< - * Duplicate an existing socket, reusing its file descriptor. - */ - void isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how); /*%< diff --git a/lib/isc/socket.c b/lib/isc/socket.c index 12d8c71550..c28b32165c 100644 --- a/lib/isc/socket.c +++ b/lib/isc/socket.c @@ -350,8 +350,8 @@ struct isc_socket { unsigned int listener : 1, /* listener socket */ connected : 1, connecting : 1, /* connect pending * */ - bound : 1, /* bound to local addr */ - dupped : 1, active : 1, /* currently active */ + bound : 1, /* bound to local addr */ + active : 1, /* currently active */ pktdscp : 1; /* per packet dscp */ #ifdef ISC_PLATFORM_RECVOVERFLOW @@ -434,7 +434,7 @@ struct isc__socketthread { static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, - isc_socket_t **socketp, isc_socket_t *dup_socket); + isc_socket_t **socketp); static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **); static void @@ -1881,7 +1881,6 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, sock->fd = -1; sock->threadid = -1; sock->dscp = 0; /* TOS/TCLASS is zero until set. */ - sock->dupped = 0; sock->statsindex = NULL; sock->active = 0; @@ -2123,8 +2122,7 @@ set_ip_disable_pmtud(isc_socket_t *sock) { } static isc_result_t -opensocket(isc_socketmgr_t *manager, isc_socket_t *sock, - isc_socket_t *dup_socket) { +opensocket(isc_socketmgr_t *manager, isc_socket_t *sock) { isc_result_t result; char strbuf[ISC_STRERRORSIZE]; const char *err = "socket"; @@ -2138,60 +2136,52 @@ opensocket(isc_socketmgr_t *manager, isc_socket_t *sock, #endif again: - if (dup_socket == NULL) { - switch (sock->type) { - case isc_sockettype_udp: - sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP); - break; - case isc_sockettype_tcp: - sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); - break; - case isc_sockettype_unix: - sock->fd = socket(sock->pf, SOCK_STREAM, 0); - break; - case isc_sockettype_raw: - errno = EPFNOSUPPORT; - /* - * PF_ROUTE is a alias for PF_NETLINK on linux. - */ + switch (sock->type) { + case isc_sockettype_udp: + sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP); + break; + case isc_sockettype_tcp: + sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); + break; + case isc_sockettype_unix: + sock->fd = socket(sock->pf, SOCK_STREAM, 0); + break; + case isc_sockettype_raw: + errno = EPFNOSUPPORT; + /* + * PF_ROUTE is a alias for PF_NETLINK on linux. + */ #if defined(PF_ROUTE) - if (sock->fd == -1 && sock->pf == PF_ROUTE) { + if (sock->fd == -1 && sock->pf == PF_ROUTE) { #ifdef NETLINK_ROUTE - sock->fd = socket(sock->pf, SOCK_RAW, - NETLINK_ROUTE); + sock->fd = socket(sock->pf, SOCK_RAW, NETLINK_ROUTE); #else /* ifdef NETLINK_ROUTE */ - sock->fd = socket(sock->pf, SOCK_RAW, 0); + sock->fd = socket(sock->pf, SOCK_RAW, 0); #endif /* ifdef NETLINK_ROUTE */ - if (sock->fd != -1) { + if (sock->fd != -1) { #ifdef NETLINK_ROUTE - struct sockaddr_nl sa; - int n; + struct sockaddr_nl sa; + int n; - /* - * Do an implicit bind. - */ - memset(&sa, 0, sizeof(sa)); - sa.nl_family = AF_NETLINK; - sa.nl_groups = RTMGRP_IPV4_IFADDR | - RTMGRP_IPV6_IFADDR; - n = bind(sock->fd, - (struct sockaddr *)&sa, - sizeof(sa)); - if (n < 0) { - close(sock->fd); - sock->fd = -1; - } -#endif /* ifdef NETLINK_ROUTE */ - sock->bound = 1; + /* + * Do an implicit bind. + */ + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + sa.nl_groups = RTMGRP_IPV4_IFADDR | + RTMGRP_IPV6_IFADDR; + n = bind(sock->fd, (struct sockaddr *)&sa, + sizeof(sa)); + if (n < 0) { + close(sock->fd); + sock->fd = -1; } +#endif /* ifdef NETLINK_ROUTE */ + sock->bound = 1; } -#endif /* if defined(PF_ROUTE) */ - break; } - } else { - sock->fd = dup(dup_socket->fd); - sock->dupped = 1; - sock->bound = dup_socket->bound; +#endif /* if defined(PF_ROUTE) */ + break; } if (sock->fd == -1 && errno == EINTR && tries++ < 42) { goto again; @@ -2268,10 +2258,6 @@ again: } } - if (dup_socket != NULL) { - goto setup_done; - } - result = make_nonblock(sock->fd); if (result != ISC_R_SUCCESS) { (void)close(sock->fd); @@ -2410,7 +2396,6 @@ again: set_ip_disable_pmtud(sock); -setup_done: inc_stats(manager->stats, sock->statsindex[STATID_OPEN]); if (sock->active == 0) { inc_stats(manager->stats, sock->statsindex[STATID_ACTIVE]); @@ -2421,14 +2406,13 @@ setup_done: } /* - * Create a 'type' socket or duplicate an existing socket, managed - * by 'manager'. Events will be posted to 'task' and when dispatched - * 'action' will be called with 'arg' as the arg value. The new - * socket is returned in 'socketp'. + * Create a 'type' socket, managed by 'manager'. Events will be posted to + * 'task' and when dispatched 'action' will be called with 'arg' as the arg + * value. The new socket is returned in 'socketp'. */ static isc_result_t socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, - isc_socket_t **socketp, isc_socket_t *dup_socket) { + isc_socket_t **socketp) { isc_socket_t *sock = NULL; isc__socketthread_t *thread; isc_result_t result; @@ -2466,7 +2450,7 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, sock->pf = pf; - result = opensocket(manager, sock, dup_socket); + result = opensocket(manager, sock); if (result != ISC_R_SUCCESS) { free_socket(&sock); return (result); @@ -2507,8 +2491,7 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #endif /* ifdef USE_SELECT */ UNLOCK(&manager->lock); - socket_log(sock, NULL, CREATION, - dup_socket != NULL ? "dupped" : "created"); + socket_log(sock, NULL, CREATION, "created"); return (ISC_R_SUCCESS); } @@ -2520,22 +2503,9 @@ socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, * in 'socketp'. */ isc_result_t -isc_socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, +isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, isc_socket_t **socketp) { - return (socket_create(manager0, pf, type, socketp, NULL)); -} - -/*% - * Duplicate an existing socket. The new socket is returned - * in 'socketp'. - */ -isc_result_t -isc_socket_dup(isc_socket_t *sock, isc_socket_t **socketp) { - REQUIRE(VALID_SOCKET(sock)); - REQUIRE(socketp != NULL && *socketp == NULL); - - return (socket_create(sock->manager, sock->pf, sock->type, socketp, - sock)); + return (socket_create(manager, pf, type, socketp)); } isc_result_t @@ -2551,7 +2521,7 @@ isc_socket_open(isc_socket_t *sock) { REQUIRE(sock->fd == -1); REQUIRE(sock->threadid == -1); - result = opensocket(sock->manager, sock, NULL); + result = opensocket(sock->manager, sock); UNLOCK(&sock->lock); @@ -2642,7 +2612,6 @@ isc_socket_close(isc_socket_t *sock) { sock->fd = -1; sock->threadid = -1; - sock->dupped = 0; memset(sock->name, 0, sizeof(sock->name)); sock->tag = NULL; sock->listener = 0; @@ -4334,7 +4303,6 @@ isc_socket_bind(isc_socket_t *sock, const isc_sockaddr_t *sockaddr, LOCK(&sock->lock); INSIST(!sock->bound); - INSIST(!sock->dupped); if (sock->pf != sockaddr->type.sa.sa_family) { UNLOCK(&sock->lock); @@ -5078,7 +5046,6 @@ isc_socket_ipv6only(isc_socket_t *sock, bool yes) { #endif /* if defined(IPV6_V6ONLY) */ REQUIRE(VALID_SOCKET(sock)); - INSIST(!sock->dupped); #ifdef IPV6_V6ONLY if (sock->pf == AF_INET6) { @@ -5151,10 +5118,6 @@ isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) { } #endif /* if !defined(IP_TOS) && !defined(IPV6_TCLASS) */ -#ifdef notyet - REQUIRE(!sock->dupped); -#endif /* ifdef notyet */ - setdscp(sock, dscp); } @@ -5200,8 +5163,7 @@ static void init_hasreuseport(void) { /* * SO_REUSEPORT works very differently on *BSD and on Linux (because why not). - * We only want to use it on Linux, if it's available. On BSD we want to dup() - * sockets instead of re-binding them. + * We only want to use it on Linux, if it's available. */ #if (defined(SO_REUSEPORT) && defined(__linux__)) || \ (defined(SO_REUSEPORT_LB) && defined(__FreeBSD_kernel__)) diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c index 285e3c86ab..a98fc11906 100644 --- a/lib/isc/tests/socket_test.c +++ b/lib/isc/tests/socket_test.c @@ -218,89 +218,6 @@ udp_sendto_test(void **state) { assert_string_equal(recvbuf, "Hello"); } -/* Test UDP sendto/recv with duplicated socket */ -static void -udp_dup_test(void **state) { - isc_result_t result; - isc_sockaddr_t addr1, addr2; - struct in_addr in; - char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; - completion_t completion; - isc_region_t r; - - UNUSED(state); - - in.s_addr = inet_addr("127.0.0.1"); - isc_sockaddr_fromin(&addr1, &in, 0); - isc_sockaddr_fromin(&addr2, &in, 0); - - result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_bind(s1, &addr1, 0); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_getsockname(s1, &addr1); - assert_int_equal(result, ISC_R_SUCCESS); - assert_true(isc_sockaddr_getport(&addr1) != 0); - - result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_bind(s2, &addr2, 0); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_socket_getsockname(s2, &addr2); - assert_int_equal(result, ISC_R_SUCCESS); - assert_true(isc_sockaddr_getport(&addr2) != 0); - - result = isc_socket_dup(s2, &s3); - assert_int_equal(result, ISC_R_SUCCESS); - - result = isc_task_create(taskmgr, 0, &test_task); - assert_int_equal(result, ISC_R_SUCCESS); - - snprintf(sendbuf, sizeof(sendbuf), "Hello"); - r.base = (void *)sendbuf; - r.length = strlen(sendbuf) + 1; - - completion_init(&completion); - result = isc_socket_sendto(s1, &r, test_task, event_done, &completion, - &addr2, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - - snprintf(sendbuf, sizeof(sendbuf), "World"); - r.base = (void *)sendbuf; - r.length = strlen(sendbuf) + 1; - - completion_init(&completion); - result = isc_socket_sendto(s1, &r, test_task, event_done, &completion, - &addr2, NULL); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - - r.base = (void *)recvbuf; - r.length = BUFSIZ; - completion_init(&completion); - result = isc_socket_recv(s2, &r, 1, test_task, event_done, &completion); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - assert_string_equal(recvbuf, "Hello"); - - r.base = (void *)recvbuf; - r.length = BUFSIZ; - completion_init(&completion); - result = isc_socket_recv(s3, &r, 1, test_task, event_done, &completion); - assert_int_equal(result, ISC_R_SUCCESS); - waitfor(&completion); - assert_true(atomic_load(&completion.done)); - assert_int_equal(completion.result, ISC_R_SUCCESS); - assert_string_equal(recvbuf, "World"); -} - /* Test UDP sendto/recv (IPv4) */ static void udp_dscp_v4_test(void **state) { @@ -787,8 +704,6 @@ main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(udp_sendto_test, _setup, _teardown), - cmocka_unit_test_setup_teardown(udp_dup_test, _setup, - _teardown), cmocka_unit_test_setup_teardown(tcp_dscp_v4_test, _setup, _teardown), cmocka_unit_test_setup_teardown(tcp_dscp_v6_test, _setup, From 4f30b679e7c561f73ff6824fbdea09521748a61b Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 18 Dec 2020 14:59:50 -0800 Subject: [PATCH 09/28] Creating TCP dispatch now creates/binds the socket Previously, creation of TCP dispatches differed from UDP in that a TCP dispatch was created to attach to an existing socket, whereas a UDP dispatch would be created in a vacuum and sockets would be opened on demand when a transaction was initiated. We are moving as much socket code as possible into the dispatch module, so that it can be replaced with a netmgr version as easily as possible. (This will also have the side effect of making TCP and UDP dispatches more similar.) As a step in that direction, this commit changes dns_dispatch_createtcp() so that it creates the TCP socket. --- lib/dns/dispatch.c | 178 +++++++++++++++------------------ lib/dns/include/dns/dispatch.h | 4 +- lib/dns/request.c | 31 +----- lib/dns/resolver.c | 128 +++++++----------------- 4 files changed, 125 insertions(+), 216 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index cbb84220ee..6cdd138a7a 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -631,6 +631,7 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, continue; } UNLOCK(&qid->lock); + result = open_socket(sockmgr, &localaddr, ISC_SOCKET_REUSEADDRESS, &sock); if (result == ISC_R_SUCCESS) { @@ -1652,8 +1653,9 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { /* * Allocate and set important limits. */ -static isc_result_t -dispatch_allocate(dns_dispatchmgr_t *mgr, dns_dispatch_t **dispp) { +static void +dispatch_allocate(dns_dispatchmgr_t *mgr, isc_sockettype_t type, int pf, + unsigned int attributes, dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); @@ -1668,18 +1670,50 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, dns_dispatch_t **dispp) { isc_refcount_increment0(&mgr->irefs); *disp = (dns_dispatch_t){ .mgr = mgr, + .socktype = type, .shutdown_why = ISC_R_UNEXPECTED }; isc_refcount_init(&disp->refcount, 1); ISC_LINK_INIT(disp, link); ISC_LIST_INIT(disp->activesockets); ISC_LIST_INIT(disp->inactivesockets); + switch (type) { + case isc_sockettype_tcp: + disp->attributes |= DNS_DISPATCHATTR_TCP; + break; + case isc_sockettype_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_mutex_init(&disp->lock); disp->failsafe_ev = allocate_devent(disp); disp->magic = DISPATCH_MAGIC; *dispp = disp; - return (ISC_R_SUCCESS); } /* @@ -1720,30 +1754,38 @@ dispatch_free(dns_dispatch_t **dispp) { } isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, const isc_sockaddr_t *destaddr, unsigned int attributes, - dns_dispatch_t **dispp) { + 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(isc_socket_gettype(sock) == isc_sockettype_tcp); - - attributes |= DNS_DISPATCHATTR_TCP; - attributes &= ~DNS_DISPATCHATTR_UDP; + REQUIRE(sockmgr != NULL); + REQUIRE(destaddr != NULL); LOCK(&mgr->lock); - result = dispatch_allocate(mgr, &disp); - if (result != ISC_R_SUCCESS) { - UNLOCK(&mgr->lock); - return (result); - } + pf = isc_sockaddr_pf(destaddr); + dispatch_allocate(mgr, isc_sockettype_tcp, pf, attributes, &disp); - disp->socktype = isc_sockettype_tcp; - isc_socket_attach(sock, &disp->socket); + 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; @@ -1752,6 +1794,26 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, goto cleanup; } + result = isc_socket_create(sockmgr, isc_sockaddr_pf(destaddr), + isc_sockettype_tcp, &disp->socket); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + if (localaddr == NULL) { + isc_sockaddr_anyofpf(&src, pf); + } else { + src = *localaddr; + isc_sockaddr_setport(&src, 0); + } + + result = isc_socket_bind(disp->socket, &src, 0); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + isc_socket_dscp(disp->socket, dscp); + disp->ctlevent = isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, destroy_disp, disp, sizeof(isc_event_t)); @@ -1761,48 +1823,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg); disp->tcpmsg_valid = 1; - if (destaddr == NULL) { - (void)isc_socket_getpeername(sock, &disp->peer); - attributes |= DNS_DISPATCHATTR_PRIVATE; - } else { - disp->peer = *destaddr; - } - - pf = isc_sockaddr_pf(&disp->peer); - - if (localaddr == NULL) { - if (destaddr != NULL) { - switch (pf) { - case AF_INET: - isc_sockaddr_any(&disp->local); - break; - case AF_INET6: - isc_sockaddr_any6(&disp->local); - break; - } - } else { - (void)isc_socket_getsockname(sock, &disp->local); - } - } else { - disp->local = *localaddr; - } - - switch (pf) { - case PF_INET: - attributes |= DNS_DISPATCHATTR_IPV4; - break; - - case PF_INET6: - attributes |= DNS_DISPATCHATTR_IPV6; - break; - - default: - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } - - disp->attributes = attributes; - /* * Append it to the dispatcher list. */ @@ -1908,6 +1928,7 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, disp = ISC_LIST_NEXT(disp, link); } UNLOCK(&mgr->lock); + return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); } @@ -1924,43 +1945,29 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, REQUIRE(taskmgr != NULL); REQUIRE(dispp != NULL && *dispp == NULL); - attributes |= DNS_DISPATCHATTR_UDP; - attributes &= ~DNS_DISPATCHATTR_TCP; - LOCK(&mgr->lock); result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, attributes, &disp); - if (result == ISC_R_SUCCESS) { *dispp = disp; } - UNLOCK(&mgr->lock); - return (ISC_R_SUCCESS); + + return (result); } 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) { - isc_result_t result; + 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; - /* - * dispatch_allocate() checks mgr for us. - */ - disp = NULL; - result = dispatch_allocate(mgr, &disp); - if (result != ISC_R_SUCCESS) { - return (result); - } - pf = isc_sockaddr_pf(localaddr); - - disp->socktype = isc_sockettype_udp; + dispatch_allocate(mgr, isc_sockettype_udp, pf, attributes, &disp); /* * For dispatches with a specified source address, we open a @@ -2014,25 +2021,6 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_mem_create(&disp->sepool); isc_mem_setname(disp->sepool, "disp_sepool"); - attributes &= ~DNS_DISPATCHATTR_TCP; - attributes |= DNS_DISPATCHATTR_UDP; - - switch (pf) { - case PF_INET: - attributes |= DNS_DISPATCHATTR_IPV4; - break; - - case PF_INET6: - attributes |= DNS_DISPATCHATTR_IPV6; - break; - - default: - result = ISC_R_NOTIMPLEMENTED; - goto kill_socket; - } - - disp->attributes = attributes; - /* * Append it to the dispatcher list. */ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index c9bdc42954..69e0d81c62 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -223,10 +223,10 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, */ isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, const isc_sockaddr_t *destaddr, unsigned int attributes, - dns_dispatch_t **dispp); + isc_dscp_t dscp, dns_dispatch_t **dispp); /*%< * Create a new dns_dispatch and attach it to the provided isc_socket_t. * diff --git a/lib/dns/request.c b/lib/dns/request.c index fed16798ee..960ff04d95 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -498,9 +498,6 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { isc_result_t result; - isc_socket_t *sock = NULL; - isc_sockaddr_t src; - isc_sockaddr_t bind_any; if (!newtcp) { result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, @@ -517,31 +514,9 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, } } - result = isc_socket_create(requestmgr->socketmgr, - isc_sockaddr_pf(destaddr), - isc_sockettype_tcp, &sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - if (srcaddr == NULL) { - isc_sockaddr_anyofpf(&bind_any, isc_sockaddr_pf(destaddr)); - result = isc_socket_bind(sock, &bind_any, 0); - } else { - src = *srcaddr; - isc_sockaddr_setport(&src, 0); - result = isc_socket_bind(sock, &src, 0); - } - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - isc_socket_dscp(sock, dscp); - result = dns_dispatch_createtcp(requestmgr->dispatchmgr, sock, - requestmgr->taskmgr, srcaddr, destaddr, - 0, dispatchp); - -cleanup: - isc_socket_detach(&sock); + result = dns_dispatch_createtcp( + requestmgr->dispatchmgr, requestmgr->socketmgr, + requestmgr->taskmgr, srcaddr, destaddr, 0, dscp, dispatchp); return (result); } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 9a39175319..5d156e5edc 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -228,7 +228,6 @@ typedef struct query { dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatch; dns_adbaddrinfo_t *addrinfo; - isc_socket_t *tcpsocket; isc_time_t start; dns_messageid_t id; dns_dispentry_t *dispentry; @@ -1200,7 +1199,7 @@ resquery_destroy(resquery_t **queryp) { *queryp = NULL; REQUIRE(!ISC_LINK_LINKED(query, link)); - INSIST(query->tcpsocket == NULL); + INSIST(query->dispatch == NULL); fctx = query->fctx; res = fctx->res; @@ -1245,13 +1244,13 @@ update_edns_stats(resquery_t *query) { static void fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, isc_time_t *finish, bool no_response, bool age_untried) { - fetchctx_t *fctx; - resquery_t *query; + fetchctx_t *fctx = NULL; + resquery_t *query = NULL; unsigned int rtt, rttms; unsigned int factor; - dns_adbfind_t *find; + dns_adbfind_t *find = NULL; + isc_socket_t *sock = NULL; dns_adbaddrinfo_t *addrinfo; - isc_socket_t *sock; isc_stdtime_t now; query = *queryp; @@ -1423,33 +1422,20 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, * only needs to worry about managing the connect and send events; * the dispatcher manages the recv events. */ - if (RESQUERY_CONNECTING(query)) { - /* - * Cancel the connect. - */ - if (query->tcpsocket != NULL) { - isc_socket_cancel(query->tcpsocket, NULL, - ISC_SOCKCANCEL_CONNECT); - } else if (query->dispentry != NULL) { - sock = dns_dispatch_getentrysocket(query->dispentry); - if (sock != NULL) { - isc_socket_cancel(sock, NULL, - ISC_SOCKCANCEL_CONNECT); - } - } + if (query->dispentry != NULL) { + sock = dns_dispatch_getentrysocket(query->dispentry); + } else { + sock = dns_dispatch_getsocket(query->dispatch); } - if (RESQUERY_SENDING(query)) { - /* - * Cancel the pending send. - */ - if (query->dispentry != NULL) { - sock = dns_dispatch_getentrysocket(query->dispentry); - } else { - sock = dns_dispatch_getsocket(query->dispatch); - } - if (sock != NULL) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); - } + + /* Cancel the connect. */ + if (sock != NULL && RESQUERY_CONNECTING(query)) { + isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); + } + + /* Cancel the pending send. */ + if (sock != NULL && RESQUERY_SENDING(query)) { + isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); } if (query->dispentry != NULL) { @@ -1829,19 +1815,12 @@ process_sendevent(resquery_t *query, isc_event_t *event) { bool destroy_query = false; bool retry = false; isc_result_t result; - fetchctx_t *fctx; + fetchctx_t *fctx = NULL; fctx = query->fctx; if (RESQUERY_CANCELED(query)) { if (query->sends == 0 && query->connects == 0) { - /* - * This query was canceled while the - * isc_socket_sendto/connect() was in progress. - */ - if (query->tcpsocket != NULL) { - isc_socket_detach(&query->tcpsocket); - } destroy_query = true; } } else { @@ -2007,10 +1986,10 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { static isc_result_t fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, unsigned int options) { - dns_resolver_t *res; - isc_task_t *task; + dns_resolver_t *res = NULL; + isc_task_t *task = NULL; isc_result_t result; - resquery_t *query; + resquery_t *query = NULL; isc_sockaddr_t addr; bool have_addr = false; unsigned int srtt; @@ -2123,21 +2102,12 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->dscp = dscp; } - result = isc_socket_create(res->socketmgr, pf, - isc_sockettype_tcp, - &query->tcpsocket); + result = dns_dispatch_createtcp( + res->dispatchmgr, res->socketmgr, res->taskmgr, &addr, + &addrinfo->sockaddr, 0, query->dscp, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } - - result = isc_socket_bind(query->tcpsocket, &addr, 0); - if (result != ISC_R_SUCCESS) { - goto cleanup_socket; - } - - /* - * A dispatch will be created once the connect succeeds. - */ } else { if (have_addr) { switch (isc_sockaddr_pf(&addr)) { @@ -2195,19 +2165,16 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->magic = QUERY_MAGIC; if ((query->options & DNS_FETCHOPT_TCP) != 0) { + isc_socket_t *sock = NULL; + /* * Connect to the remote server. - * - * XXXRTH Should we attach to the socket? */ - if (query->dscp != -1) { - isc_socket_dscp(query->tcpsocket, query->dscp); - } - result = isc_socket_connect(query->tcpsocket, - &addrinfo->sockaddr, task, + sock = dns_dispatch_getsocket(query->dispatch); + result = isc_socket_connect(sock, &addrinfo->sockaddr, task, resquery_connected, query); if (result != ISC_R_SUCCESS) { - goto cleanup_socket; + goto cleanup_dispatch; } query->connects++; QTRACE("connecting via TCP"); @@ -2244,9 +2211,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, return (ISC_R_SUCCESS); -cleanup_socket: - isc_socket_detach(&query->tcpsocket); - cleanup_dispatch: if (query->dispatch != NULL) { dns_dispatch_detach(&query->dispatch); @@ -2961,11 +2925,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { * This query was canceled while the connect() was in * progress. */ - isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } else { - int attrs = 0; - switch (sevent->result) { case ISC_R_SUCCESS: @@ -2989,27 +2950,16 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { fctx_done(fctx, result, __LINE__); break; } + /* - * We are connected. Create a dispatcher and + * We are connected. Update the dispatcher and * send the query. */ - attrs = DNS_DISPATCHATTR_CONNECTED; - result = dns_dispatch_createtcp( - query->dispatchmgr, query->tcpsocket, - query->fctx->res->taskmgr, NULL, NULL, attrs, - &query->dispatch); - - /* - * Regardless of whether dns_dispatch_create() - * succeeded or not, we don't need our reference - * to the socket anymore. - */ - isc_socket_detach(&query->tcpsocket); - - if (result == ISC_R_SUCCESS) { - result = resquery_send(query); - } + dns_dispatch_changeattributes( + query->dispatch, DNS_DISPATCHATTR_CONNECTED, + DNS_DISPATCHATTR_CONNECTED); + result = resquery_send(query); if (result != ISC_R_SUCCESS) { FCTXTRACE("query canceled: " "resquery_send() failed; responding"); @@ -3030,10 +2980,6 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { "no route to host; no response", sevent->result); - /* - * No route to remote. - */ - isc_socket_detach(&query->tcpsocket); /* * Do not query this server again in this fetch context * if the server is unavailable over TCP. @@ -3049,7 +2995,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { "unexpected event result; responding", sevent->result); - isc_socket_detach(&query->tcpsocket); + dns_dispatch_detach(&query->dispatch); fctx_cancelquery(&query, NULL, NULL, false, false); break; } From 2c7232d82f56e030956989cf49e06cd9d1f3ec1e Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 18 Dec 2020 17:21:00 -0800 Subject: [PATCH 10/28] Temporarily move dns_tcpmsg functionality into dispatch Continuing the effort to move all uses of the isc_socket API into dispatch.c, this commit removes the dns_tcpmsg module entirely, as dispatch was its only caller, and moves the parts of its functionality that were being used into the dispatch module. This code will be removed when we switch to using netmgr TCPDNS. --- bin/named/controlconf.c | 3 + lib/dns/Makefile.am | 2 - lib/dns/dispatch.c | 150 ++++++++++++++++++++-- lib/dns/include/dns/tcpmsg.h | 141 --------------------- lib/dns/tcpmsg.c | 234 ----------------------------------- lib/dns/xfrin.c | 1 - lib/ns/include/ns/client.h | 1 - util/copyrights | 2 - 8 files changed, 142 insertions(+), 392 deletions(-) delete mode 100644 lib/dns/include/dns/tcpmsg.h delete mode 100644 lib/dns/tcpmsg.c diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c index 3669cac1dc..caa1055877 100644 --- a/bin/named/controlconf.c +++ b/bin/named/controlconf.c @@ -1050,6 +1050,8 @@ update_listener(named_controls_t *cp, controllistener_t **listenerp, socktext, isc_result_totext(result)); } +#if 0 + /* XXX: no unix socket support yet */ if (result == ISC_R_SUCCESS && type == isc_socktype_unix) { uint32_t perm, owner, group; perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); @@ -1073,6 +1075,7 @@ update_listener(named_controls_t *cp, controllistener_t **listenerp, socktext); } } +#endif *listenerp = listener; } diff --git a/lib/dns/Makefile.am b/lib/dns/Makefile.am index 2bf55ecaf0..d724dbd45b 100644 --- a/lib/dns/Makefile.am +++ b/lib/dns/Makefile.am @@ -126,7 +126,6 @@ libdns_la_HEADERS = \ include/dns/soa.h \ include/dns/ssu.h \ include/dns/stats.h \ - include/dns/tcpmsg.h \ include/dns/time.h \ include/dns/timer.h \ include/dns/transport.h \ @@ -232,7 +231,6 @@ libdns_la_SOURCES = \ ssu.c \ ssu_external.c \ stats.c \ - tcpmsg.c \ time.c \ timer.c \ transport.c \ diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 6cdd138a7a..f021b71107 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -35,7 +35,6 @@ #include #include #include -#include #include typedef ISC_LIST(dns_dispentry_t) dns_displist_t; @@ -133,6 +132,18 @@ struct dispsocket { 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 @@ -176,7 +187,7 @@ struct dns_dispatch { unsigned int nsockets; unsigned int requests; /*%< how many requests we have */ unsigned int tcpbuffers; /*%< allocated buffers */ - dns_tcpmsg_t tcpmsg; /*%< for tcp streams */ + tcpmsg_t tcpmsg; }; #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') @@ -1123,7 +1134,7 @@ restart: static void tcp_recv(isc_task_t *task, isc_event_t *ev_in) { dns_dispatch_t *disp = ev_in->ev_arg; - dns_tcpmsg_t *tcpmsg = &disp->tcpmsg; + tcpmsg_t *tcpmsg = &disp->tcpmsg; dns_messageid_t id; isc_result_t dres; unsigned int flags; @@ -1206,13 +1217,13 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { } dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", - tcpmsg->result, tcpmsg->buffer.length, - tcpmsg->buffer.base); + tcpmsg->result, disp->tcpmsg.buffer.length, + disp->tcpmsg.buffer.base); /* * Peek into the buffer to see what we can see. */ - dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags); + dres = dns_message_peekheader(&disp->tcpmsg.buffer, &id, &flags); if (dres != ISC_R_SUCCESS) { dispatch_log(disp, LVL(10), "got garbage packet"); goto restart; @@ -1258,7 +1269,10 @@ 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. */ - dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer); + 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; @@ -1288,6 +1302,115 @@ restart: UNLOCK(&disp->lock); } +static void +recv_tcpmsg(isc_task_t *task, isc_event_t *ev_in) { + isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; + tcpmsg_t *tcpmsg = ev_in->ev_arg; + isc_event_t *dev = &tcpmsg->event; + + UNUSED(task); + + tcpmsg->address = ev->address; + + if (ev->result != ISC_R_SUCCESS) { + tcpmsg->result = ev->result; + goto send_and_free; + } + + tcpmsg->result = ISC_R_SUCCESS; + isc_buffer_add(&tcpmsg->buffer, ev->n); + +send_and_free: + isc_task_send(tcpmsg->task, &dev); + tcpmsg->task = NULL; + isc_event_free(&ev_in); +} + +static void +recv_tcplen(isc_task_t *task, isc_event_t *ev_in) { + isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; + tcpmsg_t *tcpmsg = ev_in->ev_arg; + isc_event_t *dev = &tcpmsg->event; + isc_region_t region; + isc_result_t result; + + tcpmsg->address = ev->address; + + if (ev->result != ISC_R_SUCCESS) { + tcpmsg->result = ev->result; + goto send_and_free; + } + + /* + * Success. + */ + tcpmsg->size = ntohs(tcpmsg->size); + if (tcpmsg->size == 0) { + tcpmsg->result = ISC_R_UNEXPECTEDEND; + goto send_and_free; + } + + region.base = isc_mem_get(tcpmsg->disp->mgr->mctx, tcpmsg->size); + region.length = tcpmsg->size; + if (region.base == NULL) { + tcpmsg->result = ISC_R_NOMEMORY; + goto send_and_free; + } + + isc_buffer_init(&tcpmsg->buffer, region.base, region.length); + result = isc_socket_recv(tcpmsg->disp->socket, ®ion, 0, task, + recv_tcpmsg, tcpmsg); + if (result != ISC_R_SUCCESS) { + tcpmsg->result = result; + goto send_and_free; + } + + isc_event_free(&ev_in); + return; + +send_and_free: + isc_task_send(tcpmsg->task, &dev); + tcpmsg->task = NULL; + isc_event_free(&ev_in); + return; +} + +static isc_result_t +tcp_readmessage(tcpmsg_t *tcpmsg, isc_task_t *task, isc_taskaction_t action, + void *arg) { + isc_result_t result; + isc_region_t region; + + REQUIRE(task != NULL); + REQUIRE(tcpmsg->task == NULL); /* not currently in use */ + + if (tcpmsg->buffer.base != NULL) { + isc_mem_put(tcpmsg->disp->mgr->mctx, tcpmsg->buffer.base, + tcpmsg->buffer.length); + tcpmsg->buffer.base = NULL; + tcpmsg->buffer.length = 0; + } + + tcpmsg->task = task; + tcpmsg->action = action; + tcpmsg->arg = arg; + tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */ + + ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0, + DNS_EVENT_TCPMSG, action, arg, tcpmsg, NULL, NULL); + + region.base = (unsigned char *)&tcpmsg->size; + region.length = 2; /* uint16_t */ + result = isc_socket_recv(tcpmsg->disp->socket, ®ion, 0, tcpmsg->task, + recv_tcplen, tcpmsg); + + if (result != ISC_R_SUCCESS) { + tcpmsg->task = NULL; + } + + return (result); +} + /* * disp must be locked. */ @@ -1333,8 +1456,8 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { break; case isc_sockettype_tcp: - res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0], - tcp_recv, disp); + res = tcp_readmessage(&disp->tcpmsg, disp->task[0], tcp_recv, + disp); if (res != ISC_R_SUCCESS) { disp->shutdown_why = res; disp->shutting_down = 1; @@ -1732,7 +1855,12 @@ dispatch_free(dns_dispatch_t **dispp) { REQUIRE(VALID_DISPATCHMGR(mgr)); if (disp->tcpmsg_valid) { - dns_tcpmsg_invalidate(&disp->tcpmsg); + 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; } @@ -1820,7 +1948,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_task_setname(disp->task[0], "tcpdispatch", disp); - dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg); + disp->tcpmsg = (tcpmsg_t){ .disp = disp, .result = ISC_R_UNEXPECTED }; disp->tcpmsg_valid = 1; /* diff --git a/lib/dns/include/dns/tcpmsg.h b/lib/dns/include/dns/tcpmsg.h deleted file mode 100644 index 375df60c7a..0000000000 --- a/lib/dns/include/dns/tcpmsg.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -#ifndef DNS_TCPMSG_H -#define DNS_TCPMSG_H 1 - -/*! \file dns/tcpmsg.h */ - -#include - -#include -#include -#include - -typedef struct dns_tcpmsg { - /* private (don't touch!) */ - unsigned int magic; - uint16_t size; - isc_buffer_t buffer; - unsigned int maxsize; - isc_mem_t * mctx; - isc_socket_t * sock; - isc_task_t * task; - isc_taskaction_t action; - void * arg; - isc_event_t event; - /* public (read-only) */ - isc_result_t result; - isc_sockaddr_t address; -} dns_tcpmsg_t; - -ISC_LANG_BEGINDECLS - -void -dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg); -/*%< - * Associate a tcp message state with a given memory context and - * TCP socket. - * - * Requires: - * - *\li "mctx" and "sock" be non-NULL and valid types. - * - *\li "sock" be a read/write TCP socket. - * - *\li "tcpmsg" be non-NULL and an uninitialized or invalidated structure. - * - * Ensures: - * - *\li "tcpmsg" is a valid structure. - */ - -void -dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize); -/*%< - * Set the maximum packet size to "maxsize" - * - * Requires: - * - *\li "tcpmsg" be valid. - * - *\li 512 <= "maxsize" <= 65536 - */ - -isc_result_t -dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, isc_task_t *task, - isc_taskaction_t action, void *arg); -/*%< - * Schedule an event to be delivered when a DNS message is readable, or - * when an error occurs on the socket. - * - * Requires: - * - *\li "tcpmsg" be valid. - * - *\li "task", "taskaction", and "arg" be valid. - * - * Returns: - * - *\li ISC_R_SUCCESS -- no error - *\li Anything that the isc_socket_recv() call can return. XXXMLG - * - * Notes: - * - *\li The event delivered is a fully generic event. It will contain no - * actual data. The sender will be a pointer to the dns_tcpmsg_t. - * The result code inside that structure should be checked to see - * what the final result was. - */ - -void -dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg); -/*%< - * Cancel a readmessage() call. The event will still be posted with a - * CANCELED result code. - * - * Requires: - * - *\li "tcpmsg" be valid. - */ - -void -dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer); -/*%< - * If a dns buffer is to be kept between calls, this function marks the - * internal state-machine buffer as invalid, and copies all the contents - * of the state into "buffer". - * - * Requires: - * - *\li "tcpmsg" be valid. - * - *\li "buffer" be non-NULL. - */ - -void -dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg); -/*%< - * Clean up all allocated state, and invalidate the structure. - * - * Requires: - * - *\li "tcpmsg" be valid. - * - * Ensures: - * - *\li "tcpmsg" is invalidated and disassociated with all memory contexts, - * sockets, etc. - */ - -ISC_LANG_ENDDECLS - -#endif /* DNS_TCPMSG_H */ diff --git a/lib/dns/tcpmsg.c b/lib/dns/tcpmsg.c deleted file mode 100644 index 47e1d2e19f..0000000000 --- a/lib/dns/tcpmsg.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -/*! \file */ - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef TCPMSG_DEBUG -#include /* Required for printf. */ -#define XDEBUG(x) printf x -#else /* ifdef TCPMSG_DEBUG */ -#define XDEBUG(x) -#endif /* ifdef TCPMSG_DEBUG */ - -#define TCPMSG_MAGIC ISC_MAGIC('T', 'C', 'P', 'm') -#define VALID_TCPMSG(foo) ISC_MAGIC_VALID(foo, TCPMSG_MAGIC) - -static void -recv_length(isc_task_t *, isc_event_t *); -static void -recv_message(isc_task_t *, isc_event_t *); - -static void -recv_length(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - isc_event_t *dev; - dns_tcpmsg_t *tcpmsg = ev_in->ev_arg; - isc_region_t region; - isc_result_t result; - - INSIST(VALID_TCPMSG(tcpmsg)); - - dev = &tcpmsg->event; - 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; - } - if (tcpmsg->size > tcpmsg->maxsize) { - tcpmsg->result = ISC_R_RANGE; - goto send_and_free; - } - - region.base = isc_mem_get(tcpmsg->mctx, tcpmsg->size); - region.length = tcpmsg->size; - if (region.base == NULL) { - tcpmsg->result = ISC_R_NOMEMORY; - goto send_and_free; - } - XDEBUG(("Allocated %d bytes\n", tcpmsg->size)); - - isc_buffer_init(&tcpmsg->buffer, region.base, region.length); - result = isc_socket_recv(tcpmsg->sock, ®ion, 0, task, recv_message, - 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 void -recv_message(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - isc_event_t *dev; - dns_tcpmsg_t *tcpmsg = ev_in->ev_arg; - - (void)task; - - INSIST(VALID_TCPMSG(tcpmsg)); - - dev = &tcpmsg->event; - 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); - - XDEBUG(("Received %u bytes (of %d)\n", ev->n, tcpmsg->size)); - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); -} - -void -dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg) { - REQUIRE(mctx != NULL); - REQUIRE(sock != NULL); - REQUIRE(tcpmsg != NULL); - - tcpmsg->magic = TCPMSG_MAGIC; - tcpmsg->size = 0; - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - tcpmsg->maxsize = 65535; /* Largest message possible. */ - tcpmsg->mctx = mctx; - tcpmsg->sock = sock; - tcpmsg->task = NULL; /* None yet. */ - tcpmsg->result = ISC_R_UNEXPECTED; /* None yet. */ - - /* Should probably initialize the event here, but it can wait. */ -} - -void -dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - REQUIRE(maxsize < 65536); - - tcpmsg->maxsize = maxsize; -} - -isc_result_t -dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, isc_task_t *task, - isc_taskaction_t action, void *arg) { - isc_result_t result; - isc_region_t region; - - REQUIRE(VALID_TCPMSG(tcpmsg)); - REQUIRE(task != NULL); - REQUIRE(tcpmsg->task == NULL); /* not currently in use */ - - if (tcpmsg->buffer.base != NULL) { - isc_mem_put(tcpmsg->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->sock, ®ion, 0, tcpmsg->task, - recv_length, tcpmsg); - - if (result != ISC_R_SUCCESS) { - tcpmsg->task = NULL; - } - - return (result); -} - -void -dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - - isc_socket_cancel(tcpmsg->sock, NULL, ISC_SOCKCANCEL_RECV); -} - -void -dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - REQUIRE(buffer != NULL); - - *buffer = tcpmsg->buffer; - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; -} - -#if 0 -void -dns_tcpmsg_freebuffer(dns_tcpmsg_t *tcpmsg) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - - if (tcpmsg->buffer.base == NULL) { - return; - } - - isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; -} -#endif /* if 0 */ - -void -dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg) { - REQUIRE(VALID_TCPMSG(tcpmsg)); - - tcpmsg->magic = 0; - - if (tcpmsg->buffer.base != NULL) { - isc_mem_put(tcpmsg->mctx, tcpmsg->buffer.base, - tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - } -} diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 0d2930506b..fe3b233a0f 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index a99835bd4e..c734358dcd 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -70,7 +70,6 @@ #include #include #include -#include #include #include diff --git a/util/copyrights b/util/copyrights index 0e24a2361d..dff5713217 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1231,7 +1231,6 @@ ./lib/dns/include/dns/soa.h C 2000,2001,2004,2005,2006,2007,2009,2016,2018,2019,2020,2021 ./lib/dns/include/dns/ssu.h C 2000,2001,2003,2004,2005,2006,2007,2008,2010,2011,2016,2017,2018,2019,2020,2021 ./lib/dns/include/dns/stats.h C 2000,2001,2004,2005,2006,2007,2008,2009,2012,2014,2015,2016,2017,2018,2019,2020,2021 -./lib/dns/include/dns/tcpmsg.h C 1999,2000,2001,2004,2005,2006,2007,2015,2016,2018,2019,2020,2021 ./lib/dns/include/dns/time.h C 1999,2000,2001,2004,2005,2006,2007,2012,2016,2018,2019,2020,2021 ./lib/dns/include/dns/timer.h C 2000,2001,2004,2005,2006,2007,2016,2018,2019,2020,2021 ./lib/dns/include/dns/tkey.h C 1999,2000,2001,2004,2005,2006,2007,2009,2010,2011,2016,2018,2019,2020,2021 @@ -1471,7 +1470,6 @@ ./lib/dns/ssu.c C 2000,2001,2003,2004,2005,2006,2007,2008,2010,2011,2013,2014,2016,2017,2018,2019,2020,2021 ./lib/dns/ssu_external.c C 2011,2012,2013,2016,2017,2018,2019,2020,2021 ./lib/dns/stats.c C 2000,2001,2004,2005,2007,2008,2009,2012,2016,2018,2019,2020,2021 -./lib/dns/tcpmsg.c C 1999,2000,2001,2004,2005,2006,2007,2015,2016,2018,2019,2020,2021 ./lib/dns/tests/Kdh.+002+18602.key X 2014,2018,2019,2020,2021 ./lib/dns/tests/Krsa.+005+29235.key X 2016,2018,2019,2020,2021 ./lib/dns/tests/acl_test.c C 2016,2018,2019,2020,2021 From 9f9a327b223c4b3f31d17c41cae8e9e6f9639095 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sat, 19 Dec 2020 01:34:41 -0800 Subject: [PATCH 11/28] Move isc_socket_connect() calls into dispatch dns_dispatch_connect() connects a dispatch socket (for TCP) or a dispatch entry socket (for UDP). This is the next step in moving all uses of the isc_socket code into the dispatch module. This API is temporary; it needs to be cleaned up further so that it can be called the same way for both TCP and UDP. --- lib/dns/dispatch.c | 38 +++++++++++++++++++-------------- lib/dns/include/dns/dispatch.h | 12 +++++++++++ lib/dns/request.c | 8 +++---- lib/dns/resolver.c | 39 ++++++++++++---------------------- lib/dns/xfrin.c | 2 +- 5 files changed, 53 insertions(+), 46 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index f021b71107..2f65f7d4c7 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -71,22 +71,6 @@ struct dns_dispatchmgr { isc_refcount_t irefs; - /*% - * Locked by qid->lock if qid exists; otherwise, can be used without - * being locked. - * - * Memory footprint considerations: this is a simple implementation of - * available ports, i.e., an ordered array of the actual port numbers. - * This will require about 256KB of memory in the worst case (128KB for - * each of IPv4 and IPv6). We could reduce it by representing it as a - * more sophisticated way such as a list (or array) of ranges that are - * searched to identify a specific port. Our decision here is the saved - * memory isn't worth the implementation complexity, considering the - * fact that the whole BIND9 process (which is mainly named) already - * requires a pretty large memory footprint. We may, however, have to - * revisit the decision when we want to use it as a separate module for - * an environment where memory requirement is severer. - */ in_port_t *v4ports; /*%< available ports for IPv4 */ unsigned int nv4ports; /*%< # of available ports for IPv4 */ in_port_t *v6ports; /*%< available ports for IPv4 */ @@ -2591,6 +2575,28 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, } } +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; + + 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 { + INSIST(0); + ISC_UNREACHABLE(); + } + + return (isc_socket_connect(sock, address, task, action, arg)); +} + /* * disp must be locked. */ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 69e0d81c62..2854a7bcb6 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -264,6 +264,18 @@ dns_dispatch_detach(dns_dispatch_t **dispp); *\li dispp != NULL and *dispp be a valid dispatch. */ +isc_result_t +dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, + isc_task_t *task, isc_taskaction_t action, void *arg); +/*%< + * Connect the UDP socket in 'resp' or the TCP socket in 'disp' to the + * remote server, and run the specified callback. + * + * Requires: + *\li 'resp' is NULL and 'disp' is valid, or + *\li 'disp' is NULL and 'resp' is valid. + */ + void dns_dispatch_starttcp(dns_dispatch_t *disp); /*%< diff --git a/lib/dns/request.c b/lib/dns/request.c index 960ff04d95..1a16f2d0e5 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -729,8 +729,8 @@ again: request->destaddr = *destaddr; if (tcp && !connected) { - result = isc_socket_connect(sock, destaddr, task, req_connected, - request); + result = dns_dispatch_connect(request->dispatch, NULL, task, + req_connected, request); if (result != ISC_R_SUCCESS) { goto unlink; } @@ -912,8 +912,8 @@ use_tcp: request->destaddr = *destaddr; if (tcp && !connected) { - result = isc_socket_connect(sock, destaddr, task, req_connected, - request); + result = dns_dispatch_connect(request->dispatch, NULL, task, + req_connected, request); if (result != ISC_R_SUCCESS) { goto unlink; } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 5d156e5edc..59079b0c5f 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2165,14 +2165,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->magic = QUERY_MAGIC; if ((query->options & DNS_FETCHOPT_TCP) != 0) { - isc_socket_t *sock = NULL; - /* * Connect to the remote server. */ - sock = dns_dispatch_getsocket(query->dispatch); - result = isc_socket_connect(sock, &addrinfo->sockaddr, task, - resquery_connected, query); + result = dns_dispatch_connect(query->dispatch, NULL, task, + resquery_connected, query); if (result != ISC_R_SUCCESS) { goto cleanup_dispatch; } @@ -2314,11 +2311,6 @@ addr2buf(void *buf, const size_t bufsize, const isc_sockaddr_t *sockaddr) { return (0); } -static inline isc_socket_t * -query2sock(const resquery_t *query) { - return (dns_dispatch_getentrysocket(query->dispentry)); -} - static inline size_t add_serveraddr(uint8_t *buf, const size_t bufsize, const resquery_t *query) { return (addr2buf(buf, bufsize, &query->addrinfo->sockaddr)); @@ -2371,17 +2363,17 @@ 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; + fetchctx_t *fctx = NULL; isc_result_t result; dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_region_t r; - dns_resolver_t *res; + dns_resolver_t *res = NULL; isc_task_t *task; isc_socket_t *sock; isc_buffer_t tcpbuffer; - isc_sockaddr_t *address; - isc_buffer_t *buffer; + isc_sockaddr_t *address = NULL; + isc_buffer_t *buffer = NULL; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; dns_peer_t *peer = NULL; @@ -2406,7 +2398,6 @@ resquery_send(resquery_t *query) { res = fctx->res; task = res->buckets[fctx->bucketnum].task; - address = NULL; if (tcp) { /* @@ -2805,22 +2796,20 @@ resquery_send(resquery_t *query) { */ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER); - sock = query2sock(query); - - /* - * Send the query! - */ if (!tcp) { - address = &query->addrinfo->sockaddr; - result = isc_socket_connect(sock, address, task, - resquery_udpconnected, query); + /* 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); + sock = dns_dispatch_getentrysocket(query->dispentry); + /* * XXXRTH Make sure we don't send to ourselves! We should probably * prune out these addresses when we get them from the ADB. @@ -2841,6 +2830,7 @@ resquery_send(resquery_t *query) { } } + address = tcp ? NULL : &query->addrinfo->sockaddr; result = isc_socket_sendto2(sock, &r, task, address, NULL, &query->sendevent, 0); INSIST(result == ISC_R_SUCCESS); @@ -9848,8 +9838,7 @@ rctx_logpacket(respctx_t *rctx) { dtmsgtype = DNS_DTTYPE_RR; } - sock = query2sock(rctx->query); - + sock = dns_dispatch_getentrysocket(rctx->query); if (sock != NULL) { result = isc_socket_getsockname(sock, &localaddr); if (result == ISC_R_SUCCESS) { diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index fe3b233a0f..0dc3088397 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -956,7 +956,6 @@ xfrin_start(dns_xfrin_ctx_t *xfr) { ISC_UNREACHABLE(); } - /* TODO isc_socket_dscp(xfr->socket, xfr->dscp); */ return (ISC_R_SUCCESS); failure: @@ -1035,6 +1034,7 @@ xfrin_connect_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { xfr->handle = handle; sockaddr = isc_nmhandle_peeraddr(handle); isc_sockaddr_format(&sockaddr, sourcetext, sizeof(sourcetext)); + /* TODO set DSCP */ if (xfr->tsigkey != NULL && xfr->tsigkey->key != NULL) { dns_name_format(dst_key_name(xfr->tsigkey->key), signerbuf, From 655e7fcacc07dd4f2df3a2afe11b2ca0c751a82c Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 4 Jan 2021 14:38:35 -0800 Subject: [PATCH 12/28] Move isc_socket_getsockname() calls into dispatch We now use dns_dispentry_getlocaladdress(). (this API is likely to be cleaned up further later.) --- lib/dns/dispatch.c | 17 +++++++++++++++++ lib/dns/include/dns/dispatch.h | 16 +++++++++++++++- lib/dns/resolver.c | 15 ++++++--------- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 2f65f7d4c7..24cb01fe6a 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -2678,6 +2678,23 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) { return (ISC_R_NOTIMPLEMENTED); } +isc_result_t +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->dispsocket != NULL) { + return (isc_socket_getsockname(resp->dispsocket->socket, + addrp)); + } + + return (ISC_R_NOTIMPLEMENTED); +} + unsigned int dns_dispatch_getattributes(dns_dispatch_t *disp) { REQUIRE(VALID_DISPATCH(disp)); diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 2854a7bcb6..7ce569111b 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -374,7 +374,21 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); * * Requires: *\li disp is valid. - *\li addrp to be non null. + *\li addrp to be non NULL. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp); +/*%< + * Return the local address for this dispatch entry. + * + * Requires: + *\li resp is valid. + *\li addrp to be non NULL. * * Returns: *\li ISC_R_SUCCESS diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 59079b0c5f..c011dabae7 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2370,7 +2370,7 @@ resquery_send(resquery_t *query) { isc_region_t r; dns_resolver_t *res = NULL; isc_task_t *task; - isc_socket_t *sock; + isc_socket_t *sock = NULL; isc_buffer_t tcpbuffer; isc_sockaddr_t *address = NULL; isc_buffer_t *buffer = NULL; @@ -2849,7 +2849,7 @@ resquery_send(resquery_t *query) { dtmsgtype = DNS_DTTYPE_RQ; } - result = isc_socket_getsockname(sock, &localaddr); + result = dns_dispentry_getlocaladdress(query->dispentry, &localaddr); if (result == ISC_R_SUCCESS) { la = &localaddr; } @@ -9801,7 +9801,6 @@ rctx_logpacket(respctx_t *rctx) { #ifdef HAVE_DNSTAP isc_result_t result; fetchctx_t *fctx = rctx->fctx; - isc_socket_t *sock = NULL; isc_sockaddr_t localaddr, *la = NULL; unsigned char zone[DNS_NAME_MAXWIRE]; dns_dtmsgtype_t dtmsgtype; @@ -9838,12 +9837,10 @@ rctx_logpacket(respctx_t *rctx) { dtmsgtype = DNS_DTTYPE_RR; } - sock = dns_dispatch_getentrysocket(rctx->query); - if (sock != NULL) { - result = isc_socket_getsockname(sock, &localaddr); - if (result == ISC_R_SUCCESS) { - la = &localaddr; - } + result = dns_dispentry_getlocaladdress(rctx->query->dispentry, + &localaddr); + if (result == ISC_R_SUCCESS) { + la = &localaddr; } dns_dt_send(fctx->res->view, dtmsgtype, la, From 2523be1cbebc366dc6bc8401e0e51fde0758cc51 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 4 Jan 2021 23:03:50 -0800 Subject: [PATCH 13/28] Move isc_socket_sendto2() calls into dispatch We now use dns_dispatch_send() for this purpose. --- lib/dns/dispatch.c | 40 ++++++++++++++++++++++++++++++++-- lib/dns/include/dns/dispatch.h | 14 ++++++++++++ lib/dns/request.c | 31 ++++++-------------------- lib/dns/resolver.c | 34 +++++------------------------ 4 files changed, 64 insertions(+), 55 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 24cb01fe6a..fcc43995b7 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -163,8 +163,8 @@ struct dns_dispatch { unsigned int attributes; isc_refcount_t refcount; dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ - unsigned int shutting_down : 1, shutdown_out : 1, connected : 1, - tcpmsg_valid : 1, recv_pending : 1; + unsigned int shutting_down : 1, shutdown_out : 1, recv_pending : 1, + tcpmsg_valid : 1; isc_result_t shutdown_why; ISC_LIST(dispsocket_t) activesockets; ISC_LIST(dispsocket_t) inactivesockets; @@ -2597,6 +2597,42 @@ dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, return (isc_socket_connect(sock, address, task, action, 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; + + 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); + + sock = dns_dispatch_getentrysocket(resp); + + if (dscp == -1) { + sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; + sendevent->dscp = 0; + } else { + sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; + sendevent->dscp = dscp; + if (tcp) { + isc_socket_dscp(sock, dscp); + } + } + + if (tcp) { + address = NULL; + } + + result = isc_socket_sendto2(sock, r, task, address, NULL, sendevent, 0); + return (result); +} + /* * disp must be locked. */ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 7ce569111b..180e17997a 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -276,6 +276,20 @@ dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, *\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); +/*%< + * 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. + * + * Requires: + *\li 'resp' is valid. + */ + void dns_dispatch_starttcp(dns_dispatch_t *disp); /*%< diff --git a/lib/dns/request.c b/lib/dns/request.c index 1a16f2d0e5..79c6b6147d 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -78,6 +78,7 @@ struct dns_request { dns_requestmgr_t *requestmgr; isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; + isc_socketevent_t sendevent; isc_event_t ctlevent; bool canceling; /* ctlevent outstanding */ isc_sockaddr_t destaddr; @@ -412,40 +413,22 @@ mgr_gethash(dns_requestmgr_t *requestmgr) { static inline isc_result_t req_send(dns_request_t *request, isc_task_t *task, const isc_sockaddr_t *address) { - isc_region_t r; - isc_socket_t *sock = NULL; - isc_socketevent_t *sendevent = NULL; isc_result_t result; + isc_region_t r; + bool tcp; req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); REQUIRE(VALID_REQUEST(request)); - sock = dns_dispatch_getentrysocket(request->dispentry); isc_buffer_usedregion(request->query, &r); - /* - * We could connect the socket when we are using an exclusive dispatch - * as we do in resolver.c, but we prefer implementation simplicity - * at this moment. - */ - sendevent = isc_socket_socketevent(request->mctx, sock, - ISC_SOCKEVENT_SENDDONE, req_senddone, - request); - if (sendevent == NULL) { - return (ISC_R_NOMEMORY); - } - if (request->dscp == -1) { - sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; - sendevent->dscp = 0; - } else { - sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; - sendevent->dscp = request->dscp; - } + tcp = dns_request_usedtcp(request); request->flags |= DNS_REQUEST_F_SENDING; - result = isc_socket_sendto2(sock, &r, task, address, NULL, sendevent, - 0); + result = dns_dispatch_send(request->dispentry, tcp, task, + &request->sendevent, &r, address, + request->dscp, req_senddone, request); INSIST(result == ISC_R_SUCCESS); return (result); } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index c011dabae7..269cff7d2b 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2369,10 +2369,8 @@ resquery_send(resquery_t *query) { dns_rdataset_t *qrdataset = NULL; isc_region_t r; dns_resolver_t *res = NULL; - isc_task_t *task; - isc_socket_t *sock = NULL; + isc_task_t *task = NULL; isc_buffer_t tcpbuffer; - isc_sockaddr_t *address = NULL; isc_buffer_t *buffer = NULL; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; @@ -2808,33 +2806,11 @@ resquery_send(resquery_t *query) { isc_buffer_usedregion(buffer, &r); - sock = dns_dispatch_getentrysocket(query->dispentry); - - /* - * XXXRTH Make sure we don't send to ourselves! We should probably - * prune out these addresses when we get them from the ADB. - */ - memset(&query->sendevent, 0, sizeof(query->sendevent)); - ISC_EVENT_INIT(&query->sendevent, sizeof(query->sendevent), 0, NULL, - ISC_SOCKEVENT_SENDDONE, resquery_senddone, query, NULL, - NULL, NULL); - - if (query->dscp == -1) { - query->sendevent.attributes &= ~ISC_SOCKEVENTATTR_DSCP; - query->sendevent.dscp = 0; - } else { - query->sendevent.attributes |= ISC_SOCKEVENTATTR_DSCP; - query->sendevent.dscp = query->dscp; - if (tcp) { - isc_socket_dscp(sock, query->dscp); - } - } - - address = tcp ? NULL : &query->addrinfo->sockaddr; - result = isc_socket_sendto2(sock, &r, task, address, NULL, - &query->sendevent, 0); + result = dns_dispatch_send(query->dispentry, tcp, task, + &query->sendevent, &r, + &query->addrinfo->sockaddr, query->dscp, + resquery_senddone, query); INSIST(result == ISC_R_SUCCESS); - query->sends++; QTRACE("sent"); From e76a7f764e2ab8b0db98d434fdc6293d3688796a Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 4 Jan 2021 23:51:07 -0800 Subject: [PATCH 14/28] Move isc_socket_cancel() calls into dispatch We now use dns_dispatch_cancel() for this purpose. NOTE: The caller still has to track whether there are pending send or connect events in the dispatch or dispatch entry; later this should be moved into the dispatch module as well. Also removed some public dns_dispatch_*() API calls that are no longer used outside dispatch itself. --- lib/dns/dispatch.c | 45 ++++++++++++++++++++++++++++++---- lib/dns/include/dns/dispatch.h | 27 +++++++++----------- lib/dns/request.c | 24 +++--------------- lib/dns/resolver.c | 28 ++++++--------------- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index fcc43995b7..e8f78d5550 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -302,6 +302,10 @@ 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); #define LVL(x) ISC_LOG_DEBUG(x) @@ -2612,7 +2616,7 @@ dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, ISC_EVENT_INIT(sendevent, sizeof(isc_socketevent_t), 0, NULL, ISC_SOCKEVENT_SENDDONE, action, arg, NULL, NULL, NULL); - sock = dns_dispatch_getentrysocket(resp); + sock = getentrysocket(resp); if (dscp == -1) { sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; @@ -2633,6 +2637,37 @@ dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, return (result); } +void +dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, + bool connecting) { + isc_socket_t *sock = NULL; + + REQUIRE(disp != NULL || resp != NULL); + + if (resp != NULL) { + REQUIRE(VALID_RESPONSE(resp)); + sock = getentrysocket(resp); + } else if (disp != NULL) { + REQUIRE(VALID_DISPATCH(disp)); + sock = getsocket(disp); + } else { + INSIST(0); + ISC_UNREACHABLE(); + } + + if (sock == NULL) { + return; + } + + if (connecting) { + isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); + } + + if (sending) { + isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); + } +} + /* * disp must be locked. */ @@ -2682,15 +2717,15 @@ unlock: UNLOCK(&qid->lock); } -isc_socket_t * -dns_dispatch_getsocket(dns_dispatch_t *disp) { +static isc_socket_t * +getsocket(dns_dispatch_t *disp) { REQUIRE(VALID_DISPATCH(disp)); return (disp->socket); } -isc_socket_t * -dns_dispatch_getentrysocket(dns_dispentry_t *resp) { +static isc_socket_t * +getentrysocket(dns_dispentry_t *resp) { REQUIRE(VALID_RESPONSE(resp)); if (resp->disp->socktype == isc_sockettype_tcp) { diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 180e17997a..0ff11844ff 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -276,6 +276,18 @@ dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, *\li 'disp' is NULL and 'resp' is valid. */ +void +dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, + bool connecting); +/*%< + * Cancel pending sends (if 'sending' is true) and connects (if + * 'connecting' is true) in 'resp' or 'disp'. + * + * Requires: + *\li 'resp' is NULL and 'disp' is valid, or + *\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, @@ -365,21 +377,6 @@ dns_dispatch_removeresponse(dns_dispentry_t ** resp, * argument to dns_dispatch_addresponse() when allocating '*resp'. */ -isc_socket_t * -dns_dispatch_getentrysocket(dns_dispentry_t *resp); - -isc_socket_t * -dns_dispatch_getsocket(dns_dispatch_t *disp); -/*%< - * Return the socket associated with dispatcher or dispatch entry. - * - * Requires: - *\li disp is valid. - * - * Returns: - *\li The socket the dispatcher is using. - */ - isc_result_t dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); /*%< diff --git a/lib/dns/request.c b/lib/dns/request.c index 79c6b6147d..367a716d20 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -577,7 +577,6 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; - isc_socket_t *sock = NULL; isc_result_t result; isc_mem_t *mctx; dns_messageid_t id; @@ -674,9 +673,6 @@ again: goto cleanup; } - sock = dns_dispatch_getentrysocket(request->dispentry); - INSIST(sock != NULL); - isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); if (tcp) { isc_buffer_putuint16(request->query, (uint16_t)r.length); @@ -766,7 +762,6 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; - isc_socket_t *sock = NULL; isc_result_t result; isc_mem_t *mctx; dns_messageid_t id; @@ -845,8 +840,6 @@ use_tcp: if (result != ISC_R_SUCCESS) { goto cleanup; } - sock = dns_dispatch_getentrysocket(request->dispentry); - INSIST(sock != NULL); message->id = id; if (settsigkey) { @@ -863,7 +856,6 @@ use_tcp: dns_message_renderreset(message); dns_dispatch_removeresponse(&request->dispentry, NULL); dns_dispatch_detach(&request->dispatch); - sock = NULL; options |= DNS_REQUESTOPT_TCP; settsigkey = false; goto use_tcp; @@ -1358,8 +1350,6 @@ req_destroy(dns_request_t *request) { */ static void req_cancel(dns_request_t *request) { - isc_socket_t *sock = NULL; - REQUIRE(VALID_REQUEST(request)); req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request); @@ -1373,18 +1363,10 @@ req_cancel(dns_request_t *request) { isc_timer_detach(&request->timer); } - if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) { - if (request->dispentry != NULL) { - sock = dns_dispatch_getentrysocket(request->dispentry); - } - if (DNS_REQUEST_CONNECTING(request) && sock != NULL) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); - } - if (DNS_REQUEST_SENDING(request) && sock != NULL) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); - } - } if (request->dispentry != NULL) { + dns_dispatch_cancel(NULL, request->dispentry, + DNS_REQUEST_SENDING(request), + DNS_REQUEST_CONNECTING(request)); dns_dispatch_removeresponse(&request->dispentry, NULL); } dns_dispatch_detach(&request->dispatch); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 269cff7d2b..febec16482 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -1249,7 +1248,6 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, unsigned int rtt, rttms; unsigned int factor; dns_adbfind_t *find = NULL; - isc_socket_t *sock = NULL; dns_adbaddrinfo_t *addrinfo; isc_stdtime_t now; @@ -1418,26 +1416,14 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, /* * Check for any outstanding socket events. If they exist, cancel - * them and let the event handlers finish the cleanup. The resolver - * only needs to worry about managing the connect and send events; - * the dispatcher manages the recv events. + * them and let the event handlers finish the cleanup. (XXX: + * Currently the resolver, rather than dispatch, tracks whether + * it's sending or connecting; this will be moved into dispatch + * later.) */ - if (query->dispentry != NULL) { - sock = dns_dispatch_getentrysocket(query->dispentry); - } else { - sock = dns_dispatch_getsocket(query->dispatch); - } - - /* Cancel the connect. */ - if (sock != NULL && RESQUERY_CONNECTING(query)) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); - } - - /* Cancel the pending send. */ - if (sock != NULL && RESQUERY_SENDING(query)) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); - } - + dns_dispatch_cancel(query->dispatch, query->dispentry, + RESQUERY_SENDING(query), + RESQUERY_CONNECTING(query)); if (query->dispentry != NULL) { dns_dispatch_removeresponse(&query->dispentry, deventp); } From d9e1ad9e37f7941dff0b19c18ea64cfd7d842467 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 25 Jan 2021 13:14:14 -0800 Subject: [PATCH 15/28] Remove reference count REQUIRE in isc_nm_read() Previously isc_nm_read() required references on the handle to be at least 2, under the assumption that it would only ever be called from a connect or accept callback. however, it can also be called from a read callback, in which case the reference count might be only 1. --- lib/isc/netmgr/netmgr.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 6f10061fcd..c5f24e5150 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -2527,13 +2527,6 @@ void isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(VALID_NMHANDLE(handle)); - /* - * This is always called via callback (from accept or connect), and - * caller must attach to the handle, so the references always need to be - * at least 2. - */ - REQUIRE(isc_refcount_current(&handle->references) >= 2); - switch (handle->sock->type) { case isc_nm_udpsocket: isc__nm_udp_read(handle, cb, cbarg); From 9ee60e7a17bf34c7ef7f4d79e6a00ca45444ec8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Mon, 26 Jul 2021 13:14:41 +0200 Subject: [PATCH 16/28] netmgr fixes needed for dispatch - The read timer must always be stopped when reading stops. - Read callbacks can now call isc_nm_read() again in TCP, TCPDNS and TLSDNS; previously this caused an assertion. - The wrong failure code could be sent after a UDP recv failure because the if statements were in the wrong order. the check for a NULL address needs to be after the check for an error code, otherwise the result will always be set to ISC_R_EOF. - When aborting a read or connect because the netmgr is shutting down, use ISC_R_SHUTTINGDOWN. (ISC_R_CANCELED is now reserved for when the read has been canceled by the caller.) - A new function isc_nmhandle_timer_running() has been added enabling a callback to check whether the timer has been reset after processing a timeout. - Incidental netmgr fix: always use isc__nm_closing() instead of referencing sock->mgr->closing directly - Corrected a few comments that used outdated function names. --- lib/isc/netmgr/http.c | 23 +++++-------- lib/isc/netmgr/netmgr-int.h | 4 +-- lib/isc/netmgr/netmgr.c | 68 +++++++++++++++++++++++++++++-------- lib/isc/netmgr/tcp.c | 32 ++++++++++------- lib/isc/netmgr/tcpdns.c | 63 ++++++++++++++++++++-------------- lib/isc/netmgr/tlsdns.c | 57 ++++++++++++++++++------------- lib/isc/netmgr/tlsstream.c | 4 +-- lib/isc/netmgr/udp.c | 50 +++++++++++++++++++-------- 8 files changed, 192 insertions(+), 109 deletions(-) diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index abca92731c..faba79a803 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -222,13 +222,6 @@ http_session_active(isc_nm_http_session_t *session) { return (!session->closed && !session->closing); } -static bool -inactive(isc_nmsocket_t *sock) { - return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || - (sock->server != NULL && !isc__nmsocket_active(sock->server))); -} - static void * http_malloc(size_t sz, isc_mem_t *mctx) { return (isc_mem_allocate(mctx, sz)); @@ -1461,7 +1454,7 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, } isc__nmsocket_clearcb(sock); - isc__nm_connectcb(sock, req, ISC_R_CANCELED, true); + isc__nm_connectcb(sock, req, ISC_R_SHUTTINGDOWN, true); isc__nmsocket_prep_destroy(sock); isc__nmsocket_detach(&sock); return; @@ -2154,7 +2147,8 @@ server_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock, isc_result_t result = ISC_R_SUCCESS; isc_nm_cb_t cb = req->cb.send; void *cbarg = req->cbarg; - if (inactive(sock) || !http_session_active(handle->httpsession)) { + if (isc__nmsocket_closing(sock) || + !http_session_active(handle->httpsession)) { failed_send_cb(sock, req, ISC_R_CANCELED); return; } @@ -2381,7 +2375,7 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { * function gets invoked, so we need to do extra sanity checks to * detect this case. */ - if (inactive(handle->sock) || httpserver == NULL) { + if (isc__nmsocket_closing(handle->sock) || httpserver == NULL) { return (ISC_R_CANCELED); } @@ -2393,8 +2387,9 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { REQUIRE(VALID_NMSOCK(httplistensock)); INSIST(httplistensock == httpserver); - if (inactive(httplistensock) || - !atomic_load(&httplistensock->listening)) { + if (isc__nmsocket_closing(httplistensock) || + !atomic_load(&httplistensock->listening)) + { return (ISC_R_CANCELED); } @@ -3041,7 +3036,7 @@ isc__nm_http_cleartimeout(isc_nmhandle_t *handle) { REQUIRE(handle->sock->type == isc_nm_httpsocket); sock = handle->sock; - if (sock->h2.session != NULL && sock->h2.session->handle) { + if (sock->h2.session != NULL && sock->h2.session->handle != NULL) { INSIST(VALID_HTTP2_SESSION(sock->h2.session)); INSIST(VALID_NMHANDLE(sock->h2.session->handle)); isc_nmhandle_cleartimeout(sock->h2.session->handle); @@ -3057,7 +3052,7 @@ isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { REQUIRE(handle->sock->type == isc_nm_httpsocket); sock = handle->sock; - if (sock->h2.session != NULL && sock->h2.session->handle) { + if (sock->h2.session != NULL && sock->h2.session->handle != NULL) { INSIST(VALID_HTTP2_SESSION(sock->h2.session)); INSIST(VALID_NMHANDLE(sock->h2.session->handle)); isc_nmhandle_settimeout(sock->h2.session->handle, timeout); diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 60d6b83c51..e5a02343b8 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -976,8 +976,8 @@ struct isc_nmsocket { atomic_bool listening; atomic_bool connecting; atomic_bool connected; - bool accepting; - bool reading; + atomic_bool accepting; + atomic_bool reading; isc_refcount_t references; /*% diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index c5f24e5150..d79a4cbeb8 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -1915,7 +1915,7 @@ isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, void isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { - REQUIRE(sock->accepting); + REQUIRE(atomic_load(&sock->accepting)); REQUIRE(sock->server); /* @@ -1929,7 +1929,7 @@ isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { isc__nmsocket_detach(&sock->server); - sock->accepting = false; + atomic_store(&sock->accepting, false); switch (eresult) { case ISC_R_NOTCONNECTED: @@ -2024,11 +2024,13 @@ isc__nmsocket_readtimeout_cb(uv_timer_t *timer) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); if (atomic_load(&sock->client)) { uv_timer_stop(timer); + sock->recv_read = false; + if (sock->recv_cb != NULL) { isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nm_readcb(sock, req, ISC_R_TIMEDOUT); @@ -2172,7 +2174,7 @@ void isc__nm_start_reading(isc_nmsocket_t *sock) { int r; - if (sock->reading) { + if (atomic_load(&sock->reading)) { return; } @@ -2198,14 +2200,14 @@ isc__nm_start_reading(isc_nmsocket_t *sock) { ISC_UNREACHABLE(); } RUNTIME_CHECK(r == 0); - sock->reading = true; + atomic_store(&sock->reading, true); } void isc__nm_stop_reading(isc_nmsocket_t *sock) { int r; - if (!sock->reading) { + if (!atomic_load(&sock->reading)) { return; } @@ -2223,7 +2225,7 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) { ISC_UNREACHABLE(); } RUNTIME_CHECK(r == 0); - sock->reading = false; + atomic_store(&sock->reading, false); } bool @@ -2234,7 +2236,7 @@ isc__nm_closing(isc_nmsocket_t *sock) { bool isc__nmsocket_closing(isc_nmsocket_t *sock) { return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || + isc__nm_closing(sock) || (sock->server != NULL && !isc__nmsocket_active(sock->server))); } @@ -2260,8 +2262,8 @@ processbuffer(isc_nmsocket_t *sock) { * Stop reading if this is a client socket, or if the server socket * has been set to sequential mode, or the number of queries we are * processing simultaneously has reached the clients-per-connection - * limit. In this case we'll be called again by resume_processing() - * later. + * limit. In this case we'll be called again later by + * isc__nm_resume_processing(). */ void isc__nm_process_sock_buffer(isc_nmsocket_t *sock) { @@ -3123,6 +3125,45 @@ isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family) { return (ISC_R_NOTIMPLEMENTED); } +isc_result_t +isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type) { + int proto, pf, addrlen, fd, r; + + REQUIRE(addr != NULL); + + switch (type) { + case isc_socktype_tcp: + proto = SOCK_STREAM; + break; + case isc_socktype_udp: + proto = SOCK_DGRAM; + break; + default: + return (ISC_R_NOTIMPLEMENTED); + } + + pf = isc_sockaddr_pf(addr); + if (pf == AF_INET) { + addrlen = sizeof(struct sockaddr_in); + } else { + addrlen = sizeof(struct sockaddr_in6); + } + + fd = socket(pf, proto, 0); + if (fd < 0) { + return (isc_errno_toresult(errno)); + } + + r = bind(fd, (const struct sockaddr *)&addr->type.sa, addrlen); + if (r < 0) { + close(fd); + return (isc_errno_toresult(errno)); + } + + close(fd); + return (ISC_R_SUCCESS); +} + #if defined(TCP_CONNECTIONTIMEOUT) #define TIMEOUT_TYPE int #define TIMEOUT_DIV 1000 @@ -3304,11 +3345,10 @@ isc_nm_sequential(isc_nmhandle_t *handle) { * We don't want pipelining on this connection. That means * that we need to pause after reading each request, and * resume only after the request has been processed. This - * is done in resume_processing(), which is the socket's - * closehandle_cb callback, called whenever a handle + * is done in isc__nm_resume_processing(), which is the + * socket's closehandle_cb callback, called whenever a handle * is released. */ - isc__nmsocket_timer_stop(sock); isc__nm_stop_reading(sock); atomic_store(&sock->sequential, true); @@ -3414,7 +3454,7 @@ nmsocket_dump(isc_nmsocket_t *sock) { atomic_load(&sock->closing) ? " closing" : "", atomic_load(&sock->destroying) ? " destroying" : "", atomic_load(&sock->connecting) ? " connecting" : "", - sock->accepting ? " accepting" : ""); + atomic_load(&sock->accepting) ? " accepting" : ""); fprintf(stderr, "Created by:\n"); isc_backtrace_symbols_fd(sock->backtrace, sock->backtrace_size, STDERR_FILENO); diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index 382a8360c9..e5bbd1822b 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -86,7 +86,7 @@ stop_tcp_child(isc_nmsocket_t *sock); static void failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { - REQUIRE(sock->accepting); + REQUIRE(atomic_load(&sock->accepting)); REQUIRE(sock->server); /* @@ -100,7 +100,7 @@ failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { isc__nmsocket_detach(&sock->server); - sock->accepting = false; + atomic_store(&sock->accepting, false); switch (eresult) { case ISC_R_NOTCONNECTED: @@ -250,7 +250,11 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) { isc__nm_uvreq_put(&req, sock); return; } else if (isc__nmsocket_closing(sock)) { - /* Socket was closed midflight by isc__nm_tcp_shutdown() */ + /* Network manager shutting down */ + result = ISC_R_SHUTTINGDOWN; + goto error; + } else if (isc__nmsocket_closing(sock)) { + /* Connection canceled */ result = ISC_R_CANCELED; goto error; } else if (status == UV_ETIMEDOUT) { @@ -732,8 +736,6 @@ isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_tcpsocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; @@ -770,7 +772,7 @@ isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) { UNUSED(worker); if (isc__nmsocket_closing(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -833,7 +835,7 @@ isc__nm_tcp_resumeread(isc_nmhandle_t *handle) { } if (!isc__nmsocket_active(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -856,7 +858,7 @@ isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); REQUIRE(buf != NULL); if (isc__nmsocket_closing(sock)) { @@ -895,7 +897,7 @@ isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { isc__nm_readcb(sock, req, ISC_R_SUCCESS); /* The readcb could have paused the reading */ - if (sock->reading) { + if (atomic_load(&sock->reading)) { /* The timer will be updated */ isc__nmsocket_timer_restart(sock); } @@ -973,7 +975,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->recv_cb = ssock->recv_cb; csock->recv_cbarg = ssock->recv_cbarg; csock->quota = quota; - csock->accepting = true; + atomic_init(&csock->accepting, true); worker = &csock->mgr->workers[isc_nm_tid()]; @@ -1024,7 +1026,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { goto failure; } - csock->accepting = false; + atomic_store(&csock->accepting, false); isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); @@ -1354,7 +1356,7 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { return; } - if (sock->accepting) { + if (atomic_load(&sock->accepting)) { return; } @@ -1366,7 +1368,11 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { } if (sock->statichandle != NULL) { - isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index b5d2d248ce..9f4a7fc595 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -107,7 +107,7 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { RUNTIME_CHECK(r == 0); if (isc__nm_closing(sock)) { - result = ISC_R_CANCELED; + result = ISC_R_SHUTTINGDOWN; goto error; } @@ -217,7 +217,11 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMHANDLE(req->handle)); if (isc__nmsocket_closing(sock)) { - /* Socket was closed midflight by isc__nm_tcpdns_shutdown() */ + /* Network manager shutting down */ + result = ISC_R_SHUTTINGDOWN; + goto error; + } else if (isc__nmsocket_closing(sock)) { + /* Connection canceled */ result = ISC_R_CANCELED; goto error; } else if (status == UV_ETIMEDOUT) { @@ -690,8 +694,6 @@ isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_tcpdnssocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; @@ -729,7 +731,7 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); if (isc__nmsocket_closing(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -780,8 +782,8 @@ isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_UVREQ(req)); /* - * We need to launch the resume_processing after the buffer has - * been consumed, thus we need to delay the detaching the handle. + * We need to launch isc__nm_resume_processing() after the buffer + * has been consumed, thus we must delay detaching the handle. */ isc_nmhandle_attach(req->handle, &handle); @@ -800,9 +802,10 @@ isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) { sock->recv_read = false; /* - * The assertion failure here means that there's a errnoneous extra - * nmhandle detach happening in the callback and resume_processing gets - * called while we are still processing the buffer. + * An assertion failure here means that there's an erroneous + * extra nmhandle detach happening in the callback and + * isc__nm_resume_processing() is called while we're + * processing the buffer. */ REQUIRE(sock->processing == false); sock->processing = true; @@ -829,7 +832,7 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); REQUIRE(buf != NULL); if (isc__nmsocket_closing(sock)) { @@ -949,7 +952,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->recv_cb = ssock->recv_cb; csock->recv_cbarg = ssock->recv_cbarg; csock->quota = quota; - csock->accepting = true; + atomic_init(&csock->accepting, true); worker = &csock->mgr->workers[csock->tid]; @@ -1007,7 +1010,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { goto failure; } - csock->accepting = false; + atomic_store(&csock->accepting, false); isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); @@ -1056,13 +1059,15 @@ failure: void isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, void *cbarg) { - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - isc_nmsocket_t *sock = handle->sock; isc__netievent_tcpdnssend_t *ievent = NULL; isc__nm_uvreq_t *uvreq = NULL; + isc_nmsocket_t *sock = NULL; + REQUIRE(VALID_NMHANDLE(handle)); + + sock = handle->sock; + + REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->type == isc_nm_tcpdnssocket); uvreq = isc__nm_uvreq_get(sock->mgr, sock); @@ -1107,24 +1112,26 @@ tcpdns_send_cb(uv_write_t *req, int status) { */ void isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) { + isc_result_t result; isc__netievent_tcpdnssend_t *ievent = (isc__netievent_tcpdnssend_t *)ev0; + isc_nmsocket_t *sock = NULL; + isc__nm_uvreq_t *uvreq = NULL; + int r, nbufs = 2; + + UNUSED(worker); REQUIRE(VALID_UVREQ(ievent->req)); REQUIRE(VALID_NMSOCK(ievent->sock)); REQUIRE(ievent->sock->type == isc_nm_tcpdnssocket); REQUIRE(ievent->sock->tid == isc_nm_tid()); - isc_result_t result; - isc_nmsocket_t *sock = ievent->sock; - isc__nm_uvreq_t *uvreq = ievent->req; + sock = ievent->sock; + uvreq = ievent->req; + uv_buf_t bufs[2] = { { .base = uvreq->tcplen, .len = 2 }, { .base = uvreq->uvbuf.base, .len = uvreq->uvbuf.len } }; - int nbufs = 2; - int r; - - UNUSED(worker); if (isc__nmsocket_closing(sock)) { result = ISC_R_CANCELED; @@ -1380,7 +1387,7 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) { return; } - if (sock->accepting) { + if (atomic_load(&sock->accepting)) { return; } @@ -1392,7 +1399,11 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) { } if (sock->statichandle != NULL) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index 72fe096f5c..0b3b43703a 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -124,7 +124,7 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { uv_handle_set_data((uv_handle_t *)&sock->timer, sock); if (isc__nm_closing(sock)) { - result = ISC_R_CANCELED; + result = ISC_R_SHUTTINGDOWN; goto error; } @@ -233,7 +233,11 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) { REQUIRE(VALID_NMHANDLE(req->handle)); if (isc__nmsocket_closing(sock)) { - /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ + /* Network manager shutting down */ + result = ISC_R_SHUTTINGDOWN; + goto error; + } else if (isc__nmsocket_closing(sock)) { + /* Connection canceled */ result = ISC_R_CANCELED; goto error; } else if (status == UV_ETIMEDOUT) { @@ -344,6 +348,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, } if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; goto failure; } @@ -373,6 +378,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, BROADCAST(&sock->scond); UNLOCK(&sock->lock); return; + failure: if (isc__nm_in_netthread()) { sock->tid = isc_nm_tid(); @@ -843,8 +849,6 @@ isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_tlsdnssocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; @@ -884,7 +888,7 @@ isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { REQUIRE(sock->tid == isc_nm_tid()); if (isc__nmsocket_closing(sock)) { - sock->reading = true; + atomic_store(&sock->reading, true); isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); return; } @@ -938,9 +942,8 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_UVREQ(req)); /* - * We need to launch the resume_processing after the buffer has - * been consumed, thus we need to delay the detaching the - * handle. + * We need to launch isc__nm_resume_processing() after the buffer + * has been consumed, thus we must delay detaching the handle. */ isc_nmhandle_attach(req->handle, &handle); @@ -959,10 +962,10 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { sock->recv_read = false; /* - * The assertion failure here means that there's a errnoneous + * An assertion failure here means that there's an erroneous * extra nmhandle detach happening in the callback and - * resume_processing gets called while we are still processing - * the buffer. + * isc__nm_resume_processing() is called while we're + * processing the buffer. */ REQUIRE(sock->processing == false); sock->processing = true; @@ -1278,6 +1281,8 @@ done: static void async_tlsdns_cycle(isc_nmsocket_t *sock) { + isc__netievent_tlsdnscycle_t *ievent = NULL; + REQUIRE(VALID_NMSOCK(sock)); /* Socket was closed midflight by isc__nm_tlsdns_shutdown() */ @@ -1285,8 +1290,7 @@ async_tlsdns_cycle(isc_nmsocket_t *sock) { return; } - isc__netievent_tlsdnscycle_t *ievent = - isc__nm_get_netievent_tlsdnscycle(sock->mgr, sock); + ievent = isc__nm_get_netievent_tlsdnscycle(sock->mgr, sock); isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], (isc__netievent_t *)ievent); } @@ -1321,7 +1325,7 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); REQUIRE(buf != NULL); if (isc__nmsocket_closing(sock)) { @@ -1441,7 +1445,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { csock->recv_cb = ssock->recv_cb; csock->recv_cbarg = ssock->recv_cbarg; csock->quota = quota; - csock->accepting = true; + atomic_init(&csock->accepting, true); worker = &csock->mgr->workers[csock->tid]; @@ -1530,7 +1534,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { /* FIXME: Set SSL_MODE_RELEASE_BUFFERS */ - csock->accepting = false; + atomic_store(&csock->accepting, false); isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); @@ -1579,13 +1583,15 @@ failure: void isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, void *cbarg) { - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - isc_nmsocket_t *sock = handle->sock; isc__netievent_tlsdnssend_t *ievent = NULL; isc__nm_uvreq_t *uvreq = NULL; + isc_nmsocket_t *sock = NULL; + REQUIRE(VALID_NMHANDLE(handle)); + + sock = handle->sock; + + REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->type == isc_nm_tlsdnssocket); uvreq = isc__nm_uvreq_get(sock->mgr, sock); @@ -1936,12 +1942,14 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) { (void)SSL_shutdown(sock->tls.tls); } - if (sock->accepting) { + if (atomic_load(&sock->accepting)) { return; } /* TLS handshake hasn't been completed yet */ if (atomic_load(&sock->connecting)) { + isc_nmsocket_t *tsock = NULL; + /* * TCP connection has been established, now waiting on * TLS handshake to complete @@ -1956,14 +1964,17 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) { } /* The TCP connection hasn't been established yet */ - isc_nmsocket_t *tsock = NULL; isc__nmsocket_attach(sock, &tsock); uv_close(&sock->uv_handle.handle, tlsdns_close_connect_cb); return; } if (sock->statichandle != NULL) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index 8321b74f3b..49edb68191 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -83,7 +83,7 @@ inactive(isc_nmsocket_t *sock) { atomic_load(&sock->outerhandle->sock->closing) || (sock->listener != NULL && !isc__nmsocket_active(sock->listener)) || - atomic_load(&sock->mgr->closing)); + isc__nm_closing(sock)); } static void @@ -913,7 +913,7 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { tlssock->iface = handle->sock->iface; tlssock->peer = handle->sock->peer; if (isc__nm_closing(tlssock)) { - result = ISC_R_CANCELED; + result = ISC_R_SHUTTINGDOWN; goto error; } diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index fbf9345592..f4de7d3e73 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -89,7 +89,7 @@ start_udp_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock, isc__nmsocket_init(csock, mgr, isc_nm_udpsocket, iface); csock->parent = sock; csock->iface = sock->iface; - csock->reading = true; + atomic_init(&csock->reading, true); csock->recv_cb = sock->recv_cb; csock->recv_cbarg = sock->recv_cbarg; csock->extrahandlesize = sock->extrahandlesize; @@ -344,7 +344,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); + REQUIRE(atomic_load(&sock->reading)); #ifdef UV_UDP_MMSG_FREE free_buf = ((flags & UV_UDP_MMSG_FREE) == UV_UDP_MMSG_FREE); @@ -356,7 +356,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, #endif /* - * Three possible reasons to return now without processing: + * Four possible reasons to return now without processing: */ /* @@ -373,6 +373,15 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, goto free; } + /* + * - If there was a networking error. + */ + if (nrecv < 0) { + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv), + false); + goto free; + } + /* * - If addr == NULL, in which case it's the end of stream; * we can free the buffer and bail. @@ -390,12 +399,6 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, goto free; } - if (nrecv < 0) { - isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv), - false); - goto free; - } - result = isc_sockaddr_fromsockaddr(&sockaddr, addr); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -612,6 +615,11 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { RUNTIME_CHECK(r == 0); uv_handle_set_data((uv_handle_t *)&sock->timer, sock); + if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; + goto error; + } + r = uv_udp_open(&sock->uv_handle.udp, sock->fd); if (r != 0) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]); @@ -653,6 +661,7 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { done: result = isc__nm_uverr2result(r); +error: LOCK(&sock->lock); sock->result = result; @@ -800,6 +809,7 @@ isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, * does not. */ if (!sock->parent) { + isc__nmsocket_timer_stop(sock); isc__nm_stop_reading(sock); } } @@ -856,15 +866,22 @@ void isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_udpread_t *ievent = (isc__netievent_udpread_t *)ev0; isc_nmsocket_t *sock = ievent->sock; + isc_result_t result = ISC_R_SUCCESS; UNUSED(worker); REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (isc__nmsocket_closing(sock)) { - sock->reading = true; - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; + } else if (isc__nmsocket_closing(sock)) { + result = ISC_R_CANCELED; + } + + if (result != ISC_R_SUCCESS) { + atomic_store(&sock->reading, true); + isc__nm_failed_read_cb(sock, result, false); return; } @@ -881,14 +898,13 @@ isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(sock->type == isc_nm_udpsocket); REQUIRE(sock->statichandle == handle); - REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(!sock->recv_read); sock->recv_cb = cb; sock->recv_cbarg = cbarg; sock->recv_read = true; - if (!sock->reading && sock->tid == isc_nm_tid()) { + if (!atomic_load(&sock->reading) && sock->tid == isc_nm_tid()) { isc__netievent_udpread_t ievent = { .sock = sock }; isc__nm_async_udpread(NULL, (isc__netievent_t *)&ievent); } else { @@ -1079,7 +1095,11 @@ isc__nm_udp_shutdown(isc_nmsocket_t *sock) { * interested in the callback. */ if (sock->statichandle != NULL) { - isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + if (isc__nm_closing(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false); + } else { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); + } return; } From 308bc46a59302c88ecff11d4831475ecfa8b8fb0 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 14 Jan 2021 13:02:57 -0800 Subject: [PATCH 17/28] Convert dispatch to netmgr The flow of operations in dispatch is changing and will now be similar for both UDP and TCP queries: 1) Call dns_dispatch_addresponse() to assign a query ID and register that we'll be listening for a response with that ID soon. the parameters for this function include callback functions to inform the caller when the socket is connected and when the message has been sent, as well as a task action that will be sent when the response arrives. (later this could become a netmgr callback, but at this stage to minimize disruption to the calling code, we continue to use isc_task for the response event.) on successful completion of this function, a dispatch entry object will be instantiated. 2) Call dns_dispatch_connect() on the dispatch entry. this runs isc_nm_udpconnect() or isc_nm_tcpdnsconnect(), as needed, and begins listening for responses. the caller is informed via a callback function when the connection is established. 3) Call dns_dispatch_send() on the dispatch entry. this runs isc_nm_send() to send a request. 4) Call dns_dispatch_removeresponse() to terminate listening and close the connection. Implementation comments below: - As we will be using netmgr buffers now. code to send the length in TCP queries has also been removed as that is handled by the netmgr. - TCP dispatches can be used by multiple simultaneous queries, so dns_dispatch_connect() now checks whether the dispatch is already connected before calling isc_nm_tcpdnsconnect() again. - Running dns_dispatch_getnext() from a non-network thread caused a crash due to assertions in the netmgr read functions that appear to be unnecessary now. the assertions have been removed. - fctx->nqueries was formerly incremented when the connection was successful, but is now incremented when the query is started and decremented if the connection fails. - It's no longer necessary for each dispatch to have a pool of tasks, so there's now a single task per dispatch. - Dispatch code to avoid UDP ports already in use has been removed. - dns_resolver and dns_request have been modified to use netmgr callback functions instead of task events. some additional changes were needed to handle shutdown processing correctly. - Timeout processing is not yet fully converted to use netmgr timeouts. - Fixed a lock order cycle reported by TSAN (view -> zone-> adb -> view) by by calling dns_zt functions without holding the view lock. --- bin/delv/delv.c | 11 +- bin/named/server.c | 13 +- bin/nsupdate/nsupdate.c | 27 +- bin/tests/system/pipelined/pipequeries.c | 23 +- bin/tests/system/resolve.c | 16 +- bin/tests/system/tkey/keycreate.c | 27 +- bin/tests/system/tkey/keydelete.c | 25 +- bin/tools/mdig.c | 20 +- lib/dns/client.c | 53 +- lib/dns/dispatch.c | 1283 +++++++--------------- lib/dns/include/dns/client.h | 7 +- lib/dns/include/dns/dispatch.h | 90 +- lib/dns/include/dns/request.h | 5 +- lib/dns/include/dns/resolver.h | 14 +- lib/dns/include/dns/view.h | 8 +- lib/dns/request.c | 203 +--- lib/dns/resolver.c | 397 +++---- lib/dns/tests/dispatch_test.c | 234 ++-- lib/dns/tests/dnstest.c | 3 + lib/dns/tests/dnstest.h | 1 + lib/dns/tests/resolver_test.c | 10 +- lib/dns/view.c | 40 +- lib/dns/zt.c | 2 + lib/isc/include/isc/netmgr.h | 10 + lib/isc/managers.c | 2 +- lib/isc/socket.c | 2 +- lib/ns/interfacemgr.c | 2 +- lib/ns/tests/nstest.c | 2 +- 28 files changed, 924 insertions(+), 1606 deletions(-) diff --git a/bin/delv/delv.c b/bin/delv/delv.c index dd1181076b..3559f1bf63 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -1725,7 +1725,6 @@ main(int argc, char *argv[]) { isc_appctx_t *actx = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_socketmgr_t *socketmgr = NULL; isc_timermgr_t *timermgr = NULL; dns_master_style_t *style = NULL; struct sigaction sa; @@ -1744,8 +1743,8 @@ main(int argc, char *argv[]) { isc_mem_create(&mctx); CHECK(isc_appctx_create(mctx, &actx)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, NULL); parse_args(argc, argv); @@ -1763,7 +1762,7 @@ main(int argc, char *argv[]) { } /* Create client */ - result = dns_client_create(mctx, actx, taskmgr, socketmgr, timermgr, 0, + result = dns_client_create(mctx, actx, taskmgr, netmgr, timermgr, 0, &client, srcaddr4, srcaddr6); if (result != ISC_R_SUCCESS) { delv_log(ISC_LOG_ERROR, "dns_client_create: %s", @@ -1846,7 +1845,9 @@ cleanup: if (client != NULL) { dns_client_detach(&client); } - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + + isc_managers_destroy(&netmgr, &taskmgr, &timermgr, NULL); + if (actx != NULL) { isc_appctx_destroy(&actx); } diff --git a/bin/named/server.c b/bin/named/server.c index e70cba3662..0abefe8407 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1315,8 +1315,8 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, } } - result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &sa, attrs, &disp); + result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_taskmgr, + &sa, attrs, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -4716,7 +4716,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH); CHECK(dns_view_createresolver( view, named_g_taskmgr, RESOLVER_NTASKS_PERCPU * named_g_cpus, - ndisp, named_g_socketmgr, named_g_timermgr, resopts, + ndisp, named_g_netmgr, named_g_timermgr, resopts, named_g_dispatchmgr, dispatch4, dispatch6)); if (dscp4 == -1) { @@ -9862,7 +9862,8 @@ run_server(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); - CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr), + CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr, + &named_g_dispatchmgr), "creating dispatch manager"); dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats); @@ -10357,8 +10358,8 @@ named_add_reserved_dispatch(named_server_t *server, dispatch->dispatchgen = server->dispatchgen; dispatch->dispatch = NULL; - result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_socketmgr, - named_g_taskmgr, &dispatch->addr, attrs, + result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_taskmgr, + &dispatch->addr, attrs, &dispatch->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index be39164216..a3bb130a7e 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -38,11 +39,9 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -131,8 +130,6 @@ static isc_log_t *glctx = NULL; static isc_mem_t *gmctx = NULL; static dns_dispatchmgr_t *dispatchmgr = NULL; static dns_requestmgr_t *requestmgr = NULL; -static isc_socketmgr_t *socketmgr = NULL; -static isc_timermgr_t *timermgr = NULL; static dns_dispatch_t *dispatchv4 = NULL; static dns_dispatch_t *dispatchv6 = NULL; static dns_message_t *updatemsg = NULL; @@ -917,11 +914,12 @@ setup_system(void) { irs_resconf_destroy(&resconf); - result = dns_dispatchmgr_create(gmctx, &dispatchmgr); - check_result(result, "dns_dispatchmgr_create"); + result = isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, NULL, + NULL); + check_result(result, "isc_managers_create"); - isc_managers_create(gmctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + result = dns_dispatchmgr_create(gmctx, netmgr, &dispatchmgr); + check_result(result, "dns_dispatchmgr_create"); result = isc_task_create(taskmgr, 0, &global_task); check_result(result, "isc_task_create"); @@ -937,21 +935,20 @@ setup_system(void) { if (have_ipv6) { isc_sockaddr_any6(&bind_any6); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any6, 0, &dispatchv6); check_result(result, "dns_dispatch_createudp (v6)"); } if (have_ipv4) { isc_sockaddr_any(&bind_any); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 0, &dispatchv4); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, + 0, &dispatchv4); check_result(result, "dns_dispatch_createudp (v4)"); } - result = dns_requestmgr_create(gmctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, dispatchv6, - &requestmgr); + result = dns_requestmgr_create(gmctx, taskmgr, dispatchmgr, dispatchv4, + dispatchv6, &requestmgr); check_result(result, "dns_requestmgr_create"); if (keystr != NULL) { @@ -3322,7 +3319,7 @@ cleanup(void) { } ddebug("Shutting down managers"); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); ddebug("Destroying event"); isc_event_free(&global_event); diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 6466771ff2..6b34dd808c 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -23,12 +23,11 @@ #include #include #include +#include #include #include #include -#include #include -#include #include #include @@ -70,7 +69,8 @@ static void recvresponse(isc_task_t *task, isc_event_t *event) { dns_requestevent_t *reqev = (dns_requestevent_t *)event; isc_result_t result; - dns_message_t *query = NULL, *response = NULL; + dns_message_t *query = NULL; + dns_message_t *response = NULL; isc_buffer_t outbuf; char output[1024]; @@ -203,8 +203,6 @@ main(int argc, char *argv[]) { isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; dns_view_t *view = NULL; @@ -267,18 +265,15 @@ main(int argc, char *argv[]) { RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); - + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchv4)); - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); RUNCHECK(isc_app_onrun(mctx, task, sendqueries, NULL)); @@ -296,7 +291,7 @@ main(int argc, char *argv[]) { isc_task_shutdown(task); isc_task_detach(&task); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_lib_destroy(); diff --git a/bin/tests/system/resolve.c b/bin/tests/system/resolve.c index c13cb5bee4..6508b6e9ff 100644 --- a/bin/tests/system/resolve.c +++ b/bin/tests/system/resolve.c @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -58,13 +58,11 @@ isc_mem_t *ctxs_mctx = NULL; isc_appctx_t *ctxs_actx = NULL; isc_nm_t *ctxs_netmgr = NULL; isc_taskmgr_t *ctxs_taskmgr = NULL; -isc_socketmgr_t *ctxs_socketmgr = NULL; isc_timermgr_t *ctxs_timermgr = NULL; static void ctxs_destroy(void) { - isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, - &ctxs_socketmgr); + isc_managers_destroy(&ctxs_netmgr, &ctxs_taskmgr, &ctxs_timermgr, NULL); if (ctxs_actx != NULL) { isc_appctx_destroy(&ctxs_actx); @@ -87,7 +85,7 @@ ctxs_init(void) { } isc_managers_create(ctxs_mctx, 1, 0, 0, &ctxs_netmgr, &ctxs_taskmgr, - &ctxs_timermgr, &ctxs_socketmgr); + &ctxs_timermgr, NULL); result = isc_app_ctxstart(ctxs_actx); if (result != ISC_R_SUCCESS) { @@ -102,7 +100,7 @@ fail: return (result); } -static char *algname; +static char *algname = NULL; static isc_result_t printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { @@ -281,9 +279,9 @@ main(int argc, char *argv[]) { isc_buffer_t b; dns_fixedname_t qname0; unsigned int namelen; - dns_name_t *qname, *name; + dns_name_t *qname = NULL, *name = NULL; dns_rdatatype_t type = dns_rdatatype_a; - dns_rdataset_t *rdataset; + dns_rdataset_t *rdataset = NULL; dns_namelist_t namelist; unsigned int clientopt, resopt = 0; bool is_sep = false; @@ -406,7 +404,7 @@ main(int argc, char *argv[]) { clientopt = 0; result = dns_client_create(ctxs_mctx, ctxs_actx, ctxs_taskmgr, - ctxs_socketmgr, ctxs_timermgr, clientopt, + ctxs_netmgr, ctxs_timermgr, clientopt, &client, addr4, addr6); if (result != ISC_R_SUCCESS) { fprintf(stderr, "dns_client_create failed: %u, %s\n", result, diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 6904c1998a..9ede9a65b5 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -18,13 +18,12 @@ #include #include #include +#include #include #include #include #include -#include #include -#include #include #include @@ -86,7 +85,6 @@ recvquery(isc_task_t *task, isc_event_t *event) { query = reqev->ev_arg; - response = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response); result = dns_request_getresponse(reqev->request, response, @@ -190,9 +188,6 @@ main(int argc, char *argv[]) { char *ourkeyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; - isc_socket_t *sock = NULL; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -227,18 +222,16 @@ main(int argc, char *argv[]) { RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 0, &dispatchv4)); - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, 0, + &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); @@ -247,9 +240,6 @@ main(int argc, char *argv[]) { dns_view_setkeyring(view, ring); dns_tsigkeyring_detach(&ring); - RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, - &sock)); - RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; @@ -268,8 +258,7 @@ main(int argc, char *argv[]) { dns_dispatchmgr_destroy(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_socket_detach(&sock); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_key_free(&ourkey); dns_tsigkey_detach(&initialkey); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index 1b8d3dc336..c76d816132 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include @@ -134,9 +132,6 @@ main(int argc, char **argv) { char *keyname = NULL; isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; - isc_socket_t *sock = NULL; isc_sockaddr_t bind_any; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; @@ -171,17 +166,15 @@ main(int argc, char **argv) { RUNCHECK(dst_lib_init(mctx, NULL)); - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - &bind_any, 0, &dispatchv4)); - RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr, - dispatchmgr, dispatchv4, NULL, - &requestmgr)); + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, 0, + &dispatchv4)); + RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, + NULL, &requestmgr)); RUNCHECK(dns_tsigkeyring_create(mctx, &ring)); RUNCHECK(dns_tkeyctx_create(mctx, &tctx)); @@ -189,9 +182,6 @@ main(int argc, char **argv) { RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); dns_view_setkeyring(view, ring); - RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, - &sock)); - RUNCHECK(isc_app_onrun(mctx, task, sendquery, NULL)); type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_KEY; @@ -211,8 +201,7 @@ main(int argc, char **argv) { dns_dispatchmgr_destroy(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); - isc_socket_detach(&sock); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dns_tsigkeyring_detach(&ring); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index 9c58a337cd..f3d37da52c 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -24,15 +24,14 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include -#include #include #include @@ -2068,8 +2067,6 @@ main(int argc, char *argv[]) { isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; - isc_timermgr_t *timermgr = NULL; - isc_socketmgr_t *socketmgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchvx = NULL; dns_view_t *view = NULL; @@ -2122,25 +2119,22 @@ main(int argc, char *argv[]) { fatal("can't choose between IPv4 and IPv6"); } - isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); - + isc_managers_create(mctx, 1, 0, 0, &netmgr, &taskmgr, NULL, NULL); RUNCHECK(isc_task_create(taskmgr, 0, &task)); - RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); if (have_ipv4) { isc_sockaddr_any(&bind_any); } else { isc_sockaddr_any6(&bind_any); } - RUNCHECK(dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, + RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchvx)); RUNCHECK(dns_requestmgr_create( - mctx, timermgr, socketmgr, taskmgr, dispatchmgr, - have_ipv4 ? dispatchvx : NULL, have_ipv6 ? dispatchvx : NULL, - &requestmgr)); + mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL, + have_ipv6 ? dispatchvx : NULL, &requestmgr)); RUNCHECK(dns_view_create(mctx, 0, "_test", &view)); @@ -2186,7 +2180,7 @@ main(int argc, char *argv[]) { isc_task_shutdown(task); isc_task_detach(&task); - isc_managers_destroy(&netmgr, &taskmgr, &timermgr, &socketmgr); + isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); dst_lib_destroy(); diff --git a/lib/dns/client.c b/lib/dns/client.c index 1d113972b8..70a1adb859 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -86,7 +86,7 @@ struct dns_client { isc_appctx_t *actx; isc_taskmgr_t *taskmgr; isc_task_t *task; - isc_socketmgr_t *socketmgr; + isc_nm_t *nm; isc_timermgr_t *timermgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; @@ -202,8 +202,8 @@ cleanup: static isc_result_t getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, - dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { + isc_taskmgr_t *taskmgr, dns_dispatch_t **dispp, + const isc_sockaddr_t *localaddr) { dns_dispatch_t *disp = NULL; isc_result_t result; isc_sockaddr_t anyaddr; @@ -213,8 +213,8 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, localaddr = &anyaddr; } - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, - localaddr, 0, &disp); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, localaddr, 0, + &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -224,10 +224,9 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, static isc_result_t createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, - unsigned int ntasks, isc_socketmgr_t *socketmgr, - isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_view_t **viewp) { + unsigned int ntasks, isc_nm_t *nm, isc_timermgr_t *timermgr, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_view_t **viewp) { isc_result_t result; dns_view_t *view = NULL; @@ -243,8 +242,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, return (result); } - result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr, - timermgr, 0, dispatchmgr, dispatchv4, + result = dns_view_createresolver(view, taskmgr, ntasks, 1, nm, timermgr, + 0, dispatchmgr, dispatchv4, dispatchv6); if (result != ISC_R_SUCCESS) { dns_view_detach(&view); @@ -264,9 +263,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, isc_result_t dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_client_t **clientp, - const isc_sockaddr_t *localaddr4, + isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, const isc_sockaddr_t *localaddr4, const isc_sockaddr_t *localaddr6) { isc_result_t result; dns_client_t *client = NULL; @@ -278,27 +276,24 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, REQUIRE(mctx != NULL); REQUIRE(taskmgr != NULL); REQUIRE(timermgr != NULL); - REQUIRE(socketmgr != NULL); + REQUIRE(nm != NULL); REQUIRE(clientp != NULL && *clientp == NULL); UNUSED(options); client = isc_mem_get(mctx, sizeof(*client)); + *client = (dns_client_t){ + .actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm + }; isc_mutex_init(&client->lock); - client->actx = actx; - client->taskmgr = taskmgr; - client->socketmgr = socketmgr; - client->timermgr = timermgr; - - client->task = NULL; result = isc_task_create(client->taskmgr, 0, &client->task); if (result != ISC_R_SUCCESS) { goto cleanup_lock; } - result = dns_dispatchmgr_create(mctx, &dispatchmgr); + result = dns_dispatchmgr_create(mctx, nm, &dispatchmgr); if (result != ISC_R_SUCCESS) { goto cleanup_task; } @@ -311,8 +306,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, */ client->dispatchv4 = NULL; if (localaddr4 != NULL || localaddr6 == NULL) { - result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, - taskmgr, &dispatchv4, localaddr4); + result = getudpdispatch(AF_INET, dispatchmgr, taskmgr, + &dispatchv4, localaddr4); if (result == ISC_R_SUCCESS) { client->dispatchv4 = dispatchv4; } @@ -320,8 +315,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, client->dispatchv6 = NULL; if (localaddr6 != NULL || localaddr4 == NULL) { - result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, - taskmgr, &dispatchv6, localaddr6); + result = getudpdispatch(AF_INET6, dispatchmgr, taskmgr, + &dispatchv6, localaddr6); if (result == ISC_R_SUCCESS) { client->dispatchv6 = dispatchv6; } @@ -337,8 +332,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, /* Create the default view for class IN */ result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS, - socketmgr, timermgr, dispatchmgr, dispatchv4, - dispatchv6, &view); + nm, timermgr, dispatchmgr, dispatchv4, dispatchv6, + &view); if (result != ISC_R_SUCCESS) { goto cleanup_references; } @@ -350,12 +345,10 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, ISC_LIST_INIT(client->resctxs); - client->mctx = NULL; isc_mem_attach(mctx, &client->mctx); client->find_timeout = DEF_FIND_TIMEOUT; client->find_udpretries = DEF_FIND_UDPRETRIES; - client->attributes = 0; client->magic = DNS_CLIENT_MAGIC; diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index e8f78d5550..a159e79c55 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -19,10 +19,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -40,15 +40,13 @@ typedef ISC_LIST(dns_dispentry_t) dns_displist_t; typedef struct dispsocket dispsocket_t; -typedef ISC_LIST(dispsocket_t) dispsocketlist_t; typedef struct dns_qid { unsigned int magic; + isc_mutex_t lock; unsigned int qid_nbuckets; /*%< hash table size */ unsigned int qid_increment; /*%< id increment on collision */ - isc_mutex_t lock; - dns_displist_t *qid_table; /*%< the table itself */ - dispsocketlist_t *sock_table; /*%< socket table */ + dns_displist_t *qid_table; /*%< the table itself */ } dns_qid_t; struct dns_dispatchmgr { @@ -57,6 +55,7 @@ struct dns_dispatchmgr { isc_mem_t *mctx; dns_acl_t *blackhole; isc_stats_t *stats; + isc_nm_t *nm; /* Locked by "lock". */ isc_mutex_t lock; @@ -66,8 +65,7 @@ struct dns_dispatchmgr { /* locked by buffer_lock */ dns_qid_t *qid; isc_mutex_t buffer_lock; - unsigned int buffers; /*%< allocated buffers */ - unsigned int buffersize; /*%< size of each buffer */ + unsigned int buffers; isc_refcount_t irefs; @@ -86,9 +84,13 @@ struct dns_dispentry { dns_messageid_t id; in_port_t port; unsigned int bucket; - isc_sockaddr_t host; + unsigned int timeout; + isc_sockaddr_t peer; isc_task_t *task; + isc_nm_cb_t connected; + isc_nm_cb_t sent; isc_taskaction_t action; + isc_taskaction_t timeout_action; void *arg; bool item_out; dispsocket_t *dispsocket; @@ -105,51 +107,24 @@ struct dns_dispentry { struct dispsocket { unsigned int magic; - isc_socket_t *socket; + isc_nmhandle_t *handle; dns_dispatch_t *disp; - isc_sockaddr_t host; + isc_sockaddr_t local; + isc_sockaddr_t peer; dns_dispentry_t *resp; - isc_task_t *task; in_port_t port; ISC_LINK(dispsocket_t) link; - unsigned int bucket; - ISC_LINK(dispsocket_t) blink; }; -typedef struct tcpmsg { - uint16_t size; - dns_dispatch_t *disp; - isc_buffer_t buffer; - isc_task_t *task; - isc_taskaction_t action; - void *arg; - isc_event_t event; - isc_result_t result; - isc_sockaddr_t address; -} tcpmsg_t; - -/*% - * Number of tasks for each dispatch that use separate sockets for different - * transactions. This must be a power of 2 as it will divide 32 bit numbers - * to get an uniformly random tasks selection. See get_dispsocket(). - */ -#define MAX_INTERNAL_TASKS 64 - struct dns_dispatch { /* Unlocked. */ unsigned int magic; /*%< magic */ dns_dispatchmgr_t *mgr; /*%< dispatch manager */ - int ntasks; - /*% - * internal task buckets. We use multiple tasks to distribute various - * socket events well when using separate dispatch sockets. We use the - * 1st task (task[0]) for internal control events. - */ - isc_task_t *task[MAX_INTERNAL_TASKS]; - isc_socket_t *socket; /*%< isc socket attached to */ - isc_sockaddr_t local; /*%< local address */ - in_port_t localport; /*%< local UDP port */ - isc_sockaddr_t peer; /*%< peer address (TCP) */ + isc_task_t *task; + isc_nmhandle_t *handle; /*%< netmgr handle for TCP connection */ + isc_sockaddr_t local; /*%< local address */ + in_port_t localport; /*%< local UDP port */ + isc_sockaddr_t peer; /*%< peer address (TCP) */ isc_event_t *ctlevent; isc_mem_t *sepool; /*%< pool for socket events */ @@ -159,19 +134,17 @@ struct dns_dispatch { /* Locked by "lock". */ isc_mutex_t lock; /*%< locks all below */ - isc_sockettype_t socktype; + isc_socktype_t socktype; unsigned int attributes; isc_refcount_t refcount; dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ - unsigned int shutting_down : 1, shutdown_out : 1, recv_pending : 1, - tcpmsg_valid : 1; + unsigned int shutting_down : 1, shutdown_out : 1, recv_pending : 1; isc_result_t shutdown_why; ISC_LIST(dispsocket_t) activesockets; ISC_LIST(dispsocket_t) inactivesockets; unsigned int nsockets; unsigned int requests; /*%< how many requests we have */ unsigned int tcpbuffers; /*%< allocated buffers */ - tcpmsg_t tcpmsg; }; #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') @@ -212,11 +185,11 @@ struct dns_dispatch { #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ /*% - * Number of buffers available for all dispatches in the buffery memory - * pool. + * Number of buffers available for all dispatches in the buffer + * memory pool. */ #ifndef DNS_DISPATCH_MAXBUFFERS -#define DNS_DISPATCH_MAXBUFFERS 32768 +#define DNS_DISPATCH_MAXBUFFERS 37268 #endif /* ifndef DNS_DISPATCH_MAXBUFFERS */ /*% @@ -264,17 +237,13 @@ destroy_dispsocket(dns_dispatch_t *, dispsocket_t **); static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *); static void -udp_recv(isc_task_t *, isc_event_t *); +udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg); static void -tcp_recv(isc_task_t *, isc_event_t *); -static isc_result_t -startrecv(dns_dispatch_t *, dispsocket_t *); +tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg); static uint32_t dns_hash(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t); -static void -free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); -static void * -allocate_udp_buffer(dns_dispatch_t *disp); static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); static inline dns_dispatchevent_t * @@ -288,9 +257,9 @@ linear_next(dns_qid_t *disp, dns_dispentry_t *resp); static void dispatch_free(dns_dispatch_t **dispp); static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp); +dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp); static bool destroy_mgr_ok(dns_dispatchmgr_t *mgr); static void @@ -299,13 +268,12 @@ static void qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp); static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp); -static isc_result_t -open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp); -static isc_socket_t * -getentrysocket(dns_dispentry_t *resp); -static isc_socket_t * -getsocket(dns_dispatch_t *disp); +static isc_nmhandle_t * +gethandle(dns_dispatch_t *disp); +static isc_nmhandle_t * +getentryhandle(dns_dispentry_t *resp); +static void +startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket); #define LVL(x) ISC_LOG_DEBUG(x) @@ -387,7 +355,7 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, va_end(ap); if (VALID_RESPONSE(resp)) { - isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf)); + isc_sockaddr_format(&resp->peer, peerbuf, sizeof(peerbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH, level, "dispatch %p response %p %s: %s", disp, resp, @@ -498,7 +466,6 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { dns_dispatchmgr_t *mgr = NULL; bool killmgr; dispsocket_t *dispsocket = NULL; - int i; INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL); @@ -510,23 +477,21 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { LOCK(&mgr->lock); ISC_LIST_UNLINK(mgr->list, disp, link); - dispatch_log(disp, LVL(90), "shutting down; detaching from sock %p", - disp->socket); + dispatch_log(disp, LVL(90), "shutting down; detaching from handle %p", + disp->handle); if (disp->sepool != NULL) { isc_mem_destroy(&disp->sepool); } - if (disp->socket != NULL) { - isc_socket_detach(&disp->socket); + if (disp->handle != NULL) { + isc_nmhandle_detach(&disp->handle); } while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) { ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link); destroy_dispsocket(disp, &dispsocket); } - for (i = 0; i < disp->ntasks; i++) { - isc_task_detach(&disp->task[i]); - } + isc_task_detach(&disp->task); isc_event_free(&event); dispatch_free(&disp); @@ -538,47 +503,15 @@ destroy_disp(isc_task_t *task, isc_event_t *event) { } } -/*% - * Find a dispsocket for socket address 'dest', and port number 'port'. - * Return NULL if no such entry exists. Requires qid->lock to be held. - */ -static dispsocket_t * -socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port, - unsigned int bucket) { - dispsocket_t *dispsock = NULL; - - REQUIRE(VALID_QID(qid)); - REQUIRE(bucket < qid->qid_nbuckets); - - dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); - - while (dispsock != NULL) { - if (dispsock->port == port && - isc_sockaddr_equal(dest, &dispsock->host)) { - return (dispsock); - } - dispsock = ISC_LIST_NEXT(dispsock, blink); - } - - return (NULL); -} - /*% * Make a new socket for a single dispatch with a random port number. * The caller must hold the disp->lock */ static isc_result_t get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, - isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp, - in_port_t *portp) { - int i; + dispsocket_t **dispsockp, in_port_t *portp) { dns_dispatchmgr_t *mgr = disp->mgr; - dns_qid_t *qid = mgr->qid; - isc_socket_t *sock = NULL; - isc_result_t result = ISC_R_FAILURE; in_port_t port; - isc_sockaddr_t localaddr; - unsigned int bucket = 0; dispsocket_t *dispsock = NULL; unsigned int nports; in_port_t *ports = NULL; @@ -597,71 +530,23 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, dispsock = ISC_LIST_HEAD(disp->inactivesockets); if (dispsock != NULL) { ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link); - sock = dispsock->socket; - dispsock->socket = NULL; } else { dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock)); - disp->nsockets++; *dispsock = (dispsocket_t){ .disp = disp }; - isc_task_attach(disp->task[isc_random_uniform(disp->ntasks)], - &dispsock->task); ISC_LINK_INIT(dispsock, link); - ISC_LINK_INIT(dispsock, blink); dispsock->magic = DISPSOCK_MAGIC; } - /* - * Pick up a random UDP port and open a new socket with it. Avoid - * choosing ports that share the same destination because it will be - * very likely to fail in bind(2) or connect(2). - */ - localaddr = disp->local; + dispsock->local = disp->local; + dispsock->peer = *dest; - for (i = 0; i < 64; i++) { - port = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&localaddr, port); - - LOCK(&qid->lock); - bucket = dns_hash(qid, dest, 0, port); - if (socket_search(qid, dest, port, bucket) != NULL) { - UNLOCK(&qid->lock); - continue; - } - UNLOCK(&qid->lock); - - result = open_socket(sockmgr, &localaddr, - ISC_SOCKET_REUSEADDRESS, &sock); - if (result == ISC_R_SUCCESS) { - break; - } else if (result == ISC_R_NOPERM) { - char buf[ISC_SOCKADDR_FORMATSIZE]; - isc_sockaddr_format(&localaddr, buf, sizeof(buf)); - dispatch_log(disp, ISC_LOG_WARNING, - "open_socket(%s) -> %s: continuing", buf, - isc_result_totext(result)); - } else if (result != ISC_R_ADDRINUSE) { - break; - } - } - - if (result != ISC_R_SUCCESS) { - if (sock != NULL) { - isc_socket_detach(&sock); - } - destroy_dispsocket(disp, &dispsock); - return (result); - } - - dispsock->socket = sock; - dispsock->host = *dest; - dispsock->bucket = bucket; + /* Pick a random UDP port */ + port = ports[isc_random_uniform(nports)]; + isc_sockaddr_setport(&dispsock->local, port); dispsock->port = port; - LOCK(&qid->lock); - ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); - UNLOCK(&qid->lock); *dispsockp = dispsock; *portp = port; @@ -670,77 +555,52 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, /*% * Destroy a dedicated dispatch socket. + * The dispatch must be locked. */ static void destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { dispsocket_t *dispsock = NULL; - dns_qid_t *qid = disp->mgr->qid; - - /* - * The dispatch must be locked. - */ REQUIRE(dispsockp != NULL && *dispsockp != NULL); + dispsock = *dispsockp; *dispsockp = NULL; + REQUIRE(!ISC_LINK_LINKED(dispsock, link)); disp->nsockets--; dispsock->magic = 0; - if (dispsock->socket != NULL) { - isc_socket_detach(&dispsock->socket); - } - if (ISC_LINK_LINKED(dispsock, blink)) { - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, - blink); - UNLOCK(&qid->lock); - } - if (dispsock->task != NULL) { - isc_task_detach(&dispsock->task); + if (dispsock->handle != NULL) { + isc_nm_cancelread(dispsock->handle); + isc_nmhandle_detach(&dispsock->handle); } + isc_mem_put(disp->mgr->mctx, dispsock, sizeof(*dispsock)); } /*% * Deactivate a dedicated dispatch socket. Move it to the inactive list for * future reuse unless the total number of sockets are exceeding the maximum. + * The dispatch must be locked. */ static void deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_result_t result; - dns_qid_t *qid = disp->mgr->qid; - - /* - * The dispatch must be locked. - */ ISC_LIST_UNLINK(disp->activesockets, dispsock, link); if (dispsock->resp != NULL) { INSIST(dispsock->resp->dispsocket == dispsock); dispsock->resp->dispsocket = NULL; + dispsock->resp = NULL; } if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) { destroy_dispsocket(disp, &dispsock); } else { - result = isc_socket_close(dispsock->socket); - - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, - blink); - UNLOCK(&qid->lock); - - if (result == ISC_R_SUCCESS) { - ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); - } else { - /* - * If the underlying system does not allow this - * optimization, destroy this temporary structure (and - * create a new one for a new transaction). - */ - INSIST(result == ISC_R_NOTIMPLEMENTED); - destroy_dispsocket(disp, &dispsock); + if (dispsock->handle != NULL) { + isc_nm_cancelread(dispsock->handle); + isc_nmhandle_detach(&dispsock->handle); } + + ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); } } @@ -760,7 +620,7 @@ entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, res = ISC_LIST_HEAD(qid->qid_table[bucket]); while (res != NULL) { - if (res->id == id && isc_sockaddr_equal(dest, &res->host) && + if (res->id == id && isc_sockaddr_equal(dest, &res->peer) && res->port == port) { return (res); } @@ -775,12 +635,12 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { REQUIRE(buf != NULL && len != 0); switch (disp->socktype) { - case isc_sockettype_tcp: + case isc_socktype_tcp: INSIST(disp->tcpbuffers > 0); disp->tcpbuffers--; isc_mem_put(disp->mgr->mctx, buf, len); break; - case isc_sockettype_udp: + case isc_socktype_udp: LOCK(&disp->mgr->buffer_lock); INSIST(disp->mgr->buffers > 0); INSIST(len == DNS_DISPATCH_UDPBUFSIZE); @@ -807,33 +667,6 @@ allocate_udp_buffer(dns_dispatch_t *disp) { return (isc_mem_get(disp->mgr->mctx, DNS_DISPATCH_UDPBUFSIZE)); } -static inline void -free_sevent(isc_event_t *ev) { - isc_mem_t *pool = ev->ev_destroy_arg; - isc_socketevent_t *sev = (isc_socketevent_t *)ev; - isc_mem_put(pool, sev, sizeof(*sev)); -} - -static inline isc_socketevent_t * -allocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock, isc_eventtype_t type, - isc_taskaction_t action, const void *arg) { - isc_socketevent_t *ev = NULL; - void *deconst_arg; - - ev = isc_mem_get(disp->sepool, sizeof(*ev)); - DE_CONST(arg, deconst_arg); - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type, action, deconst_arg, - sock, free_sevent, disp->sepool); - ev->result = ISC_R_UNSET; - ISC_LINK_INIT(ev, ev_link); - ev->region.base = NULL; - ev->n = 0; - ev->offset = 0; - ev->attributes = 0; - - return (ev); -} - static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { if (disp->failsafe_ev == ev) { @@ -843,6 +676,12 @@ free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { return; } + if (ev->region.base != NULL) { + free_buffer(disp, ev->region.base, ev->region.length); + ev->region.base = NULL; + ev->region.length = 0; + } + isc_refcount_decrement(&disp->mgr->irefs); isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev)); } @@ -853,6 +692,8 @@ allocate_devent(dns_dispatch_t *disp) { ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); isc_refcount_increment0(&disp->mgr->irefs); + + *ev = (dns_dispatchevent_t){ 0 }; ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, NULL); return (ev); @@ -873,9 +714,9 @@ allocate_devent(dns_dispatch_t *disp) { * restart. */ static void -udp_recv(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - dispsocket_t *dispsock = NULL; +udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg) { + dispsocket_t *dispsock = (dispsocket_t *)arg; dns_dispatch_t *disp = NULL; dns_messageid_t id; isc_result_t dres; @@ -886,15 +727,10 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { bool killit; bool queue_response; dns_dispatchmgr_t *mgr = NULL; + isc_sockaddr_t peer; isc_netaddr_t netaddr; + isc_taskaction_t action; int match; - int result; - - UNUSED(task); - - REQUIRE(ev->ev_type == ISC_SOCKEVENT_RECVDONE); - - dispsock = ev_in->ev_arg; REQUIRE(VALID_DISPSOCK(dispsock)); @@ -905,44 +741,32 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { mgr = disp->mgr; LOCK(&disp->mgr->buffer_lock); - dispatch_log(disp, LVL(90), - "got packet: requests %d, buffers %d, recvs %d", - disp->requests, disp->mgr->buffers, disp->recv_pending); + dispatch_log(disp, LVL(90), "got packet: requests %d, recvs %d", + disp->requests, disp->recv_pending); UNLOCK(&disp->mgr->buffer_lock); - if (ev->result == ISC_R_CANCELED || dispsock->resp == NULL) { + if (eresult == ISC_R_CANCELED || dispsock->resp == NULL) { /* * dispsock->resp can be NULL if this transaction was canceled - * just after receiving a response. Since this socket is - * exclusively used and there should be at most one receive - * event the canceled event should have no effect. So - * we can (and should) deactivate the socket right now. + * just after receiving a response. So we can just move on. */ - deactivate_dispsocket(disp, dispsock); dispsock = NULL; } - if (disp->shutting_down) { + if (disp->shutting_down == 1) { /* * This dispatcher is shutting down. */ - free_buffer(disp, ev->region.base, ev->region.length); - - isc_event_free(&ev_in); - ev = NULL; - killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + isc_task_send(disp->task, &disp->ctlevent); } return; } if (dispsock == NULL) { - free_buffer(disp, ev->region.base, ev->region.length); - isc_event_free(&ev_in); UNLOCK(&disp->lock); return; } @@ -950,20 +774,22 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { resp = dispsock->resp; id = resp->id; - if (ev->result != ISC_R_SUCCESS) { + peer = isc_nmhandle_peeraddr(handle); + isc_netaddr_fromsockaddr(&netaddr, &peer); + + if (eresult != ISC_R_SUCCESS) { /* - * This is most likely a network error on a - * connected socket. It makes no sense to + * This is most likely either a timeout or a network + * error on a connected socket. It makes no sense to * check the address or parse the packet, but it * will help to return the error to the caller. */ - goto sendresponse; + goto sendevent; } /* * If this is from a blackholed address, drop it. */ - isc_netaddr_fromsockaddr(&netaddr, &ev->address); if (disp->mgr->blackhole != NULL && dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match, NULL) == ISC_R_SUCCESS && @@ -976,20 +802,18 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { dispatch_log(disp, LVL(10), "blackholed packet from %s", netaddrstr); } - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } /* * Peek into the buffer to see what we can see. */ - isc_buffer_init(&source, ev->region.base, ev->region.length); - isc_buffer_add(&source, ev->n); + isc_buffer_init(&source, region->base, region->length); + isc_buffer_add(&source, region->length); dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { - free_buffer(disp, ev->region.base, ev->region.length); dispatch_log(disp, LVL(10), "got garbage packet"); - goto restart; + goto next; } dispatch_log(disp, LVL(92), @@ -1002,105 +826,55 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* query */ - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } /* * The QID and the address must match the expected ones. */ - if (resp->id != id || !isc_sockaddr_equal(&ev->address, &resp->host)) { + if (resp->id != id || !isc_sockaddr_equal(&peer, &resp->peer)) { dispatch_log(disp, LVL(90), "response doesn't match"); inc_stats(mgr, dns_resstatscounter_mismatch); - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; + goto next; } - /* - * Now that we have the original dispatch the query was sent - * from check that the address and port the response was - * sent to make sense. - */ - if (disp != resp->disp) { - isc_sockaddr_t a1; - isc_sockaddr_t a2; - - /* - * Check that the socket types and ports match. - */ - if (disp->socktype != resp->disp->socktype || - isc_sockaddr_getport(&disp->local) != - isc_sockaddr_getport(&resp->disp->local)) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; - } - - /* - * If each dispatch is bound to a different address - * then fail. - * - * Note under Linux a packet can be sent out via IPv4 socket - * and the response be received via a IPv6 socket. - * - * Requests sent out via IPv6 should always come back in - * via IPv6. - */ - if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 && - isc_sockaddr_pf(&disp->local) != PF_INET6) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; - } - isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); - isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); - if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) && - !isc_sockaddr_eqaddr(&a1, &resp->disp->local) && - !isc_sockaddr_eqaddr(&a2, &disp->local)) - { - free_buffer(disp, ev->region.base, ev->region.length); - goto restart; - } - } - -sendresponse: +sendevent: + rev = allocate_devent(disp); queue_response = resp->item_out; - rev = allocate_devent(resp->disp); /* * At this point, rev contains the event we want to fill in, and * resp contains the information on the place to send it to. * Send the event off. */ - isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length); - isc_buffer_add(&rev->buffer, ev->n); - rev->result = ev->result; - rev->id = id; - rev->addr = ev->address; - rev->pktinfo = ev->pktinfo; - rev->attributes = ev->attributes; + rev->result = eresult; + resp->item_out = true; + if (region != NULL) { + rev->region.base = allocate_udp_buffer(disp); + rev->region.length = DNS_DISPATCH_UDPBUFSIZE; + memmove(rev->region.base, region->base, region->length); + isc_buffer_init(&rev->buffer, rev->region.base, + rev->region.length); + isc_buffer_add(&rev->buffer, rev->region.length); + } + + rev->result = eresult; if (queue_response) { ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); + action, resp->arg, resp, NULL, NULL); request_log(disp, resp, LVL(90), "[a] Sent event %p buffer %p len %d to task %p", rev, rev->buffer.base, rev->buffer.length, resp->task); - resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } - /* - * Restart recv() to get the next packet. - */ -restart: - result = startrecv(disp, dispsock); - if (result != ISC_R_SUCCESS) { - deactivate_dispsocket(disp, dispsock); - } - isc_event_free(&ev_in); + UNLOCK(&disp->lock); + return; + +next: UNLOCK(&disp->lock); } @@ -1120,9 +894,9 @@ restart: * restart. */ static void -tcp_recv(isc_task_t *task, isc_event_t *ev_in) { - dns_dispatch_t *disp = ev_in->ev_arg; - tcpmsg_t *tcpmsg = &disp->tcpmsg; +tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *arg) { + dns_dispatch_t *disp = (dns_dispatch_t *)arg; dns_messageid_t id; isc_result_t dres; unsigned int flags; @@ -1134,8 +908,9 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { dns_qid_t *qid = NULL; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; - - UNUSED(task); + isc_buffer_t source; + isc_sockaddr_t peer; + isc_taskaction_t action; REQUIRE(VALID_DISPATCH(disp)); @@ -1154,11 +929,16 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { /* * This dispatcher is shutting down. Force cancellation. */ - tcpmsg->result = ISC_R_CANCELED; + eresult = ISC_R_CANCELED; } - if (tcpmsg->result != ISC_R_SUCCESS) { - switch (tcpmsg->result) { + peer = isc_nmhandle_peeraddr(handle); + isc_nmhandle_detach(&handle); + + if (eresult != ISC_R_SUCCESS) { + disp->shutdown_why = eresult; + + switch (eresult) { case ISC_R_CANCELED: break; @@ -1171,27 +951,23 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { level = ISC_LOG_INFO; goto logit; + case ISC_R_TIMEDOUT: + id = 0; /* XXX this is broken */ + goto sendevent; + default: level = ISC_LOG_ERROR; logit: - isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf)); + isc_sockaddr_format(&peer, buf, sizeof(buf)); dispatch_log(disp, level, "shutting down due to TCP " "receive error: %s: %s", - buf, isc_result_totext(tcpmsg->result)); + buf, isc_result_totext(eresult)); do_cancel(disp); break; } - /* - * The event is statically allocated in the tcpmsg - * structure, and destroy_disp() frees the tcpmsg, so we must - * free the event *before* calling destroy_disp(). - */ - isc_event_free(&ev_in); - disp->shutting_down = 1; - disp->shutdown_why = tcpmsg->result; /* * If the recv() was canceled pass the word on. @@ -1199,22 +975,23 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + isc_task_send(disp->task, &disp->ctlevent); } return; } dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", - tcpmsg->result, disp->tcpmsg.buffer.length, - disp->tcpmsg.buffer.base); + eresult, region->length, region->base); /* * Peek into the buffer to see what we can see. */ - dres = dns_message_peekheader(&disp->tcpmsg.buffer, &id, &flags); + isc_buffer_init(&source, region->base, region->length); + isc_buffer_add(&source, region->length); + dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { dispatch_log(disp, LVL(10), "got garbage packet"); - goto restart; + goto next; } dispatch_log(disp, LVL(92), @@ -1234,19 +1011,21 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { /* * Query. */ - goto restart; + goto next; } +sendevent: /* * Response. */ - bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport); + bucket = dns_hash(qid, &peer, id, disp->localport); LOCK(&qid->lock); - resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket); + resp = entry_search(qid, &peer, id, disp->localport, bucket); dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); if (resp == NULL) { - goto unlock; + UNLOCK(&qid->lock); + goto next; } queue_response = resp->item_out; @@ -1257,212 +1036,36 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { * resp contains the information on the place to send it to. * Send the event off. */ - rev->buffer = disp->tcpmsg.buffer; - disp->tcpmsg.buffer.base = NULL; - disp->tcpmsg.buffer.length = 0; + rev->result = eresult; + resp->item_out = true; + if (region != NULL) { + disp->tcpbuffers++; + rev->region.base = isc_mem_get(disp->mgr->mctx, region->length); + rev->region.length = region->length; + memmove(rev->region.base, region->base, region->length); + isc_buffer_init(&rev->buffer, rev->region.base, + rev->region.length); + isc_buffer_add(&rev->buffer, rev->region.length); + } - disp->tcpbuffers++; - rev->result = ISC_R_SUCCESS; - rev->id = id; - rev->addr = tcpmsg->address; if (queue_response) { ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); + action, resp->arg, resp, NULL, NULL); request_log(disp, resp, LVL(90), "[b] Sent event %p buffer %p len %d to task %p", rev, rev->buffer.base, rev->buffer.length, resp->task); - resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } -unlock: UNLOCK(&qid->lock); - /* - * Restart recv() to get the next packet. - */ -restart: - (void)startrecv(disp, NULL); - - isc_event_free(&ev_in); +next: + startrecv(disp, NULL); UNLOCK(&disp->lock); } -static void -recv_tcpmsg(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - tcpmsg_t *tcpmsg = ev_in->ev_arg; - isc_event_t *dev = &tcpmsg->event; - - UNUSED(task); - - tcpmsg->address = ev->address; - - if (ev->result != ISC_R_SUCCESS) { - tcpmsg->result = ev->result; - goto send_and_free; - } - - tcpmsg->result = ISC_R_SUCCESS; - isc_buffer_add(&tcpmsg->buffer, ev->n); - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); -} - -static void -recv_tcplen(isc_task_t *task, isc_event_t *ev_in) { - isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; - tcpmsg_t *tcpmsg = ev_in->ev_arg; - isc_event_t *dev = &tcpmsg->event; - isc_region_t region; - isc_result_t result; - - tcpmsg->address = ev->address; - - if (ev->result != ISC_R_SUCCESS) { - tcpmsg->result = ev->result; - goto send_and_free; - } - - /* - * Success. - */ - tcpmsg->size = ntohs(tcpmsg->size); - if (tcpmsg->size == 0) { - tcpmsg->result = ISC_R_UNEXPECTEDEND; - goto send_and_free; - } - - region.base = isc_mem_get(tcpmsg->disp->mgr->mctx, tcpmsg->size); - region.length = tcpmsg->size; - if (region.base == NULL) { - tcpmsg->result = ISC_R_NOMEMORY; - goto send_and_free; - } - - isc_buffer_init(&tcpmsg->buffer, region.base, region.length); - result = isc_socket_recv(tcpmsg->disp->socket, ®ion, 0, task, - recv_tcpmsg, tcpmsg); - if (result != ISC_R_SUCCESS) { - tcpmsg->result = result; - goto send_and_free; - } - - isc_event_free(&ev_in); - return; - -send_and_free: - isc_task_send(tcpmsg->task, &dev); - tcpmsg->task = NULL; - isc_event_free(&ev_in); - return; -} - -static isc_result_t -tcp_readmessage(tcpmsg_t *tcpmsg, isc_task_t *task, isc_taskaction_t action, - void *arg) { - isc_result_t result; - isc_region_t region; - - REQUIRE(task != NULL); - REQUIRE(tcpmsg->task == NULL); /* not currently in use */ - - if (tcpmsg->buffer.base != NULL) { - isc_mem_put(tcpmsg->disp->mgr->mctx, tcpmsg->buffer.base, - tcpmsg->buffer.length); - tcpmsg->buffer.base = NULL; - tcpmsg->buffer.length = 0; - } - - tcpmsg->task = task; - tcpmsg->action = action; - tcpmsg->arg = arg; - tcpmsg->result = ISC_R_UNEXPECTED; /* unknown right now */ - - ISC_EVENT_INIT(&tcpmsg->event, sizeof(isc_event_t), 0, 0, - DNS_EVENT_TCPMSG, action, arg, tcpmsg, NULL, NULL); - - region.base = (unsigned char *)&tcpmsg->size; - region.length = 2; /* uint16_t */ - result = isc_socket_recv(tcpmsg->disp->socket, ®ion, 0, tcpmsg->task, - recv_tcplen, tcpmsg); - - if (result != ISC_R_SUCCESS) { - tcpmsg->task = NULL; - } - - return (result); -} - -/* - * disp must be locked. - */ -static isc_result_t -startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { - isc_result_t res; - isc_region_t region; - isc_socket_t *sock = NULL; - isc_socketevent_t *sev = NULL; - - if (disp->shutting_down == 1) { - return (ISC_R_SUCCESS); - } - - if (dispsock == NULL) { - if (disp->socktype == isc_sockettype_udp || - disp->recv_pending != 0) { - return (ISC_R_SUCCESS); - } - sock = disp->socket; - } else { - sock = dispsock->socket; - } - - switch (disp->socktype) { - /* - * UDP reads are always maximal. - */ - case isc_sockettype_udp: - region.length = DNS_DISPATCH_UDPBUFSIZE; - region.base = allocate_udp_buffer(disp); - if (region.base == NULL) { - return (ISC_R_NOMEMORY); - } - sev = allocate_sevent(disp, sock, ISC_SOCKEVENT_RECVDONE, - udp_recv, dispsock); - res = isc_socket_recv2(sock, ®ion, 1, dispsock->task, sev, - 0); - if (res != ISC_R_SUCCESS) { - free_buffer(disp, region.base, region.length); - return (res); - } - break; - - case isc_sockettype_tcp: - res = tcp_readmessage(&disp->tcpmsg, disp->task[0], tcp_recv, - disp); - if (res != ISC_R_SUCCESS) { - disp->shutdown_why = res; - disp->shutting_down = 1; - do_cancel(disp); - return (ISC_R_SUCCESS); /* recover by cancel */ - } - INSIST(disp->recv_pending == 0); - disp->recv_pending = 1; - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } - - return (ISC_R_SUCCESS); -} - /* * Mgr must be locked when calling this function. */ @@ -1520,48 +1123,12 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { isc_mem_put(mgr->mctx, mgr->v6ports, mgr->nv6ports * sizeof(in_port_t)); } + + isc_nm_detach(&mgr->nm); + isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); } -static isc_result_t -open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, - unsigned int options, isc_socket_t **sockp) { - isc_socket_t *sock = NULL; - isc_result_t result; - - sock = *sockp; - if (sock != NULL) { - result = isc_socket_open(sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - } else { - result = isc_socket_create(mgr, isc_sockaddr_pf(local), - isc_sockettype_udp, &sock); - if (result != ISC_R_SUCCESS) { - return (result); - } - } - - isc_socket_setname(sock, "dispatcher", NULL); - -#ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(sock, true); -#endif /* ifndef ISC_ALLOW_MAPPED */ - result = isc_socket_bind(sock, local, options); - if (result != ISC_R_SUCCESS) { - if (*sockp == NULL) { - isc_socket_detach(&sock); - } else { - isc_socket_close(sock); - } - return (result); - } - - *sockp = sock; - return (ISC_R_SUCCESS); -} - /*% * Create a temporary port list to set the initial default set of dispatch * ports: [1024, 65535]. This is almost meaningless as the application will @@ -1626,7 +1193,8 @@ setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, */ isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { +dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, + dns_dispatchmgr_t **mgrp) { dns_dispatchmgr_t *mgr = NULL; isc_portset_t *v4portset = NULL; isc_portset_t *v6portset = NULL; @@ -1635,15 +1203,16 @@ dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { REQUIRE(mgrp != NULL && *mgrp == NULL); mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); - *mgr = (dns_dispatchmgr_t){ 0 }; + *mgr = (dns_dispatchmgr_t){ .magic = 0 }; + + isc_refcount_init(&mgr->irefs, 0); isc_mem_attach(mctx, &mgr->mctx); + isc_nm_attach(nm, &mgr->nm); isc_mutex_init(&mgr->lock); isc_mutex_init(&mgr->buffer_lock); - isc_refcount_init(&mgr->irefs, 0); - ISC_LIST_INIT(mgr->list); create_default_portset(mctx, &v4portset); @@ -1728,16 +1297,11 @@ qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp) { qid->qid_table = isc_mem_get(mgr->mctx, DNS_QID_BUCKETS * sizeof(dns_displist_t)); - qid->sock_table = isc_mem_get( - mgr->mctx, DNS_QID_BUCKETS * sizeof(dispsocketlist_t)); - - isc_mutex_init(&qid->lock); - for (i = 0; i < qid->qid_nbuckets; i++) { ISC_LIST_INIT(qid->qid_table[i]); - ISC_LIST_INIT(qid->sock_table[i]); } + isc_mutex_init(&qid->lock); qid->magic = QID_MAGIC; *qidp = qid; } @@ -1755,8 +1319,6 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { qid->magic = 0; isc_mem_put(mctx, qid->qid_table, qid->qid_nbuckets * sizeof(dns_displist_t)); - isc_mem_put(mctx, qid->sock_table, - qid->qid_nbuckets * sizeof(dispsocketlist_t)); isc_mutex_destroy(&qid->lock); isc_mem_put(mctx, qid, sizeof(*qid)); } @@ -1765,7 +1327,7 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { * Allocate and set important limits. */ static void -dispatch_allocate(dns_dispatchmgr_t *mgr, isc_sockettype_t type, int pf, +dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf, unsigned int attributes, dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; @@ -1789,10 +1351,10 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_sockettype_t type, int pf, ISC_LIST_INIT(disp->inactivesockets); switch (type) { - case isc_sockettype_tcp: + case isc_socktype_tcp: disp->attributes |= DNS_DISPATCHATTR_TCP; break; - case isc_sockettype_udp: + case isc_socktype_udp: disp->attributes |= DNS_DISPATCHATTR_UDP; break; default: @@ -1842,25 +1404,18 @@ dispatch_free(dns_dispatch_t **dispp) { mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); - if (disp->tcpmsg_valid) { - if (disp->tcpmsg.buffer.base != NULL) { - isc_mem_put(disp->mgr->mctx, disp->tcpmsg.buffer.base, - disp->tcpmsg.buffer.length); - disp->tcpmsg.buffer.base = NULL; - disp->tcpmsg.buffer.length = 0; - } - disp->tcpmsg_valid = 0; - } - - INSIST(disp->tcpbuffers == 0); INSIST(disp->requests == 0); INSIST(disp->recv_pending == 0); INSIST(ISC_LIST_EMPTY(disp->activesockets)); INSIST(ISC_LIST_EMPTY(disp->inactivesockets)); isc_refcount_decrement(&mgr->irefs); - isc_mem_put(mgr->mctx, disp->failsafe_ev, sizeof(*disp->failsafe_ev)); - disp->failsafe_ev = NULL; + + if (disp->failsafe_ev != NULL) { + isc_mem_put(mgr->mctx, disp->failsafe_ev, + sizeof(*disp->failsafe_ev)); + disp->failsafe_ev = NULL; + } disp->mgr = NULL; isc_mutex_destroy(&disp->lock); @@ -1870,74 +1425,43 @@ dispatch_free(dns_dispatch_t **dispp) { } isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, const isc_sockaddr_t *destaddr, unsigned int attributes, isc_dscp_t dscp, dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; - isc_sockaddr_t src; int pf; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(sockmgr != NULL); REQUIRE(destaddr != NULL); + UNUSED(dscp); + LOCK(&mgr->lock); pf = isc_sockaddr_pf(destaddr); - dispatch_allocate(mgr, isc_sockettype_tcp, pf, attributes, &disp); + dispatch_allocate(mgr, isc_socktype_tcp, pf, attributes, &disp); disp->peer = *destaddr; if (localaddr != NULL) { disp->local = *localaddr; } else { - switch (pf) { - case AF_INET: - isc_sockaddr_any(&disp->local); - break; - case AF_INET6: - isc_sockaddr_any6(&disp->local); - break; - } + isc_sockaddr_anyofpf(&disp->local, pf); + isc_sockaddr_setport(&disp->local, 0); } - disp->ntasks = 1; - disp->task[0] = NULL; - result = isc_task_create(taskmgr, 50, &disp->task[0]); + result = isc_task_create(taskmgr, 50, &disp->task); if (result != ISC_R_SUCCESS) { goto cleanup; } - result = isc_socket_create(sockmgr, isc_sockaddr_pf(destaddr), - isc_sockettype_tcp, &disp->socket); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - if (localaddr == NULL) { - isc_sockaddr_anyofpf(&src, pf); - } else { - src = *localaddr; - isc_sockaddr_setport(&src, 0); - } - - result = isc_socket_bind(disp->socket, &src, 0); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - isc_socket_dscp(disp->socket, dscp); - disp->ctlevent = isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, destroy_disp, disp, sizeof(isc_event_t)); - isc_task_setname(disp->task[0], "tcpdispatch", disp); - - disp->tcpmsg = (tcpmsg_t){ .disp = disp, .result = ISC_R_UNEXPECTED }; - disp->tcpmsg_valid = 1; + isc_task_setname(disp->task, "tcpdispatch", disp); /* * Append it to the dispatcher list. @@ -1949,14 +1473,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, mgr_log(mgr, LVL(90), "dns_dispatch_createtcp: created TCP dispatch %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); + dispatch_log(disp, LVL(90), "created task %p", disp->task); } *dispp = disp; return (ISC_R_SUCCESS); cleanup: - isc_socket_detach(&disp->socket); dispatch_free(&disp); UNLOCK(&mgr->lock); @@ -1971,7 +1494,6 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, const isc_sockaddr_t *localaddr, bool *connected, dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; - isc_result_t result; isc_sockaddr_t peeraddr; isc_sockaddr_t sockname; unsigned int attributes, mask; @@ -1995,14 +1517,9 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, (localaddr == NULL || isc_sockaddr_eqaddr(localaddr, &disp->local))) { - result = isc_socket_getsockname(disp->socket, - &sockname); - if (result == ISC_R_SUCCESS) { - result = isc_socket_getpeername(disp->socket, - &peeraddr); - } - if (result == ISC_R_SUCCESS && - isc_sockaddr_equal(destaddr, &peeraddr) && + sockname = isc_nmhandle_localaddr(disp->handle); + peeraddr = isc_nmhandle_peeraddr(disp->handle); + if (isc_sockaddr_equal(destaddr, &peeraddr) && (localaddr == NULL || isc_sockaddr_eqaddr(localaddr, &sockname))) { @@ -2049,21 +1566,19 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, } isc_result_t -dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp) { +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp) { isc_result_t result; dns_dispatch_t *disp = NULL; REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(sockmgr != NULL); REQUIRE(localaddr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(dispp != NULL && *dispp == NULL); LOCK(&mgr->lock); - result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr, - attributes, &disp); + result = dispatch_createudp(mgr, taskmgr, localaddr, attributes, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -2073,32 +1588,25 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, } static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp) { +dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp) { isc_result_t result = ISC_R_SUCCESS; dns_dispatch_t *disp = NULL; - isc_socket_t *sock = NULL; isc_sockaddr_t sa_any; - int pf, i = 0; + int pf; pf = isc_sockaddr_pf(localaddr); - dispatch_allocate(mgr, isc_sockettype_udp, pf, attributes, &disp); + dispatch_allocate(mgr, isc_socktype_udp, pf, attributes, &disp); /* - * For dispatches with a specified source address, we open a - * socket to make sure that address is available on the system, - * but we don't keep it open; sockets used for sending requests - * will be created later on demand. + * Check whether this address/port is available locally. */ isc_sockaddr_anyofpf(&sa_any, pf); if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { - result = open_socket(sockmgr, localaddr, 0, &sock); - if (sock != NULL) { - isc_socket_detach(&sock); - } + result = isc_nm_checkaddr(localaddr, isc_socktype_udp); if (result != ISC_R_SUCCESS) { - goto deallocate_dispatch; + goto cleanup; } } @@ -2112,21 +1620,10 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, addrbuf); } - disp->socket = sock; disp->local = *localaddr; - disp->ntasks = MAX_INTERNAL_TASKS; - - for (i = 0; i < disp->ntasks; i++) { - disp->task[i] = NULL; - result = isc_task_create(taskmgr, 0, &disp->task[i]); - if (result != ISC_R_SUCCESS) { - while (--i >= 0) { - isc_task_shutdown(disp->task[i]); - isc_task_detach(&disp->task[i]); - } - goto kill_socket; - } - isc_task_setname(disp->task[i], "udpdispatch", disp); + result = isc_task_create(taskmgr, 0, &disp->task); + if (result != ISC_R_SUCCESS) { + goto cleanup; } disp->ctlevent = @@ -2143,10 +1640,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, ISC_LIST_APPEND(mgr->list, disp, link); mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */ - if (disp->socket != NULL) { - dispatch_log(disp, LVL(90), "created socket %p", disp->socket); - } + dispatch_log(disp, LVL(90), "created task %p", disp->task); *dispp = disp; @@ -2155,11 +1649,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, /* * Error returns. */ -kill_socket: - if (disp->socket != NULL) { - isc_socket_detach(&disp->socket); - } -deallocate_dispatch: +cleanup: dispatch_free(&disp); return (result); @@ -2178,60 +1668,67 @@ void dns_dispatch_detach(dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; dispsocket_t *dispsock = NULL; - bool killit; + bool killit = false; REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); disp = *dispp; *dispp = NULL; - LOCK(&disp->lock); if (isc_refcount_decrement(&disp->refcount) == 1) { - if (disp->recv_pending > 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); + LOCK(&disp->lock); + if (disp->recv_pending != 0 && disp->handle != NULL) { + isc_nm_cancelread(disp->handle); + } + if (disp->handle != NULL) { + isc_nmhandle_detach(&disp->handle); } for (dispsock = ISC_LIST_HEAD(disp->activesockets); dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) { - isc_socket_cancel(dispsock->socket, dispsock->task, - ISC_SOCKCANCEL_RECV); + if (dispsock->handle != NULL) { + isc_nmhandle_detach(&dispsock->handle); + } } disp->shutting_down = 1; + do_cancel(disp); + + killit = destroy_disp_ok(disp); + UNLOCK(&disp->lock); } dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, isc_refcount_current(&disp->refcount)); - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); + isc_task_send(disp->task, &disp->ctlevent); } } isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, - const isc_sockaddr_t *dest, isc_task_t *task, - isc_taskaction_t action, void *arg, - dns_messageid_t *idp, dns_dispentry_t **resp, - isc_socketmgr_t *sockmgr) { + unsigned int timeout, const isc_sockaddr_t *dest, + isc_task_t *task, isc_nm_cb_t connected, + isc_nm_cb_t sent, isc_taskaction_t action, + isc_taskaction_t timeout_action, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp) { + isc_result_t result; dns_dispentry_t *res = NULL; - unsigned int bucket; + dispsocket_t *dispsocket = NULL; + dns_qid_t *qid = NULL; in_port_t localport = 0; dns_messageid_t id; - int i = 0; + unsigned int bucket; bool ok = false; - dns_qid_t *qid = NULL; - dispsocket_t *dispsocket = NULL; - isc_result_t result; + int i = 0; REQUIRE(VALID_DISPATCH(disp)); REQUIRE(task != NULL); REQUIRE(dest != NULL); REQUIRE(resp != NULL && *resp == NULL); REQUIRE(idp != NULL); - REQUIRE(disp->socktype == isc_sockettype_tcp || sockmgr != NULL); + REQUIRE(disp->socktype == isc_socktype_tcp || + disp->socktype == isc_socktype_udp); LOCK(&disp->lock); @@ -2247,7 +1744,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, qid = disp->mgr->qid; - if (disp->socktype == isc_sockettype_udp && + if (disp->socktype == isc_socktype_udp && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { dispsocket_t *oldestsocket = NULL; @@ -2264,7 +1761,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, rev = allocate_devent(oldestresp->disp); rev->buffer.base = NULL; rev->result = ISC_R_CANCELED; - rev->id = oldestresp->id; ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, oldestresp->action, oldestresp->arg, oldestresp, NULL, NULL); @@ -2281,12 +1777,11 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ISC_LIST_APPEND(disp->activesockets, oldestsocket, link); } - if (disp->socktype == isc_sockettype_udp) { + if (disp->socktype == isc_socktype_udp) { /* * Get a separate UDP socket with a random port number. */ - result = get_dispsocket(disp, dest, sockmgr, &dispsocket, - &localport); + result = get_dispsocket(disp, dest, &dispsocket, &localport); if (result != ISC_R_SUCCESS) { UNLOCK(&disp->lock); inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); @@ -2326,20 +1821,26 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); isc_refcount_increment0(&disp->mgr->irefs); - *res = (dns_dispentry_t){ .disp = disp, - .id = id, + + *res = (dns_dispentry_t){ .id = id, .port = localport, .bucket = bucket, - .host = *dest, + .timeout = timeout, + .peer = *dest, + .connected = connected, + .sent = sent, .action = action, + .timeout_action = timeout_action, .arg = arg, .dispsocket = dispsocket }; + + dns_dispatch_attach(disp, &res->disp); isc_task_attach(task, &res->task); + ISC_LIST_INIT(res->items); ISC_LINK_INIT(res, link); res->magic = RESPONSE_MAGIC; - isc_refcount_increment(&disp->refcount); disp->requests++; if (dispsocket != NULL) { @@ -2350,40 +1851,11 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); - inc_stats(disp->mgr, (disp->socktype == isc_sockettype_udp) - ? dns_resstatscounter_disprequdp - : dns_resstatscounter_dispreqtcp); - request_log(disp, res, LVL(90), "attached to task %p", res->task); - if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) || - ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) - { - result = startrecv(disp, dispsocket); - if (result != ISC_R_SUCCESS) { - LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); - UNLOCK(&qid->lock); - - if (dispsocket != NULL) { - destroy_dispsocket(disp, &dispsocket); - } - - isc_refcount_decrement(&disp->refcount); - disp->requests--; - - dec_stats(disp->mgr, - (disp->socktype == isc_sockettype_udp) - ? dns_resstatscounter_disprequdp - : dns_resstatscounter_dispreqtcp); - - UNLOCK(&disp->lock); - isc_task_detach(&res->task); - isc_refcount_decrement(&disp->mgr->irefs); - isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - return (result); - } - } + inc_stats(disp->mgr, (disp->socktype == isc_socktype_udp) + ? dns_resstatscounter_disprequdp + : dns_resstatscounter_dispreqtcp); if (dispsocket != NULL) { ISC_LIST_APPEND(disp->activesockets, dispsocket, link); @@ -2391,7 +1863,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, UNLOCK(&disp->lock); - INSIST(disp->socktype == isc_sockettype_tcp || res->dispsocket != NULL); + INSIST(disp->socktype == isc_socktype_tcp || res->dispsocket != NULL); *idp = id; *resp = res; @@ -2399,20 +1871,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, return (ISC_R_SUCCESS); } -void -dns_dispatch_starttcp(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - - dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]); - - LOCK(&disp->lock); - if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) { - disp->attributes |= DNS_DISPATCHATTR_CONNECTED; - (void)startrecv(disp, NULL); - } - UNLOCK(&disp->lock); -} - isc_result_t dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { dns_dispatch_t *disp = NULL; @@ -2432,15 +1890,13 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { REQUIRE(resp->item_out); resp->item_out = false; - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } free_devent(disp, ev); if (disp->shutting_down == 1) { UNLOCK(&disp->lock); return (ISC_R_SHUTTINGDOWN); } + ev = ISC_LIST_HEAD(resp->items); if (ev != NULL) { ISC_LIST_UNLINK(resp->items, ev, ev_link); @@ -2452,7 +1908,11 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { resp->item_out = true; isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); } + + startrecv(disp, resp->dispsocket); + UNLOCK(&disp->lock); + return (ISC_R_SUCCESS); } @@ -2462,11 +1922,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, dns_dispatchmgr_t *mgr = NULL; dns_dispatch_t *disp = NULL; dns_dispentry_t *res = NULL; - dispsocket_t *dispsock = NULL; dns_dispatchevent_t *ev = NULL; unsigned int bucket; - bool killit; - unsigned int n; isc_eventlist_t events; dns_qid_t *qid = NULL; @@ -2477,7 +1934,9 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, *resp = NULL; disp = res->disp; + res->disp = NULL; REQUIRE(VALID_DISPATCH(disp)); + mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); qid = mgr->qid; @@ -2491,26 +1950,16 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, } LOCK(&disp->lock); - INSIST(disp->requests > 0); disp->requests--; - dec_stats(disp->mgr, (disp->socktype == isc_sockettype_udp) + dec_stats(disp->mgr, (disp->socktype == isc_socktype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - if (isc_refcount_decrement(&disp->refcount) == 1) { - if (disp->recv_pending > 0) { - isc_socket_cancel(disp->socket, disp->task[0], - ISC_SOCKCANCEL_RECV); - } - for (dispsock = ISC_LIST_HEAD(disp->activesockets); - dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) - { - isc_socket_cancel(dispsock->socket, dispsock->task, - ISC_SOCKCANCEL_RECV); - } - disp->shutting_down = 1; + if (res->dispsocket != NULL) { + deactivate_dispsocket(disp, res->dispsocket); } + UNLOCK(&disp->lock); bucket = res->bucket; @@ -2519,6 +1968,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, UNLOCK(&qid->lock); if (ev == NULL && res->item_out) { + unsigned int n; + /* * We've posted our event, but the caller hasn't gotten it * yet. Take it back. @@ -2536,88 +1987,130 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, if (ev != NULL) { REQUIRE(res->item_out); res->item_out = false; - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } free_devent(disp, ev); } request_log(disp, res, LVL(90), "detaching from task %p", res->task); isc_task_detach(&res->task); - if (res->dispsocket != NULL) { - isc_socket_cancel(res->dispsocket->socket, - res->dispsocket->task, ISC_SOCKCANCEL_RECV); - res->dispsocket->resp = NULL; - } - /* * Free any buffered responses as well */ ev = ISC_LIST_HEAD(res->items); while (ev != NULL) { ISC_LIST_UNLINK(res->items, ev, ev_link); - if (ev->buffer.base != NULL) { - free_buffer(disp, ev->buffer.base, ev->buffer.length); - } free_devent(disp, ev); ev = ISC_LIST_HEAD(res->items); } res->magic = 0; isc_refcount_decrement(&disp->mgr->irefs); isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - if (disp->shutting_down == 1) { - do_cancel(disp); - } else { - (void)startrecv(disp, NULL); - } - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task[0], &disp->ctlevent); - } + dns_dispatch_detach(&disp); } -isc_result_t -dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, - isc_task_t *task, isc_taskaction_t action, void *arg) { - isc_socket_t *sock = NULL; - isc_sockaddr_t *address = NULL; +/* + * disp must be locked. + */ +static void +startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket) { + isc_nmhandle_t *handle = NULL; - if (resp != NULL) { - REQUIRE(VALID_RESPONSE(resp)); - sock = resp->dispsocket->socket; - address = &resp->host; - } else if (disp != NULL) { - REQUIRE(VALID_DISPATCH(disp)); - sock = disp->socket; - address = &disp->peer; + if (disp->shutting_down == 1) { + return; + } + + if (dispsocket == NULL) { + if (disp->socktype == isc_socktype_udp || + disp->recv_pending != 0) { + return; + } + isc_nmhandle_attach(disp->handle, &handle); } else { + handle = dispsocket->handle; + } + + switch (disp->socktype) { + case isc_socktype_udp: + isc_nm_read(handle, udp_recv, dispsocket); + break; + + case isc_socktype_tcp: + isc_nm_read(handle, tcp_recv, disp); + INSIST(disp->recv_pending == 0); + disp->recv_pending = 1; + break; + + default: INSIST(0); ISC_UNREACHABLE(); } +} - return (isc_socket_connect(sock, address, task, action, arg)); +static void +disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_dispentry_t *resp = (dns_dispentry_t *)arg; + dns_dispatch_t *disp = resp->disp; + dispsocket_t *dispsocket = NULL; + + if (eresult == ISC_R_SUCCESS) { + if (disp->socktype == isc_socktype_udp) { + dispsocket = resp->dispsocket; + isc_nmhandle_attach(handle, &dispsocket->handle); + } else if (disp->handle == NULL) { + disp->attributes |= DNS_DISPATCHATTR_CONNECTED; + isc_nmhandle_attach(handle, &disp->handle); + } + + startrecv(disp, dispsocket); + } + + if (resp->connected != NULL) { + resp->connected(handle, eresult, resp->arg); + } } isc_result_t -dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, - isc_socketevent_t *sendevent, isc_region_t *r, - const isc_sockaddr_t *address, isc_dscp_t dscp, - isc_taskaction_t action, void *arg) { - isc_result_t result; - isc_socket_t *sock = NULL; +dns_dispatch_connect(dns_dispentry_t *resp) { + dns_dispatch_t *disp = NULL; REQUIRE(VALID_RESPONSE(resp)); - REQUIRE(sendevent != NULL); - memset(sendevent, 0, sizeof(isc_socketevent_t)); - ISC_EVENT_INIT(sendevent, sizeof(isc_socketevent_t), 0, NULL, - ISC_SOCKEVENT_SENDDONE, action, arg, NULL, NULL, NULL); + disp = resp->disp; - sock = getentrysocket(resp); + switch (disp->socktype) { + case isc_socktype_tcp: + if (disp->handle != NULL) { + break; + } + isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer, + disp_connected, resp, resp->timeout, 0); + break; + case isc_socktype_udp: + isc_nm_udpconnect(disp->mgr->nm, &resp->dispsocket->local, + &resp->dispsocket->peer, disp_connected, resp, + resp->timeout, 0); + break; + default: + return (ISC_R_NOTIMPLEMENTED); + } + + return (ISC_R_SUCCESS); +} + +void +dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { + isc_nmhandle_t *handle = NULL; + + REQUIRE(VALID_RESPONSE(resp)); + + UNUSED(dscp); + + handle = getentryhandle(resp); + +#if 0 + /* XXX: no DSCP support */ if (dscp == -1) { sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; sendevent->dscp = 0; @@ -2628,43 +2121,39 @@ dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, isc_socket_dscp(sock, dscp); } } +#endif - if (tcp) { - address = NULL; - } - - result = isc_socket_sendto2(sock, r, task, address, NULL, sendevent, 0); - return (result); + isc_nm_send(handle, r, resp->sent, resp->arg); } void dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, bool connecting) { - isc_socket_t *sock = NULL; + isc_nmhandle_t *handle = NULL; REQUIRE(disp != NULL || resp != NULL); if (resp != NULL) { REQUIRE(VALID_RESPONSE(resp)); - sock = getentrysocket(resp); + handle = getentryhandle(resp); } else if (disp != NULL) { REQUIRE(VALID_DISPATCH(disp)); - sock = getsocket(disp); + handle = gethandle(disp); } else { INSIST(0); ISC_UNREACHABLE(); } - if (sock == NULL) { + if (handle == NULL) { return; } if (connecting) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); + // isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); } if (sending) { - isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); + // isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); } } @@ -2703,6 +2192,7 @@ do_cancel(dns_dispatch_t *disp) { * Send the shutdown failsafe event to this resp. */ ev = disp->failsafe_ev; + disp->failsafe_ev = NULL; ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, resp->action, resp->arg, resp, NULL, NULL); ev->result = disp->shutdown_why; @@ -2717,21 +2207,21 @@ unlock: UNLOCK(&qid->lock); } -static isc_socket_t * -getsocket(dns_dispatch_t *disp) { +static isc_nmhandle_t * +gethandle(dns_dispatch_t *disp) { REQUIRE(VALID_DISPATCH(disp)); - return (disp->socket); + return (disp->handle); } -static isc_socket_t * -getentrysocket(dns_dispentry_t *resp) { +static isc_nmhandle_t * +getentryhandle(dns_dispentry_t *resp) { REQUIRE(VALID_RESPONSE(resp)); - if (resp->disp->socktype == isc_sockettype_tcp) { - return (resp->disp->socket); + if (resp->disp->socktype == isc_socktype_tcp) { + return (resp->disp->handle); } else if (resp->dispsocket != NULL) { - return (resp->dispsocket->socket); + return (resp->dispsocket->handle); } else { return (NULL); } @@ -2742,7 +2232,7 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) { REQUIRE(VALID_DISPATCH(disp)); REQUIRE(addrp != NULL); - if (disp->socktype == isc_sockettype_udp) { + if (disp->socktype == isc_socktype_udp) { *addrp = disp->local; return (ISC_R_SUCCESS); } @@ -2754,13 +2244,14 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) { REQUIRE(VALID_RESPONSE(resp)); REQUIRE(addrp != NULL); - if (resp->disp->socktype == isc_sockettype_tcp) { - return (isc_socket_getsockname(resp->disp->socket, addrp)); + if (resp->disp->socktype == isc_socktype_tcp) { + *addrp = resp->disp->local; + return (ISC_R_SUCCESS); } - if (resp->dispsocket != NULL) { - return (isc_socket_getsockname(resp->dispsocket->socket, - addrp)); + if (resp->dispsocket != NULL && resp->dispsocket->handle != NULL) { + *addrp = isc_nmhandle_localaddr(resp->dispsocket->handle); + return (ISC_R_SUCCESS); } return (ISC_R_NOTIMPLEMENTED); @@ -2810,9 +2301,9 @@ dns_dispatchset_get(dns_dispatchset_t *dset) { } isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t *source, - dns_dispatchset_t **dsetp, int n) { +dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + dns_dispatch_t *source, dns_dispatchset_t **dsetp, + int n) { isc_result_t result; dns_dispatchset_t *dset = NULL; dns_dispatchmgr_t *mgr = NULL; @@ -2839,8 +2330,8 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, LOCK(&mgr->lock); for (i = 1; i < n; i++) { dset->dispatches[i] = NULL; - result = dispatch_createudp(mgr, sockmgr, taskmgr, - &source->local, source->attributes, + result = dispatch_createudp(mgr, taskmgr, &source->local, + source->attributes, &dset->dispatches[i]); if (result != ISC_R_SUCCESS) { goto fail; diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index d8fcfd3c9e..9c3114dbd0 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -89,9 +89,8 @@ typedef struct dns_clientresevent { isc_result_t dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_client_t **clientp, - const isc_sockaddr_t *localaddr4, + isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, + dns_client_t **clientp, const isc_sockaddr_t *localaddr4, const isc_sockaddr_t *localaddr6); /*%< * Create a DNS client object with minimal internal resources, such as @@ -113,7 +112,7 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, * *\li 'taskmgr' is a valid task manager. * - *\li 'socketmgr' is a valid socket manager. + *\li 'nm' is a valid network manager. * *\li 'timermgr' is a valid timer manager. * diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 0ff11844ff..aea71f9bd5 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -9,6 +9,8 @@ * information regarding copyright ownership. */ +#include + #ifndef DNS_DISPATCH_H #define DNS_DISPATCH_H 1 @@ -50,6 +52,7 @@ #include #include #include +#include #include #include @@ -76,12 +79,9 @@ ISC_LANG_BEGINDECLS struct dns_dispatchevent { ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */ - isc_result_t result; /*%< result code */ - int32_t id; /*%< message id */ - isc_sockaddr_t addr; /*%< address recv'd from */ - struct in6_pktinfo pktinfo; /*%< reply info for v6 */ - isc_buffer_t buffer; /*%< data buffer */ - uint32_t attributes; /*%< mirrored from socket.h */ + isc_result_t result; /*%< result code */ + isc_region_t region; /*%< data region */ + isc_buffer_t buffer; /*%< data buffer */ }; /*% @@ -128,14 +128,16 @@ struct dns_dispatchset { #define DNS_DISPATCHOPT_FIXEDID 0x00000001U isc_result_t -dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp); +dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, dns_dispatchmgr_t **mgrp); /*%< * Creates a new dispatchmgr object, and sets the available ports * to the default range (1024-65535). * * Requires: - *\li "mctx" be a valid memory context. + *\li 'mctx' be a valid memory context. * + *\li 'nm' is a valid network manager. + *\li mgrp != NULL && *mgrp == NULL * * Returns: @@ -205,9 +207,9 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); */ isc_result_t -dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, - unsigned int attributes, dns_dispatch_t **dispp); +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, unsigned int attributes, + dns_dispatch_t **dispp); /*%< * Create a new UDP dispatch. * @@ -223,8 +225,8 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, */ isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, + const isc_sockaddr_t *localaddr, const isc_sockaddr_t *destaddr, unsigned int attributes, isc_dscp_t dscp, dns_dispatch_t **dispp); /*%< @@ -265,15 +267,13 @@ dns_dispatch_detach(dns_dispatch_t **dispp); */ isc_result_t -dns_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp, - isc_task_t *task, isc_taskaction_t action, void *arg); +dns_dispatch_connect(dns_dispentry_t *resp); /*%< - * Connect the UDP socket in 'resp' or the TCP socket in 'disp' to the - * remote server, and run the specified callback. + * Connect to the remote server configured in 'resp' and run the + * connect callback that was set up via dns_dispatch_addresponse(). * * Requires: - *\li 'resp' is NULL and 'disp' is valid, or - *\li 'disp' is NULL and 'resp' is valid. + *\li 'resp' is valid. */ void @@ -288,29 +288,16 @@ dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, *\li 'disp' is NULL and 'resp' is valid. */ -isc_result_t -dns_dispatch_send(dns_dispentry_t *resp, bool tcp, isc_task_t *task, - isc_socketevent_t *sendevent, isc_region_t *r, - const isc_sockaddr_t *address, isc_dscp_t dscp, - isc_taskaction_t action, void *arg); +void +dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp); /*%< * Send region 'r' using the socket in 'resp', then run the specified - * callback. 'sendevent' must point to enough memory to hold an - * isc_socketevent; it will be overwritten. + * callback. * * Requires: *\li 'resp' is valid. */ -void -dns_dispatch_starttcp(dns_dispatch_t *disp); -/*%< - * Start processing of a TCP dispatch once the socket connects. - * - * Requires: - *\li 'disp' is valid. - */ - isc_result_t dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, const isc_sockaddr_t *localaddr, bool *connected, @@ -322,18 +309,29 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, - const isc_sockaddr_t *dest, isc_task_t *task, - isc_taskaction_t action, void *arg, uint16_t *idp, - dns_dispentry_t **resp, isc_socketmgr_t *sockmgr); + unsigned int timeout, const isc_sockaddr_t *dest, + isc_task_t *task, isc_nm_cb_t connected, + isc_nm_cb_t sent, isc_taskaction_t action, + isc_taskaction_t timeout_action, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp); /*%< * Add a response entry for this dispatch. * * "*idp" is filled in with the assigned message ID, and *resp is filled in * to contain the magic token used to request event flow stop. * - * Arranges for the given task to get a callback for response packets. When - * the event is delivered, it must be returned using dns_dispatch_freeevent() - * or through dns_dispatch_removeresponse() for another to be delivered. + * The 'connected' and 'sent' callbacks are run to inform the caller when + * the connection and send functions are complete. + * + * The specified 'task' is sent the 'action' callback for response packets. + * (Later, this should be updated to a network manager callback function, + * but for now we still use isc_task for this.) When the event is delivered, + * it must be returned using dns_dispatch_freeevent() or through + * dns_dispatch_removeresponse() for another to be delivered. + * + * On timeout, 'timeout_action' will be sent to the task. + * + * All three callback functions are sent 'arg' as a parameter. * * Requires: *\li "idp" be non-NULL. @@ -344,10 +342,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, * *\li "resp" be non-NULL and *resp be NULL * - *\li "sockmgr" be NULL or a valid socket manager. If 'disp' has - * the DNS_DISPATCHATTR_EXCLUSIVE attribute, this must not be NULL, - * which also means dns_dispatch_addresponse() cannot be used. - * * Ensures: * *\li <id, dest> is a unique tuple. That means incoming messages @@ -452,9 +446,9 @@ dns_dispatchset_get(dns_dispatchset_t *dset); */ isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t *source, - dns_dispatchset_t **dsetp, int n); +dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + dns_dispatch_t *source, dns_dispatchset_t **dsetp, + int n); /*%< * Given a valid dispatch 'source', create a dispatch set containing * 'n' UDP dispatches, with the remainder filled out by clones of the diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 98afe5a4ae..9554603b50 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -53,8 +53,7 @@ typedef struct dns_requestevent { ISC_LANG_BEGINDECLS isc_result_t -dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, +dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_requestmgr_t **requestmgrp); @@ -65,8 +64,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, * *\li 'mctx' is a valid memory context. * - *\li 'timermgr' is a valid timer manager. - * *\li 'socketmgr' is a valid socket manager. * *\li 'taskmgr' is a valid task manager. diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 07b94fdcd1..aeda97dd38 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -163,11 +163,10 @@ typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t; isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_resolver_t **resp); + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_resolver_t **resp); /*%< * Create a resolver. @@ -185,7 +184,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, * *\li 'ntasks' > 0. * - *\li 'socketmgr' is a valid socket manager. + *\li 'nm' is a valid network manager. * *\li 'timermgr' is a valid timer manager. * @@ -413,9 +412,6 @@ dns_resolver_dispatchv4(dns_resolver_t *resolver); dns_dispatch_t * dns_resolver_dispatchv6(dns_resolver_t *resolver); -isc_socketmgr_t * -dns_resolver_socketmgr(dns_resolver_t *resolver); - isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver); diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index bfe9abd763..5e777229e8 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -393,9 +393,9 @@ dns_view_createzonetable(dns_view_t *view); isc_result_t dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6); /*%< * Create a resolver and address database for the view. @@ -407,7 +407,7 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, *\li 'view' does not have a resolver already. * *\li The requirements of dns_resolver_create() apply to 'taskmgr', - * 'ntasks', 'socketmgr', 'timermgr', 'options', 'dispatchv4', and + * 'ntasks', 'nm', 'timermgr', 'options', 'dispatchv4', and * 'dispatchv6'. * * Returns: diff --git a/lib/dns/request.c b/lib/dns/request.c index 367a716d20..c629997c02 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -50,8 +49,6 @@ struct dns_requestmgr { /* locked */ int32_t eref; int32_t iref; - isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; isc_taskmgr_t *taskmgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; @@ -74,7 +71,6 @@ struct dns_request { dns_requestevent_t *event; dns_dispatch_t *dispatch; dns_dispentry_t *dispentry; - isc_timer_t *timer; dns_requestmgr_t *requestmgr; isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; @@ -115,16 +111,16 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, isc_mem_t *mctx); static void -req_senddone(isc_task_t *task, isc_event_t *event); -static void req_response(isc_task_t *task, isc_event_t *event); static void req_timeout(isc_task_t *task, isc_event_t *event); static void -req_connected(isc_task_t *task, isc_event_t *event); +req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void req_sendevent(dns_request_t *request, isc_result_t result); static void +req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); +static void req_cancel(dns_request_t *request); static void req_destroy(dns_request_t *request); @@ -138,8 +134,7 @@ do_cancel(isc_task_t *task, isc_event_t *event); ***/ isc_result_t -dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, +dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_requestmgr_t **requestmgrp) { @@ -150,8 +145,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create"); REQUIRE(requestmgrp != NULL && *requestmgrp == NULL); - REQUIRE(timermgr != NULL); - REQUIRE(socketmgr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(dispatchmgr != NULL); @@ -171,8 +164,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { isc_mutex_init(&requestmgr->locks[i]); } - requestmgr->timermgr = timermgr; - requestmgr->socketmgr = socketmgr; requestmgr->taskmgr = taskmgr; requestmgr->dispatchmgr = dispatchmgr; requestmgr->dispatchv4 = NULL; @@ -410,12 +401,9 @@ mgr_gethash(dns_requestmgr_t *requestmgr) { return (requestmgr->hash % DNS_REQUEST_NLOCKS); } -static inline isc_result_t -req_send(dns_request_t *request, isc_task_t *task, - const isc_sockaddr_t *address) { - isc_result_t result; +static inline void +req_send(dns_request_t *request) { isc_region_t r; - bool tcp; req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); @@ -423,14 +411,8 @@ req_send(dns_request_t *request, isc_task_t *task, isc_buffer_usedregion(request->query, &r); - tcp = dns_request_usedtcp(request); - request->flags |= DNS_REQUEST_F_SENDING; - result = dns_dispatch_send(request->dispentry, tcp, task, - &request->sendevent, &r, address, - request->dscp, req_senddone, request); - INSIST(result == ISC_R_SUCCESS); - return (result); + dns_dispatch_send(request->dispentry, &r, request->dscp); } static isc_result_t @@ -497,9 +479,9 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, } } - result = dns_dispatch_createtcp( - requestmgr->dispatchmgr, requestmgr->socketmgr, - requestmgr->taskmgr, srcaddr, destaddr, 0, dscp, dispatchp); + result = dns_dispatch_createtcp(requestmgr->dispatchmgr, + requestmgr->taskmgr, srcaddr, destaddr, + 0, dscp, dispatchp); return (result); } @@ -528,9 +510,9 @@ udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, return (ISC_R_SUCCESS); } - return (dns_dispatch_createudp( - requestmgr->dispatchmgr, requestmgr->socketmgr, - requestmgr->taskmgr, srcaddr, 0, dispatchp)); + return (dns_dispatch_createudp(requestmgr->dispatchmgr, + requestmgr->taskmgr, srcaddr, 0, + dispatchp)); } static isc_result_t @@ -548,25 +530,6 @@ get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr, return (result); } -static isc_result_t -set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) { - isc_time_t expires; - isc_interval_t interval; - isc_result_t result; - isc_timertype_t timertype; - - isc_interval_set(&interval, timeout, 0); - result = isc_time_nowplusinterval(&expires, &interval); - isc_interval_set(&interval, udpresend, 0); - - timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once; - if (result == ISC_R_SUCCESS) { - result = isc_timer_reset(timer, timertype, &expires, &interval, - false); - } - return (result); -} - isc_result_t dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, const isc_sockaddr_t *srcaddr, @@ -617,19 +580,13 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, udptimeout = 1; } } + + timeout *= 1000; + udptimeout *= 1000; + request->udpcount = udpretries; request->dscp = dscp; - /* - * Create timer now. We will set it below once. - */ - result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, - NULL, NULL, task, req_timeout, request, - &request->timer); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - request->event = (dns_requestevent_t *)isc_event_allocate( mctx, task, DNS_EVENT_REQUESTDONE, action, arg, sizeof(dns_requestevent_t)); @@ -661,8 +618,9 @@ again: } result = dns_dispatch_addresponse( - request->dispatch, dispopt, destaddr, task, req_response, - request, &id, &request->dispentry, requestmgr->socketmgr); + request->dispatch, dispopt, tcp ? timeout : udptimeout, + destaddr, task, req_connected, req_senddone, req_response, + req_timeout, request, &id, &request->dispentry); if (result != ISC_R_SUCCESS) { if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) { newtcp = true; @@ -674,9 +632,6 @@ again: } isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); - if (tcp) { - isc_buffer_putuint16(request->query, (uint16_t)r.length); - } result = isc_buffer_copyregion(request->query, &r); if (result != ISC_R_SUCCESS) { goto cleanup; @@ -684,9 +639,6 @@ again: /* Add message ID. */ isc_buffer_usedregion(request->query, &r); - if (tcp) { - isc_region_consume(&r, 2); - } r.base[0] = (id >> 8) & 0xff; r.base[1] = id & 0xff; @@ -701,24 +653,15 @@ again: ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->destaddr = *destaddr; - if (tcp && !connected) { - result = dns_dispatch_connect(request->dispatch, NULL, task, - req_connected, request); + if (!tcp || !connected) { + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; } else { - result = req_send(request, task, connected ? NULL : destaddr); - if (result != ISC_R_SUCCESS) { - goto unlink; - } + req_send(request); } req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request); @@ -790,7 +733,6 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, return (DNS_R_BLACKHOLED); } - request = NULL; result = new_request(mctx, &request); if (result != ISC_R_SUCCESS) { return (result); @@ -802,19 +744,13 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, udptimeout = 1; } } + + timeout *= 1000; + udptimeout *= 1000; + request->udpcount = udpretries; request->dscp = dscp; - /* - * Create timer now. We will set it below once. - */ - result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, - NULL, NULL, task, req_timeout, request, - &request->timer); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - request->event = (dns_requestevent_t *)isc_event_allocate( mctx, task, DNS_EVENT_REQUESTDONE, action, arg, sizeof(dns_requestevent_t)); @@ -835,8 +771,9 @@ use_tcp: } result = dns_dispatch_addresponse( - request->dispatch, 0, destaddr, task, req_response, request, - &id, &request->dispentry, requestmgr->socketmgr); + request->dispatch, 0, tcp ? timeout : udptimeout, destaddr, + task, req_connected, req_senddone, req_response, req_timeout, + request, &id, &request->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -880,24 +817,15 @@ use_tcp: ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); - result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); - if (result != ISC_R_SUCCESS) { - goto unlink; - } - request->destaddr = *destaddr; - if (tcp && !connected) { - result = dns_dispatch_connect(request->dispatch, NULL, task, - req_connected, request); + if (!tcp || !connected) { + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; } else { - result = req_send(request, task, connected ? NULL : destaddr); - if (result != ISC_R_SUCCESS) { - goto unlink; - } + req_send(request); } req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request); @@ -926,7 +854,6 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, isc_buffer_t *buf2 = NULL; isc_result_t result; isc_region_t r; - bool tcp = false; dns_compress_t cctx; bool cleanup_cctx = false; @@ -984,16 +911,11 @@ req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, * Copy rendered message to exact sized buffer. */ isc_buffer_usedregion(buf1, &r); - if ((options & DNS_REQUESTOPT_TCP) != 0) { - tcp = true; - } else if (r.length > 512) { + if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) { result = DNS_R_USETCP; goto cleanup; } - isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0)); - if (tcp) { - isc_buffer_putuint16(buf2, (uint16_t)r.length); - } + isc_buffer_allocate(mctx, &buf2, r.length); result = isc_buffer_copyregion(buf2, &r); if (result != ISC_R_SUCCESS) { goto cleanup; @@ -1138,7 +1060,6 @@ dns_request_destroy(dns_request_t **requestp) { INSIST(!ISC_LINK_LINKED(request, link)); INSIST(request->dispentry == NULL); INSIST(request->dispatch == NULL); - INSIST(request->timer == NULL); req_destroy(request); } @@ -1147,12 +1068,11 @@ dns_request_destroy(dns_request_t **requestp) { *** Private: request. ***/ static void -req_connected(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - isc_result_t result; - dns_request_t *request = event->ev_arg; +req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_request_t *request = (dns_request_t *)arg; + + UNUSED(handle); - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_CONNECTING(request)); @@ -1171,53 +1091,42 @@ req_connected(isc_task_t *task, isc_event_t *event) { send_if_done(request, ISC_R_CANCELED); } } else { - dns_dispatch_starttcp(request->dispatch); - result = sevent->result; - if (result == ISC_R_SUCCESS) { - result = req_send(request, task, NULL); - } - - if (result != ISC_R_SUCCESS) { + if (eresult == ISC_R_SUCCESS) { + req_send(request); + } else { req_cancel(request); send_if_done(request, ISC_R_CANCELED); } } UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); } static void -req_senddone(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - dns_request_t *request = event->ev_arg; +req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_request_t *request = (dns_request_t *)arg; - REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_SENDING(request)); - req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); + UNUSED(handle); - UNUSED(task); + req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_SENDING; if (DNS_REQUEST_CANCELED(request)) { - /* - * Send delayed event. - */ if (DNS_REQUEST_TIMEDOUT(request)) { send_if_done(request, ISC_R_TIMEDOUT); } else { send_if_done(request, ISC_R_CANCELED); } - } else if (sevent->result != ISC_R_SUCCESS) { + } else if (eresult != ISC_R_SUCCESS) { req_cancel(request); send_if_done(request, ISC_R_CANCELED); } - UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); + UNLOCK(&request->requestmgr->locks[request->hash]); } static void @@ -1266,7 +1175,6 @@ done: static void req_timeout(isc_task_t *task, isc_event_t *event) { dns_request_t *request = event->ev_arg; - isc_result_t result; REQUIRE(VALID_REQUEST(request)); @@ -1274,13 +1182,9 @@ req_timeout(isc_task_t *task, isc_event_t *event) { UNUSED(task); LOCK(&request->requestmgr->locks[request->hash]); - if (event->ev_type == ISC_TIMEREVENT_TICK && request->udpcount-- != 0) { + if (request->udpcount-- != 0) { if (!DNS_REQUEST_SENDING(request)) { - result = req_send(request, task, &request->destaddr); - if (result != ISC_R_SUCCESS) { - req_cancel(request); - send_if_done(request, result); - } + req_send(request); } } else { request->flags |= DNS_REQUEST_F_TIMEDOUT; @@ -1330,9 +1234,6 @@ req_destroy(dns_request_t *request) { if (request->dispatch != NULL) { dns_dispatch_detach(&request->dispatch); } - if (request->timer != NULL) { - isc_timer_detach(&request->timer); - } if (request->tsig != NULL) { isc_buffer_free(&request->tsig); } @@ -1359,10 +1260,6 @@ req_cancel(dns_request_t *request) { */ request->flags |= DNS_REQUEST_F_CANCELED; - if (request->timer != NULL) { - isc_timer_detach(&request->timer); - } - if (request->dispentry != NULL) { dns_dispatch_cancel(NULL, request->dispentry, DNS_REQUEST_SENDING(request), diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index febec16482..b987b888cb 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -496,7 +496,7 @@ struct dns_resolver { isc_mutex_t lock; isc_mutex_t primelock; dns_rdataclass_t rdclass; - isc_socketmgr_t *socketmgr; + isc_nm_t *nm; isc_timermgr_t *timermgr; isc_taskmgr_t *taskmgr; dns_view_t *view; @@ -604,7 +604,7 @@ resquery_send(resquery_t *query); static void resquery_response(isc_task_t *task, isc_event_t *event); static void -resquery_connected(isc_task_t *task, isc_event_t *event); +resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void fctx_try(fetchctx_t *fctx, bool retrying, bool badcache); static isc_result_t @@ -1354,10 +1354,11 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, } dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor); - } - if ((query->options & DNS_FETCHOPT_TCP) == 0) { - /* Inform the ADB that we're ending a UDP fetch */ - dns_adb_endudpfetch(fctx->adb, query->addrinfo); + + if ((query->options & DNS_FETCHOPT_TCP) == 0) { + /* Inform the ADB that we're ending a UDP fetch */ + dns_adb_endudpfetch(fctx->adb, query->addrinfo); + } } /* @@ -1428,7 +1429,9 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, dns_dispatch_removeresponse(&query->dispentry, deventp); } - ISC_LIST_UNLINK(fctx->queries, query, link); + if (ISC_LINK_LINKED(query, link)) { + ISC_LIST_UNLINK(fctx->queries, query, link); + } if (query->tsig != NULL) { isc_buffer_free(&query->tsig); @@ -1796,13 +1799,20 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { } static void -process_sendevent(resquery_t *query, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; +resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + resquery_t *query = (resquery_t *)arg; bool destroy_query = false; - bool retry = false; isc_result_t result; fetchctx_t *fctx = NULL; + QTRACE("senddone"); + + UNUSED(handle); + + INSIST(RESQUERY_SENDING(query)); + + query->sends--; + fctx = query->fctx; if (RESQUERY_CANCELED(query)) { @@ -1810,7 +1820,7 @@ process_sendevent(resquery_t *query, isc_event_t *event) { destroy_query = true; } } else { - switch (sevent->result) { + switch (eresult) { case ISC_R_SUCCESS: break; @@ -1819,94 +1829,44 @@ process_sendevent(resquery_t *query, isc_event_t *event) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNREFUSED: - FCTXTRACE3("query canceled in sendevent(): " + FCTXTRACE3("query canceled in resquery_senddone(): " "no route to host; no response", - sevent->result); + eresult); /* * No route to remote. */ - add_bad(fctx, query->rmessage, query->addrinfo, - sevent->result, badns_unreachable); + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); fctx_cancelquery(&query, NULL, NULL, true, false); - retry = true; + + /* + * Behave as if the idle timer has expired. For TCP + * this may not actually reflect the latest timer. + */ + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) { + fctx_done(fctx, result, __LINE__); + } else { + fctx_try(fctx, true, false); + } break; default: - FCTXTRACE3("query canceled in sendevent() due to " - "unexpected event result; responding", - sevent->result); - + FCTXTRACE3("query canceled in resquery_senddone() " + "due to unexpected result; responding", + eresult); fctx_cancelquery(&query, NULL, NULL, false, false); break; } } - if (event->ev_type == ISC_SOCKEVENT_CONNECT) { - isc_event_free(&event); - } - - if (retry) { - /* - * Behave as if the idle timer has expired. For TCP - * this may not actually reflect the latest timer. - */ - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, true, false); - } - } - if (destroy_query) { resquery_destroy(&query); } } -static void -resquery_udpconnected(isc_task_t *task, isc_event_t *event) { - resquery_t *query = event->ev_arg; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); - - QTRACE("udpconnected"); - - UNUSED(task); - - INSIST(RESQUERY_CONNECTING(query)); - - query->connects--; - - process_sendevent(query, event); -} - -static void -resquery_senddone(isc_task_t *task, isc_event_t *event) { - resquery_t *query = event->ev_arg; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); - - QTRACE("senddone"); - - /* - * XXXRTH - * - * Currently we don't wait for the senddone event before retrying - * a query. This means that if we get really behind, we may end - * up doing extra work! - */ - - UNUSED(task); - - INSIST(RESQUERY_SENDING(query)); - - query->sends--; - - process_sendevent(query, event); -} - static inline isc_result_t fctx_addopt(dns_message_t *message, unsigned int version, uint16_t udpsize, dns_ednsopt_t *ednsopts, size_t count) { @@ -1972,15 +1932,14 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { static isc_result_t fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, unsigned int options) { + isc_result_t result; dns_resolver_t *res = NULL; isc_task_t *task = NULL; - isc_result_t result; resquery_t *query = NULL; isc_sockaddr_t addr; bool have_addr = false; unsigned int srtt; isc_dscp_t dscp = -1; - unsigned int bucketnum; FCTXTRACE("query"); @@ -2088,9 +2047,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->dscp = dscp; } - result = dns_dispatch_createtcp( - res->dispatchmgr, res->socketmgr, res->taskmgr, &addr, - &addrinfo->sockaddr, 0, query->dscp, &query->dispatch); + result = dns_dispatch_createtcp(res->dispatchmgr, res->taskmgr, + &addr, &addrinfo->sockaddr, 0, + query->dscp, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2107,9 +2066,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } - result = dns_dispatch_createudp( - res->dispatchmgr, res->socketmgr, res->taskmgr, - &addr, 0, &query->dispatch); + result = dns_dispatch_createudp(res->dispatchmgr, + res->taskmgr, &addr, 0, + &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2150,49 +2109,34 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; - if ((query->options & DNS_FETCHOPT_TCP) != 0) { - /* - * Connect to the remote server. - */ - result = dns_dispatch_connect(query->dispatch, NULL, task, - resquery_connected, query); - if (result != ISC_R_SUCCESS) { - goto cleanup_dispatch; - } - query->connects++; - QTRACE("connecting via TCP"); - } else { + if ((query->options & DNS_FETCHOPT_TCP) == 0) { if (dns_adbentry_overquota(addrinfo->entry)) { goto cleanup_dispatch; } /* Inform the ADB that we're starting a UDP fetch */ dns_adb_beginudpfetch(fctx->adb, addrinfo); - - result = resquery_send(query); - if (result != ISC_R_SUCCESS) { - goto cleanup_dispatch; - } } - fctx->querysent++; - - ISC_LIST_APPEND(fctx->queries, query, link); - bucketnum = fctx->bucketnum; - LOCK(&res->buckets[bucketnum].lock); + LOCK(&res->buckets[fctx->bucketnum].lock); fctx->nqueries++; - UNLOCK(&res->buckets[bucketnum].lock); - if (isc_sockaddr_pf(&addrinfo->sockaddr) == PF_INET) { - inc_stats(res, dns_resstatscounter_queryv4); - } else { - inc_stats(res, dns_resstatscounter_queryv6); - } - if (res->view->resquerystats != NULL) { - dns_rdatatypestats_increment(res->view->resquerystats, - fctx->type); + UNLOCK(&res->buckets[fctx->bucketnum].lock); + + /* Set up the dispatch and set the query ID */ + /* XXX: timeout hard-coded to 10 seconds */ + result = dns_dispatch_addresponse( + query->dispatch, 0, 10000, &query->addrinfo->sockaddr, task, + resquery_connected, resquery_senddone, resquery_response, NULL, + query, &query->id, &query->dispentry); + if (result != ISC_R_SUCCESS) { + goto cleanup_dispatch; } - return (ISC_R_SUCCESS); + /* Connect the socket */ + query->connects++; + fctx_increference(fctx); + result = dns_dispatch_connect(query->dispentry); + return (result); cleanup_dispatch: if (query->dispatch != NULL) { @@ -2349,21 +2293,19 @@ issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type, static isc_result_t resquery_send(resquery_t *query) { - fetchctx_t *fctx = NULL; isc_result_t result; + fetchctx_t *fctx = query->fctx; + dns_resolver_t *res = fctx->res; + isc_buffer_t buffer; dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_region_t r; - dns_resolver_t *res = NULL; - isc_task_t *task = NULL; - isc_buffer_t tcpbuffer; - isc_buffer_t *buffer = NULL; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; dns_peer_t *peer = NULL; - bool useedns; dns_compress_t cctx; bool cleanup_cctx = false; + bool useedns; bool secure_domain; bool tcp = ((query->options & DNS_FETCHOPT_TCP) != 0); dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; @@ -2377,24 +2319,11 @@ resquery_send(resquery_t *query) { isc_buffer_t zb; #endif /* HAVE_DNSTAP */ - fctx = query->fctx; QTRACE("send"); - res = fctx->res; - task = res->buckets[fctx->bucketnum].task; - - if (tcp) { - /* - * Reserve space for the TCP message length. - */ - isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data)); - isc_buffer_init(&query->buffer, query->data + 2, - sizeof(query->data) - 2); - buffer = &tcpbuffer; - } else { - isc_buffer_init(&query->buffer, query->data, - sizeof(query->data)); - buffer = &query->buffer; + if (atomic_load_acquire(&res->exiting)) { + FCTXTRACE("resquery_send: resolver shutting down"); + return (ISC_R_SHUTTINGDOWN); } result = dns_message_gettempname(fctx->qmessage, &qname); @@ -2406,17 +2335,6 @@ resquery_send(resquery_t *query) { goto cleanup_temps; } - /* - * Get a query id from the dispatch. - */ - result = dns_dispatch_addresponse(query->dispatch, 0, - &query->addrinfo->sockaddr, task, - resquery_response, query, &query->id, - &query->dispentry, res->socketmgr); - if (result != ISC_R_SUCCESS) { - goto cleanup_temps; - } - fctx->qmessage->opcode = dns_opcode_query; /* @@ -2479,7 +2397,8 @@ resquery_send(resquery_t *query) { } cleanup_cctx = true; - result = dns_message_renderbegin(fctx->qmessage, &cctx, &query->buffer); + isc_buffer_init(&buffer, query->data, sizeof(query->data)); + result = dns_message_renderbegin(fctx->qmessage, &cctx, &buffer); if (result != ISC_R_SUCCESS) { goto cleanup_message; } @@ -2490,7 +2409,6 @@ resquery_send(resquery_t *query) { goto cleanup_message; } - peer = NULL; isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr); (void)dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer); @@ -2757,16 +2675,6 @@ resquery_send(resquery_t *query) { } } - /* - * If using TCP, write the length of the message at the beginning - * of the buffer. - */ - if (tcp) { - isc_buffer_usedregion(&query->buffer, &r); - isc_buffer_putuint16(&tcpbuffer, (uint16_t)r.length); - isc_buffer_add(&tcpbuffer, r.length); - } - /* * Log the outgoing packet. */ @@ -2780,23 +2688,9 @@ resquery_send(resquery_t *query) { */ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER); - if (!tcp) { - /* Connect the UDP socket */ - result = dns_dispatch_connect(NULL, query->dispentry, task, - resquery_udpconnected, query); - if (result != ISC_R_SUCCESS) { - goto cleanup_message; - } - query->connects++; - } + isc_buffer_usedregion(&buffer, &r); - isc_buffer_usedregion(buffer, &r); - - result = dns_dispatch_send(query->dispentry, tcp, task, - &query->sendevent, &r, - &query->addrinfo->sockaddr, query->dscp, - resquery_senddone, query); - INSIST(result == ISC_R_SUCCESS); + dns_dispatch_send(query->dispentry, &r, query->dscp); query->sends++; QTRACE("sent"); @@ -2817,7 +2711,7 @@ resquery_send(resquery_t *query) { } dns_dt_send(fctx->res->view, dtmsgtype, la, &query->addrinfo->sockaddr, - tcp, &zr, &query->start, NULL, &query->buffer); + tcp, &zr, &query->start, NULL, &buffer); #endif /* HAVE_DNSTAP */ return (ISC_R_SUCCESS); @@ -2846,40 +2740,40 @@ cleanup_temps: } static void -resquery_connected(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sevent = (isc_socketevent_t *)event; - resquery_t *query = event->ev_arg; - bool retry = false; +resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + resquery_t *query = (resquery_t *)arg; isc_interval_t interval; isc_result_t result; - fetchctx_t *fctx; + fetchctx_t *fctx = NULL; + dns_resolver_t *res = NULL; + unsigned int bucketnum; + bool bucket_empty; + int pf; - REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_QUERY(query)); QTRACE("connected"); - UNUSED(task); - - /* - * XXXRTH - * - * Currently we don't wait for the connect event before retrying - * a query. This means that if we get really behind, we may end - * up doing extra work! - */ + UNUSED(handle); query->connects--; fctx = query->fctx; + res = fctx->res; + + bucketnum = fctx->bucketnum; + + if (atomic_load_acquire(&res->exiting)) { + eresult = ISC_R_SHUTTINGDOWN; + } if (RESQUERY_CANCELED(query)) { /* - * This query was canceled while the connect() was in - * progress. + * This query was canceled while the connect() was + * in progress. */ resquery_destroy(&query); } else { - switch (sevent->result) { + switch (eresult) { case ISC_R_SUCCESS: /* @@ -2890,8 +2784,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { * received. */ isc_interval_set(&interval, - fctx->res->query_timeout / 1000 / 2, - 0); + res->query_timeout / 1000 / 2, 0); result = fctx_startidletimer(query->fctx, &interval); if (result != ISC_R_SUCCESS) { FCTXTRACE("query canceled: idle timer failed; " @@ -2904,7 +2797,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { } /* - * We are connected. Update the dispatcher and + * We are connected. Update the dispatcher and * send the query. */ dns_dispatch_changeattributes( @@ -2920,6 +2813,20 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { false); fctx_done(fctx, result, __LINE__); } + + fctx->querysent++; + + ISC_LIST_APPEND(fctx->queries, query, link); + pf = isc_sockaddr_pf(&query->addrinfo->sockaddr); + if (pf == PF_INET) { + inc_stats(res, dns_resstatscounter_queryv4); + } else { + inc_stats(res, dns_resstatscounter_queryv6); + } + if (res->view->resquerystats != NULL) { + dns_rdatatypestats_increment( + res->view->resquerystats, fctx->type); + } break; case ISC_R_NETUNREACH: @@ -2928,45 +2835,46 @@ resquery_connected(isc_task_t *task, isc_event_t *event) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNECTIONRESET: - FCTXTRACE3("query canceled in connected(): " + FCTXTRACE3("query canceled in resquery_connected(): " "no route to host; no response", - sevent->result); + eresult); /* * Do not query this server again in this fetch context * if the server is unavailable over TCP. */ - add_bad(fctx, query->rmessage, query->addrinfo, - sevent->result, badns_unreachable); + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); fctx_cancelquery(&query, NULL, NULL, true, false); - retry = true; + + /* + * Behave as if the idle timer has expired. For + * TCP connections this may not actually reflect + * the latest timer. + */ + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) { + fctx_done(fctx, result, __LINE__); + } else { + fctx_try(fctx, true, false); + } break; default: - FCTXTRACE3("query canceled in connected() due to " - "unexpected event result; responding", - sevent->result); + FCTXTRACE3("query canceled in resquery_connected() " + "due to unexpected result; responding", + eresult); - dns_dispatch_detach(&query->dispatch); fctx_cancelquery(&query, NULL, NULL, false, false); - break; } } - isc_event_free(&event); - - if (retry) { - /* - * Behave as if the idle timer has expired. For TCP - * connections this may not actually reflect the latest timer. - */ - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, true, false); - } + LOCK(&res->buckets[bucketnum].lock); + bucket_empty = fctx_decreference(fctx); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) { + empty_bucket(res); } } @@ -4140,7 +4048,6 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { } fctx_increference(fctx); - result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) { fctx_done(fctx, result, __LINE__); @@ -5033,8 +4940,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, (res->query_timeout - 1000)); /* * Compute an expiration time after which stale data will - * attempted to be served, if stale answers are enabled and - * target RRset is available in cache. + * be served, if stale answers are enabled and target RRset is + * available in cache. */ isc_interval_set( &interval, res->view->staleanswerclienttimeout / 1000, @@ -7521,6 +7428,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if (atomic_load_acquire(&fctx->res->exiting)) { result = ISC_R_SHUTTINGDOWN; FCTXTRACE("resolver shutting down"); + rctx.finish = NULL; rctx_done(&rctx, result); return; } @@ -9689,13 +9597,13 @@ rctx_done(respctx_t *rctx, isc_result_t result) { /* * Need to attach to the message until the scope * of this function ends, since there are many places - * where te message is used and/or may be destroyed + * where the message is used and/or may be destroyed * before this function ends. */ dns_message_t *message = NULL; dns_message_attach(query->rmessage, &message); - FCTXTRACE4("query canceled in response(); ", + FCTXTRACE4("query canceled in rctx_done(); ", rctx->no_response ? "no response" : "responding", result); /* @@ -10128,11 +10036,10 @@ spillattimer_countdown(isc_task_t *task, isc_event_t *event) { isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, - dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, - dns_resolver_t **resp) { + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, + dns_dispatch_t *dispatchv6, dns_resolver_t **resp) { dns_resolver_t *res = NULL; isc_result_t result = ISC_R_SUCCESS; unsigned int i, buckets_created = 0, dbuckets_created = 0; @@ -10154,7 +10061,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, res = isc_mem_get(view->mctx, sizeof(*res)); *res = (dns_resolver_t){ .mctx = view->mctx, .rdclass = view->rdclass, - .socketmgr = socketmgr, + .nm = nm, .timermgr = timermgr, .taskmgr = taskmgr, .dispatchmgr = dispatchmgr, @@ -10230,13 +10137,13 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, } if (dispatchv4 != NULL) { - dns_dispatchset_create(view->mctx, socketmgr, taskmgr, - dispatchv4, &res->dispatches4, ndisp); + dns_dispatchset_create(view->mctx, taskmgr, dispatchv4, + &res->dispatches4, ndisp); } if (dispatchv6 != NULL) { - dns_dispatchset_create(view->mctx, socketmgr, taskmgr, - dispatchv6, &res->dispatches6, ndisp); + dns_dispatchset_create(view->mctx, taskmgr, dispatchv6, + &res->dispatches6, ndisp); } isc_mutex_init(&res->lock); @@ -10951,12 +10858,6 @@ dns_resolver_dispatchv6(dns_resolver_t *resolver) { return (dns_dispatchset_get(resolver->dispatches6)); } -isc_socketmgr_t * -dns_resolver_socketmgr(dns_resolver_t *resolver) { - REQUIRE(VALID_RESOLVER(resolver)); - return (resolver->socketmgr); -} - isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index aa92f4ed87..65a2f3d441 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -20,16 +20,17 @@ #include #include #include +#include #define UNIT_TESTING #include #include #include +#include #include #include #include -#include #include #include @@ -38,18 +39,91 @@ #include "dnstest.h" +/* Timeouts in miliseconds */ +#define T_INIT 120 * 1000 +#define T_IDLE 120 * 1000 +#define T_KEEPALIVE 120 * 1000 +#define T_ADVERTISED 120 * 1000 +#define T_CONNECT 30 * 1000 + dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatchset_t *dset = NULL; +isc_nm_t *connect_nm = NULL; +static isc_sockaddr_t server_addr; +static isc_sockaddr_t connect_addr; + +static int +setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { + socklen_t addrlen = sizeof(*addr); + uv_os_sock_t fd; + int r; + + isc_sockaddr_fromin6(addr, &in6addr_loopback, 0); + + fd = socket(AF_INET6, family, 0); + if (fd < 0) { + perror("setup_ephemeral_port: socket()"); + return (-1); + } + + r = bind(fd, (const struct sockaddr *)&addr->type.sa, + sizeof(addr->type.sin6)); + if (r != 0) { + perror("setup_ephemeral_port: bind()"); + close(fd); + return (r); + } + + r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen); + if (r != 0) { + perror("setup_ephemeral_port: getsockname()"); + close(fd); + return (r); + } + +#if IPV6_RECVERR +#define setsockopt_on(socket, level, name) \ + setsockopt(socket, level, name, &(int){ 1 }, sizeof(int)) + + r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR); + if (r != 0) { + perror("setup_ephemeral_port"); + close(fd); + return (r); + } +#endif + + return (fd); +} static int _setup(void **state) { isc_result_t result; + uv_os_sock_t sock = -1; UNUSED(state); result = dns_test_begin(NULL, true); assert_int_equal(result, ISC_R_SUCCESS); + connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0); + + server_addr = (isc_sockaddr_t){ .length = 0 }; + sock = setup_ephemeral_port(&server_addr, SOCK_DGRAM); + if (sock < 0) { + return (-1); + } + close(sock); + + /* Create a secondary network manager */ + isc_managers_create(dt_mctx, ncpus, 0, 0, &connect_nm, NULL, NULL, + NULL); + + isc_nm_settimeouts(netmgr, T_INIT, T_IDLE, T_KEEPALIVE, T_ADVERTISED); + isc_nm_settimeouts(connect_nm, T_INIT, T_IDLE, T_KEEPALIVE, + T_ADVERTISED); + return (0); } @@ -57,6 +131,9 @@ static int _teardown(void **state) { UNUSED(state); + isc_managers_destroy(&connect_nm, NULL, NULL, NULL); + assert_null(connect_nm); + dns_test_end(); return (0); @@ -68,20 +145,18 @@ make_dispatchset(unsigned int ndisps) { isc_sockaddr_t any; dns_dispatch_t *disp = NULL; - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, netmgr, &dispatchmgr); if (result != ISC_R_SUCCESS) { return (result); } isc_sockaddr_any(&any); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &any, - 0, &disp); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &any, 0, &disp); if (result != ISC_R_SUCCESS) { return (result); } - result = dns_dispatchset_create(dt_mctx, socketmgr, taskmgr, disp, - &dset, ndisps); + result = dns_dispatchset_create(dt_mctx, taskmgr, disp, &dset, ndisps); dns_dispatch_detach(&disp); return (result); @@ -155,68 +230,57 @@ dispatchset_get(void **state) { reset(); } +struct { + isc_nmhandle_t *handle; + atomic_uint_fast32_t responses; +} testdata; + +static dns_dispatch_t *dispatch = NULL; +static dns_dispentry_t *dispentry = NULL; +static atomic_bool first = ATOMIC_VAR_INIT(true); + static void -senddone(isc_task_t *task, isc_event_t *event) { - isc_socket_t *sock = event->ev_arg; +server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(cbarg); - UNUSED(task); - - isc_socket_detach(&sock); - isc_event_free(&event); + return; } static void -nameserver(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - isc_region_t region; - isc_socket_t *dummy; - isc_socket_t *sock = event->ev_arg; - isc_socketevent_t *ev = (isc_socketevent_t *)event; +nameserver(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, + void *cbarg) { + isc_region_t response; static unsigned char buf1[16]; static unsigned char buf2[16]; - memmove(buf1, ev->region.base, 12); + UNUSED(eresult); + UNUSED(cbarg); + + memmove(buf1, region->base, 12); memset(buf1 + 12, 0, 4); buf1[2] |= 0x80; /* qr=1 */ - memmove(buf2, ev->region.base, 12); + memmove(buf2, region->base, 12); memset(buf2 + 12, 1, 4); buf2[2] |= 0x80; /* qr=1 */ /* * send message to be discarded. */ - region.base = buf1; - region.length = sizeof(buf1); - dummy = NULL; - isc_socket_attach(sock, &dummy); - result = isc_socket_sendto(sock, ®ion, task, senddone, sock, - &ev->address, NULL); - if (result != ISC_R_SUCCESS) { - isc_socket_detach(&dummy); - } + response.base = buf1; + response.length = sizeof(buf1); + isc_nm_send(handle, &response, server_senddone, NULL); /* * send nextitem message. */ - region.base = buf2; - region.length = sizeof(buf2); - dummy = NULL; - isc_socket_attach(sock, &dummy); - result = isc_socket_sendto(sock, ®ion, task, senddone, sock, - &ev->address, NULL); - if (result != ISC_R_SUCCESS) { - isc_socket_detach(&dummy); - } - isc_event_free(&event); + response.base = buf2; + response.length = sizeof(buf2); + isc_nm_send(handle, &response, server_senddone, NULL); } -static dns_dispatch_t *dispatch = NULL; -static dns_dispentry_t *dispentry = NULL; -static atomic_bool first = ATOMIC_VAR_INIT(true); -static isc_sockaddr_t local; -static atomic_uint_fast32_t responses; - static void response(isc_task_t *task, isc_event_t *event) { dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; @@ -224,78 +288,81 @@ response(isc_task_t *task, isc_event_t *event) { UNUSED(task); - atomic_fetch_add_relaxed(&responses, 1); + atomic_fetch_add_relaxed(&testdata.responses, 1); if (atomic_compare_exchange_strong(&first, &exp_true, false)) { isc_result_t result = dns_dispatch_getnext(dispentry, &devent); assert_int_equal(result, ISC_R_SUCCESS); } else { dns_dispatch_removeresponse(&dispentry, &devent); + isc_nmhandle_detach(&testdata.handle); isc_app_shutdown(); } } static void -startit(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - isc_socket_t *sock = NULL; +connected(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + isc_region_t *r = (isc_region_t *)cbarg; - isc_socket_attach(dns_dispatch_getentrysocket(dispentry), &sock); - result = isc_socket_sendto(sock, event->ev_arg, task, senddone, sock, - &local, NULL); - assert_int_equal(result, ISC_R_SUCCESS); + UNUSED(eresult); + + isc_nmhandle_attach(handle, &testdata.handle); + dns_dispatch_send(dispentry, r, -1); +} + +static void +client_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(cbarg); + + return; +} + +static void +startit(isc_task_t *task, isc_event_t *event) { + UNUSED(task); + dns_dispatch_connect(dispentry); isc_event_free(&event); } /* test dispatch getnext */ static void dispatch_getnext(void **state) { - isc_region_t region; isc_result_t result; - isc_socket_t *sock = NULL; + isc_region_t region; + isc_nmsocket_t *sock = NULL; isc_task_t *task = NULL; - uint16_t id; - struct in_addr ina; unsigned char message[12]; unsigned char rbuf[12]; + uint16_t id; UNUSED(state); - atomic_init(&responses, 0); + testdata.handle = NULL; + atomic_init(&testdata.responses, 0); result = isc_task_create(taskmgr, 0, &task); assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); - ina.s_addr = htonl(INADDR_LOOPBACK); - isc_sockaddr_fromin(&local, &ina, 0); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, - 0, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &connect_addr, 0, + &dispatch); assert_int_equal(result, ISC_R_SUCCESS); /* * Create a local udp nameserver on the loopback. */ - result = isc_socket_create(socketmgr, AF_INET, isc_sockettype_udp, - &sock); - assert_int_equal(result, ISC_R_SUCCESS); - - ina.s_addr = htonl(INADDR_LOOPBACK); - isc_sockaddr_fromin(&local, &ina, 0); - result = isc_socket_bind(sock, &local, 0); - assert_int_equal(result, ISC_R_SUCCESS); - - result = isc_socket_getsockname(sock, &local); + result = isc_nm_listenudp(netmgr, &server_addr, nameserver, NULL, 0, + &sock); assert_int_equal(result, ISC_R_SUCCESS); region.base = rbuf; region.length = sizeof(rbuf); - result = isc_socket_recv(sock, ®ion, 1, task, nameserver, sock); - assert_int_equal(result, ISC_R_SUCCESS); - - result = dns_dispatch_addresponse(dispatch, 0, &local, task, response, - NULL, &id, &dispentry, socketmgr); + result = dns_dispatch_addresponse( + dispatch, 0, 10000, &server_addr, task, connected, + client_senddone, response, NULL, ®ion, &id, &dispentry); assert_int_equal(result, ISC_R_SUCCESS); memset(message, 0, sizeof(message)); @@ -304,19 +371,22 @@ dispatch_getnext(void **state) { region.base = message; region.length = sizeof(message); - result = isc_app_onrun(dt_mctx, task, startit, ®ion); + + result = isc_app_onrun(dt_mctx, task, startit, NULL); assert_int_equal(result, ISC_R_SUCCESS); result = isc_app_run(); assert_int_equal(result, ISC_R_SUCCESS); - assert_int_equal(atomic_load_acquire(&responses), 2); + assert_int_equal(atomic_load_acquire(&testdata.responses), 2); + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); /* * Shutdown nameserver. */ - isc_socket_cancel(sock, task, ISC_SOCKCANCEL_RECV); - isc_socket_detach(&sock); isc_task_detach(&task); /* diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index 5a16027e48..fac3f25725 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -96,10 +97,12 @@ cleanup_managers(void) { isc_task_shutdown(maintask); isc_task_destroy(&maintask); } + isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, taskmgr == NULL ? NULL : &taskmgr, timermgr == NULL ? NULL : &timermgr, socketmgr == NULL ? NULL : &socketmgr); + if (app_running) { isc_app_finish(); } diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index 53c7c6529f..a2c32cc146 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -46,6 +46,7 @@ extern isc_taskmgr_t *taskmgr; extern isc_task_t *maintask; extern isc_timermgr_t *timermgr; extern isc_socketmgr_t *socketmgr; +extern isc_nm_t *netmgr; extern dns_zonemgr_t *zonemgr; extern bool app_running; extern int ncpus; diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index 1a6e0f6143..2989af3041 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -50,15 +50,15 @@ _setup(void **state) { result = dns_test_begin(NULL, true); assert_int_equal(result, ISC_R_SUCCESS); - result = dns_dispatchmgr_create(dt_mctx, &dispatchmgr); + result = dns_dispatchmgr_create(dt_mctx, netmgr, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); result = dns_test_makeview("view", &view); assert_int_equal(result, ISC_R_SUCCESS); isc_sockaddr_any(&local); - result = dns_dispatch_createudp(dispatchmgr, socketmgr, taskmgr, &local, - 0, &dispatch); + result = dns_dispatch_createudp(dispatchmgr, taskmgr, &local, 0, + &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); @@ -80,8 +80,8 @@ static void mkres(dns_resolver_t **resolverp) { isc_result_t result; - result = dns_resolver_create(view, taskmgr, 1, 1, socketmgr, timermgr, - 0, dispatchmgr, dispatch, NULL, resolverp); + result = dns_resolver_create(view, taskmgr, 1, 1, netmgr, timermgr, 0, + dispatchmgr, dispatch, NULL, resolverp); assert_int_equal(result, ISC_R_SUCCESS); } diff --git a/lib/dns/view.c b/lib/dns/view.c index 27df703811..ed2045f131 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -634,6 +634,7 @@ view_flushanddetach(dns_view_t **viewp, bool flush) { dns_zone_t *mkzone = NULL, *rdzone = NULL; isc_refcount_destroy(&view->references); + if (!RESSHUTDOWN(view)) { dns_resolver_shutdown(view->resolver); } @@ -643,14 +644,14 @@ view_flushanddetach(dns_view_t **viewp, bool flush) { if (!REQSHUTDOWN(view)) { dns_requestmgr_shutdown(view->requestmgr); } - LOCK(&view->lock); - if (view->zonetable != NULL) { - if (view->flush) { - dns_zt_flushanddetach(&view->zonetable); - } else { - dns_zt_detach(&view->zonetable); - } + + if (view->zonetable != NULL && view->flush) { + dns_zt_flushanddetach(&view->zonetable); + } else if (view->zonetable != NULL) { + dns_zt_detach(&view->zonetable); } + + LOCK(&view->lock); if (view->managed_keys != NULL) { mkzone = view->managed_keys; view->managed_keys = NULL; @@ -796,9 +797,9 @@ dns_view_createzonetable(dns_view_t *view) { isc_result_t dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, - unsigned int ntasks, unsigned int ndisp, - isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, - unsigned int options, dns_dispatchmgr_t *dispatchmgr, + unsigned int ntasks, unsigned int ndisp, isc_nm_t *nm, + isc_timermgr_t *timermgr, unsigned int options, + dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6) { isc_result_t result; @@ -815,8 +816,8 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, } isc_task_setname(view->task, "view", view); - result = dns_resolver_create(view, taskmgr, ntasks, ndisp, socketmgr, - timermgr, options, dispatchmgr, dispatchv4, + result = dns_resolver_create(view, taskmgr, ntasks, ndisp, nm, timermgr, + options, dispatchmgr, dispatchv4, dispatchv6, &view->resolver); if (result != ISC_R_SUCCESS) { isc_task_detach(&view->task); @@ -841,11 +842,10 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, atomic_fetch_and(&view->attributes, ~DNS_VIEWATTR_ADBSHUTDOWN); isc_refcount_increment(&view->weakrefs); - result = dns_requestmgr_create(view->mctx, timermgr, socketmgr, - dns_resolver_taskmgr(view->resolver), - dns_resolver_dispatchmgr(view->resolver), - dispatchv4, dispatchv6, - &view->requestmgr); + result = dns_requestmgr_create( + view->mctx, dns_resolver_taskmgr(view->resolver), + dns_resolver_dispatchmgr(view->resolver), dispatchv4, + dispatchv6, &view->requestmgr); if (result != ISC_R_SUCCESS) { dns_adb_shutdown(view->adb); dns_resolver_shutdown(view->resolver); @@ -2502,12 +2502,12 @@ dns_view_setviewcommit(dns_view_t *view) { if (view->managed_keys != NULL) { dns_zone_attach(view->managed_keys, &managed_keys); } - if (view->zonetable != NULL) { - dns_zt_setviewcommit(view->zonetable); - } UNLOCK(&view->lock); + if (view->zonetable != NULL) { + dns_zt_setviewcommit(view->zonetable); + } if (redirect != NULL) { dns_zone_setviewcommit(redirect); dns_zone_detach(&redirect); diff --git a/lib/dns/zt.c b/lib/dns/zt.c index 8ca9cd65aa..da4f222ab6 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -483,6 +483,7 @@ dns_zt_setviewcommit(dns_zt_t *zt) { REQUIRE(VALID_ZT(zt)); + RWLOCK(&zt->rwlock, isc_rwlocktype_read); dns_rbtnodechain_init(&chain); result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); @@ -496,6 +497,7 @@ dns_zt_setviewcommit(dns_zt_t *zt) { } dns_rbtnodechain_invalidate(&chain); + RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); } void diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 19cc946bc3..c14607f81d 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -450,6 +450,16 @@ isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats); * full range of socket-related stats counter numbers. */ +isc_result_t +isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type); +/*%< + * Check whether the specified address is available on the local system + * by opening a socket and immediately closing it. + * + * Requires: + *\li 'addr' is not NULL. + */ + void isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, diff --git a/lib/isc/managers.c b/lib/isc/managers.c index f86d4c8485..628dd33fa9 100644 --- a/lib/isc/managers.c +++ b/lib/isc/managers.c @@ -91,7 +91,7 @@ isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp, /* * If we have a taskmgr to clean up, then we must also have a netmgr. */ - REQUIRE(taskmgrp != NULL || netmgrp == NULL); + REQUIRE(taskmgrp == NULL || netmgrp != NULL); /* * The sequence of operations here is important: diff --git a/lib/isc/socket.c b/lib/isc/socket.c index c28b32165c..1f3b107bf9 100644 --- a/lib/isc/socket.c +++ b/lib/isc/socket.c @@ -2593,7 +2593,7 @@ isc_socket_close(isc_socket_t *sock) { int fd; isc_socketmgr_t *manager; isc__socketthread_t *thread; - fflush(stdout); + REQUIRE(VALID_SOCKET(sock)); LOCK(&sock->lock); diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 045c74f9cc..2590794285 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -482,7 +482,7 @@ ns_interface_listentcp(ns_interface_t *ifp) { #if 0 #ifndef ISC_ALLOW_MAPPED - isc_socket_ipv6only(ifp->tcpsocket,true); + isc_socket_ipv6only(ifp->tcpsocket, true); #endif /* ifndef ISC_ALLOW_MAPPED */ if (ifp->dscp != -1) { diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index ffcf23adfa..8ece586163 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -233,7 +233,7 @@ create_managers(void) { CHECK(ns_server_create(mctx, matchview, &sctx)); - CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + CHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, socketmgr, netmgr, dispatchmgr, maintask, NULL, ncpus, From 08ce69a0ea1c33cbf62b6b5896affb047a71be42 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 22 Apr 2021 18:58:01 -0700 Subject: [PATCH 18/28] Rewrite dns_resolver and dns_request to use netmgr timeouts - The `timeout_action` parameter to dns_dispatch_addresponse() been replaced with a netmgr callback that is called when a dispatch read times out. this callback may optionally reset the read timer and resume reading. - Added a function to convert isc_interval to milliseconds; this is used to translate fctx->interval into a value that can be passed to dns_dispatch_addresponse() as the timeout. - Note that netmgr timeouts are accurate to the millisecond, so code to check whether a timeout has been reached cannot rely on microsecond accuracy. - If serve-stale is configured, then a timeout received by the resolver may trigger it to return stale data, and then resume waiting for the read timeout. this is no longer based on a separate stale timer. - The code for canceling requests in request.c has been altered so that it can run asynchronously. - TCP timeout events apply to the dispatch, which may be shared by multiple queries. since in the event of a timeout we have no query ID to use to identify the resp we wanted, we now just send the timeout to the oldest query that was pending. - There was some additional refactoring in the resolver: combining fctx_join() and fctx_try_events() into one function to reduce code duplication, and using fixednames in fetchctx and fetchevent. - Incidental fix: new_adbaddrinfo() can't return NULL anymore, so the code can be simplified. --- lib/dns/adb.c | 23 +- lib/dns/client.c | 6 +- lib/dns/dispatch.c | 68 ++- lib/dns/include/dns/dispatch.h | 10 +- lib/dns/include/dns/resolver.h | 3 +- lib/dns/lookup.c | 9 +- lib/dns/request.c | 232 +++---- lib/dns/resolver.c | 1038 +++++++++++++------------------- lib/dns/validator.c | 4 +- lib/isc/include/isc/netmgr.h | 6 + lib/isc/include/isc/time.h | 10 + lib/isc/netmgr/netmgr.c | 8 + lib/isc/time.c | 9 + lib/ns/query.c | 2 +- 14 files changed, 601 insertions(+), 827 deletions(-) diff --git a/lib/dns/adb.c b/lib/dns/adb.c index e7fee8d38e..e3a469222f 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -2237,11 +2237,9 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, find->options |= DNS_ADBFIND_LAMEPRUNED; goto nextv4; } + addrinfo = new_adbaddrinfo(adb, entry, find->port); - if (addrinfo == NULL) { - find->partial_result |= DNS_ADBFIND_INET; - goto out; - } + /* * Found a valid entry. Add it to the find's list. */ @@ -2275,10 +2273,7 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, goto nextv6; } addrinfo = new_adbaddrinfo(adb, entry, find->port); - if (addrinfo == NULL) { - find->partial_result |= DNS_ADBFIND_INET6; - goto out; - } + /* * Found a valid entry. Add it to the find's list. */ @@ -2292,7 +2287,6 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, } } -out: if (bucket != DNS_ADB_INVALIDBUCKET) { UNLOCK(&adb->entrylocks[bucket]); } @@ -3962,8 +3956,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl); clean_target(adb, &name->target); name->expire_target = INT_MAX; - result = set_target(adb, &name->name, - dns_fixedname_name(&dev->foundname), + result = set_target(adb, &name->name, dev->foundname, dev->rdataset, &name->target); if (result == ISC_R_SUCCESS) { DP(NCACHE_LEVEL, @@ -4533,12 +4526,8 @@ dns_adb_findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *sa, port = isc_sockaddr_getport(sa); addr = new_adbaddrinfo(adb, entry, port); - if (addr == NULL) { - result = ISC_R_NOMEMORY; - } else { - inc_entry_refcnt(adb, entry, false); - *addrp = addr; - } + inc_entry_refcnt(adb, entry, false); + *addrp = addr; unlock: UNLOCK(&adb->entrylocks[bucket]); diff --git a/lib/dns/client.c b/lib/dns/client.c index 70a1adb859..d33be3708f 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -579,9 +579,9 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { isc_result_t vresult = ISC_R_SUCCESS; bool want_restart; bool send_event = false; - dns_name_t *name, *prefix; + dns_name_t *name = NULL, *prefix = NULL; dns_fixedname_t foundname, fixed; - dns_rdataset_t *trdataset; + dns_rdataset_t *trdataset = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int nlabels; int order; @@ -643,7 +643,7 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { node = event->node; result = event->result; vresult = event->vresult; - fname = dns_fixedname_name(&event->foundname); + fname = event->foundname; INSIST(event->rdataset == rctx->rdataset); INSIST(event->sigrdataset == rctx->sigrdataset); } diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index a159e79c55..3f36a52223 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -37,6 +37,8 @@ #include #include +#define DISPATCH_TRACE + typedef ISC_LIST(dns_dispentry_t) dns_displist_t; typedef struct dispsocket dispsocket_t; @@ -89,8 +91,8 @@ struct dns_dispentry { isc_task_t *task; isc_nm_cb_t connected; isc_nm_cb_t sent; + isc_nm_cb_t timedout; isc_taskaction_t action; - isc_taskaction_t timeout_action; void *arg; bool item_out; dispsocket_t *dispsocket; @@ -729,7 +731,6 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dns_dispatchmgr_t *mgr = NULL; isc_sockaddr_t peer; isc_netaddr_t netaddr; - isc_taskaction_t action; int match; REQUIRE(VALID_DISPSOCK(dispsock)); @@ -767,8 +768,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, } if (dispsock == NULL) { - UNLOCK(&disp->lock); - return; + goto next; } resp = dispsock->resp; @@ -777,12 +777,20 @@ 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)) { + goto next; + } + } + if (eresult != ISC_R_SUCCESS) { /* - * 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. + * This is most likely a network error on a connected + * socket, or a timeout on a timer that has not been + * reset. It makes no sense to check the address or + * parse the packet, but it will help to return the + * error to the caller. */ goto sendevent; } @@ -858,12 +866,11 @@ sendevent: 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, - action, resp->arg, resp, NULL, NULL); + resp->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, @@ -900,6 +907,7 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dns_messageid_t id; isc_result_t dres; unsigned int flags; + dispsocket_t *dispsock = NULL; dns_dispentry_t *resp = NULL; dns_dispatchevent_t *rev = NULL; unsigned int bucket; @@ -910,7 +918,6 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, char buf[ISC_SOCKADDR_FORMATSIZE]; isc_buffer_t source; isc_sockaddr_t peer; - isc_taskaction_t action; REQUIRE(VALID_DISPATCH(disp)); @@ -940,6 +947,8 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, switch (eresult) { case ISC_R_CANCELED: + dispatch_log(disp, LVL(90), "shutting down on cancel"); + do_cancel(disp); break; case ISC_R_EOF: @@ -952,8 +961,26 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, goto logit; case ISC_R_TIMEDOUT: - id = 0; /* XXX this is broken */ - goto sendevent; + /* + * Time out the first active response for which + * no event has already been sent. + */ + for (dispsock = ISC_LIST_HEAD(disp->activesockets); + dispsock != NULL; + dispsock = ISC_LIST_NEXT(dispsock, link)) + { + resp = dispsock->resp; + if (resp->item_out) { + continue; + } + ISC_LIST_UNLINK(disp->activesockets, dispsock, + link); + ISC_LIST_APPEND(disp->activesockets, dispsock, + link); + goto sendevent; + } + INSIST(0); + ISC_UNREACHABLE(); default: level = ISC_LOG_ERROR; @@ -1014,20 +1041,20 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, goto next; } -sendevent: /* - * Response. + * We have a response; find the associated dispentry. */ bucket = dns_hash(qid, &peer, id, disp->localport); LOCK(&qid->lock); 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")); + UNLOCK(&qid->lock); if (resp == NULL) { - UNLOCK(&qid->lock); goto next; } +sendevent: queue_response = resp->item_out; rev = allocate_devent(disp); @@ -1052,14 +1079,13 @@ sendevent: ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - action, resp->arg, resp, NULL, NULL); + resp->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); isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } - UNLOCK(&qid->lock); next: startrecv(disp, NULL); @@ -1710,8 +1736,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, 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_nm_cb_t timedout, void *arg, dns_messageid_t *idp, + dns_dispentry_t **resp) { isc_result_t result; dns_dispentry_t *res = NULL; dispsocket_t *dispsocket = NULL; @@ -1829,8 +1855,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, .peer = *dest, .connected = connected, .sent = sent, + .timedout = timedout, .action = action, - .timeout_action = timeout_action, .arg = arg, .dispsocket = dispsocket }; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index aea71f9bd5..762a979ad8 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -312,8 +312,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, 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_nm_cb_t timedout, void *arg, dns_messageid_t *idp, + dns_dispentry_t **resp); /*%< * Add a response entry for this dispatch. * @@ -321,7 +321,9 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, * to contain the magic token used to request event flow stop. * * The 'connected' and 'sent' callbacks are run to inform the caller when - * the connection and send functions are complete. + * the connect and send functions are complete. The 'timedout' callback + * is run to inform the caller that a read has timed out; it may optionally + * reset the read timer. * * The specified 'task' is sent the 'action' callback for response packets. * (Later, this should be updated to a network manager callback function, @@ -329,8 +331,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, * 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: diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index aeda97dd38..350bdf0ac2 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -74,7 +74,8 @@ typedef struct dns_fetchevent { dns_dbnode_t * node; dns_rdataset_t * rdataset; dns_rdataset_t * sigrdataset; - dns_fixedname_t foundname; + dns_fixedname_t fname; + dns_name_t * foundname; const isc_sockaddr_t *client; dns_messageid_t id; isc_result_t vresult; diff --git a/lib/dns/lookup.c b/lib/dns/lookup.c index d62aaee2f4..6d9dadd165 100644 --- a/lib/dns/lookup.c +++ b/lib/dns/lookup.c @@ -140,10 +140,10 @@ view_find(dns_lookup_t *lookup, dns_name_t *foundname) { static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { - isc_result_t result; + isc_result_t result = ISC_R_SUCCESS; bool want_restart; bool send_event; - dns_name_t *name, *fname, *prefix; + dns_name_t *name = NULL, *fname = NULL, *prefix = NULL; dns_fixedname_t foundname, fixed; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int nlabels; @@ -156,7 +156,6 @@ lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { LOCK(&lookup->lock); - result = ISC_R_SUCCESS; name = dns_fixedname_name(&lookup->name); do { @@ -202,12 +201,10 @@ lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { } } else if (event != NULL) { result = event->result; - fname = dns_fixedname_name(&event->foundname); + fname = event->foundname; dns_resolver_destroyfetch(&lookup->fetch); INSIST(event->rdataset == &lookup->rdataset); INSIST(event->sigrdataset == &lookup->sigrdataset); - } else { - fname = NULL; /* Silence compiler warning. */ } /* diff --git a/lib/dns/request.c b/lib/dns/request.c index c629997c02..fcb378ed6a 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -75,24 +76,20 @@ struct dns_request { isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; isc_socketevent_t sendevent; - isc_event_t ctlevent; - bool canceling; /* ctlevent outstanding */ isc_sockaddr_t destaddr; + unsigned int timeout; unsigned int udpcount; isc_dscp_t dscp; }; #define DNS_REQUEST_F_CONNECTING 0x0001 #define DNS_REQUEST_F_SENDING 0x0002 -#define DNS_REQUEST_F_CANCELED \ - 0x0004 /*%< ctlevent received, or otherwise \ - * synchronously canceled */ -#define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< canceled due to a timeout */ -#define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */ +#define DNS_REQUEST_F_CANCELED 0x0004 +#define DNS_REQUEST_F_TCP 0x0010 + #define DNS_REQUEST_CANCELED(r) (((r)->flags & DNS_REQUEST_F_CANCELED) != 0) #define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0) #define DNS_REQUEST_SENDING(r) (((r)->flags & DNS_REQUEST_F_SENDING) != 0) -#define DNS_REQUEST_TIMEDOUT(r) (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0) /*** *** Forward @@ -113,21 +110,19 @@ req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, 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_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); +req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void req_destroy(dns_request_t *request); static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); -static void -do_cancel(isc_task_t *task, isc_event_t *event); +void +request_cancel(dns_request_t *request); /*** *** Public @@ -236,9 +231,6 @@ static void mgr_shutdown(dns_requestmgr_t *requestmgr) { dns_request_t *request; - /* - * Caller holds lock. - */ if (!requestmgr->exiting) { requestmgr->exiting = true; for (request = ISC_LIST_HEAD(requestmgr->requests); @@ -422,9 +414,6 @@ new_request(isc_mem_t *mctx, dns_request_t **requestp) { request = isc_mem_get(mctx, sizeof(*request)); *request = (dns_request_t){ .dscp = -1 }; ISC_LINK_INIT(request, link); - ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL, - DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL, - NULL); isc_mem_attach(mctx, &request->mctx); @@ -574,16 +563,6 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, return (result); } - if (udptimeout == 0 && udpretries != 0) { - udptimeout = timeout / (udpretries + 1); - if (udptimeout == 0) { - udptimeout = 1; - } - } - - timeout *= 1000; - udptimeout *= 1000; - request->udpcount = udpretries; request->dscp = dscp; @@ -603,6 +582,15 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) { tcp = true; + request->timeout = timeout * 1000; + } else { + if (udptimeout == 0 && udpretries != 0) { + udptimeout = timeout / (udpretries + 1); + } + if (udptimeout == 0) { + udptimeout = 1; + } + request->timeout = udptimeout * 1000; } again: @@ -618,9 +606,9 @@ again: } result = dns_dispatch_addresponse( - request->dispatch, dispopt, tcp ? timeout : udptimeout, - destaddr, task, req_connected, req_senddone, req_response, - req_timeout, request, &id, &request->dispentry); + request->dispatch, dispopt, request->timeout, 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; @@ -708,7 +696,7 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_result_t result; isc_mem_t *mctx; dns_messageid_t id; - bool tcp; + bool tcp = false; bool settsigkey = true; bool connected = false; @@ -738,16 +726,6 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, return (result); } - if (udptimeout == 0 && udpretries != 0) { - udptimeout = timeout / (udpretries + 1); - if (udptimeout == 0) { - udptimeout = 1; - } - } - - timeout *= 1000; - udptimeout *= 1000; - request->udpcount = udpretries; request->dscp = dscp; @@ -763,7 +741,19 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, } use_tcp: - tcp = ((options & DNS_REQUESTOPT_TCP) != 0); + if ((options & DNS_REQUESTOPT_TCP) != 0) { + tcp = true; + request->timeout = timeout * 1000; + } else { + if (udptimeout == 0 && udpretries != 0) { + udptimeout = timeout / (udpretries + 1); + } + if (udptimeout == 0) { + udptimeout = 1; + } + request->timeout = udptimeout * 1000; + } + result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr, dscp, &connected, &request->dispatch); if (result != ISC_R_SUCCESS) { @@ -771,9 +761,9 @@ use_tcp: } result = dns_dispatch_addresponse( - request->dispatch, 0, tcp ? timeout : udptimeout, destaddr, - task, req_connected, req_senddone, req_response, req_timeout, - request, &id, &request->dispentry); + request->dispatch, 0, request->timeout, destaddr, task, + req_connected, req_senddone, req_response, req_timeout, request, + &id, &request->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -952,26 +942,28 @@ cleanup: */ static void send_if_done(dns_request_t *request, isc_result_t result) { - if (request->event != NULL && !request->canceling) { + if (request->event != NULL) { req_sendevent(request, result); } } -/* - * Handle the control event. - */ -static void -do_cancel(isc_task_t *task, isc_event_t *event) { - dns_request_t *request = event->ev_arg; - UNUSED(task); - INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL); - LOCK(&request->requestmgr->locks[request->hash]); - request->canceling = false; +void +request_cancel(dns_request_t *request) { if (!DNS_REQUEST_CANCELED(request)) { - req_cancel(request); + req_log(ISC_LOG_DEBUG(3), "do_cancel: request %p", request); + + request->flags |= DNS_REQUEST_F_CANCELED; + request->flags &= ~DNS_REQUEST_F_CONNECTING; + + if (request->dispentry != NULL) { + dns_dispatch_cancel(NULL, request->dispentry, + DNS_REQUEST_SENDING(request), + DNS_REQUEST_CONNECTING(request)); + dns_dispatch_removeresponse(&request->dispentry, NULL); + } + + dns_dispatch_detach(&request->dispatch); } - send_if_done(request, ISC_R_CANCELED); - UNLOCK(&request->requestmgr->locks[request->hash]); } void @@ -979,15 +971,9 @@ dns_request_cancel(dns_request_t *request) { REQUIRE(VALID_REQUEST(request)); req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request); - - REQUIRE(VALID_REQUEST(request)); - LOCK(&request->requestmgr->locks[request->hash]); - if (!request->canceling && !DNS_REQUEST_CANCELED(request)) { - isc_event_t *ev = &request->ctlevent; - isc_task_send(request->event->ev_sender, &ev); - request->canceling = true; - } + request_cancel(request); + send_if_done(request, ISC_R_CANCELED); UNLOCK(&request->requestmgr->locks[request->hash]); } @@ -1054,8 +1040,8 @@ dns_request_destroy(dns_request_t **requestp) { UNLOCK(&request->requestmgr->lock); /* - * These should have been cleaned up by req_cancel() before - * the completion event was sent. + * These should have been cleaned up before the completion + * event was sent. */ INSIST(!ISC_LINK_LINKED(request, link)); INSIST(request->dispentry == NULL); @@ -1073,6 +1059,10 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { UNUSED(handle); + if (eresult == ISC_R_CANCELED) { + return; + } + REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_CONNECTING(request)); @@ -1081,22 +1071,17 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_CONNECTING; - 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); - } + if (eresult == ISC_R_TIMEDOUT) { + dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_detach(&request->dispatch); + send_if_done(request, eresult); + } else if (DNS_REQUEST_CANCELED(request)) { + send_if_done(request, ISC_R_CANCELED); + } else if (eresult == ISC_R_SUCCESS) { + req_send(request); } else { - if (eresult == ISC_R_SUCCESS) { - req_send(request); - } else { - req_cancel(request); - send_if_done(request, ISC_R_CANCELED); - } + request_cancel(request); + send_if_done(request, ISC_R_CANCELED); } UNLOCK(&request->requestmgr->locks[request->hash]); } @@ -1116,19 +1101,39 @@ req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { request->flags &= ~DNS_REQUEST_F_SENDING; if (DNS_REQUEST_CANCELED(request)) { - if (DNS_REQUEST_TIMEDOUT(request)) { - send_if_done(request, ISC_R_TIMEDOUT); + if (eresult == ISC_R_TIMEDOUT) { + send_if_done(request, eresult); } else { send_if_done(request, ISC_R_CANCELED); } } else if (eresult != ISC_R_SUCCESS) { - req_cancel(request); + request_cancel(request); send_if_done(request, ISC_R_CANCELED); } UNLOCK(&request->requestmgr->locks[request->hash]); } +static void +req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_request_t *request = (dns_request_t *)arg; + + REQUIRE(VALID_REQUEST(request)); + + UNUSED(eresult); + + req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); + + LOCK(&request->requestmgr->locks[request->hash]); + if (--request->udpcount != 0) { + isc_nmhandle_settimeout(handle, request->timeout); + if (!DNS_REQUEST_SENDING(request)) { + req_send(request); + } + } + UNLOCK(&request->requestmgr->locks[request->hash]); +} + static void req_response(isc_task_t *task, isc_event_t *event) { isc_result_t result; @@ -1164,7 +1169,8 @@ done: * Cleanup. */ dns_dispatch_removeresponse(&request->dispentry, &devent); - req_cancel(request); + request_cancel(request); + /* * Send completion event. */ @@ -1172,29 +1178,6 @@ done: UNLOCK(&request->requestmgr->locks[request->hash]); } -static void -req_timeout(isc_task_t *task, isc_event_t *event) { - dns_request_t *request = event->ev_arg; - - REQUIRE(VALID_REQUEST(request)); - - req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); - - UNUSED(task); - LOCK(&request->requestmgr->locks[request->hash]); - if (request->udpcount-- != 0) { - if (!DNS_REQUEST_SENDING(request)) { - req_send(request); - } - } else { - request->flags |= DNS_REQUEST_F_TIMEDOUT; - req_cancel(request); - send_if_done(request, ISC_R_TIMEDOUT); - } - UNLOCK(&request->requestmgr->locks[request->hash]); - isc_event_free(&event); -} - static void req_sendevent(dns_request_t *request, isc_result_t result) { isc_task_t *task; @@ -1246,29 +1229,6 @@ req_destroy(dns_request_t *request) { isc_mem_putanddetach(&request->mctx, request, sizeof(*request)); } -/* - * Stop the current request. Must be called from the request's task. - */ -static void -req_cancel(dns_request_t *request) { - REQUIRE(VALID_REQUEST(request)); - - req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request); - - /* - * Lock held by caller. - */ - request->flags |= DNS_REQUEST_F_CANCELED; - - if (request->dispentry != NULL) { - dns_dispatch_cancel(NULL, request->dispentry, - DNS_REQUEST_SENDING(request), - DNS_REQUEST_CONNECTING(request)); - dns_dispatch_removeresponse(&request->dispentry, NULL); - } - dns_dispatch_detach(&request->dispatch); -} - static void req_log(int level, const char *fmt, ...) { va_list ap; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index b987b888cb..d140628fb0 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -151,6 +151,7 @@ #define US_PER_SEC 1000000U #define US_PER_MSEC 1000U +#define NS_PER_US 1000U /* * The maximum time we will wait for a single query. */ @@ -277,7 +278,8 @@ struct fetchctx { /*% Not locked. */ unsigned int magic; dns_resolver_t *res; - dns_name_t name; + dns_fixedname_t fname; + dns_name_t *name; dns_rdatatype_t type; unsigned int options; unsigned int bucketnum; @@ -299,13 +301,13 @@ struct fetchctx { ISC_LIST(dns_fetchevent_t) events; /*% Locked by task event serialization. */ - dns_name_t domain; + dns_fixedname_t dfname; + dns_name_t *domain; dns_rdataset_t nameservers; atomic_uint_fast32_t attributes; - isc_timer_t *timer; - isc_timer_t *timer_try_stale; isc_time_t expires; isc_time_t expires_try_stale; + isc_time_t next_timeout; isc_interval_t interval; dns_message_t *qmessage; ISC_LIST(resquery_t) queries; @@ -332,11 +334,13 @@ struct fetchctx { isc_result_t qmin_warning; bool ip6arpaskip; bool forwarding; - dns_name_t qminname; + dns_fixedname_t qminfname; + dns_name_t *qminname; dns_rdatatype_t qmintype; dns_fetch_t *qminfetch; dns_rdataset_t qminrrset; - dns_name_t qmindcname; + dns_fixedname_t qmindcfname; + dns_name_t *qmindcname; /*% * The number of events we're waiting for. @@ -363,7 +367,9 @@ struct fetchctx { /*% * Look aside state for DS lookups. */ - dns_name_t nsname; + dns_fixedname_t nsfname; + dns_name_t *nsname; + dns_fetch_t *nsfetch; dns_rdataset_t nsrrset; @@ -462,7 +468,7 @@ typedef struct fctxbucket { typedef struct fctxcount fctxcount_t; struct fctxcount { - dns_fixedname_t fdname; + dns_fixedname_t dfname; dns_name_t *domain; uint32_t count; uint32_t allowed; @@ -852,6 +858,9 @@ rctx_lameserver(respctx_t *rctx); static isc_result_t rctx_dispfail(respctx_t *rctx); +static isc_result_t +rctx_timedout(respctx_t *rctx); + static void rctx_delonly_zone(respctx_t *rctx); @@ -929,7 +938,7 @@ rrsig_fromchildzone(fetchctx_t *fctx, dns_rdataset_t *rdataset) { dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &rrsig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - namereln = dns_name_fullcompare(&rrsig.signer, &fctx->domain, + namereln = dns_name_fullcompare(&rrsig.signer, fctx->domain, &order, &labels); if (namereln == dns_namereln_subdomain) { return (true); @@ -942,7 +951,7 @@ rrsig_fromchildzone(fetchctx_t *fctx, dns_rdataset_t *rdataset) { static bool fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) { dns_name_t *name; - dns_name_t *domain = &fctx->domain; + dns_name_t *domain = fctx->domain; dns_rdataset_t *rdataset; dns_rdatatype_t type; isc_result_t result; @@ -999,7 +1008,7 @@ fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) { rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { - if (!dns_name_equal(name, &fctx->name)) { + if (!dns_name_equal(name, fctx->name)) { continue; } type = rdataset->type; @@ -1112,79 +1121,6 @@ munge: return (true); } -static inline isc_result_t -fctx_starttimer(fetchctx_t *fctx) { - /* - * Start the lifetime timer for fctx. - * - * This is also used for stopping the idle timer; in that - * case we must purge events already posted to ensure that - * no further idle events are delivered. - */ - return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->expires, - NULL, true)); -} - -static inline isc_result_t -fctx_starttimer_trystale(fetchctx_t *fctx) { - /* - * Start the stale-answer-client-timeout timer for fctx. - */ - - return (isc_timer_reset(fctx->timer_try_stale, isc_timertype_once, - &fctx->expires_try_stale, NULL, true)); -} - -static inline void -fctx_stoptimer(fetchctx_t *fctx) { - isc_result_t result; - - /* - * We don't return a result if resetting the timer to inactive fails - * since there's nothing to be done about it. Resetting to inactive - * should never fail anyway, since the code as currently written - * cannot fail in that case. - */ - result = isc_timer_reset(fctx->timer, isc_timertype_inactive, NULL, - NULL, true); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_reset(): %s", - isc_result_totext(result)); - } -} - -static inline void -fctx_stoptimer_trystale(fetchctx_t *fctx) { - isc_result_t result; - - if (fctx->timer_try_stale != NULL) { - result = isc_timer_reset(fctx->timer_try_stale, - isc_timertype_inactive, NULL, NULL, - true); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_timer_reset(): %s", - isc_result_totext(result)); - } - } -} - -static inline isc_result_t -fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) { - /* - * Start the idle timer for fctx. The lifetime timer continues - * to be in effect. - */ - return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->expires, - interval, false)); -} - -/* - * Stopping the idle timer is equivalent to calling fctx_starttimer(), but - * we use fctx_stopidletimer for readability in the code below. - */ -#define fctx_stopidletimer fctx_starttimer - static inline void resquery_destroy(resquery_t **queryp) { dns_resolver_t *res; @@ -1273,7 +1209,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, &query->start); factor = DNS_ADB_RTTADJDEFAULT; - rttms = rtt / 1000; + rttms = rtt / US_PER_MSEC; if (rttms < DNS_RESOLVER_QRYRTTCLASS0) { inc_stats(fctx->res, dns_resstatscounter_queryrtt0); @@ -1528,8 +1464,6 @@ static inline void fctx_stopqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { FCTXTRACE("stopqueries"); fctx_cancelqueries(fctx, no_response, age_untried); - fctx_stoptimer(fctx); - fctx_stoptimer_trystale(fctx); } static inline void @@ -1554,7 +1488,7 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter) { return; } - dns_name_format(&fctx->domain, dbuf, sizeof(dbuf)); + dns_name_format(fctx->domain, dbuf, sizeof(dbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_SPILL, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -1568,16 +1502,15 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter) { static isc_result_t fcount_incr(fetchctx_t *fctx, bool force) { isc_result_t result = ISC_R_SUCCESS; - zonebucket_t *dbucket; - fctxcount_t *counter; + zonebucket_t *dbucket = NULL; + fctxcount_t *counter = NULL; unsigned int bucketnum; REQUIRE(fctx != NULL); REQUIRE(fctx->res != NULL); INSIST(fctx->dbucketnum == RES_NOBUCKET); - bucketnum = dns_name_fullhash(&fctx->domain, false) % - RES_DOMAIN_BUCKETS; + bucketnum = dns_name_fullhash(fctx->domain, false) % RES_DOMAIN_BUCKETS; dbucket = &fctx->res->dbuckets[bucketnum]; @@ -1585,7 +1518,7 @@ fcount_incr(fetchctx_t *fctx, bool force) { for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; counter = ISC_LIST_NEXT(counter, link)) { - if (dns_name_equal(counter->domain, &fctx->domain)) { + if (dns_name_equal(counter->domain, fctx->domain)) { break; } } @@ -1599,8 +1532,8 @@ fcount_incr(fetchctx_t *fctx, bool force) { counter->allowed = 1; counter->dropped = 0; counter->domain = - dns_fixedname_initname(&counter->fdname); - dns_name_copy(&fctx->domain, counter->domain); + dns_fixedname_initname(&counter->dfname); + dns_name_copy(fctx->domain, counter->domain); ISC_LIST_APPEND(dbucket->list, counter, link); } } else { @@ -1625,8 +1558,8 @@ fcount_incr(fetchctx_t *fctx, bool force) { static void fcount_decr(fetchctx_t *fctx) { - zonebucket_t *dbucket; - fctxcount_t *counter; + zonebucket_t *dbucket = NULL; + fctxcount_t *counter = NULL; REQUIRE(fctx != NULL); @@ -1640,7 +1573,7 @@ fcount_decr(fetchctx_t *fctx) { for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; counter = ISC_LIST_NEXT(counter, link)) { - if (dns_name_equal(counter->domain, &fctx->domain)) { + if (dns_name_equal(counter->domain, fctx->domain)) { break; } } @@ -1802,7 +1735,6 @@ static void resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { resquery_t *query = (resquery_t *)arg; bool destroy_query = false; - isc_result_t result; fetchctx_t *fctx = NULL; QTRACE("senddone"); @@ -1840,17 +1772,8 @@ resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { badns_unreachable); fctx_cancelquery(&query, NULL, NULL, true, false); - /* - * 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); - } + fctx_try(fctx, true, false); break; default: @@ -1858,6 +1781,7 @@ resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { "due to unexpected result; responding", eresult); fctx_cancelquery(&query, NULL, NULL, false, false); + fctx_done(fctx, eresult, __LINE__); break; } } @@ -1883,10 +1807,23 @@ fctx_addopt(dns_message_t *message, unsigned int version, uint16_t udpsize, static inline void fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { - unsigned int seconds; - unsigned int us; + unsigned int seconds, us; + uint64_t limit; + isc_time_t now; + + /* + * Has this fetch already expired? + */ + isc_time_now(&now); + limit = isc_time_microdiff(&fctx->expires, &now); + if (limit < US_PER_MSEC) { + FCTXTRACE("fetch already expired"); + isc_interval_set(&fctx->interval, 0, 0); + return; + } + + us = fctx->res->retryinterval * US_PER_MSEC; - us = fctx->res->retryinterval * 1000; /* * Exponential backoff after the first few tries. */ @@ -1918,15 +1855,90 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { } /* - * But don't ever wait for more than 10 seconds. + * But don't wait past the stale timeout (if any), the final + * expiration of the fetch, or for more than 10 seconds total. */ + if ((fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0) { + uint64_t stale = isc_time_microdiff(&fctx->expires_try_stale, + &now); + if (stale >= US_PER_MSEC && us > stale) { + FCTXTRACE("setting stale timeout"); + us = stale; + } + } + if (us > limit) { + us = limit; + } if (us > MAX_SINGLE_QUERY_TIMEOUT_US) { us = MAX_SINGLE_QUERY_TIMEOUT_US; } seconds = us / US_PER_SEC; us -= seconds * US_PER_SEC; - isc_interval_set(&fctx->interval, seconds, us * 1000); + isc_interval_set(&fctx->interval, seconds, us * NS_PER_US); + isc_time_nowplusinterval(&fctx->next_timeout, &fctx->interval); +} + +static void +resquery_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + resquery_t *query = (resquery_t *)arg; + fetchctx_t *fctx = query->fctx; + dns_fetchevent_t *event = NULL, *next = NULL; + uint64_t timeleft; + isc_time_t now; + + REQUIRE(VALID_FCTX(fctx)); + + FCTXTRACE("timeout"); + + /* + * If not configured for serve-stale, do nothing. + */ + if (eresult == ISC_R_CANCELED || + (fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) == 0) + { + return; + } + + /* + * If we haven't reached the serve-stale timeout, do nothing. + * (Note that netmgr timeouts have millisecond accuracy, so + * anything less than 1000 microseconds is close enough to zero.) + */ + isc_time_now(&now); + timeleft = isc_time_microdiff(&fctx->expires_try_stale, &now); + if (timeleft >= US_PER_MSEC) { + return; + } + + /* + * Send the TRYSTALE events. + */ + LOCK(&fctx->res->buckets[fctx->bucketnum].lock); + for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next) { + isc_task_t *sender = NULL; + + next = ISC_LIST_NEXT(event, ev_link); + if (event->ev_type != DNS_EVENT_TRYSTALE) { + continue; + } + + ISC_LIST_UNLINK(fctx->events, event, ev_link); + sender = event->ev_sender; + event->vresult = ISC_R_TIMEDOUT; + event->result = ISC_R_TIMEDOUT; + isc_task_sendanddetach(&sender, ISC_EVENT_PTR(&event)); + } + UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + + /* + * If the next timeout is more than 1ms in the future, + * resume waiting. + */ + timeleft = isc_time_microdiff(&fctx->next_timeout, &now); + if (timeleft < US_PER_MSEC) { + isc_nmhandle_settimeout(handle, (timeleft / US_PER_MSEC)); + } } static isc_result_t @@ -1954,21 +1966,21 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, * negotiation) over the current RTT estimate. */ if ((options & DNS_FETCHOPT_TCP) != 0) { - srtt += 1000000; + srtt += US_PER_SEC; } /* * A forwarder needs to make multiple queries. Give it at least * a second to do these in. */ - if (ISFORWARDER(addrinfo) && srtt < 1000000) { - srtt = 1000000; + if (ISFORWARDER(addrinfo) && srtt < US_PER_SEC) { + srtt = US_PER_SEC; } fctx_setretryinterval(fctx, srtt); - result = fctx_startidletimer(fctx, &fctx->interval); - if (result != ISC_R_SUCCESS) { - return (result); + if (isc_interval_iszero(&fctx->interval)) { + FCTXTRACE("fetch expired"); + return (ISC_R_TIMEDOUT); } INSIST(ISC_LIST_EMPTY(fctx->validators)); @@ -2053,6 +2065,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (result != ISC_R_SUCCESS) { goto cleanup_query; } + + FCTXTRACE("connecting via TCP"); } else { if (have_addr) { switch (isc_sockaddr_pf(&addr)) { @@ -2111,6 +2125,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if ((query->options & DNS_FETCHOPT_TCP) == 0) { if (dns_adbentry_overquota(addrinfo->entry)) { + result = ISC_R_QUOTA; goto cleanup_dispatch; } @@ -2123,11 +2138,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, 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); + query->dispatch, 0, isc_interval_ms(&fctx->interval), + &query->addrinfo->sockaddr, task, resquery_connected, + resquery_senddone, resquery_response, resquery_timeout, query, + &query->id, &query->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup_dispatch; } @@ -2150,8 +2165,6 @@ cleanup_query: isc_mem_put(fctx->mctx, query, sizeof(*query)); } - RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS); - return (result); } @@ -2340,7 +2353,7 @@ resquery_send(resquery_t *query) { /* * Set up question. */ - dns_name_clone(&fctx->name, qname); + dns_name_clone(fctx->name, qname); dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION); @@ -2371,7 +2384,7 @@ resquery_send(resquery_t *query) { { bool checknta = ((query->options & DNS_FETCHOPT_NONTA) == 0); bool ntacovered = false; - result = issecuredomain(res->view, &fctx->name, fctx->type, + result = issecuredomain(res->view, fctx->name, fctx->type, isc_time_seconds(&query->start), checknta, &ntacovered, &secure_domain); if (result != ISC_R_SUCCESS) { @@ -2656,7 +2669,7 @@ resquery_send(resquery_t *query) { memset(&zr, 0, sizeof(zr)); isc_buffer_init(&zb, zone, sizeof(zone)); dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE); - result = dns_name_towire(&fctx->domain, &cctx, &zb); + result = dns_name_towire(fctx->domain, &cctx, &zb); if (result == ISC_R_SUCCESS) { isc_buffer_usedregion(&zb, &zr); } @@ -2742,7 +2755,6 @@ cleanup_temps: static void 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 = NULL; dns_resolver_t *res = NULL; @@ -2775,27 +2787,6 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } else { switch (eresult) { case ISC_R_SUCCESS: - - /* - * Extend the idle timer for TCP. Half of - * "resolver-query-timeout" will hopefully be long - * enough for a TCP connection to be established, a - * single DNS request to be sent, and the response - * received. - */ - isc_interval_set(&interval, - res->query_timeout / 1000 / 2, 0); - result = fctx_startidletimer(query->fctx, &interval); - if (result != ISC_R_SUCCESS) { - FCTXTRACE("query canceled: idle timer failed; " - "responding"); - - fctx_cancelquery(&query, NULL, NULL, false, - false); - fctx_done(fctx, result, __LINE__); - break; - } - /* * We are connected. Update the dispatcher and * send the query. @@ -2835,6 +2826,7 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNECTIONRESET: + case ISC_R_TIMEDOUT: FCTXTRACE3("query canceled in resquery_connected(): " "no route to host; no response", eresult); @@ -2847,18 +2839,8 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { badns_unreachable); fctx_cancelquery(&query, NULL, NULL, true, false); - /* - * 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); - } + fctx_try(fctx, true, false); break; default: @@ -2867,6 +2849,7 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { eresult); fctx_cancelquery(&query, NULL, NULL, false, false); + fctx_done(fctx, eresult, __LINE__); } } @@ -3117,7 +3100,7 @@ add_bad(fetchctx_t *fctx, dns_message_t *rmessage, dns_adbaddrinfo_t *addrinfo, } else { code[0] = '\0'; } - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(address, addrbuf, sizeof(addrbuf)); @@ -3229,7 +3212,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, * and we don't know its address (e.g. because the A record has * expired). */ - if (dns_name_issubdomain(name, &fctx->domain)) { + if (dns_name_issubdomain(name, fctx->domain)) { options |= DNS_ADBFIND_STARTATZONE; } options |= DNS_ADBFIND_GLUEOK; @@ -3241,7 +3224,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, find = NULL; result = dns_adb_createfind( fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone, - fctx, name, &fctx->name, fctx->type, options, now, NULL, + fctx, name, fctx->name, fctx->type, options, now, NULL, res->view->dstport, fctx->depth + 1, fctx->qc, &find); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, @@ -3418,7 +3401,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { fwd = ISC_LIST_HEAD(fctx->forwarders); if (fwd == NULL) { dns_forwarders_t *forwarders = NULL; - dns_name_t *name = &fctx->name; + dns_name_t *name = fctx->name; dns_name_t suffix; unsigned int labels; dns_fixedname_t fixed; @@ -3443,12 +3426,10 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { fwd = ISC_LIST_HEAD(forwarders->fwdrs); fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy == dns_fwdpolicy_only && - isstrictsubdomain(domain, &fctx->domain)) + isstrictsubdomain(domain, fctx->domain)) { fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(domain, fctx->mctx, &fctx->domain); + dns_name_copy(domain, fctx->domain); result = fcount_incr(fctx, true); if (result != ISC_R_SUCCESS) { return (result); @@ -3637,7 +3618,7 @@ out: fctx->type == dns_rdatatype_ds) && result == ISC_R_SUCCESS) { - dns_resolver_addbadcache(res, &fctx->name, + dns_resolver_addbadcache(res, fctx->name, fctx->type, &expire); } @@ -3993,7 +3974,7 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { char namebuf[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; - dns_name_format(&fctx->qminname, namebuf, + dns_name_format(fctx->qminname, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->qmintype, typebuf, sizeof(typebuf)); @@ -4021,13 +4002,11 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { } fctx_increference(fctx); task = res->buckets[bucketnum].task; - fctx_stoptimer(fctx); - fctx_stoptimer_trystale(fctx); result = dns_resolver_createfetch( - fctx->res, &fctx->qminname, fctx->qmintype, - &fctx->domain, &fctx->nameservers, NULL, NULL, 0, - options, 0, fctx->qc, task, resume_qmin, fctx, - &fctx->qminrrset, NULL, &fctx->qminfetch); + fctx->res, fctx->qminname, fctx->qmintype, fctx->domain, + &fctx->nameservers, NULL, NULL, 0, options, 0, fctx->qc, + task, resume_qmin, fctx, &fctx->qminrrset, NULL, + &fctx->qminfetch); if (result != ISC_R_SUCCESS) { LOCK(&fctx->res->buckets[fctx->bucketnum].lock); RUNTIME_CHECK(!fctx_decreference(fctx)); @@ -4156,7 +4135,7 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { if (dns_rdatatype_atparent(fctx->type)) { findoptions |= DNS_DBFIND_NOEXACT; } - result = dns_view_findzonecut(res->view, &fctx->name, fname, dcname, + result = dns_view_findzonecut(res->view, fctx->name, fname, dcname, fctx->now, findoptions, true, true, &fctx->nameservers, NULL); @@ -4174,9 +4153,8 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { goto cleanup; } fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(fname, fctx->mctx, &fctx->domain); + + dns_name_copy(fname, fctx->domain); result = fcount_incr(fctx, false); if (result != ISC_R_SUCCESS) { @@ -4184,9 +4162,7 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { goto cleanup; } - dns_name_free(&fctx->qmindcname, fctx->mctx); - dns_name_init(&fctx->qmindcname, NULL); - dns_name_dup(dcname, fctx->mctx, &fctx->qmindcname); + dns_name_copy(dcname, fctx->qmindcname); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; @@ -4304,20 +4280,10 @@ fctx_destroy(fetchctx_t *fctx) { isc_counter_detach(&fctx->qc); fcount_decr(fctx); - isc_timer_detach(&fctx->timer); - if (fctx->timer_try_stale != NULL) { - isc_timer_detach(&fctx->timer_try_stale); - } dns_message_detach(&fctx->qmessage); - if (dns_name_countlabels(&fctx->domain) > 0) { - dns_name_free(&fctx->domain, fctx->mctx); - } if (dns_rdataset_isassociated(&fctx->nameservers)) { dns_rdataset_disassociate(&fctx->nameservers); } - dns_name_free(&fctx->name, fctx->mctx); - dns_name_free(&fctx->qminname, fctx->mctx); - dns_name_free(&fctx->qmindcname, fctx->mctx); dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); isc_mem_free(fctx->mctx, fctx->info); @@ -4328,112 +4294,6 @@ fctx_destroy(fetchctx_t *fctx) { * Fetch event handlers. */ -static void -fctx_timeout(isc_task_t *task, isc_event_t *event) { - fetchctx_t *fctx = event->ev_arg; - isc_timerevent_t *tevent = (isc_timerevent_t *)event; - resquery_t *query; - - REQUIRE(VALID_FCTX(fctx)); - - UNUSED(task); - - FCTXTRACE("timeout"); - - inc_stats(fctx->res, dns_resstatscounter_querytimeout); - - if (event->ev_type == ISC_TIMEREVENT_LIFE) { - fctx_done(fctx, ISC_R_TIMEDOUT, __LINE__); - } else { - isc_result_t result; - - fctx->timeouts++; - fctx->timeout = true; - - /* - * We could cancel the running queries here, or we could let - * them keep going. Since we normally use separate sockets for - * different queries, we adopt the former approach to reduce - * the number of open sockets: cancel the oldest query if it - * expired after the query had started (this is usually the - * case but is not always so, depending on the task schedule - * timing). - */ - query = ISC_LIST_HEAD(fctx->queries); - if (query != NULL && - isc_time_compare(&tevent->due, &query->start) >= 0) { - FCTXTRACE("query timed out; no response"); - fctx_cancelquery(&query, NULL, NULL, true, false); - } - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - - /* - * Our timer has triggered. Reestablish the fctx lifetime - * timer. - */ - result = fctx_starttimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - /* Keep trying */ - fctx_try(fctx, true, false); - } - } - - isc_event_free(&event); -} - -/* - * Fetch event handlers called if stale answers are enabled - * (stale-answer-enabled) and the fetch took more than - * stale-answer-client-timeout to complete. - */ -static void -fctx_timeout_try_stale(isc_task_t *task, isc_event_t *event) { - fetchctx_t *fctx = event->ev_arg; - dns_fetchevent_t *dns_event, *next_event; - isc_task_t *sender_task; - unsigned int count = 0; - - REQUIRE(VALID_FCTX(fctx)); - - UNUSED(task); - - FCTXTRACE("timeout_try_stale"); - - if (event->ev_type != ISC_TIMEREVENT_LIFE) { - return; - } - - LOCK(&fctx->res->buckets[fctx->bucketnum].lock); - - /* - * Trigger events of type DNS_EVENT_TRYSTALE. - */ - for (dns_event = ISC_LIST_HEAD(fctx->events); dns_event != NULL; - dns_event = next_event) - { - next_event = ISC_LIST_NEXT(dns_event, ev_link); - - if (dns_event->ev_type != DNS_EVENT_TRYSTALE) { - continue; - } - - ISC_LIST_UNLINK(fctx->events, dns_event, ev_link); - sender_task = dns_event->ev_sender; - dns_event->ev_sender = fctx; - dns_event->vresult = ISC_R_TIMEDOUT; - dns_event->result = ISC_R_TIMEDOUT; - - isc_task_sendanddetach(&sender_task, ISC_EVENT_PTR(&dns_event)); - count++; - } - - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); - - isc_event_free(&event); -} - static void fctx_shutdown(fetchctx_t *fctx) { isc_event_t *cevent; @@ -4607,22 +4467,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { UNLOCK(&res->buckets[bucketnum].lock); if (!done) { - isc_result_t result; - INSIST(!dodestroy); - - /* - * All is well. Start working on the fetch. - */ - result = fctx_starttimer(fctx); - if (result == ISC_R_SUCCESS && fctx->timer_try_stale != NULL) { - result = fctx_starttimer_trystale(fctx); - } - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } else { - fctx_try(fctx, false, false); - } + fctx_try(fctx, false, false); } else if (dodestroy) { fctx_destroy(fctx); if (bucket_empty) { @@ -4635,26 +4481,23 @@ fctx_start(isc_task_t *task, isc_event_t *event) { * Fetch Creation, Joining, and Cancellation. */ -static inline isc_result_t -fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, - dns_messageid_t id, isc_taskaction_t action, void *arg, - dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, - dns_fetch_t *fetch) { - isc_task_t *tclone; - dns_fetchevent_t *event; - - FCTXTRACE("join"); +static inline void +fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, + dns_messageid_t id, isc_taskaction_t action, void *arg, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_fetch_t *fetch, isc_eventtype_t event_type) { + isc_task_t *tclone = NULL; + dns_fetchevent_t *event = NULL; /* * We store the task we're going to send this event to in the * sender field. We'll make the fetch the sender when we actually * send the event. */ - tclone = NULL; isc_task_attach(task, &tclone); - event = (dns_fetchevent_t *)isc_event_allocate( - fctx->res->mctx, tclone, DNS_EVENT_FETCHDONE, action, arg, - sizeof(*event)); + event = (dns_fetchevent_t *)isc_event_allocate(fctx->res->mctx, tclone, + event_type, action, arg, + sizeof(*event)); event->result = DNS_R_SERVFAIL; event->qtype = fctx->type; event->db = NULL; @@ -4664,17 +4507,28 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, event->fetch = fetch; event->client = client; event->id = id; - dns_fixedname_init(&event->foundname); + event->foundname = dns_fixedname_initname(&event->fname); /* - * Make sure that we can store the sigrdataset in the - * first event if it is needed by any of the events. + * Store the sigrdataset in the first event in case it is needed by + * any of the events. */ if (event->sigrdataset != NULL) { ISC_LIST_PREPEND(fctx->events, event, ev_link); } else { ISC_LIST_APPEND(fctx->events, event, ev_link); } +} + +static inline isc_result_t +fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, + dns_messageid_t id, isc_taskaction_t action, void *arg, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_fetch_t *fetch) { + FCTXTRACE("join"); + + fctx_add_event(fctx, task, client, id, action, arg, rdataset, + sigrdataset, fetch, DNS_EVENT_FETCHDONE); fctx_increference(fctx); @@ -4684,41 +4538,13 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, return (ISC_R_SUCCESS); } -static inline void -fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, - dns_messageid_t id, isc_taskaction_t action, void *arg, - dns_fetch_t *fetch, isc_eventtype_t event_type) { - isc_task_t *tclone; - dns_fetchevent_t *event; - /* - * We store the task we're going to send this event to in the - * sender field. We'll make the fetch the sender when we actually - * send the event. - */ - tclone = NULL; - isc_task_attach(task, &tclone); - event = (dns_fetchevent_t *)isc_event_allocate(fctx->res->mctx, tclone, - event_type, action, arg, - sizeof(*event)); - event->result = DNS_R_SERVFAIL; - event->qtype = fctx->type; - event->db = NULL; - event->node = NULL; - event->rdataset = NULL; - event->sigrdataset = NULL; - event->fetch = fetch; - event->client = client; - event->id = id; - ISC_LIST_APPEND(fctx->events, event, ev_link); -} - static inline void log_ns_ttl(fetchctx_t *fctx, const char *where) { char namebuf[DNS_NAME_FORMATSIZE]; char domainbuf[DNS_NAME_FORMATSIZE]; - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10), "log_ns_ttl: fctx %p: %s: %s (in '%s'?): %u %u", fctx, @@ -4739,7 +4565,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1]; isc_mem_t *mctx = NULL; size_t p; - bool try_stale; /* * Caller must be holding the lock for bucket number 'bucketnum'. @@ -4749,10 +4574,10 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, mctx = res->buckets[bucketnum].mctx; fctx = isc_mem_get(mctx, sizeof(*fctx)); *fctx = (fetchctx_t){ - .res = res, .type = type, .qmintype = type, .options = options, + .res = res, .bucketnum = bucketnum, .dbucketnum = RES_NOBUCKET, .state = fetchstate_init, @@ -4760,11 +4585,9 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, .qmin_labels = 1, .fwdpolicy = dns_fwdpolicy_none, .result = ISC_R_FAILURE, - .exitline = -1 /* sentinel */ + .exitline = -1, /* sentinel */ }; - FCTXTRACE("create"); - if (qc != NULL) { isc_counter_attach(qc, &fctx->qc); } else { @@ -4777,7 +4600,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, /* * Make fctx->info point to a copy of a formatted string - * "name/type". + * "name/type". FCTXTRACE won't work until this is done. */ dns_name_format(name, buf, sizeof(buf)); p = strlcat(buf, "/", sizeof(buf)); @@ -4785,22 +4608,10 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_format(type, buf + p, sizeof(buf) - p); fctx->info = isc_mem_strdup(mctx, buf); - dns_name_init(&fctx->name, NULL); - dns_name_dup(name, mctx, &fctx->name); - dns_name_init(&fctx->qminname, NULL); - dns_name_dup(name, mctx, &fctx->qminname); - dns_name_init(&fctx->domain, NULL); - dns_rdataset_init(&fctx->nameservers); + FCTXTRACE("create"); - /* - * Note! We do not attach to the task. We are relying on the - * resolver to ensure that this task doesn't go away while we are - * using it. - */ isc_refcount_init(&fctx->references, 0); - dns_rdataset_init(&fctx->qminrrset); - dns_name_init(&fctx->qmindcname, NULL); - isc_stdtime_get(&fctx->now); + ISC_LIST_INIT(fctx->queries); ISC_LIST_INIT(fctx->finds); ISC_LIST_INIT(fctx->altfinds); @@ -4811,9 +4622,25 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, ISC_LIST_INIT(fctx->edns); ISC_LIST_INIT(fctx->bad_edns); ISC_LIST_INIT(fctx->validators); - TIME_NOW(&fctx->start); + atomic_init(&fctx->attributes, 0); + fctx->name = dns_fixedname_initname(&fctx->fname); + fctx->nsname = dns_fixedname_initname(&fctx->nsfname); + fctx->domain = dns_fixedname_initname(&fctx->dfname); + fctx->qminname = dns_fixedname_initname(&fctx->qminfname); + fctx->qmindcname = dns_fixedname_initname(&fctx->qmindcfname); + + dns_name_copy(name, fctx->name); + dns_name_copy(name, fctx->qminname); + + dns_rdataset_init(&fctx->nameservers); + dns_rdataset_init(&fctx->qminrrset); + dns_rdataset_init(&fctx->nsrrset); + + TIME_NOW(&fctx->start); + fctx->now = (isc_stdtime_t)fctx->start.seconds; + if (client != NULL) { isc_sockaddr_format(client, fctx->clientstr, sizeof(fctx->clientstr)); @@ -4821,16 +4648,13 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, strlcpy(fctx->clientstr, "", sizeof(fctx->clientstr)); } - dns_name_init(&fctx->nsname, NULL); - dns_rdataset_init(&fctx->nsrrset); - if (domain == NULL) { dns_forwarders_t *forwarders = NULL; dns_fixedname_t fixed; + dns_name_t *fname = dns_fixedname_initname(&fixed); unsigned int labels; const dns_name_t *fwdname = name; dns_name_t suffix; - dns_name_t *fname; /* * DS records are found in the parent server. Strip one @@ -4846,7 +4670,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, } /* Find the forwarder for this name. */ - fname = dns_fixedname_initname(&fixed); result = dns_fwdtable_find(fctx->res->view->fwdtable, fwdname, fname, &forwarders); if (result == ISC_R_SUCCESS) { @@ -4855,8 +4678,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, if (fctx->fwdpolicy != dns_fwdpolicy_only) { dns_fixedname_t dcfixed; - dns_name_t *dcname; - dcname = dns_fixedname_initname(&dcfixed); + dns_name_t *dcname = dns_fixedname_initname(&dcfixed); + /* * The caller didn't supply a query domain and * nameservers, and we're not in forward-only mode, @@ -4873,24 +4696,24 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, goto cleanup_nameservers; } - dns_name_dup(fname, mctx, &fctx->domain); - dns_name_dup(dcname, mctx, &fctx->qmindcname); + dns_name_copy(fname, fctx->domain); + dns_name_copy(dcname, fctx->qmindcname); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; } else { /* * We're in forward-only mode. Set the query domain. */ - dns_name_dup(fname, mctx, &fctx->domain); - dns_name_dup(fname, mctx, &fctx->qmindcname); + dns_name_copy(fname, fctx->domain); + dns_name_copy(fname, fctx->qmindcname); /* * Disable query minimization */ options &= ~DNS_FETCHOPT_QMINIMIZE; } } else { - dns_name_dup(domain, mctx, &fctx->domain); - dns_name_dup(domain, mctx, &fctx->qmindcname); + dns_name_copy(domain, fctx->domain); + dns_name_copy(domain, fctx->qmindcname); dns_rdataset_clone(nameservers, &fctx->nameservers); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; @@ -4903,13 +4726,13 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, if (result != ISC_R_SUCCESS) { result = fctx->res->quotaresp[dns_quotatype_zone]; inc_stats(res, dns_resstatscounter_zonequota); - goto cleanup_domain; + goto cleanup_nameservers; } log_ns_ttl(fctx, "fctx_create"); - if (!dns_name_issubdomain(&fctx->name, &fctx->domain)) { - dns_name_format(&fctx->domain, buf, sizeof(buf)); + if (!dns_name_issubdomain(fctx->name, fctx->domain)) { + dns_name_format(fctx->domain, buf, sizeof(buf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "'%s' is not subdomain of '%s'", fctx->info, buf); @@ -4917,7 +4740,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, goto cleanup_fcount; } - fctx->qmessage = NULL; dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &fctx->qmessage); /* @@ -4934,15 +4756,21 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, goto cleanup_qmessage; } - try_stale = ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0); - if (try_stale) { + /* + * Default retry interval initialization. We set the interval now + * mostly so it won't be uninitialized. It will be set to the + * correct value before a query is issued. + */ + isc_interval_set(&fctx->interval, 2, 0); + + /* + * If stale answers are enabled, compute an expiration time after + * which stale data will be served, if the target RRset is + * available in cache. + */ + if ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0) { INSIST(res->view->staleanswerclienttimeout <= (res->query_timeout - 1000)); - /* - * Compute an expiration time after which stale data will - * be served, if stale answers are enabled and target RRset is - * available in cache. - */ isc_interval_set( &interval, res->view->staleanswerclienttimeout / 1000, res->view->staleanswerclienttimeout % 1000 * 1000000); @@ -4957,57 +4785,11 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, } } - /* - * Default retry interval initialization. We set the interval now - * mostly so it won't be uninitialized. It will be set to the - * correct value before a query is issued. - */ - isc_interval_set(&fctx->interval, 2, 0); - - /* - * Create an inactive timer for resolver-query-timeout. It - * will be made active when the fetch is actually started. - */ - fctx->timer = NULL; - - iresult = isc_timer_create(res->timermgr, isc_timertype_inactive, NULL, - NULL, res->buckets[bucketnum].task, - fctx_timeout, fctx, &fctx->timer); - if (iresult != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_create: %s", - isc_result_totext(iresult)); - result = ISC_R_UNEXPECTED; - goto cleanup_qmessage; - } - - /* - * If stale answers are enabled, then create an inactive timer - * for stale-answer-client-timeout. It will be made active when - * the fetch is actually started. - */ - fctx->timer_try_stale = NULL; - if (try_stale) { - iresult = isc_timer_create( - res->timermgr, isc_timertype_inactive, NULL, NULL, - res->buckets[bucketnum].task, fctx_timeout_try_stale, - fctx, &fctx->timer_try_stale); - if (iresult != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_timer_create: %s", - isc_result_totext(iresult)); - result = ISC_R_UNEXPECTED; - goto cleanup_qmessage; - } - } - /* * Attach to the view's cache and adb. */ - fctx->cache = NULL; dns_db_attach(res->view->cachedb, &fctx->cache); - fctx->adb = NULL; dns_adb_attach(res->view->adb, &fctx->adb); - fctx->mctx = NULL; isc_mem_attach(mctx, &fctx->mctx); ISC_LIST_INIT(fctx->events); @@ -5019,9 +4801,9 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, * the name in fctx to proper length. */ if ((options & DNS_FETCHOPT_QMINIMIZE) != 0) { - fctx->ip6arpaskip = - (options & DNS_FETCHOPT_QMIN_SKIP_IP6A) != 0 && - dns_name_issubdomain(&fctx->name, &ip6_arpa); + fctx->ip6arpaskip = (options & DNS_FETCHOPT_QMIN_SKIP_IP6A) != + 0 && + dns_name_issubdomain(fctx->name, &ip6_arpa); result = fctx_minimize_qname(fctx); if (result != ISC_R_SUCCESS) { goto cleanup_mctx; @@ -5043,8 +4825,6 @@ cleanup_mctx: isc_mem_detach(&fctx->mctx); dns_adb_detach(&fctx->adb); dns_db_detach(&fctx->cache); - isc_timer_detach(&fctx->timer); - isc_timer_detach(&fctx->timer_try_stale); cleanup_qmessage: dns_message_detach(&fctx->qmessage); @@ -5052,20 +4832,10 @@ cleanup_qmessage: cleanup_fcount: fcount_decr(fctx); -cleanup_domain: - if (dns_name_countlabels(&fctx->domain) > 0) { - dns_name_free(&fctx->domain, mctx); - } - if (dns_name_countlabels(&fctx->qmindcname) > 0) { - dns_name_free(&fctx->qmindcname, mctx); - } - cleanup_nameservers: if (dns_rdataset_isassociated(&fctx->nameservers)) { dns_rdataset_disassociate(&fctx->nameservers); } - dns_name_free(&fctx->name, mctx); - dns_name_free(&fctx->qminname, mctx); isc_mem_free(mctx, fctx->info); isc_counter_detach(&fctx->qc); @@ -5112,7 +4882,7 @@ is_lame(fetchctx_t *fctx, dns_message_t *message) { if (rdataset->type != dns_rdatatype_ns) { continue; } - namereln = dns_name_fullcompare(name, &fctx->domain, + namereln = dns_name_fullcompare(name, fctx->domain, &order, &labels); if (namereln == dns_namereln_equal && (message->flags & DNS_MESSAGEFLAG_AA) != 0) @@ -5136,8 +4906,8 @@ log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) { char domainbuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -5166,8 +4936,8 @@ log_formerr(fetchctx_t *fctx, const char *format, ...) { static isc_result_t same_question(fetchctx_t *fctx, dns_message_t *message) { isc_result_t result; - dns_name_t *name; - dns_rdataset_t *rdataset; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; /* * Caller must be holding the fctx lock. @@ -5209,7 +4979,7 @@ same_question(fetchctx_t *fctx, dns_message_t *message) { if (result != ISC_R_SUCCESS) { return (result); } - name = NULL; + dns_message_currentname(message, DNS_SECTION_QUESTION, &name); rdataset = ISC_LIST_HEAD(name->list); INSIST(rdataset != NULL); @@ -5217,7 +4987,7 @@ same_question(fetchctx_t *fctx, dns_message_t *message) { if (fctx->type != rdataset->type || fctx->res->rdclass != rdataset->rdclass || - !dns_name_equal(&fctx->name, name)) + !dns_name_equal(fctx->name, name)) { char namebuf[DNS_NAME_FORMATSIZE]; char classbuf[DNS_RDATACLASS_FORMATSIZE]; @@ -5237,8 +5007,7 @@ same_question(fetchctx_t *fctx, dns_message_t *message) { static void clone_results(fetchctx_t *fctx) { - dns_fetchevent_t *event, *hevent; - dns_name_t *name, *hname; + dns_fetchevent_t *event = NULL, *hevent = NULL; FCTXTRACE("clone_results"); @@ -5250,14 +5019,16 @@ clone_results(fetchctx_t *fctx) { */ fctx->cloned = true; - hevent = ISC_LIST_HEAD(fctx->events); - if (hevent == NULL) { - return; - } - hname = dns_fixedname_name(&hevent->foundname); - for (event = ISC_LIST_NEXT(hevent, ev_link); event != NULL; + + for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = ISC_LIST_NEXT(event, ev_link)) { + /* This is the the head event; keep a pointer and move on */ + if (hevent == NULL) { + hevent = ISC_LIST_HEAD(fctx->events); + continue; + } + if (event->ev_type == DNS_EVENT_TRYSTALE) { /* * We don't need to clone resulting data to this @@ -5275,16 +5046,18 @@ clone_results(fetchctx_t *fctx) { */ continue; } - name = dns_fixedname_name(&event->foundname); - dns_name_copy(hname, name); + event->result = hevent->result; + dns_name_copy(hevent->foundname, event->foundname); dns_db_attach(hevent->db, &event->db); dns_db_attachnode(hevent->db, hevent->node, &event->node); + INSIST(hevent->rdataset != NULL); INSIST(event->rdataset != NULL); if (dns_rdataset_isassociated(hevent->rdataset)) { dns_rdataset_clone(hevent->rdataset, event->rdataset); } + INSIST(!(hevent->sigrdataset == NULL && event->sigrdataset != NULL)); if (hevent->sigrdataset != NULL && @@ -5560,7 +5333,7 @@ validated(isc_task_t *task, isc_event_t *event) { fctx->type == dns_rdatatype_ds) && tresult == ISC_R_SUCCESS) { - dns_resolver_addbadcache(res, &fctx->name, + dns_resolver_addbadcache(res, fctx->name, fctx->type, &expire); } fctx_done(fctx, result, __LINE__); /* Locks bucket. */ @@ -5816,9 +5589,9 @@ answer_response: INSIST(eresult == DNS_R_NCACHENXDOMAIN || eresult == DNS_R_NCACHENXRRSET); } + hevent->result = eresult; - dns_name_copy(vevent->name, - dns_fixedname_name(&hevent->foundname)); + dns_name_copy(vevent->name, hevent->foundname); dns_db_attach(fctx->cache, &hevent->db); dns_db_transfernode(fctx->cache, &node, &hevent->node); clone_results(fctx); @@ -5994,7 +5767,6 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL; dns_dbnode_t *node = NULL, **anodep = NULL; dns_db_t **adbp = NULL; - dns_name_t *aname = NULL; dns_resolver_t *res = fctx->res; bool need_validation = false; bool secure_domain = false; @@ -6047,9 +5819,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, if (event != NULL) { adbp = &event->db; - aname = dns_fixedname_name(&event->foundname); - dns_name_copy(name, aname); + dns_name_copy(name, event->foundname); anodep = &event->node; + /* * If this is an ANY, SIG or RRSIG query, we're not * going to return any rdatasets, unless we encountered @@ -6558,15 +6330,14 @@ static inline isc_result_t ncache_message(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo, dns_rdatatype_t covers, isc_stdtime_t now) { - isc_result_t result, eresult; - dns_name_t *name; - dns_resolver_t *res; - dns_db_t **adbp; - dns_dbnode_t *node, **anodep; - dns_rdataset_t *ardataset; - bool need_validation, secure_domain; - dns_name_t *aname; - dns_fetchevent_t *event; + isc_result_t result, eresult = ISC_R_SUCCESS; + dns_name_t *name = fctx->name; + dns_resolver_t *res = fctx->res; + dns_db_t **adbp = NULL; + dns_dbnode_t *node = NULL, **anodep = NULL; + dns_rdataset_t *ardataset = NULL; + bool need_validation = false, secure_domain = false; + dns_fetchevent_t *event = NULL; uint32_t ttl; unsigned int valoptions = 0; bool checknta = true; @@ -6575,13 +6346,7 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTNCACHE); - res = fctx->res; - need_validation = false; POST(need_validation); - secure_domain = false; - eresult = ISC_R_SUCCESS; - name = &fctx->name; - node = NULL; /* * XXXMPA remove when we follow cnames and adjust the setting @@ -6619,12 +6384,11 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, /* * Mark all rdatasets as pending. */ - dns_rdataset_t *trdataset; - dns_name_t *tname; - result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { - tname = NULL; + dns_rdataset_t *trdataset = NULL; + dns_name_t *tname = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &tname); for (trdataset = ISC_LIST_HEAD(tname->list); @@ -6658,21 +6422,14 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, LOCK(&res->buckets[fctx->bucketnum].lock); - adbp = NULL; - aname = NULL; - anodep = NULL; - ardataset = NULL; if (!HAVE_ANSWER(fctx)) { event = ISC_LIST_HEAD(fctx->events); if (event != NULL) { adbp = &event->db; - aname = dns_fixedname_name(&event->foundname); - dns_name_copy(name, aname); + dns_name_copy(name, event->foundname); anodep = &event->node; ardataset = event->rdataset; } - } else { - event = NULL; } result = dns_db_findnode(fctx->cache, name, true, &node); @@ -6775,12 +6532,12 @@ check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type, #endif /* if CHECK_FOR_GLUE_IN_ANSWER */ gluing = (GLUING(fctx) || (fctx->type == dns_rdatatype_ns && - dns_name_equal(&fctx->name, dns_rootname))); + dns_name_equal(fctx->name, dns_rootname))); result = dns_message_findname(rctx->query->rmessage, section, addname, dns_rdatatype_any, 0, &name, NULL); if (result == ISC_R_SUCCESS) { - external = !dns_name_issubdomain(name, &fctx->domain); + external = !dns_name_issubdomain(name, fctx->domain); if (type == dns_rdatatype_a) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -7010,7 +6767,7 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, * must also check whether forwarding is enabled so that filters * can be applied; see GL #1574. */ - if (!fctx->forwarding && dns_name_issubdomain(tname, &fctx->domain)) { + if (!fctx->forwarding && dns_name_issubdomain(tname, fctx->domain)) { return (true); } @@ -7043,7 +6800,7 @@ trim_ns_ttl(fetchctx_t *fctx, dns_name_t *name, dns_rdataset_t *rdataset) { if (fctx->ns_ttl_ok && rdataset->ttl > fctx->ns_ttl) { dns_name_format(name, ns_namebuf, sizeof(ns_namebuf)); - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, tbuf, sizeof(tbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, @@ -7184,9 +6941,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(&fctx->nsname, fctx->mctx, &fctx->domain); + dns_name_copy(fctx->nsname, fctx->domain); result = fcount_incr(fctx, true); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); @@ -7204,8 +6959,8 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { * Retrieve state from fctx->nsfetch before we destroy it. */ domain = dns_fixedname_initname(&fixed); - dns_name_copy(&fctx->nsfetch->private->domain, domain); - if (dns_name_equal(&fctx->nsname, domain)) { + dns_name_copy(fctx->nsfetch->private->domain, domain); + if (dns_name_equal(fctx->nsname, domain)) { if (dns_rdataset_isassociated(fevent->rdataset)) { dns_rdataset_disassociate(fevent->rdataset); } @@ -7225,9 +6980,8 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { domain = NULL; } dns_resolver_destroyfetch(&fctx->nsfetch); - n = dns_name_countlabels(&fctx->nsname); - dns_name_getlabelsequence(&fctx->nsname, 1, n - 1, - &fctx->nsname); + n = dns_name_countlabels(fctx->nsname); + dns_name_getlabelsequence(fctx->nsname, 1, n - 1, fctx->nsname); if (dns_rdataset_isassociated(fevent->rdataset)) { dns_rdataset_disassociate(fevent->rdataset); @@ -7238,7 +6992,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { FCTXTRACE("continuing to look for parent's NS records"); result = dns_resolver_createfetch( - fctx->res, &fctx->nsname, dns_rdatatype_ns, domain, + fctx->res, fctx->nsname, dns_rdatatype_ns, domain, nsrdataset, NULL, NULL, 0, fctx->options, 0, NULL, task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); @@ -7381,7 +7135,7 @@ betterreferral(respctx_t *rctx) { name = NULL; dns_message_currentname(rctx->query->rmessage, DNS_SECTION_AUTHORITY, &name); - if (!isstrictsubdomain(name, &rctx->fctx->domain)) { + if (!isstrictsubdomain(name, rctx->fctx->domain)) { continue; } for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -7421,8 +7175,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) { inc_stats(fctx->res, dns_resstatscounter_responsev6); } - (void)isc_timer_touch(fctx->timer); - rctx_respinit(task, devent, query, fctx, &rctx); if (atomic_load_acquire(&fctx->res->exiting)) { @@ -7433,9 +7185,15 @@ resquery_response(isc_task_t *task, isc_event_t *event) { return; } - fctx->timeouts = 0; - fctx->timeout = false; + result = rctx_timedout(&rctx); + if (result == ISC_R_COMPLETE) { + FCTXTRACE("timed out"); + return; + } + fctx->addrinfo = query->addrinfo; + fctx->timeout = false; + fctx->timeouts = 0; /* * Check whether the dispatcher has failed; if so we're done @@ -7454,7 +7212,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } } - if (query->tsigkey) { + if (query->tsigkey != NULL) { result = dns_message_settsigkey(query->rmessage, query->tsigkey); if (result != ISC_R_SUCCESS) { @@ -7792,6 +7550,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ rctx_ncache(&rctx); + FCTXTRACE("resquery_response done"); rctx_done(&rctx, result); } @@ -7803,23 +7562,17 @@ resquery_response(isc_task_t *task, isc_event_t *event) { static void rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, fetchctx_t *fctx, respctx_t *rctx) { - memset(rctx, 0, sizeof(*rctx)); + *rctx = (respctx_t){ .task = task, + .devent = devent, + .result = devent->result, + .query = query, + .fctx = fctx, + .broken_type = badns_response, + .retryopts = query->options }; - rctx->task = task; - rctx->devent = devent; - rctx->query = query; - rctx->fctx = fctx; - rctx->broken_type = badns_response; - rctx->retryopts = query->options; - - /* - * XXXRTH We should really get the current time just once. We - * need a routine to convert from an isc_time_t to an - * isc_stdtime_t. - */ TIME_NOW(&rctx->tnow); rctx->finish = &rctx->tnow; - isc_stdtime_get(&rctx->now); + rctx->now = (isc_stdtime_t)isc_time_seconds(&rctx->tnow); } /* @@ -7853,8 +7606,8 @@ rctx_answer_init(respctx_t *rctx) { /* * Bigger than any valid DNAME label count. */ - rctx->dname_labels = dns_name_countlabels(&fctx->name); - rctx->domain_labels = dns_name_countlabels(&fctx->domain); + rctx->dname_labels = dns_name_countlabels(fctx->name); + rctx->domain_labels = dns_name_countlabels(fctx->domain); rctx->found_type = dns_rdatatype_none; @@ -7904,7 +7657,6 @@ rctx_dispfail(respctx_t *rctx) { * There's no hope for this response. */ rctx->next_server = true; - /* * If this is a network error, mark the server as bad so * that we won't try it for this fetch again. Also adjust @@ -7927,6 +7679,44 @@ rctx_dispfail(respctx_t *rctx) { return (ISC_R_COMPLETE); } +/* + * rctx_timedout(): + * Handle the case where a dispatch read timed out. + */ +static isc_result_t +rctx_timedout(respctx_t *rctx) { + fetchctx_t *fctx = rctx->fctx; + + if (rctx->result == ISC_R_TIMEDOUT) { + isc_time_t now; + + inc_stats(fctx->res, dns_resstatscounter_querytimeout); + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + fctx->timeout = true; + fctx->timeouts++; + + isc_time_now(&now); + /* netmgr timeouts are accurate to the millisecond */ + if (isc_time_microdiff(&fctx->expires, &now) < US_PER_MSEC) { + FCTXTRACE("stopped trying to make fetch happen"); + } else { + FCTXTRACE("query timed out; no response"); + rctx->no_response = true; + rctx->finish = NULL; + if (!ISFORWARDER(rctx->query->addrinfo) || + fctx->fwdpolicy != dns_fwdpolicy_first) + { + rctx->resend = true; + } + } + + rctx_done(rctx, rctx->result); + return (ISC_R_COMPLETE); + } + + return (ISC_R_SUCCESS); +} + /* * rctx_parse(): * Parse the response message. @@ -8184,7 +7974,7 @@ rctx_answer(respctx_t *rctx) { if (result != ISC_R_SUCCESS) { FCTXTRACE3("rctx_answer_positive (AA/fwd)", result); } - } else if (iscname(query->rmessage, &fctx->name) && + } else if (iscname(query->rmessage, fctx->name) && fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_cname) { @@ -8254,6 +8044,7 @@ rctx_answer(respctx_t *rctx) { */ rctx->broken_server = DNS_R_LAME; rctx->next_server = true; + FCTXTRACE3("rctx_answer lame", result); rctx_done(rctx, result); return (ISC_R_COMPLETE); } @@ -8263,6 +8054,7 @@ rctx_answer(respctx_t *rctx) { if (result == DNS_R_FORMERR) { rctx->next_server = true; } + FCTXTRACE3("rctx_answer failed", result); rctx_done(rctx, result); return (ISC_R_COMPLETE); } @@ -8348,7 +8140,7 @@ rctx_answer_positive(respctx_t *rctx) { log_ns_ttl(fctx, "rctx_answer"); if (rctx->ns_rdataset != NULL && - dns_name_equal(&fctx->domain, rctx->ns_name) && + dns_name_equal(fctx->domain, rctx->ns_name) && !dns_name_equal(rctx->ns_name, dns_rootname)) { trim_ns_ttl(fctx, rctx->ns_name, rctx->ns_rdataset); @@ -8384,7 +8176,7 @@ rctx_answer_scan(respctx_t *rctx) { dns_message_currentname(rctx->query->rmessage, DNS_SECTION_ANSWER, &name); - namereln = dns_name_fullcompare(&fctx->name, name, &order, + namereln = dns_name_fullcompare(fctx->name, name, &order, &nlabels); switch (namereln) { case dns_namereln_equal: @@ -8496,7 +8288,7 @@ rctx_answer_any(respctx_t *rctx) { if ((rdataset->type == dns_rdatatype_cname || rdataset->type == dns_rdatatype_dname) && - !is_answertarget_allowed(fctx, &fctx->name, rctx->aname, + !is_answertarget_allowed(fctx, fctx->name, rctx->aname, rdataset, NULL)) { rctx->result = DNS_R_SERVFAIL; @@ -8545,7 +8337,7 @@ rctx_answer_match(respctx_t *rctx) { rctx->ardataset->type == dns_rdatatype_dname) && rctx->type != rctx->ardataset->type && rctx->type != dns_rdatatype_any && - !is_answertarget_allowed(fctx, &fctx->name, rctx->aname, + !is_answertarget_allowed(fctx, fctx->name, rctx->aname, rctx->ardataset, NULL)) { rctx->result = DNS_R_SERVFAIL; @@ -8609,7 +8401,7 @@ rctx_answer_cname(respctx_t *rctx) { return (ISC_R_COMPLETE); } - if (!is_answertarget_allowed(fctx, &fctx->name, rctx->cname, + if (!is_answertarget_allowed(fctx, fctx->name, rctx->cname, rctx->crdataset, NULL)) { rctx->result = DNS_R_SERVFAIL; @@ -8663,7 +8455,7 @@ rctx_answer_dname(respctx_t *rctx) { return (ISC_R_COMPLETE); } - if (!is_answertarget_allowed(fctx, &fctx->name, rctx->dname, + if (!is_answertarget_allowed(fctx, fctx->name, rctx->dname, rctx->drdataset, &rctx->chaining)) { rctx->result = DNS_R_SERVFAIL; @@ -8727,7 +8519,7 @@ rctx_authority_positive(respctx_t *rctx) { dns_message_currentname(rctx->query->rmessage, DNS_SECTION_AUTHORITY, &name); - external = !dns_name_issubdomain(name, &fctx->domain); + external = !dns_name_issubdomain(name, fctx->domain); if (!external) { dns_rdataset_t *rdataset = NULL; @@ -8816,7 +8608,7 @@ rctx_answer_none(respctx_t *rctx) { log_ns_ttl(fctx, "rctx_answer_none"); if (rctx->ns_rdataset != NULL && - dns_name_equal(&fctx->domain, rctx->ns_name) && + dns_name_equal(fctx->domain, rctx->ns_name) && !dns_name_equal(rctx->ns_name, dns_rootname)) { trim_ns_ttl(fctx, rctx->ns_name, rctx->ns_rdataset); @@ -8849,8 +8641,8 @@ rctx_answer_none(respctx_t *rctx) { if (rctx->negative && rctx->query->rmessage->rcode == dns_rcode_noerror && fctx->type == dns_rdatatype_ds && rctx->soa_name != NULL && - dns_name_equal(rctx->soa_name, &fctx->name) && - !dns_name_equal(&fctx->name, dns_rootname)) + dns_name_equal(rctx->soa_name, fctx->name) && + !dns_name_equal(fctx->name, dns_rootname)) { return (DNS_R_CHASEDSSERVERS); } @@ -8866,7 +8658,7 @@ rctx_answer_none(respctx_t *rctx) { log_formerr(fctx, "invalid response"); return (DNS_R_FORMERR); } - if (!dns_name_issubdomain(rctx->found_name, &fctx->domain)) { + if (!dns_name_issubdomain(rctx->found_name, fctx->domain)) { char nbuf[DNS_NAME_FORMATSIZE]; char dbuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; @@ -8874,7 +8666,7 @@ rctx_answer_none(respctx_t *rctx) { dns_rdatatype_format(rctx->found_type, tbuf, sizeof(tbuf)); dns_name_format(rctx->found_name, nbuf, sizeof(nbuf)); - dns_name_format(&fctx->domain, dbuf, sizeof(dbuf)); + dns_name_format(fctx->domain, dbuf, sizeof(dbuf)); log_formerr(fctx, "Name %s (%s) not subdomain" @@ -8955,7 +8747,7 @@ rctx_authority_negative(respctx_t *rctx) { finished = true; } - if (!dns_name_issubdomain(name, &fctx->domain)) { + if (!dns_name_issubdomain(name, fctx->domain)) { continue; } @@ -8968,15 +8760,14 @@ rctx_authority_negative(respctx_t *rctx) { } if (((type == dns_rdatatype_ns || type == dns_rdatatype_soa) && - !dns_name_issubdomain(&fctx->name, name))) + !dns_name_issubdomain(fctx->name, name))) { char qbuf[DNS_NAME_FORMATSIZE]; char nbuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; dns_rdatatype_format(type, tbuf, sizeof(tbuf)); dns_name_format(name, nbuf, sizeof(nbuf)); - dns_name_format(&fctx->name, qbuf, - sizeof(qbuf)); + dns_name_format(fctx->name, qbuf, sizeof(qbuf)); log_formerr(fctx, "unrelated %s %s in " "%s authority section", @@ -9116,7 +8907,7 @@ rctx_authority_dnssec(respctx_t *rctx) { finished = true; } - if (!dns_name_issubdomain(name, &fctx->domain)) { + if (!dns_name_issubdomain(name, fctx->domain)) { /* Invalid name found; preserve it for logging later */ rctx->found_name = name; rctx->found_type = ISC_LIST_HEAD(name->list)->type; @@ -9243,7 +9034,7 @@ rctx_referral(respctx_t *rctx) { * progress. We return DNS_R_FORMERR so that we'll keep * trying other servers. */ - if (dns_name_equal(rctx->ns_name, &fctx->domain)) { + if (dns_name_equal(rctx->ns_name, fctx->domain)) { log_formerr(fctx, "non-improving referral"); rctx->result = DNS_R_FORMERR; return (ISC_R_COMPLETE); @@ -9253,7 +9044,7 @@ rctx_referral(respctx_t *rctx) { * If the referral name is not a parent of the query * name, consider the responder insane. */ - if (!dns_name_issubdomain(&fctx->name, rctx->ns_name)) { + if (!dns_name_issubdomain(fctx->name, rctx->ns_name)) { /* Logged twice */ log_formerr(fctx, "referral to non-parent"); FCTXTRACE("referral to non-parent"); @@ -9304,21 +9095,17 @@ rctx_referral(respctx_t *rctx) { * XXXRTH We should check if we're in forward-only mode, and * if so we should bail out. */ - INSIST(dns_name_countlabels(&fctx->domain) > 0); + INSIST(dns_name_countlabels(fctx->domain) > 0); fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) { dns_rdataset_disassociate(&fctx->nameservers); } - dns_name_init(&fctx->domain, NULL); - dns_name_dup(rctx->ns_name, fctx->mctx, &fctx->domain); + dns_name_copy(rctx->ns_name, fctx->domain); if ((fctx->options & DNS_FETCHOPT_QMINIMIZE) != 0) { - dns_name_free(&fctx->qmindcname, fctx->mctx); - dns_name_init(&fctx->qmindcname, NULL); - dns_name_dup(rctx->ns_name, fctx->mctx, &fctx->qmindcname); + dns_name_copy(rctx->ns_name, fctx->qmindcname); result = fctx_minimize_qname(fctx); if (result != ISC_R_SUCCESS) { @@ -9440,9 +9227,9 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, findoptions |= DNS_DBFIND_NOEXACT; } if ((rctx->retryopts & DNS_FETCHOPT_UNSHARED) == 0) { - name = &fctx->name; + name = fctx->name; } else { - name = &fctx->domain; + name = fctx->domain; } result = dns_view_findzonecut( fctx->res->view, name, fname, dcname, fctx->now, @@ -9452,7 +9239,7 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } - if (!dns_name_issubdomain(fname, &fctx->domain)) { + if (!dns_name_issubdomain(fname, fctx->domain)) { /* * The best nameservers are now above our QDOMAIN. */ @@ -9463,12 +9250,8 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, fcount_decr(fctx); - dns_name_free(&fctx->domain, fctx->mctx); - dns_name_init(&fctx->domain, NULL); - dns_name_dup(fname, fctx->mctx, &fctx->domain); - dns_name_free(&fctx->qmindcname, fctx->mctx); - dns_name_init(&fctx->qmindcname, NULL); - dns_name_dup(dcname, fctx->mctx, &fctx->qmindcname); + dns_name_copy(fname, fctx->domain); + dns_name_copy(dcname, fctx->qmindcname); result = fcount_incr(fctx, true); if (result != ISC_R_SUCCESS) { @@ -9559,13 +9342,13 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, fctx_cleanupfinds(fctx); fctx_cleanupforwaddrs(fctx); - n = dns_name_countlabels(&fctx->name); - dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname); + n = dns_name_countlabels(fctx->name); + dns_name_getlabelsequence(fctx->name, 1, n - 1, fctx->nsname); FCTXTRACE("suspending DS lookup to find parent's NS records"); result = dns_resolver_createfetch( - fctx->res, &fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, + fctx->res, fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, NULL, 0, fctx->options, 0, NULL, rctx->task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) { @@ -9575,10 +9358,6 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, fctx_done(fctx, result, __LINE__); } else { fctx_increference(fctx); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } } } @@ -9594,22 +9373,21 @@ rctx_done(respctx_t *rctx, isc_result_t result) { resquery_t *query = rctx->query; fetchctx_t *fctx = rctx->fctx; dns_adbaddrinfo_t *addrinfo = query->addrinfo; + dns_message_t *message = NULL; + /* * Need to attach to the message until the scope * of this function ends, since there are many places * 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 rctx_done(); ", + FCTXTRACE4("query canceled in rctx_done();", rctx->no_response ? "no response" : "responding", result); /* * Cancel the query. - * - * XXXRTH Don't cancel the query if waiting for validation? */ if (!rctx->nextitem) { fctx_cancelquery(&query, &rctx->devent, rctx->finish, @@ -9644,14 +9422,6 @@ rctx_done(respctx_t *rctx, isc_result_t result) { */ FCTXTRACE("wait for validator"); fctx_cancelqueries(fctx, true, false); - /* - * We must not retransmit while the validator is working; - * it has references to the current rmessage. - */ - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) { - fctx_done(fctx, result, __LINE__); - } } else { /* * We're done. @@ -9694,7 +9464,7 @@ rctx_logpacket(respctx_t *rctx) { if (result == ISC_R_SUCCESS) { isc_buffer_init(&zb, zone, sizeof(zone)); dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE); - result = dns_name_towire(&fctx->domain, &cctx, &zb); + result = dns_name_towire(fctx->domain, &cctx, &zb); if (result == ISC_R_SUCCESS) { isc_buffer_usedregion(&zb, &zr); } @@ -9859,7 +9629,7 @@ rctx_lameserver(respctx_t *rctx) { inc_stats(fctx->res, dns_resstatscounter_lame); log_lame(fctx, query->addrinfo); - result = dns_adb_marklame(fctx->adb, query->addrinfo, &fctx->name, + result = dns_adb_marklame(fctx->adb, query->addrinfo, fctx->name, fctx->type, rctx->now + fctx->res->lame_ttl); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, @@ -9889,15 +9659,15 @@ rctx_delonly_zone(respctx_t *rctx) { char typebuf[64]; if (ISFORWARDER(rctx->query->addrinfo) || - !dns_view_isdelegationonly(fctx->res->view, &fctx->domain) || - dns_name_equal(&fctx->domain, &fctx->name) || + !dns_view_isdelegationonly(fctx->res->view, fctx->domain) || + dns_name_equal(fctx->domain, fctx->name) || !fix_mustbedelegationornxdomain(rctx->query->rmessage, fctx)) { return; } - dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->name, namebuf, sizeof(namebuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(&rctx->query->addrinfo->sockaddr, addrbuf, @@ -10071,7 +9841,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, .spillatmin = 10, .spillat = 10, .spillatmax = 100, - .retryinterval = 30000, + .retryinterval = 10000, .nonbackofftries = 3, .query_timeout = DEFAULT_QUERY_TIMEOUT, .maxdepth = DEFAULT_RECURSION_DEPTH, @@ -10106,21 +9876,24 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, for (i = 0; i < ntasks; i++) { isc_mutex_init(&res->buckets[i].lock); - res->buckets[i].task = NULL; /* * Since we have a pool of tasks we bind them to task queues * to spread the load evenly */ + res->buckets[i].task = NULL; result = isc_task_create_bound(taskmgr, 0, &res->buckets[i].task, i); if (result != ISC_R_SUCCESS) { isc_mutex_destroy(&res->buckets[i].lock); goto cleanup_buckets; } - res->buckets[i].mctx = NULL; + snprintf(name, sizeof(name), "res%u", i); - isc_mem_attach(view->mctx, &res->buckets[i].mctx); isc_task_setname(res->buckets[i].task, name, res); + + res->buckets[i].mctx = NULL; + isc_mem_attach(view->mctx, &res->buckets[i].mctx); + ISC_LIST_INIT(res->buckets[i].fctxs); atomic_init(&res->buckets[i].exiting, false); buckets_created++; @@ -10435,7 +10208,7 @@ fctx_match(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type, if (fctx->type != type || fctx->options != options) { return (false); } - return (dns_name_equal(&fctx->name, name)); + return (dns_name_equal(fctx->name, name)); } static inline void @@ -10467,10 +10240,8 @@ fctx_minimize_qname(fetchctx_t *fctx) { REQUIRE(VALID_FCTX(fctx)); - dlabels = dns_name_countlabels(&fctx->qmindcname); - nlabels = dns_name_countlabels(&fctx->name); - dns_name_free(&fctx->qminname, fctx->mctx); - dns_name_init(&fctx->qminname, NULL); + dlabels = dns_name_countlabels(fctx->qmindcname); + nlabels = dns_name_countlabels(fctx->name); if (dlabels > fctx->qmin_labels) { fctx->qmin_labels = dlabels + 1; @@ -10511,8 +10282,7 @@ fctx_minimize_qname(fetchctx_t *fctx) { */ dns_fixedname_t fname; dns_name_t *name = dns_fixedname_initname(&fname); - dns_name_split(&fctx->name, fctx->qmin_labels, NULL, - dns_fixedname_name(&fname)); + dns_name_split(fctx->name, fctx->qmin_labels, NULL, name); if ((fctx->options & DNS_FETCHOPT_QMIN_USE_A) != 0) { isc_buffer_t dbuf; dns_fixedname_t tmpname; @@ -10524,25 +10294,23 @@ fctx_minimize_qname(fetchctx_t *fctx) { result = dns_name_concatenate(&underscore_name, name, tname, &dbuf); if (result == ISC_R_SUCCESS) { - dns_name_dup(tname, fctx->mctx, - &fctx->qminname); + dns_name_copy(tname, fctx->qminname); } fctx->qmintype = dns_rdatatype_a; } else { - dns_name_dup(dns_fixedname_name(&fname), fctx->mctx, - &fctx->qminname); + dns_name_copy(name, fctx->qminname); fctx->qmintype = dns_rdatatype_ns; } fctx->minimized = true; } else { /* Minimization is done, we'll ask for whole qname */ fctx->qmintype = fctx->type; - dns_name_dup(&fctx->name, fctx->mctx, &fctx->qminname); + dns_name_copy(fctx->name, fctx->qminname); fctx->minimized = false; } char domainbuf[DNS_NAME_FORMATSIZE]; - dns_name_format(&fctx->qminname, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->qminname, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(5), "QNAME minimization - %s minimized, qmintype %d " @@ -10668,8 +10436,8 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, if (result == ISC_R_SUCCESS && ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0)) { - fctx_add_event(fctx, task, client, id, action, arg, fetch, - DNS_EVENT_TRYSTALE); + fctx_add_event(fctx, task, client, id, action, arg, NULL, NULL, + fetch, DNS_EVENT_TRYSTALE); } if (new_fctx) { @@ -10817,7 +10585,7 @@ dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx, INSIST(fctx->exitline >= 0); if (!fctx->logged || duplicateok) { - dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + dns_name_format(fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(lctx, category, module, level, "fetch completed at %s:%d for %s in " "%" PRIu64 "." diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 18c35466e8..1ea26f8343 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -576,8 +576,8 @@ fetch_callback_ds(isc_task_t *task, isc_event_t *event) { } else if (eresult == DNS_R_SERVFAIL) { goto unexpected; } else if (eresult != DNS_R_CNAME && - isdelegation(dns_fixedname_name(&devent->foundname), - &val->frdataset, eresult)) + isdelegation(devent->foundname, &val->frdataset, + eresult)) { /* * Failed to find a DS while trying to prove diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index c14607f81d..b198713092 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -160,6 +160,12 @@ isc_nmhandle_cleartimeout(isc_nmhandle_t *handle); * a TCPDNS socket wrapping a TCP connection), the timer is set for * both socket layers. */ +bool +isc_nmhandle_timer_running(isc_nmhandle_t *handle); +/*%< + * Return true if the timer for the socket connected to 'handle' + * is running. + */ void isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value); diff --git a/lib/isc/include/isc/time.h b/lib/isc/include/isc/time.h index adf56fc19d..6946ecbb3c 100644 --- a/lib/isc/include/isc/time.h +++ b/lib/isc/include/isc/time.h @@ -71,6 +71,16 @@ isc_interval_iszero(const isc_interval_t *i); *\li 'i' is a valid pointer. */ +unsigned int +isc_interval_ms(const isc_interval_t *i); +/*%< + * Returns interval 'i' expressed as a number of milliseconds. + * + * Requires: + * + *\li 'i' is a valid pointer. + */ + /*** *** Absolute Times ***/ diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index d79a4cbeb8..b67a94e246 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -2404,6 +2404,14 @@ isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) { } } +bool +isc_nmhandle_timer_running(isc_nmhandle_t *handle) { + REQUIRE(VALID_NMHANDLE(handle)); + REQUIRE(VALID_NMSOCK(handle->sock)); + + return (isc__nmsocket_timer_running(handle->sock)); +} + void * isc_nmhandle_getextra(isc_nmhandle_t *handle) { REQUIRE(VALID_NMHANDLE(handle)); diff --git a/lib/isc/time.c b/lib/isc/time.c index 727b399271..19f2ce33c6 100644 --- a/lib/isc/time.c +++ b/lib/isc/time.c @@ -31,6 +31,7 @@ #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ #define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ #define NS_PER_MS 1000000 /*%< Nanoseconds per millisecond. */ +#define MS_PER_S 1000 /*%< Milliseonds per second. */ #if defined(CLOCK_REALTIME) #define CLOCKSOURCE_HIRES CLOCK_REALTIME @@ -77,6 +78,14 @@ isc_interval_iszero(const isc_interval_t *i) { return (false); } +unsigned int +isc_interval_ms(const isc_interval_t *i) { + REQUIRE(i != NULL); + INSIST(i->nanoseconds < NS_PER_S); + + return ((i->seconds * MS_PER_S) + (i->nanoseconds / NS_PER_MS)); +} + /*** *** Absolute Times ***/ diff --git a/lib/ns/query.c b/lib/ns/query.c index 0916db2010..e5bbb3df1a 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -6652,7 +6652,7 @@ query_resume(query_ctx_t *qctx) { } else if (REDIRECT(qctx->client)) { tname = qctx->client->query.redirect.fname; } else { - tname = dns_fixedname_name(&qctx->event->foundname); + tname = qctx->event->foundname; } dns_name_copy(tname, qctx->fname); From 7dc54fa6f2da81162f4a12469a775c8bc7b48bbd Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 25 May 2021 22:54:17 -0700 Subject: [PATCH 19/28] Refactor dispatch, resolver and request Since every dispsock was associated with a dispentry anyway (though not always vice versa), the members of dispsock have been combined into dispentry, which is now reference-counted. dispentry objects are now attached before connecting and detached afterward to prevent races between the connect callback and dns_dispatch_removeresponse(). Dispatch and dispatchmgr objects are now reference counted as well, and the shutdown process has been simplified. reference counting of resquery and request objects has also been cleaned up significantly. dns_dispatch_cancel() now flags a dispentry as having been canceled, so that if the connect callback runs after cancellation, it will not initiate a read. The isblackholed() function has been simplified. --- bin/named/server.c | 2 +- bin/nsupdate/nsupdate.c | 2 +- bin/tests/system/pipelined/pipequeries.c | 2 +- bin/tests/system/tkey/keycreate.c | 2 +- bin/tests/system/tkey/keydelete.c | 2 +- bin/tools/mdig.c | 2 +- lib/dns/client.c | 18 +- lib/dns/dispatch.c | 1335 +++++++++------------- lib/dns/include/dns/dispatch.h | 42 +- lib/dns/include/dns/request.h | 12 +- lib/dns/request.c | 351 +++--- lib/dns/resolver.c | 984 +++++++++------- lib/dns/tests/dispatch_test.c | 4 +- lib/dns/tests/resolver_test.c | 2 +- lib/dns/zone.c | 4 +- lib/ns/tests/nstest.c | 2 +- 16 files changed, 1360 insertions(+), 1406 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 0abefe8407..7957591281 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -10003,7 +10003,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { ns_interfacemgr_detach(&server->interfacemgr); - dns_dispatchmgr_destroy(&named_g_dispatchmgr); + dns_dispatchmgr_detach(&named_g_dispatchmgr); dns_zonemgr_shutdown(server->zonemgr); diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index a3bb130a7e..0690676db4 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -735,7 +735,7 @@ doshutdown(void) { } ddebug("Shutting down dispatch manager"); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } static void diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 6b34dd808c..e41f14a566 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -286,7 +286,7 @@ main(int argc, char *argv[]) { dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchv4); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index 9ede9a65b5..b83d613f82 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -255,7 +255,7 @@ main(int argc, char *argv[]) { dns_requestmgr_shutdown(requestmgr); dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchv4); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index c76d816132..9b32e2930e 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -198,7 +198,7 @@ main(int argc, char **argv) { dns_requestmgr_shutdown(requestmgr); dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchv4); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); isc_managers_destroy(&netmgr, &taskmgr, NULL, NULL); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index f3d37da52c..ca3acb8eac 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -2175,7 +2175,7 @@ main(int argc, char *argv[]) { dns_requestmgr_detach(&requestmgr); dns_dispatch_detach(&dispatchvx); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); isc_task_shutdown(task); isc_task_detach(&task); diff --git a/lib/dns/client.c b/lib/dns/client.c index d33be3708f..030fa035b6 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -268,7 +268,6 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr6) { isc_result_t result; dns_client_t *client = NULL; - dns_dispatchmgr_t *dispatchmgr = NULL; dns_dispatch_t *dispatchv4 = NULL; dns_dispatch_t *dispatchv6 = NULL; dns_view_t *view = NULL; @@ -293,12 +292,11 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, goto cleanup_lock; } - result = dns_dispatchmgr_create(mctx, nm, &dispatchmgr); + result = dns_dispatchmgr_create(mctx, nm, &client->dispatchmgr); if (result != ISC_R_SUCCESS) { goto cleanup_task; } - client->dispatchmgr = dispatchmgr; - (void)setsourceports(mctx, dispatchmgr); + (void)setsourceports(mctx, client->dispatchmgr); /* * If only one address family is specified, use it. @@ -306,7 +304,7 @@ 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, taskmgr, + result = getudpdispatch(AF_INET, client->dispatchmgr, taskmgr, &dispatchv4, localaddr4); if (result == ISC_R_SUCCESS) { client->dispatchv4 = dispatchv4; @@ -315,7 +313,7 @@ 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, taskmgr, + result = getudpdispatch(AF_INET6, client->dispatchmgr, taskmgr, &dispatchv6, localaddr6); if (result == ISC_R_SUCCESS) { client->dispatchv6 = dispatchv6; @@ -332,8 +330,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, - nm, timermgr, dispatchmgr, dispatchv4, dispatchv6, - &view); + nm, timermgr, client->dispatchmgr, dispatchv4, + dispatchv6, &view); if (result != ISC_R_SUCCESS) { goto cleanup_references; } @@ -366,7 +364,7 @@ cleanup_dispatchmgr: if (dispatchv6 != NULL) { dns_dispatch_detach(&dispatchv6); } - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&client->dispatchmgr); cleanup_task: isc_task_detach(&client->task); cleanup_lock: @@ -394,7 +392,7 @@ destroyclient(dns_client_t *client) { dns_dispatch_detach(&client->dispatchv6); } - dns_dispatchmgr_destroy(&client->dispatchmgr); + dns_dispatchmgr_detach(&client->dispatchmgr); isc_task_detach(&client->task); diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 3f36a52223..75803f210d 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -41,8 +41,6 @@ typedef ISC_LIST(dns_dispentry_t) dns_displist_t; -typedef struct dispsocket dispsocket_t; - typedef struct dns_qid { unsigned int magic; isc_mutex_t lock; @@ -54,6 +52,7 @@ typedef struct dns_qid { struct dns_dispatchmgr { /* Unlocked. */ unsigned int magic; + isc_refcount_t references; isc_mem_t *mctx; dns_acl_t *blackhole; isc_stats_t *stats; @@ -69,8 +68,6 @@ struct dns_dispatchmgr { isc_mutex_t buffer_lock; unsigned int buffers; - isc_refcount_t irefs; - in_port_t *v4ports; /*%< available ports for IPv4 */ unsigned int nv4ports; /*%< # of available ports for IPv4 */ in_port_t *v6ports; /*%< available ports for IPv4 */ @@ -82,22 +79,25 @@ struct dns_dispatchmgr { struct dns_dispentry { unsigned int magic; + isc_refcount_t references; dns_dispatch_t *disp; - dns_messageid_t id; - in_port_t port; + isc_task_t *task; + isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */ unsigned int bucket; unsigned int timeout; + isc_sockaddr_t local; isc_sockaddr_t peer; - isc_task_t *task; + in_port_t port; + dns_messageid_t id; isc_nm_cb_t connected; isc_nm_cb_t sent; isc_nm_cb_t timedout; isc_taskaction_t action; void *arg; - bool item_out; - dispsocket_t *dispsocket; + bool canceled; ISC_LIST(dns_dispatchevent_t) items; ISC_LINK(dns_dispentry_t) link; + ISC_LINK(dns_dispentry_t) alink; }; /*% @@ -107,17 +107,6 @@ struct dns_dispentry { #define DNS_DISPATCH_UDPBUFSIZE 4096 #endif /* ifndef DNS_DISPATCH_UDPBUFSIZE */ -struct dispsocket { - unsigned int magic; - isc_nmhandle_t *handle; - dns_dispatch_t *disp; - isc_sockaddr_t local; - isc_sockaddr_t peer; - dns_dispentry_t *resp; - in_port_t port; - ISC_LINK(dispsocket_t) link; -}; - struct dns_dispatch { /* Unlocked. */ unsigned int magic; /*%< magic */ @@ -127,9 +116,6 @@ struct dns_dispatch { 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 */ /*% Locked by mgr->lock. */ ISC_LINK(dns_dispatch_t) link; @@ -138,13 +124,13 @@ struct dns_dispatch { isc_mutex_t lock; /*%< locks all below */ 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; - isc_result_t shutdown_why; - ISC_LIST(dispsocket_t) activesockets; - ISC_LIST(dispsocket_t) inactivesockets; + isc_refcount_t references; + dns_dispatchevent_t failsafe_ev; /*%< failsafe cancel event */ + unsigned int shutdown_out : 1, recv_pending : 1; + + ISC_LIST(dns_dispentry_t) active; unsigned int nsockets; + unsigned int requests; /*%< how many requests we have */ unsigned int tcpbuffers; /*%< allocated buffers */ }; @@ -164,17 +150,6 @@ struct dns_dispatch { #define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r') #define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC) -/*% - * Maximum number of dispatch sockets that can be pooled for reuse. The - * appropriate value may vary, but experiments have shown a busy caching server - * may need more than 1000 sockets concurrently opened. The maximum allowable - * number of dispatch sockets (per manager) will be set to the double of this - * value. - */ -#ifndef DNS_DISPATCH_POOLSOCKS -#define DNS_DISPATCH_POOLSOCKS 2048 -#endif /* ifndef DNS_DISPATCH_POOLSOCKS */ - /*% * Quota to control the number of UDP dispatch sockets. If a dispatch has * more than the quota of sockets, new queries will purge oldest ones, so @@ -194,14 +169,6 @@ struct dns_dispatch { #define DNS_DISPATCH_MAXBUFFERS 37268 #endif /* ifndef DNS_DISPATCH_MAXBUFFERS */ -/*% - * Number of dispatch sockets available for all dispatches in the - * socket memory pool. - */ -#ifndef DNS_DISPATCH_MAXSOCKETS -#define DNS_DISPATCH_MAXSOCKETS 32768 -#endif /* ifndef DNS_DISPATCH_MAXSOCKETS */ - /*% * Quota to control the number of concurrent requests that can be handled * by each TCP dispatch. (UDP dispatches do not currently support socket @@ -227,17 +194,12 @@ struct dns_dispatch { /* * Statics. */ +static void +dispatchmgr_destroy(dns_dispatchmgr_t *mgr); + static dns_dispentry_t * entry_search(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t, unsigned int); -static bool -destroy_disp_ok(dns_dispatch_t *); -static void -destroy_disp(isc_task_t *task, isc_event_t *event); -static void -destroy_dispsocket(dns_dispatch_t *, dispsocket_t **); -static void -deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *); static void udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, void *arg); @@ -251,31 +213,19 @@ free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); static inline dns_dispatchevent_t * allocate_devent(dns_dispatch_t *disp); static void -do_cancel(dns_dispatch_t *disp); -static dns_dispentry_t * -linear_first(dns_qid_t *disp); -static dns_dispentry_t * -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_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 -destroy_mgr(dns_dispatchmgr_t **mgrp); 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_nmhandle_t * -gethandle(dns_dispatch_t *disp); -static isc_nmhandle_t * +static inline isc_nmhandle_t * getentryhandle(dns_dispentry_t *resp); static void -startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket); +startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp); #define LVL(x) ISC_LOG_DEBUG(x) @@ -345,7 +295,6 @@ static void request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, const char *fmt, ...) { char msgbuf[2048]; - char peerbuf[256]; va_list ap; if (!isc_log_wouldlog(dns_lctx, level)) { @@ -357,6 +306,7 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, va_end(ap); if (VALID_RESPONSE(resp)) { + char peerbuf[256]; isc_sockaddr_format(&resp->peer, peerbuf, sizeof(peerbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH, level, @@ -387,136 +337,17 @@ dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, return (ret); } -/* - * Find the first entry in 'qid'. Returns NULL if there are no entries. - */ -static dns_dispentry_t * -linear_first(dns_qid_t *qid) { - dns_dispentry_t *ret = NULL; - unsigned int bucket = 0; - - while (bucket < qid->qid_nbuckets) { - ret = ISC_LIST_HEAD(qid->qid_table[bucket]); - if (ret != NULL) { - return (ret); - } - bucket++; - } - - return (NULL); -} - -/* - * Find the next entry after 'resp' in 'qid'. Return NULL if there are - * no more entries. - */ -static dns_dispentry_t * -linear_next(dns_qid_t *qid, dns_dispentry_t *resp) { - dns_dispentry_t *ret = NULL; - unsigned int bucket; - - ret = ISC_LIST_NEXT(resp, link); - if (ret != NULL) { - return (ret); - } - - bucket = resp->bucket + 1; - while (bucket < qid->qid_nbuckets) { - ret = ISC_LIST_HEAD(qid->qid_table[bucket]); - if (ret != NULL) { - return (ret); - } - bucket++; - } - - return (NULL); -} - -/* - * The dispatch must be locked. - */ -static bool -destroy_disp_ok(dns_dispatch_t *disp) { - if (isc_refcount_current(&disp->refcount) != 0) { - return (false); - } - - if (disp->recv_pending != 0) { - return (false); - } - - if (!ISC_LIST_EMPTY(disp->activesockets)) { - return (false); - } - - if (disp->shutting_down == 0) { - return (false); - } - - return (true); -} - -/* - * Called when refcount reaches 0 (and safe to destroy). - * - * The dispatcher must be locked. - * The manager must not be locked. - */ -static void -destroy_disp(isc_task_t *task, isc_event_t *event) { - dns_dispatch_t *disp = NULL; - dns_dispatchmgr_t *mgr = NULL; - bool killmgr; - dispsocket_t *dispsocket = NULL; - - INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL); - - UNUSED(task); - - disp = event->ev_arg; - mgr = disp->mgr; - - LOCK(&mgr->lock); - ISC_LIST_UNLINK(mgr->list, disp, link); - - dispatch_log(disp, LVL(90), "shutting down; detaching from handle %p", - disp->handle); - - if (disp->sepool != NULL) { - isc_mem_destroy(&disp->sepool); - } - - 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); - } - isc_task_detach(&disp->task); - isc_event_free(&event); - - dispatch_free(&disp); - - killmgr = destroy_mgr_ok(mgr); - UNLOCK(&mgr->lock); - if (killmgr) { - destroy_mgr(&mgr); - } -} - /*% - * Make a new socket for a single dispatch with a random port number. + * Choose a random port number for a dispatch entry. * The caller must hold the disp->lock */ static isc_result_t -get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, - dispsocket_t **dispsockp, in_port_t *portp) { +setup_socket(dns_dispatch_t *disp, dns_dispentry_t *resp, + const isc_sockaddr_t *dest, in_port_t *portp) { dns_dispatchmgr_t *mgr = disp->mgr; - in_port_t port; - dispsocket_t *dispsock = NULL; unsigned int nports; in_port_t *ports = NULL; + in_port_t port; if (isc_sockaddr_pf(&disp->local) == AF_INET) { nports = mgr->nv4ports; @@ -529,81 +360,34 @@ get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, return (ISC_R_ADDRNOTAVAIL); } - dispsock = ISC_LIST_HEAD(disp->inactivesockets); - if (dispsock != NULL) { - ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link); - } else { - dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock)); - disp->nsockets++; + disp->nsockets++; - *dispsock = (dispsocket_t){ .disp = disp }; - ISC_LINK_INIT(dispsock, link); - dispsock->magic = DISPSOCK_MAGIC; - } + resp->local = disp->local; + resp->peer = *dest; - dispsock->local = disp->local; - dispsock->peer = *dest; - - /* Pick a random UDP port */ port = ports[isc_random_uniform(nports)]; - isc_sockaddr_setport(&dispsock->local, port); - dispsock->port = port; + isc_sockaddr_setport(&resp->local, port); + resp->port = port; - *dispsockp = dispsock; *portp = port; return (ISC_R_SUCCESS); } /*% - * Destroy a dedicated dispatch socket. + * Deactivate the socket for a dispatch entry. * The dispatch must be locked. */ static void -destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { - dispsocket_t *dispsock = NULL; - - REQUIRE(dispsockp != NULL && *dispsockp != NULL); - - dispsock = *dispsockp; - *dispsockp = NULL; - - REQUIRE(!ISC_LINK_LINKED(dispsock, link)); - +deactivate_dispentry(dns_dispatch_t *disp, dns_dispentry_t *resp) { + if (ISC_LINK_LINKED(resp, alink)) { + ISC_LIST_UNLINK(disp->active, resp, alink); + } + if (resp->handle != NULL) { + isc_nm_cancelread(resp->handle); + isc_nmhandle_detach(&resp->handle); + } disp->nsockets--; - dispsock->magic = 0; - 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_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 { - if (dispsock->handle != NULL) { - isc_nm_cancelread(dispsock->handle); - isc_nmhandle_detach(&dispsock->handle); - } - - ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); - } } /* @@ -671,7 +455,8 @@ allocate_udp_buffer(dns_dispatch_t *disp) { static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { - if (disp->failsafe_ev == ev) { + /* failsafe_ev is not allocated */ + if (&(disp->failsafe_ev) == ev) { INSIST(disp->shutdown_out == 1); disp->shutdown_out = 0; @@ -684,8 +469,9 @@ free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { ev->region.length = 0; } - isc_refcount_decrement(&disp->mgr->irefs); isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev)); + + dns_dispatch_detach(&disp); } static inline dns_dispatchevent_t * @@ -693,14 +479,95 @@ allocate_devent(dns_dispatch_t *disp) { dns_dispatchevent_t *ev = NULL; ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); - isc_refcount_increment0(&disp->mgr->irefs); *ev = (dns_dispatchevent_t){ 0 }; + + dns_dispatch_attach(disp, &ev->dispatch); + ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, NULL); return (ev); } +#define dispentry_attach(r, rp) \ + __dispentry_attach(r, rp, __func__, __FILE__, __LINE__) + +static void +__dispentry_attach(dns_dispentry_t *resp, dns_dispentry_t **respp, + const char *func, const char *file, unsigned int line) { + uint_fast32_t ref; + + REQUIRE(VALID_RESPONSE(resp)); + REQUIRE(respp != NULL && *respp == NULL); + + ref = isc_refcount_increment(&resp->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, resp, respp, ref + 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* DISPATCH_TRACE */ + + *respp = resp; +} + +static void +__dispentry_destroy(dns_dispentry_t *resp) { + dns_dispatch_t *disp = resp->disp; + + resp->magic = 0; + + if (resp->handle != NULL) { + isc_nmhandle_detach(&resp->handle); + } + + isc_refcount_destroy(&resp->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%d:%s:isc_task_detach(%p) -> %p\n", __FILE__, + __LINE__, __func__, &resp->task, resp->task); +#endif /* DISPATCH_TRACE */ + + isc_task_detach(&resp->task); + isc_mem_put(disp->mgr->mctx, resp, sizeof(*resp)); + + dns_dispatch_detach(&disp); +} + +#define dispentry_detach(rp) \ + __dispentry_detach(rp, __func__, __FILE__, __LINE__) + +static void +__dispentry_detach(dns_dispentry_t **respp, const char *func, const char *file, + unsigned int line) { + dns_dispentry_t *resp = NULL; + uint_fast32_t ref; + + REQUIRE(respp != NULL && VALID_RESPONSE(*respp)); + + resp = *respp; + *respp = NULL; + + ref = isc_refcount_decrement(&resp->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, resp, respp, ref - 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); +#endif /* DISPATCH_TRACE */ + + if (ref == 1) { + __dispentry_destroy(resp); + } +} + /* * General flow: * @@ -718,60 +585,43 @@ allocate_devent(dns_dispatch_t *disp) { static void udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, void *arg) { - dispsocket_t *dispsock = (dispsocket_t *)arg; + dns_dispentry_t *resp = (dns_dispentry_t *)arg; dns_dispatch_t *disp = NULL; dns_messageid_t id; isc_result_t dres; isc_buffer_t source; unsigned int flags; - dns_dispentry_t *resp = NULL; dns_dispatchevent_t *rev = NULL; - bool killit; - bool queue_response; - dns_dispatchmgr_t *mgr = NULL; isc_sockaddr_t peer; isc_netaddr_t netaddr; int match; + isc_taskaction_t action = NULL; + bool nomore = true; - REQUIRE(VALID_DISPSOCK(dispsock)); + REQUIRE(VALID_RESPONSE(resp)); - disp = dispsock->disp; + disp = resp->disp; LOCK(&disp->lock); - mgr = disp->mgr; - - LOCK(&disp->mgr->buffer_lock); - dispatch_log(disp, LVL(90), "got packet: requests %d, recvs %d", - disp->requests, disp->recv_pending); - UNLOCK(&disp->mgr->buffer_lock); - - if (eresult == ISC_R_CANCELED || dispsock->resp == NULL) { - /* - * dispsock->resp can be NULL if this transaction was canceled - * just after receiving a response. So we can just move on. - */ - dispsock = NULL; + if (isc_log_wouldlog(dns_lctx, LVL(90))) { + LOCK(&disp->mgr->buffer_lock); + dispatch_log(disp, LVL(90), "got packet: requests %d, recvs %d", + disp->requests, disp->recv_pending); + UNLOCK(&disp->mgr->buffer_lock); } - if (disp->shutting_down == 1) { + if (eresult == ISC_R_CANCELED) { /* * This dispatcher is shutting down. */ - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task, &disp->ctlevent); - } - - return; + goto unlock; } - if (dispsock == NULL) { - goto next; + if (!ISC_LINK_LINKED(resp, alink)) { + goto unlock; } - resp = dispsock->resp; id = resp->id; peer = isc_nmhandle_peeraddr(handle); @@ -780,7 +630,8 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, if (eresult == ISC_R_TIMEDOUT && resp->timedout != NULL) { resp->timedout(handle, ISC_R_TIMEDOUT, resp->arg); if (isc_nmhandle_timer_running(handle)) { - goto next; + nomore = false; + goto unlock; } } @@ -810,7 +661,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dispatch_log(disp, LVL(10), "blackholed packet from %s", netaddrstr); } - goto next; + goto unlock; } /* @@ -821,7 +672,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { dispatch_log(disp, LVL(10), "got garbage packet"); - goto next; + goto unlock; } dispatch_log(disp, LVL(92), @@ -834,7 +685,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* query */ - goto next; + goto unlock; } /* @@ -842,13 +693,12 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, */ 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); - goto next; + inc_stats(disp->mgr, dns_resstatscounter_mismatch); + goto unlock; } sendevent: rev = allocate_devent(disp); - queue_response = resp->item_out; /* * At this point, rev contains the event we want to fill in, and @@ -856,7 +706,6 @@ sendevent: * Send the event off. */ rev->result = eresult; - resp->item_out = true; if (region != NULL) { rev->region.base = allocate_udp_buffer(disp); rev->region.length = DNS_DISPATCH_UDPBUFSIZE; @@ -866,23 +715,26 @@ sendevent: 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); - 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); - isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); + ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, + resp->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); + + action = resp->action; + +unlock: + UNLOCK(&disp->lock); + + if (action != NULL) { + action(resp->task, (isc_event_t *)rev); } - UNLOCK(&disp->lock); + if (nomore) { + dispentry_detach(&resp); + } return; - -next: - UNLOCK(&disp->lock); } /* @@ -907,17 +759,15 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dns_messageid_t id; isc_result_t dres; unsigned int flags; - dispsocket_t *dispsock = NULL; dns_dispentry_t *resp = NULL; dns_dispatchevent_t *rev = NULL; unsigned int bucket; - bool killit; - bool queue_response; dns_qid_t *qid = NULL; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; isc_buffer_t source; isc_sockaddr_t peer; + isc_taskaction_t action = NULL; REQUIRE(VALID_DISPATCH(disp)); @@ -932,79 +782,48 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, INSIST(disp->recv_pending != 0); disp->recv_pending = 0; - if (isc_refcount_current(&disp->refcount) == 0) { - /* - * This dispatcher is shutting down. Force cancellation. - */ - eresult = ISC_R_CANCELED; - } - peer = isc_nmhandle_peeraddr(handle); - isc_nmhandle_detach(&handle); if (eresult != ISC_R_SUCCESS) { - disp->shutdown_why = eresult; - switch (eresult) { case ISC_R_CANCELED: dispatch_log(disp, LVL(90), "shutting down on cancel"); - do_cancel(disp); break; case ISC_R_EOF: dispatch_log(disp, LVL(90), "shutting down on EOF"); - do_cancel(disp); break; - case ISC_R_CONNECTIONRESET: - level = ISC_LOG_INFO; - goto logit; - case ISC_R_TIMEDOUT: /* * Time out the first active response for which * no event has already been sent. */ - for (dispsock = ISC_LIST_HEAD(disp->activesockets); - dispsock != NULL; - dispsock = ISC_LIST_NEXT(dispsock, link)) + for (resp = ISC_LIST_HEAD(disp->active); resp != NULL; + resp = ISC_LIST_NEXT(resp, alink)) { - resp = dispsock->resp; - if (resp->item_out) { - continue; - } - ISC_LIST_UNLINK(disp->activesockets, dispsock, - link); - ISC_LIST_APPEND(disp->activesockets, dispsock, - link); + ISC_LIST_UNLINK(disp->active, resp, alink); + ISC_LIST_APPEND(disp->active, resp, alink); goto sendevent; } - INSIST(0); - ISC_UNREACHABLE(); + break; default: - level = ISC_LOG_ERROR; - logit: + 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)); - do_cancel(disp); break; } - disp->shutting_down = 1; - - /* - * If the recv() was canceled pass the word on. - */ - killit = destroy_disp_ok(disp); - UNLOCK(&disp->lock); - if (killit) { - isc_task_send(disp->task, &disp->ctlevent); - } - return; + goto unlock; } dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", @@ -1055,7 +874,6 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, } sendevent: - queue_response = resp->item_out; rev = allocate_devent(disp); /* @@ -1064,7 +882,6 @@ sendevent: * Send the event off. */ rev->result = eresult; - resp->item_out = true; if (region != NULL) { disp->tcpbuffers++; rev->region.base = isc_mem_get(disp->mgr->mctx, region->length); @@ -1075,84 +892,26 @@ sendevent: 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); - 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); - isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); - } + ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, + resp->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); + + action = resp->action; next: startrecv(disp, NULL); + +unlock: + isc_nmhandle_detach(&handle); UNLOCK(&disp->lock); -} -/* - * Mgr must be locked when calling this function. - */ -static bool -destroy_mgr_ok(dns_dispatchmgr_t *mgr) { - mgr_log(mgr, LVL(90), - "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, ", - MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list)); - if (!MGR_IS_SHUTTINGDOWN(mgr)) { - return (false); + dns_dispatch_detach(&disp); + + if (action != NULL) { + action(resp->task, (isc_event_t *)rev); } - if (!ISC_LIST_EMPTY(mgr->list)) { - return (false); - } - if (isc_refcount_current(&mgr->irefs) != 0) { - return (false); - } - - return (true); -} - -/* - * Mgr must be unlocked when calling this function. - */ -static void -destroy_mgr(dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr = NULL; - - mgr = *mgrp; - *mgrp = NULL; - - mgr->magic = 0; - isc_mutex_destroy(&mgr->lock); - mgr->state = 0; - - if (mgr->qid != NULL) { - qid_destroy(mgr->mctx, &mgr->qid); - } - - isc_mutex_destroy(&mgr->buffer_lock); - - if (mgr->blackhole != NULL) { - dns_acl_detach(&mgr->blackhole); - } - - if (mgr->stats != NULL) { - isc_stats_detach(&mgr->stats); - } - - if (mgr->v4ports != NULL) { - isc_mem_put(mgr->mctx, mgr->v4ports, - mgr->nv4ports * sizeof(in_port_t)); - } - if (mgr->v6ports != NULL) { - isc_mem_put(mgr->mctx, mgr->v6ports, - mgr->nv6ports * sizeof(in_port_t)); - } - - isc_nm_detach(&mgr->nm); - - isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); } /*% @@ -1231,7 +990,7 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); *mgr = (dns_dispatchmgr_t){ .magic = 0 }; - isc_refcount_init(&mgr->irefs, 0); + isc_refcount_init(&mgr->references, 1); isc_mem_attach(mctx, &mgr->mctx); isc_nm_attach(nm, &mgr->nm); @@ -1256,6 +1015,56 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, return (ISC_R_SUCCESS); } +void +dns__dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp, + const char *func, const char *file, unsigned int line) { + uint_fast32_t ref; + + REQUIRE(VALID_DISPATCHMGR(mgr)); + REQUIRE(mgrp != NULL && *mgrp == NULL); + + ref = isc_refcount_increment(&mgr->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, mgr, mgrp, ref + 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* DISPATCH_TRACE */ + + *mgrp = mgr; +} + +void +dns__dispatchmgr_detach(dns_dispatchmgr_t **mgrp, const char *func, + const char *file, unsigned int line) { + dns_dispatchmgr_t *mgr = NULL; + uint_fast32_t ref; + + REQUIRE(mgrp != NULL && VALID_DISPATCHMGR(*mgrp)); + + mgr = *mgrp; + *mgrp = NULL; + + ref = isc_refcount_decrement(&mgr->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, mgr, mgrp, ref - 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); +#endif /* DISPATCH_TRACE */ + + if (ref == 1) { + dispatchmgr_destroy(mgr); + } +} + void dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) { REQUIRE(VALID_DISPATCHMGR(mgr)); @@ -1278,27 +1087,40 @@ dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, return (setavailports(mgr, v4portset, v6portset)); } -void -dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { - dns_dispatchmgr_t *mgr = NULL; - bool killit; +static void +dispatchmgr_destroy(dns_dispatchmgr_t *mgr) { + REQUIRE(VALID_DISPATCHMGR(mgr)); - REQUIRE(mgrp != NULL); - REQUIRE(VALID_DISPATCHMGR(*mgrp)); + isc_refcount_destroy(&mgr->references); - mgr = *mgrp; - *mgrp = NULL; + mgr->magic = 0; + isc_mutex_destroy(&mgr->lock); + mgr->state = 0; - LOCK(&mgr->lock); - mgr->state |= MGR_SHUTTINGDOWN; - killit = destroy_mgr_ok(mgr); - UNLOCK(&mgr->lock); + qid_destroy(mgr->mctx, &mgr->qid); - mgr_log(mgr, LVL(90), "destroy: killit=%d", killit); + isc_mutex_destroy(&mgr->buffer_lock); - if (killit) { - destroy_mgr(&mgr); + if (mgr->blackhole != NULL) { + dns_acl_detach(&mgr->blackhole); } + + if (mgr->stats != NULL) { + isc_stats_detach(&mgr->stats); + } + + if (mgr->v4ports != NULL) { + isc_mem_put(mgr->mctx, mgr->v4ports, + mgr->nv4ports * sizeof(in_port_t)); + } + if (mgr->v6ports != NULL) { + isc_mem_put(mgr->mctx, mgr->v6ports, + mgr->nv6ports * sizeof(in_port_t)); + } + + isc_nm_detach(&mgr->nm); + + isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); } void @@ -1366,15 +1188,12 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf, */ disp = isc_mem_get(mgr->mctx, sizeof(*disp)); - isc_refcount_increment0(&mgr->irefs); + *disp = (dns_dispatch_t){ .socktype = type }; - *disp = (dns_dispatch_t){ .mgr = mgr, - .socktype = type, - .shutdown_why = ISC_R_UNEXPECTED }; - isc_refcount_init(&disp->refcount, 1); + dns_dispatchmgr_attach(mgr, &disp->mgr); + isc_refcount_init(&disp->references, 1); ISC_LINK_INIT(disp, link); - ISC_LIST_INIT(disp->activesockets); - ISC_LIST_INIT(disp->inactivesockets); + ISC_LIST_INIT(disp->active); switch (type) { case isc_socktype_tcp: @@ -1409,7 +1228,11 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf, disp->attributes |= attributes; isc_mutex_init(&disp->lock); - disp->failsafe_ev = allocate_devent(disp); + + /* failsafe_ev is not allocated */ + ISC_EVENT_INIT(&disp->failsafe_ev, sizeof(disp->failsafe_ev), 0, NULL, + 0, NULL, NULL, NULL, NULL, NULL); + disp->magic = DISPATCH_MAGIC; *dispp = disp; @@ -1427,26 +1250,17 @@ dispatch_free(dns_dispatch_t **dispp) { disp = *dispp; *dispp = NULL; + disp->magic = 0; + mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); INSIST(disp->requests == 0); INSIST(disp->recv_pending == 0); - INSIST(ISC_LIST_EMPTY(disp->activesockets)); - INSIST(ISC_LIST_EMPTY(disp->inactivesockets)); + INSIST(ISC_LIST_EMPTY(disp->active)); - isc_refcount_decrement(&mgr->irefs); - - 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); - disp->magic = 0; - isc_refcount_decrement(&mgr->irefs); + isc_mem_put(mgr->mctx, disp, sizeof(*disp)); } @@ -1479,14 +1293,16 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, } result = isc_task_create(taskmgr, 50, &disp->task); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%d:%s:isc_task_create() -> %p\n", __FILE__, + __LINE__, __func__, disp->task); +#endif /* DISPATCH_TRACE */ + if (result != ISC_R_SUCCESS) { goto cleanup; } - disp->ctlevent = - isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, - destroy_disp, disp, sizeof(isc_event_t)); - isc_task_setname(disp->task, "tcpdispatch", disp); /* @@ -1520,10 +1336,7 @@ 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_sockaddr_t peeraddr; - isc_sockaddr_t sockname; unsigned int attributes, mask; - bool match = false; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(destaddr != NULL); @@ -1535,24 +1348,32 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, DNS_DISPATCHATTR_CONNECTED; LOCK(&mgr->lock); +again: disp = ISC_LIST_HEAD(mgr->list); - while (disp != NULL && !match) { + while (disp != NULL && *dispp == NULL) { + isc_sockaddr_t sockname; + isc_sockaddr_t peeraddr; + LOCK(&disp->lock); - if ((disp->shutting_down == 0) && - ATTRMATCH(disp->attributes, attributes, mask) && + + if (disp->handle != NULL) { + sockname = isc_nmhandle_localaddr(disp->handle); + peeraddr = isc_nmhandle_peeraddr(disp->handle); + } else { + sockname = disp->local; + peeraddr = disp->peer; + } + + if (ATTRMATCH(disp->attributes, attributes, mask) && (localaddr == NULL || isc_sockaddr_eqaddr(localaddr, &disp->local))) { - 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))) { /* attach */ - isc_refcount_increment(&disp->refcount); - *dispp = disp; - match = true; + dns_dispatch_attach(disp, dispp); if (connected != NULL) { *connected = true; } @@ -1561,34 +1382,21 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, UNLOCK(&disp->lock); disp = ISC_LIST_NEXT(disp, link); } - if (match || connected == NULL) { + + if (*dispp != NULL) { UNLOCK(&mgr->lock); - return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); + return (ISC_R_SUCCESS); } - /* Second pass, only if connected != NULL */ - attributes = DNS_DISPATCHATTR_TCP; - - disp = ISC_LIST_HEAD(mgr->list); - while (disp != NULL && !match) { - LOCK(&disp->lock); - if ((disp->shutting_down == 0) && - ATTRMATCH(disp->attributes, attributes, mask) && - (localaddr == NULL || - isc_sockaddr_eqaddr(localaddr, &disp->local)) && - isc_sockaddr_equal(destaddr, &disp->peer)) - { - /* attach */ - isc_refcount_increment(&disp->refcount); - *dispp = disp; - match = true; - } - UNLOCK(&disp->lock); - disp = ISC_LIST_NEXT(disp, link); + if (connected != NULL) { + /* Second pass, only if connected != NULL */ + attributes = DNS_DISPATCHATTR_TCP; + connected = NULL; + goto again; } + UNLOCK(&mgr->lock); - - return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); + return (ISC_R_NOTFOUND); } isc_result_t @@ -1648,18 +1456,16 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, disp->local = *localaddr; result = isc_task_create(taskmgr, 0, &disp->task); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%d:%s:isc_task_create() -> %p\n", __FILE__, + __LINE__, __func__, disp->task); +#endif /* DISPATCH_TRACE */ + if (result != ISC_R_SUCCESS) { goto cleanup; } - disp->ctlevent = - isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, - destroy_disp, disp, sizeof(isc_event_t)); - - disp->sepool = NULL; - isc_mem_create(&disp->sepool); - isc_mem_setname(disp->sepool, "disp_sepool"); - /* * Append it to the dispatcher list. */ @@ -1681,53 +1487,90 @@ cleanup: return (result); } +static void +dns_dispatch_destroy(dns_dispatch_t *disp) { + dns_dispatchmgr_t *mgr = disp->mgr; + + LOCK(&mgr->lock); + ISC_LIST_UNLINK(mgr->list, disp, link); + UNLOCK(&mgr->lock); + + dispatch_log(disp, LVL(90), "shutting down; detaching from handle %p", + disp->handle); + + if (disp->handle != NULL) { + isc_nmhandle_detach(&disp->handle); + } + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%d:%s:isc_task_detach(%p) -> %p\n", __FILE__, + __LINE__, __func__, &disp->task, disp->task); +#endif /* DISPATCH_TRACE */ + + isc_task_detach(&disp->task); + + dispatch_free(&disp); + + /* Because dispatch uses mgr->mctx, we must detach after freeing + * dispatch, not before + */ + dns_dispatchmgr_detach(&mgr); +} + void -dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { +dns__dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp, + const char *func, const char *file, unsigned int line) { + uint_fast32_t ref; + REQUIRE(VALID_DISPATCH(disp)); REQUIRE(dispp != NULL && *dispp == NULL); - isc_refcount_increment(&disp->refcount); + ref = isc_refcount_increment(&disp->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, disp, dispp, ref + 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* DISPATCH_TRACE */ + *dispp = disp; } void -dns_dispatch_detach(dns_dispatch_t **dispp) { +dns__dispatch_detach(dns_dispatch_t **dispp, const char *func, const char *file, + unsigned int line) { dns_dispatch_t *disp = NULL; - dispsocket_t *dispsock = NULL; - bool killit = false; + uint_fast32_t ref; REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); disp = *dispp; *dispp = NULL; - if (isc_refcount_decrement(&disp->refcount) == 1) { + ref = isc_refcount_decrement(&disp->references); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, disp, dispp, ref - 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); +#endif /* DISPATCH_TRACE */ + + dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1); + + if (ref == 1) { 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)) - { - if (dispsock->handle != NULL) { - isc_nmhandle_detach(&dispsock->handle); - } - } - disp->shutting_down = 1; - do_cancel(disp); - - killit = destroy_disp_ok(disp); + REQUIRE(disp->recv_pending == 0); + REQUIRE(ISC_LIST_EMPTY(disp->active)); UNLOCK(&disp->lock); - } - dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, - isc_refcount_current(&disp->refcount)); - - if (killit) { - isc_task_send(disp->task, &disp->ctlevent); + dns_dispatch_destroy(disp); } } @@ -1738,15 +1581,16 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, isc_nm_cb_t sent, isc_taskaction_t action, isc_nm_cb_t timedout, void *arg, dns_messageid_t *idp, dns_dispentry_t **resp) { - isc_result_t result; dns_dispentry_t *res = NULL; - dispsocket_t *dispsocket = NULL; dns_qid_t *qid = NULL; in_port_t localport = 0; dns_messageid_t id; unsigned int bucket; bool ok = false; int i = 0; + isc_taskaction_t oldest_action = NULL; + isc_task_t *oldest_task = NULL; + isc_event_t *oldest_ev = NULL; REQUIRE(VALID_DISPATCH(disp)); REQUIRE(task != NULL); @@ -1758,11 +1602,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, LOCK(&disp->lock); - if (disp->shutting_down == 1) { - UNLOCK(&disp->lock); - return (ISC_R_SHUTTINGDOWN); - } - if (disp->requests >= DNS_DISPATCH_MAXREQUESTS) { UNLOCK(&disp->lock); return (ISC_R_QUOTA); @@ -1773,42 +1612,51 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, if (disp->socktype == isc_socktype_udp && disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { - dispsocket_t *oldestsocket = NULL; - dns_dispentry_t *oldestresp = NULL; + dns_dispentry_t *oldest = NULL; dns_dispatchevent_t *rev = NULL; /* * Kill oldest outstanding query if the number of sockets * exceeds the quota to keep the room for new queries. */ - oldestsocket = ISC_LIST_HEAD(disp->activesockets); - oldestresp = oldestsocket->resp; - if (oldestresp != NULL && !oldestresp->item_out) { - rev = allocate_devent(oldestresp->disp); + oldest = ISC_LIST_HEAD(disp->active); + if (oldest != NULL) { + rev = allocate_devent(oldest->disp); rev->buffer.base = NULL; rev->result = ISC_R_CANCELED; ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, - DNS_EVENT_DISPATCH, oldestresp->action, - oldestresp->arg, oldestresp, NULL, NULL); - oldestresp->item_out = true; - isc_task_send(oldestresp->task, ISC_EVENT_PTR(&rev)); + DNS_EVENT_DISPATCH, oldest->action, + oldest->arg, oldest, NULL, NULL); + + oldest_action = oldest->action; + oldest_task = oldest->task; + oldest_ev = (isc_event_t *)rev; + inc_stats(disp->mgr, dns_resstatscounter_dispabort); } - - /* - * Move this entry to the tail so that it won't (easily) be - * examined before actually being canceled. - */ - ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link); - ISC_LIST_APPEND(disp->activesockets, oldestsocket, link); } + res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); + + *res = (dns_dispentry_t){ .port = localport, + .timeout = timeout, + .peer = *dest, + .connected = connected, + .sent = sent, + .timedout = timedout, + .action = action, + .arg = arg }; + + isc_refcount_init(&res->references, 1); + + ISC_LIST_INIT(res->items); + ISC_LINK_INIT(res, link); + ISC_LINK_INIT(res, alink); + if (disp->socktype == isc_socktype_udp) { - /* - * Get a separate UDP socket with a random port number. - */ - result = get_dispsocket(disp, dest, &dispsocket, &localport); + isc_result_t result = setup_socket(disp, res, dest, &localport); if (result != ISC_R_SUCCESS) { + isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); UNLOCK(&disp->lock); inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); return (result); @@ -1841,38 +1689,26 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, UNLOCK(&qid->lock); if (!ok) { + isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); UNLOCK(&disp->lock); return (ISC_R_NOMORE); } - res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); - isc_refcount_increment0(&disp->mgr->irefs); - - *res = (dns_dispentry_t){ .id = id, - .port = localport, - .bucket = bucket, - .timeout = timeout, - .peer = *dest, - .connected = connected, - .sent = sent, - .timedout = timedout, - .action = action, - .arg = arg, - .dispsocket = dispsocket }; - dns_dispatch_attach(disp, &res->disp); + +#ifdef DISPATCH_TRACE + fprintf(stderr, "%s:%d:%s:isc_task_attach(%p, %p)\n", __FILE__, + __LINE__, __func__, task, &res->task); +#endif /* DISPATCH_TRACE */ + isc_task_attach(task, &res->task); - ISC_LIST_INIT(res->items); - ISC_LINK_INIT(res, link); + res->id = id; + res->bucket = bucket; res->magic = RESPONSE_MAGIC; disp->requests++; - if (dispsocket != NULL) { - dispsocket->resp = res; - } - LOCK(&qid->lock); ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); @@ -1883,13 +1719,13 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - if (dispsocket != NULL) { - ISC_LIST_APPEND(disp->activesockets, dispsocket, link); - } + ISC_LIST_APPEND(disp->active, res, alink); UNLOCK(&disp->lock); - INSIST(disp->socktype == isc_socktype_tcp || res->dispsocket != NULL); + if (oldest_action != NULL) { + oldest_action(oldest_task, oldest_ev); + } *idp = id; *resp = res; @@ -1901,6 +1737,7 @@ isc_result_t dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { dns_dispatch_t *disp = NULL; dns_dispatchevent_t *ev = NULL; + isc_taskaction_t action = NULL; REQUIRE(VALID_RESPONSE(resp)); REQUIRE(sockevent != NULL && *sockevent != NULL); @@ -1913,16 +1750,8 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { LOCK(&disp->lock); - REQUIRE(resp->item_out); - resp->item_out = false; - 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); @@ -1931,40 +1760,44 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { request_log(disp, resp, LVL(90), "[c] Sent event %p buffer %p len %d to task %p", ev, ev->buffer.base, ev->buffer.length, resp->task); - resp->item_out = true; - isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); + + action = resp->action; } - startrecv(disp, resp->dispsocket); + startrecv(disp, resp); UNLOCK(&disp->lock); + if (action != NULL) { + action(resp->task, (isc_event_t *)ev); + } + return (ISC_R_SUCCESS); } void -dns_dispatch_removeresponse(dns_dispentry_t **resp, +dns_dispatch_removeresponse(dns_dispentry_t **respp, dns_dispatchevent_t **sockevent) { dns_dispatchmgr_t *mgr = NULL; dns_dispatch_t *disp = NULL; - dns_dispentry_t *res = NULL; + dns_dispentry_t *resp = NULL; dns_dispatchevent_t *ev = NULL; - unsigned int bucket; - isc_eventlist_t events; dns_qid_t *qid = NULL; - REQUIRE(resp != NULL); - REQUIRE(VALID_RESPONSE(*resp)); + REQUIRE(respp != NULL); - res = *resp; - *resp = NULL; + resp = *respp; + + REQUIRE(VALID_RESPONSE(resp)); + + disp = resp->disp; - disp = res->disp; - res->disp = NULL; REQUIRE(VALID_DISPATCH(disp)); mgr = disp->mgr; + REQUIRE(VALID_DISPATCHMGR(mgr)); + qid = mgr->qid; if (sockevent != NULL) { @@ -1978,95 +1811,66 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, LOCK(&disp->lock); INSIST(disp->requests > 0); disp->requests--; + dec_stats(disp->mgr, (disp->socktype == isc_socktype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); - if (res->dispsocket != NULL) { - deactivate_dispsocket(disp, res->dispsocket); - } - UNLOCK(&disp->lock); - - bucket = res->bucket; + deactivate_dispentry(disp, resp); LOCK(&qid->lock); - ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); + ISC_LIST_UNLINK(qid->qid_table[resp->bucket], resp, link); 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. - */ - ISC_LIST_INIT(events); - n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH, NULL, - &events); - /* - * We had better have gotten it back. - */ - INSIST(n == 1); - ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events); - } + UNLOCK(&disp->lock); if (ev != NULL) { - REQUIRE(res->item_out); - res->item_out = false; free_devent(disp, ev); } - request_log(disp, res, LVL(90), "detaching from task %p", res->task); - isc_task_detach(&res->task); - /* * Free any buffered responses as well */ - ev = ISC_LIST_HEAD(res->items); + ev = ISC_LIST_HEAD(resp->items); while (ev != NULL) { - ISC_LIST_UNLINK(res->items, ev, ev_link); + ISC_LIST_UNLINK(resp->items, ev, ev_link); free_devent(disp, ev); - ev = ISC_LIST_HEAD(res->items); + ev = ISC_LIST_HEAD(resp->items); } - res->magic = 0; - isc_refcount_decrement(&disp->mgr->irefs); - isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); - dns_dispatch_detach(&disp); + dispentry_detach(respp); } /* * disp must be locked. */ static void -startrecv(dns_dispatch_t *disp, dispsocket_t *dispsocket) { +startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) { isc_nmhandle_t *handle = NULL; - - if (disp->shutting_down == 1) { - return; - } - - if (dispsocket == NULL) { - if (disp->socktype == isc_socktype_udp || - disp->recv_pending != 0) { - return; - } - isc_nmhandle_attach(disp->handle, &handle); - } else { - handle = dispsocket->handle; - } + dns_dispentry_t *tmp_resp = NULL; + dns_dispatch_t *tmp_disp = NULL; switch (disp->socktype) { case isc_socktype_udp: - isc_nm_read(handle, udp_recv, dispsocket); - break; + REQUIRE(resp != NULL); + REQUIRE(resp->handle != NULL); + dispentry_attach(resp, &tmp_resp); + + /* resp->handle is detached in _removeresponse() */ + isc_nm_read(resp->handle, udp_recv, resp); + + break; case isc_socktype_tcp: + if (resp != NULL) { + REQUIRE(resp->handle == NULL); + } + + isc_nmhandle_attach(disp->handle, &handle); + dns_dispatch_attach(disp, &tmp_disp); isc_nm_read(handle, tcp_recv, disp); INSIST(disp->recv_pending == 0); disp->recv_pending = 1; break; - default: INSIST(0); ISC_UNREACHABLE(); @@ -2077,36 +1881,64 @@ 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 (resp->canceled && eresult == ISC_R_SUCCESS) { + eresult = ISC_R_CANCELED; + goto detach; + } + + if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { + eresult = ISC_R_SHUTTINGDOWN; + } + + /* + * Start listening on success + */ 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); + switch (disp->socktype) { + case isc_socktype_udp: + isc_nmhandle_attach(handle, &resp->handle); + startrecv(disp, resp); + break; + case isc_socktype_tcp: + if (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(); } - - startrecv(disp, dispsocket); } if (resp->connected != NULL) { resp->connected(handle, eresult, resp->arg); } + +detach: + dispentry_detach(&resp); } isc_result_t dns_dispatch_connect(dns_dispentry_t *resp) { dns_dispatch_t *disp = NULL; + dns_dispentry_t *tmp = NULL; REQUIRE(VALID_RESPONSE(resp)); disp = resp->disp; + dispentry_attach(resp, &tmp); /* detached in disp_connected */ + switch (disp->socktype) { case isc_socktype_tcp: + INSIST(disp->handle == NULL); if (disp->handle != NULL) { + /* We are already connected */ break; } @@ -2114,9 +1946,8 @@ dns_dispatch_connect(dns_dispentry_t *resp) { 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); + isc_nm_udpconnect(disp->mgr->nm, &resp->local, &resp->peer, + disp_connected, resp, resp->timeout, 0); break; default: return (ISC_R_NOTIMPLEMENTED); @@ -2125,9 +1956,25 @@ dns_dispatch_connect(dns_dispentry_t *resp) { return (ISC_R_SUCCESS); } +static void +send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { + dns_dispentry_t *resp = (dns_dispentry_t *)cbarg; + + REQUIRE(VALID_RESPONSE(resp)); + + resp->sent(handle, result, resp->arg); + + if (result != ISC_R_SUCCESS) { + isc_nm_cancelread(handle); + } + + dispentry_detach(&resp); +} + void dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { isc_nmhandle_t *handle = NULL; + dns_dispentry_t *tmp = NULL; REQUIRE(VALID_RESPONSE(resp)); @@ -2149,108 +1996,38 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { } #endif - isc_nm_send(handle, r, resp->sent, resp->arg); + dispentry_attach(resp, &tmp); /* detached in send_done() */ + isc_nm_send(handle, r, send_done, resp); } void -dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, - bool connecting) { +dns_dispatch_cancel(dns_dispentry_t *resp) { + REQUIRE(VALID_RESPONSE(resp)); + + resp->canceled = true; + + if (resp->handle) { + isc_nm_cancelread(resp->handle); + } else if (resp->disp->handle != NULL) { + isc_nm_cancelread(resp->disp->handle); + } +} + +static inline isc_nmhandle_t * +getentryhandle(dns_dispentry_t *resp) { isc_nmhandle_t *handle = NULL; - REQUIRE(disp != NULL || resp != NULL); - - if (resp != NULL) { - REQUIRE(VALID_RESPONSE(resp)); - handle = getentryhandle(resp); - } else if (disp != NULL) { - REQUIRE(VALID_DISPATCH(disp)); - handle = gethandle(disp); - } else { - INSIST(0); - ISC_UNREACHABLE(); - } - - if (handle == NULL) { - return; - } - - if (connecting) { - // isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); - } - - if (sending) { - // isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); - } -} - -/* - * disp must be locked. - */ -static void -do_cancel(dns_dispatch_t *disp) { - dns_dispatchevent_t *ev = NULL; - dns_dispentry_t *resp = NULL; - dns_qid_t *qid = disp->mgr->qid; - - if (disp->shutdown_out == 1) { - return; - } - - /* - * Search for the first response handler without packets outstanding - * unless a specific handler is given. - */ - LOCK(&qid->lock); - for (resp = linear_first(qid); resp != NULL && resp->item_out; - /* Empty. */) - { - resp = linear_next(qid, resp); - } - - /* - * No one to send the cancel event to, so nothing to do. - */ - if (resp == NULL) { - goto unlock; - } - - /* - * 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; - ev->buffer.base = NULL; - ev->buffer.length = 0; - disp->shutdown_out = 1; - request_log(disp, resp, LVL(10), "cancel: failsafe event %p -> task %p", - ev, resp->task); - resp->item_out = true; - isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); -unlock: - UNLOCK(&qid->lock); -} - -static isc_nmhandle_t * -gethandle(dns_dispatch_t *disp) { - REQUIRE(VALID_DISPATCH(disp)); - - return (disp->handle); -} - -static isc_nmhandle_t * -getentryhandle(dns_dispentry_t *resp) { REQUIRE(VALID_RESPONSE(resp)); if (resp->disp->socktype == isc_socktype_tcp) { - return (resp->disp->handle); - } else if (resp->dispsocket != NULL) { - return (resp->dispsocket->handle); + handle = resp->disp->handle; } else { - return (NULL); + handle = resp->handle; } + + INSIST(handle != NULL); + + return (handle); } isc_result_t @@ -2275,8 +2052,8 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) { return (ISC_R_SUCCESS); } - if (resp->dispsocket != NULL && resp->dispsocket->handle != NULL) { - *addrp = isc_nmhandle_localaddr(resp->dispsocket->handle); + if (resp->handle != NULL) { + *addrp = isc_nmhandle_localaddr(resp->handle); return (ISC_R_SUCCESS); } @@ -2288,8 +2065,8 @@ 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. + * We don't bother locking disp here; it's the caller's + * responsibility to use only non volatile flags. */ return (disp->attributes); } diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 762a979ad8..01054a1dc0 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -79,9 +79,10 @@ ISC_LANG_BEGINDECLS struct dns_dispatchevent { ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */ - isc_result_t result; /*%< result code */ - isc_region_t region; /*%< data region */ - isc_buffer_t buffer; /*%< data buffer */ + isc_result_t result; /*%< result code */ + isc_region_t region; /*%< data region */ + isc_buffer_t buffer; /*%< data buffer */ + dns_dispatch_t *dispatch; }; /*% @@ -146,8 +147,19 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, dns_dispatchmgr_t **mgrp); *\li anything else -- failure */ +#define dns_dispatchmgr_attach(mgr, mgrp) \ + dns__dispatchmgr_attach(mgr, mgrp, __func__, __FILE__, __LINE__) + void -dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp); +dns__dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp, + const char *func, const char *file, unsigned int line); + +#define dns_dispatchmgr_detach(mgrp) \ + dns__dispatchmgr_detach(mgrp, __func__, __FILE__, __LINE__) + +void +dns__dispatchmgr_detach(dns_dispatchmgr_t **mgrp, const char *func, + const char *file, unsigned int line); /*%< * Destroys the dispatchmgr when it becomes empty. This could be * immediately. @@ -246,8 +258,12 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, *\li Anything else -- failure. */ +#define dns_dispatch_attach(d, dp) \ + dns__dispatch_attach(d, dp, __func__, __FILE__, __LINE__) + void -dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp); +dns__dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp, + const char *func, const char *file, unsigned int line); /*%< * Attach to a dispatch handle. * @@ -257,8 +273,12 @@ dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp); *\li dispp != NULL && *dispp == NULL */ +#define dns_dispatch_detach(dp) \ + dns__dispatch_detach(dp, __func__, __FILE__, __LINE__) + void -dns_dispatch_detach(dns_dispatch_t **dispp); +dns__dispatch_detach(dns_dispatch_t **dispp, const char *func, const char *file, + unsigned int line); /*%< * Detaches from the dispatch. * @@ -277,15 +297,13 @@ dns_dispatch_connect(dns_dispentry_t *resp); */ void -dns_dispatch_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp, bool sending, - bool connecting); +dns_dispatch_cancel(dns_dispentry_t *resp); /*%< - * Cancel pending sends (if 'sending' is true) and connects (if - * 'connecting' is true) in 'resp' or 'disp'. + * Cancel pending connects in 'resp', by setting a flag so that + * a read is not started when the connect handler runs. * * Requires: - *\li 'resp' is NULL and 'disp' is valid, or - *\li 'disp' is NULL and 'resp' is valid. + *\li 'resp' is valid. */ void diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index 9554603b50..fd8e08cebe 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -124,8 +124,12 @@ dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr); *\li 'requestmgr' is a valid requestmgr. */ +#define dns_requestmgr_attach(source, targetp) \ + dns__requestmgr_attach(source, targetp, __FILE__, __LINE__, __func__) + void -dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp); +dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, + const char *file, unsigned int line, const char *func); /*%< * Attach to the request manager. dns_requestmgr_shutdown() must not * have been called on 'source' prior to calling dns_requestmgr_attach(). @@ -137,8 +141,12 @@ dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp); *\li 'targetp' to be non NULL and '*targetp' to be NULL. */ +#define dns_requestmgr_detach(requestmgrp) \ + dns__requestmgr_detach(requestmgrp, __FILE__, __LINE__, __func__) + void -dns_requestmgr_detach(dns_requestmgr_t **requestmgrp); +dns__requestmgr_detach(dns_requestmgr_t **requestmgrp, const char *file, + unsigned int line, const char *func); /*%< * Detach from the given requestmgr. If this is the final detach * requestmgr will be destroyed. dns_requestmgr_shutdown() must diff --git a/lib/dns/request.c b/lib/dns/request.c index fcb378ed6a..7d2b938fa3 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -32,6 +32,8 @@ #include #include +#define REQ_TRACE + #define REQUESTMGR_MAGIC ISC_MAGIC('R', 'q', 'u', 'M') #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC) @@ -44,17 +46,17 @@ typedef ISC_LIST(dns_request_t) dns_requestlist_t; struct dns_requestmgr { unsigned int magic; + isc_refcount_t references; + isc_mutex_t lock; isc_mem_t *mctx; /* locked */ - int32_t eref; - int32_t iref; isc_taskmgr_t *taskmgr; dns_dispatchmgr_t *dispatchmgr; dns_dispatch_t *dispatchv4; dns_dispatch_t *dispatchv6; - bool exiting; + atomic_bool exiting; isc_eventlist_t whenshutdown; unsigned int hash; isc_mutex_t locks[DNS_REQUEST_NLOCKS]; @@ -63,6 +65,8 @@ struct dns_requestmgr { struct dns_request { unsigned int magic; + isc_refcount_t references; + unsigned int hash; isc_mem_t *mctx; int32_t flags; @@ -97,8 +101,6 @@ struct dns_request { static void mgr_destroy(dns_requestmgr_t *requestmgr); -static void -mgr_shutdown(dns_requestmgr_t *requestmgr); static unsigned int mgr_gethash(dns_requestmgr_t *requestmgr); static void @@ -118,12 +120,23 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void +__req_attach(dns_request_t *source, dns_request_t **targetp, const char *file, + unsigned int line, const char *func); +static void +__req_detach(dns_request_t **requestp, const char *file, unsigned int line, + const char *func); +static void req_destroy(dns_request_t *request); static void req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); void request_cancel(dns_request_t *request); +#define req_attach(source, targetp) \ + __req_attach(source, targetp, __FILE__, __LINE__, __func__) +#define req_detach(requestp) \ + __req_detach(requestp, __FILE__, __LINE__, __func__) + /*** *** Public ***/ @@ -171,11 +184,10 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, } requestmgr->mctx = NULL; isc_mem_attach(mctx, &requestmgr->mctx); - requestmgr->eref = 1; /* implicit attach */ - requestmgr->iref = 0; + isc_refcount_init(&requestmgr->references, 1); ISC_LIST_INIT(requestmgr->whenshutdown); ISC_LIST_INIT(requestmgr->requests); - requestmgr->exiting = false; + atomic_init(&requestmgr->exiting, false); requestmgr->hash = 0; requestmgr->magic = REQUESTMGR_MAGIC; @@ -201,7 +213,7 @@ dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task, LOCK(&requestmgr->lock); - if (requestmgr->exiting) { + if (atomic_load_acquire(&requestmgr->exiting)) { /* * We're already shutdown. Send the event. */ @@ -218,126 +230,95 @@ dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task, void dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) { + dns_request_t *request; + REQUIRE(VALID_REQUESTMGR(requestmgr)); req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr); - LOCK(&requestmgr->lock); - mgr_shutdown(requestmgr); - UNLOCK(&requestmgr->lock); -} - -static void -mgr_shutdown(dns_requestmgr_t *requestmgr) { - dns_request_t *request; - - if (!requestmgr->exiting) { - requestmgr->exiting = true; - for (request = ISC_LIST_HEAD(requestmgr->requests); - request != NULL; request = ISC_LIST_NEXT(request, link)) - { - dns_request_cancel(request); - } - if (requestmgr->iref == 0) { - INSIST(ISC_LIST_EMPTY(requestmgr->requests)); - send_shutdown_events(requestmgr); - } + if (!atomic_compare_exchange_strong(&requestmgr->exiting, + &(bool){ false }, true)) + { + return; } -} - -static void -requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { - /* - * Locked by caller. - */ - - REQUIRE(VALID_REQUESTMGR(source)); - REQUIRE(targetp != NULL && *targetp == NULL); - - REQUIRE(!source->exiting); - - source->iref++; - *targetp = source; - - req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d", - source, source->eref, source->iref); -} - -static void -requestmgr_detach(dns_requestmgr_t **requestmgrp) { - dns_requestmgr_t *requestmgr; - bool need_destroy = false; - - REQUIRE(requestmgrp != NULL); - requestmgr = *requestmgrp; - *requestmgrp = NULL; - REQUIRE(VALID_REQUESTMGR(requestmgr)); LOCK(&requestmgr->lock); - INSIST(requestmgr->iref > 0); - requestmgr->iref--; + for (request = ISC_LIST_HEAD(requestmgr->requests); request != NULL; + request = ISC_LIST_NEXT(request, link)) + { + dns_request_cancel(request); + } - req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d", - requestmgr, requestmgr->eref, requestmgr->iref); - - if (requestmgr->iref == 0 && requestmgr->exiting) { - INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL); + if (ISC_LIST_EMPTY(requestmgr->requests)) { send_shutdown_events(requestmgr); - if (requestmgr->eref == 0) { - need_destroy = true; - } } - UNLOCK(&requestmgr->lock); - if (need_destroy) { - mgr_destroy(requestmgr); - } + UNLOCK(&requestmgr->lock); } void -dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { +dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, + const char *file, unsigned int line, const char *func) { + uint_fast32_t ref; + REQUIRE(VALID_REQUESTMGR(source)); REQUIRE(targetp != NULL && *targetp == NULL); - REQUIRE(!source->exiting); - LOCK(&source->lock); - source->eref++; + REQUIRE(!atomic_load_acquire(&source->exiting)); + + ref = isc_refcount_increment(&source->references); + +#ifdef REQ_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, source, targetp, ref + 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* REQ_TRACE */ + + req_log(ISC_LOG_DEBUG(3), + "dns_requestmgr_attach: %p: references = %" PRIuFAST32, source, + ref + 1); + *targetp = source; - UNLOCK(&source->lock); - - req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d", - source, source->eref, source->iref); } void -dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) { - dns_requestmgr_t *requestmgr; - bool need_destroy = false; +dns__requestmgr_detach(dns_requestmgr_t **requestmgrp, const char *file, + unsigned int line, const char *func) { + dns_requestmgr_t *requestmgr = NULL; + uint_fast32_t ref; + + REQUIRE(requestmgrp != NULL && VALID_REQUESTMGR(*requestmgrp)); - REQUIRE(requestmgrp != NULL); requestmgr = *requestmgrp; *requestmgrp = NULL; - REQUIRE(VALID_REQUESTMGR(requestmgr)); - LOCK(&requestmgr->lock); - INSIST(requestmgr->eref > 0); - requestmgr->eref--; + ref = isc_refcount_decrement(&requestmgr->references); - req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d", - requestmgr, requestmgr->eref, requestmgr->iref); +#ifdef REQ_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, requestmgr, requestmgrp, ref - 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* REQ_TRACE */ - if (requestmgr->eref == 0 && requestmgr->iref == 0) { - INSIST(requestmgr->exiting && - ISC_LIST_HEAD(requestmgr->requests) == NULL); - need_destroy = true; - } - UNLOCK(&requestmgr->lock); + req_log(ISC_LOG_DEBUG(3), + "dns_requestmgr_detach: %p: references = %" PRIuFAST32, + requestmgr, ref - 1); - if (need_destroy) { + if (ref == 1) { + INSIST(ISC_LIST_EMPTY(requestmgr->requests)); mgr_destroy(requestmgr); } } +/* FIXME */ static void send_shutdown_events(dns_requestmgr_t *requestmgr) { isc_event_t *event, *next_event; @@ -365,8 +346,7 @@ mgr_destroy(dns_requestmgr_t *requestmgr) { req_log(ISC_LOG_DEBUG(3), "mgr_destroy"); - REQUIRE(requestmgr->eref == 0); - REQUIRE(requestmgr->iref == 0); + isc_refcount_destroy(&requestmgr->references); isc_mutex_destroy(&requestmgr->lock); for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { @@ -409,12 +389,13 @@ req_send(dns_request_t *request) { static isc_result_t new_request(isc_mem_t *mctx, dns_request_t **requestp) { - dns_request_t *request; + dns_request_t *request = NULL; request = isc_mem_get(mctx, sizeof(*request)); *request = (dns_request_t){ .dscp = -1 }; ISC_LINK_INIT(request, link); + isc_refcount_init(&request->references, 1); isc_mem_attach(mctx, &request->mctx); request->magic = REQUEST_MAGIC; @@ -426,25 +407,25 @@ static bool isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) { dns_acl_t *blackhole; isc_netaddr_t netaddr; - int match; - bool drop = false; char netaddrstr[ISC_NETADDR_FORMATSIZE]; + int match; + isc_result_t result; blackhole = dns_dispatchmgr_getblackhole(dispatchmgr); - if (blackhole != NULL) { - isc_netaddr_fromsockaddr(&netaddr, destaddr); - if (dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, - NULL) == ISC_R_SUCCESS && - match > 0) - { - drop = true; - } + if (blackhole == NULL) { + return (false); } - if (drop) { - isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr)); - req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr); + + isc_netaddr_fromsockaddr(&netaddr, destaddr); + result = dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, NULL); + if (result != ISC_R_SUCCESS || match == 0) { + return (false); } - return (drop); + + isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr)); + req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr); + + return (true); } static isc_result_t @@ -553,6 +534,10 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, req_log(ISC_LOG_DEBUG(3), "dns_request_createraw"); + if (atomic_load_acquire(&requestmgr->exiting)) { + return (ISC_R_SHUTTINGDOWN); + } + if (isblackholed(requestmgr->dispatchmgr, destaddr)) { return (DNS_R_BLACKHOLED); } @@ -593,6 +578,12 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, request->timeout = udptimeout * 1000; } + isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); + result = isc_buffer_copyregion(request->query, &r); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + again: result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr, dscp, &connected, &request->dispatch); @@ -605,6 +596,9 @@ again: dispopt |= DNS_DISPATCHOPT_FIXEDID; } + dns_request_t *tmp = NULL; + req_attach(request, &tmp); + result = dns_dispatch_addresponse( request->dispatch, dispopt, request->timeout, destaddr, task, req_connected, req_senddone, req_response, req_timeout, request, @@ -619,24 +613,13 @@ again: goto cleanup; } - isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); - result = isc_buffer_copyregion(request->query, &r); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - /* Add message ID. */ isc_buffer_usedregion(request->query, &r); r.base[0] = (id >> 8) & 0xff; r.base[1] = id & 0xff; LOCK(&requestmgr->lock); - if (requestmgr->exiting) { - UNLOCK(&requestmgr->lock); - result = ISC_R_SHUTTINGDOWN; - goto cleanup; - } - requestmgr_attach(requestmgr, &request->requestmgr); + dns_requestmgr_attach(requestmgr, &request->requestmgr); request->hash = mgr_gethash(requestmgr); ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); @@ -665,7 +648,7 @@ cleanup: if (tclone != NULL) { isc_task_detach(&tclone); } - req_destroy(request); + req_detach(&request); req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s", dns_result_totext(result)); return (result); @@ -697,7 +680,6 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, isc_mem_t *mctx; dns_messageid_t id; bool tcp = false; - bool settsigkey = true; bool connected = false; REQUIRE(VALID_REQUESTMGR(requestmgr)); @@ -712,6 +694,10 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, req_log(ISC_LOG_DEBUG(3), "dns_request_createvia"); + if (atomic_load_acquire(&requestmgr->exiting)) { + return (ISC_R_SHUTTINGDOWN); + } + if (srcaddr != NULL && isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr)) { return (ISC_R_FAMILYMISMATCH); @@ -740,7 +726,11 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, dns_tsigkey_attach(key, &request->tsigkey); } -use_tcp: + result = dns_message_settsigkey(message, request->tsigkey); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + if ((options & DNS_REQUESTOPT_TCP) != 0) { tcp = true; request->timeout = timeout * 1000; @@ -754,12 +744,16 @@ use_tcp: request->timeout = udptimeout * 1000; } +use_tcp: result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr, dscp, &connected, &request->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } + dns_request_t *tmp = NULL; + req_attach(request, &tmp); + result = dns_dispatch_addresponse( request->dispatch, 0, request->timeout, destaddr, task, req_connected, req_senddone, req_response, req_timeout, request, @@ -769,14 +763,8 @@ use_tcp: } message->id = id; - if (settsigkey) { - result = dns_message_settsigkey(message, request->tsigkey); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - } result = req_render(message, &request->query, options, mctx); - if (result == DNS_R_USETCP && (options & DNS_REQUESTOPT_TCP) == 0) { + if (result == DNS_R_USETCP && !tcp) { /* * Try again using TCP. */ @@ -784,7 +772,7 @@ use_tcp: dns_dispatch_removeresponse(&request->dispentry, NULL); dns_dispatch_detach(&request->dispatch); options |= DNS_REQUESTOPT_TCP; - settsigkey = false; + tcp = true; goto use_tcp; } if (result != ISC_R_SUCCESS) { @@ -797,12 +785,7 @@ use_tcp: } LOCK(&requestmgr->lock); - if (requestmgr->exiting) { - UNLOCK(&requestmgr->lock); - result = ISC_R_SHUTTINGDOWN; - goto cleanup; - } - requestmgr_attach(requestmgr, &request->requestmgr); + dns_requestmgr_attach(requestmgr, &request->requestmgr); request->hash = mgr_gethash(requestmgr); ISC_LIST_APPEND(requestmgr->requests, request, link); UNLOCK(&requestmgr->lock); @@ -831,7 +814,7 @@ cleanup: if (tclone != NULL) { isc_task_detach(&tclone); } - req_destroy(request); + req_detach(&request); req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s", dns_result_totext(result)); return (result); @@ -956,9 +939,7 @@ request_cancel(dns_request_t *request) { request->flags &= ~DNS_REQUEST_F_CONNECTING; if (request->dispentry != NULL) { - dns_dispatch_cancel(NULL, request->dispentry, - DNS_REQUEST_SENDING(request), - DNS_REQUEST_CONNECTING(request)); + dns_dispatch_cancel(request->dispentry); dns_dispatch_removeresponse(&request->dispentry, NULL); } @@ -1047,7 +1028,7 @@ dns_request_destroy(dns_request_t **requestp) { INSIST(request->dispentry == NULL); INSIST(request->dispatch == NULL); - req_destroy(request); + req_detach(&request); } /*** @@ -1059,15 +1040,17 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { UNUSED(handle); + req_log(ISC_LOG_DEBUG(3), "req_connected: request %p: %s", request, + isc_result_totext(eresult)); + if (eresult == ISC_R_CANCELED) { + req_detach(&request); return; } REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_CONNECTING(request)); - req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request); - LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_CONNECTING; @@ -1084,6 +1067,8 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { send_if_done(request, ISC_R_CANCELED); } UNLOCK(&request->requestmgr->locks[request->hash]); + + req_detach(&request); } static void @@ -1195,12 +1180,76 @@ req_sendevent(dns_request_t *request, isc_result_t result) { isc_task_sendanddetach(&task, (isc_event_t **)&request->event); } +static void +__req_attach(dns_request_t *source, dns_request_t **targetp, const char *file, + unsigned int line, const char *func) { + uint_fast32_t ref; + + REQUIRE(VALID_REQUEST(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + ref = isc_refcount_increment(&source->references); + +#ifdef REQ_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, source, targetp, ref + 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* REQ_TRACE */ + + *targetp = source; +} + +static void +__req_detach(dns_request_t **requestp, const char *file, unsigned int line, + const char *func) { + dns_request_t *request = NULL; + uint_fast32_t ref; + + REQUIRE(requestp != NULL && VALID_REQUEST(*requestp)); + + request = *requestp; + *requestp = NULL; + + ref = isc_refcount_decrement(&request->references); + +#ifdef REQ_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, request, requestp, ref - 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* REQ_TRACE */ + + if (request->requestmgr != NULL && + atomic_load_acquire(&request->requestmgr->exiting)) + { + /* We are shutting down and this was last request */ + LOCK(&request->requestmgr->lock); + if (ISC_LIST_EMPTY(request->requestmgr->requests)) { + send_shutdown_events(request->requestmgr); + } + UNLOCK(&request->requestmgr->lock); + } + + if (ref == 1) { + req_destroy(request); + } +} + static void req_destroy(dns_request_t *request) { REQUIRE(VALID_REQUEST(request)); req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request); + isc_refcount_destroy(&request->references); + request->magic = 0; if (request->query != NULL) { isc_buffer_free(&request->query); @@ -1224,7 +1273,7 @@ req_destroy(dns_request_t *request) { dns_tsigkey_detach(&request->tsigkey); } if (request->requestmgr != NULL) { - requestmgr_detach(&request->requestmgr); + dns_requestmgr_detach(&request->requestmgr); } isc_mem_putanddetach(&request->mctx, request, sizeof(*request)); } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index d140628fb0..2a65090906 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -61,6 +61,11 @@ #include #include #include + +#define RESOLVER_TRACE 1 + +#define WANT_QUERYTRACE 1 + #ifdef WANT_QUERYTRACE #define RTRACE(m) \ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, \ @@ -222,6 +227,7 @@ typedef struct fetchctx fetchctx_t; typedef struct query { /* Locked by task event serialization. */ unsigned int magic; + isc_refcount_t references; fetchctx_t *fctx; dns_message_t *rmessage; isc_mem_t *mctx; @@ -240,8 +246,6 @@ typedef struct query { int ednsversion; unsigned int options; isc_sockeventattr_t attributes; - unsigned int sends; - unsigned int connects; unsigned int udpsize; unsigned char data[512]; } resquery_t; @@ -543,7 +547,7 @@ struct dns_resolver { /* Locked by lock. */ isc_eventlist_t whenshutdown; - unsigned int activebuckets; + isc_refcount_t activebuckets; unsigned int spillat; /* clients-per-query */ dns_badcache_t *badcache; /* Bad cache. */ @@ -824,7 +828,7 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, static void rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo); -static void +static isc_result_t rctx_next(respctx_t *rctx); static void @@ -1122,19 +1126,27 @@ munge: } static inline void -resquery_destroy(resquery_t **queryp) { +resquery_destroy(resquery_t *query) { dns_resolver_t *res; bool empty; - resquery_t *query; fetchctx_t *fctx; unsigned int bucket; - REQUIRE(queryp != NULL); - query = *queryp; - *queryp = NULL; REQUIRE(!ISC_LINK_LINKED(query, link)); - INSIST(query->dispatch == NULL); + if (query->tsig != NULL) { + isc_buffer_free(&query->tsig); + } + + if (query->tsigkey != NULL) { + dns_tsigkey_detach(&query->tsigkey); + } + + if (query->dispatch != NULL) { + dns_dispatch_detach(&query->dispatch); + } + + isc_refcount_destroy(&query->references); fctx = query->fctx; res = fctx->res; @@ -1157,6 +1169,61 @@ resquery_destroy(resquery_t **queryp) { } } +#define resquery_attach(s, t) \ + __resquery_attach(s, t, __FILE__, __LINE__, __func__) + +static void __attribute__((unused)) +__resquery_attach(resquery_t *source, resquery_t **targetp, const char *file, + unsigned int line, const char *func) { + uint_fast32_t ref; + + REQUIRE(VALID_QUERY(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + ref = isc_refcount_increment(&source->references); + +#ifdef RESOLVER_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, source, targetp, ref + 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); + UNUSED(ref); +#endif /* RESOLVER_TRACE */ + + *targetp = source; +} + +#define resquery_detach(q) __resquery_detach(q, __FILE__, __LINE__, __func__) + +static void +__resquery_detach(resquery_t **queryp, const char *file, unsigned int line, + const char *func) { + uint_fast32_t ref; + resquery_t *query = NULL; + + REQUIRE(queryp != NULL && VALID_QUERY(*queryp)); + + query = *queryp; + *queryp = NULL; + + ref = isc_refcount_decrement(&query->references); + +#ifdef RESOLVER_TRACE + fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, + line, __func__, query, queryp, ref - 1); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); +#endif /* RESOLVER_TRACE */ + + if (ref == 1) { + resquery_destroy(query); + } +} + /*% * Update EDNS statistics for a server after not getting a response to a UDP * query sent to it. @@ -1176,23 +1243,36 @@ update_edns_stats(resquery_t *query) { } } +#define fctx_cancelquery(q, d, f, n, a) \ + __fctx_cancelquery(q, d, f, n, a, __FILE__, __LINE__, __func__) + static void -fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, - isc_time_t *finish, bool no_response, bool age_untried) { +__fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, + isc_time_t *finish, bool no_response, bool age_untried, + const char *file, unsigned int line, const char *func) { fetchctx_t *fctx = NULL; - resquery_t *query = NULL; unsigned int rtt, rttms; unsigned int factor; dns_adbfind_t *find = NULL; dns_adbaddrinfo_t *addrinfo; isc_stdtime_t now; - query = *queryp; fctx = query->fctx; +#ifdef RESOLVER_TRACE + fprintf(stderr, "%s:%s:%u:%s(query = %p, ...)\n", func, file, line, + __func__, query); +#else + UNUSED(func); + UNUSED(file); + UNUSED(line); +#endif /* RESOLVER_TRACE */ + FCTXTRACE("cancelquery"); - REQUIRE(!RESQUERY_CANCELED(query)); + if (RESQUERY_CANCELED(query)) { + return; + } query->attributes |= RESQUERY_ATTR_CANCELED; @@ -1352,16 +1432,14 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, } /* - * Check for any outstanding socket events. If they exist, cancel - * them and let the event handlers finish the cleanup. (XXX: - * Currently the resolver, rather than dispatch, tracks whether - * it's sending or connecting; this will be moved into dispatch - * later.) + * Check for any outstanding socket events. If they exist, + * cancel them and let the event handlers finish the cleanup. + * (XXX: Currently the resolver, rather than dispatch, tracks + * whether it's sending or connecting; this will be moved into + * dispatch later.) */ - dns_dispatch_cancel(query->dispatch, query->dispentry, - RESQUERY_SENDING(query), - RESQUERY_CONNECTING(query)); if (query->dispentry != NULL) { + dns_dispatch_cancel(query->dispentry); dns_dispatch_removeresponse(&query->dispentry, deventp); } @@ -1369,24 +1447,8 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, ISC_LIST_UNLINK(fctx->queries, query, link); } - if (query->tsig != NULL) { - isc_buffer_free(&query->tsig); - } - - if (query->tsigkey != NULL) { - dns_tsigkey_detach(&query->tsigkey); - } - - if (query->dispatch != NULL) { - dns_dispatch_detach(&query->dispatch); - } - - if (!(RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query))) { - /* - * It's safe to destroy the query now. - */ - resquery_destroy(&query); - } + /* This is the final detach matching the "init" */ + resquery_detach(&query); } static void @@ -1398,7 +1460,7 @@ fctx_cancelqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; query = next_query) { next_query = ISC_LIST_NEXT(query, link); - fctx_cancelquery(&query, NULL, NULL, no_response, age_untried); + fctx_cancelquery(query, NULL, NULL, no_response, age_untried); } } @@ -1734,61 +1796,53 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { static void resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { resquery_t *query = (resquery_t *)arg; - bool destroy_query = false; fetchctx_t *fctx = NULL; QTRACE("senddone"); UNUSED(handle); - INSIST(RESQUERY_SENDING(query)); - - query->sends--; - fctx = query->fctx; if (RESQUERY_CANCELED(query)) { - if (query->sends == 0 && query->connects == 0) { - destroy_query = true; - } - } else { - switch (eresult) { - case ISC_R_SUCCESS: - break; - - case ISC_R_HOSTUNREACH: - case ISC_R_NETUNREACH: - case ISC_R_NOPERM: - case ISC_R_ADDRNOTAVAIL: - case ISC_R_CONNREFUSED: - FCTXTRACE3("query canceled in resquery_senddone(): " - "no route to host; no response", - eresult); - - /* - * No route to remote. - */ - add_bad(fctx, query->rmessage, query->addrinfo, eresult, - badns_unreachable); - fctx_cancelquery(&query, NULL, NULL, true, false); - - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - fctx_try(fctx, true, false); - break; - - default: - FCTXTRACE3("query canceled in resquery_senddone() " - "due to unexpected result; responding", - eresult); - fctx_cancelquery(&query, NULL, NULL, false, false); - fctx_done(fctx, eresult, __LINE__); - break; - } + goto detach; } - if (destroy_query) { - resquery_destroy(&query); + switch (eresult) { + case ISC_R_SUCCESS: + /* Don't detach from resquery */ + return; + + case ISC_R_HOSTUNREACH: + case ISC_R_NETUNREACH: + case ISC_R_NOPERM: + case ISC_R_ADDRNOTAVAIL: + case ISC_R_CONNREFUSED: + FCTXTRACE3("query canceled in resquery_senddone(): " + "no route to host; no response", + eresult); + + /* + * No route to remote. + */ + add_bad(fctx, query->rmessage, query->addrinfo, eresult, + badns_unreachable); + fctx_cancelquery(query, NULL, NULL, true, false); + + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + fctx_try(fctx, true, false); + break; + default: + FCTXTRACE3("query canceled in resquery_senddone() " + "due to unexpected result; responding", + eresult); + fctx_cancelquery(query, NULL, NULL, false, false); + fctx_done(fctx, eresult, __LINE__); + break; } + +detach: + resquery_detach(&query); } static inline isc_result_t @@ -1961,9 +2015,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, srtt = addrinfo->srtt; /* - * Allow an additional second for the kernel to resend the SYN (or - * SYN without ECN in the case of stupid firewalls blocking ECN - * negotiation) over the current RTT estimate. + * Allow an additional second for the kernel to resend the SYN + * (or SYN without ECN in the case of stupid firewalls blocking + * ECN negotiation) over the current RTT estimate. */ if ((options & DNS_FETCHOPT_TCP) != 0) { srtt += US_PER_SEC; @@ -1992,9 +2046,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, .addrinfo = addrinfo, .dispatchmgr = res->dispatchmgr }; + isc_refcount_init(&query->references, 1); + /* - * Note that the caller MUST guarantee that 'addrinfo' will remain - * valid until this query is canceled. + * Note that the caller MUST guarantee that 'addrinfo' will + * remain valid until this query is canceled. */ dns_message_create(fctx->mctx, DNS_MESSAGE_INTENTPARSE, @@ -2112,9 +2168,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, /* * We should always have a valid dispatcher here. If we * don't support a protocol family, then its dispatcher - * will be NULL, but we shouldn't be finding addresses for - * protocol types we don't support, so the dispatcher - * we found should never be NULL. + * will be NULL, but we shouldn't be finding addresses + * for protocol types we don't support, so the + * dispatcher we found should never be NULL. */ INSIST(query->dispatch != NULL); } @@ -2137,6 +2193,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, fctx->nqueries++; UNLOCK(&res->buckets[fctx->bucketnum].lock); + resquery_t *tmp = NULL; + resquery_attach(query, &tmp); + /* Set up the dispatch and set the query ID */ result = dns_dispatch_addresponse( query->dispatch, 0, isc_interval_ms(&fctx->interval), @@ -2148,8 +2207,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } /* Connect the socket */ - query->connects++; fctx_increference(fctx); + result = dns_dispatch_connect(query->dispentry); return (result); @@ -2159,11 +2218,10 @@ cleanup_dispatch: } cleanup_query: - if (query->connects == 0) { - query->magic = 0; - dns_message_detach(&query->rmessage); - isc_mem_put(fctx->mctx, query, sizeof(*query)); - } + + query->magic = 0; + dns_message_detach(&query->rmessage); + isc_mem_put(fctx->mctx, query, sizeof(*query)); return (result); } @@ -2271,7 +2329,8 @@ compute_cc(const resquery_t *query, uint8_t *cookie, const size_t len) { INSIST(len >= CLIENT_COOKIE_SIZE); STATIC_ASSERT(sizeof(query->fctx->res->view->secret) >= ISC_SIPHASH24_KEY_LENGTH, - "The view->secret size can't fit SipHash 2-4 key length"); + "The view->secret size can't fit SipHash 2-4 key " + "length"); uint8_t buf[16] ISC_NONSTRING = { 0 }; size_t buflen = add_serveraddr(buf, sizeof(buf), query); @@ -2361,8 +2420,8 @@ resquery_send(resquery_t *query) { qrdataset = NULL; /* - * Set RD if the client has requested that we do a recursive query, - * or if we're sending to a forwarder. + * Set RD if the client has requested that we do a recursive + * query, or if we're sending to a forwarder. */ if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 || ISFORWARDER(query->addrinfo)) @@ -2426,8 +2485,8 @@ resquery_send(resquery_t *query) { (void)dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer); /* - * The ADB does not know about servers with "edns no". Check this, - * and then inform the ADB for future use. + * The ADB does not know about servers with "edns no". Check + * this, and then inform the ADB for future use. */ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 && peer != NULL && @@ -2449,12 +2508,13 @@ resquery_send(resquery_t *query) { struct tried *tried; /* - * If this is the first timeout for this server in this fetch - * context, try setting EDNS UDP buffer size to the largest UDP - * response size we have seen from this server so far. + * If this is the first timeout for this server in this + * fetch context, try setting EDNS UDP buffer size to + * the largest UDP response size we have seen from this + * server so far. * - * If this server has already timed out twice or more in this - * fetch context, force TCP. + * If this server has already timed out twice or more in + * this fetch context, force TCP. */ if ((tried = triededns(fctx, sockaddr)) != NULL) { if (tried->count == 1U) { @@ -2468,8 +2528,8 @@ resquery_send(resquery_t *query) { fctx->timeout = false; /* - * Use EDNS0, unless the caller doesn't want it, or we know that the - * remote server doesn't like it. + * Use EDNS0, unless the caller doesn't want it, or we know that + * the remote server doesn't like it. */ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) { @@ -2483,26 +2543,26 @@ resquery_send(resquery_t *query) { uint16_t padding = 0; /* - * Set the default UDP size to what was configured as - * 'edns-buffer-size' + * Set the default UDP size to what was + * configured as 'edns-buffer-size' */ udpsize = res->udpsize; /* - * This server timed out for the first time in this - * fetch context and we received a response from it - * before (either in this fetch context or in a - * different one). Set 'udpsize' to the size of the - * largest UDP response we have received from this - * server so far. + * This server timed out for the first time in + * this fetch context and we received a response + * from it before (either in this fetch context + * or in a different one). Set 'udpsize' to the + * size of the largest UDP response we have + * received from this server so far. */ if (hint != 0U) { udpsize = hint; } /* - * If a fixed EDNS UDP buffer size is configured for - * this server, make sure we obey that. + * If a fixed EDNS UDP buffer size is configured + * for this server, make sure we obey that. */ if (peer != NULL) { (void)dns_peer_getudpsize(peer, &peerudpsize); @@ -2516,7 +2576,8 @@ resquery_send(resquery_t *query) { version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT; } - /* Request NSID/COOKIE/VERSION for current peer? */ + /* Request NSID/COOKIE/VERSION for current peer? + */ if (peer != NULL) { uint8_t ednsversion; (void)dns_peer_getrequestnsid(peer, &reqnsid); @@ -2576,7 +2637,8 @@ resquery_send(resquery_t *query) { ednsopt++; } - /* Add PAD for current peer? Require TCP for now */ + /* Add PAD for current peer? Require TCP for now + */ if ((peer != NULL) && tcp) { (void)dns_peer_getpadding(peer, &padding); } @@ -2595,9 +2657,9 @@ resquery_send(resquery_t *query) { query->options |= DNS_FETCHOPT_WANTNSID; } else if (result != ISC_R_SUCCESS) { /* - * We couldn't add the OPT, but we'll press on. - * We're not using EDNS0, so set the NOEDNS0 - * bit. + * We couldn't add the OPT, but we'll + * press on. We're not using EDNS0, so + * set the NOEDNS0 bit. */ query->options |= DNS_FETCHOPT_NOEDNS0; query->ednsversion = -1; @@ -2606,8 +2668,8 @@ resquery_send(resquery_t *query) { } else { /* * We know this server doesn't like EDNS0, so we - * won't use it. Set the NOEDNS0 bit since we're - * not using EDNS0. + * won't use it. Set the NOEDNS0 bit since + * we're not using EDNS0. */ query->options |= DNS_FETCHOPT_NOEDNS0; query->ednsversion = -1; @@ -2622,7 +2684,8 @@ resquery_send(resquery_t *query) { query->udpsize = udpsize; /* - * If we need EDNS0 to do this query and aren't using it, we lose. + * If we need EDNS0 to do this query and aren't using it, we + * lose. */ if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) { result = DNS_R_SERVFAIL; @@ -2704,7 +2767,6 @@ resquery_send(resquery_t *query) { isc_buffer_usedregion(&buffer, &r); dns_dispatch_send(query->dispentry, &r, query->dscp); - query->sends++; QTRACE("sent"); @@ -2755,6 +2817,7 @@ cleanup_temps: static void resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { resquery_t *query = (resquery_t *)arg; + resquery_t *connquery = query; isc_result_t result; fetchctx_t *fctx = NULL; dns_resolver_t *res = NULL; @@ -2768,7 +2831,6 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { UNUSED(handle); - query->connects--; fctx = query->fctx; res = fctx->res; @@ -2779,78 +2841,77 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } if (RESQUERY_CANCELED(query)) { + goto detach; + } + + switch (eresult) { + case ISC_R_SUCCESS: /* - * This query was canceled while the connect() was - * in progress. + * We are connected. Update the dispatcher and + * send the query. */ - resquery_destroy(&query); - } else { - switch (eresult) { - case ISC_R_SUCCESS: - /* - * We are connected. Update the dispatcher and - * send the query. - */ - dns_dispatch_changeattributes( - query->dispatch, DNS_DISPATCHATTR_CONNECTED, - DNS_DISPATCHATTR_CONNECTED); + dns_dispatch_changeattributes(query->dispatch, + DNS_DISPATCHATTR_CONNECTED, + DNS_DISPATCHATTR_CONNECTED); - result = resquery_send(query); - if (result != ISC_R_SUCCESS) { - FCTXTRACE("query canceled: " - "resquery_send() failed; responding"); + result = resquery_send(query); + if (result != ISC_R_SUCCESS) { + FCTXTRACE("query canceled: " + "resquery_send() failed; " + "responding"); - fctx_cancelquery(&query, NULL, NULL, false, - 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: - case ISC_R_HOSTUNREACH: - case ISC_R_CONNREFUSED: - case ISC_R_NOPERM: - case ISC_R_ADDRNOTAVAIL: - case ISC_R_CONNECTIONRESET: - case ISC_R_TIMEDOUT: - FCTXTRACE3("query canceled in resquery_connected(): " - "no route to host; no response", - 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, eresult, - badns_unreachable); - fctx_cancelquery(&query, NULL, NULL, true, false); - - FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); - fctx_try(fctx, true, false); - break; - - default: - FCTXTRACE3("query canceled in resquery_connected() " - "due to unexpected result; responding", - eresult); - - fctx_cancelquery(&query, NULL, NULL, false, false); - fctx_done(fctx, eresult, __LINE__); + fctx_cancelquery(query, NULL, NULL, false, 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: + case ISC_R_HOSTUNREACH: + case ISC_R_CONNREFUSED: + case ISC_R_NOPERM: + case ISC_R_ADDRNOTAVAIL: + case ISC_R_CONNECTIONRESET: + case ISC_R_TIMEDOUT: + FCTXTRACE3("query canceled in " + "resquery_connected(): " + "no route to host; no response", + 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, eresult, + badns_unreachable); + fctx_cancelquery(query, NULL, NULL, true, false); + + FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); + fctx_try(fctx, true, false); + break; + + default: + FCTXTRACE3("query canceled in " + "resquery_connected() " + "due to unexpected result; responding", + eresult); + + fctx_cancelquery(query, NULL, NULL, false, false); + fctx_done(fctx, eresult, __LINE__); } LOCK(&res->buckets[bucketnum].lock); @@ -2859,6 +2920,9 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { if (bucket_empty) { empty_bucket(res); } + +detach: + resquery_detach(&connquery); } static void @@ -2899,9 +2963,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { fctx->findfail++; if (fctx->pending == 0) { /* - * We've got nothing else to wait for and don't - * know the answer. There's nothing to do but - * fail the fctx. + * We've got nothing else to wait for + * and don't know the answer. There's + * nothing to do but fail the fctx. */ FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); want_done = true; @@ -2923,7 +2987,8 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { if (want_try) { fctx_try(fctx, true, false); } else if (want_done) { - FCTXTRACE("fetch failed in finddone(); return ISC_R_FAILURE"); + FCTXTRACE("fetch failed in finddone(); return " + "ISC_R_FAILURE"); fctx_done(fctx, ISC_R_FAILURE, __LINE__); } else if (dodestroy) { fctx_destroy(fctx); @@ -3057,8 +3122,8 @@ add_bad(fetchctx_t *fctx, dns_message_t *rmessage, dns_adbaddrinfo_t *addrinfo, break; /* counted as 'valfail' */ case badns_forwarder: /* - * We were called to prevent the given forwarder from - * being used again for this fetch context. + * We were called to prevent the given forwarder + * from being used again for this fetch context. */ break; } @@ -3304,9 +3369,11 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, fctx->quotacount++; /* quota exceeded */ } else if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) { - fctx->lamecount++; /* cached lame server */ + fctx->lamecount++; /* cached lame server + */ } else { - fctx->adberr++; /* unreachable server, etc. */ + fctx->adberr++; /* unreachable server, + etc. */ } /* @@ -3384,8 +3451,8 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { /* * If we have DNS_FETCHOPT_NOFORWARD set and forwarding policy * allows us to not forward - skip forwarders and go straight - * to NSes. This is currently used to make sure that priming query - * gets root servers' IP addresses in ADDITIONAL section. + * to NSes. This is currently used to make sure that priming + * query gets root servers' IP addresses in ADDITIONAL section. */ if ((fctx->options & DNS_FETCHOPT_NOFORWARD) != 0 && (fctx->fwdpolicy != dns_fwdpolicy_only)) @@ -3468,8 +3535,8 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { } /* - * If the forwarding policy is "only", we don't need the addresses - * of the nameservers. + * If the forwarding policy is "only", we don't need the + * addresses of the nameservers. */ if (fctx->fwdpolicy == dns_fwdpolicy_only) { goto out; @@ -3489,8 +3556,9 @@ normal_nses: * can use. * * We don't want to set this option all the time, since - * if fctx->restarts > 1, we've clearly been having trouble - * with the addresses we had, so getting more could help. + * if fctx->restarts > 1, we've clearly been having + * trouble with the addresses we had, so getting more + * could help. */ stdoptions |= DNS_ADBFIND_AVOIDFETCHES; } @@ -3598,8 +3666,9 @@ out: */ if (fctx->pending > 0) { /* - * We're fetching the addresses, but don't have any - * yet. Tell the caller to wait for an answer. + * We're fetching the addresses, but don't have + * any yet. Tell the caller to wait for an + * answer. */ result = DNS_R_WAIT; } else { @@ -3607,8 +3676,8 @@ out: isc_interval_t i; /* * We've lost completely. We don't know any - * addresses, and the ADB has told us it can't get - * them. + * addresses, and the ADB has told us it can't + * get them. */ FCTXTRACE("no addresses"); isc_interval_set(&i, DNS_RESOLVER_BADCACHETTL(fctx), 0); @@ -3626,8 +3695,8 @@ out: /* * If all of the addresses found were over the - * fetches-per-server quota, return the configured - * response. + * fetches-per-server quota, return the + * configured response. */ if (all_spilled) { result = res->quotaresp[dns_quotatype_server]; @@ -3636,8 +3705,8 @@ out: } } else { /* - * We've found some addresses. We might still be looking - * for more addresses. + * We've found some addresses. We might still be + * looking for more addresses. */ sort_finds(&fctx->finds, res->view->v6bias); sort_finds(&fctx->altfinds, 0); @@ -3958,9 +4027,9 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { if (fctx->minimized && !fctx->forwarding) { unsigned int options = fctx->options; /* - * Also clear DNS_FETCHOPT_TRYSTALE_ONTIMEOUT here, otherwise - * every query minimization step will activate the try-stale - * timer again. + * Also clear DNS_FETCHOPT_TRYSTALE_ONTIMEOUT here, + * otherwise every query minimization step will activate + * the try-stale timer again. */ options &= ~(DNS_FETCHOPT_QMINIMIZE | DNS_FETCHOPT_TRYSTALE_ONTIMEOUT); @@ -4119,7 +4188,8 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { fctx->qmin_labels = DNS_MAX_LABELS + 1; /* * We store the result. If we succeed in the end - * we'll issue a warning that the server is broken. + * we'll issue a warning that the server is + * broken. */ fctx->qmin_warning = result; } else { @@ -4140,9 +4210,9 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { &fctx->nameservers, NULL); /* - * DNS_R_NXDOMAIN here means we have not loaded the root zone mirror - * yet - but DNS_R_NXDOMAIN is not a valid return value when doing - * recursion, we need to patch it. + * DNS_R_NXDOMAIN here means we have not loaded the root zone + * mirror yet - but DNS_R_NXDOMAIN is not a valid return value + * when doing recursion, we need to patch it. */ if (result == DNS_R_NXDOMAIN) { result = DNS_R_SERVFAIL; @@ -4174,9 +4244,10 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { if (!fctx->minimized) { /* - * We have finished minimizing, but fctx->finds was filled at - * the beginning of the run - now we need to clear it before - * sending the final query to use proper nameservers. + * We have finished minimizing, but fctx->finds was + * filled at the beginning of the run - now we need to + * clear it before sending the final query to use proper + * nameservers. */ fctx_cancelqueries(fctx, false, false); fctx_cleanupall(fctx); @@ -4299,7 +4370,8 @@ fctx_shutdown(fetchctx_t *fctx) { isc_event_t *cevent; /* - * Start the shutdown process for fctx, if it isn't already underway. + * Start the shutdown process for fctx, if it isn't already + * underway. */ FCTXTRACE("shutdown"); @@ -4352,7 +4424,8 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { /* * Cancel all pending validators. Note that this must be done - * without the bucket lock held, since that could cause deadlock. + * without the bucket lock held, since that could cause + * deadlock. */ validator = ISC_LIST_HEAD(fctx->validators); while (validator != NULL) { @@ -4429,8 +4502,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { INSIST(fctx->state == fetchstate_init); if (fctx->want_shutdown) { /* - * We haven't started this fctx yet, and we've been requested - * to shut it down. + * We haven't started this fctx yet, and we've been + * requested to shut it down. */ FCTX_ATTR_SET(fctx, FCTX_ATTR_SHUTTINGDOWN); fctx->state = fetchstate_done; @@ -4456,8 +4529,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { */ fctx->state = fetchstate_active; /* - * Reset the control event for later use in shutting down - * the fctx. + * Reset the control event for later use in shutting + * down the fctx. */ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx, @@ -4491,8 +4564,8 @@ fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, /* * We store the task we're going to send this event to in the - * sender field. We'll make the fetch the sender when we actually - * send the event. + * sender field. We'll make the fetch the sender when we + * actually send the event. */ isc_task_attach(task, &tclone); event = (dns_fetchevent_t *)isc_event_allocate(fctx->res->mctx, tclone, @@ -4510,8 +4583,8 @@ fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, event->foundname = dns_fixedname_initname(&event->fname); /* - * Store the sigrdataset in the first event in case it is needed by - * any of the events. + * Store the sigrdataset in the first event in case it is needed + * by any of the events. */ if (event->sigrdataset != NULL) { ISC_LIST_PREPEND(fctx->events, event, ev_link); @@ -4567,7 +4640,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, size_t p; /* - * Caller must be holding the lock for bucket number 'bucketnum'. + * Caller must be holding the lock for bucket number + * 'bucketnum'. */ REQUIRE(fctxp != NULL && *fctxp == NULL); @@ -4682,8 +4756,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, /* * The caller didn't supply a query domain and - * nameservers, and we're not in forward-only mode, - * so find the best nameservers to use. + * nameservers, and we're not in forward-only + * mode, so find the best nameservers to use. */ if (dns_rdatatype_atparent(fctx->type)) { findoptions |= DNS_DBFIND_NOEXACT; @@ -4702,7 +4776,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, fctx->ns_ttl_ok = true; } else { /* - * We're in forward-only mode. Set the query domain. + * We're in forward-only mode. Set the query + * domain. */ dns_name_copy(fname, fctx->domain); dns_name_copy(fname, fctx->qmindcname); @@ -4757,15 +4832,15 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, } /* - * Default retry interval initialization. We set the interval now - * mostly so it won't be uninitialized. It will be set to the - * correct value before a query is issued. + * Default retry interval initialization. We set the interval + * now mostly so it won't be uninitialized. It will be set to + * the correct value before a query is issued. */ isc_interval_set(&fctx->interval, 2, 0); /* - * If stale answers are enabled, compute an expiration time after - * which stale data will be served, if the target RRset is + * If stale answers are enabled, compute an expiration time + * after which stale data will be served, if the target RRset is * available in cache. */ if ((options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) != 0) { @@ -5023,7 +5098,8 @@ clone_results(fetchctx_t *fctx) { for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = ISC_LIST_NEXT(event, ev_link)) { - /* This is the the head event; keep a pointer and move on */ + /* This is the the head event; keep a pointer and move + * on */ if (hevent == NULL) { hevent = ISC_LIST_HEAD(fctx->events); continue; @@ -5032,17 +5108,18 @@ clone_results(fetchctx_t *fctx) { if (event->ev_type == DNS_EVENT_TRYSTALE) { /* * We don't need to clone resulting data to this - * type of event, as its associated callback is only - * called when stale-answer-client-timeout triggers, - * and the logic in there doesn't expect any result - * as input, as it will itself lookup for stale data - * in cache to use as result, if any is available. + * type of event, as its associated callback is + * only called when stale-answer-client-timeout + * triggers, and the logic in there doesn't + * expect any result as input, as it will itself + * lookup for stale data in cache to use as + * result, if any is available. * - * Also, if we reached this point, then the whole fetch - * context is done, it will cancel timers, process - * associated callbacks of type DNS_EVENT_FETCHDONE, and - * silently remove/free events of type - * DNS_EVENT_TRYSTALE. + * Also, if we reached this point, then the + * whole fetch context is done, it will cancel + * timers, process associated callbacks of type + * DNS_EVENT_FETCHDONE, and silently remove/free + * events of type DNS_EVENT_TRYSTALE. */ continue; } @@ -5086,7 +5163,8 @@ clone_results(fetchctx_t *fctx) { * '*fctx' is shutting down. * * Returns: - * true if the resolver is exiting and this is the last fctx in the bucket. + * true if the resolver is exiting and this is the last fctx in the + *bucket. */ static bool maybe_destroy(fetchctx_t *fctx, bool locked) { @@ -5205,8 +5283,8 @@ validated(isc_task_t *task, isc_event_t *event) { /* * If shutting down, ignore the results. Check to see if we're - * done waiting for validator completions and ADB pending events; if - * so, destroy the fctx. + * done waiting for validator completions and ADB pending + * events; if so, destroy the fctx. */ if (SHUTTINGDOWN(fctx) && !sentresponse) { bool bucket_empty; @@ -5221,8 +5299,8 @@ validated(isc_task_t *task, isc_event_t *event) { isc_stdtime_get(&now); /* - * If chaining, we need to make sure that the right result code is - * returned, and that the rdatasets are bound. + * If chaining, we need to make sure that the right result code + * is returned, and that the rdatasets are bound. */ if (vevent->result == ISC_R_SUCCESS && !negative && vevent->rdataset != NULL && CHAINING(vevent->rdataset)) @@ -5239,9 +5317,9 @@ validated(isc_task_t *task, isc_event_t *event) { } /* - * Either we're not shutting down, or we are shutting down but want - * to cache the result anyway (if this was a validation started by - * a query with cd set) + * Either we're not shutting down, or we are shutting down but + * want to cache the result anyway (if this was a validation + * started by a query with cd set) */ hevent = ISC_LIST_HEAD(fctx->events); @@ -5289,7 +5367,8 @@ validated(isc_task_t *task, isc_event_t *event) { } if (fctx->vresult == DNS_R_BROKENCHAIN && !negative) { /* - * Cache the data as pending for later validation. + * Cache the data as pending for later + * validation. */ result = ISC_R_NOTFOUND; if (vevent->rdataset != NULL) { @@ -5320,7 +5399,8 @@ validated(isc_task_t *task, isc_event_t *event) { if (fctx->validator != NULL) { dns_validator_send(fctx->validator); } else if (sentresponse) { - fctx_done(fctx, result, __LINE__); /* Locks bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks + bucket. */ } else if (result == DNS_R_BROKENCHAIN) { isc_result_t tresult; isc_time_t expire; @@ -5336,7 +5416,8 @@ validated(isc_task_t *task, isc_event_t *event) { dns_resolver_addbadcache(res, fctx->name, fctx->type, &expire); } - fctx_done(fctx, result, __LINE__); /* Locks bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks + bucket. */ } else { fctx_try(fctx, true, true); /* Locks bucket. */ } @@ -5458,8 +5539,8 @@ validated(isc_task_t *task, isc_event_t *event) { if (sentresponse) { bool bucket_empty = false; /* - * If we only deferred the destroy because we wanted to cache - * the data, destroy now. + * If we only deferred the destroy because we wanted to + * cache the data, destroy now. */ dns_db_detachnode(fctx->cache, &node); if (SHUTTINGDOWN(fctx)) { @@ -5823,11 +5904,12 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, anodep = &event->node; /* - * If this is an ANY, SIG or RRSIG query, we're not - * going to return any rdatasets, unless we encountered - * a CNAME or DNAME as "the answer". In this case, - * we're going to return DNS_R_CNAME or DNS_R_DNAME - * and we must set up the rdatasets. + * If this is an ANY, SIG or RRSIG query, we're + * not going to return any rdatasets, unless we + * encountered a CNAME or DNAME as "the answer". + * In this case, we're going to return + * DNS_R_CNAME or DNS_R_DNAME and we must set up + * the rdatasets. */ if ((fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_rrsig && @@ -5920,21 +6002,21 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, /* * If this RRset is in a secure domain, is in bailiwick, - * and is not glue, attempt DNSSEC validation. (We do not - * attempt to validate glue or out-of-bailiwick data--even - * though there might be some performance benefit to doing - * so--because it makes it simpler and safer to ensure that - * records from a secure domain are only cached if validated - * within the context of a query to the domain that owns - * them.) + * and is not glue, attempt DNSSEC validation. (We do + * not attempt to validate glue or out-of-bailiwick + * data--even though there might be some performance + * benefit to doing so--because it makes it simpler and + * safer to ensure that records from a secure domain are + * only cached if validated within the context of a + * query to the domain that owns them.) */ if (secure_domain && rdataset->trust != dns_trust_glue && !EXTERNAL(rdataset)) { dns_trust_t trust; /* - * RRSIGs are validated as part of validating the - * type they cover. + * RRSIGs are validated as part of validating + * the type they cover. */ if (rdataset->type == dns_rdatatype_rrsig) { continue; @@ -5944,7 +6026,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, !ANSWER(rdataset)) { /* * Ignore unrelated non-answer - * rdatasets that are missing signatures. + * rdatasets that are missing + * signatures. */ continue; } @@ -5969,9 +6052,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, /* * Cache this rdataset/sigrdataset pair as - * pending data. Track whether it was additional - * or not. If this was a priming query, additional - * should be cached as glue. + * pending data. Track whether it was + * additional or not. If this was a priming + * query, additional should be cached as glue. */ if (rdataset->trust == dns_trust_additional) { trust = dns_trust_pending_additional; @@ -6016,11 +6099,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, ardataset != NULL && NEGATIVE(ardataset)) { /* - * The answer in the cache is - * better than the answer we - * found, and is a negative - * cache entry, so we must set - * eresult appropriately. + * The answer in the + * cache is better than + * the answer we found, + * and is a negative + * cache entry, so we + * must set eresult + * appropriately. */ if (NXDOMAIN(ardataset)) { eresult = @@ -6030,10 +6115,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, DNS_R_NCACHENXRRSET; } /* - * We have a negative response - * from the cache so don't - * attempt to add the RRSIG - * rrset. + * We have a negative + * response from the + * cache so don't + * attempt to add the + * RRSIG rrset. */ continue; } @@ -6065,9 +6151,10 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, { /* * This is The Answer. We will - * validate it, but first we cache - * the rest of the response - it may - * contain useful keys. + * validate it, but first we + * cache the rest of the + * response - it may contain + * useful keys. */ INSIST(valrdataset == NULL && valsigrdataset == NULL); @@ -6124,10 +6211,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, rdataset->covers == dns_rdatatype_ns))) { /* - * If the trust level is 'dns_trust_glue' - * then we are adding data from a referral - * we got while executing the search algorithm. - * New referral data always takes precedence + * If the trust level is + * 'dns_trust_glue' then we are adding + * data from a referral we got while + * executing the search algorithm. New + * referral data always takes precedence * over the existing cache contents. */ options = DNS_DBADD_FORCE; @@ -6162,10 +6250,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, if (ANSWER(rdataset) && ardataset != NULL && NEGATIVE(ardataset)) { /* - * The answer in the cache is better - * than the answer we found, and is - * a negative cache entry, so we - * must set eresult appropriately. + * The answer in the cache is + * better than the answer we + * found, and is a negative + * cache entry, so we must set + * eresult appropriately. */ if (NXDOMAIN(ardataset)) { eresult = DNS_R_NCACHENXDOMAIN; @@ -6199,7 +6288,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER); if (event != NULL) { /* - * Negative results must be indicated in event->result. + * Negative results must be indicated in + * event->result. */ if (dns_rdataset_isassociated(event->rdataset) && NEGATIVE(event->rdataset)) { @@ -6268,7 +6358,8 @@ cache_message(fetchctx_t *fctx, dns_message_t *message, } /* - * Do what dns_ncache_addoptout() does, and then compute an appropriate eresult. + * Do what dns_ncache_addoptout() does, and then compute an appropriate + * eresult. */ static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, @@ -6308,10 +6399,10 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, } else { /* * Either we don't care about the nature of the - * cache rdataset (because no fetch is interested - * in the outcome), or the cache rdataset is not - * a negative cache entry. Whichever case it is, - * we can return success. + * cache rdataset (because no fetch is + * interested in the outcome), or the cache + * rdataset is not a negative cache entry. + * Whichever case it is, we can return success. * * XXXRTH There's a CNAME/DNAME problem here. */ @@ -6413,9 +6504,9 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message, NULL, NULL, valoptions, res->buckets[fctx->bucketnum].task); /* - * If validation is necessary, return now. Otherwise continue - * to process the message, letting the validation complete - * in its own good time. + * If validation is necessary, return now. Otherwise + * continue to process the message, letting the + * validation complete in its own good time. */ return (result); } @@ -6618,8 +6709,8 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, } /* - * If the owner name matches one in the exclusion list, either exactly - * or partially, allow it. + * If the owner name matches one in the exclusion list, either + * exactly or partially, allow it. */ if (view->answeracl_exclude != NULL) { dns_rbtnode_t *node = NULL; @@ -6633,9 +6724,9 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, } /* - * Otherwise, search the filter list for a match for each address - * record. If a match is found, the address should be filtered, - * so should the entire answer. + * Otherwise, search the filter list for a match for each + * address record. If a match is found, the address should be + * filtered, so should the entire answer. */ for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) @@ -6748,8 +6839,8 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, } /* - * If the owner name matches one in the exclusion list, either exactly - * or partially, allow it. + * If the owner name matches one in the exclusion list, either + * exactly or partially, allow it. */ if (view->answernames_exclude != NULL) { result = dns_rbt_findnode(view->answernames_exclude, qname, @@ -6760,12 +6851,13 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, } /* - * If the target name is a subdomain of the search domain, allow it. + * If the target name is a subdomain of the search domain, allow + * it. * - * Note that if BIND is configured as a forwarding DNS server, the - * search domain will always match the root domain ("."), so we - * must also check whether forwarding is enabled so that filters - * can be applied; see GL #1574. + * Note that if BIND is configured as a forwarding DNS server, + * the search domain will always match the root domain ("."), so + * we must also check whether forwarding is enabled so that + * filters can be applied; see GL #1574. */ if (!fctx->forwarding && dns_name_issubdomain(tname, fctx->domain)) { return (true); @@ -6956,7 +7048,8 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { dns_rdataset_t *nsrdataset = NULL; /* - * Retrieve state from fctx->nsfetch before we destroy it. + * Retrieve state from fctx->nsfetch before we destroy + * it. */ domain = dns_fixedname_initname(&fixed); dns_name_copy(fctx->nsfetch->private->domain, domain); @@ -7283,9 +7376,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* * Is the question the same as the one we asked? - * NOERROR/NXDOMAIN/YXDOMAIN/REFUSED/SERVFAIL/BADCOOKIE must have - * the same question. - * FORMERR/NOTIMP if they have a question section then it must match. + * NOERROR/NXDOMAIN/YXDOMAIN/REFUSED/SERVFAIL/BADCOOKIE must + * have the same question. FORMERR/NOTIMP if they have a + * question section then it must match. */ switch (query->rmessage->rcode) { case dns_rcode_notimp: @@ -7328,21 +7421,15 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } /* - * The dispatcher should ensure we only get responses with QR set. + * The dispatcher should ensure we only get responses with QR + * set. */ INSIST((query->rmessage->flags & DNS_MESSAGEFLAG_QR) != 0); - /* - * INSIST() that the message comes from the place we sent it to, - * since the dispatch code should ensure this. - * - * INSIST() that the message id is correct (this should also be - * ensured by the dispatch code). - */ /* - * If we have had a server cookie and don't get one retry over TCP. - * This may be a misconfigured anycast server or an attempt to send - * a spoofed response. Skip if we have a valid tsig. + * If we have had a server cookie and don't get one retry over + * TCP. This may be a misconfigured anycast server or an attempt + * to send a spoofed response. Skip if we have a valid tsig. */ if (dns_message_gettsig(query->rmessage, NULL) == NULL && !query->rmessage->cc_ok && !query->rmessage->cc_bad && @@ -7359,7 +7446,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { isc_log_write( dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, - "missing expected cookie from %s", + "missing expected cookie " + "from %s", addrbuf); } rctx.retryopts |= DNS_FETCHOPT_TCP; @@ -7367,10 +7455,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_done(&rctx, result); return; } - /* - * XXXMPA When support for DNS COOKIE becomes ubiquitous, fall - * back to TCP for all non-COOKIE responses. - */ } rctx_edns(&rctx); @@ -7459,8 +7543,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_delonly_zone(&rctx); /* - * Optionally call dns_rdata_checkowner() and dns_rdata_checknames() - * to validate the names in the response message. + * Optionally call dns_rdata_checkowner() and + * dns_rdata_checknames() to validate the names in the response + * message. */ if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0) { checknames(query->rmessage); @@ -7497,7 +7582,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { case DNS_R_CHASEDSSERVERS: break; case DNS_R_DELEGATION: - /* With NOFOLLOW we want to pass the result code */ + /* With NOFOLLOW we want to pass the result code + */ if ((fctx->options & DNS_FETCHOPT_NOFOLLOW) == 0) { result = ISC_R_SUCCESS; } @@ -7531,8 +7617,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { rctx_additional(&rctx); /* - * Cache the cacheable parts of the message. This may also cause - * work to be queued to the DNSSEC validator. + * Cache the cacheable parts of the message. This may also + * cause work to be queued to the DNSSEC validator. */ if (WANTCACHE(fctx)) { isc_result_t tresult; @@ -7556,8 +7642,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* * rctx_respinit(): - * Initialize the response context structure 'rctx' to all zeroes, then set - * the task, event, query and fctx information from resquery_response(). + * Initialize the response context structure 'rctx' to all zeroes, then + * set the task, event, query and fctx information from + * resquery_response(). */ static void rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, @@ -7579,8 +7666,8 @@ rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, * rctx_answer_init(): * Clear and reinitialize those portions of 'rctx' that will be needed * when scanning the answer section of the response message. This can be - * called more than once if scanning needs to be restarted (though currently - * there are no cases in which this occurs). + * called more than once if scanning needs to be restarted (though + * currently there are no cases in which this occurs). */ static void rctx_answer_init(respctx_t *rctx) { @@ -7646,8 +7733,8 @@ rctx_dispfail(respctx_t *rctx) { (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { /* - * The problem might be that they don't understand EDNS0. - * Turn it off and try again. + * The problem might be that they don't understand + * EDNS0. Turn it off and try again. */ rctx->retryopts |= DNS_FETCHOPT_NOEDNS0; rctx->resend = true; @@ -7659,9 +7746,9 @@ rctx_dispfail(respctx_t *rctx) { rctx->next_server = true; /* * If this is a network error, mark the server as bad so - * that we won't try it for this fetch again. Also adjust - * finish and no_response so that we penalize this address - * in SRTT adjustment later. + * that we won't try it for this fetch again. Also + * adjust finish and no_response so that we penalize + * this address in SRTT adjustment later. */ if (devent->result == ISC_R_HOSTUNREACH || devent->result == ISC_R_NETUNREACH || @@ -7920,15 +8007,16 @@ rctx_edns(respctx_t *rctx) { (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { /* - * We didn't get a OPT record in response to a EDNS query. + * We didn't get a OPT record in response to a EDNS + * query. * * Old versions of named incorrectly drop the OPT record - * when there is a signed, truncated response so we check - * that TC is not set. + * when there is a signed, truncated response so we + * check that TC is not set. * - * Record that the server is not talking EDNS. While this - * should be safe to do for any rcode we limit it to NOERROR - * and NXDOMAIN. + * Record that the server is not talking EDNS. While + * this should be safe to do for any rcode we limit it + * to NOERROR and NXDOMAIN. */ dns_message_logpacket( query->rmessage, "received packet (no opt) from", @@ -8122,8 +8210,8 @@ rctx_answer_positive(respctx_t *rctx) { } /* - * We didn't end with an incomplete chain, so the rcode should be - * "no error". + * We didn't end with an incomplete chain, so the rcode should + * be "no error". */ if (rctx->query->rmessage->rcode != dns_rcode_noerror) { log_formerr(fctx, "CNAME/DNAME chain complete, but RCODE " @@ -8152,8 +8240,8 @@ rctx_answer_positive(respctx_t *rctx) { /* * rctx_answer_scan(): * Perform a single pass over the answer section of a response, looking - * for an answer that matches QNAME/QTYPE, or a CNAME matching QNAME, or a - * covering DNAME. If more than one rdataset is found matching these + * for an answer that matches QNAME/QTYPE, or a CNAME matching QNAME, or + * a covering DNAME. If more than one rdataset is found matching these * criteria, then only one is kept. Order of preference is 1) the * shortest DNAME, 2) the first matching answer, or 3) the first CNAME. */ @@ -8213,8 +8301,9 @@ rctx_answer_scan(respctx_t *rctx) { } /* - * We are looking for the shortest DNAME if there - * are multiple ones (which there shouldn't be). + * We are looking for the shortest DNAME if + * there are multiple ones (which there + * shouldn't be). */ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; @@ -8236,9 +8325,9 @@ rctx_answer_scan(respctx_t *rctx) { /* * If a DNAME was found, then any CNAME or other answer matching - * QNAME that may also have been found must be ignored. Similarly, - * if a matching answer was found along with a CNAME, the CNAME - * must be ignored. + * QNAME that may also have been found must be ignored. + * Similarly, if a matching answer was found along with a CNAME, + * the CNAME must be ignored. */ if (rctx->dname != NULL) { rctx->aname = NULL; @@ -8497,9 +8586,9 @@ rctx_answer_dname(respctx_t *rctx) { /* * rctx_authority_positive(): * Examine the records in the authority section (if there are any) for a - * positive answer. We expect the names for all rdatasets in this section - * to be subdomains of the domain being queried; any that are not are - * skipped. We expect to find only *one* owner name; any names + * positive answer. We expect the names for all rdatasets in this + * section to be subdomains of the domain being queried; any that are + * not are skipped. We expect to find only *one* owner name; any names * after the first one processed are ignored. We expect to find only * rdatasets of type NS, RRSIG, or SIG; all others are ignored. Whatever * remains can be cached at trust level authauthority or additional @@ -8554,8 +8643,8 @@ rctx_authority_positive(respctx_t *rctx) { rctx->ns_rdataset = rdataset; } /* - * Mark any additional data related - * to this rdataset. + * Mark any additional data + * related to this rdataset. */ (void)dns_rdataset_additionaldata( rdataset, name, check_related, @@ -8587,8 +8676,8 @@ rctx_answer_none(respctx_t *rctx) { rctx_answer_init(rctx); /* - * Sometimes we can tell if its a negative response by looking at - * the message header. + * Sometimes we can tell if its a negative response by looking + * at the message header. */ if (rctx->query->rmessage->rcode == dns_rcode_nxdomain || (rctx->query->rmessage->counts[DNS_SECTION_ANSWER] == 0 && @@ -8908,7 +8997,8 @@ rctx_authority_dnssec(respctx_t *rctx) { } if (!dns_name_issubdomain(name, fctx->domain)) { - /* Invalid name found; preserve it for logging later */ + /* Invalid name found; preserve it for logging + * later */ rctx->found_name = name; rctx->found_type = ISC_LIST_HEAD(name->list)->type; continue; @@ -8947,16 +9037,17 @@ rctx_authority_dnssec(respctx_t *rctx) { rdataset->trust = dns_trust_additional; } /* - * No additional data needs to be marked. + * No additional data needs to be + * marked. */ break; case dns_rdatatype_ds: /* * DS or SIG DS. * - * These should only be here if this is a - * referral, and there should only be one - * DS RRset. + * These should only be here if this is + * a referral, and there should only be + * one DS RRset. */ if (rctx->ns_name == NULL) { log_formerr(fctx, "DS with no " @@ -9127,8 +9218,8 @@ rctx_referral(respctx_t *rctx) { /* * Reinitialize 'rctx' to prepare for following the delegation: - * set the get_nameservers and next_server flags appropriately and - * reset the fetch context counters. + * set the get_nameservers and next_server flags appropriately + * and reset the fetch context counters. * */ if ((rctx->fctx->options & DNS_FETCHOPT_NOFOLLOW) == 0) { @@ -9241,7 +9332,8 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, } if (!dns_name_issubdomain(fname, fctx->domain)) { /* - * The best nameservers are now above our QDOMAIN. + * The best nameservers are now above our + * QDOMAIN. */ FCTXTRACE("nameservers now above QDOMAIN"); fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); @@ -9273,9 +9365,10 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, /* * rctx_resend(): * - * Resend the query, probably with the options changed. Calls fctx_query(), - * passing rctx->retryopts (which is based on query->options, but may have been - * updated since the last time fctx_query() was called). + * Resend the query, probably with the options changed. Calls + * fctx_query(), passing rctx->retryopts (which is based on + * query->options, but may have been updated since the last time + * fctx_query() was called). */ static void rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { @@ -9305,12 +9398,12 @@ rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { /* * rctx_next(): - * We got what appeared to be a response but it didn't match the question - * or the cookie; it may have been meant for someone else, or it may be a - * spoofing attack. Drop it and continue listening for the response we - * wanted. + * We got what appeared to be a response but it didn't match the + * question or the cookie; it may have been meant for someone else, or + * it may be a spoofing attack. Drop it and continue listening for the + * response we wanted. */ -static void +static isc_result_t rctx_next(respctx_t *rctx) { #ifdef WANT_QUERYTRACE fetchctx_t *fctx = rctx->fctx; @@ -9325,11 +9418,14 @@ rctx_next(respctx_t *rctx) { if (result != ISC_R_SUCCESS) { fctx_done(rctx->fctx, result, __LINE__); } + + return (result); } /* * rctx_chaseds(): - * Look up the parent zone's NS records so that DS records can be fetched. + * Look up the parent zone's NS records so that DS records can be + * fetched. */ static void rctx_chaseds(respctx_t *rctx, dns_message_t *message, @@ -9363,10 +9459,11 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, /* * rctx_done(): - * This resolver query response is finished, either because we encountered - * a problem or because we've gotten all the information from it that we - * can. We either wait for another response, resend the query to the - * same server, resend to a new server, or clean up and shut down the fetch. + * This resolver query response is finished, either because we + * encountered a problem or because we've gotten all the information + * from it that we can. We either wait for another response, resend the + * query to the same server, resend to a new server, or clean up and + * shut down the fetch. */ static void rctx_done(respctx_t *rctx, isc_result_t result) { @@ -9390,7 +9487,7 @@ rctx_done(respctx_t *rctx, isc_result_t result) { * Cancel the query. */ if (!rctx->nextitem) { - fctx_cancelquery(&query, &rctx->devent, rctx->finish, + fctx_cancelquery(query, &rctx->devent, rctx->finish, rctx->no_response, false); } @@ -9399,7 +9496,7 @@ rctx_done(respctx_t *rctx, isc_result_t result) { (rctx->next_server || rctx->resend || rctx->nextitem)) { if (rctx->nextitem) { - fctx_cancelquery(&query, &rctx->devent, rctx->finish, + fctx_cancelquery(query, &rctx->devent, rctx->finish, rctx->no_response, false); } fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); @@ -9412,7 +9509,9 @@ rctx_done(respctx_t *rctx, isc_result_t result) { } else if (rctx->resend) { rctx_resend(rctx, addrinfo); } else if (rctx->nextitem) { - rctx_next(rctx); + if (rctx_next(rctx) != ISC_R_SUCCESS) { + resquery_detach(&query); + } } else if (result == DNS_R_CHASEDSSERVERS) { rctx_chaseds(rctx, message, addrinfo, result); } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) { @@ -9759,15 +9858,11 @@ static void empty_bucket(dns_resolver_t *res) { RTRACE("empty_bucket"); - LOCK(&res->lock); - - INSIST(res->activebuckets > 0); - res->activebuckets--; - if (res->activebuckets == 0) { + if (isc_refcount_decrement(&res->activebuckets) == 1) { + LOCK(&res->lock); send_shutdown_events(res); + UNLOCK(&res->lock); } - - UNLOCK(&res->lock); } static void @@ -9847,10 +9942,11 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, .maxdepth = DEFAULT_RECURSION_DEPTH, .maxqueries = DEFAULT_MAX_QUERIES, .nbuckets = ntasks, - .activebuckets = ntasks, .querydscp4 = -1, .querydscp6 = -1 }; + atomic_init(&res->activebuckets, ntasks); + res->quotaresp[dns_quotatype_zone] = DNS_R_DROP; res->quotaresp[dns_quotatype_server] = DNS_R_SERVFAIL; isc_refcount_init(&res->references, 1); @@ -9877,8 +9973,8 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, isc_mutex_init(&res->buckets[i].lock); /* - * Since we have a pool of tasks we bind them to task queues - * to spread the load evenly + * Since we have a pool of tasks we bind them to task + * queues to spread the load evenly */ res->buckets[i].task = NULL; result = isc_task_create_bound(taskmgr, 0, @@ -10048,12 +10144,12 @@ dns_resolver_prime(dns_resolver_t *res) { if (want_priming) { /* * To avoid any possible recursive locking problems, we - * start the priming fetch like any other fetch, and holding - * no resolver locks. No one else will try to start it - * because we're the ones who set res->priming to true. - * Any other callers of dns_resolver_prime() while we're - * running will see that res->priming is already true and - * do nothing. + * start the priming fetch like any other fetch, and + * holding no resolver locks. No one else will try to + * start it because we're the ones who set res->priming + * to true. Any other callers of dns_resolver_prime() + * while we're running will see that res->priming is + * already true and do nothing. */ RTRACE("priming"); rdataset = isc_mem_get(res->mctx, sizeof(*rdataset)); @@ -10117,7 +10213,9 @@ dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, LOCK(&res->lock); - if (atomic_load_acquire(&res->exiting) && res->activebuckets == 0) { + if (atomic_load_acquire(&res->exiting) && + atomic_load_acquire(&res->activebuckets) == 0) + { /* * We're already shutdown. Send the event. */ @@ -10139,6 +10237,7 @@ dns_resolver_shutdown(dns_resolver_t *res) { fetchctx_t *fctx; isc_result_t result; bool is_false = false; + bool is_done = false; REQUIRE(VALID_RESOLVER(res)); @@ -10157,12 +10256,14 @@ dns_resolver_shutdown(dns_resolver_t *res) { } atomic_store(&res->buckets[i].exiting, true); if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) { - INSIST(res->activebuckets > 0); - res->activebuckets--; + if (isc_refcount_decrement( + &res->activebuckets) == 1) { + is_done = true; + } } UNLOCK(&res->buckets[i].lock); } - if (res->activebuckets == 0) { + if (is_done) { send_shutdown_events(res); } result = isc_timer_reset(res->spillattimer, @@ -10185,10 +10286,8 @@ dns_resolver_detach(dns_resolver_t **resp) { RTRACE("detach"); if (isc_refcount_decrement(&res->references) == 1) { - LOCK(&res->lock); + isc_refcount_destroy(&res->activebuckets); INSIST(atomic_load_acquire(&res->exiting)); - INSIST(res->activebuckets == 0); - UNLOCK(&res->lock); destroy(res); } } @@ -10255,7 +10354,8 @@ fctx_minimize_qname(fetchctx_t *fctx) { * boundaries at /16, /32, /48, /56, /64 and /128 * In 'label count' terms that's equal to * 7 11 15 17 19 35 - * We fix fctx->qmin_labels to point to the nearest boundary + * We fix fctx->qmin_labels to point to the nearest + * boundary */ if (fctx->qmin_labels < 7) { fctx->qmin_labels = 7; @@ -10452,8 +10552,9 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, isc_task_send(res->buckets[bucketnum].task, &event); } else { /* - * We don't care about the result of fctx_unlink() - * since we know we're not exiting. + * We don't care about the result of + * fctx_unlink() since we know we're not + * exiting. */ (void)fctx_unlink(fctx); dodestroy = true; @@ -10787,7 +10888,8 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, memmove(tmp, algorithms, *algorithms); } tmp[len - 1] |= mask; - /* 'tmp[0]' should contain the length of 'tmp'. */ + /* 'tmp[0]' should contain the length of 'tmp'. + */ *tmp = len; node->data = tmp; /* Free the older bitfield. */ @@ -11155,7 +11257,9 @@ dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format, fc = ISC_LIST_NEXT(fc, link)) { dns_name_print(fc->domain, fp); - fprintf(fp, ": %u active (%u spilled, %u allowed)\n", + fprintf(fp, + ": %u active (%u spilled, %u " + "allowed)\n", fc->count, fc->dropped, fc->allowed); } UNLOCK(&resolver->dbuckets[i].lock); diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index 65a2f3d441..b8d083b687 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -168,7 +168,7 @@ reset(void) { dns_dispatchset_destroy(&dset); } if (dispatchmgr != NULL) { - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } } @@ -393,7 +393,7 @@ dispatch_getnext(void **state) { * Shutdown the dispatch. */ dns_dispatch_detach(&dispatch); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } int diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index 2989af3041..2c8b6f4e9a 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -70,7 +70,7 @@ _teardown(void **state) { dns_dispatch_detach(&dispatch); dns_view_detach(&view); - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); dns_test_end(); return (0); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9b26c61ffe..d2e1b75bbf 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -14011,8 +14011,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { result = dns_request_getresponse(revent->request, msg, 0); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_INFO, - "refresh: failure trying master " - "%s (source %s): %s", + "refresh: unable to get response, master " + "%s, source %s: %s", master, source, dns_result_totext(result)); goto next_master; } diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 8ece586163..8f49e53047 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -165,7 +165,7 @@ shutdown_managers(isc_task_t *task, isc_event_t *event) { } if (dispatchmgr != NULL) { - dns_dispatchmgr_destroy(&dispatchmgr); + dns_dispatchmgr_detach(&dispatchmgr); } atomic_store(&shutdown_done, true); From 81a22cbf5fa7e8662dff02d68a92cc82eb41c099 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 9 Sep 2021 15:25:08 -0700 Subject: [PATCH 20/28] Remove DISPATH_TRACE, RESOLVER_TRACE and REQ_TRACE logging Remove the debugging printfs. (leaving this as a separate commit rather than squashing it so we can restore it in the future if we ever need it again.) --- lib/dns/dispatch.c | 130 +++------------------------------ lib/dns/include/dns/dispatch.h | 40 ++++------ lib/dns/include/dns/request.h | 12 +-- lib/dns/request.c | 69 ++--------------- lib/dns/resolver.c | 58 ++------------- 5 files changed, 42 insertions(+), 267 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 75803f210d..a839164a7b 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -37,8 +37,6 @@ #include #include -#define DISPATCH_TRACE - typedef ISC_LIST(dns_dispentry_t) dns_displist_t; typedef struct dns_qid { @@ -489,34 +487,18 @@ allocate_devent(dns_dispatch_t *disp) { return (ev); } -#define dispentry_attach(r, rp) \ - __dispentry_attach(r, rp, __func__, __FILE__, __LINE__) - static void -__dispentry_attach(dns_dispentry_t *resp, dns_dispentry_t **respp, - const char *func, const char *file, unsigned int line) { - uint_fast32_t ref; - +dispentry_attach(dns_dispentry_t *resp, dns_dispentry_t **respp) { REQUIRE(VALID_RESPONSE(resp)); REQUIRE(respp != NULL && *respp == NULL); - ref = isc_refcount_increment(&resp->references); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, resp, respp, ref + 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* DISPATCH_TRACE */ + isc_refcount_increment(&resp->references); *respp = resp; } static void -__dispentry_destroy(dns_dispentry_t *resp) { +dispentry_destroy(dns_dispentry_t *resp) { dns_dispatch_t *disp = resp->disp; resp->magic = 0; @@ -527,23 +509,14 @@ __dispentry_destroy(dns_dispentry_t *resp) { isc_refcount_destroy(&resp->references); -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%d:%s:isc_task_detach(%p) -> %p\n", __FILE__, - __LINE__, __func__, &resp->task, resp->task); -#endif /* DISPATCH_TRACE */ - isc_task_detach(&resp->task); isc_mem_put(disp->mgr->mctx, resp, sizeof(*resp)); dns_dispatch_detach(&disp); } -#define dispentry_detach(rp) \ - __dispentry_detach(rp, __func__, __FILE__, __LINE__) - static void -__dispentry_detach(dns_dispentry_t **respp, const char *func, const char *file, - unsigned int line) { +dispentry_detach(dns_dispentry_t **respp) { dns_dispentry_t *resp = NULL; uint_fast32_t ref; @@ -553,18 +526,8 @@ __dispentry_detach(dns_dispentry_t **respp, const char *func, const char *file, *respp = NULL; ref = isc_refcount_decrement(&resp->references); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, resp, respp, ref - 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); -#endif /* DISPATCH_TRACE */ - if (ref == 1) { - __dispentry_destroy(resp); + dispentry_destroy(resp); } } @@ -1016,31 +979,17 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, } void -dns__dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp, - const char *func, const char *file, unsigned int line) { - uint_fast32_t ref; - +dns_dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp) { REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(mgrp != NULL && *mgrp == NULL); - ref = isc_refcount_increment(&mgr->references); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, mgr, mgrp, ref + 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* DISPATCH_TRACE */ + isc_refcount_increment(&mgr->references); *mgrp = mgr; } void -dns__dispatchmgr_detach(dns_dispatchmgr_t **mgrp, const char *func, - const char *file, unsigned int line) { +dns_dispatchmgr_detach(dns_dispatchmgr_t **mgrp) { dns_dispatchmgr_t *mgr = NULL; uint_fast32_t ref; @@ -1050,16 +999,6 @@ dns__dispatchmgr_detach(dns_dispatchmgr_t **mgrp, const char *func, *mgrp = NULL; ref = isc_refcount_decrement(&mgr->references); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, mgr, mgrp, ref - 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); -#endif /* DISPATCH_TRACE */ - if (ref == 1) { dispatchmgr_destroy(mgr); } @@ -1293,12 +1232,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, } result = isc_task_create(taskmgr, 50, &disp->task); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%d:%s:isc_task_create() -> %p\n", __FILE__, - __LINE__, __func__, disp->task); -#endif /* DISPATCH_TRACE */ - if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -1456,12 +1389,6 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, disp->local = *localaddr; result = isc_task_create(taskmgr, 0, &disp->task); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%d:%s:isc_task_create() -> %p\n", __FILE__, - __LINE__, __func__, disp->task); -#endif /* DISPATCH_TRACE */ - if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -1502,11 +1429,6 @@ dns_dispatch_destroy(dns_dispatch_t *disp) { isc_nmhandle_detach(&disp->handle); } -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%d:%s:isc_task_detach(%p) -> %p\n", __FILE__, - __LINE__, __func__, &disp->task, disp->task); -#endif /* DISPATCH_TRACE */ - isc_task_detach(&disp->task); dispatch_free(&disp); @@ -1518,31 +1440,17 @@ dns_dispatch_destroy(dns_dispatch_t *disp) { } void -dns__dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp, - const char *func, const char *file, unsigned int line) { - uint_fast32_t ref; - +dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { REQUIRE(VALID_DISPATCH(disp)); REQUIRE(dispp != NULL && *dispp == NULL); - ref = isc_refcount_increment(&disp->references); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, disp, dispp, ref + 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* DISPATCH_TRACE */ + isc_refcount_increment(&disp->references); *dispp = disp; } void -dns__dispatch_detach(dns_dispatch_t **dispp, const char *func, const char *file, - unsigned int line) { +dns_dispatch_detach(dns_dispatch_t **dispp) { dns_dispatch_t *disp = NULL; uint_fast32_t ref; @@ -1552,18 +1460,7 @@ dns__dispatch_detach(dns_dispatch_t **dispp, const char *func, const char *file, *dispp = NULL; ref = isc_refcount_decrement(&disp->references); - -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, disp, dispp, ref - 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); -#endif /* DISPATCH_TRACE */ - dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1); - if (ref == 1) { LOCK(&disp->lock); REQUIRE(disp->recv_pending == 0); @@ -1696,11 +1593,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, dns_dispatch_attach(disp, &res->disp); -#ifdef DISPATCH_TRACE - fprintf(stderr, "%s:%d:%s:isc_task_attach(%p, %p)\n", __FILE__, - __LINE__, __func__, task, &res->task); -#endif /* DISPATCH_TRACE */ - isc_task_attach(task, &res->task); res->id = id; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 01054a1dc0..70a6f42623 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -147,22 +147,22 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, dns_dispatchmgr_t **mgrp); *\li anything else -- failure */ -#define dns_dispatchmgr_attach(mgr, mgrp) \ - dns__dispatchmgr_attach(mgr, mgrp, __func__, __FILE__, __LINE__) - void -dns__dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp, - const char *func, const char *file, unsigned int line); - -#define dns_dispatchmgr_detach(mgrp) \ - dns__dispatchmgr_detach(mgrp, __func__, __FILE__, __LINE__) - -void -dns__dispatchmgr_detach(dns_dispatchmgr_t **mgrp, const char *func, - const char *file, unsigned int line); +dns_dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp); /*%< - * Destroys the dispatchmgr when it becomes empty. This could be - * immediately. + * Attach to a dispatch manger. + * + * Requires: + *\li is valid. + * + *\li mgrp != NULL && *mgrp == NULL + */ + +void +dns_dispatchmgr_detach(dns_dispatchmgr_t **mgrp); +/*%< + * Detach from the dispatch manager, and destroy it if no references + * remain. * * Requires: *\li mgrp != NULL && *mgrp is a valid dispatchmgr. @@ -258,12 +258,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, *\li Anything else -- failure. */ -#define dns_dispatch_attach(d, dp) \ - dns__dispatch_attach(d, dp, __func__, __FILE__, __LINE__) - void -dns__dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp, - const char *func, const char *file, unsigned int line); +dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp); /*%< * Attach to a dispatch handle. * @@ -273,12 +269,8 @@ dns__dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp, *\li dispp != NULL && *dispp == NULL */ -#define dns_dispatch_detach(dp) \ - dns__dispatch_detach(dp, __func__, __FILE__, __LINE__) - void -dns__dispatch_detach(dns_dispatch_t **dispp, const char *func, const char *file, - unsigned int line); +dns_dispatch_detach(dns_dispatch_t **dispp); /*%< * Detaches from the dispatch. * diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h index fd8e08cebe..9554603b50 100644 --- a/lib/dns/include/dns/request.h +++ b/lib/dns/include/dns/request.h @@ -124,12 +124,8 @@ dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr); *\li 'requestmgr' is a valid requestmgr. */ -#define dns_requestmgr_attach(source, targetp) \ - dns__requestmgr_attach(source, targetp, __FILE__, __LINE__, __func__) - void -dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, - const char *file, unsigned int line, const char *func); +dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp); /*%< * Attach to the request manager. dns_requestmgr_shutdown() must not * have been called on 'source' prior to calling dns_requestmgr_attach(). @@ -141,12 +137,8 @@ dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, *\li 'targetp' to be non NULL and '*targetp' to be NULL. */ -#define dns_requestmgr_detach(requestmgrp) \ - dns__requestmgr_detach(requestmgrp, __FILE__, __LINE__, __func__) - void -dns__requestmgr_detach(dns_requestmgr_t **requestmgrp, const char *file, - unsigned int line, const char *func); +dns_requestmgr_detach(dns_requestmgr_t **requestmgrp); /*%< * Detach from the given requestmgr. If this is the final detach * requestmgr will be destroyed. dns_requestmgr_shutdown() must diff --git a/lib/dns/request.c b/lib/dns/request.c index 7d2b938fa3..9d4bb57f3d 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -32,8 +32,6 @@ #include #include -#define REQ_TRACE - #define REQUESTMGR_MAGIC ISC_MAGIC('R', 'q', 'u', 'M') #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC) @@ -120,11 +118,9 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void -__req_attach(dns_request_t *source, dns_request_t **targetp, const char *file, - unsigned int line, const char *func); +req_attach(dns_request_t *source, dns_request_t **targetp); static void -__req_detach(dns_request_t **requestp, const char *file, unsigned int line, - const char *func); +req_detach(dns_request_t **requestp); static void req_destroy(dns_request_t *request); static void @@ -132,11 +128,6 @@ req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); void request_cancel(dns_request_t *request); -#define req_attach(source, targetp) \ - __req_attach(source, targetp, __FILE__, __LINE__, __func__) -#define req_detach(requestp) \ - __req_detach(requestp, __FILE__, __LINE__, __func__) - /*** *** Public ***/ @@ -257,8 +248,7 @@ dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) { } void -dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, - const char *file, unsigned int line, const char *func) { +dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { uint_fast32_t ref; REQUIRE(VALID_REQUESTMGR(source)); @@ -268,16 +258,6 @@ dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, ref = isc_refcount_increment(&source->references); -#ifdef REQ_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, source, targetp, ref + 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* REQ_TRACE */ - req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: references = %" PRIuFAST32, source, ref + 1); @@ -286,8 +266,7 @@ dns__requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp, } void -dns__requestmgr_detach(dns_requestmgr_t **requestmgrp, const char *file, - unsigned int line, const char *func) { +dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) { dns_requestmgr_t *requestmgr = NULL; uint_fast32_t ref; @@ -298,16 +277,6 @@ dns__requestmgr_detach(dns_requestmgr_t **requestmgrp, const char *file, ref = isc_refcount_decrement(&requestmgr->references); -#ifdef REQ_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, requestmgr, requestmgrp, ref - 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* REQ_TRACE */ - req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: references = %" PRIuFAST32, requestmgr, ref - 1); @@ -1181,31 +1150,17 @@ req_sendevent(dns_request_t *request, isc_result_t result) { } static void -__req_attach(dns_request_t *source, dns_request_t **targetp, const char *file, - unsigned int line, const char *func) { - uint_fast32_t ref; - +req_attach(dns_request_t *source, dns_request_t **targetp) { REQUIRE(VALID_REQUEST(source)); REQUIRE(targetp != NULL && *targetp == NULL); - ref = isc_refcount_increment(&source->references); - -#ifdef REQ_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, source, targetp, ref + 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* REQ_TRACE */ + isc_refcount_increment(&source->references); *targetp = source; } static void -__req_detach(dns_request_t **requestp, const char *file, unsigned int line, - const char *func) { +req_detach(dns_request_t **requestp) { dns_request_t *request = NULL; uint_fast32_t ref; @@ -1216,16 +1171,6 @@ __req_detach(dns_request_t **requestp, const char *file, unsigned int line, ref = isc_refcount_decrement(&request->references); -#ifdef REQ_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, request, requestp, ref - 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* REQ_TRACE */ - if (request->requestmgr != NULL && atomic_load_acquire(&request->requestmgr->exiting)) { diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 2a65090906..ff24608062 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -62,10 +62,6 @@ #include #include -#define RESOLVER_TRACE 1 - -#define WANT_QUERYTRACE 1 - #ifdef WANT_QUERYTRACE #define RTRACE(m) \ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, \ @@ -1169,37 +1165,18 @@ resquery_destroy(resquery_t *query) { } } -#define resquery_attach(s, t) \ - __resquery_attach(s, t, __FILE__, __LINE__, __func__) - -static void __attribute__((unused)) -__resquery_attach(resquery_t *source, resquery_t **targetp, const char *file, - unsigned int line, const char *func) { - uint_fast32_t ref; - +static void +resquery_attach(resquery_t *source, resquery_t **targetp) { REQUIRE(VALID_QUERY(source)); REQUIRE(targetp != NULL && *targetp == NULL); - ref = isc_refcount_increment(&source->references); - -#ifdef RESOLVER_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, source, targetp, ref + 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); - UNUSED(ref); -#endif /* RESOLVER_TRACE */ + isc_refcount_increment(&source->references); *targetp = source; } -#define resquery_detach(q) __resquery_detach(q, __FILE__, __LINE__, __func__) - static void -__resquery_detach(resquery_t **queryp, const char *file, unsigned int line, - const char *func) { +resquery_detach(resquery_t **queryp) { uint_fast32_t ref; resquery_t *query = NULL; @@ -1209,16 +1186,6 @@ __resquery_detach(resquery_t **queryp, const char *file, unsigned int line, *queryp = NULL; ref = isc_refcount_decrement(&query->references); - -#ifdef RESOLVER_TRACE - fprintf(stderr, "%s:%s:%u:%s(%p, %p) = %" PRIuFAST32 "\n", func, file, - line, __func__, query, queryp, ref - 1); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); -#endif /* RESOLVER_TRACE */ - if (ref == 1) { resquery_destroy(query); } @@ -1243,13 +1210,9 @@ update_edns_stats(resquery_t *query) { } } -#define fctx_cancelquery(q, d, f, n, a) \ - __fctx_cancelquery(q, d, f, n, a, __FILE__, __LINE__, __func__) - static void -__fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, - isc_time_t *finish, bool no_response, bool age_untried, - const char *file, unsigned int line, const char *func) { +fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, + isc_time_t *finish, bool no_response, bool age_untried) { fetchctx_t *fctx = NULL; unsigned int rtt, rttms; unsigned int factor; @@ -1259,15 +1222,6 @@ __fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, fctx = query->fctx; -#ifdef RESOLVER_TRACE - fprintf(stderr, "%s:%s:%u:%s(query = %p, ...)\n", func, file, line, - __func__, query); -#else - UNUSED(func); - UNUSED(file); - UNUSED(line); -#endif /* RESOLVER_TRACE */ - FCTXTRACE("cancelquery"); if (RESQUERY_CANCELED(query)) { From 8b532d2e642c58c4234004600ddda82b81ac887e Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 26 Jul 2021 20:23:18 -0700 Subject: [PATCH 21/28] dispatch: Refactor to eliminate dns_dispatchevent - Responses received by the dispatch are no longer sent to the caller via a task event, but via a netmgr-style recv callback. the 'action' parameter to dns_dispatch_addresponse() is now called 'response' and is called directly from udp_recv() or tcp_recv() when a valid response has been received. - All references to isc_task and isc_taskmgr have been removed from dispatch functions. - All references to dns_dispatchevent_t have been removed and the type has been deleted. - Added a task to the resolver response context, to be used for fctx events. - When the caller cancels an operation, the response handler will be called with ISC_R_CANCELED; it can abort immediately since the caller will presumably have taken care of cleanup already. - Cleaned up attach/detach in resquery and request. --- bin/named/server.c | 12 +- bin/nsupdate/nsupdate.c | 8 +- bin/tests/system/pipelined/pipequeries.c | 5 +- bin/tests/system/tkey/keycreate.c | 4 +- bin/tests/system/tkey/keydelete.c | 4 +- bin/tools/mdig.c | 5 +- lib/dns/client.c | 10 +- lib/dns/dispatch.c | 433 ++++------------------- lib/dns/include/dns/dispatch.h | 75 +--- lib/dns/include/dns/types.h | 1 - lib/dns/include/dns/zone.h | 4 +- lib/dns/request.c | 78 ++-- lib/dns/resolver.c | 264 +++++++------- lib/dns/zone.c | 6 +- lib/isc/include/isc/types.h | 1 - lib/ns/client.c | 1 + lib/ns/include/ns/interfacemgr.h | 2 - lib/ns/interfacemgr.c | 4 - 18 files changed, 288 insertions(+), 629 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 7957591281..dd929b881b 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1315,8 +1315,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af, } } - result = dns_dispatch_createudp(named_g_dispatchmgr, named_g_taskmgr, - &sa, attrs, &disp); + result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, attrs, &disp); if (result != ISC_R_SUCCESS) { isc_sockaddr_t any; char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -10145,8 +10144,8 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) { server->heartbeat_interval = 0; CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr, - named_g_timermgr, named_g_socketmgr, - named_g_netmgr, &server->zonemgr), + named_g_timermgr, named_g_netmgr, + &server->zonemgr), "dns_zonemgr_create"); CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_" "setsize"); @@ -10358,9 +10357,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_taskmgr, - &dispatch->addr, attrs, - &dispatch->dispatch); + result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr, + attrs, &dispatch->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup; } diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 0690676db4..9502fc8299 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -935,15 +935,15 @@ setup_system(void) { if (have_ipv6) { isc_sockaddr_any6(&bind_any6); - result = dns_dispatch_createudp(dispatchmgr, taskmgr, - &bind_any6, 0, &dispatchv6); + result = dns_dispatch_createudp(dispatchmgr, &bind_any6, 0, + &dispatchv6); check_result(result, "dns_dispatch_createudp (v6)"); } if (have_ipv4) { isc_sockaddr_any(&bind_any); - result = dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, - 0, &dispatchv4); + result = dns_dispatch_createudp(dispatchmgr, &bind_any, 0, + &dispatchv4); check_result(result, "dns_dispatch_createudp (v4)"); } diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index e41f14a566..238e04c0f1 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -269,9 +269,8 @@ main(int argc, char *argv[]) { RUNCHECK(isc_task_create(taskmgr, 0, &task)); RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 0, - &dispatchv4)); + RUNCHECK(dns_dispatch_createudp( + dispatchmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index b83d613f82..ab10793a12 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -228,8 +228,8 @@ main(int argc, char *argv[]) { RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr)); isc_sockaddr_any(&bind_any); - RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, &bind_any, 0, - &dispatchv4)); + RUNCHECK( + dns_dispatch_createudp(dispatchmgr, &bind_any, 0, &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index 9b32e2930e..c81c306a8c 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -171,8 +171,8 @@ 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, taskmgr, &bind_any, 0, - &dispatchv4)); + RUNCHECK( + dns_dispatch_createudp(dispatchmgr, &bind_any, 0, &dispatchv4)); RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4, NULL, &requestmgr)); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index ca3acb8eac..5be81925d9 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -2128,9 +2128,8 @@ main(int argc, char *argv[]) { } else { isc_sockaddr_any6(&bind_any); } - RUNCHECK(dns_dispatch_createudp(dispatchmgr, taskmgr, - have_src ? &srcaddr : &bind_any, 0, - &dispatchvx)); + RUNCHECK(dns_dispatch_createudp( + dispatchmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchvx)); RUNCHECK(dns_requestmgr_create( mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL, diff --git a/lib/dns/client.c b/lib/dns/client.c index 030fa035b6..83b21bb12e 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -202,8 +202,7 @@ cleanup: static isc_result_t getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, - isc_taskmgr_t *taskmgr, dns_dispatch_t **dispp, - const isc_sockaddr_t *localaddr) { + dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { dns_dispatch_t *disp = NULL; isc_result_t result; isc_sockaddr_t anyaddr; @@ -213,8 +212,7 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, localaddr = &anyaddr; } - result = dns_dispatch_createudp(dispatchmgr, taskmgr, localaddr, 0, - &disp); + result = dns_dispatch_createudp(dispatchmgr, localaddr, 0, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -304,7 +302,7 @@ 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, client->dispatchmgr, taskmgr, + result = getudpdispatch(AF_INET, client->dispatchmgr, &dispatchv4, localaddr4); if (result == ISC_R_SUCCESS) { client->dispatchv4 = dispatchv4; @@ -313,7 +311,7 @@ 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, client->dispatchmgr, taskmgr, + result = getudpdispatch(AF_INET6, client->dispatchmgr, &dispatchv6, localaddr6); if (result == ISC_R_SUCCESS) { client->dispatchv6 = dispatchv6; diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index a839164a7b..08936b43c2 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -25,13 +25,11 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -79,7 +77,6 @@ struct dns_dispentry { unsigned int magic; isc_refcount_t references; dns_dispatch_t *disp; - isc_task_t *task; isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */ unsigned int bucket; unsigned int timeout; @@ -89,11 +86,10 @@ struct dns_dispentry { dns_messageid_t id; isc_nm_cb_t connected; isc_nm_cb_t sent; + isc_nm_recv_cb_t response; isc_nm_cb_t timedout; - isc_taskaction_t action; void *arg; bool canceled; - ISC_LIST(dns_dispatchevent_t) items; ISC_LINK(dns_dispentry_t) link; ISC_LINK(dns_dispentry_t) alink; }; @@ -109,7 +105,6 @@ struct dns_dispatch { /* Unlocked. */ unsigned int magic; /*%< magic */ dns_dispatchmgr_t *mgr; /*%< dispatch manager */ - 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 */ @@ -123,8 +118,7 @@ struct dns_dispatch { isc_socktype_t socktype; unsigned int attributes; isc_refcount_t references; - dns_dispatchevent_t failsafe_ev; /*%< failsafe cancel event */ - unsigned int shutdown_out : 1, recv_pending : 1; + unsigned int shutdown_out : 1; ISC_LIST(dns_dispentry_t) active; unsigned int nsockets; @@ -159,14 +153,6 @@ struct dns_dispatch { #define DNS_DISPATCH_SOCKSQUOTA 3072 #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ -/*% - * Number of buffers available for all dispatches in the buffer - * memory pool. - */ -#ifndef DNS_DISPATCH_MAXBUFFERS -#define DNS_DISPATCH_MAXBUFFERS 37268 -#endif /* ifndef DNS_DISPATCH_MAXBUFFERS */ - /*% * Quota to control the number of concurrent requests that can be handled * by each TCP dispatch. (UDP dispatches do not currently support socket @@ -206,16 +192,11 @@ 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 inline void -free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); -static inline dns_dispatchevent_t * -allocate_devent(dns_dispatch_t *disp); static void dispatch_free(dns_dispatch_t **dispp); static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, - const isc_sockaddr_t *localaddr, unsigned int attributes, - dns_dispatch_t **dispp); +dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + unsigned int attributes, dns_dispatch_t **dispp); static void qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp); static void @@ -285,39 +266,6 @@ dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) { msgbuf); } -static void -request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, - const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); - -static void -request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, - const char *fmt, ...) { - char msgbuf[2048]; - va_list ap; - - if (!isc_log_wouldlog(dns_lctx, level)) { - return; - } - - va_start(ap, fmt); - vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); - va_end(ap); - - if (VALID_RESPONSE(resp)) { - char peerbuf[256]; - 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, - peerbuf, msgbuf); - } else { - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, - DNS_LOGMODULE_DISPATCH, level, - "dispatch %p req/resp %p: %s", disp, resp, - msgbuf); - } -} - /* * Return a hash of the destination and message id. */ @@ -381,10 +329,12 @@ deactivate_dispentry(dns_dispatch_t *disp, dns_dispentry_t *resp) { if (ISC_LINK_LINKED(resp, alink)) { ISC_LIST_UNLINK(disp->active, resp, alink); } + if (resp->handle != NULL) { isc_nm_cancelread(resp->handle); isc_nmhandle_detach(&resp->handle); } + disp->nsockets--; } @@ -414,79 +364,6 @@ entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, return (NULL); } -static void -free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { - REQUIRE(buf != NULL && len != 0); - - switch (disp->socktype) { - case isc_socktype_tcp: - INSIST(disp->tcpbuffers > 0); - disp->tcpbuffers--; - isc_mem_put(disp->mgr->mctx, buf, len); - break; - case isc_socktype_udp: - LOCK(&disp->mgr->buffer_lock); - INSIST(disp->mgr->buffers > 0); - INSIST(len == DNS_DISPATCH_UDPBUFSIZE); - disp->mgr->buffers--; - UNLOCK(&disp->mgr->buffer_lock); - isc_mem_put(disp->mgr->mctx, buf, len); - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } -} - -static void * -allocate_udp_buffer(dns_dispatch_t *disp) { - LOCK(&disp->mgr->buffer_lock); - if (disp->mgr->buffers >= DNS_DISPATCH_MAXBUFFERS) { - UNLOCK(&disp->mgr->buffer_lock); - return (NULL); - } - disp->mgr->buffers++; - UNLOCK(&disp->mgr->buffer_lock); - - return (isc_mem_get(disp->mgr->mctx, DNS_DISPATCH_UDPBUFSIZE)); -} - -static inline void -free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { - /* failsafe_ev is not allocated */ - if (&(disp->failsafe_ev) == ev) { - INSIST(disp->shutdown_out == 1); - disp->shutdown_out = 0; - - return; - } - - if (ev->region.base != NULL) { - free_buffer(disp, ev->region.base, ev->region.length); - ev->region.base = NULL; - ev->region.length = 0; - } - - isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev)); - - dns_dispatch_detach(&disp); -} - -static inline dns_dispatchevent_t * -allocate_devent(dns_dispatch_t *disp) { - dns_dispatchevent_t *ev = NULL; - - ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); - - *ev = (dns_dispatchevent_t){ 0 }; - - dns_dispatch_attach(disp, &ev->dispatch); - - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, - NULL); - return (ev); -} - static void dispentry_attach(dns_dispentry_t *resp, dns_dispentry_t **respp) { REQUIRE(VALID_RESPONSE(resp)); @@ -509,7 +386,6 @@ dispentry_destroy(dns_dispentry_t *resp) { isc_refcount_destroy(&resp->references); - isc_task_detach(&resp->task); isc_mem_put(disp->mgr->mctx, resp, sizeof(*resp)); dns_dispatch_detach(&disp); @@ -554,14 +430,14 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, isc_result_t dres; isc_buffer_t source; unsigned int flags; - dns_dispatchevent_t *rev = NULL; isc_sockaddr_t peer; isc_netaddr_t netaddr; int match; - isc_taskaction_t action = NULL; + isc_nm_recv_cb_t response = NULL; bool nomore = true; REQUIRE(VALID_RESPONSE(resp)); + REQUIRE(VALID_DISPATCH(resp->disp)); disp = resp->disp; @@ -569,8 +445,8 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, if (isc_log_wouldlog(dns_lctx, LVL(90))) { LOCK(&disp->mgr->buffer_lock); - dispatch_log(disp, LVL(90), "got packet: requests %d, recvs %d", - disp->requests, disp->recv_pending); + dispatch_log(disp, LVL(90), "got packet: requests %d", + disp->requests); UNLOCK(&disp->mgr->buffer_lock); } @@ -578,7 +454,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, /* * This dispatcher is shutting down. */ - goto unlock; + goto sendevent; } if (!ISC_LINK_LINKED(resp, alink)) { @@ -661,43 +537,24 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, } sendevent: - rev = allocate_devent(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. */ - rev->result = eresult; - 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); - } - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->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); - - action = resp->action; + response = resp->response; unlock: UNLOCK(&disp->lock); - if (action != NULL) { - action(resp->task, (isc_event_t *)rev); + if (response != NULL) { + response(handle, eresult, region, resp->arg); } if (nomore) { dispentry_detach(&resp); } - return; } /* @@ -718,32 +575,30 @@ unlock: static void 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_dispentry_t *resp0 = (dns_dispentry_t *)arg; + dns_dispentry_t *resp = NULL; + dns_dispatch_t *disp = NULL; dns_messageid_t id; isc_result_t dres; unsigned int flags; - dns_dispentry_t *resp = NULL; - dns_dispatchevent_t *rev = NULL; unsigned int bucket; dns_qid_t *qid = NULL; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; isc_buffer_t source; isc_sockaddr_t peer; - isc_taskaction_t action = NULL; - REQUIRE(VALID_DISPATCH(disp)); + REQUIRE(VALID_RESPONSE(resp0)); + REQUIRE(VALID_DISPATCH(resp0->disp)); + + disp = resp0->disp; qid = disp->mgr->qid; LOCK(&disp->lock); - dispatch_log(disp, LVL(90), - "got TCP packet: requests %d, buffers %d, recvs %d", - disp->requests, disp->tcpbuffers, disp->recv_pending); - - INSIST(disp->recv_pending != 0); - disp->recv_pending = 0; + dispatch_log(disp, LVL(90), "got TCP packet: requests %d, buffers %d", + disp->requests, disp->tcpbuffers); peer = isc_nmhandle_peeraddr(handle); @@ -761,13 +616,14 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, /* * 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); - goto sendevent; + break; } break; @@ -832,48 +688,22 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); UNLOCK(&qid->lock); + if (resp == NULL) { - goto next; + goto unlock; } -sendevent: - rev = allocate_devent(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. - */ - rev->result = eresult; - 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); - } - - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, - resp->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); - - action = resp->action; - next: - startrecv(disp, NULL); + startrecv(disp, resp0); unlock: isc_nmhandle_detach(&handle); UNLOCK(&disp->lock); - dns_dispatch_detach(&disp); + dispentry_detach(&resp0); - if (action != NULL) { - action(resp->task, (isc_event_t *)rev); + if (resp != NULL) { + resp->response(handle, eresult, region, resp->arg); } } @@ -1168,10 +998,6 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf, isc_mutex_init(&disp->lock); - /* failsafe_ev is not allocated */ - ISC_EVENT_INIT(&disp->failsafe_ev, sizeof(disp->failsafe_ev), 0, NULL, - 0, NULL, NULL, NULL, NULL, NULL); - disp->magic = DISPATCH_MAGIC; *dispp = disp; @@ -1195,7 +1021,6 @@ dispatch_free(dns_dispatch_t **dispp) { REQUIRE(VALID_DISPATCHMGR(mgr)); INSIST(disp->requests == 0); - INSIST(disp->recv_pending == 0); INSIST(ISC_LIST_EMPTY(disp->active)); isc_mutex_destroy(&disp->lock); @@ -1204,11 +1029,9 @@ dispatch_free(dns_dispatch_t **dispp) { } isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, - const isc_sockaddr_t *localaddr, +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) { - isc_result_t result; dns_dispatch_t *disp = NULL; int pf; @@ -1231,13 +1054,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, isc_sockaddr_setport(&disp->local, 0); } - result = isc_task_create(taskmgr, 50, &disp->task); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - isc_task_setname(disp->task, "tcpdispatch", disp); - /* * Append it to the dispatcher list. */ @@ -1248,18 +1064,10 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, mgr_log(mgr, LVL(90), "dns_dispatch_createtcp: created TCP dispatch %p", disp); - dispatch_log(disp, LVL(90), "created task %p", disp->task); } *dispp = disp; return (ISC_R_SUCCESS); - -cleanup: - dispatch_free(&disp); - - UNLOCK(&mgr->lock); - - return (result); } #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask))) @@ -1333,19 +1141,17 @@ again: } isc_result_t -dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, - const isc_sockaddr_t *localaddr, unsigned int attributes, - dns_dispatch_t **dispp) { +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, 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(localaddr != NULL); - REQUIRE(taskmgr != NULL); REQUIRE(dispp != NULL && *dispp == NULL); LOCK(&mgr->lock); - result = dispatch_createudp(mgr, taskmgr, localaddr, attributes, &disp); + result = dispatch_createudp(mgr, localaddr, attributes, &disp); if (result == ISC_R_SUCCESS) { *dispp = disp; } @@ -1355,9 +1161,8 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, } static isc_result_t -dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, - const isc_sockaddr_t *localaddr, unsigned int attributes, - dns_dispatch_t **dispp) { +dispatch_createudp(dns_dispatchmgr_t *mgr, 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_sockaddr_t sa_any; @@ -1388,10 +1193,6 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, } disp->local = *localaddr; - result = isc_task_create(taskmgr, 0, &disp->task); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } /* * Append it to the dispatcher list. @@ -1399,7 +1200,6 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, 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); *dispp = disp; @@ -1429,8 +1229,6 @@ dns_dispatch_destroy(dns_dispatch_t *disp) { isc_nmhandle_detach(&disp->handle); } - isc_task_detach(&disp->task); - dispatch_free(&disp); /* Because dispatch uses mgr->mctx, we must detach after freeing @@ -1463,7 +1261,6 @@ dns_dispatch_detach(dns_dispatch_t **dispp) { dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1); if (ref == 1) { LOCK(&disp->lock); - REQUIRE(disp->recv_pending == 0); REQUIRE(ISC_LIST_EMPTY(disp->active)); UNLOCK(&disp->lock); @@ -1474,9 +1271,9 @@ dns_dispatch_detach(dns_dispatch_t **dispp) { isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, 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_nm_cb_t timedout, void *arg, dns_messageid_t *idp, + isc_nm_cb_t connected, isc_nm_cb_t sent, + isc_nm_recv_cb_t response, isc_nm_cb_t timedout, + void *arg, dns_messageid_t *idp, dns_dispentry_t **resp) { dns_dispentry_t *res = NULL; dns_qid_t *qid = NULL; @@ -1485,12 +1282,9 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, unsigned int bucket; bool ok = false; int i = 0; - isc_taskaction_t oldest_action = NULL; - isc_task_t *oldest_task = NULL; - isc_event_t *oldest_ev = NULL; + isc_nm_recv_cb_t oldest_response = NULL; REQUIRE(VALID_DISPATCH(disp)); - REQUIRE(task != NULL); REQUIRE(dest != NULL); REQUIRE(resp != NULL && *resp == NULL); REQUIRE(idp != NULL); @@ -1510,7 +1304,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) { dns_dispentry_t *oldest = NULL; - dns_dispatchevent_t *rev = NULL; /* * Kill oldest outstanding query if the number of sockets @@ -1518,17 +1311,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, */ oldest = ISC_LIST_HEAD(disp->active); if (oldest != NULL) { - rev = allocate_devent(oldest->disp); - rev->buffer.base = NULL; - rev->result = ISC_R_CANCELED; - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, - DNS_EVENT_DISPATCH, oldest->action, - oldest->arg, oldest, NULL, NULL); - - oldest_action = oldest->action; - oldest_task = oldest->task; - oldest_ev = (isc_event_t *)rev; - + oldest_response = oldest->response; inc_stats(disp->mgr, dns_resstatscounter_dispabort); } } @@ -1541,12 +1324,11 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, .connected = connected, .sent = sent, .timedout = timedout, - .action = action, + .response = response, .arg = arg }; isc_refcount_init(&res->references, 1); - ISC_LIST_INIT(res->items); ISC_LINK_INIT(res, link); ISC_LINK_INIT(res, alink); @@ -1593,8 +1375,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, dns_dispatch_attach(disp, &res->disp); - isc_task_attach(task, &res->task); - res->id = id; res->bucket = bucket; res->magic = RESPONSE_MAGIC; @@ -1605,8 +1385,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); - request_log(disp, res, LVL(90), "attached to task %p", res->task); - inc_stats(disp->mgr, (disp->socktype == isc_socktype_udp) ? dns_resstatscounter_disprequdp : dns_resstatscounter_dispreqtcp); @@ -1615,8 +1393,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, UNLOCK(&disp->lock); - if (oldest_action != NULL) { - oldest_action(oldest_task, oldest_ev); + if (oldest_response != NULL) { + oldest_response(res->handle, ISC_R_CANCELED, NULL, res->arg); } *idp = id; @@ -1626,54 +1404,28 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, } isc_result_t -dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { +dns_dispatch_getnext(dns_dispentry_t *resp) { dns_dispatch_t *disp = NULL; - dns_dispatchevent_t *ev = NULL; - isc_taskaction_t action = NULL; REQUIRE(VALID_RESPONSE(resp)); - REQUIRE(sockevent != NULL && *sockevent != NULL); disp = resp->disp; REQUIRE(VALID_DISPATCH(disp)); - ev = *sockevent; - *sockevent = NULL; - LOCK(&disp->lock); - free_devent(disp, ev); - - ev = ISC_LIST_HEAD(resp->items); - if (ev != NULL) { - ISC_LIST_UNLINK(resp->items, ev, ev_link); - ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, - resp->action, resp->arg, resp, NULL, NULL); - request_log(disp, resp, LVL(90), - "[c] Sent event %p buffer %p len %d to task %p", ev, - ev->buffer.base, ev->buffer.length, resp->task); - - action = resp->action; - } - startrecv(disp, resp); UNLOCK(&disp->lock); - if (action != NULL) { - action(resp->task, (isc_event_t *)ev); - } - return (ISC_R_SUCCESS); } void -dns_dispatch_removeresponse(dns_dispentry_t **respp, - dns_dispatchevent_t **sockevent) { +dns_dispatch_removeresponse(dns_dispentry_t **respp) { dns_dispatchmgr_t *mgr = NULL; dns_dispatch_t *disp = NULL; dns_dispentry_t *resp = NULL; - dns_dispatchevent_t *ev = NULL; dns_qid_t *qid = NULL; REQUIRE(respp != NULL); @@ -1692,14 +1444,6 @@ dns_dispatch_removeresponse(dns_dispentry_t **respp, qid = mgr->qid; - if (sockevent != NULL) { - REQUIRE(*sockevent != NULL); - ev = *sockevent; - *sockevent = NULL; - } else { - ev = NULL; - } - LOCK(&disp->lock); INSIST(disp->requests > 0); disp->requests--; @@ -1715,20 +1459,6 @@ dns_dispatch_removeresponse(dns_dispentry_t **respp, UNLOCK(&qid->lock); UNLOCK(&disp->lock); - if (ev != NULL) { - free_devent(disp, ev); - } - - /* - * Free any buffered responses as well - */ - ev = ISC_LIST_HEAD(resp->items); - while (ev != NULL) { - ISC_LIST_UNLINK(resp->items, ev, ev_link); - free_devent(disp, ev); - ev = ISC_LIST_HEAD(resp->items); - } - dispentry_detach(respp); } @@ -1737,32 +1467,28 @@ dns_dispatch_removeresponse(dns_dispentry_t **respp, */ static void startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) { - isc_nmhandle_t *handle = NULL; - dns_dispentry_t *tmp_resp = NULL; - dns_dispatch_t *tmp_disp = NULL; - switch (disp->socktype) { case isc_socktype_udp: - REQUIRE(resp != NULL); - REQUIRE(resp->handle != NULL); + REQUIRE(resp != NULL && resp->handle != NULL); - dispentry_attach(resp, &tmp_resp); - - /* resp->handle is detached in _removeresponse() */ + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); isc_nm_read(resp->handle, udp_recv, resp); - break; + case isc_socktype_tcp: - if (resp != NULL) { - REQUIRE(resp->handle == NULL); + 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; } - isc_nmhandle_attach(disp->handle, &handle); - dns_dispatch_attach(disp, &tmp_disp); - isc_nm_read(handle, tcp_recv, disp); - INSIST(disp->recv_pending == 0); - disp->recv_pending = 1; + isc_nmhandle_attach(disp->handle, &(isc_nmhandle_t *){ NULL }); + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + isc_nm_read(disp->handle, tcp_recv, resp); break; + default: INSIST(0); ISC_UNREACHABLE(); @@ -1779,13 +1505,6 @@ disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { goto detach; } - if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { - eresult = ISC_R_SHUTTINGDOWN; - } - - /* - * Start listening on success - */ if (eresult == ISC_R_SUCCESS) { switch (disp->socktype) { case isc_socktype_udp: @@ -1793,13 +1512,12 @@ disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { startrecv(disp, resp); break; case isc_socktype_tcp: - if (disp->handle == NULL) { - LOCK(&disp->lock); - isc_nmhandle_attach(handle, &disp->handle); - disp->attributes |= DNS_DISPATCHATTR_CONNECTED; - UNLOCK(&disp->lock); - startrecv(disp, resp); - } + 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); @@ -1807,6 +1525,10 @@ disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } } + if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { + eresult = ISC_R_SHUTTINGDOWN; + } + if (resp->connected != NULL) { resp->connected(handle, eresult, resp->arg); } @@ -1829,11 +1551,6 @@ dns_dispatch_connect(dns_dispentry_t *resp) { switch (disp->socktype) { case isc_socktype_tcp: INSIST(disp->handle == NULL); - if (disp->handle != NULL) { - /* We are already connected */ - break; - } - isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer, disp_connected, resp, resp->timeout, 0); break; @@ -1866,7 +1583,6 @@ send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { void dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { isc_nmhandle_t *handle = NULL; - dns_dispentry_t *tmp = NULL; REQUIRE(VALID_RESPONSE(resp)); @@ -1888,7 +1604,7 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { } #endif - dispentry_attach(resp, &tmp); /* detached in send_done() */ + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); isc_nm_send(handle, r, send_done, resp); } @@ -1996,9 +1712,8 @@ dns_dispatchset_get(dns_dispatchset_t *dset) { } isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - dns_dispatch_t *source, dns_dispatchset_t **dsetp, - int n) { +dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source, + dns_dispatchset_t **dsetp, int n) { isc_result_t result; dns_dispatchset_t *dset = NULL; dns_dispatchmgr_t *mgr = NULL; @@ -2025,7 +1740,7 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, LOCK(&mgr->lock); for (i = 1; i < n; i++) { dset->dispatches[i] = NULL; - result = dispatch_createudp(mgr, taskmgr, &source->local, + result = dispatch_createudp(mgr, &source->local, source->attributes, &dset->dispatches[i]); if (result != ISC_R_SUCCESS) { diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 70a6f42623..e467c964e7 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -60,31 +60,6 @@ ISC_LANG_BEGINDECLS -/*% - * This event is sent to a task when a response comes in. - * No part of this structure should ever be modified by the caller, - * other than parts of the buffer. The holy parts of the buffer are - * the base and size of the buffer. All other parts of the buffer may - * be used. On event delivery the used region contains the packet. - * - * "id" is the received message id, - * - * "addr" is the host that sent it to us, - * - * "buffer" holds state on the received data. - * - * The "free" routine for this event will clean up itself as well as - * any buffer space allocated from common pools. - */ - -struct dns_dispatchevent { - ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */ - isc_result_t result; /*%< result code */ - isc_region_t region; /*%< data region */ - isc_buffer_t buffer; /*%< data buffer */ - dns_dispatch_t *dispatch; -}; - /*% * This is a set of one or more dispatches which can be retrieved * round-robin fashion. @@ -219,9 +194,8 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); */ isc_result_t -dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, - const isc_sockaddr_t *localaddr, unsigned int attributes, - dns_dispatch_t **dispp); +dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, + unsigned int attributes, dns_dispatch_t **dispp); /*%< * Create a new UDP dispatch. * @@ -237,8 +211,7 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, */ isc_result_t -dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, - const isc_sockaddr_t *localaddr, +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); /*%< @@ -250,8 +223,6 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_taskmgr_t *taskmgr, * *\li sock is a valid. * - *\li task is a valid task that can be used internally to this dispatcher. - * * Returns: *\li ISC_R_SUCCESS -- success. * @@ -320,33 +291,28 @@ 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, 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_nm_cb_t timedout, void *arg, dns_messageid_t *idp, + isc_nm_cb_t connected, isc_nm_cb_t sent, + isc_nm_recv_cb_t response, isc_nm_cb_t timedout, + 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. + * with the dispatch entry object. * * The 'connected' and 'sent' callbacks are run to inform the caller when * the connect and send functions are complete. The 'timedout' callback * is run to inform the caller that a read has timed out; it may optionally - * reset the read timer. + * reset the read timer. The 'response' callback is run for recv results + * (response packets, timeouts, or cancellations). * - * 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. - * - * All three callback functions are sent 'arg' as a parameter. + * All the callback functions are sent 'arg' as a parameter. * * Requires: *\li "idp" be non-NULL. * - *\li "task" "action" and "arg" be set as appropriate. + *\li "response" and "arg" be set as appropriate. * *\li "dest" be non-NULL and valid. * @@ -366,19 +332,13 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, */ void -dns_dispatch_removeresponse(dns_dispentry_t ** resp, - dns_dispatchevent_t **sockevent); +dns_dispatch_removeresponse(dns_dispentry_t **resp); /*%< * Stops the flow of responses for the provided id and destination. - * If "sockevent" is non-NULL, the dispatch event and associated buffer is - * also returned to the system. * * Requires: *\li "resp" != NULL and "*resp" contain a value previously allocated * by dns_dispatch_addresponse(); - * - *\li May only be called from within the task given as the 'task' - * argument to dns_dispatch_addresponse() when allocating '*resp'. */ isc_result_t @@ -456,9 +416,8 @@ dns_dispatchset_get(dns_dispatchset_t *dset); */ isc_result_t -dns_dispatchset_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - dns_dispatch_t *source, dns_dispatchset_t **dsetp, - int n); +dns_dispatchset_create(isc_mem_t *mctx, 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 @@ -480,14 +439,12 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp); */ isc_result_t -dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent); +dns_dispatch_getnext(dns_dispentry_t *resp); /*%< - * Free the sockevent and trigger the sending of the next item off the - * dispatch queue if present. + * Trigger the sending of the next item off the dispatch queue if present. * * Requires: *\li resp is valid - *\li *sockevent to be valid */ ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 6192731846..59d2fb28bd 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -65,7 +65,6 @@ typedef struct dns_dyndbctx dns_dyndbctx_t; typedef struct dns_sdlzimplementation dns_sdlzimplementation_t; typedef struct dns_decompress dns_decompress_t; typedef struct dns_dispatch dns_dispatch_t; -typedef struct dns_dispatchevent dns_dispatchevent_t; typedef struct dns_dispatchlist dns_dispatchlist_t; typedef struct dns_dispatchset dns_dispatchset_t; typedef struct dns_dispatchmgr dns_dispatchmgr_t; diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 354ee64659..10f977cc5a 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -1780,8 +1780,8 @@ dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, isc_result_t dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, - isc_nm_t *netmgr, dns_zonemgr_t **zmgrp); + isc_timermgr_t *timermgr, isc_nm_t *netmgr, + dns_zonemgr_t **zmgrp); /*%< * Create a zone manager. Note: the zone manager will not be able to * manage any zones until dns_zonemgr_setsize() has been run. diff --git a/lib/dns/request.c b/lib/dns/request.c index 9d4bb57f3d..9e00932f79 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -108,7 +108,8 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, isc_mem_t *mctx); static void -req_response(isc_task_t *task, isc_event_t *event); +req_response(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, + void *arg); static void req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void @@ -418,9 +419,8 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr, } } - result = dns_dispatch_createtcp(requestmgr->dispatchmgr, - requestmgr->taskmgr, srcaddr, destaddr, - 0, dscp, dispatchp); + result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr, + destaddr, 0, dscp, dispatchp); return (result); } @@ -449,8 +449,7 @@ udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, return (ISC_R_SUCCESS); } - return (dns_dispatch_createudp(requestmgr->dispatchmgr, - requestmgr->taskmgr, srcaddr, 0, + return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr, 0, dispatchp)); } @@ -479,8 +478,9 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; + dns_request_t *rclone = NULL; isc_result_t result; - isc_mem_t *mctx; + isc_mem_t *mctx = NULL; dns_messageid_t id; bool tcp = false; bool newtcp = false; @@ -511,7 +511,6 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, return (DNS_R_BLACKHOLED); } - request = NULL; result = new_request(mctx, &request); if (result != ISC_R_SUCCESS) { return (result); @@ -565,17 +564,16 @@ again: dispopt |= DNS_DISPATCHOPT_FIXEDID; } - dns_request_t *tmp = NULL; - req_attach(request, &tmp); - + req_attach(request, &rclone); result = dns_dispatch_addresponse( - request->dispatch, dispopt, request->timeout, destaddr, task, + request->dispatch, dispopt, request->timeout, destaddr, 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; connected = false; + req_detach(&rclone); dns_dispatch_detach(&request->dispatch); goto again; } @@ -602,6 +600,7 @@ again: request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; } else { req_send(request); + req_detach(&rclone); } req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request); @@ -645,8 +644,9 @@ dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, dns_request_t **requestp) { dns_request_t *request = NULL; isc_task_t *tclone = NULL; + dns_request_t *rclone = NULL; isc_result_t result; - isc_mem_t *mctx; + isc_mem_t *mctx = NULL; dns_messageid_t id; bool tcp = false; bool connected = false; @@ -720,13 +720,11 @@ use_tcp: goto cleanup; } - dns_request_t *tmp = NULL; - req_attach(request, &tmp); - + req_attach(request, &rclone); result = dns_dispatch_addresponse( - request->dispatch, 0, request->timeout, destaddr, task, - req_connected, req_senddone, req_response, req_timeout, request, - &id, &request->dispentry); + request->dispatch, 0, request->timeout, destaddr, req_connected, + req_senddone, req_response, req_timeout, request, &id, + &request->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -737,8 +735,9 @@ use_tcp: /* * Try again using TCP. */ + req_detach(&rclone); dns_message_renderreset(message); - dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_removeresponse(&request->dispentry); dns_dispatch_detach(&request->dispatch); options |= DNS_REQUESTOPT_TCP; tcp = true; @@ -768,6 +767,7 @@ use_tcp: request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; } else { req_send(request); + req_detach(&rclone); } req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request); @@ -783,6 +783,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_createvia: failed %s", dns_result_totext(result)); @@ -909,7 +912,7 @@ request_cancel(dns_request_t *request) { if (request->dispentry != NULL) { dns_dispatch_cancel(request->dispentry); - dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_removeresponse(&request->dispentry); } dns_dispatch_detach(&request->dispatch); @@ -1024,7 +1027,7 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { request->flags &= ~DNS_REQUEST_F_CONNECTING; if (eresult == ISC_R_TIMEDOUT) { - dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_removeresponse(&request->dispentry); dns_dispatch_detach(&request->dispatch); send_if_done(request, eresult); } else if (DNS_REQUEST_CANCELED(request)) { @@ -1089,32 +1092,31 @@ req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } static void -req_response(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - dns_request_t *request = event->ev_arg; - dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; - isc_region_t r; +req_response(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, + void *arg) { + dns_request_t *request = (dns_request_t *)arg; + + UNUSED(handle); + + if (result == ISC_R_CANCELED) { + return; + } REQUIRE(VALID_REQUEST(request)); - REQUIRE(event->ev_type == DNS_EVENT_DISPATCH); - - UNUSED(task); req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request, - dns_result_totext(devent->result)); + dns_result_totext(result)); LOCK(&request->requestmgr->locks[request->hash]); - result = devent->result; if (result != ISC_R_SUCCESS) { goto done; } /* - * Copy buffer to request. + * Copy region to request. */ - isc_buffer_usedregion(&devent->buffer, &r); - isc_buffer_allocate(request->mctx, &request->answer, r.length); - result = isc_buffer_copyregion(request->answer, &r); + isc_buffer_allocate(request->mctx, &request->answer, region->length); + result = isc_buffer_copyregion(request->answer, region); if (result != ISC_R_SUCCESS) { isc_buffer_free(&request->answer); } @@ -1122,7 +1124,7 @@ done: /* * Cleanup. */ - dns_dispatch_removeresponse(&request->dispentry, &devent); + dns_dispatch_removeresponse(&request->dispentry); request_cancel(request); /* @@ -1206,7 +1208,7 @@ req_destroy(dns_request_t *request) { isc_event_free((isc_event_t **)&request->event); } if (request->dispentry != NULL) { - dns_dispatch_removeresponse(&request->dispentry, NULL); + dns_dispatch_removeresponse(&request->dispentry); } if (request->dispatch != NULL) { dns_dispatch_detach(&request->dispatch); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index ff24608062..406d91118d 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -287,6 +287,7 @@ struct fetchctx { char *info; isc_mem_t *mctx; isc_stdtime_t now; + isc_task_t *task; /* Atomic */ isc_refcount_t references; @@ -608,7 +609,8 @@ empty_bucket(dns_resolver_t *res); static isc_result_t resquery_send(resquery_t *query); static void -resquery_response(isc_task_t *task, isc_event_t *event); +resquery_response(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *arg); static void resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); static void @@ -709,11 +711,10 @@ resume_qmin(isc_task_t *task, isc_event_t *event); */ typedef struct respctx { - isc_task_t *task; - dns_dispatchevent_t *devent; resquery_t *query; fetchctx_t *fctx; isc_result_t result; + isc_buffer_t buffer; unsigned int retryopts; /* updated options to pass to * fctx_query() when resending */ @@ -775,8 +776,8 @@ typedef struct respctx { } respctx_t; static void -rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, - fetchctx_t *fctx, respctx_t *rctx); +rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result, + isc_region_t *region, respctx_t *rctx); static void rctx_answer_init(respctx_t *rctx); @@ -1138,6 +1139,10 @@ resquery_destroy(resquery_t *query) { dns_tsigkey_detach(&query->tsigkey); } + if (query->dispentry != NULL) { + dns_dispatch_removeresponse(&query->dispentry); + } + if (query->dispatch != NULL) { dns_dispatch_detach(&query->dispatch); } @@ -1211,8 +1216,8 @@ update_edns_stats(resquery_t *query) { } static void -fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, - isc_time_t *finish, bool no_response, bool age_untried) { +fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response, + bool age_untried) { fetchctx_t *fctx = NULL; unsigned int rtt, rttms; unsigned int factor; @@ -1394,7 +1399,7 @@ fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, */ if (query->dispentry != NULL) { dns_dispatch_cancel(query->dispentry); - dns_dispatch_removeresponse(&query->dispentry, deventp); + dns_dispatch_removeresponse(&query->dispentry); } if (ISC_LINK_LINKED(query, link)) { @@ -1407,14 +1412,14 @@ fctx_cancelquery(resquery_t *query, dns_dispatchevent_t **deventp, static void fctx_cancelqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { - resquery_t *query, *next_query; + resquery_t *query = NULL, *next_query = NULL; FCTXTRACE("cancelqueries"); for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; query = next_query) { next_query = ISC_LIST_NEXT(query, link); - fctx_cancelquery(query, NULL, NULL, no_response, age_untried); + fctx_cancelquery(query, NULL, no_response, age_untried); } } @@ -1764,8 +1769,7 @@ resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { switch (eresult) { case ISC_R_SUCCESS: - /* Don't detach from resquery */ - return; + goto detach; case ISC_R_HOSTUNREACH: case ISC_R_NETUNREACH: @@ -1781,22 +1785,24 @@ resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { */ add_bad(fctx, query->rmessage, query->addrinfo, eresult, badns_unreachable); - fctx_cancelquery(query, NULL, NULL, true, false); + fctx_cancelquery(query, NULL, true, false); FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); fctx_try(fctx, true, false); break; + case ISC_R_CANCELED: + break; default: FCTXTRACE3("query canceled in resquery_senddone() " "due to unexpected result; responding", eresult); - fctx_cancelquery(query, NULL, NULL, false, false); + fctx_cancelquery(query, NULL, false, false); fctx_done(fctx, eresult, __LINE__); break; } detach: - resquery_detach(&query); + resquery_detach(&query); /* Detach dispatch query */ } static inline isc_result_t @@ -1954,7 +1960,6 @@ 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; resquery_t *query = NULL; isc_sockaddr_t addr; bool have_addr = false; @@ -1964,7 +1969,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, FCTXTRACE("query"); res = fctx->res; - task = res->buckets[fctx->bucketnum].task; srtt = addrinfo->srtt; @@ -2069,8 +2073,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, query->dscp = dscp; } - result = dns_dispatch_createtcp(res->dispatchmgr, res->taskmgr, - &addr, &addrinfo->sockaddr, 0, + result = dns_dispatch_createtcp(res->dispatchmgr, &addr, + &addrinfo->sockaddr, 0, query->dscp, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; @@ -2090,9 +2094,8 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } - result = dns_dispatch_createudp(res->dispatchmgr, - res->taskmgr, &addr, 0, - &query->dispatch); + result = dns_dispatch_createudp(res->dispatchmgr, &addr, + 0, &query->dispatch); if (result != ISC_R_SUCCESS) { goto cleanup_query; } @@ -2147,13 +2150,10 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, fctx->nqueries++; UNLOCK(&res->buckets[fctx->bucketnum].lock); - resquery_t *tmp = NULL; - resquery_attach(query, &tmp); - /* Set up the dispatch and set the query ID */ result = dns_dispatch_addresponse( query->dispatch, 0, isc_interval_ms(&fctx->interval), - &query->addrinfo->sockaddr, task, resquery_connected, + &query->addrinfo->sockaddr, resquery_connected, resquery_senddone, resquery_response, resquery_timeout, query, &query->id, &query->dispentry); if (result != ISC_R_SUCCESS) { @@ -2161,9 +2161,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } /* Connect the socket */ - fctx_increference(fctx); - + resquery_attach(query, &(resquery_t *){ NULL }); /* dispatch query */ result = dns_dispatch_connect(query->dispentry); + + RUNTIME_CHECK(result == ISC_R_SUCCESS); + return (result); cleanup_dispatch: @@ -2720,6 +2722,7 @@ resquery_send(resquery_t *query) { isc_buffer_usedregion(&buffer, &r); + resquery_attach(query, &(resquery_t *){ NULL }); dns_dispatch_send(query->dispentry, &r, query->dscp); QTRACE("sent"); @@ -2755,7 +2758,7 @@ cleanup_message: /* * Stop the dispatcher from listening. */ - dns_dispatch_removeresponse(&query->dispentry, NULL); + dns_dispatch_removeresponse(&query->dispentry); cleanup_temps: if (qname != NULL) { @@ -2771,12 +2774,9 @@ cleanup_temps: static void resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { resquery_t *query = (resquery_t *)arg; - resquery_t *connquery = query; isc_result_t result; fetchctx_t *fctx = NULL; dns_resolver_t *res = NULL; - unsigned int bucketnum; - bool bucket_empty; int pf; REQUIRE(VALID_QUERY(query)); @@ -2788,16 +2788,23 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { fctx = query->fctx; res = fctx->res; - bucketnum = fctx->bucketnum; - - if (atomic_load_acquire(&res->exiting)) { - eresult = ISC_R_SHUTTINGDOWN; - } - if (RESQUERY_CANCELED(query)) { goto detach; } + if (atomic_load_acquire(&fctx->res->exiting)) { + if (eresult == ISC_R_SUCCESS) { + /* + * The reading from the socket has already started at + * this point, so we need to properly cancel the reading + * and then detach the final resquery_t + */ + resquery_attach(query, &(resquery_t *){ NULL }); + dns_dispatch_cancel(query->dispentry); + } + eresult = ISC_R_SHUTTINGDOWN; + } + switch (eresult) { case ISC_R_SUCCESS: /* @@ -2814,8 +2821,9 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { "resquery_send() failed; " "responding"); - fctx_cancelquery(query, NULL, NULL, false, false); + fctx_cancelquery(query, NULL, false, false); fctx_done(fctx, result, __LINE__); + break; } fctx->querysent++; @@ -2831,7 +2839,7 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { dns_rdatatypestats_increment(res->view->resquerystats, fctx->type); } - break; + goto detach; case ISC_R_NETUNREACH: case ISC_R_HOSTUNREACH: @@ -2852,31 +2860,28 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { */ add_bad(fctx, query->rmessage, query->addrinfo, eresult, badns_unreachable); - fctx_cancelquery(query, NULL, NULL, true, false); + fctx_cancelquery(query, NULL, true, false); FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); fctx_try(fctx, true, false); break; + case ISC_R_CANCELED: + break; + default: FCTXTRACE3("query canceled in " "resquery_connected() " "due to unexpected result; responding", eresult); - fctx_cancelquery(query, NULL, NULL, false, false); + fctx_cancelquery(query, NULL, false, false); fctx_done(fctx, eresult, __LINE__); - } - - LOCK(&res->buckets[bucketnum].lock); - bucket_empty = fctx_decreference(fctx); - UNLOCK(&res->buckets[bucketnum].lock); - if (bucket_empty) { - empty_bucket(res); + break; } detach: - resquery_detach(&connquery); + resquery_detach(&query); /* Detach dispatch query */ } static void @@ -4513,7 +4518,6 @@ fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, dns_messageid_t id, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t *fetch, isc_eventtype_t event_type) { - isc_task_t *tclone = NULL; dns_fetchevent_t *event = NULL; /* @@ -4521,10 +4525,9 @@ fctx_add_event(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, * sender field. We'll make the fetch the sender when we * actually send the event. */ - isc_task_attach(task, &tclone); - event = (dns_fetchevent_t *)isc_event_allocate(fctx->res->mctx, tclone, - event_type, action, arg, - sizeof(*event)); + isc_task_attach(task, &(isc_task_t *){ NULL }); + event = (dns_fetchevent_t *)isc_event_allocate( + fctx->res->mctx, task, event_type, action, arg, sizeof(*event)); event->result = DNS_R_SERVFAIL; event->qtype = fctx->type; event->db = NULL; @@ -4579,11 +4582,11 @@ log_ns_ttl(fetchctx_t *fctx, const char *where) { } static isc_result_t -fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, - const dns_name_t *domain, dns_rdataset_t *nameservers, - const isc_sockaddr_t *client, unsigned int options, - unsigned int bucketnum, unsigned int depth, isc_counter_t *qc, - fetchctx_t **fctxp) { +fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, + dns_rdatatype_t type, const dns_name_t *domain, + dns_rdataset_t *nameservers, const isc_sockaddr_t *client, + unsigned int options, unsigned int bucketnum, unsigned int depth, + isc_counter_t *qc, fetchctx_t **fctxp) { fetchctx_t *fctx = NULL; isc_result_t result; isc_result_t iresult; @@ -4606,6 +4609,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, .qmintype = type, .options = options, .res = res, + .task = task, .bucketnum = bucketnum, .dbucketnum = RES_NOBUCKET, .state = fetchstate_init, @@ -7202,17 +7206,22 @@ betterreferral(respctx_t *rctx) { * resquery_send(). Sets up a response context (respctx_t). */ static void -resquery_response(isc_task_t *task, isc_event_t *event) { - isc_result_t result = ISC_R_SUCCESS; - resquery_t *query = event->ev_arg; - dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; - fetchctx_t *fctx; +resquery_response(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *arg) { + isc_result_t result; + resquery_t *query = (resquery_t *)arg; + fetchctx_t *fctx = NULL; respctx_t rctx; + UNUSED(handle); + + if (eresult == ISC_R_CANCELED) { + return; + } + REQUIRE(VALID_QUERY(query)); fctx = query->fctx; REQUIRE(VALID_FCTX(fctx)); - REQUIRE(event->ev_type == DNS_EVENT_DISPATCH); QTRACE("response"); @@ -7222,7 +7231,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { inc_stats(fctx->res, dns_resstatscounter_responsev6); } - rctx_respinit(task, devent, query, fctx, &rctx); + rctx_respinit(query, fctx, eresult, region, &rctx); if (atomic_load_acquire(&fctx->res->exiting)) { result = ISC_R_SHUTTINGDOWN; @@ -7273,9 +7282,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if ((rctx.retryopts & DNS_FETCHOPT_TCP) == 0) { if ((rctx.retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { - dns_adb_setudpsize( - fctx->adb, query->addrinfo, - isc_buffer_usedlength(&devent->buffer)); + dns_adb_setudpsize(fctx->adb, query->addrinfo, + isc_buffer_usedlength(&rctx.buffer)); } else { dns_adb_plainresponse(fctx->adb, query->addrinfo); } @@ -7601,16 +7609,15 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * resquery_response(). */ static void -rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent, resquery_t *query, - fetchctx_t *fctx, respctx_t *rctx) { - *rctx = (respctx_t){ .task = task, - .devent = devent, - .result = devent->result, +rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result, + isc_region_t *region, respctx_t *rctx) { + *rctx = (respctx_t){ .result = result, .query = query, .fctx = fctx, .broken_type = badns_response, .retryopts = query->options }; - + isc_buffer_init(&rctx->buffer, region->base, region->length); + isc_buffer_add(&rctx->buffer, region->length); TIME_NOW(&rctx->tnow); rctx->finish = &rctx->tnow; rctx->now = (isc_stdtime_t)isc_time_seconds(&rctx->tnow); @@ -7675,17 +7682,15 @@ rctx_answer_init(respctx_t *rctx) { */ static isc_result_t rctx_dispfail(respctx_t *rctx) { - dns_dispatchevent_t *devent = rctx->devent; fetchctx_t *fctx = rctx->fctx; resquery_t *query = rctx->query; - if (devent->result == ISC_R_SUCCESS) { + if (rctx->result == ISC_R_SUCCESS) { return (ISC_R_SUCCESS); } - if (devent->result == ISC_R_EOF && - (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) - { + if (rctx->result == ISC_R_EOF && + (rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) { /* * The problem might be that they don't understand * EDNS0. Turn it off and try again. @@ -7704,18 +7709,18 @@ rctx_dispfail(respctx_t *rctx) { * adjust finish and no_response so that we penalize * this address in SRTT adjustment later. */ - if (devent->result == ISC_R_HOSTUNREACH || - devent->result == ISC_R_NETUNREACH || - devent->result == ISC_R_CONNREFUSED || - devent->result == ISC_R_CANCELED) + if (rctx->result == ISC_R_HOSTUNREACH || + rctx->result == ISC_R_NETUNREACH || + rctx->result == ISC_R_CONNREFUSED || + rctx->result == ISC_R_CANCELED) { - rctx->broken_server = devent->result; + rctx->broken_server = rctx->result; rctx->broken_type = badns_unreachable; rctx->finish = NULL; rctx->no_response = true; } } - FCTXTRACE3("dispatcher failure", devent->result); + FCTXTRACE3("dispatcher failure", rctx->result); rctx_done(rctx, ISC_R_SUCCESS); return (ISC_R_COMPLETE); } @@ -7768,7 +7773,7 @@ rctx_parse(respctx_t *rctx) { fetchctx_t *fctx = rctx->fctx; resquery_t *query = rctx->query; - result = dns_message_parse(query->rmessage, &rctx->devent->buffer, 0); + result = dns_message_parse(query->rmessage, &rctx->buffer, 0); if (result == ISC_R_SUCCESS) { return (ISC_R_SUCCESS); } @@ -9336,17 +9341,15 @@ rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) { inc_stats(fctx->res, dns_resstatscounter_retry); fctx_increference(fctx); result = fctx_query(fctx, addrinfo, rctx->retryopts); - if (result == ISC_R_SUCCESS) { - return; - } - - bucketnum = fctx->bucketnum; - fctx_done(fctx, result, __LINE__); - LOCK(&res->buckets[bucketnum].lock); - bucket_empty = fctx_decreference(fctx); - UNLOCK(&res->buckets[bucketnum].lock); - if (bucket_empty) { - empty_bucket(res); + if (result != ISC_R_SUCCESS) { + bucketnum = fctx->bucketnum; + fctx_done(fctx, result, __LINE__); + LOCK(&res->buckets[bucketnum].lock); + bucket_empty = fctx_decreference(fctx); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) { + empty_bucket(res); + } } } @@ -9368,7 +9371,7 @@ rctx_next(respctx_t *rctx) { inc_stats(rctx->fctx->res, dns_resstatscounter_nextitem); INSIST(rctx->query->dispentry != NULL); dns_message_reset(rctx->query->rmessage, DNS_MESSAGE_INTENTPARSE); - result = dns_dispatch_getnext(rctx->query->dispentry, &rctx->devent); + result = dns_dispatch_getnext(rctx->query->dispentry); if (result != ISC_R_SUCCESS) { fctx_done(rctx->fctx, result, __LINE__); } @@ -9399,7 +9402,7 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, result = dns_resolver_createfetch( fctx->res, fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, - NULL, 0, fctx->options, 0, NULL, rctx->task, resume_dslookup, + NULL, 0, fctx->options, 0, NULL, fctx->task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) { if (result == DNS_R_DUPLICATE) { @@ -9437,41 +9440,39 @@ rctx_done(respctx_t *rctx, isc_result_t result) { FCTXTRACE4("query canceled in rctx_done();", rctx->no_response ? "no response" : "responding", result); - /* - * Cancel the query. - */ - if (!rctx->nextitem) { - fctx_cancelquery(query, &rctx->devent, rctx->finish, - rctx->no_response, false); - } - #ifdef ENABLE_AFL if (dns_fuzzing_resolver && (rctx->next_server || rctx->resend || rctx->nextitem)) { - if (rctx->nextitem) { - fctx_cancelquery(query, &rctx->devent, rctx->finish, - rctx->no_response, false); - } + fctx_cancelquery(query, rctx->finish, rctx->no_response, false); fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); - return; - } else + goto detach; + } #endif /* ifdef ENABLE_AFL */ - if (rctx->next_server) - { + + if (rctx->nextitem) { + REQUIRE(!rctx->next_server); + REQUIRE(!rctx->resend); + + result = rctx_next(rctx); + if (result == ISC_R_SUCCESS) { + goto detach; + } + } + + /* Cancel the query */ + fctx_cancelquery(query, rctx->finish, rctx->no_response, false); + + if (rctx->next_server) { rctx_nextserver(rctx, message, addrinfo, result); } else if (rctx->resend) { rctx_resend(rctx, addrinfo); - } else if (rctx->nextitem) { - if (rctx_next(rctx) != ISC_R_SUCCESS) { - resquery_detach(&query); - } } else if (result == DNS_R_CHASEDSSERVERS) { rctx_chaseds(rctx, message, addrinfo, result); } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) { /* - * All has gone well so far, but we are waiting for the - * DNSSEC validator to validate the answer. + * All has gone well so far, but we are waiting for the DNSSEC + * validator to validate the answer. */ FCTXTRACE("wait for validator"); fctx_cancelqueries(fctx, true, false); @@ -9482,6 +9483,7 @@ rctx_done(respctx_t *rctx, isc_result_t result) { fctx_done(fctx, result, __LINE__); } +detach: dns_message_detach(&message); } @@ -9539,7 +9541,7 @@ rctx_logpacket(respctx_t *rctx) { dns_dt_send(fctx->res->view, dtmsgtype, la, &rctx->query->addrinfo->sockaddr, ((rctx->query->options & DNS_FETCHOPT_TCP) != 0), &zr, - &rctx->query->start, NULL, &rctx->devent->buffer); + &rctx->query->start, NULL, &rctx->buffer); #endif /* HAVE_DNSTAP */ } @@ -9960,12 +9962,12 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, } if (dispatchv4 != NULL) { - dns_dispatchset_create(view->mctx, taskmgr, dispatchv4, + dns_dispatchset_create(view->mctx, dispatchv4, &res->dispatches4, ndisp); } if (dispatchv6 != NULL) { - dns_dispatchset_create(view->mctx, taskmgr, dispatchv6, + dns_dispatchset_create(view->mctx, dispatchv6, &res->dispatches6, ndisp); } @@ -10156,8 +10158,7 @@ dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) { void dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, isc_event_t **eventp) { - isc_task_t *tclone; - isc_event_t *event; + isc_event_t *event = NULL; REQUIRE(VALID_RESOLVER(res)); REQUIRE(eventp != NULL); @@ -10176,9 +10177,8 @@ dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, event->ev_sender = res; isc_task_send(task, &event); } else { - tclone = NULL; - isc_task_attach(task, &tclone); - event->ev_sender = tclone; + isc_task_attach(task, &(isc_task_t *){ NULL }); + event->ev_sender = task; ISC_LIST_APPEND(res->whenshutdown, event, ev_link); } @@ -10473,7 +10473,7 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, } if (fctx == NULL) { - result = fctx_create(res, name, type, domain, nameservers, + result = fctx_create(res, task, name, type, domain, nameservers, client, options, bucketnum, depth, qc, &fctx); if (result != ISC_R_SUCCESS) { diff --git a/lib/dns/zone.c b/lib/dns/zone.c index d2e1b75bbf..5fbe523b22 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -590,7 +590,6 @@ struct dns_zonemgr { isc_refcount_t refs; isc_taskmgr_t *taskmgr; isc_timermgr_t *timermgr; - isc_socketmgr_t *socketmgr; isc_nm_t *netmgr; isc_taskpool_t *zonetasks; isc_taskpool_t *loadtasks; @@ -18735,8 +18734,8 @@ zonemgr_keymgmt_find(dns_zonemgr_t *zmgr, dns_zone_t *zone, isc_result_t dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, - isc_nm_t *netmgr, dns_zonemgr_t **zmgrp) { + isc_timermgr_t *timermgr, isc_nm_t *netmgr, + dns_zonemgr_t **zmgrp) { dns_zonemgr_t *zmgr; isc_result_t result; @@ -18746,7 +18745,6 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_mem_attach(mctx, &zmgr->mctx); zmgr->taskmgr = taskmgr; zmgr->timermgr = timermgr; - zmgr->socketmgr = socketmgr; zmgr->netmgr = netmgr; zmgr->zonetasks = NULL; zmgr->loadtasks = NULL; diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index 84f3be07e1..2890b56a3f 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -98,7 +98,6 @@ typedef struct isc_nm_http_endpoints isc_nm_http_endpoints_t; #endif /* HAVE_LIBNGHTTP2 */ typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *); -typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *, int); /* The following cannot be listed alphabetically due to forward reference */ typedef isc_result_t(isc_httpdaction_t)( diff --git a/lib/ns/client.c b/lib/ns/client.c index 34d94d15e7..f06f9bda79 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -2413,6 +2413,7 @@ ns_clientmgr_create(ns_server_t *sctx, isc_taskmgr_t *taskmgr, result = isc_task_create_bound(manager->taskmgr, 20, &manager->task, manager->tid); RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_task_setname(manager->task, "clientmgr", NULL); isc_refcount_init(&manager->references, 1); manager->sctx = NULL; diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 9dbde5f76c..ae552a9656 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -74,7 +73,6 @@ struct ns_interface { isc_sockaddr_t addr; /*%< Address and port. */ unsigned int flags; /*%< Interface flags */ char name[32]; /*%< Null terminated. */ - isc_socket_t * tcpsocket; /*%< TCP socket. */ isc_nmsocket_t * udplistensocket; isc_nmsocket_t * tcplistensocket; isc_nmsocket_t * http_listensocket; diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 2590794285..72b86dc0c9 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -698,10 +698,6 @@ ns_interface_destroy(ns_interface_t *ifp) { ns_interface_shutdown(ifp); - if (ifp->tcpsocket != NULL) { - isc_socket_detach(&ifp->tcpsocket); - } - isc_mutex_destroy(&ifp->lock); ns_interfacemgr_detach(&ifp->mgr); From e317386090c6b18bf4d7c688dd2048de325aef28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 3 Aug 2021 15:27:06 +0200 Subject: [PATCH 22/28] dispatch: Remove 'timeout' callback - It is no longer necessary to pass a 'timeout' callback to dns_dispatch_addresponse(); timeouts are handled directly by the 'response' callback instead. - The netmgr handle is no longer passed to dispatch callbacks, since they don't (and can't) use it. instead, dispatch_cb_t now takes a result code, region, and argument. - Cleaned up timeout-related tests in dispatch_test.c --- bin/nsupdate/nsupdate.c | 3 +- lib/dns/dispatch.c | 80 +++++++++++++++++++++------------- lib/dns/include/dns/dispatch.h | 13 ++++-- lib/dns/request.c | 67 ++++++++++++---------------- lib/dns/resolver.c | 75 ++++++++++++++----------------- 5 files changed, 122 insertions(+), 116 deletions(-) diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 9502fc8299..320e3812c0 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -741,8 +741,9 @@ doshutdown(void) { static void maybeshutdown(void) { /* when called from getinput, doshutdown might be already finished */ - if (requestmgr == NULL) + if (requestmgr == NULL) { return; + } ddebug("Shutting down request manager"); dns_requestmgr_shutdown(requestmgr); diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 08936b43c2..0475d67055 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -61,8 +61,6 @@ struct dns_dispatchmgr { /* locked by buffer_lock */ dns_qid_t *qid; - isc_mutex_t buffer_lock; - unsigned int buffers; in_port_t *v4ports; /*%< available ports for IPv4 */ unsigned int nv4ports; /*%< # of available ports for IPv4 */ @@ -84,10 +82,9 @@ struct dns_dispentry { isc_sockaddr_t peer; in_port_t port; dns_messageid_t id; - isc_nm_cb_t connected; - isc_nm_cb_t sent; - isc_nm_recv_cb_t response; - isc_nm_cb_t timedout; + dispatch_cb_t connected; + dispatch_cb_t sent; + dispatch_cb_t response; void *arg; bool canceled; ISC_LINK(dns_dispentry_t) link; @@ -433,7 +430,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, isc_sockaddr_t peer; isc_netaddr_t netaddr; int match; - isc_nm_recv_cb_t response = NULL; + dispatch_cb_t response = NULL; bool nomore = true; REQUIRE(VALID_RESPONSE(resp)); @@ -444,10 +441,8 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, LOCK(&disp->lock); if (isc_log_wouldlog(dns_lctx, LVL(90))) { - LOCK(&disp->mgr->buffer_lock); - dispatch_log(disp, LVL(90), "got packet: requests %d", + dispatch_log(disp, LVL(90), "got UDP packet: requests %d", disp->requests); - UNLOCK(&disp->mgr->buffer_lock); } if (eresult == ISC_R_CANCELED) { @@ -466,13 +461,13 @@ 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_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) { /* @@ -549,7 +544,7 @@ unlock: UNLOCK(&disp->lock); if (response != NULL) { - response(handle, eresult, region, resp->arg); + response(eresult, region, resp->arg); } if (nomore) { @@ -703,7 +698,7 @@ unlock: dispentry_detach(&resp0); if (resp != NULL) { - resp->response(handle, eresult, region, resp->arg); + resp->response(eresult, region, resp->arg); } } @@ -789,7 +784,6 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm, isc_nm_attach(nm, &mgr->nm); isc_mutex_init(&mgr->lock); - isc_mutex_init(&mgr->buffer_lock); ISC_LIST_INIT(mgr->list); @@ -868,8 +862,6 @@ dispatchmgr_destroy(dns_dispatchmgr_t *mgr) { qid_destroy(mgr->mctx, &mgr->qid); - isc_mutex_destroy(&mgr->buffer_lock); - if (mgr->blackhole != NULL) { dns_acl_detach(&mgr->blackhole); } @@ -1271,10 +1263,9 @@ dns_dispatch_detach(dns_dispatch_t **dispp) { isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, unsigned int timeout, const isc_sockaddr_t *dest, - isc_nm_cb_t connected, isc_nm_cb_t sent, - isc_nm_recv_cb_t response, isc_nm_cb_t timedout, - void *arg, dns_messageid_t *idp, - dns_dispentry_t **resp) { + dispatch_cb_t connected, dispatch_cb_t sent, + dispatch_cb_t response, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp) { dns_dispentry_t *res = NULL; dns_qid_t *qid = NULL; in_port_t localport = 0; @@ -1282,7 +1273,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, unsigned int bucket; bool ok = false; int i = 0; - isc_nm_recv_cb_t oldest_response = NULL; + dispatch_cb_t oldest_response = NULL; REQUIRE(VALID_DISPATCH(disp)); REQUIRE(dest != NULL); @@ -1323,7 +1314,6 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, .peer = *dest, .connected = connected, .sent = sent, - .timedout = timedout, .response = response, .arg = arg }; @@ -1394,7 +1384,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, UNLOCK(&disp->lock); if (oldest_response != NULL) { - oldest_response(res->handle, ISC_R_CANCELED, NULL, res->arg); + oldest_response(ISC_R_CANCELED, NULL, res->arg); } *idp = id; @@ -1530,7 +1520,7 @@ disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } if (resp->connected != NULL) { - resp->connected(handle, eresult, resp->arg); + resp->connected(eresult, NULL, resp->arg); } detach: @@ -1571,7 +1561,7 @@ send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { REQUIRE(VALID_RESPONSE(resp)); - resp->sent(handle, result, resp->arg); + resp->sent(result, NULL, resp->arg); if (result != ISC_R_SUCCESS) { isc_nm_cancelread(handle); @@ -1580,6 +1570,34 @@ send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { dispentry_detach(&resp); } +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; + + break; + case isc_socktype_tcp: + REQUIRE(disp != NULL && disp->handle == NULL); + + handle = disp->handle; + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + } + + isc_nmhandle_settimeout(handle, timeout); + startrecv(disp, resp); +} + void dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) { isc_nmhandle_t *handle = NULL; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index e467c964e7..a4686724fa 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -279,6 +279,9 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp); *\li 'resp' is valid. */ +void +dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout); + isc_result_t dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, const isc_sockaddr_t *localaddr, bool *connected, @@ -288,13 +291,15 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, * if connected == NULL). */ +typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region, + void *cbarg); + isc_result_t dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, unsigned int timeout, const isc_sockaddr_t *dest, - isc_nm_cb_t connected, isc_nm_cb_t sent, - isc_nm_recv_cb_t response, isc_nm_cb_t timedout, - void *arg, dns_messageid_t *idp, - dns_dispentry_t **resp); + dispatch_cb_t connected, dispatch_cb_t sent, + dispatch_cb_t response, void *arg, + dns_messageid_t *idp, dns_dispentry_t **resp); /*%< * Add a response entry for this dispatch. * diff --git a/lib/dns/request.c b/lib/dns/request.c index 9e00932f79..513ffcbbad 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -108,16 +108,13 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, isc_mem_t *mctx); static void -req_response(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, - void *arg); +req_response(isc_result_t result, isc_region_t *region, void *arg); static void -req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); +req_senddone(isc_result_t eresult, isc_region_t *region, 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_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); +req_connected(isc_result_t eresult, isc_region_t *region, void *arg); static void req_attach(dns_request_t *source, dns_request_t **targetp); static void @@ -567,8 +564,8 @@ again: req_attach(request, &rclone); result = dns_dispatch_addresponse( request->dispatch, dispopt, request->timeout, destaddr, - req_connected, req_senddone, req_response, req_timeout, request, - &id, &request->dispentry); + req_connected, req_senddone, req_response, request, &id, + &request->dispentry); if (result != ISC_R_SUCCESS) { if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) { newtcp = true; @@ -723,8 +720,7 @@ use_tcp: req_attach(request, &rclone); result = dns_dispatch_addresponse( request->dispatch, 0, request->timeout, destaddr, req_connected, - req_senddone, req_response, req_timeout, request, &id, - &request->dispentry); + req_senddone, req_response, request, &id, &request->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -1007,10 +1003,10 @@ dns_request_destroy(dns_request_t **requestp) { *** Private: request. ***/ static void -req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { +req_connected(isc_result_t eresult, isc_region_t *region, void *arg) { dns_request_t *request = (dns_request_t *)arg; - UNUSED(handle); + UNUSED(region); req_log(ISC_LOG_DEBUG(3), "req_connected: request %p: %s", request, isc_result_totext(eresult)); @@ -1044,13 +1040,13 @@ req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } static void -req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { +req_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { dns_request_t *request = (dns_request_t *)arg; REQUIRE(VALID_REQUEST(request)); REQUIRE(DNS_REQUEST_SENDING(request)); - UNUSED(handle); + UNUSED(region); req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); @@ -1072,42 +1068,37 @@ req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } static void -req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { +req_response(isc_result_t result, isc_region_t *region, void *arg) { dns_request_t *request = (dns_request_t *)arg; - REQUIRE(VALID_REQUEST(request)); - - UNUSED(eresult); - - req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); - - LOCK(&request->requestmgr->locks[request->hash]); - if (--request->udpcount != 0) { - isc_nmhandle_settimeout(handle, request->timeout); - if (!DNS_REQUEST_SENDING(request)) { - req_send(request); - } - } - UNLOCK(&request->requestmgr->locks[request->hash]); -} - -static void -req_response(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, - void *arg) { - dns_request_t *request = (dns_request_t *)arg; - - UNUSED(handle); - if (result == ISC_R_CANCELED) { return; } + if (result == ISC_R_TIMEDOUT) { + req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); + + LOCK(&request->requestmgr->locks[request->hash]); + if (--request->udpcount != 0) { + dns_dispatch_read(request->dispentry, request->timeout); + if (!DNS_REQUEST_SENDING(request)) { + req_send(request); + } + UNLOCK(&request->requestmgr->locks[request->hash]); + return; + } + + /* The lock is unlocked below */ + goto done; + } + REQUIRE(VALID_REQUEST(request)); req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request, dns_result_totext(result)); LOCK(&request->requestmgr->locks[request->hash]); + if (result != ISC_R_SUCCESS) { goto done; } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 406d91118d..72387fdfcb 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -609,10 +609,9 @@ empty_bucket(dns_resolver_t *res); static isc_result_t resquery_send(resquery_t *query); static void -resquery_response(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *arg); +resquery_response(isc_result_t eresult, isc_region_t *region, void *arg); static void -resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg); +resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg); static void fctx_try(fetchctx_t *fctx, bool retrying, bool badcache); static isc_result_t @@ -1391,11 +1390,8 @@ fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response, } /* - * Check for any outstanding socket events. If they exist, - * cancel them and let the event handlers finish the cleanup. - * (XXX: Currently the resolver, rather than dispatch, tracks - * whether it's sending or connecting; this will be moved into - * dispatch later.) + * Check for any outstanding dispatch responses. If they exist, + * cancel them and let their callbacks finish the cleanup. */ if (query->dispentry != NULL) { dns_dispatch_cancel(query->dispentry); @@ -1406,7 +1402,6 @@ fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response, ISC_LIST_UNLINK(fctx->queries, query, link); } - /* This is the final detach matching the "init" */ resquery_detach(&query); } @@ -1481,12 +1476,6 @@ fctx_cleanupaltaddrs(fetchctx_t *fctx) { } } -static inline void -fctx_stopqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { - FCTXTRACE("stopqueries"); - fctx_cancelqueries(fctx, no_response, age_untried); -} - static inline void fctx_cleanupall(fetchctx_t *fctx) { fctx_cleanupfinds(fctx); @@ -1741,7 +1730,7 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { fctx->qmin_warning = ISC_R_SUCCESS; - fctx_stopqueries(fctx, no_response, age_untried); + fctx_cancelqueries(fctx, no_response, age_untried); LOCK(&res->buckets[fctx->bucketnum].lock); @@ -1753,13 +1742,13 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { } static void -resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { +resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { resquery_t *query = (resquery_t *)arg; fetchctx_t *fctx = NULL; QTRACE("senddone"); - UNUSED(handle); + UNUSED(region); fctx = query->fctx; @@ -1802,7 +1791,7 @@ resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } detach: - resquery_detach(&query); /* Detach dispatch query */ + resquery_detach(&query); } static inline isc_result_t @@ -1893,25 +1882,20 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { isc_time_nowplusinterval(&fctx->next_timeout, &fctx->interval); } -static void -resquery_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { - resquery_t *query = (resquery_t *)arg; +static isc_result_t +resquery_timeout(resquery_t *query) { fetchctx_t *fctx = query->fctx; dns_fetchevent_t *event = NULL, *next = NULL; uint64_t timeleft; isc_time_t now; - REQUIRE(VALID_FCTX(fctx)); - FCTXTRACE("timeout"); /* * If not configured for serve-stale, do nothing. */ - if (eresult == ISC_R_CANCELED || - (fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) == 0) - { - return; + if ((fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) == 0) { + return (ISC_R_SUCCESS); } /* @@ -1922,7 +1906,7 @@ resquery_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { isc_time_now(&now); timeleft = isc_time_microdiff(&fctx->expires_try_stale, &now); if (timeleft >= US_PER_MSEC) { - return; + return (ISC_R_SUCCESS); } /* @@ -1950,9 +1934,12 @@ resquery_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { * resume waiting. */ timeleft = isc_time_microdiff(&fctx->next_timeout, &now); - if (timeleft < US_PER_MSEC) { - isc_nmhandle_settimeout(handle, (timeleft / US_PER_MSEC)); + if (timeleft >= US_PER_MSEC) { + dns_dispatch_read(query->dispentry, (timeleft / US_PER_MSEC)); + return (ISC_R_COMPLETE); } + + return (ISC_R_SUCCESS); } static isc_result_t @@ -2154,14 +2141,14 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, result = dns_dispatch_addresponse( query->dispatch, 0, isc_interval_ms(&fctx->interval), &query->addrinfo->sockaddr, resquery_connected, - resquery_senddone, resquery_response, resquery_timeout, query, - &query->id, &query->dispentry); + resquery_senddone, resquery_response, query, &query->id, + &query->dispentry); if (result != ISC_R_SUCCESS) { goto cleanup_dispatch; } /* Connect the socket */ - resquery_attach(query, &(resquery_t *){ NULL }); /* dispatch query */ + resquery_attach(query, &(resquery_t *){ NULL }); result = dns_dispatch_connect(query->dispentry); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -2772,7 +2759,7 @@ cleanup_temps: } static void -resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { +resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { resquery_t *query = (resquery_t *)arg; isc_result_t result; fetchctx_t *fctx = NULL; @@ -2783,7 +2770,7 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { QTRACE("connected"); - UNUSED(handle); + UNUSED(region); fctx = query->fctx; res = fctx->res; @@ -2881,7 +2868,7 @@ resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } detach: - resquery_detach(&query); /* Detach dispatch query */ + resquery_detach(&query); } static void @@ -4405,7 +4392,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { * fetch, and clean up finds and addresses. To avoid deadlock * with the ADB, we must do this before we lock the bucket lock. */ - fctx_stopqueries(fctx, false, false); + fctx_cancelqueries(fctx, false, false); fctx_cleanupall(fctx); LOCK(&res->buckets[bucketnum].lock); @@ -7206,15 +7193,12 @@ betterreferral(respctx_t *rctx) { * resquery_send(). Sets up a response context (respctx_t). */ static void -resquery_response(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *arg) { +resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) { isc_result_t result; resquery_t *query = (resquery_t *)arg; fetchctx_t *fctx = NULL; respctx_t rctx; - UNUSED(handle); - if (eresult == ISC_R_CANCELED) { return; } @@ -7225,6 +7209,13 @@ resquery_response(isc_nmhandle_t *handle, isc_result_t eresult, QTRACE("response"); + if (eresult == ISC_R_TIMEDOUT) { + result = resquery_timeout(query); + if (result == ISC_R_COMPLETE) { + return; + } + } + if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) { inc_stats(fctx->res, dns_resstatscounter_responsev4); } else { From 8551ad026fe1232f23b2c2778e5d21ca0d785c19 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 3 Aug 2021 18:24:27 -0700 Subject: [PATCH 23/28] dispatch: Fix several connect-related issues - 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 | 6 +- bin/nsupdate/nsupdate.c | 4 +- bin/tests/system/pipelined/pipequeries.c | 2 +- bin/tests/system/tkey/keycreate.c | 3 +- bin/tests/system/tkey/keydelete.c | 3 +- bin/tools/mdig.c | 2 +- lib/dns/client.c | 2 +- lib/dns/dispatch.c | 510 ++++++++++++----------- lib/dns/include/dns/dispatch.h | 100 +---- lib/dns/request.c | 66 +-- lib/dns/resolver.c | 26 +- 11 files changed, 339 insertions(+), 385 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index dd929b881b..31c9af5572 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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; } diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 320e3812c0..4aa9289cb2 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -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)"); } diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c index 238e04c0f1..342ff12039 100644 --- a/bin/tests/system/pipelined/pipequeries.c +++ b/bin/tests/system/pipelined/pipequeries.c @@ -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)); diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c index ab10793a12..79cfdeeb2c 100644 --- a/bin/tests/system/tkey/keycreate.c +++ b/bin/tests/system/tkey/keycreate.c @@ -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)); diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c index c81c306a8c..f5a2a17472 100644 --- a/bin/tests/system/tkey/keydelete.c +++ b/bin/tests/system/tkey/keydelete.c @@ -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)); diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index 5be81925d9..2c88c90908 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -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, diff --git a/lib/dns/client.c b/lib/dns/client.c index 83b21bb12e..9902e2d571 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -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; } diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 0475d67055..341ac86308 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -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); + REQUIRE(disp != NULL && disp->handle == NULL); - if (isc_nmhandle_timer_running(disp->handle)) { - isc_nmhandle_settimeout(disp->handle, resp->timeout); - break; - } - - 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_resume(dns_dispentry_t *resp, uint16_t timeout) { + dns_dispatch_t *disp = NULL; + REQUIRE(VALID_RESPONSE(resp)); - dns_dispatch_t *disp = resp->disp; - isc_nmhandle_t *handle = NULL; + disp = resp->disp; - switch (disp->socktype) { - case isc_socktype_udp: - REQUIRE(resp->handle != NULL); + REQUIRE(VALID_DISPATCH(disp)); - handle = resp->handle; - - break; - case isc_socktype_tcp: - REQUIRE(disp != NULL && disp->handle == NULL); - - handle = disp->handle; - break; - default: - INSIST(0); - ISC_UNREACHABLE(); - } - - 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); - } -} - -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; + return; } - INSIST(handle != NULL); - - return (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); + } + } } 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; diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index a4686724fa..93f676f5f9 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -9,10 +9,9 @@ * information regarding copyright ownership. */ -#include +#pragma once -#ifndef DNS_DISPATCH_H -#define DNS_DISPATCH_H 1 +#include /***** ***** Module Info @@ -21,12 +20,12 @@ /*! \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 */ diff --git a/lib/dns/request.c b/lib/dns/request.c index 513ffcbbad..b2b569ddf1 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -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); } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 72387fdfcb..1643b3c0d6 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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) { From 6ea7d59ad2bb9aae7ae2f2c6a995bb2027131e94 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 4 Aug 2021 13:14:11 -0700 Subject: [PATCH 24/28] dispatch: Clean up connect and recv callbacks - disp_connected() has been split into two functions, udp_connected() (which takes 'resp' as an argument) and tcp_connected() (which takes 'disp', and calls the connect callbacks for all pending resps). - In dns_dispatch_connect(), if a connection is already open, we need to detach the dispentry immediately because we won't be running tcp_connected(). - dns_disptach_cancel() also now calls the connect callbacks for pending TCP responses, and the response callbacks for open TCP connections waiting on read. - If udp_connected() runs after dns_dispatch_cancel() has been called, ensure that the caller's connect callback is run. - If a UDP connection fails with EADDRINUSE, we try again up to five times with a different local port number before giving up. - If a TCP connection is canceled while still pending connection, the connect timeout may still fire. we attach the dispatch before connecting to ensure that it won't be detached too soon in this case. - The dispentry is no longer removed from the pending list when deactivating, so that the connect callback can still be run if dns_dispatch_removeresponse() was run while the connecting was pending. - Rewrote dns_dispatch_gettcp() to avoid a data race. - startrecv() and dispatch_getnext() can be called with a NULL resp when using TCP. - Refactored udp_recv() and tcp_recv() and added result logging. - EOF is now treated the same as CANCELED in response callbacks. - ISC_R_SHUTTINGDOWN is sent to the reponse callbacks for all resps if tcp_recv() is triggered by a netmgr shutdown. (response callbacks are *not* sent by udp_recv() in this case.) --- lib/dns/dispatch.c | 444 ++++++++++++++++++-------------- lib/dns/request.c | 48 ++-- lib/dns/resolver.c | 22 +- lib/dns/tests/Makefile.am | 2 + lib/dns/tests/dispatch_test.c | 462 +++++++++++++++++++++++++++++----- lib/dns/tests/dnstest.c | 9 +- lib/dns/tests/dnstest.h | 1 - lib/dns/tests/resolver_test.c | 3 +- lib/dns/tests/zonemgr_test.c | 8 +- lib/ns/tests/nstest.c | 3 +- 10 files changed, 705 insertions(+), 297 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 341ac86308..888ab1f315 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -60,7 +60,6 @@ struct dns_dispatchmgr { unsigned int state; ISC_LIST(dns_dispatch_t) list; - /* locked by buffer_lock */ dns_qid_t *qid; in_port_t *v4ports; /*%< available ports for IPv4 */ @@ -79,6 +78,7 @@ struct dns_dispentry { isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */ unsigned int bucket; unsigned int timeout; + unsigned int retries; isc_sockaddr_t local; isc_sockaddr_t peer; in_port_t port; @@ -91,6 +91,7 @@ struct dns_dispentry { ISC_LINK(dns_dispentry_t) link; ISC_LINK(dns_dispentry_t) alink; ISC_LINK(dns_dispentry_t) plink; + ISC_LINK(dns_dispentry_t) rlink; }; /*% @@ -125,8 +126,8 @@ struct dns_dispatch { isc_refcount_t references; unsigned int shutdown_out : 1; - ISC_LIST(dns_dispentry_t) pending; - ISC_LIST(dns_dispentry_t) active; + dns_displist_t pending; + dns_displist_t active; unsigned int nsockets; unsigned int requests; /*%< how many requests we have */ @@ -301,6 +302,10 @@ setup_socket(dns_dispatch_t *disp, dns_dispentry_t *resp, in_port_t *ports = NULL; in_port_t port; + if (resp->retries++ > 5) { + return (ISC_R_FAILURE); + } + if (isc_sockaddr_pf(&disp->local) == AF_INET) { nports = mgr->nv4ports; ports = mgr->v4ports; @@ -336,10 +341,6 @@ 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); @@ -392,6 +393,13 @@ dispentry_destroy(dns_dispentry_t *resp) { resp->magic = 0; + if (ISC_LINK_LINKED(resp, plink)) { + ISC_LIST_UNLINK(disp->pending, resp, plink); + } + + INSIST(!ISC_LINK_LINKED(resp, alink)); + INSIST(!ISC_LINK_LINKED(resp, rlink)); + if (resp->handle != NULL) { isc_nmhandle_detach(&resp->handle); } @@ -433,11 +441,6 @@ 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) { @@ -459,38 +462,32 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, LOCK(&disp->lock); - if (isc_log_wouldlog(dns_lctx, LVL(90))) { - dispatch_log(disp, LVL(90), "got UDP packet: requests %d", - disp->requests); + dispatch_log(disp, LVL(90), "UDP response %p:%s:requests %d", resp, + isc_result_totext(eresult), disp->requests); + + /* + * The resp may have been deactivated by shutdown; if + * so, we can skip the response callback. + */ + if (ISC_LINK_LINKED(resp, alink)) { + response = resp->response; } - if (eresult == ISC_R_CANCELED) { - /* - * This dispatcher is shutting down. - */ - goto sendevent; - } - - if (!ISC_LINK_LINKED(resp, alink)) { - goto unlock; - } - - id = resp->id; - - 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, or a timeout on a timer that has not been - * reset. It makes no sense to check the address or - * parse the packet, but it will help to return the - * error to the caller. + * socket, a timeout, or the query has been canceled. + * It makes no sense to check the address or parse the + * packet, but we can return the error to the caller. */ - goto sendevent; + goto done; } + INSIST(ISC_LINK_LINKED(resp, alink)); + + peer = isc_nmhandle_peeraddr(handle); + isc_netaddr_fromsockaddr(&netaddr, &peer); + /* * If this is from a blackholed address, drop it. */ @@ -506,18 +503,19 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, dispatch_log(disp, LVL(10), "blackholed packet from %s", netaddrstr); } - goto unlock; + goto next; } /* * Peek into the buffer to see what we can see. */ + id = resp->id; 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 unlock; + goto next; } dispatch_log(disp, LVL(92), @@ -525,12 +523,10 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id); /* - * Look at flags. If query, drop it. If response, - * look to see where it goes. + * Look at the message flags. If it's a query, ignore it. */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { - /* query */ - goto unlock; + goto next; } /* @@ -539,19 +535,23 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, if (resp->id != id || !isc_sockaddr_equal(&peer, &resp->peer)) { dispatch_log(disp, LVL(90), "response doesn't match"); inc_stats(disp->mgr, dns_resstatscounter_mismatch); - goto unlock; + goto next; } -sendevent: /* - * 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. + * We have the right resp, so call the caller back. */ + goto done; - response = resp->response; +next: + /* + * This is the wrong response. Don't call the caller back + * but keep listening. + */ + response = NULL; + dispatch_getnext(disp, resp, resp->timeout); -unlock: +done: UNLOCK(&disp->lock); if (response != NULL) { @@ -580,7 +580,7 @@ static void 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_dispentry_t *resp = NULL; + dns_dispentry_t *resp = NULL, *next = NULL; dns_messageid_t id; isc_result_t dres; unsigned int flags; @@ -590,6 +590,7 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, char buf[ISC_SOCKADDR_FORMATSIZE]; isc_buffer_t source; isc_sockaddr_t peer; + dns_displist_t resps; REQUIRE(VALID_DISPATCH(disp)); @@ -597,35 +598,49 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, LOCK(&disp->lock); - dispatch_log(disp, LVL(90), "got TCP packet: requests %d, buffers %d", - disp->requests, disp->tcpbuffers); + dispatch_log(disp, LVL(90), "TCP read:%s:requests %d, buffers %d", + isc_result_totext(eresult), disp->requests, + disp->tcpbuffers); peer = isc_nmhandle_peeraddr(handle); + ISC_LIST_INIT(resps); 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_SHUTTINGDOWN: + case ISC_R_CANCELED: case ISC_R_EOF: - dispatch_log(disp, LVL(90), "shutting down on EOF"); - goto unlock; + dispatch_log(disp, LVL(90), "shutting down: %s", + isc_result_totext(eresult)); + /* + * If there are any active responses, shut them all down. + */ + for (resp = ISC_LIST_HEAD(disp->active); resp != NULL; + resp = next) { + next = ISC_LIST_NEXT(resp, alink); + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + ISC_LIST_UNLINK(disp->active, resp, alink); + ISC_LIST_APPEND(resps, resp, rlink); + } + goto done; case ISC_R_TIMEDOUT: /* - * Time out the first active response for which - * no event has already been sent. + * Time out the oldest response in the active queue, + * and move it to the end. (We don't remove it from the + * active queue immediately, though, because the callback + * might decide to keep waiting and leave it active.) */ resp = ISC_LIST_HEAD(disp->active); - INSIST(resp != NULL); - - ISC_LIST_UNLINK(disp->active, resp, alink); - ISC_LIST_APPEND(disp->active, resp, alink); - - goto unlock; + if (resp != NULL) { + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + ISC_LIST_UNLINK(disp->active, resp, alink); + ISC_LIST_APPEND(disp->active, resp, alink); + } + goto done; default: if (eresult == ISC_R_CONNECTIONRESET) { @@ -639,11 +654,11 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, "shutting down due to TCP " "receive error: %s: %s", buf, isc_result_totext(eresult)); - goto unlock; + goto done; } - dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", - eresult, region->length, region->base); + dispatch_log(disp, LVL(90), "success, length == %d, addr = %p", + region->length, region->base); /* * Peek into the buffer to see what we can see. @@ -661,13 +676,8 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id); /* - * Allocate an event to send to the query or response client, and - * allocate a new buffer for our use. - */ - - /* - * Look at flags. If query, drop it. If response, - * look to see where it goes. + * Look at the message flags. If it's a query, ignore it + * and keep reading. */ if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* @@ -677,24 +687,37 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, } /* - * We have a response; find the associated dispentry. + * We have a valid response; find the associated dispentry object + * and call the caller back. */ bucket = dns_hash(qid, &peer, id, disp->localport); LOCK(&qid->lock); resp = entry_search(qid, &peer, id, disp->localport, bucket); + if (resp != NULL) { + dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); + } dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); UNLOCK(&qid->lock); next: - /* Restart the reading from the TCP socket */ - dispatch_getnext(disp, resp, -1); + dispatch_getnext(disp, NULL, -1); -unlock: +done: UNLOCK(&disp->lock); if (resp != NULL) { + /* We got a matching response, or timed out */ resp->response(eresult, region, resp->arg); + dispentry_detach(&resp); + } else { + /* We're being shut down; cancel all outstanding resps */ + for (resp = ISC_LIST_HEAD(resps); resp != NULL; resp = next) { + next = ISC_LIST_NEXT(resp, rlink); + ISC_LIST_UNLINK(resps, resp, rlink); + resp->response(ISC_R_SHUTTINGDOWN, region, resp->arg); + dispentry_detach(&resp); + } } dns_dispatch_detach(&disp); @@ -1021,11 +1044,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr, ISC_LIST_APPEND(mgr->list, disp, link); UNLOCK(&mgr->lock); - if (isc_log_wouldlog(dns_lctx, 90)) { - mgr_log(mgr, LVL(90), - "dns_dispatch_createtcp: created TCP dispatch %p", - disp); - } + mgr_log(mgr, LVL(90), "dns_dispatch_createtcp: created TCP dispatch %p", + disp); *dispp = disp; return (ISC_R_SUCCESS); @@ -1035,19 +1055,18 @@ 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; + dns_dispatch_t *disp_connected = NULL; + dns_dispatch_t *disp_fallback = NULL; + isc_result_t result = ISC_R_NOTFOUND; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(destaddr != NULL); REQUIRE(connected != NULL); REQUIRE(dispp != NULL && *dispp == NULL); - /* First pass, look for connected TCP dispatches */ - *connected = true; - LOCK(&mgr->lock); -again: - for (disp = ISC_LIST_HEAD(mgr->list); disp != NULL && *dispp == NULL; + + for (dns_dispatch_t *disp = ISC_LIST_HEAD(mgr->list); disp != NULL; disp = ISC_LIST_NEXT(disp, link)) { isc_sockaddr_t sockname; @@ -1063,56 +1082,57 @@ again: peeraddr = disp->peer; } - if (*connected == true && - atomic_load(&disp->state) != DNS_DISPATCHSTATE_CONNECTED) - { - 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)) - { - 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: + if (disp->socktype == isc_socktype_tcp && + isc_sockaddr_equal(destaddr, &peeraddr) && + (localaddr == NULL || + isc_sockaddr_eqaddr(localaddr, &sockname))) + { + if (atomic_load(&disp->state) == + DNS_DISPATCHSTATE_CONNECTED) { + /* We found connected dispatch */ + disp_connected = disp; + UNLOCK(&disp->lock); + break; + } + + /* We found "a" dispatch, store it for later */ + if (disp_fallback == NULL) { + disp_fallback = disp; + } + + UNLOCK(&disp->lock); + continue; + } + UNLOCK(&disp->lock); } - if (*dispp != NULL) { - UNLOCK(&mgr->lock); - return (ISC_R_SUCCESS); - } + if (disp_connected != NULL) { + /* We found connected dispatch */ + INSIST(disp_connected->handle != NULL); - if (*connected) { - /* Second pass, look also for not-yet-connected dispatch */ + *connected = true; + dns_dispatch_attach(disp_connected, dispp); + + result = ISC_R_SUCCESS; + } else if (disp_fallback != NULL) { + /* We found matching dispatch */ *connected = false; - goto again; + + dns_dispatch_attach(disp_fallback, dispp); + + result = ISC_R_SUCCESS; } UNLOCK(&mgr->lock); - return (ISC_R_NOTFOUND); + + return (result); } isc_result_t @@ -1305,6 +1325,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); + ISC_LINK_INIT(res, rlink); if (disp->socktype == isc_socktype_udp) { isc_result_t result = setup_socket(disp, res, dest, &localport); @@ -1390,21 +1411,20 @@ dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) { 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(); @@ -1418,14 +1438,12 @@ dns_dispatch_getnext(dns_dispentry_t *resp) { REQUIRE(VALID_RESPONSE(resp)); disp = resp->disp; + REQUIRE(VALID_DISPATCH(disp)); LOCK(&disp->lock); - dispatch_getnext(disp, resp, resp->timeout); - UNLOCK(&disp->lock); - return (ISC_R_SUCCESS); } @@ -1485,12 +1503,15 @@ startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp) { break; case isc_socktype_tcp: - REQUIRE(resp != NULL && resp->handle == NULL); - REQUIRE(disp != NULL && disp->handle == NULL); + REQUIRE(disp != NULL); + LOCK(&disp->lock); + REQUIRE(disp->handle == NULL); isc_nmhandle_attach(handle, &disp->handle); dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); isc_nm_read(disp->handle, tcp_recv, disp); + UNLOCK(&disp->lock); + break; default: @@ -1499,51 +1520,88 @@ startrecv(isc_nmhandle_t *handle, 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; +tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { + dns_dispatch_t *disp = (dns_dispatch_t *)arg; + dns_dispentry_t *resp = NULL, *next = NULL; + dns_displist_t resps; - if (eresult == ISC_R_SUCCESS) { - if (resp->canceled) { - dispentry_detach(&resp); - return; - } + dispatch_log(disp, LVL(90), "TCP connected (%p): %s", disp, + isc_result_totext(eresult)); - 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); - } + ISC_LIST_INIT(resps); if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { eresult = ISC_R_SHUTTINGDOWN; } + if (eresult == ISC_R_SUCCESS) { + REQUIRE(atomic_compare_exchange_strong( + &disp->state, + &(uint_fast32_t){ DNS_DISPATCHSTATE_CONNECTING }, + DNS_DISPATCHSTATE_CONNECTED)); + startrecv(handle, disp, NULL); + } + + /* + * If there are pending responses, call the connect + * callbacks for all of them. + */ + LOCK(&disp->lock); + for (resp = ISC_LIST_HEAD(disp->pending); resp != NULL; resp = next) { + next = ISC_LIST_NEXT(resp, plink); + ISC_LIST_UNLINK(disp->pending, resp, plink); + ISC_LIST_APPEND(resps, resp, plink); + } + UNLOCK(&disp->lock); + + for (resp = ISC_LIST_HEAD(resps); resp != NULL; resp = next) { + next = ISC_LIST_NEXT(resp, plink); + ISC_LIST_UNLINK(resps, resp, plink); + + if (resp->connected != NULL) { + resp->connected(eresult, NULL, resp->arg); + } + dispentry_detach(&resp); + } + + dns_dispatch_detach(&disp); +} + +static void +udp_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; + + dispatch_log(disp, LVL(90), "UDP connected (%p): %s", resp, + isc_result_totext(eresult)); + + if (MGR_IS_SHUTTINGDOWN(disp->mgr)) { + eresult = ISC_R_SHUTTINGDOWN; + } + + if (eresult == ISC_R_SUCCESS && resp->canceled) { + eresult = ISC_R_CANCELED; + } else if (eresult == ISC_R_SUCCESS) { + startrecv(handle, disp, resp); + } else if (eresult == ISC_R_ADDRINUSE) { + in_port_t localport = 0; + isc_result_t result; + + /* probably a port collision; try a different one */ + disp->nsockets--; + result = setup_socket(disp, resp, &resp->peer, &localport); + if (result == ISC_R_SUCCESS) { + dns_dispatch_connect(resp); + goto detach; + } + } + if (resp->connected != NULL) { resp->connected(eresult, NULL, resp->arg); } - 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); - } - +detach: dispentry_detach(&resp); } @@ -1556,46 +1614,58 @@ dns_dispatch_connect(dns_dispentry_t *resp) { disp = resp->disp; - /* This will be detached in disp_connected() */ + /* This will be detached once we've connected. */ dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); switch (disp->socktype) { case isc_socktype_tcp: /* - * Check whether the dispatch was already connecting. - * If so, add resp to the pending responses. + * Check whether the dispatch is already connecting + * or connected. */ 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); + LOCK(&disp->lock); + INSIST(ISC_LIST_EMPTY(disp->pending)); + ISC_LIST_APPEND(disp->pending, resp, plink); + UNLOCK(&disp->lock); + dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, - &disp->peer, disp_connected, resp, + &disp->peer, tcp_connected, disp, resp->timeout, 0); break; + case DNS_DISPATCHSTATE_CONNECTING: + /* Connection pending; add resp to the list */ + LOCK(&disp->lock); ISC_LIST_APPEND(disp->pending, resp, plink); - return (ISC_R_SUCCESS); + UNLOCK(&disp->lock); + break; + case DNS_DISPATCHSTATE_CONNECTED: - /* We are already connected, call the connected cb */ + /* We are already connected; call the connected cb */ if (resp->connected != NULL) { resp->connected(ISC_R_SUCCESS, NULL, resp->arg); } - return (ISC_R_SUCCESS); + dispentry_detach(&resp); + break; + default: INSIST(0); ISC_UNREACHABLE(); } break; + case isc_socktype_udp: isc_nm_udpconnect(disp->mgr->nm, &resp->local, &resp->peer, - disp_connected, resp, resp->timeout, 0); + udp_connected, resp, resp->timeout, 0); break; + default: return (ISC_R_NOTIMPLEMENTED); } @@ -1621,6 +1691,7 @@ send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { void dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout) { dns_dispatch_t *disp = NULL; + REQUIRE(VALID_RESPONSE(resp)); disp = resp->disp; @@ -1668,22 +1739,29 @@ dns_dispatch_cancel(dns_dispentry_t *resp) { resp->canceled = true; - /* UDP case. */ + /* Connected UDP */ if (resp->handle != NULL) { isc_nm_cancelread(resp->handle); return; } - /* - * TCP case. We only want to cancel if this is the last resp - * listening on this TCP connection. - */ + /* TCP pending 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); + dispentry_detach(&resp); } - } else if (ISC_LINK_LINKED(resp, alink)) { + return; + } + + /* + * Connected TCP, or unconnected UDP. + * + * If TCP, we don't want to cancel the dispatch + * unless this is the last resp waiting. + */ + 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) { diff --git a/lib/dns/request.c b/lib/dns/request.c index b2b569ddf1..9214225e04 100644 --- a/lib/dns/request.c +++ b/lib/dns/request.c @@ -590,15 +590,15 @@ again: req_send(request); req_detach(&rclone); } else { + request->flags |= DNS_REQUEST_F_CONNECTING; + if (tcp) { + request->flags |= DNS_REQUEST_F_TCP; + } + result = dns_dispatch_connect(request->dispentry); if (result != ISC_R_SUCCESS) { goto unlink; } - 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); @@ -763,14 +763,15 @@ use_tcp: 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; if (tcp) { request->flags |= DNS_REQUEST_F_TCP; } + + result = dns_dispatch_connect(request->dispentry); + if (result != ISC_R_SUCCESS) { + goto unlink; + } } req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request); @@ -908,7 +909,8 @@ send_if_done(dns_request_t *request, isc_result_t result) { void request_cancel(dns_request_t *request) { if (!DNS_REQUEST_CANCELED(request)) { - req_log(ISC_LOG_DEBUG(3), "do_cancel: request %p", request); + req_log(ISC_LOG_DEBUG(3), "request_cancel: request %p", + request); request->flags |= DNS_REQUEST_F_CANCELED; request->flags &= ~DNS_REQUEST_F_CONNECTING; @@ -1006,9 +1008,6 @@ dns_request_destroy(dns_request_t **requestp) { req_detach(&request); } -/*** - *** Private: request. - ***/ static void req_connected(isc_result_t eresult, isc_region_t *region, void *arg) { dns_request_t *request = (dns_request_t *)arg; @@ -1018,13 +1017,9 @@ req_connected(isc_result_t eresult, isc_region_t *region, void *arg) { req_log(ISC_LOG_DEBUG(3), "req_connected: request %p: %s", request, isc_result_totext(eresult)); - if (eresult == ISC_R_CANCELED) { - req_detach(&request); - return; - } - REQUIRE(VALID_REQUEST(request)); - REQUIRE(DNS_REQUEST_CONNECTING(request)); + REQUIRE(DNS_REQUEST_CONNECTING(request) || + DNS_REQUEST_CANCELED(request)); LOCK(&request->requestmgr->locks[request->hash]); request->flags &= ~DNS_REQUEST_F_CONNECTING; @@ -1078,13 +1073,14 @@ static void req_response(isc_result_t result, isc_region_t *region, void *arg) { dns_request_t *request = (dns_request_t *)arg; - if (result == ISC_R_CANCELED) { + req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request, + dns_result_totext(result)); + + if (result == ISC_R_CANCELED || result == ISC_R_EOF) { return; } if (result == ISC_R_TIMEDOUT) { - req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); - LOCK(&request->requestmgr->locks[request->hash]); if (--request->udpcount != 0) { dns_dispatch_resume(request->dispentry, @@ -1102,9 +1098,6 @@ req_response(isc_result_t result, isc_region_t *region, void *arg) { REQUIRE(VALID_REQUEST(request)); - req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request, - dns_result_totext(result)); - LOCK(&request->requestmgr->locks[request->hash]); if (result != ISC_R_SUCCESS) { @@ -1119,11 +1112,14 @@ req_response(isc_result_t result, isc_region_t *region, void *arg) { if (result != ISC_R_SUCCESS) { isc_buffer_free(&request->answer); } + done: /* * Cleanup. */ - dns_dispatch_removeresponse(&request->dispentry); + if (request->dispentry != NULL) { + dns_dispatch_removeresponse(&request->dispentry); + } request_cancel(request); /* diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 1643b3c0d6..ba9b9f01b5 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -1388,8 +1388,8 @@ fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response, } /* - * Check for any outstanding dispatch responses. If they exist, - * cancel them and let their callbacks finish the cleanup. + * Check for any outstanding dispatch responses and if they + * exist, cancel them. */ if (query->dispentry != NULL) { dns_dispatch_cancel(query->dispentry); @@ -1756,6 +1756,7 @@ resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { switch (eresult) { case ISC_R_SUCCESS: + case ISC_R_SHUTTINGDOWN: goto detach; case ISC_R_HOSTUNREACH: @@ -1777,8 +1778,10 @@ resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT); fctx_try(fctx, true, false); break; + case ISC_R_CANCELED: break; + default: FCTXTRACE3("query canceled in resquery_senddone() " "due to unexpected result; responding", @@ -2822,6 +2825,13 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { } goto detach; + case ISC_R_SHUTTINGDOWN: + FCTXTRACE3("shutdown in resquery_connected(): no response", + eresult); + fctx_cancelquery(query, NULL, true, false); + fctx_done(fctx, eresult, __LINE__); + break; + case ISC_R_NETUNREACH: case ISC_R_HOSTUNREACH: case ISC_R_CONNREFUSED: @@ -7193,7 +7203,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) { fetchctx_t *fctx = NULL; respctx_t rctx; - if (eresult == ISC_R_CANCELED) { + if (eresult == ISC_R_CANCELED || eresult == ISC_R_EOF) { return; } @@ -7697,7 +7707,8 @@ rctx_dispfail(respctx_t *rctx) { if (rctx->result == ISC_R_HOSTUNREACH || rctx->result == ISC_R_NETUNREACH || rctx->result == ISC_R_CONNREFUSED || - rctx->result == ISC_R_CANCELED) + rctx->result == ISC_R_CANCELED || + rctx->result == ISC_R_SHUTTINGDOWN) { rctx->broken_server = rctx->result; rctx->broken_type = badns_unreachable; @@ -10827,8 +10838,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, memmove(tmp, algorithms, *algorithms); } tmp[len - 1] |= mask; - /* 'tmp[0]' should contain the length of 'tmp'. - */ + /* tmp[0] should contain the length of 'tmp'. */ *tmp = len; node->data = tmp; /* Free the older bitfield. */ diff --git a/lib/dns/tests/Makefile.am b/lib/dns/tests/Makefile.am index bc7250600f..a90f97c79e 100644 --- a/lib/dns/tests/Makefile.am +++ b/lib/dns/tests/Makefile.am @@ -3,6 +3,7 @@ include $(top_srcdir)/Makefile.top AM_CPPFLAGS += \ $(LIBISC_CFLAGS) \ $(LIBDNS_CFLAGS) \ + $(LIBUV_CFLAGS) \ $(KRB5_CFLAGS) \ -DSRCDIR=\"$(abs_srcdir)\" \ -DBUILDDIR=\"$(abs_builddir)\" @@ -10,6 +11,7 @@ AM_CPPFLAGS += \ LDADD += \ libdnstest.la \ $(LIBISC_LIBS) \ + $(LIBUV_LIBS) \ $(LIBDNS_LIBS) check_LTLIBRARIES = libdnstest.la diff --git a/lib/dns/tests/dispatch_test.c b/lib/dns/tests/dispatch_test.c index b8d083b687..8b64c82ce0 100644 --- a/lib/dns/tests/dispatch_test.c +++ b/lib/dns/tests/dispatch_test.c @@ -25,7 +25,6 @@ #define UNIT_TESTING #include -#include #include #include #include @@ -39,18 +38,31 @@ #include "dnstest.h" +uv_sem_t sem; + /* 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 +#define T_SERVER_INIT 5000 +#define T_SERVER_IDLE 5000 +#define T_SERVER_KEEPALIVE 5000 +#define T_SERVER_ADVERTISED 5000 + +#define T_CLIENT_INIT 2000 +#define T_CLIENT_IDLE 2000 +#define T_CLIENT_KEEPALIVE 2000 +#define T_CLIENT_ADVERTISED 2000 + +#define T_CLIENT_CONNECT 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 isc_sockaddr_t udp_server_addr; +static isc_sockaddr_t udp_connect_addr; +static isc_sockaddr_t tcp_server_addr; +static isc_sockaddr_t tcp_connect_addr; + +const struct in6_addr in6addr_blackhole = { { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1 } } }; static int setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { @@ -96,21 +108,35 @@ setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) { return (fd); } +static void +reset_testdata(void); + static int _setup(void **state) { isc_result_t result; uv_os_sock_t sock = -1; + int r; 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); + udp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0); - server_addr = (isc_sockaddr_t){ .length = 0 }; - sock = setup_ephemeral_port(&server_addr, SOCK_DGRAM); + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0); + + udp_server_addr = (isc_sockaddr_t){ .length = 0 }; + sock = setup_ephemeral_port(&udp_server_addr, SOCK_DGRAM); + if (sock < 0) { + return (-1); + } + close(sock); + + tcp_server_addr = (isc_sockaddr_t){ .length = 0 }; + sock = setup_ephemeral_port(&tcp_server_addr, SOCK_STREAM); if (sock < 0) { return (-1); } @@ -120,9 +146,20 @@ _setup(void **state) { 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); + isc_nm_settimeouts(netmgr, T_SERVER_INIT, T_SERVER_IDLE, + T_SERVER_KEEPALIVE, T_SERVER_ADVERTISED); + + /* + * Use shorter client-side timeouts, to ensure that clients + * time out before the server. + */ + isc_nm_settimeouts(connect_nm, T_CLIENT_INIT, T_CLIENT_IDLE, + T_CLIENT_KEEPALIVE, T_CLIENT_ADVERTISED); + + r = uv_sem_init(&sem, 0); + assert_int_equal(r, 0); + + reset_testdata(); return (0); } @@ -131,6 +168,8 @@ static int _teardown(void **state) { UNUSED(state); + uv_sem_destroy(&sem); + isc_managers_destroy(&connect_nm, NULL, NULL, NULL); assert_null(connect_nm); @@ -151,12 +190,12 @@ make_dispatchset(unsigned int ndisps) { } isc_sockaddr_any(&any); - result = dns_dispatch_createudp(dispatchmgr, taskmgr, &any, 0, &disp); + result = dns_dispatch_createudp(dispatchmgr, &any, &disp); if (result != ISC_R_SUCCESS) { return (result); } - result = dns_dispatchset_create(dt_mctx, taskmgr, disp, &dset, ndisps); + result = dns_dispatchset_create(dt_mctx, disp, &dset, ndisps); dns_dispatch_detach(&disp); return (result); @@ -231,20 +270,29 @@ dispatchset_get(void **state) { } struct { - isc_nmhandle_t *handle; atomic_uint_fast32_t responses; + atomic_uint_fast32_t result; } testdata; static dns_dispatch_t *dispatch = NULL; static dns_dispentry_t *dispentry = NULL; static atomic_bool first = ATOMIC_VAR_INIT(true); +static void +reset_testdata(void) { + atomic_init(&testdata.responses, 0); + atomic_init(&testdata.result, ISC_R_UNSET); +} + static void server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { UNUSED(handle); UNUSED(eresult); UNUSED(cbarg); + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + return; } @@ -281,88 +329,137 @@ nameserver(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, isc_nm_send(handle, &response, server_senddone, NULL); } -static void -response(isc_task_t *task, isc_event_t *event) { - dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; - bool exp_true = true; +static isc_result_t +accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + UNUSED(handle); + UNUSED(cbarg); - UNUSED(task); + return (eresult); +} + +static void +noop_nameserver(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(region); + UNUSED(cbarg); +} + +static void +response_getnext(isc_result_t result, isc_region_t *region, void *arg) { + UNUSED(region); + UNUSED(arg); 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); + + if (atomic_compare_exchange_strong(&first, &(bool){ true }, false)) { + result = dns_dispatch_getnext(dispentry); assert_int_equal(result, ISC_R_SUCCESS); } else { - dns_dispatch_removeresponse(&dispentry, &devent); - isc_nmhandle_detach(&testdata.handle); - isc_app_shutdown(); + uv_sem_post(&sem); } } static void -connected(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { +response(isc_result_t eresult, isc_region_t *region, void *arg) { + UNUSED(region); + UNUSED(arg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + switch (eresult) { + case ISC_R_EOF: + case ISC_R_CANCELED: + case ISC_R_SHUTTINGDOWN: + break; + default: + atomic_fetch_add_relaxed(&testdata.responses, 1); + atomic_store_relaxed(&testdata.result, eresult); + } + + uv_sem_post(&sem); +} + +static void +response_timeout(isc_result_t eresult, isc_region_t *region, void *arg) { + UNUSED(region); + UNUSED(arg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + atomic_store_relaxed(&testdata.result, eresult); + + uv_sem_post(&sem); +} + +static void +connected(isc_result_t eresult, isc_region_t *region, void *cbarg) { isc_region_t *r = (isc_region_t *)cbarg; UNUSED(eresult); + UNUSED(region); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(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); +client_senddone(isc_result_t eresult, isc_region_t *region, void *cbarg) { UNUSED(eresult); + UNUSED(region); UNUSED(cbarg); + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + return; } static void -startit(isc_task_t *task, isc_event_t *event) { - UNUSED(task); - dns_dispatch_connect(dispentry); - isc_event_free(&event); +timeout_connected(isc_result_t eresult, isc_region_t *region, void *cbarg) { + UNUSED(region); + UNUSED(cbarg); + + fprintf(stderr, "%s(..., %s, ...)\n", __func__, + isc_result_totext(eresult)); + + atomic_store_relaxed(&testdata.result, eresult); + + uv_sem_post(&sem); } -/* test dispatch getnext */ static void -dispatch_getnext(void **state) { +dispatch_timeout_tcp_connect(void **state) { isc_result_t result; isc_region_t region; - isc_nmsocket_t *sock = NULL; - isc_task_t *task = NULL; - unsigned char message[12]; - unsigned char rbuf[12]; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; uint16_t id; UNUSED(state); - testdata.handle = NULL; - atomic_init(&testdata.responses, 0); - - result = isc_task_create(taskmgr, 0, &task); - assert_int_equal(result, ISC_R_SUCCESS); + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_blackhole, 0); result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); - 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_nm_listenudp(netmgr, &server_addr, nameserver, NULL, 0, - &sock); + result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr, + &tcp_server_addr, -1, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); region.base = rbuf; region.length = sizeof(rbuf); - result = dns_dispatch_addresponse( - dispatch, 0, 10000, &server_addr, task, connected, - client_senddone, response, NULL, ®ion, &id, &dispentry); + + result = dns_dispatch_addresponse(dispatch, 0, T_CLIENT_CONNECT, + &tcp_server_addr, timeout_connected, + client_senddone, response, ®ion, + &id, &dispentry); assert_int_equal(result, ISC_R_SUCCESS); memset(message, 0, sizeof(message)); @@ -372,26 +469,249 @@ dispatch_getnext(void **state) { region.base = message; region.length = sizeof(message); - result = isc_app_onrun(dt_mctx, task, startit, NULL); + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); + + /* Skip if the IPv6 is not available or not blackholed */ + + result = atomic_load_acquire(&testdata.result); + if (result == ISC_R_ADDRNOTAVAIL || result == ISC_R_CONNREFUSED) { + skip(); + return; + } + + assert_int_equal(result, ISC_R_TIMEDOUT); +} + +static void +dispatch_timeout_tcp_response(void **state __attribute__((unused))) { + isc_result_t result; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; + uint16_t id; + isc_nmsocket_t *sock = NULL; + + UNUSED(state); + + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); assert_int_equal(result, ISC_R_SUCCESS); - result = isc_app_run(); + result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr, + &tcp_server_addr, -1, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); - assert_int_equal(atomic_load_acquire(&testdata.responses), 2); + result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, noop_nameserver, + NULL, accept_cb, NULL, 0, 0, NULL, &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &tcp_server_addr, connected, + client_senddone, response_timeout, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT); isc_nm_stoplistening(sock); isc_nmsocket_close(&sock); assert_null(sock); - /* - * Shutdown nameserver. - */ - isc_task_detach(&task); + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); +} + +static void +dispatch_tcp_response(void **state __attribute__((unused))) { + isc_result_t result; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; + uint16_t id; + isc_nmsocket_t *sock = NULL; + + UNUSED(state); + + tcp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr, + &tcp_server_addr, -1, &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, nameserver, NULL, + accept_cb, NULL, 0, 0, NULL, &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &tcp_server_addr, connected, + client_senddone, response, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_in_range(atomic_load_acquire(&testdata.responses), 1, 2); + assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_SUCCESS); + + /* Cleanup */ + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); +} + +static void +dispatch_timeout_udp_response(void **state __attribute__((unused))) { + isc_result_t result; + isc_region_t region; + unsigned char rbuf[12] = { 0 }; + unsigned char message[12] = { 0 }; + uint16_t id; + isc_nmsocket_t *sock = NULL; + + UNUSED(state); + + udp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createudp(dispatchmgr, &tcp_connect_addr, + &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); + + result = isc_nm_listenudp(netmgr, &udp_server_addr, noop_nameserver, + NULL, 0, &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &udp_server_addr, connected, + client_senddone, response_timeout, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT); + + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); + + dns_dispatch_detach(&dispatch); + dns_dispatchmgr_detach(&dispatchmgr); +} + +/* test dispatch getnext */ +static void +dispatch_getnext(void **state) { + isc_result_t result; + isc_region_t region; + isc_nmsocket_t *sock = NULL; + unsigned char message[12] = { 0 }; + unsigned char rbuf[12] = { 0 }; + uint16_t id; + + UNUSED(state); + + result = dns_dispatchmgr_create(dt_mctx, connect_nm, &dispatchmgr); + assert_int_equal(result, ISC_R_SUCCESS); + + result = dns_dispatch_createudp(dispatchmgr, &udp_connect_addr, + &dispatch); + assert_int_equal(result, ISC_R_SUCCESS); /* - * Shutdown the dispatch. + * Create a local udp nameserver on the loopback. */ + result = isc_nm_listenudp(netmgr, &udp_server_addr, nameserver, NULL, 0, + &sock); + assert_int_equal(result, ISC_R_SUCCESS); + + region.base = rbuf; + region.length = sizeof(rbuf); + result = dns_dispatch_addresponse( + dispatch, 0, T_CLIENT_CONNECT, &udp_server_addr, connected, + client_senddone, response_getnext, ®ion, &id, &dispentry); + assert_int_equal(result, ISC_R_SUCCESS); + + memset(message, 0, sizeof(message)); + message[0] = (id >> 8) & 0xff; + message[1] = id & 0xff; + + region.base = message; + region.length = sizeof(message); + + dns_dispatch_connect(dispentry); + + uv_sem_wait(&sem); + + assert_int_equal(atomic_load_acquire(&testdata.responses), 2); + + /* Cleanup */ + isc_nm_stoplistening(sock); + isc_nmsocket_close(&sock); + assert_null(sock); + + dns_dispatch_removeresponse(&dispentry); dns_dispatch_detach(&dispatch); dns_dispatchmgr_detach(&dispatchmgr); } @@ -399,6 +719,14 @@ dispatch_getnext(void **state) { int main(void) { const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(dispatch_timeout_tcp_connect, + _setup, _teardown), + cmocka_unit_test_setup_teardown(dispatch_timeout_tcp_response, + _setup, _teardown), + cmocka_unit_test_setup_teardown(dispatch_tcp_response, _setup, + _teardown), + cmocka_unit_test_setup_teardown(dispatch_timeout_udp_response, + _setup, _teardown), cmocka_unit_test_setup_teardown(dispatchset_create, _setup, _teardown), cmocka_unit_test_setup_teardown(dispatchset_get, _setup, diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index fac3f25725..990bc8ceb9 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -69,7 +69,6 @@ isc_nm_t *netmgr = NULL; isc_taskmgr_t *taskmgr = NULL; isc_task_t *maintask = NULL; isc_timermgr_t *timermgr = NULL; -isc_socketmgr_t *socketmgr = NULL; dns_zonemgr_t *zonemgr = NULL; bool app_running = false; int ncpus; @@ -100,8 +99,7 @@ cleanup_managers(void) { isc_managers_destroy(netmgr == NULL ? NULL : &netmgr, taskmgr == NULL ? NULL : &taskmgr, - timermgr == NULL ? NULL : &timermgr, - socketmgr == NULL ? NULL : &socketmgr); + timermgr == NULL ? NULL : &timermgr, NULL); if (app_running) { isc_app_finish(); @@ -114,7 +112,7 @@ create_managers(void) { ncpus = isc_os_ncpus(); isc_managers_create(dt_mctx, ncpus, 0, 0, &netmgr, &taskmgr, &timermgr, - &socketmgr); + NULL); CHECK(isc_task_create(taskmgr, 0, &maintask)); return (ISC_R_SUCCESS); @@ -296,8 +294,7 @@ dns_test_setupzonemgr(void) { isc_result_t result; REQUIRE(zonemgr == NULL); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, - &zonemgr); + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &zonemgr); return (result); } diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h index a2c32cc146..adc88913c2 100644 --- a/lib/dns/tests/dnstest.h +++ b/lib/dns/tests/dnstest.h @@ -45,7 +45,6 @@ extern isc_log_t *lctx; 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; diff --git a/lib/dns/tests/resolver_test.c b/lib/dns/tests/resolver_test.c index 2c8b6f4e9a..866498e35e 100644 --- a/lib/dns/tests/resolver_test.c +++ b/lib/dns/tests/resolver_test.c @@ -57,8 +57,7 @@ _setup(void **state) { assert_int_equal(result, ISC_R_SUCCESS); isc_sockaddr_any(&local); - result = dns_dispatch_createudp(dispatchmgr, taskmgr, &local, 0, - &dispatch); + result = dns_dispatch_createudp(dispatchmgr, &local, &dispatch); assert_int_equal(result, ISC_R_SUCCESS); return (0); diff --git a/lib/dns/tests/zonemgr_test.c b/lib/dns/tests/zonemgr_test.c index ca7559e181..694401e871 100644 --- a/lib/dns/tests/zonemgr_test.c +++ b/lib/dns/tests/zonemgr_test.c @@ -62,7 +62,7 @@ zonemgr_create(void **state) { UNUSED(state); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); @@ -80,7 +80,7 @@ zonemgr_managezone(void **state) { UNUSED(state); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); @@ -121,7 +121,7 @@ zonemgr_createzone(void **state) { UNUSED(state); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); @@ -160,7 +160,7 @@ zonemgr_unreachable(void **state) { TIME_NOW(&now); - result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, socketmgr, NULL, + result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &myzonemgr); assert_int_equal(result, ISC_R_SUCCESS); diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 8f49e53047..1df32364e1 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -442,8 +442,7 @@ ns_test_setupzonemgr(void) { isc_result_t result; REQUIRE(zonemgr == NULL); - result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr, NULL, - &zonemgr); + result = dns_zonemgr_create(mctx, taskmgr, timermgr, NULL, &zonemgr); return (result); } From f67f524405e71b73cc1a55e5c12585a757cd356c Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 1 Oct 2021 12:53:31 -0700 Subject: [PATCH 25/28] dispatch: Enforce original timeout when calling _getnext() udp_recv() will call dispatch_getnext() if the message received is invalid or doesn't match; we need to reduce the timeout each time this happens so we can't be starved forever by someone sending garbage packets. --- lib/dns/dispatch.c | 49 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 888ab1f315..41751ed890 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -77,8 +77,9 @@ struct dns_dispentry { dns_dispatch_t *disp; isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */ unsigned int bucket; - unsigned int timeout; unsigned int retries; + unsigned int timeout; + isc_time_t start; isc_sockaddr_t local; isc_sockaddr_t peer; in_port_t port; @@ -427,6 +428,23 @@ dispentry_detach(dns_dispentry_t **respp) { } } +/* + * How long in milliseconds has it been since this dispentry + * started reading? (Only used for UDP, to adjust the timeout + * downward when running getnext.) + */ +static unsigned int +dispentry_runtime(dns_dispentry_t *resp) { + isc_time_t now; + + if (isc_time_isepoch(&resp->start)) { + return (0); + } + + TIME_NOW(&now); + return (isc_time_microdiff(&now, &resp->start) / 1000); +} + /* * General flow: * @@ -452,7 +470,7 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, unsigned int flags; isc_sockaddr_t peer; isc_netaddr_t netaddr; - int match; + int match, timeout; dispatch_cb_t response = NULL; REQUIRE(VALID_RESPONSE(resp)); @@ -549,7 +567,13 @@ next: * but keep listening. */ response = NULL; - dispatch_getnext(disp, resp, resp->timeout); + + timeout = resp->timeout - dispentry_runtime(resp); + if (timeout <= 0) { + eresult = ISC_R_TIMEDOUT; + goto done; + } + dispatch_getnext(disp, resp, resp->timeout - dispentry_runtime(resp)); done: UNLOCK(&disp->lock); @@ -1402,12 +1426,6 @@ 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 }); @@ -1434,6 +1452,7 @@ dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) { isc_result_t dns_dispatch_getnext(dns_dispentry_t *resp) { dns_dispatch_t *disp = NULL; + int32_t timeout; REQUIRE(VALID_RESPONSE(resp)); @@ -1441,8 +1460,17 @@ dns_dispatch_getnext(dns_dispentry_t *resp) { REQUIRE(VALID_DISPATCH(disp)); + if (disp->socktype == isc_socktype_udp) { + timeout = resp->timeout - dispentry_runtime(resp); + if (timeout <= 0) { + return (ISC_R_TIMEDOUT); + } + } else { + timeout = -1; + } + LOCK(&disp->lock); - dispatch_getnext(disp, resp, resp->timeout); + dispatch_getnext(disp, resp, timeout); UNLOCK(&disp->lock); return (ISC_R_SUCCESS); } @@ -1497,6 +1525,7 @@ startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp) { case isc_socktype_udp: REQUIRE(resp != NULL && resp->handle == NULL); + TIME_NOW(&resp->start); isc_nmhandle_attach(handle, &resp->handle); dispentry_attach(resp, &(dns_dispentry_t *){ NULL }); isc_nm_read(resp->handle, udp_recv, resp); From dc1203b426f6e0725cf010f08bae305d919b4bed Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 5 Aug 2021 09:33:53 -0700 Subject: [PATCH 26/28] resolver: Fixed shutdown processing - Prevent shutdown races: attach/detach to dns_resolver in dns_fetch_t and fctx_t; delay destruction of fctx when finds are still active; reference the fctx while canceling; reverse the order of fctx_destroy() and empty_bucket(). - Don't resend queries if fetches have been canceled. - It's possible for fctx_doshutdown() to run before a TCP connection has completed. if the query is not on the queries list, then it is not canceled, but the adbaddrinfo is freed. when tcp_connected() runs later, the query is in an inconstent state. to fix this, we add the query to queries before running dns_dispatch_connect(), instead of in the connect callback. - Combined the five fctx_cleanup* functions into a single one. - Added comments and changed some names to make this code easier to understand. --- lib/dns/resolver.c | 166 ++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 86 deletions(-) diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index ba9b9f01b5..395aa4f92b 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -453,6 +453,7 @@ typedef struct { struct dns_fetch { unsigned int magic; isc_mem_t *mctx; + dns_resolver_t *res; fetchctx_t *private; }; @@ -1404,21 +1405,9 @@ fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response, } static void -fctx_cancelqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { - resquery_t *query = NULL, *next_query = NULL; - - FCTXTRACE("cancelqueries"); - - for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; - query = next_query) { - next_query = ISC_LIST_NEXT(query, link); - fctx_cancelquery(query, NULL, no_response, age_untried); - } -} - -static void -fctx_cleanupfinds(fetchctx_t *fctx) { - dns_adbfind_t *find, *next_find; +fctx_cleanup(fetchctx_t *fctx) { + dns_adbfind_t *find = NULL, *next_find = NULL; + dns_adbaddrinfo_t *addr = NULL, *next_addr = NULL; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); @@ -1429,13 +1418,6 @@ fctx_cleanupfinds(fetchctx_t *fctx) { dns_adb_destroyfind(&find); } fctx->find = NULL; -} - -static void -fctx_cleanupaltfinds(fetchctx_t *fctx) { - dns_adbfind_t *find, *next_find; - - REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL; find = next_find) { @@ -1444,13 +1426,6 @@ fctx_cleanupaltfinds(fetchctx_t *fctx) { dns_adb_destroyfind(&find); } fctx->altfind = NULL; -} - -static void -fctx_cleanupforwaddrs(fetchctx_t *fctx) { - dns_adbaddrinfo_t *addr, *next_addr; - - REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->forwaddrs); addr != NULL; addr = next_addr) { @@ -1458,13 +1433,6 @@ fctx_cleanupforwaddrs(fetchctx_t *fctx) { ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink); dns_adb_freeaddrinfo(fctx->adb, &addr); } -} - -static void -fctx_cleanupaltaddrs(fetchctx_t *fctx) { - dns_adbaddrinfo_t *addr, *next_addr; - - REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->altaddrs); addr != NULL; addr = next_addr) { @@ -1474,12 +1442,17 @@ fctx_cleanupaltaddrs(fetchctx_t *fctx) { } } -static inline void -fctx_cleanupall(fetchctx_t *fctx) { - fctx_cleanupfinds(fctx); - fctx_cleanupaltfinds(fctx); - fctx_cleanupforwaddrs(fctx); - fctx_cleanupaltaddrs(fctx); +static void +fctx_cancelqueries(fetchctx_t *fctx, bool no_response, bool age_untried) { + resquery_t *query = NULL, *next_query = NULL; + + FCTXTRACE("cancelqueries"); + + for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; + query = next_query) { + next_query = ISC_LIST_NEXT(query, link); + fctx_cancelquery(query, NULL, no_response, age_untried); + } } static void @@ -1712,7 +1685,6 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { res = fctx->res; if (result == ISC_R_SUCCESS) { - no_response = true; if (fctx->qmin_warning != ISC_R_SUCCESS) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, @@ -1722,6 +1694,17 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { fctx->info, isc_result_totext(fctx->qmin_warning)); } + + /* + * A success result indicates we got a response to a + * query. That query should be canceled already. If + * there still are any outstanding queries attached to the + * same fctx, then those have *not* gotten a response, + * so we set 'no_response' to true here: that way, when + * we run fctx_cancelqueries() below, the SRTTs will + * be adjusted. + */ + no_response = true; } else if (result == ISC_R_TIMEDOUT) { age_untried = true; } @@ -1756,8 +1739,9 @@ resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { switch (eresult) { case ISC_R_SUCCESS: + case ISC_R_CANCELED: case ISC_R_SHUTTINGDOWN: - goto detach; + break; case ISC_R_HOSTUNREACH: case ISC_R_NETUNREACH: @@ -1779,9 +1763,6 @@ resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) { fctx_try(fctx, true, false); break; - case ISC_R_CANCELED: - break; - default: FCTXTRACE3("query canceled in resquery_senddone() " "due to unexpected result; responding", @@ -2135,6 +2116,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } LOCK(&res->buckets[fctx->bucketnum].lock); + ISC_LIST_APPEND(fctx->queries, query, link); fctx->nqueries++; UNLOCK(&res->buckets[fctx->bucketnum].lock); @@ -2781,15 +2763,6 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { } if (atomic_load_acquire(&fctx->res->exiting)) { - if (eresult == ISC_R_SUCCESS) { - /* - * The reading from the socket has already started at - * this point, so we need to properly cancel the reading - * and then detach the final resquery_t - */ - resquery_attach(query, &(resquery_t *){ NULL }); - dns_dispatch_cancel(query->dispentry); - } eresult = ISC_R_SHUTTINGDOWN; } @@ -2801,8 +2774,7 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { result = resquery_send(query); if (result != ISC_R_SUCCESS) { - FCTXTRACE("query canceled: " - "resquery_send() failed; " + FCTXTRACE("query canceled: resquery_send() failed; " "responding"); fctx_cancelquery(query, NULL, false, false); @@ -2812,7 +2784,6 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { 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); @@ -2823,7 +2794,10 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { dns_rdatatypestats_increment(res->view->resquerystats, fctx->type); } - goto detach; + break; + + case ISC_R_CANCELED: + break; case ISC_R_SHUTTINGDOWN: FCTXTRACE3("shutdown in resquery_connected(): no response", @@ -2857,9 +2831,6 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) { fctx_try(fctx, true, false); break; - case ISC_R_CANCELED: - break; - default: FCTXTRACE3("query canceled in " "resquery_connected() " @@ -2941,10 +2912,10 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { "ISC_R_FAILURE"); fctx_done(fctx, ISC_R_FAILURE, __LINE__); } else if (dodestroy) { - fctx_destroy(fctx); if (bucket_empty) { empty_bucket(res); } + fctx_destroy(fctx); } } @@ -3937,7 +3908,7 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { if (addrinfo == NULL) { /* We have no more addresses. Start over. */ fctx_cancelqueries(fctx, true, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); result = fctx_getaddresses(fctx, badcache); if (result == DNS_R_WAIT) { /* @@ -4200,7 +4171,7 @@ resume_qmin(isc_task_t *task, isc_event_t *event) { * nameservers. */ fctx_cancelqueries(fctx, false, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); } fctx_try(fctx, true, false); @@ -4307,6 +4278,9 @@ fctx_destroy(fetchctx_t *fctx) { } dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); + + dns_resolver_detach(&fctx->res); + isc_mem_free(fctx->mctx, fctx->info); isc_mem_putanddetach(&fctx->mctx, fctx, sizeof(*fctx)); } @@ -4395,11 +4369,14 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { * Shut down anything still running on behalf of this * fetch, and clean up finds and addresses. To avoid deadlock * with the ADB, we must do this before we lock the bucket lock. + * Increment the fctx references to avoid a race. */ + fctx_increference(fctx); fctx_cancelqueries(fctx, false, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); LOCK(&res->buckets[bucketnum].lock); + fctx_decreference(fctx); FCTX_ATTR_SET(fctx, FCTX_ATTR_SHUTTINGDOWN); @@ -4423,10 +4400,10 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { UNLOCK(&res->buckets[bucketnum].lock); if (dodestroy) { - fctx_destroy(fctx); if (bucket_empty) { empty_bucket(res); } + fctx_destroy(fctx); } } @@ -4493,10 +4470,10 @@ fctx_start(isc_task_t *task, isc_event_t *event) { INSIST(!dodestroy); fctx_try(fctx, false, false); } else if (dodestroy) { - fctx_destroy(fctx); if (bucket_empty) { empty_bucket(res); } + fctx_destroy(fctx); } } @@ -4599,7 +4576,6 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, .type = type, .qmintype = type, .options = options, - .res = res, .task = task, .bucketnum = bucketnum, .dbucketnum = RES_NOBUCKET, @@ -4611,6 +4587,8 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, .exitline = -1, /* sentinel */ }; + dns_resolver_attach(res, &fctx->res); + if (qc != NULL) { isc_counter_attach(qc, &fctx->qc); } else { @@ -4864,6 +4842,7 @@ cleanup_nameservers: isc_counter_detach(&fctx->qc); cleanup_fetch: + dns_resolver_detach(&fctx->res); isc_mem_put(mctx, fctx, sizeof(*fctx)); return (result); @@ -5348,8 +5327,7 @@ validated(isc_task_t *task, isc_event_t *event) { if (fctx->validator != NULL) { dns_validator_send(fctx->validator); } else if (sentresponse) { - fctx_done(fctx, result, __LINE__); /* Locks - bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks bucket */ } else if (result == DNS_R_BROKENCHAIN) { isc_result_t tresult; isc_time_t expire; @@ -5365,10 +5343,9 @@ validated(isc_task_t *task, isc_event_t *event) { dns_resolver_addbadcache(res, fctx->name, fctx->type, &expire); } - fctx_done(fctx, result, __LINE__); /* Locks - bucket. */ + fctx_done(fctx, result, __LINE__); /* Locks bucket */ } else { - fctx_try(fctx, true, true); /* Locks bucket. */ + fctx_try(fctx, true, true); /* Locks bucket */ } dns_message_detach(&message); @@ -6900,6 +6877,8 @@ fctx_decreference(fetchctx_t *fctx) { * No one cares about the result of this fetch anymore. */ if (fctx->pending == 0 && fctx->nqueries == 0 && + ISC_LIST_EMPTY(fctx->finds) && + ISC_LIST_EMPTY(fctx->altfinds) && ISC_LIST_EMPTY(fctx->validators) && SHUTTINGDOWN(fctx)) { /* @@ -7698,6 +7677,7 @@ rctx_dispfail(respctx_t *rctx) { * There's no hope for this response. */ rctx->next_server = true; + /* * If this is a network error, mark the server as bad so * that we won't try it for this fetch again. Also @@ -9244,6 +9224,7 @@ static void rctx_nextserver(respctx_t *rctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo, isc_result_t result) { fetchctx_t *fctx = rctx->fctx; + bool retrying = true; if (result == DNS_R_FORMERR) { rctx->broken_server = DNS_R_FORMERR; @@ -9308,13 +9289,14 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message, fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = true; fctx_cancelqueries(fctx, true, false); - fctx_cleanupall(fctx); + fctx_cleanup(fctx); + retrying = false; } /* * Try again. */ - fctx_try(fctx, !rctx->get_nameservers, false); + fctx_try(fctx, retrying, false); } /* @@ -9388,8 +9370,7 @@ rctx_chaseds(respctx_t *rctx, dns_message_t *message, add_bad(fctx, message, addrinfo, result, rctx->broken_type); fctx_cancelqueries(fctx, true, false); - fctx_cleanupfinds(fctx); - fctx_cleanupforwaddrs(fctx); + fctx_cleanup(fctx); n = dns_name_countlabels(fctx->name); dns_name_getlabelsequence(fctx->name, 1, n - 1, fctx->nsname); @@ -9459,6 +9440,15 @@ rctx_done(respctx_t *rctx, isc_result_t result) { /* Cancel the query */ fctx_cancelquery(query, rctx->finish, rctx->no_response, false); + /* + * If nobody's waiting for results, don't resend. + */ + LOCK(&fctx->res->buckets[fctx->bucketnum].lock); + if (ISC_LIST_EMPTY(fctx->events)) { + rctx->resend = false; + } + UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + if (rctx->next_server) { rctx_nextserver(rctx, message, addrinfo, result); } else if (rctx->resend) { @@ -10143,10 +10133,8 @@ dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) { RRTRACE(source, "attach"); - LOCK(&source->lock); REQUIRE(!atomic_load_acquire(&source->exiting)); isc_refcount_increment(&source->references); - UNLOCK(&source->lock); *targetp = source; } @@ -10408,13 +10396,16 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, REQUIRE(sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)); REQUIRE(fetchp != NULL && *fetchp == NULL); + if (atomic_load_acquire(&res->exiting)) { + return (ISC_R_SHUTTINGDOWN); + } + log_fetch(name, type); - /* - * XXXRTH use a mempool? - */ fetch = isc_mem_get(res->mctx, sizeof(*fetch)); - fetch->mctx = NULL; + *fetch = (dns_fetch_t){ 0 }; + + dns_resolver_attach(res, &fetch->res); isc_mem_attach(res->mctx, &fetch->mctx); bucketnum = dns_name_fullhash(name, false) % res->nbuckets; @@ -10522,6 +10513,7 @@ unlock: FTRACE("created"); *fetchp = fetch; } else { + dns_resolver_detach(&fetch->res); isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch)); } @@ -10589,7 +10581,7 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { REQUIRE(DNS_FETCH_VALID(fetch)); fctx = fetch->private; REQUIRE(VALID_FCTX(fctx)); - res = fctx->res; + res = fetch->res; FTRACE("destroyfetch"); @@ -10617,6 +10609,8 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { if (bucket_empty) { empty_bucket(res); } + + dns_resolver_detach(&res); } void From ffbe6268f5f123e5b5cd913e0cdfb9329fb5bccc Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 24 Sep 2021 15:45:57 -0700 Subject: [PATCH 27/28] Corrected several system test issues - serve-stale: dig wasn't always running in background when it should. some of the serve-stale test cases are based on groups of dig calls running simultaneously in the background: the test pauses and resumes running after 'wait'. in some cases the final call to dig in a group wasn't in the background, and this sometimes caused delays that affected later test results. in another case, a test was simplified and made more reliable by running dig in the foreground removing a sleep. - serve-stale: The extension of the dig timeout period from 10 to 11 seconds in commit 5307bf64ce80 was left undone in a few places and has now been completed. - serve-stale: Resolver-query-timeout was set incorrectly. a comment above a test case in serve-stale/tests.sh says: "We configured a long value of 30 seconds for resolver-query-timeout," but resolver-query-timeout was actually set to 10, not 30. this is now fixed. - rpz: Force retransfer of the fast-expire zone, to ensure it's fully loaded in ns3; previously it could have been left unloaded if ns5 wasn't up yet when ns3 attempted the zone transfer. - statistics: The TCP4SendErr counter is incremented when a TCP dispatch is canceled while sending. depending on test timing, this may have happened by the time the statistics are dumped. worked around by ignoring that stat couunter when checking for errors. - hooks: Add a prereq.sh script to prevent running under TSAN. - zero: Disabled the servfail cache so that SERVFAIL is reported only when there actually is a failure, not repeatedly every time the same query is sent. --- bin/tests/system/hooks/prereq.sh | 19 ++++++++ bin/tests/system/qmin/ns5/named.conf.in | 2 +- bin/tests/system/qmin/ns6/named.conf.in | 2 +- bin/tests/system/qmin/ns7/named.conf.in | 2 +- bin/tests/system/rpz/tests.sh | 3 ++ .../system/serve-stale/ns3/named2.conf.in | 4 +- .../system/serve-stale/ns3/named3.conf.in | 2 +- .../system/serve-stale/ns3/named4.conf.in | 2 +- .../system/serve-stale/ns3/named5.conf.in | 2 +- .../system/serve-stale/ns3/named6.conf.in | 2 +- .../system/serve-stale/ns3/named7.conf.in | 2 +- bin/tests/system/serve-stale/tests.sh | 48 ++++++++----------- bin/tests/system/statistics/tests.sh | 11 ++--- bin/tests/system/zero/ns3/named.conf.in | 1 + util/copyrights | 1 + 15 files changed, 59 insertions(+), 44 deletions(-) create mode 100644 bin/tests/system/hooks/prereq.sh diff --git a/bin/tests/system/hooks/prereq.sh b/bin/tests/system/hooks/prereq.sh new file mode 100644 index 0000000000..140acc3d36 --- /dev/null +++ b/bin/tests/system/hooks/prereq.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +. ../conf.sh + +$FEATURETEST --tsan && { + echo_i "TSAN - skipping hooks test" + exit 255 +} + +exit 0 diff --git a/bin/tests/system/qmin/ns5/named.conf.in b/bin/tests/system/qmin/ns5/named.conf.in index b4163ab066..2171a6265a 100644 --- a/bin/tests/system/qmin/ns5/named.conf.in +++ b/bin/tests/system/qmin/ns5/named.conf.in @@ -22,7 +22,7 @@ options { recursion yes; qname-minimization disabled; querylog yes; - resolver-query-timeout 30; + resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; diff --git a/bin/tests/system/qmin/ns6/named.conf.in b/bin/tests/system/qmin/ns6/named.conf.in index c5fe9adc60..ec34d03146 100644 --- a/bin/tests/system/qmin/ns6/named.conf.in +++ b/bin/tests/system/qmin/ns6/named.conf.in @@ -22,7 +22,7 @@ options { recursion yes; qname-minimization strict; querylog yes; - resolver-query-timeout 30; + resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; diff --git a/bin/tests/system/qmin/ns7/named.conf.in b/bin/tests/system/qmin/ns7/named.conf.in index 0f69d2d26b..50fce36c50 100644 --- a/bin/tests/system/qmin/ns7/named.conf.in +++ b/bin/tests/system/qmin/ns7/named.conf.in @@ -22,7 +22,7 @@ options { recursion yes; qname-minimization relaxed; querylog yes; - resolver-query-timeout 30; + resolver-query-timeout 30000; # 30 seconds dnssec-validation no; }; diff --git a/bin/tests/system/rpz/tests.sh b/bin/tests/system/rpz/tests.sh index c888289db4..b88fe62a48 100644 --- a/bin/tests/system/rpz/tests.sh +++ b/bin/tests/system/rpz/tests.sh @@ -453,6 +453,9 @@ make_proto_nodata() { return 0 } +# ensure that the fast-expire zone is populated before we begin testing +$RNDCCMD $ns3 retransfer fast-expire + for mode in native dnsrps; do status=0 case ${mode} in diff --git a/bin/tests/system/serve-stale/ns3/named2.conf.in b/bin/tests/system/serve-stale/ns3/named2.conf.in index 40c053e07f..57919b7bbe 100644 --- a/bin/tests/system/serve-stale/ns3/named2.conf.in +++ b/bin/tests/system/serve-stale/ns3/named2.conf.in @@ -37,9 +37,9 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 0; - stale-answer-client-timeout 1800; + stale-answer-client-timeout 1800; # 1.8 seconds max-stale-ttl 3600; - resolver-query-timeout 10; + resolver-query-timeout 30000; # 30 seconds }; zone "." { diff --git a/bin/tests/system/serve-stale/ns3/named3.conf.in b/bin/tests/system/serve-stale/ns3/named3.conf.in index 7d50bc8ff8..5a840e9cdf 100644 --- a/bin/tests/system/serve-stale/ns3/named3.conf.in +++ b/bin/tests/system/serve-stale/ns3/named3.conf.in @@ -38,7 +38,7 @@ options { stale-answer-ttl 3; stale-refresh-time 0; max-stale-ttl 3600; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds }; zone "." { diff --git a/bin/tests/system/serve-stale/ns3/named4.conf.in b/bin/tests/system/serve-stale/ns3/named4.conf.in index 5fd5ef82f4..af3bd868a2 100644 --- a/bin/tests/system/serve-stale/ns3/named4.conf.in +++ b/bin/tests/system/serve-stale/ns3/named4.conf.in @@ -38,7 +38,7 @@ options { stale-answer-ttl 3; stale-answer-client-timeout 0; stale-refresh-time 0; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds max-stale-ttl 3600; }; diff --git a/bin/tests/system/serve-stale/ns3/named5.conf.in b/bin/tests/system/serve-stale/ns3/named5.conf.in index 92b2cdf108..e62de8bfb1 100644 --- a/bin/tests/system/serve-stale/ns3/named5.conf.in +++ b/bin/tests/system/serve-stale/ns3/named5.conf.in @@ -38,7 +38,7 @@ options { stale-answer-ttl 3; stale-answer-client-timeout 0; stale-refresh-time 4; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds max-stale-ttl 3600; }; diff --git a/bin/tests/system/serve-stale/ns3/named6.conf.in b/bin/tests/system/serve-stale/ns3/named6.conf.in index 2b7c42c456..92c0eaf057 100644 --- a/bin/tests/system/serve-stale/ns3/named6.conf.in +++ b/bin/tests/system/serve-stale/ns3/named6.conf.in @@ -37,7 +37,7 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 4; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds fetches-per-zone 1 fail; fetches-per-server 1 fail; max-stale-ttl 3600; diff --git a/bin/tests/system/serve-stale/ns3/named7.conf.in b/bin/tests/system/serve-stale/ns3/named7.conf.in index 10e77d7d25..c3582ba084 100644 --- a/bin/tests/system/serve-stale/ns3/named7.conf.in +++ b/bin/tests/system/serve-stale/ns3/named7.conf.in @@ -41,7 +41,7 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-refresh-time 4; - resolver-query-timeout 10; + resolver-query-timeout 10000; # 10 seconds fetches-per-zone 1 fail; fetches-per-server 1 fail; max-stale-ttl 3600; diff --git a/bin/tests/system/serve-stale/tests.sh b/bin/tests/system/serve-stale/tests.sh index c49f6647bf..b524630d9e 100755 --- a/bin/tests/system/serve-stale/tests.sh +++ b/bin/tests/system/serve-stale/tests.sh @@ -124,7 +124,7 @@ $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 longttl.example TXT > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+3)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+4)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+5)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+5)) & wait @@ -282,7 +282,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -336,7 +336,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -402,7 +402,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -594,7 +594,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -672,7 +672,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.1 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1006,7 +1006,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1094,7 +1094,7 @@ $DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$((n+3)) & $DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) & -$DIG -p ${PORT} @10.53.0.3 notfound.example TXT > dig.out.test$((n+5)) +$DIG -p ${PORT} @10.53.0.3 notfound.example TXT > dig.out.test$((n+5)) & wait @@ -1247,7 +1247,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.4 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.4 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.4 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.4 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.4 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1453,7 +1453,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.5 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.5 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.5 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.5 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.5 nxdomain.example TXT > dig.out.test$((n+4)) & wait @@ -1651,8 +1651,8 @@ nextpart ns3/named.run > /dev/null echo_i "sending queries for tests $((n+1))-$((n+2))..." t1=`$PERL -e 'print time()'` -$DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & -$DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 nodata.example TXT > dig.out.test$((n+2)) +$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & +$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 nodata.example TXT > dig.out.test$((n+2)) & wait t2=`$PERL -e 'print time()'` @@ -1687,14 +1687,14 @@ status=$((status+ret)) nextpart ns3/named.run > /dev/null echo_i "sending queries for tests $((n+2))-$((n+3))..." -$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 longttl.example TXT > dig.out.test$((n+2)) & +# first dig runs in background for 3 seconds, second in foreground for 3 $DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 longttl.example TXT > dig.out.test$((n+3)) & +$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 longttl.example TXT > dig.out.test$((n+2)) # Enable the authoritative name server after stale-answer-client-timeout. n=$((n+1)) echo_i "enable responses from authoritative server ($n)" ret=0 -sleep 4 $DIG -p ${PORT} @10.53.0.2 txt enable > dig.out.test$n grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1 grep "TXT.\"1\"" dig.out.test$n > /dev/null || ret=1 @@ -1705,25 +1705,17 @@ n=$((n+1)) echo_i "check not in cache longttl.example times out (stale-answer-client-timeout 1.8) ($n)" ret=0 wait_for_log 4 "longttl.example client timeout, stale answer unavailable" ns3/named.run || ret=1 -check_results() { - [ -s "$1" ] || return 1 - grep "connection timed out" "$1" > /dev/null || return 1 - return 0 -} -retry_quiet 4 check_results dig.out.test$n || ret=1 +grep "connection timed out" dig.out.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status+ret)) +wait + n=$((n+1)) echo_i "check not in cache longttl.example comes from authoritative (stale-answer-client-timeout 1.8) ($n)" ret=0 -check_results() { - [ -s "$1" ] || return 1 - grep "status: NOERROR" "$1" > /dev/null || return 1 - grep "ANSWER: 1," "$1" > /dev/null || return 1 - return 0 -} -retry_quiet 8 check_results dig.out.test$n || ret=1 +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status+ret)) @@ -2214,7 +2206,7 @@ echo_i "sending queries for tests $((n+1))-$((n+4))..." $DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$((n+1)) & $DIG -p ${PORT} @10.53.0.3 othertype.example CAA > dig.out.test$((n+2)) & $DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$((n+3)) & -$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) +$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$((n+4)) & wait diff --git a/bin/tests/system/statistics/tests.sh b/bin/tests/system/statistics/tests.sh index 2c44788ce1..b019dfac69 100644 --- a/bin/tests/system/statistics/tests.sh +++ b/bin/tests/system/statistics/tests.sh @@ -11,8 +11,7 @@ . ../conf.sh -DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd" -DIGCMD="$DIG $DIGOPTS -p ${PORT}" +DIGCMD="$DIG +tcp -p ${PORT}" RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../common/rndc.conf" status=0 @@ -163,8 +162,8 @@ n=`expr $n + 1` ret=0 echo_i "checking bind9.xsl vs xml ($n)" if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ] ; then - $DIGCMD +notcp +recurse @10.53.0.3 soa . > /dev/null 2>&1 - $DIGCMD +notcp +recurse @10.53.0.3 soa example > /dev/null 2>&1 + $DIGCMD +notcp +recurse @10.53.0.3 soa . > dig.out.test$n.1 2>&1 + $DIGCMD +notcp +recurse @10.53.0.3 soa example > dig.out.test$n.2 2>&1 ${CURL} http://10.53.0.3:${EXTRAPORT1}/xml/v3 > curl.out.${n}.xml 2>/dev/null || ret=1 ${CURL} http://10.53.0.3:${EXTRAPORT1}/bind9.xsl > curl.out.${n}.xsl 2>/dev/null || ret=1 ${XSLTPROC} curl.out.${n}.xsl - < curl.out.${n}.xml > xsltproc.out.${n} 2>/dev/null || ret=1 @@ -181,7 +180,7 @@ if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ] ; th grep "

View " xsltproc.out.${n} >/dev/null || ret=1 grep "

Server Statistics

" xsltproc.out.${n} >/dev/null || ret=1 grep "

Zone Maintenance Statistics

" xsltproc.out.${n} >/dev/null || ret=1 - grep "

Resolver Statistics (Common)

" xsltproc.out.${n} >/dev/null || ret=1 + # grep "

Resolver Statistics (Common)

" xsltproc.out.${n} >/dev/null || ret=1 grep "

Resolver Statistics for View " xsltproc.out.${n} >/dev/null || ret=1 grep "

ADB Statistics for View " xsltproc.out.${n} >/dev/null || ret=1 grep "

Cache Statistics for View " xsltproc.out.${n} >/dev/null || ret=1 @@ -223,7 +222,7 @@ if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ] ; th grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 - grep "0" stats.xml.out >/dev/null || ret=1 + # grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 grep "0" stats.xml.out >/dev/null || ret=1 diff --git a/bin/tests/system/zero/ns3/named.conf.in b/bin/tests/system/zero/ns3/named.conf.in index aa35d03fc5..39044310c6 100644 --- a/bin/tests/system/zero/ns3/named.conf.in +++ b/bin/tests/system/zero/ns3/named.conf.in @@ -19,6 +19,7 @@ options { listen-on-v6 { none; }; recursion yes; dnssec-validation yes; + servfail-ttl 0; }; zone "." { diff --git a/util/copyrights b/util/copyrights index dff5713217..42ce88bb7e 100644 --- a/util/copyrights +++ b/util/copyrights @@ -399,6 +399,7 @@ ./bin/tests/system/glue/tests.sh SH 2000,2001,2003,2004,2007,2012,2013,2016,2017,2018,2019,2020,2021 ./bin/tests/system/hooks/clean.sh SH 2020,2021 ./bin/tests/system/hooks/driver/test-async.c C 2020,2021 +./bin/tests/system/hooks/prereq.sh SH 2021 ./bin/tests/system/hooks/setup.sh SH 2020,2021 ./bin/tests/system/hooks/tests.sh SH 2020,2021 ./bin/tests/system/idna/clean.sh SH 2018,2019,2020,2021 From d596bd04b68d8a613966b90c87bd101bf05a498c Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 27 Sep 2021 17:51:44 -0700 Subject: [PATCH 28/28] Add CHANGES and release note for [GL #2401] --- CHANGES | 8 ++++++++ doc/notes/notes-current.rst | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/CHANGES b/CHANGES index 0ee3ee6977..ec63783a19 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +5730. [func] The resolver and the request and dispatch managers + have been substantially refactored, and are now + based on the network manager instead of the old + isc_socket API. All outgoing DNS queries and + requests now use the new API; isc_socket is only + used to monitor for network interface changes. + [GL #2401] + 5729. [func] Allow finer control over the TLS protocol by implementing more options within "tls" clauses, namely: - Diffie-Hellman parameters via diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 94a49630be..5fd296f63a 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -66,6 +66,10 @@ Feature Changes 9.16.0 but no error was reported, although sending UDP messages (such as notifies) would fail. :gl:`#2888` +- The network manager API is now used by ``named`` and related tools, + including ``nsupdate``, ``delv``, ``mdig``, to send all outgoing DNS + queries and requests. :gl:`#2401` + Bug Fixes ~~~~~~~~~