From: Evan Hunt Date: Tue, 5 Nov 2019 23:34:35 +0000 (-0800) Subject: convert ns_client and related objects to use netmgr X-Git-Tag: v9.15.6~21^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53f0b6c34d3fe01c885d8020d155061d55c19477;p=thirdparty%2Fbind9.git convert ns_client and related objects to use netmgr - ns__client_request() is now called by netmgr with an isc_nmhandle_t parameter. The handle can then be permanently associated with an ns_client object. - The task manager is paused so that isc_task events that may be triggred during client processing will not fire until after the netmgr is finished with it. Before any asynchronous event, the client MUST call isc_nmhandle_ref(client->handle), to prevent the client from being reset and reused while waiting for an event to process. When the asynchronous event is complete, isc_nmhandle_unref(client->handle) must be called to ensure the handle can be reused later. - reference counting of client objects is now handled in the nmhandle object. when the handle references drop to zero, the client's "reset" callback is used to free temporary resources and reiniialize it, whereupon the handle (and associated client) is placed in the "inactive handles" queue. when the sysstem is shutdown and the handles are cleaned up, the client's "put" callback is called to free all remaining resources. - because client allocation is no longer handled in the same way, the '-T clienttest' option has now been removed and is no longer used by any system tests. - the unit tests require wrapping the isc_nmhandle_unref() function; when LD_WRAP is supported, that is used. otherwise we link a libwrap.so interposer library and use that. --- diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index eac0fe18be3..7d5877c8ac4 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ EXTERN bool named_g_run_done INIT(false); */ EXTERN isc_timermgr_t * named_g_timermgr INIT(NULL); EXTERN isc_socketmgr_t * named_g_socketmgr INIT(NULL); +EXTERN isc_nm_t * named_g_nm INIT(NULL); EXTERN cfg_parser_t * named_g_parser INIT(NULL); EXTERN cfg_parser_t * named_g_addparser INIT(NULL); EXTERN const char * named_g_version INIT(VERSION); diff --git a/bin/named/main.c b/bin/named/main.c index 21959ee756e..d707916a7c0 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -124,7 +125,6 @@ static int maxudp = 0; /* * -T options: */ -static bool clienttest = false; static bool dropedns = false; static bool ednsformerr = false; static bool ednsnotimp = false; @@ -622,17 +622,12 @@ parse_T_opt(char *option) { /* * force the server to behave (or misbehave) in * specified ways for testing purposes. - * - * clienttest: make clients single shot with their - * own memory context. * delay=xxxx: delay client responses by xxxx ms to * simulate remote servers. * dscp=x: check that dscp values are as * expected and assert otherwise. */ - if (!strcmp(option, "clienttest")) { - clienttest = true; - } else if (!strncmp(option, "delay=", 6)) { + if (!strncmp(option, "delay=", 6)) { delay = atoi(option + 6); } else if (!strcmp(option, "dropedns")) { dropedns = true; @@ -897,8 +892,15 @@ create_managers(void) { "using %u UDP listener%s per interface", named_g_udpdisp, named_g_udpdisp == 1 ? "" : "s"); - result = isc_taskmgr_create(named_g_mctx, named_g_cpus, 0, NULL, - &named_g_taskmgr); + named_g_nm = isc_nm_start(named_g_mctx, named_g_cpus); + if (named_g_nm == NULL) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_nm_start() failed"); + return (ISC_R_UNEXPECTED); + } + + result = isc_taskmgr_create(named_g_mctx, named_g_cpus, 0, + named_g_nm, &named_g_taskmgr); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_taskmgr_create() failed: %s", @@ -923,6 +925,7 @@ create_managers(void) { return (ISC_R_UNEXPECTED); } isc_socketmgr_maxudp(named_g_socketmgr, maxudp); + isc_nm_maxudp(named_g_nm, maxudp); result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &socks); if (result == ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, @@ -941,6 +944,7 @@ destroy_managers(void) { isc_taskmgr_destroy(&named_g_taskmgr); isc_timermgr_destroy(&named_g_timermgr); isc_socketmgr_destroy(&named_g_socketmgr); + isc_nm_destroy(&named_g_nm); } static void @@ -1254,8 +1258,6 @@ setup(void) { /* * Modify server context according to command line options */ - if (clienttest) - ns_server_setoption(sctx, NS_SERVER_CLIENTTEST, true); if (disable4) ns_server_setoption(sctx, NS_SERVER_DISABLE4, true); if (disable6) diff --git a/bin/named/server.c b/bin/named/server.c index ca216599fff..bf4f4a0ebc0 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -9462,6 +9462,7 @@ 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_nm, named_g_dispatchmgr, server->task, named_g_udpdisp, geoip, &server->interfacemgr), @@ -9525,6 +9526,12 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { UNUSED(task); INSIST(task == server->task); + /* + * We need to shutdown the interface before going + * exclusive (which would pause the netmgr). + */ + ns_interfacemgr_shutdown(server->interfacemgr); + result = isc_task_beginexclusive(server->task); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -9582,7 +9589,6 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { isc_timer_detach(&server->pps_timer); isc_timer_detach(&server->tat_timer); - ns_interfacemgr_shutdown(server->interfacemgr); ns_interfacemgr_detach(&server->interfacemgr); dns_dispatchmgr_destroy(&named_g_dispatchmgr); diff --git a/bin/tests/system/README b/bin/tests/system/README index f527e790d41..13286c054e6 100644 --- a/bin/tests/system/README +++ b/bin/tests/system/README @@ -584,10 +584,6 @@ By default, start.pl starts a "named" server with the following options: preventing multiple instances of this named running in this directory (which could possibly interfere with the test). -In addition, start.pl also sets the following undocumented flag: - - -T clienttest Makes clients single-shot with their own memory context. - All output is sent to a file called "named.run" in the nameserver directory. The options used to start named can be altered. There are three ways of doing @@ -608,9 +604,9 @@ the named command-line arguments. The rest of the file is ignored. 3. Tweaking the default command line arguments with "-T" options. This flag is used to alter the behavior of BIND for testing and is not documented in the -ARM. The "clienttest" option has already been mentioned, but the presence of -certain files in the "nsN" directory adds flags to the default command line -(the content of the files is irrelevant - it is only the presence that counts): +ARM. The presence of certain files in the "nsN" directory adds flags to +the default command line (the content of the files is irrelevant - it +is only the presence that counts): named.noaa Appends "-T noaa" to the command line, which causes "named" to never set the AA bit in an answer. @@ -635,7 +631,6 @@ certain files in the "nsN" directory adds flags to the default command line the additional section if the response is triggered by RPZ rewriting). - Starting Other Nameservers --- In contrast to "named", nameservers written in Perl or Python (whose script diff --git a/bin/tests/system/additional/ns1/named.args b/bin/tests/system/additional/ns1/named.args index 39b8c1ae55b..0db1ead8340 100644 --- a/bin/tests/system/additional/ns1/named.args +++ b/bin/tests/system/additional/ns1/named.args @@ -1,2 +1,2 @@ # this server runs named with only one worker thread --m record,size,mctx -c named.conf -d 99 -D additional-ns1 -X named.lock -g -T clienttest -n 1 +-m record,size,mctx -c named.conf -d 99 -D additional-ns1 -X named.lock -g -n 1 diff --git a/bin/tests/system/allow-query/ns3/named.args b/bin/tests/system/allow-query/ns3/named.args index 0f50735bfd9..5dd675d0fd2 100644 --- a/bin/tests/system/allow-query/ns3/named.args +++ b/bin/tests/system/allow-query/ns3/named.args @@ -1,2 +1,2 @@ # this server only has 127.0.0.1 in its localhost/localnets ACLs --m record,size,mctx -c named.conf -d 99 -D allow-query-ns3 -X named.lock -g -T clienttest -T fixedlocal +-m record,size,mctx -c named.conf -d 99 -D allow-query-ns3 -X named.lock -g -T fixedlocal diff --git a/bin/tests/system/delzone/ns2/named.args b/bin/tests/system/delzone/ns2/named.args index 12588aa1966..b3028b1d29f 100644 --- a/bin/tests/system/delzone/ns2/named.args +++ b/bin/tests/system/delzone/ns2/named.args @@ -1 +1 @@ --D delzone-ns2 -X named.lock -m record,size,mctx -T clienttest -c named.conf -g -U 4 +-D delzone-ns2 -X named.lock -m record,size,mctx -c named.conf -g -U 4 diff --git a/bin/tests/system/dnssec/ns6/named.args b/bin/tests/system/dnssec/ns6/named.args index f500166416e..21242f17ff6 100644 --- a/bin/tests/system/dnssec/ns6/named.args +++ b/bin/tests/system/dnssec/ns6/named.args @@ -1 +1 @@ --m record,size,mctx -c named.conf -d 99 -D dnssec-ns6 -X named.lock -g -T nonearest -T clienttest -T tat=1 +-m record,size,mctx -c named.conf -d 99 -D dnssec-ns6 -X named.lock -g -T nonearest -T tat=1 diff --git a/bin/tests/system/dscp/ns1/named.args b/bin/tests/system/dscp/ns1/named.args index 248cee7d557..4986abce059 100644 --- a/bin/tests/system/dscp/ns1/named.args +++ b/bin/tests/system/dscp/ns1/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns1 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns1 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns2/named.args b/bin/tests/system/dscp/ns2/named.args index 4a205add68a..91635e8c04b 100644 --- a/bin/tests/system/dscp/ns2/named.args +++ b/bin/tests/system/dscp/ns2/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns2 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns2 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns3/named.args b/bin/tests/system/dscp/ns3/named.args index cf4a1821d65..ec9b5934dad 100644 --- a/bin/tests/system/dscp/ns3/named.args +++ b/bin/tests/system/dscp/ns3/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns3 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns3 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns4/named.args b/bin/tests/system/dscp/ns4/named.args index 57678fe2fbb..6da9eff6075 100644 --- a/bin/tests/system/dscp/ns4/named.args +++ b/bin/tests/system/dscp/ns4/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns4 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns4 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns5/named.args b/bin/tests/system/dscp/ns5/named.args index 83824885881..dc556e7e86b 100644 --- a/bin/tests/system/dscp/ns5/named.args +++ b/bin/tests/system/dscp/ns5/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns5 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns5 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns6/named.args b/bin/tests/system/dscp/ns6/named.args index 482dd408708..c7389076ba4 100644 --- a/bin/tests/system/dscp/ns6/named.args +++ b/bin/tests/system/dscp/ns6/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns6 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns6 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dscp/ns7/named.args b/bin/tests/system/dscp/ns7/named.args index 0528448c11c..39ccaa4bbf8 100644 --- a/bin/tests/system/dscp/ns7/named.args +++ b/bin/tests/system/dscp/ns7/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D dscp-ns7 -X named.lock -g -U 4 -T dscp=46 +-m record,size,mctx -c named.conf -d 99 -D dscp-ns7 -X named.lock -g -U 4 -T dscp=46 diff --git a/bin/tests/system/dupsigs/ns1/named.args b/bin/tests/system/dupsigs/ns1/named.args index c7cab8aa5b6..2eed0529a73 100644 --- a/bin/tests/system/dupsigs/ns1/named.args +++ b/bin/tests/system/dupsigs/ns1/named.args @@ -1 +1 @@ --D dupsigs-ns1 -X named.lock -m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T sigvalinsecs +-D dupsigs-ns1 -X named.lock -m record,size,mctx -c named.conf -d 99 -g -U 4 -T sigvalinsecs diff --git a/bin/tests/system/fetchlimit/ns3/named.args b/bin/tests/system/fetchlimit/ns3/named.args deleted file mode 100644 index 1d7ee742c5b..00000000000 --- a/bin/tests/system/fetchlimit/ns3/named.args +++ /dev/null @@ -1,2 +0,0 @@ -# Don't specify '-T clienttest' as it consumes lots of memory with this test --D fetchlimit-ns3 -X named.lock -m record,size,mctx -c named.conf -d 99 -g -U 4 diff --git a/bin/tests/system/legacy/ns4/named.args b/bin/tests/system/legacy/ns4/named.args index 1f118009270..24af8c11275 100644 --- a/bin/tests/system/legacy/ns4/named.args +++ b/bin/tests/system/legacy/ns4/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D legacy-ns4 -X named.lock -g -U 4 -T noedns +-m record,size,mctx -c named.conf -d 99 -D legacy-ns4 -X named.lock -g -U 4 -T noedns diff --git a/bin/tests/system/legacy/ns5/named.args b/bin/tests/system/legacy/ns5/named.args index 54aa083f261..515e77d0d9c 100644 --- a/bin/tests/system/legacy/ns5/named.args +++ b/bin/tests/system/legacy/ns5/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D legacy-ns5 -X named.lock -g -U 4 -T noedns +-m record,size,mctx -c named.conf -d 99 -D legacy-ns5 -X named.lock -g -U 4 -T noedns diff --git a/bin/tests/system/legacy/ns6/named.args b/bin/tests/system/legacy/ns6/named.args index b9a278ec571..cdc570f7c8d 100644 --- a/bin/tests/system/legacy/ns6/named.args +++ b/bin/tests/system/legacy/ns6/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D legacy-ns6 -X named.lock -g -U 4 -T maxudp512 +-m record,size,mctx -c named.conf -d 99 -D legacy-ns6 -X named.lock -g -U 4 -T maxudp512 diff --git a/bin/tests/system/legacy/ns7/named.args b/bin/tests/system/legacy/ns7/named.args index fbe0ebfa1d3..2a1a61217bb 100644 --- a/bin/tests/system/legacy/ns7/named.args +++ b/bin/tests/system/legacy/ns7/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D legacy-ns7 -X named.lock -g -U 4 -T maxudp512 +-m record,size,mctx -c named.conf -d 99 -D legacy-ns7 -X named.lock -g -U 4 -T maxudp512 diff --git a/bin/tests/system/logfileconfig/tests.sh b/bin/tests/system/logfileconfig/tests.sh index 1a43b27a3cb..67d06d8ad04 100644 --- a/bin/tests/system/logfileconfig/tests.sh +++ b/bin/tests/system/logfileconfig/tests.sh @@ -36,7 +36,7 @@ DLFILE="named_deflog" PIDFILE="${THISDIR}/${CONFDIR}/named.pid" myRNDC="$RNDC -c ${THISDIR}/${CONFDIR}/rndc.conf" -myNAMED="$NAMED -c ${THISDIR}/${CONFDIR}/named.conf -m record,size,mctx -T clienttest -T nosyslog -d 99 -D logfileconfig-ns1 -X named.lock -U 4" +myNAMED="$NAMED -c ${THISDIR}/${CONFDIR}/named.conf -m record,size,mctx -T nosyslog -d 99 -D logfileconfig-ns1 -X named.lock -U 4" # Test given condition. If true, test again after a second. Used for testing # filesystem-dependent conditions in order to prevent false negatives caused by diff --git a/bin/tests/system/mirror/ns3/named.args b/bin/tests/system/mirror/ns3/named.args index 5330759bd42..be1cb49ce3d 100644 --- a/bin/tests/system/mirror/ns3/named.args +++ b/bin/tests/system/mirror/ns3/named.args @@ -1 +1 @@ --D mirror-ns3 -X named.lock -m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T tat=3 +-D mirror-ns3 -X named.lock -m record,size,mctx -c named.conf -d 99 -g -U 4 -T tat=3 diff --git a/bin/tests/system/mkeys/ns2/named.args b/bin/tests/system/mkeys/ns2/named.args index 614243233d4..9f4ad4e46b5 100644 --- a/bin/tests/system/mkeys/ns2/named.args +++ b/bin/tests/system/mkeys/ns2/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D mkeys-ns2 -X named.lock -g -T mkeytimers=5/10/20 -T tat=1 +-m record,size,mctx -c named.conf -d 99 -D mkeys-ns2 -X named.lock -g -T mkeytimers=5/10/20 -T tat=1 diff --git a/bin/tests/system/mkeys/ns3/named.args b/bin/tests/system/mkeys/ns3/named.args index b8fb0085623..376aa253cf0 100644 --- a/bin/tests/system/mkeys/ns3/named.args +++ b/bin/tests/system/mkeys/ns3/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -D mkeys-ns3 -X named.lock -g -T mkeytimers=5/10/20 +-m record,size,mctx -c named.conf -d 99 -D mkeys-ns3 -X named.lock -g -T mkeytimers=5/10/20 diff --git a/bin/tests/system/mkeys/ns5/named1.args b/bin/tests/system/mkeys/ns5/named1.args index efb102a4bae..2e6aadc2c1b 100644 --- a/bin/tests/system/mkeys/ns5/named1.args +++ b/bin/tests/system/mkeys/ns5/named1.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g +-m record,size,mctx -c named.conf -d 99 -X named.lock -g diff --git a/bin/tests/system/mkeys/ns5/named2.args b/bin/tests/system/mkeys/ns5/named2.args index d222b7faea7..3eaf260cff9 100644 --- a/bin/tests/system/mkeys/ns5/named2.args +++ b/bin/tests/system/mkeys/ns5/named2.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/20/40 +-m record,size,mctx -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/20/40 diff --git a/bin/tests/system/mkeys/ns6/named.args b/bin/tests/system/mkeys/ns6/named.args index 02f8f670f69..74ea7e0a813 100644 --- a/bin/tests/system/mkeys/ns6/named.args +++ b/bin/tests/system/mkeys/ns6/named.args @@ -1 +1 @@ --m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=5/10/20 +-m record,size,mctx -c named.conf -d 99 -X named.lock -g -T mkeytimers=5/10/20 diff --git a/bin/tests/system/nsupdate/ns5/named.args b/bin/tests/system/nsupdate/ns5/named.args index 49cb45ebe6b..6555b33a530 100644 --- a/bin/tests/system/nsupdate/ns5/named.args +++ b/bin/tests/system/nsupdate/ns5/named.args @@ -1 +1 @@ --D nsupdate-ns5 -m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -U 4 -T fixedlocal +-D nsupdate-ns5 -m record,size,mctx -c named.conf -d 99 -X named.lock -g -U 4 -T fixedlocal diff --git a/bin/tests/system/nsupdate/ns6/named.args b/bin/tests/system/nsupdate/ns6/named.args index 75ca52915e0..827afb99487 100644 --- a/bin/tests/system/nsupdate/ns6/named.args +++ b/bin/tests/system/nsupdate/ns6/named.args @@ -1 +1 @@ --D nsupdate-ns6 -m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -U 4 -T fixedlocal +-D nsupdate-ns6 -m record,size,mctx -c named.conf -d 99 -X named.lock -g -U 4 -T fixedlocal diff --git a/bin/tests/system/resolver/ns7/named.args b/bin/tests/system/resolver/ns7/named.args deleted file mode 100644 index 1e4a9bf3258..00000000000 --- a/bin/tests/system/resolver/ns7/named.args +++ /dev/null @@ -1,2 +0,0 @@ -# this server runs named with the "-T clienttest" option omitted --m record,size,mctx -c named.conf -d 99 -D resolver-ns7 -X named.lock -g diff --git a/bin/tests/system/rndc/ns6/named.args b/bin/tests/system/rndc/ns6/named.args index 479c740f814..e876eb89305 100644 --- a/bin/tests/system/rndc/ns6/named.args +++ b/bin/tests/system/rndc/ns6/named.args @@ -1,3 +1,3 @@ # teardown of a huge zone with tracing enabled takes way too long # -m none is set so that stop.pl does not timeout --D rndc-ns6 -X named.lock -m none -T clienttest -c named.conf -d 99 -g -U 4 +-D rndc-ns6 -X named.lock -m none -c named.conf -d 99 -g -U 4 diff --git a/bin/tests/system/start.pl b/bin/tests/system/start.pl index 869c1f0eb29..1ecbd70f226 100755 --- a/bin/tests/system/start.pl +++ b/bin/tests/system/start.pl @@ -257,7 +257,6 @@ sub construct_ns_command { $command .= "-D $test-$server "; $command .= "-X named.lock "; $command .= "-m record,size,mctx "; - $command .= "-T clienttest "; foreach my $t_option( "dropedns", "ednsformerr", "ednsnotimp", "ednsrefused", diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index c955d216dc7..a3e28f3e12d 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -598,7 +598,8 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { dns_qid_t *qid; REQUIRE(disp->port_table != NULL); - REQUIRE(portentry != NULL && isc_refcount_current(&portentry->refs) > 0); + REQUIRE(portentry != NULL && + isc_refcount_current(&portentry->refs) > 0); if (isc_refcount_decrement(&portentry->refs) == 1) { qid = DNS_QID(disp); diff --git a/lib/dns/message.c b/lib/dns/message.c index 9c6292a9a38..31321b86444 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -1103,7 +1103,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, result = ISC_R_NOMEMORY; goto cleanup; } - rdataset = isc_mempool_get(msg->rdspool); + rdataset = isc_mempool_get(msg->rdspool); if (rdataset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; diff --git a/lib/ns/client.c b/lib/ns/client.c index ceccec6e0e7..9104c3809ea 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -97,20 +98,6 @@ #define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0) -#define TCP_BUFFER_SIZE (65535 + 2) -#define SEND_BUFFER_SIZE 4096 -#define RECV_BUFFER_SIZE 4096 - -#define NMCTXS 100 -/*%< - * Number of 'mctx pools' for clients. (Should this be configurable?) - * When enabling threads, we use a pool of memory contexts shared by - * client objects, since concurrent access to a shared context would cause - * heavy contentions. The above constant is expected to be enough for - * completely avoiding contentions among threads for an authoritative-only - * server. - */ - #define COOKIE_SIZE 24U /* 8 + 4 + 4 + 8 */ #define ECS_SIZE 20U /* 2 + 1 + 1 + [0..16] */ @@ -119,108 +106,9 @@ #define WANTPAD(x) (((x)->attributes & NS_CLIENTATTR_WANTPAD) != 0) #define USEKEEPALIVE(x) (((x)->attributes & NS_CLIENTATTR_USEKEEPALIVE) != 0) -/*% nameserver client manager structure */ -struct ns_clientmgr { - /* Unlocked. */ - unsigned int magic; - - /* The queue object has its own locks */ - client_queue_t inactive; /*%< To be recycled */ - - isc_mem_t * mctx; - ns_server_t * sctx; - isc_taskmgr_t * taskmgr; - isc_timermgr_t * timermgr; - isc_task_t * excl; - - /* Lock covers manager state. */ - isc_mutex_t lock; - bool exiting; - - /* Lock covers the clients list */ - isc_mutex_t listlock; - client_list_t clients; /*%< All active clients */ - - /* Lock covers the recursing list */ - isc_mutex_t reclock; - client_list_t recursing; /*%< Recursing clients */ - -#if NMCTXS > 0 - /*%< mctx pool for clients. */ - unsigned int nextmctx; - isc_mem_t * mctxpool[NMCTXS]; -#endif -}; - #define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm') #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC) -/*! - * Client object states. Ordering is significant: higher-numbered - * states are generally "more active", meaning that the client can - * have more dynamically allocated data, outstanding events, etc. - * In the list below, any such properties listed for state N - * also apply to any state > N. - * - * To force the client into a less active state, set client->newstate - * to that state and call exit_check(). This will cause any - * activities defined for higher-numbered states to be aborted. - */ - -#define NS_CLIENTSTATE_FREED 0 -/*%< - * The client object no longer exists. - */ - -#define NS_CLIENTSTATE_INACTIVE 1 -/*%< - * The client object exists and has a task and timer. - * Its "query" struct and sendbuf are initialized. - * It is on the client manager's list of inactive clients. - * It has a message and OPT, both in the reset state. - */ - -#define NS_CLIENTSTATE_READY 2 -/*%< - * The client object is either a TCP or a UDP one, and - * it is associated with a network interface. It is on the - * client manager's list of active clients. - * - * If it is a TCP client object, it has a TCP listener socket - * and an outstanding TCP listen request. - * - * If it is a UDP client object, it has a UDP listener socket - * and an outstanding UDP receive request. - */ - -#define NS_CLIENTSTATE_READING 3 -/*%< - * The client object is a TCP client object that has received - * a connection. It has a tcpsocket, tcpmsg, TCP quota, and an - * outstanding TCP read request. This state is not used for - * UDP client objects. - */ - -#define NS_CLIENTSTATE_WORKING 4 -/*%< - * The client object has received a request and is working - * on it. It has a view, and it may have any of a non-reset OPT, - * recursion quota, and an outstanding write request. - */ - -#define NS_CLIENTSTATE_RECURSING 5 -/*%< - * The client object is recursing. It will be on the 'recursing' - * list. - */ - -#define NS_CLIENTSTATE_MAX 9 -/*%< - * Sentinel value used to indicate "no state". When client->newstate - * has this value, we are not attempting to exit the current state. - * Must be greater than any valid state. - */ - /* * Enable ns_client_dropport() by default. */ @@ -230,22 +118,16 @@ struct ns_clientmgr { LIBNS_EXTERNAL_DATA unsigned int ns_client_requests; -static void read_settimeout(ns_client_t *client, bool newconn); -static void client_read(ns_client_t *client, bool newconn); -static void client_accept(ns_client_t *client); -static void client_udprecv(ns_client_t *client); +static void clientmgr_attach(ns_clientmgr_t *source, ns_clientmgr_t **targetp); +static void clientmgr_detach(ns_clientmgr_t **mp); static void clientmgr_destroy(ns_clientmgr_t *manager); -static bool exit_check(ns_client_t *client); static void ns_client_endrequest(ns_client_t *client); -static void client_start(isc_task_t *task, isc_event_t *event); static void ns_client_dumpmessage(ns_client_t *client, const char *reason); -static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, - dns_dispatch_t *disp, bool tcp); -static isc_result_t get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, - isc_socket_t *sock, ns_client_t *oldclient); static void compute_cookie(ns_client_t *client, uint32_t when, uint32_t nonce, const unsigned char *secret, isc_buffer_t *buf); +static void +get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp); void ns_client_recursing(ns_client_t *client) { @@ -253,7 +135,7 @@ ns_client_recursing(ns_client_t *client) { REQUIRE(client->state == NS_CLIENTSTATE_WORKING); LOCK(&client->manager->reclock); - client->newstate = client->state = NS_CLIENTSTATE_RECURSING; + client->state = NS_CLIENTSTATE_RECURSING; ISC_LIST_APPEND(client->manager->recursing, client, rlink); UNLOCK(&client->manager->reclock); } @@ -275,596 +157,9 @@ ns_client_killoldestquery(ns_client_t *client) { void ns_client_settimeout(ns_client_t *client, unsigned int seconds) { - isc_result_t result; - isc_interval_t interval; - - isc_interval_set(&interval, seconds, 0); - result = isc_timer_reset(client->timer, isc_timertype_once, NULL, - &interval, false); - client->timerset = true; - if (result != ISC_R_SUCCESS) { - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, - "setting timeout: %s", - isc_result_totext(result)); - /* Continue anyway. */ - } -} - -static void -read_settimeout(ns_client_t *client, bool newconn) { - isc_result_t result; - isc_interval_t interval; - unsigned int ds; - - if (newconn) - ds = client->sctx->initialtimo; - else if (USEKEEPALIVE(client)) - ds = client->sctx->keepalivetimo; - else - ds = client->sctx->idletimo; - - isc_interval_set(&interval, ds / 10, 100000000 * (ds % 10)); - result = isc_timer_reset(client->timer, isc_timertype_once, NULL, - &interval, false); - client->timerset = true; - if (result != ISC_R_SUCCESS) { - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_ERROR, - "setting timeout: %s", - isc_result_totext(result)); - /* Continue anyway. */ - } -} - -/*% - * Allocate a reference-counted object that will maintain a single pointer to - * the (also reference-counted) TCP client quota, shared between all the - * clients processing queries on a single TCP connection, so that all - * clients sharing the one socket will together consume only one slot in - * the 'tcp-clients' quota. - */ -static isc_result_t -tcpconn_init(ns_client_t *client, bool force) { - isc_result_t result; - isc_quota_t *quota = NULL; - ns_tcpconn_t *tconn = NULL; - - REQUIRE(client->tcpconn == NULL); - - /* - * Try to attach to the quota first, so we won't pointlessly - * allocate memory for a tcpconn object if we can't get one. - */ - if (force) { - result = isc_quota_force(&client->sctx->tcpquota, "a); - } else { - result = isc_quota_attach(&client->sctx->tcpquota, "a); - } - if (result != ISC_R_SUCCESS) { - return (result); - } - - /* - * A global memory context is used for the allocation as different - * client structures may have different memory contexts assigned and a - * reference counter allocated here might need to be freed by a - * different client. The performance impact caused by memory context - * contention here is expected to be negligible, given that this code - * is only executed for TCP connections. - */ - tconn = isc_mem_allocate(client->sctx->mctx, sizeof(*tconn)); - - isc_refcount_init(&tconn->refs, 1); - tconn->tcpquota = quota; - quota = NULL; - tconn->pipelined = false; - - client->tcpconn = tconn; - - return (ISC_R_SUCCESS); -} - -/*% - * Increase the count of client structures sharing the TCP connection - * that 'source' is associated with; add a pointer to the same tcpconn - * to 'target', thus associating it with the same TCP connection. - */ -static void -tcpconn_attach(ns_client_t *source, ns_client_t *target) { - int old_refs; - - REQUIRE(source->tcpconn != NULL); - REQUIRE(target->tcpconn == NULL); - REQUIRE(source->tcpconn->pipelined); - - old_refs = isc_refcount_increment(&source->tcpconn->refs); - INSIST(old_refs > 0); - target->tcpconn = source->tcpconn; -} - -/*% - * Decrease the count of client structures sharing the TCP connection that - * 'client' is associated with. If this is the last client using this TCP - * connection, we detach from the TCP quota and free the tcpconn - * object. Either way, client->tcpconn is set to NULL. - */ -static void -tcpconn_detach(ns_client_t *client) { - ns_tcpconn_t *tconn = NULL; - int old_refs; - - REQUIRE(client->tcpconn != NULL); - - tconn = client->tcpconn; - client->tcpconn = NULL; - - old_refs = isc_refcount_decrement(&tconn->refs); - INSIST(old_refs > 0); - - if (old_refs == 1) { - isc_quota_detach(&tconn->tcpquota); - isc_mem_free(client->sctx->mctx, tconn); - } -} - -/*% - * Mark a client as active and increment the interface's 'ntcpactive' - * counter, as a signal that there is at least one client servicing - * TCP queries for the interface. If we reach the TCP client quota at - * some point, this will be used to determine whether a quota overrun - * should be permitted. - * - * Marking the client active with the 'tcpactive' flag ensures proper - * accounting, by preventing us from incrementing or decrementing - * 'ntcpactive' more than once per client. - */ -static void -mark_tcp_active(ns_client_t *client, bool active) { - if (active && !client->tcpactive) { - isc_refcount_increment0(&client->interface->ntcpactive); - client->tcpactive = active; - } else if (!active && client->tcpactive) { - uint32_t old = - isc_refcount_decrement(&client->interface->ntcpactive); - INSIST(old > 0); - client->tcpactive = active; - } -} - -/*% - * Check for a deactivation or shutdown request and take appropriate - * action. Returns true if either is in progress; in this case - * the caller must no longer use the client object as it may have been - * freed. - */ -static bool -exit_check(ns_client_t *client) { - bool destroy_manager = false; - ns_clientmgr_t *manager = NULL; - - REQUIRE(NS_CLIENT_VALID(client)); - manager = client->manager; - - if (client->state <= client->newstate) - return (false); /* Business as usual. */ - - INSIST(client->newstate < NS_CLIENTSTATE_RECURSING); - - /* - * We need to detach from the view early when shutting down - * the server to break the following vicious circle: - * - * - The resolver will not shut down until the view refcount is zero - * - The view refcount does not go to zero until all clients detach - * - The client does not detach from the view until references is zero - * - references does not go to zero until the resolver has shut down - * - * Keep the view attached until any outstanding updates complete. - */ - if (client->nupdates == 0 && - client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL) - dns_view_detach(&client->view); - - if (client->state == NS_CLIENTSTATE_WORKING || - client->state == NS_CLIENTSTATE_RECURSING) - { - INSIST(client->newstate <= NS_CLIENTSTATE_READING); - /* - * Let the update processing complete. - */ - if (client->nupdates > 0) - return (true); - - /* - * We are trying to abort request processing. - */ - if (client->nsends > 0) { - isc_socket_t *sock; - if (TCP_CLIENT(client)) - sock = client->tcpsocket; - else - sock = client->udpsocket; - isc_socket_cancel(sock, client->task, - ISC_SOCKCANCEL_SEND); - } - - if (! (client->nsends == 0 && client->nrecvs == 0 && - isc_refcount_current(&client->references) == 0)) - { - /* - * Still waiting for I/O cancel completion. - * or lingering references. - */ - return (true); - } - - /* - * I/O cancel is complete. Burn down all state - * related to the current request. Ensure that - * the client is no longer on the recursing list. - * - * We need to check whether the client is still linked, - * because it may already have been removed from the - * recursing list by ns_client_killoldestquery() - */ - if (client->state == NS_CLIENTSTATE_RECURSING) { - LOCK(&manager->reclock); - if (ISC_LINK_LINKED(client, rlink)) - ISC_LIST_UNLINK(manager->recursing, - client, rlink); - UNLOCK(&manager->reclock); - } - ns_client_endrequest(client); - - client->state = NS_CLIENTSTATE_READING; - INSIST(client->recursionquota == NULL); - - if (NS_CLIENTSTATE_READING == client->newstate) { - INSIST(client->tcpconn != NULL); - if (!client->tcpconn->pipelined) { - client_read(client, false); - client->newstate = NS_CLIENTSTATE_MAX; - return (true); /* We're done. */ - } else if (client->mortal) { - client->newstate = NS_CLIENTSTATE_INACTIVE; - } else - return (false); - } - } - - if (client->state == NS_CLIENTSTATE_READING) { - /* - * We are trying to abort the current TCP connection, - * if any. - */ - INSIST(client->recursionquota == NULL); - INSIST(client->newstate <= NS_CLIENTSTATE_READY); - - if (client->nreads > 0) { - dns_tcpmsg_cancelread(&client->tcpmsg); - /* Still waiting for read cancel completion? */ - if (client->nreads > 0) { - return (true); - } - } - - if (client->tcpmsg_valid) { - dns_tcpmsg_invalidate(&client->tcpmsg); - client->tcpmsg_valid = false; - } - - /* - * Soon the client will be ready to accept a new TCP - * connection or UDP request, but we may have enough - * clients doing that already. Check whether this client - * needs to remain active and allow it go inactive if - * not. - * - * UDP clients always go inactive at this point, but a TCP - * client may need to stay active and return to READY - * state if no other clients are available to listen - * for TCP requests on this interface. - * - * Regardless, if we're going to FREED state, that means - * the system is shutting down and we don't need to - * retain clients. - */ - if (client->mortal && TCP_CLIENT(client) && - client->newstate != NS_CLIENTSTATE_FREED && - (client->sctx->options & NS_SERVER_CLIENTTEST) == 0 && - isc_refcount_current(&client->interface->ntcpaccepting) == 0) - { - /* Nobody else is accepting */ - client->mortal = false; - client->newstate = NS_CLIENTSTATE_READY; - } - - /* - * Detach from TCP connection and TCP client quota, - * if appropriate. If this is the last reference to - * the TCP connection in our pipeline group, the - * TCP quota slot will be released. - */ - if (client->tcpconn) { - tcpconn_detach(client); - } - - if (client->tcpsocket != NULL) { - CTRACE("closetcp"); - isc_socket_detach(&client->tcpsocket); - mark_tcp_active(client, false); - } - - if (client->timerset) { - (void)isc_timer_reset(client->timer, - isc_timertype_inactive, - NULL, NULL, true); - client->timerset = false; - } - - client->peeraddr_valid = false; - - client->state = NS_CLIENTSTATE_READY; - - /* - * We don't need the client; send it to the inactive - * queue for recycling. - */ - if (client->mortal) { - if (client->newstate > NS_CLIENTSTATE_INACTIVE) { - client->newstate = NS_CLIENTSTATE_INACTIVE; - } - } - - if (NS_CLIENTSTATE_READY == client->newstate) { - if (TCP_CLIENT(client)) { - client_accept(client); - } else { - client_udprecv(client); - } - client->newstate = NS_CLIENTSTATE_MAX; - return (true); - } - } - - if (client->state == NS_CLIENTSTATE_READY) { - INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE); - - /* - * We are trying to enter the inactive state. - */ - if (client->naccepts > 0) { - isc_socket_cancel(client->tcplistener, client->task, - ISC_SOCKCANCEL_ACCEPT); - /* Still waiting for accept cancel completion? */ - if (client->naccepts > 0) { - return (true); - } - } - - /* Accept cancel is complete. */ - if (client->nrecvs > 0) { - isc_socket_cancel(client->udpsocket, client->task, - ISC_SOCKCANCEL_RECV); - /* Still waiting for recv cancel completion? */ - if (client->nrecvs > 0) { - return (true); - } - } - - /* Still waiting for control event to be delivered */ - if (client->nctls > 0) { - return (true); - } - - INSIST(client->naccepts == 0); - INSIST(client->recursionquota == NULL); - if (client->tcplistener != NULL) { - isc_socket_detach(&client->tcplistener); - mark_tcp_active(client, false); - } - if (client->udpsocket != NULL) { - isc_socket_detach(&client->udpsocket); - } - - /* Deactivate the client. */ - if (client->interface != NULL) { - ns_interface_detach(&client->interface); - } - - if (client->dispatch != NULL) { - dns_dispatch_detach(&client->dispatch); - } - - client->attributes = 0; - client->mortal = false; - client->sendcb = NULL; - - if (client->keytag != NULL) { - isc_mem_put(client->mctx, client->keytag, - client->keytag_len); - client->keytag_len = 0; - } - - /* - * Put the client on the inactive list. If we are aiming for - * the "freed" state, it will be removed from the inactive - * list shortly, and we need to keep the manager locked until - * that has been done, lest the manager decide to reactivate - * the dying client inbetween. - */ - client->state = NS_CLIENTSTATE_INACTIVE; - INSIST(client->recursionquota == NULL); - - if (client->state == client->newstate) { - client->newstate = NS_CLIENTSTATE_MAX; - if ((client->sctx->options & - NS_SERVER_CLIENTTEST) == 0 && - manager != NULL && !manager->exiting) - { - ISC_QUEUE_PUSH(manager->inactive, client, - ilink); - } - if (client->needshutdown) { - isc_task_shutdown(client->task); - } - return (true); - } - } - - if (client->state == NS_CLIENTSTATE_INACTIVE) { - INSIST(client->newstate == NS_CLIENTSTATE_FREED); - /* - * We are trying to free the client. - * - * When "shuttingdown" is true, either the task has received - * its shutdown event or no shutdown event has ever been - * set up. Thus, we have no outstanding shutdown - * event at this point. - */ - REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE); - - INSIST(client->recursionquota == NULL); - INSIST(!ISC_QLINK_LINKED(client, ilink)); - - if (manager != NULL) { - LOCK(&manager->listlock); - ISC_LIST_UNLINK(manager->clients, client, link); - LOCK(&manager->lock); - if (manager->exiting && - ISC_LIST_EMPTY(manager->clients)) - destroy_manager = true; - UNLOCK(&manager->lock); - UNLOCK(&manager->listlock); - } - - ns_query_free(client); - isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE); - isc_event_free((isc_event_t **)&client->sendevent); - isc_event_free((isc_event_t **)&client->recvevent); - isc_timer_detach(&client->timer); - if (client->delaytimer != NULL) - isc_timer_detach(&client->delaytimer); - - if (client->tcpbuf != NULL) - isc_mem_put(client->mctx, client->tcpbuf, - TCP_BUFFER_SIZE); - if (client->opt != NULL) { - INSIST(dns_rdataset_isassociated(client->opt)); - dns_rdataset_disassociate(client->opt); - dns_message_puttemprdataset(client->message, - &client->opt); - } - if (client->keytag != NULL) { - isc_mem_put(client->mctx, client->keytag, - client->keytag_len); - client->keytag_len = 0; - } - - dns_message_destroy(&client->message); - - /* - * Detaching the task must be done after unlinking from - * the manager's lists because the manager accesses - * client->task. - */ - if (client->task != NULL) - isc_task_detach(&client->task); - - CTRACE("free"); - client->magic = 0; - - /* - * Check that there are no other external references to - * the memory context. - */ - if ((client->sctx->options & NS_SERVER_CLIENTTEST) != 0 && - isc_mem_references(client->mctx) != 1) - { - isc_mem_stats(client->mctx, stderr); - INSIST(0); - ISC_UNREACHABLE(); - } - - /* - * Destroy the fetchlock mutex that was created in - * ns_query_init(). - */ - isc_mutex_destroy(&client->query.fetchlock); - - if (client->sctx != NULL) - ns_server_detach(&client->sctx); - - isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); - } - - if (destroy_manager && manager != NULL) - clientmgr_destroy(manager); - - return (true); -} - -/*% - * The client's task has received the client's control event - * as part of the startup process. - */ -static void -client_start(isc_task_t *task, isc_event_t *event) { - ns_client_t *client = (ns_client_t *) event->ev_arg; - - INSIST(task == client->task); - - UNUSED(task); - - INSIST(client->nctls == 1); - client->nctls--; - - if (exit_check(client)) - return; - - if (TCP_CLIENT(client)) { - if (client->tcpconn != NULL) { - client_read(client, false); - } else { - client_accept(client); - } - } else { - client_udprecv(client); - } -} - -/*% - * The client's task has received a shutdown event. - */ -static void -client_shutdown(isc_task_t *task, isc_event_t *event) { - ns_client_t *client; - - REQUIRE(event != NULL); - REQUIRE(event->ev_type == ISC_TASKEVENT_SHUTDOWN); - client = event->ev_arg; - REQUIRE(NS_CLIENT_VALID(client)); - REQUIRE(task == client->task); - - UNUSED(task); - - CTRACE("shutdown"); - - isc_event_free(&event); - - if (client->shutdown != NULL) { - (client->shutdown)(client->shutdown_arg, ISC_R_SHUTTINGDOWN); - client->shutdown = NULL; - client->shutdown_arg = NULL; - } - - if (ISC_QLINK_LINKED(client, ilink)) - ISC_QUEUE_UNLINK(client->manager->inactive, client, ilink); - - client->newstate = NS_CLIENTSTATE_FREED; - client->needshutdown = false; - (void)exit_check(client); + UNUSED(client); + UNUSED(seconds); + /* XXXWPK TODO use netmgr to set timeout */ } static void @@ -879,9 +174,15 @@ ns_client_endrequest(ns_client_t *client) { CTRACE("endrequest"); - if (client->next != NULL) { - (client->next)(client); - client->next = NULL; + LOCK(&client->manager->reclock); + if (ISC_LINK_LINKED(client, rlink)) { + ISC_LIST_UNLINK(client->manager->recursing, client, rlink); + } + UNLOCK(&client->manager->reclock); + + if (client->cleanup != NULL) { + (client->cleanup)(client); + client->cleanup = NULL; } if (client->view != NULL) { @@ -906,17 +207,22 @@ ns_client_endrequest(ns_client_t *client) { dns_ecs_init(&client->ecs); dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); + /* + * Clean up from recursion - normally this would be done in + * fetch_callback(), but if we're shutting down and canceling then + * it might not have happened. + */ if (client->recursionquota != NULL) { isc_quota_detach(&client->recursionquota); ns_stats_decrement(client->sctx->nsstats, ns_statscounter_recursclients); } + /* - * Clear all client attributes that are specific to - * the request; that's all except the TCP flag. + * Clear all client attributes that are specific to the request */ - client->attributes &= NS_CLIENTATTR_TCP; + client->attributes = 0; #ifdef ENABLE_AFL if (client->sctx->fuzznotify != NULL && (client->sctx->fuzztype == isc_fuzz_client || @@ -926,73 +232,36 @@ ns_client_endrequest(ns_client_t *client) { client->sctx->fuzznotify(); } #endif /* ENABLE_AFL */ - } void -ns_client_next(ns_client_t *client, isc_result_t result) { - int newstate; - +ns_client_drop(ns_client_t *client, isc_result_t result) { REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(client->state == NS_CLIENTSTATE_WORKING || - client->state == NS_CLIENTSTATE_RECURSING || - client->state == NS_CLIENTSTATE_READING); - - CTRACE("next"); + client->state == NS_CLIENTSTATE_RECURSING); - if (result != ISC_R_SUCCESS) + CTRACE("drop"); + if (result != ISC_R_SUCCESS) { ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), "request failed: %s", isc_result_totext(result)); - - /* - * An error processing a TCP request may have left - * the connection out of sync. To be safe, we always - * sever the connection when result != ISC_R_SUCCESS. - */ - if (result == ISC_R_SUCCESS && TCP_CLIENT(client)) - newstate = NS_CLIENTSTATE_READING; - else - newstate = NS_CLIENTSTATE_READY; - - if (client->newstate > newstate) - client->newstate = newstate; - (void)exit_check(client); + } } - static void -client_senddone(isc_task_t *task, isc_event_t *event) { - ns_client_t *client; - isc_socketevent_t *sevent = (isc_socketevent_t *) event; +client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { + ns_client_t *client = cbarg; - REQUIRE(sevent != NULL); - REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE); - client = sevent->ev_arg; - REQUIRE(NS_CLIENT_VALID(client)); - REQUIRE(task == client->task); - REQUIRE(sevent == client->sendevent); - - UNUSED(task); + REQUIRE(client->handle == handle); CTRACE("senddone"); - - if (sevent->result != ISC_R_SUCCESS) - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, - "error sending response: %s", - isc_result_totext(sevent->result)); - - INSIST(client->nsends > 0); - client->nsends--; - - if (client->tcpbuf != NULL) { - INSIST(TCP_CLIENT(client)); - isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); - client->tcpbuf = NULL; + if (result != ISC_R_SUCCESS) { + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "send failed: %s", isc_result_totext(result)); } - ns_client_next(client, ISC_R_SUCCESS); + isc_nmhandle_unref(handle); } /*% @@ -1006,34 +275,37 @@ client_senddone(isc_task_t *task, isc_event_t *event) { static isc_result_t client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer, isc_buffer_t *tcpbuffer, uint32_t length, - unsigned char *sendbuf, unsigned char **datap) + unsigned char **datap) { unsigned char *data; uint32_t bufsize; isc_result_t result; - INSIST(datap != NULL); - INSIST((tcpbuffer == NULL && length != 0) || - (tcpbuffer != NULL && length == 0)); + REQUIRE(datap != NULL); + REQUIRE((tcpbuffer == NULL && length != 0) || + (tcpbuffer != NULL && length == 0)); if (TCP_CLIENT(client)) { INSIST(client->tcpbuf == NULL); - if (length + 2 > TCP_BUFFER_SIZE) { + if (length + 2 > NS_CLIENT_TCP_BUFFER_SIZE) { result = ISC_R_NOSPACE; goto done; } - client->tcpbuf = isc_mem_get(client->mctx, TCP_BUFFER_SIZE); + client->tcpbuf = isc_mem_get(client->mctx, + NS_CLIENT_TCP_BUFFER_SIZE); data = client->tcpbuf; if (tcpbuffer != NULL) { - isc_buffer_init(tcpbuffer, data, TCP_BUFFER_SIZE); - isc_buffer_init(buffer, data + 2, TCP_BUFFER_SIZE - 2); + isc_buffer_init(tcpbuffer, data, + NS_CLIENT_TCP_BUFFER_SIZE); + isc_buffer_init(buffer, data, + NS_CLIENT_TCP_BUFFER_SIZE); } else { - isc_buffer_init(buffer, data, TCP_BUFFER_SIZE); + isc_buffer_init(buffer, data, + NS_CLIENT_TCP_BUFFER_SIZE); INSIST(length <= 0xffff); - isc_buffer_putuint16(buffer, (uint16_t)length); } } else { - data = sendbuf; + data = client->sendbuf; if ((client->attributes & NS_CLIENTATTR_HAVECOOKIE) == 0) { if (client->view != NULL) bufsize = client->view->nocookieudp; @@ -1043,8 +315,8 @@ client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer, bufsize = client->udpsize; if (bufsize > client->udpsize) bufsize = client->udpsize; - if (bufsize > SEND_BUFFER_SIZE) - bufsize = SEND_BUFFER_SIZE; + if (bufsize > NS_CLIENT_SEND_BUFFER_SIZE) + bufsize = NS_CLIENT_SEND_BUFFER_SIZE; if (length > bufsize) { result = ISC_R_NOSPACE; goto done; @@ -1060,82 +332,13 @@ client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer, static isc_result_t client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) { - struct in6_pktinfo *pktinfo; - isc_result_t result; isc_region_t r; - isc_sockaddr_t *address; - isc_socket_t *sock; - isc_netaddr_t netaddr; - int match; - unsigned int sockflags = ISC_SOCKFLAG_IMMEDIATE; - - if (TCP_CLIENT(client)) { - sock = client->tcpsocket; - address = NULL; - } else { - dns_aclenv_t *env = - ns_interfacemgr_getaclenv(client->interface->mgr); - - sock = client->udpsocket; - address = &client->peeraddr; - - isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); - if (client->sctx->blackholeacl != NULL && - (dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl, - env, &match, NULL) == ISC_R_SUCCESS) && - match > 0) - { - return (DNS_R_BLACKHOLED); - } - sockflags |= ISC_SOCKFLAG_NORETRY; - } - - if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0 && - (client->attributes & NS_CLIENTATTR_MULTICAST) == 0) - pktinfo = &client->pktinfo; - else - pktinfo = NULL; - - if (client->dispatch != NULL) { - isc_dscp_t dscp = dns_dispatch_getdscp(client->dispatch); - if (dscp != -1) { - client->dscp = dscp; - } - } - - if (client->dscp == -1) { - client->sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; - client->sendevent->dscp = 0; - } else { - client->sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; - client->sendevent->dscp = client->dscp; - } isc_buffer_usedregion(buffer, &r); - /* - * If this is a UDP client and the IPv6 packet can't be - * encapsulated without generating a PTB on a 1500 octet - * MTU link force fragmentation at 1280 if it is a IPv6 - * response. - */ - client->sendevent->attributes &= ~ISC_SOCKEVENTATTR_USEMINMTU; - if (!TCP_CLIENT(client) && r.length > 1432) - client->sendevent->attributes |= ISC_SOCKEVENTATTR_USEMINMTU; - - CTRACE("sendto"); + INSIST(client->handle != NULL); - result = isc_socket_sendto2(sock, &r, client->task, - address, pktinfo, - client->sendevent, sockflags); - if (result == ISC_R_SUCCESS || result == ISC_R_INPROGRESS) { - client->nsends++; - if (result == ISC_R_SUCCESS) - client_senddone(client->task, - (isc_event_t *)client->sendevent); - result = ISC_R_SUCCESS; - } - return (result); + return (isc_nm_send(client->handle, &r, client_senddone, client)); } void @@ -1145,7 +348,6 @@ ns_client_sendraw(ns_client_t *client, dns_message_t *message) { isc_buffer_t buffer; isc_region_t r; isc_region_t *mr; - unsigned char sendbuf[SEND_BUFFER_SIZE]; REQUIRE(NS_CLIENT_VALID(client)); @@ -1157,8 +359,7 @@ ns_client_sendraw(ns_client_t *client, dns_message_t *message) { goto done; } - result = client_allocsendbuf(client, &buffer, NULL, mr->length, - sendbuf, &data); + result = client_allocsendbuf(client, &buffer, NULL, mr->length, &data); if (result != ISC_R_SUCCESS) goto done; @@ -1178,22 +379,23 @@ ns_client_sendraw(ns_client_t *client, dns_message_t *message) { done: if (client->tcpbuf != NULL) { - isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); + isc_mem_put(client->mctx, client->tcpbuf, + NS_CLIENT_TCP_BUFFER_SIZE); client->tcpbuf = NULL; } - ns_client_next(client, result); + + ns_client_drop(client, result); } -static void -client_send(ns_client_t *client) { +void +ns_client_send(ns_client_t *client) { isc_result_t result; unsigned char *data; - isc_buffer_t buffer; - isc_buffer_t tcpbuffer; + isc_buffer_t buffer = { .magic = 0 }; + isc_buffer_t tcpbuffer = { .magic = 0 }; isc_region_t r; dns_compress_t cctx; bool cleanup_cctx = false; - unsigned char sendbuf[SEND_BUFFER_SIZE]; unsigned int render_opts; unsigned int preferred_glue; bool opt_included = false; @@ -1205,9 +407,18 @@ client_send(ns_client_t *client) { isc_region_t zr; #endif /* HAVE_DNSTAP */ + /* + * XXXWPK TODO + * Delay the response according to the -T delay option + */ + REQUIRE(NS_CLIENT_VALID(client)); + /* + * We need to do it to make sure the client and handle + * won't disappear from under us with client_senddone. + */ - env = ns_interfacemgr_getaclenv(client->interface->mgr); + env = ns_interfacemgr_getaclenv(client->manager->interface->mgr); CTRACE("send"); @@ -1247,8 +458,7 @@ client_send(ns_client_t *client) { /* * XXXRTH The following doesn't deal with TCP buffer resizing. */ - result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0, - sendbuf, &data); + result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0, &data); if (result != ISC_R_SUCCESS) goto done; @@ -1364,7 +574,6 @@ client_send(ns_client_t *client) { client->sendcb(&buffer); } else if (TCP_CLIENT(client)) { isc_buffer_usedregion(&buffer, &r); - isc_buffer_putuint16(&tcpbuffer, (uint16_t) r.length); isc_buffer_add(&tcpbuffer, r.length); #ifdef HAVE_DNSTAP if (client->view != NULL) { @@ -1377,6 +586,8 @@ client_send(ns_client_t *client) { /* don't count the 2-octet length header */ respsize = isc_buffer_usedlength(&tcpbuffer) - 2; + + isc_nmhandle_ref(client->handle); result = client_sendpkg(client, &tcpbuffer); switch (isc_sockaddr_pf(&client->peeraddr)) { @@ -1408,6 +619,8 @@ client_send(ns_client_t *client) { #endif /* HAVE_DNSTAP */ respsize = isc_buffer_usedlength(&buffer); + + isc_nmhandle_ref(client->handle); result = client_sendpkg(client, &buffer); switch (isc_sockaddr_pf(&client->peeraddr)) { @@ -1446,85 +659,19 @@ client_send(ns_client_t *client) { ns_stats_increment(client->sctx->nsstats, ns_statscounter_truncatedresp); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { return; + } done: if (client->tcpbuf != NULL) { - isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE); + isc_mem_put(client->mctx, client->tcpbuf, + NS_CLIENT_TCP_BUFFER_SIZE); client->tcpbuf = NULL; } if (cleanup_cctx) dns_compress_invalidate(&cctx); - - ns_client_next(client, result); -} - -/* - * Completes the sending of a delayed client response. - */ -static void -client_delay(isc_task_t *task, isc_event_t *event) { - ns_client_t *client; - - REQUIRE(event != NULL); - REQUIRE(event->ev_type == ISC_TIMEREVENT_LIFE || - event->ev_type == ISC_TIMEREVENT_IDLE); - client = event->ev_arg; - REQUIRE(NS_CLIENT_VALID(client)); - REQUIRE(task == client->task); - REQUIRE(client->delaytimer != NULL); - - UNUSED(task); - - CTRACE("client_delay"); - - isc_event_free(&event); - isc_timer_detach(&client->delaytimer); - - client_send(client); - ns_client_detach(&client); -} - -void -ns_client_send(ns_client_t *client) { - /* - * Delay the response according to the -T delay option - */ - if (client->sctx->delay != 0) { - ns_client_t *dummy = NULL; - isc_result_t result; - isc_interval_t interval; - - /* - * Replace ourselves if we have not already been replaced. - */ - if (!client->mortal) { - result = ns_client_replace(client); - if (result != ISC_R_SUCCESS) - goto nodelay; - } - - ns_client_attach(client, &dummy); - if (client->sctx->delay >= 1000) - isc_interval_set(&interval, client->sctx->delay / 1000, - (client->sctx->delay % 1000) * 1000000); - else - isc_interval_set(&interval, 0, - client->sctx->delay * 1000000); - result = isc_timer_create(client->manager->timermgr, - isc_timertype_once, NULL, &interval, - client->task, client_delay, - client, &client->delaytimer); - if (result == ISC_R_SUCCESS) - return; - - ns_client_detach(&dummy); - } - - nodelay: - client_send(client); } #if NS_CLIENT_DROPPORT @@ -1591,7 +738,7 @@ ns_client_error(ns_client_t *client, isc_result_t result) { NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), "dropped error (%.*s) response: suspicious port", (int)isc_buffer_usedlength(&b), buf); - ns_client_next(client, ISC_R_SUCCESS); + ns_client_drop(client, ISC_R_SUCCESS); return; } #endif @@ -1641,7 +788,7 @@ ns_client_error(ns_client_t *client, isc_result_t result) { ns_statscounter_ratedropped); ns_stats_increment(client->sctx->nsstats, ns_statscounter_dropped); - ns_client_next(client, DNS_R_DROP); + ns_client_drop(client, DNS_R_DROP); return; } } @@ -1666,7 +813,7 @@ ns_client_error(ns_client_t *client, isc_result_t result) { */ result = dns_message_reply(message, false); if (result != ISC_R_SUCCESS) { - ns_client_next(client, result); + ns_client_drop(client, result); return; } } @@ -1693,7 +840,7 @@ ns_client_error(ns_client_t *client, isc_result_t result) { NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), "possible error packet loop, " "FORMERR dropped"); - ns_client_next(client, result); + ns_client_drop(client, result); return; } client->formerrcache.addr = client->peeraddr; @@ -1749,7 +896,7 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, REQUIRE(opt != NULL && *opt == NULL); REQUIRE(message != NULL); - env = ns_interfacemgr_getaclenv(client->interface->mgr); + env = ns_interfacemgr_getaclenv(client->manager->interface->mgr); view = client->view; resolver = (view != NULL) ? view->resolver : NULL; if (resolver != NULL) @@ -2324,8 +1471,8 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { case DNS_OPT_TCP_KEEPALIVE: if (!USEKEEPALIVE(client)) ns_stats_increment( - client->sctx->nsstats, - ns_statscounter_keepaliveopt); + client->sctx->nsstats, + ns_statscounter_keepaliveopt); client->attributes |= NS_CLIENTATTR_USEKEEPALIVE; isc_buffer_forward(&optbuf, optlen); @@ -2355,10 +1502,88 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { } } - ns_stats_increment(client->sctx->nsstats, ns_statscounter_edns0in); - client->attributes |= NS_CLIENTATTR_WANTOPT; + ns_stats_increment(client->sctx->nsstats, ns_statscounter_edns0in); + client->attributes |= NS_CLIENTATTR_WANTOPT; + + return (result); +} + +void +ns__client_reset_cb(void *client0) { + ns_client_t *client = client0; + + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "reset client"); + + ns_client_endrequest(client); + if (client->tcpbuf != NULL) { + isc_mem_put(client->mctx, client->tcpbuf, + NS_CLIENT_TCP_BUFFER_SIZE); + } + + if (client->keytag != NULL) { + isc_mem_put(client->mctx, client->keytag, + client->keytag_len); + client->keytag_len = 0; + } + + client->state = NS_CLIENTSTATE_READY; + INSIST(client->recursionquota == NULL); +} + +void +ns__client_put_cb(void *client0) { + ns_client_t *client = client0; + + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "freeing client"); + + /* + * Call this first because it requires a valid client. + */ + ns_query_free(client); + + client->magic = 0; + client->shuttingdown = true; + + if (client->manager != NULL) { + clientmgr_detach(&client->manager); + } + + isc_mem_put(client->mctx, client->recvbuf, NS_CLIENT_RECV_BUFFER_SIZE); + if (client->opt != NULL) { + INSIST(dns_rdataset_isassociated(client->opt)); + dns_rdataset_disassociate(client->opt); + dns_message_puttemprdataset(client->message, + &client->opt); + } + + dns_message_destroy(&client->message); + + /* + * Detaching the task must be done after unlinking from + * the manager's lists because the manager accesses + * client->task. + */ + if (client->task != NULL) { + isc_task_detach(&client->task); + } + + /* + * Destroy the fetchlock mutex that was created in + * ns_query_init(). + */ + isc_mutex_destroy(&client->query.fetchlock); - return (result); + if (client->sctx != NULL) { + ns_server_detach(&client->sctx); + } + + if (client->mctx != NULL) { + isc_mem_detach(&client->mctx); + } } /* @@ -2366,9 +1591,11 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { * or tcpmsg (TCP case). */ void -ns__client_request(isc_task_t *task, isc_event_t *event) { +ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) { ns_client_t *client; - isc_socketevent_t *sevent; + bool newclient = false; + ns_clientmgr_t *mgr; + ns_interface_t *ifp; isc_result_t result; isc_result_t sigresult = ISC_R_SUCCESS; isc_buffer_t *buffer; @@ -2386,91 +1613,70 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { #ifdef HAVE_DNSTAP dns_dtmsgtype_t dtmsgtype; #endif + ifp = (ns_interface_t *) arg; - REQUIRE(event != NULL); - client = event->ev_arg; - REQUIRE(NS_CLIENT_VALID(client)); - REQUIRE(task == client->task); + mgr = ifp->clientmgr; + REQUIRE(VALID_MANAGER(mgr)); + + client = isc_nmhandle_getdata(handle); + if (client == NULL) { + client = isc_nmhandle_getextra(handle); + + result = ns__client_setup(client, mgr, true); + if (result != ISC_R_SUCCESS) { + return; + } + + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "allocate new client"); + } else { + result = ns__client_setup(client, NULL, false); + if (result != ISC_R_SUCCESS) { + return; + } + } + + client->state = NS_CLIENTSTATE_READY; + client->dscp = ifp->dscp; + + isc_task_pause(client->task); + if (client->handle == NULL) { + isc_nmhandle_setdata(handle, client, + ns__client_reset_cb, ns__client_put_cb); + client->handle = handle; + } + if (isc_nmhandle_is_stream(handle)) { + client->attributes |= NS_CLIENTATTR_TCP; + unsigned int curr_tcpquota = + isc_quota_getused(&client->sctx->tcpquota); + ns_stats_update_if_greater(client->sctx->nsstats, + ns_statscounter_tcphighwater, + curr_tcpquota); + } INSIST(client->recursionquota == NULL); - INSIST(client->state == (TCP_CLIENT(client) ? - NS_CLIENTSTATE_READING : - NS_CLIENTSTATE_READY)); + INSIST(client->state == NS_CLIENTSTATE_READY); ns_client_requests++; - if (event->ev_type == ISC_SOCKEVENT_RECVDONE) { - INSIST(!TCP_CLIENT(client)); - sevent = (isc_socketevent_t *)event; - REQUIRE(sevent == client->recvevent); - isc_buffer_init(&tbuffer, sevent->region.base, sevent->n); - isc_buffer_add(&tbuffer, sevent->n); - buffer = &tbuffer; - result = sevent->result; - if (result == ISC_R_SUCCESS) { - client->peeraddr = sevent->address; - client->peeraddr_valid = true; - } - if ((sevent->attributes & ISC_SOCKEVENTATTR_DSCP) != 0) { - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(90), - "received DSCP %d", sevent->dscp); - if (client->dscp == -1) - client->dscp = sevent->dscp; - } - if ((sevent->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) { - client->attributes |= NS_CLIENTATTR_PKTINFO; - client->pktinfo = sevent->pktinfo; - } - if ((sevent->attributes & ISC_SOCKEVENTATTR_MULTICAST) != 0) - client->attributes |= NS_CLIENTATTR_MULTICAST; - client->nrecvs--; - } else { - INSIST(TCP_CLIENT(client)); - INSIST(client->tcpconn != NULL); - REQUIRE(event->ev_type == DNS_EVENT_TCPMSG); - REQUIRE(event->ev_sender == &client->tcpmsg); - buffer = &client->tcpmsg.buffer; - result = client->tcpmsg.result; - INSIST(client->nreads == 1); - /* - * client->peeraddr was set when the connection was accepted. - */ - client->nreads--; - } + isc_buffer_init(&tbuffer, region->base, region->length); + isc_buffer_add(&tbuffer, region->length); + buffer = &tbuffer; + + client->peeraddr = isc_nmhandle_peeraddr(client->handle); + + client->peeraddr_valid = true; reqsize = isc_buffer_usedlength(buffer); - /* don't count the length header */ - if (TCP_CLIENT(client)) - reqsize -= 2; - if (exit_check(client)) { - return; - } - client->state = client->newstate = NS_CLIENTSTATE_WORKING; + client->state = NS_CLIENTSTATE_WORKING; - isc_task_getcurrenttimex(task, &client->requesttime); + TIME_NOW(&client->requesttime); client->tnow = client->requesttime; client->now = isc_time_seconds(&client->tnow); - if (result != ISC_R_SUCCESS) { - if (TCP_CLIENT(client)) { - ns_client_next(client, result); - } else { - if (result != ISC_R_CANCELED) - isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, - ISC_LOG_ERROR, - "UDP client handler shutting " - "down due to fatal receive " - "error: %s", - isc_result_totext(result)); - isc_task_shutdown(client->task); - } - return; - } - isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); #if NS_CLIENT_DROPPORT @@ -2479,7 +1685,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), "dropped request: suspicious port"); - ns_client_next(client, ISC_R_SUCCESS); + isc_task_unpause(client->task); return; } #endif @@ -2493,8 +1699,8 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { * Check the blackhole ACL for UDP only, since TCP is done in * client_newconn. */ - env = ns_interfacemgr_getaclenv(client->interface->mgr); - if (!TCP_CLIENT(client)) { + env = ns_interfacemgr_getaclenv(client->manager->interface->mgr); + if (newclient) { if (client->sctx->blackholeacl != NULL && (dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl, env, &match, NULL) == ISC_R_SUCCESS) && @@ -2503,30 +1709,18 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), "blackholed UDP datagram"); - ns_client_next(client, ISC_R_SUCCESS); + isc_task_unpause(client->task); return; } } - /* - * Silently drop multicast requests for the present. - * XXXMPA revisit this as mDNS spec was published. - */ - if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) { - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2), - "dropping multicast request"); - ns_client_next(client, DNS_R_REFUSED); - return; - } - result = dns_message_peekheader(buffer, &id, &flags); if (result != ISC_R_SUCCESS) { /* * There isn't enough header to determine whether * this was a request or a response. Drop it. */ - ns_client_next(client, result); + isc_task_unpause(client->task); return; } @@ -2536,15 +1730,9 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { * If it's a TCP response, discard it here. */ if ((flags & DNS_MESSAGEFLAG_QR) != 0) { - if (TCP_CLIENT(client)) { - CTRACE("unexpected response"); - ns_client_next(client, DNS_R_FORMERR); - return; - } else { - dns_dispatch_importrecv(client->dispatch, event); - ns_client_next(client, ISC_R_SUCCESS); - return; - } + CTRACE("unexpected response"); + isc_task_unpause(client->task); + return; } /* @@ -2611,34 +1799,20 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { result = DNS_R_FORMERR; } ns_client_error(client, result); + isc_task_unpause(client->task); return; } /* - * Pipeline TCP query processing. + * Disable pipelined TCP query processing if necessary. */ if (TCP_CLIENT(client) && - client->message->opcode != dns_opcode_query) + (client->message->opcode != dns_opcode_query || + (client->sctx->keepresporder != NULL && + dns_acl_allowed(&netaddr, NULL, + client->sctx->keepresporder, env)))) { - client->tcpconn->pipelined = false; - } - if (TCP_CLIENT(client) && client->tcpconn->pipelined) { - /* - * We're pipelining. Replace the client; the - * replacement can read the TCP socket looking - * for new messages and this one can process the - * current message asynchronously. - * - * There will now be at least three clients using this - * TCP socket - one accepting new connections, - * one reading an existing connection to get new - * messages, and one answering the message already - * received. - */ - result = ns_client_replace(client); - if (result != ISC_R_SUCCESS) { - client->tcpconn->pipelined = false; - } + isc_nm_tcpdns_sequential(handle); } dns_opcodestats_increment(client->sctx->opcodestats, @@ -2657,17 +1831,14 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { client->message->rcode = dns_rcode_noerror; - /* RFC1123 section 6.1.3.2 */ - if ((client->attributes & NS_CLIENTATTR_MULTICAST) != 0) - client->message->flags &= ~DNS_MESSAGEFLAG_RD; - /* * Deal with EDNS. */ - if ((client->sctx->options & NS_SERVER_NOEDNS) != 0) + if ((client->sctx->options & NS_SERVER_NOEDNS) != 0) { opt = NULL; - else + } else { opt = dns_message_getopt(client->message); + } client->ecs.source = 0; client->ecs.scope = 0; @@ -2679,6 +1850,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { */ if ((client->sctx->options & NS_SERVER_EDNSFORMERR) != 0) { ns_client_error(client, DNS_R_FORMERR); + isc_task_unpause(client->task); return; } @@ -2687,6 +1859,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { */ if ((client->sctx->options & NS_SERVER_EDNSNOTIMP) != 0) { ns_client_error(client, DNS_R_NOTIMP); + isc_task_unpause(client->task); return; } @@ -2695,6 +1868,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { */ if ((client->sctx->options & NS_SERVER_EDNSREFUSED) != 0) { ns_client_error(client, DNS_R_REFUSED); + isc_task_unpause(client->task); return; } @@ -2702,13 +1876,16 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { * Are we dropping all EDNS queries? */ if ((client->sctx->options & NS_SERVER_DROPEDNS) != 0) { - ns_client_next(client, ISC_R_SUCCESS); + ns_client_drop(client, ISC_R_SUCCESS); + isc_task_unpause(client->task); return; } result = process_opt(client, opt); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + isc_task_unpause(client->task); return; + } } if (client->message->rdclass == 0) { @@ -2719,19 +1896,26 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { result = dns_message_reply(client->message, true); if (result != ISC_R_SUCCESS) { ns_client_error(client, result); + isc_task_unpause(client->task); return; } - if (notimp) + + if (notimp) { client->message->rcode = dns_rcode_notimp; + } + ns_client_send(client); + isc_task_unpause(client->task); return; } + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), "message class could not be determined"); ns_client_dumpmessage(client, "message class could not be determined"); ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR); + isc_task_unpause(client->task); return; } @@ -2743,47 +1927,17 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { * receiving socket (this needs a system call and can be heavy). * For IPv6 UDP queries, we get this from the pktinfo structure (if * supported). + * * If all the attempts fail (this can happen due to memory shortage, * etc), we regard this as an error for safety. */ - if ((client->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0) + if ((client->manager->interface->flags & NS_INTERFACEFLAG_ANYADDR) == 0) isc_netaddr_fromsockaddr(&client->destaddr, - &client->interface->addr); + &client->manager->interface->addr); else { - isc_sockaddr_t sockaddr; - result = ISC_R_FAILURE; - - if (TCP_CLIENT(client)) - result = isc_socket_getsockname(client->tcpsocket, - &sockaddr); - if (result == ISC_R_SUCCESS) - isc_netaddr_fromsockaddr(&client->destaddr, &sockaddr); - if (result != ISC_R_SUCCESS && - client->interface->addr.type.sa.sa_family == AF_INET6 && - (client->attributes & NS_CLIENTATTR_PKTINFO) != 0) { - /* - * XXXJT technically, we should convert the receiving - * interface ID to a proper scope zone ID. However, - * due to the fact there is no standard API for this, - * we only handle link-local addresses and use the - * interface index as link ID. Despite the assumption, - * it should cover most typical cases. - */ - isc_netaddr_fromin6(&client->destaddr, - &client->pktinfo.ipi6_addr); - if (IN6_IS_ADDR_LINKLOCAL(&client->pktinfo.ipi6_addr)) - isc_netaddr_setzone(&client->destaddr, - client->pktinfo.ipi6_ifindex); - result = ISC_R_SUCCESS; - } - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "failed to get request's " - "destination: %s", - isc_result_totext(result)); - ns_client_next(client, ISC_R_SUCCESS); - return; - } + isc_sockaddr_t sockaddr = + isc_nmhandle_localaddr(client->handle); + isc_netaddr_fromsockaddr(&client->destaddr, &sockaddr); } isc_sockaddr_fromnetaddr(&client->destsockaddr, &client->destaddr, 0); @@ -2816,6 +1970,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { "no matching view in class '%s'", classname); ns_client_dumpmessage(client, "no matching view in class"); ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED); + isc_task_unpause(client->task); return; } @@ -2908,14 +2063,17 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { "request has invalid signature: %s (%s)", isc_result_totext(result), tsigrcode); } + /* * Accept update messages signed by unknown keys so that * update forwarding works transparently through slaves * that don't have all the same keys as the master. */ if (!(client->message->tsigstatus == dns_tsigerror_badkey && - client->message->opcode == dns_opcode_update)) { + client->message->opcode == dns_opcode_update)) + { ns_client_error(client, sigresult); + isc_task_unpause(client->task); return; } } @@ -2942,7 +2100,9 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { ns_client_checkaclsilent(client, &client->destaddr, client->view->cacheonacl, true) == ISC_R_SUCCESS) + { ra = true; + } if (ra == true) { client->attributes |= NS_CLIENTATTR_RA; @@ -2984,6 +2144,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { &client->requesttime, NULL, buffer); #endif /* HAVE_DNSTAP */ + isc_nmhandle_ref(client->handle); ns_query_start(client); break; case dns_opcode_update: @@ -2994,11 +2155,13 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { &client->requesttime, NULL, buffer); #endif /* HAVE_DNSTAP */ ns_client_settimeout(client, 60); + isc_nmhandle_ref(client->handle); ns_update_start(client, sigresult); break; case dns_opcode_notify: CTRACE("notify"); ns_client_settimeout(client, 60); + isc_nmhandle_ref(client->handle); ns_notify_start(client); break; case dns_opcode_iquery: @@ -3006,648 +2169,245 @@ ns__client_request(isc_task_t *task, isc_event_t *event) { ns_client_error(client, DNS_R_NOTIMP); break; default: - CTRACE("unknown opcode"); - ns_client_error(client, DNS_R_NOTIMP); - } -} - -static void -client_timeout(isc_task_t *task, isc_event_t *event) { - ns_client_t *client; - - REQUIRE(event != NULL); - REQUIRE(event->ev_type == ISC_TIMEREVENT_LIFE || - event->ev_type == ISC_TIMEREVENT_IDLE); - client = event->ev_arg; - REQUIRE(NS_CLIENT_VALID(client)); - REQUIRE(task == client->task); - REQUIRE(client->timer != NULL); - - UNUSED(task); - - CTRACE("timeout"); - - isc_event_free(&event); - - if (client->shutdown != NULL) { - (client->shutdown)(client->shutdown_arg, ISC_R_TIMEDOUT); - client->shutdown = NULL; - client->shutdown_arg = NULL; - } - - if (client->newstate > NS_CLIENTSTATE_READY) - client->newstate = NS_CLIENTSTATE_READY; - (void)exit_check(client); -} - -static isc_result_t -get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { - isc_mem_t *clientmctx; -#if NMCTXS > 0 - unsigned int nextmctx; -#endif - - MTRACE("clientmctx"); - - /* - * Caller must be holding the manager lock. - */ - if ((manager->sctx->options & NS_SERVER_CLIENTTEST) != 0) { - isc_mem_create(mctxp); - isc_mem_setname(*mctxp, "client", NULL); - return (ISC_R_SUCCESS); - } -#if NMCTXS > 0 - nextmctx = manager->nextmctx++; - if (manager->nextmctx == NMCTXS) - manager->nextmctx = 0; - - INSIST(nextmctx < NMCTXS); - - clientmctx = manager->mctxpool[nextmctx]; - if (clientmctx == NULL) { - isc_mem_create(&clientmctx); - isc_mem_setname(clientmctx, "client", NULL); - - manager->mctxpool[nextmctx] = clientmctx; - } -#else - clientmctx = manager->mctx; -#endif - - isc_mem_attach(clientmctx, mctxp); - - return (ISC_R_SUCCESS); -} - -static isc_result_t -client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { - ns_client_t *client; - isc_result_t result; - isc_mem_t *mctx = NULL; - - /* - * Caller must be holding the manager lock. - * - * Note: creating a client does not add the client to the - * manager's client list or set the client's manager pointer. - * The caller is responsible for that. - */ - - REQUIRE(clientp != NULL && *clientp == NULL); - - result = get_clientmctx(manager, &mctx); - if (result != ISC_R_SUCCESS) - return (result); - - client = isc_mem_get(mctx, sizeof(*client)); - client->mctx = mctx; - - client->sctx = NULL; - ns_server_attach(manager->sctx, &client->sctx); - - client->task = NULL; - result = isc_task_create(manager->taskmgr, 0, &client->task); - if (result != ISC_R_SUCCESS) - goto cleanup_client; - isc_task_setname(client->task, "client", client); - - client->timer = NULL; - result = isc_timer_create(manager->timermgr, isc_timertype_inactive, - NULL, NULL, client->task, client_timeout, - client, &client->timer); - if (result != ISC_R_SUCCESS) - goto cleanup_task; - client->timerset = false; - - client->delaytimer = NULL; - - client->message = NULL; - result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, - &client->message); - if (result != ISC_R_SUCCESS) - goto cleanup_timer; - - /* XXXRTH Hardwired constants */ - - client->sendevent = isc_socket_socketevent(client->mctx, client, - ISC_SOCKEVENT_SENDDONE, - client_senddone, client); - if (client->sendevent == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup_message; - } - - client->recvbuf = isc_mem_get(client->mctx, RECV_BUFFER_SIZE); - - client->recvevent = isc_socket_socketevent(client->mctx, client, - ISC_SOCKEVENT_RECVDONE, - ns__client_request, client); - if (client->recvevent == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup_recvbuf; - } - - client->magic = NS_CLIENT_MAGIC; - client->manager = NULL; - client->state = NS_CLIENTSTATE_INACTIVE; - client->newstate = NS_CLIENTSTATE_MAX; - client->naccepts = 0; - client->nreads = 0; - client->nsends = 0; - client->nrecvs = 0; - client->nupdates = 0; - client->nctls = 0; - isc_refcount_init(&client->references, 0); - client->attributes = 0; - client->view = NULL; - client->dispatch = NULL; - client->udpsocket = NULL; - client->tcplistener = NULL; - client->tcpsocket = NULL; - client->tcpmsg_valid = false; - client->tcpbuf = NULL; - client->opt = NULL; - client->udpsize = 512; - client->dscp = -1; - client->extflags = 0; - client->ednsversion = -1; - client->next = NULL; - client->shutdown = NULL; - client->shutdown_arg = NULL; - client->signer = NULL; - dns_name_init(&client->signername, NULL); - client->mortal = false; - client->sendcb = NULL; - client->tcpconn = NULL; - client->recursionquota = NULL; - client->interface = NULL; - client->peeraddr_valid = false; - dns_ecs_init(&client->ecs); - client->needshutdown = ((client->sctx->options & - NS_SERVER_CLIENTTEST) != 0); - client->tcpactive = false; - - ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL, - NS_EVENT_CLIENTCONTROL, client_start, client, client, - NULL, NULL); - /* - * Initialize FORMERR cache to sentinel value that will not match - * any actual FORMERR response. - */ - isc_sockaddr_any(&client->formerrcache.addr); - client->formerrcache.time = 0; - client->formerrcache.id = 0; - ISC_LINK_INIT(client, link); - ISC_LINK_INIT(client, rlink); - ISC_QLINK_INIT(client, ilink); - client->keytag = NULL; - client->keytag_len = 0; - client->rcode_override = -1; /* not set */ - - /* - * We call the init routines for the various kinds of client here, - * after we have created an otherwise valid client, because some - * of them call routines that REQUIRE(NS_CLIENT_VALID(client)). - */ - result = ns_query_init(client); - if (result != ISC_R_SUCCESS) - goto cleanup_recvevent; - - result = isc_task_onshutdown(client->task, client_shutdown, client); - if (result != ISC_R_SUCCESS) - goto cleanup_query; - - CTRACE("create"); - - *clientp = client; - - return (ISC_R_SUCCESS); - - cleanup_query: - ns_query_free(client); - - cleanup_recvevent: - isc_event_free((isc_event_t **)&client->recvevent); - - cleanup_recvbuf: - isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE); - - isc_event_free((isc_event_t **)&client->sendevent); - - client->magic = 0; - - cleanup_message: - dns_message_destroy(&client->message); - - cleanup_timer: - isc_timer_detach(&client->timer); - - cleanup_task: - isc_task_detach(&client->task); - - cleanup_client: - if (client->sctx != NULL) - ns_server_detach(&client->sctx); - isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); - - return (result); -} - -static void -client_read(ns_client_t *client, bool newconn) { - isc_result_t result; - - CTRACE("read"); - - result = dns_tcpmsg_readmessage(&client->tcpmsg, client->task, - ns__client_request, client); - if (result != ISC_R_SUCCESS) - goto fail; - - /* - * Set a timeout to limit the amount of time we will wait - * for a request on this TCP connection. - */ - read_settimeout(client, newconn); - - client->state = client->newstate = NS_CLIENTSTATE_READING; - INSIST(client->nreads == 0); - INSIST(client->recursionquota == NULL); - client->nreads++; - - return; - fail: - ns_client_next(client, result); -} - -static void -client_newconn(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - ns_client_t *client = event->ev_arg; - isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; - dns_aclenv_t *env; - uint32_t old; - - REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN); - REQUIRE(NS_CLIENT_VALID(client)); - REQUIRE(client->task == task); - - env = ns_interfacemgr_getaclenv(client->interface->mgr); - - UNUSED(task); - - INSIST(client->state == NS_CLIENTSTATE_READY); - - /* - * The accept() was successful and we're now establishing a new - * connection. We need to make note of it in the client and - * interface objects so client objects can do the right thing - * when going inactive in exit_check() (see comments in - * client_accept() for details). - */ - INSIST(client->naccepts == 1); - client->naccepts--; - - old = isc_refcount_decrement(&client->interface->ntcpaccepting); - INSIST(old > 0); - - /* - * We must take ownership of the new socket before the exit - * check to make sure it gets destroyed if we decide to exit. - */ - if (nevent->result == ISC_R_SUCCESS) { - client->tcpsocket = nevent->newsocket; - isc_socket_setname(client->tcpsocket, "client-tcp", NULL); - client->state = NS_CLIENTSTATE_READING; - INSIST(client->recursionquota == NULL); - - (void)isc_socket_getpeername(client->tcpsocket, - &client->peeraddr); - client->peeraddr_valid = true; - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), - "new TCP connection"); - } else { - /* - * XXXRTH What should we do? We're trying to accept but - * it didn't work. If we just give up, then TCP - * service may eventually stop. - * - * For now, we just go idle. - * - * Going idle is probably the right thing if the - * I/O was canceled. - */ - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), - "accept failed: %s", - isc_result_totext(nevent->result)); - tcpconn_detach(client); + CTRACE("unknown opcode"); + ns_client_error(client, DNS_R_NOTIMP); } - if (exit_check(client)) - goto freeevent; - - if (nevent->result == ISC_R_SUCCESS) { - int match; - isc_netaddr_t netaddr; + isc_task_unpause(client->task); +} - isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); +static void +get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) { + isc_mem_t *clientmctx; +#if CLIENT_NMCTXS > 0 + unsigned int nextmctx; +#endif - if (client->sctx->blackholeacl != NULL && - (dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl, - env, &match, NULL) == ISC_R_SUCCESS) && - match > 0) - { - ns_client_log(client, DNS_LOGCATEGORY_SECURITY, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), - "blackholed connection attempt"); - client->newstate = NS_CLIENTSTATE_READY; - (void)exit_check(client); - goto freeevent; - } + MTRACE("clientmctx"); - INSIST(client->tcpmsg_valid == false); - dns_tcpmsg_init(client->mctx, client->tcpsocket, - &client->tcpmsg); - client->tcpmsg_valid = true; +#if CLIENT_NMCTXS > 0 + LOCK(&manager->lock); + if (isc_nm_tid()>=0) { + nextmctx = isc_nm_tid(); + } else { + nextmctx = manager->nextmctx++; + if (manager->nextmctx == CLIENT_NMCTXS) + manager->nextmctx = 0; - /* - * Let a new client take our place immediately, before - * we wait for a request packet. If we don't, - * telnetting to port 53 (once per CPU) will - * deny service to legitimate TCP clients. - */ - result = ns_client_replace(client); - if (result == ISC_R_SUCCESS && - (client->sctx->keepresporder == NULL || - !dns_acl_allowed(&netaddr, NULL, - client->sctx->keepresporder, env))) - { - client->tcpconn->pipelined = true; - } + INSIST(nextmctx < CLIENT_NMCTXS); + } - client_read(client, true); + clientmctx = manager->mctxpool[nextmctx]; + if (clientmctx == NULL) { + isc_mem_create(&clientmctx); + isc_mem_setname(clientmctx, "client", NULL); + manager->mctxpool[nextmctx] = clientmctx; } + UNLOCK(&manager->lock); +#else + clientmctx = manager->mctx; +#endif - freeevent: - isc_event_free(&event); + isc_mem_attach(clientmctx, mctxp); } -static void -client_accept(ns_client_t *client) { +isc_result_t +ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) { isc_result_t result; - CTRACE("accept"); /* - * Set up a new TCP connection. This means try to attach to the - * TCP client quota (tcp-clients), but fail if we're over quota. + * Caller must be holding the manager lock. + * + * Note: creating a client does not add the client to the + * manager's client list or set the client's manager pointer. + * The caller is responsible for that. */ - result = tcpconn_init(client, false); - if (result != ISC_R_SUCCESS) { - bool exit; - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, - "TCP client quota reached: %s", - isc_result_totext(result)); - - /* - * We have exceeded the system-wide TCP client quota. But, - * we can't just block this accept in all cases, because if - * we did, a heavy TCP load on other interfaces might cause - * this interface to be starved, with no clients able to - * accept new connections. - * - * So, we check here to see if any other clients are - * already servicing TCP queries on this interface (whether - * accepting, reading, or processing). If we find that at - * least one client other than this one is active, then - * it's okay *not* to call accept - we can let this - * client go inactive and another will take over when it's - * done. - * - * If there aren't enough active clients on the interface, - * then we can be a little bit flexible about the quota. - * We'll allow *one* extra client through to ensure we're - * listening on every interface; we do this by setting the - * 'force' option to tcpconn_init(). - * - * (Note: In practice this means that the real TCP client - * quota is tcp-clients plus the number of listening - * interfaces plus 1.) - */ - exit = (isc_refcount_current(&client->interface->ntcpactive) > - (client->tcpactive ? 1U : 0U)); - if (exit) { - client->newstate = NS_CLIENTSTATE_INACTIVE; - (void)exit_check(client); - return; - } + REQUIRE(NS_CLIENT_VALID(client) || (new && client != NULL)); + REQUIRE(VALID_MANAGER(mgr) || !new); - result = tcpconn_init(client, true); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - } + if (new) { + *client = (ns_client_t) { + .magic = 0 + }; - /* TCP high-water stats update. */ - unsigned int curr_tcpquota = isc_quota_getused(&client->sctx->tcpquota); - ns_stats_update_if_greater(client->sctx->nsstats, - ns_statscounter_tcphighwater, - curr_tcpquota); + get_clientmctx(mgr, &client->mctx); + clientmgr_attach(mgr, &client->manager); + ns_server_attach(mgr->sctx, &client->sctx); + result = isc_task_create(mgr->taskmgr, 20, &client->task); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + result = dns_message_create(client->mctx, + DNS_MESSAGE_INTENTPARSE, + &client->message); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } - /* - * If this client was set up using get_client() or get_worker(), - * then TCP is already marked active. However, if it was restarted - * from exit_check(), it might not be, so we take care of it now. - */ - mark_tcp_active(client, true); - result = isc_socket_accept(client->tcplistener, client->task, - client_newconn, client); - if (result != ISC_R_SUCCESS) { + client->recvbuf = isc_mem_get(client->mctx, + NS_CLIENT_RECV_BUFFER_SIZE); /* - * XXXRTH What should we do? We're trying to accept but - * it didn't work. If we just give up, then TCP - * service may eventually stop. - * - * For now, we just go idle. + * Set magic earlier than usual because ns_query_init() + * and the functions it calls will require it. */ - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_socket_accept() failed: %s", - isc_result_totext(result)); - - tcpconn_detach(client); - mark_tcp_active(client, false); - return; + client->magic = NS_CLIENT_MAGIC; + result = ns_query_init(client); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + } else { + ns_clientmgr_t *oldmgr = client->manager; + ns_server_t *sctx = client->sctx; + isc_task_t *task = client->task; + unsigned char *recvbuf = client->recvbuf; + dns_message_t *message = client->message; + isc_mem_t *oldmctx = client->mctx; + ns_query_t query = client->query; + + *client = (ns_client_t) { + .magic = 0, + .mctx = oldmctx, + .manager = oldmgr, + .sctx = sctx, + .task = task, + .recvbuf = recvbuf, + .message = message, + .query = query + }; } - /* - * The client's 'naccepts' counter indicates that this client has - * called accept() and is waiting for a new connection. It should - * never exceed 1. - */ - INSIST(client->naccepts == 0); - client->naccepts++; + client->state = NS_CLIENTSTATE_INACTIVE; + client->udpsize = 512; + client->dscp = -1; + client->ednsversion = -1; + dns_name_init(&client->signername, NULL); + dns_ecs_init(&client->ecs); + isc_sockaddr_any(&client->formerrcache.addr); + client->formerrcache.time = 0; + client->formerrcache.id = 0; + ISC_LINK_INIT(client, rlink); + client->rcode_override = -1; /* not set */ - /* - * The interface's 'ntcpaccepting' counter is incremented when - * any client calls accept(), and decremented in client_newconn() - * once the connection is established. - * - * When the client object is shutting down after handling a TCP - * request (see exit_check()), if this value is at least one, that - * means another client has called accept() and is waiting to - * establish the next connection. That means the client may be - * be free to become inactive; otherwise it may need to start - * listening for connections itself to prevent the interface - * going dead. - */ - isc_refcount_increment0(&client->interface->ntcpaccepting); -} + client->magic = NS_CLIENT_MAGIC; -static void -client_udprecv(ns_client_t *client) { - isc_result_t result; - isc_region_t r; + CTRACE("client_setup"); - CTRACE("udprecv"); + return (ISC_R_SUCCESS); - r.base = client->recvbuf; - r.length = RECV_BUFFER_SIZE; - result = isc_socket_recv2(client->udpsocket, &r, 1, - client->task, client->recvevent, 0); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "isc_socket_recv2() failed: %s", - isc_result_totext(result)); - /* - * This cannot happen in the current implementation, since - * isc_socket_recv2() cannot fail if flags == 0. - * - * If this does fail, we just go idle. - */ - return; + cleanup: + if (client->recvbuf != NULL) { + isc_mem_put(client->mctx, client->recvbuf, + NS_CLIENT_RECV_BUFFER_SIZE); } - INSIST(client->nrecvs == 0); - client->nrecvs++; -} - -void -ns_client_attach(ns_client_t *source, ns_client_t **targetp) { - uint32_t oldrefs; - REQUIRE(NS_CLIENT_VALID(source)); - REQUIRE(targetp != NULL && *targetp == NULL); - oldrefs = isc_refcount_increment(&source->references); - ns_client_log(source, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), - "ns_client_attach: ref = %d", oldrefs+1); - *targetp = source; -} + if (client->message != NULL) { + dns_message_destroy(&client->message); + } -void -ns_client_detach(ns_client_t **clientp) { - int32_t oldrefs; - ns_client_t *client = *clientp; - oldrefs = isc_refcount_decrement(&client->references); - INSIST(oldrefs > 0); + if (client->task != NULL) { + isc_task_detach(&client->task); + } - *clientp = NULL; - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10), - "ns_client_detach: ref = %d", oldrefs-1); - (void)exit_check(client); + return (result); } bool ns_client_shuttingdown(ns_client_t *client) { - return (client->newstate == NS_CLIENTSTATE_FREED); + return (client->shuttingdown); } -isc_result_t -ns_client_replace(ns_client_t *client) { - isc_result_t result; - bool tcp; +/*** + *** Client Manager + ***/ - CTRACE("replace"); +static void +clientmgr_attach(ns_clientmgr_t *source, ns_clientmgr_t **targetp) { + int32_t oldrefs; - REQUIRE(client != NULL); - REQUIRE(client->manager != NULL); + REQUIRE(VALID_MANAGER(source)); + REQUIRE(targetp != NULL && *targetp == NULL); - tcp = TCP_CLIENT(client); - if (tcp && client->tcpconn != NULL && client->tcpconn->pipelined) { - result = get_worker(client->manager, client->interface, - client->tcpsocket, client); - } else { - result = get_client(client->manager, client->interface, - client->dispatch, tcp); + oldrefs = isc_refcount_increment(&source->references); + isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "clientmgr @%p attach: %d", source, oldrefs + 1); - } - if (result != ISC_R_SUCCESS) { - return (result); - } + *targetp = source; +} - /* - * The responsibility for listening for new requests is hereby - * transferred to the new client. Therefore, the old client - * should refrain from listening for any more requests. - */ - client->mortal = true; +static void +clientmgr_detach(ns_clientmgr_t **mp) { + ns_clientmgr_t *mgr = *mp; + int32_t oldrefs; + oldrefs = isc_refcount_decrement(&mgr->references); + INSIST(oldrefs > 0); - return (ISC_R_SUCCESS); -} + isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "clientmgr @%p detach: %d", mgr, oldrefs - 1); + if (oldrefs == 1) { + clientmgr_destroy(mgr); + } -/*** - *** Client Manager - ***/ + *mp = NULL; +} static void clientmgr_destroy(ns_clientmgr_t *manager) { -#if NMCTXS > 0 +#if CLIENT_NMCTXS > 0 int i; #endif - REQUIRE(ISC_LIST_EMPTY(manager->clients)); - MTRACE("clientmgr_destroy"); -#if NMCTXS > 0 - for (i = 0; i < NMCTXS; i++) { + manager->magic = 0; + +#if CLIENT_NMCTXS > 0 + for (i = 0; i < CLIENT_NMCTXS; i++) { if (manager->mctxpool[i] != NULL) isc_mem_detach(&manager->mctxpool[i]); } #endif - ISC_QUEUE_DESTROY(manager->inactive); + if (manager->interface != NULL) { + ns_interface_detach(&manager->interface); + } isc_mutex_destroy(&manager->lock); - isc_mutex_destroy(&manager->listlock); isc_mutex_destroy(&manager->reclock); if (manager->excl != NULL) isc_task_detach(&manager->excl); + for (i = 0; i < CLIENT_NTASKS; i++) { + if (manager->taskpool[i] != NULL) { + isc_task_detach(&manager->taskpool[i]); + } + } + isc_mem_put(manager->mctx, manager->taskpool, + CLIENT_NTASKS * sizeof(isc_task_t *)); ns_server_detach(&manager->sctx); - manager->magic = 0; isc_mem_put(manager->mctx, manager, sizeof(*manager)); } isc_result_t ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, ns_clientmgr_t **managerp) + isc_timermgr_t *timermgr, ns_interface_t *interface, + ns_clientmgr_t **managerp) { ns_clientmgr_t *manager; isc_result_t result; -#if NMCTXS > 0 +#if CLIENT_NMCTXS > 0 int i; #endif manager = isc_mem_get(mctx, sizeof(*manager)); + *manager = (ns_clientmgr_t) { .magic = 0 }; isc_mutex_init(&manager->lock); - isc_mutex_init(&manager->listlock); isc_mutex_init(&manager->reclock); manager->excl = NULL; @@ -3659,17 +2419,24 @@ ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, manager->mctx = mctx; manager->taskmgr = taskmgr; manager->timermgr = timermgr; - manager->exiting = false; + ns_interface_attach(interface, &manager->interface); + + manager->exiting = false; + manager->taskpool = + isc_mem_get(mctx, CLIENT_NTASKS*sizeof(isc_task_t *)); + for (i = 0; i < CLIENT_NTASKS; i++) { + manager->taskpool[i] = NULL; + isc_task_create(manager->taskmgr, 20, &manager->taskpool[i]); + } + isc_refcount_init(&manager->references, 1); manager->sctx = NULL; ns_server_attach(sctx, &manager->sctx); - ISC_LIST_INIT(manager->clients); ISC_LIST_INIT(manager->recursing); - ISC_QUEUE_INIT(manager->inactive, ilink); -#if NMCTXS > 0 +#if CLIENT_NMCTXS > 0 manager->nextmctx = 0; - for (i = 0; i < NMCTXS; i++) + for (i = 0; i < CLIENT_NMCTXS; i++) manager->mctxpool[i] = NULL; /* will be created on-demand */ #endif manager->magic = MANAGER_MAGIC; @@ -3682,7 +2449,6 @@ ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, cleanup_reclock: isc_mutex_destroy(&manager->reclock); - isc_mutex_destroy(&manager->listlock); isc_mutex_destroy(&manager->lock); isc_mem_put(manager->mctx, manager, sizeof(*manager)); @@ -3694,8 +2460,8 @@ void ns_clientmgr_destroy(ns_clientmgr_t **managerp) { isc_result_t result; ns_clientmgr_t *manager; - ns_client_t *client; - bool need_destroy = false, unlock = false; + bool unlock = false; + int32_t oldrefs; REQUIRE(managerp != NULL); manager = *managerp; @@ -3703,246 +2469,29 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp) { MTRACE("destroy"); + /* XXXWPK TODO we need to pause netmgr here */ /* * Check for success because we may already be task-exclusive * at this point. Only if we succeed at obtaining an exclusive * lock now will we need to relinquish it later. */ result = isc_task_beginexclusive(manager->excl); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { unlock = true; + } manager->exiting = true; - for (client = ISC_LIST_HEAD(manager->clients); - client != NULL; - client = ISC_LIST_NEXT(client, link)) - isc_task_shutdown(client->task); - - if (ISC_LIST_EMPTY(manager->clients)) - need_destroy = true; - - if (unlock) + if (unlock) { isc_task_endexclusive(manager->excl); - - if (need_destroy) - clientmgr_destroy(manager); - - *managerp = NULL; -} - -static isc_result_t -get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, - dns_dispatch_t *disp, bool tcp) -{ - isc_result_t result = ISC_R_SUCCESS; - isc_event_t *ev; - ns_client_t *client; - MTRACE("get client"); - - REQUIRE(manager != NULL); - - if (manager->exiting) - return (ISC_R_SHUTTINGDOWN); - - /* - * Allocate a client. First try to get a recycled one; - * if that fails, make a new one. - */ - client = NULL; - if ((manager->sctx->options & NS_SERVER_CLIENTTEST) == 0) { - ISC_QUEUE_POP(manager->inactive, ilink, client); - } - - if (client != NULL) { - MTRACE("recycle"); - } else { - MTRACE("create new"); - - LOCK(&manager->lock); - result = client_create(manager, &client); - UNLOCK(&manager->lock); - if (result != ISC_R_SUCCESS) - return (result); - - LOCK(&manager->listlock); - ISC_LIST_APPEND(manager->clients, client, link); - UNLOCK(&manager->listlock); - } - - client->manager = manager; - ns_interface_attach(ifp, &client->interface); - client->state = NS_CLIENTSTATE_READY; - client->sctx = manager->sctx; - INSIST(client->recursionquota == NULL); - - client->dscp = ifp->dscp; - client->rcode_override = -1; /* not set */ - - if (tcp) { - mark_tcp_active(client, true); - - client->attributes |= NS_CLIENTATTR_TCP; - isc_socket_attach(ifp->tcpsocket, - &client->tcplistener); - - } else { - isc_socket_t *sock; - - dns_dispatch_attach(disp, &client->dispatch); - sock = dns_dispatch_getsocket(client->dispatch); - isc_socket_attach(sock, &client->udpsocket); - } - - INSIST(client->nctls == 0); - client->nctls++; - ev = &client->ctlevent; - isc_task_send(client->task, &ev); - - return (result); -} - -static isc_result_t -get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, isc_socket_t *sock, - ns_client_t *oldclient) -{ - isc_result_t result = ISC_R_SUCCESS; - isc_event_t *ev; - ns_client_t *client; - MTRACE("get worker"); - - REQUIRE(manager != NULL); - REQUIRE(oldclient != NULL); - - if (manager->exiting) - return (ISC_R_SHUTTINGDOWN); - - /* - * Allocate a client. First try to get a recycled one; - * if that fails, make a new one. - */ - client = NULL; - if ((manager->sctx->options & NS_SERVER_CLIENTTEST) == 0) - ISC_QUEUE_POP(manager->inactive, ilink, client); - - if (client != NULL) - MTRACE("recycle"); - else { - MTRACE("create new"); - - LOCK(&manager->lock); - result = client_create(manager, &client); - UNLOCK(&manager->lock); - if (result != ISC_R_SUCCESS) - return (result); - - LOCK(&manager->listlock); - ISC_LIST_APPEND(manager->clients, client, link); - UNLOCK(&manager->listlock); - } - - client->manager = manager; - ns_interface_attach(ifp, &client->interface); - client->newstate = client->state = NS_CLIENTSTATE_WORKING; - INSIST(client->recursionquota == NULL); - client->sctx = manager->sctx; - - client->dscp = ifp->dscp; - - client->attributes |= NS_CLIENTATTR_TCP; - client->mortal = true; - client->sendcb = NULL; - client->rcode_override = -1; /* not set */ - - tcpconn_attach(oldclient, client); - mark_tcp_active(client, true); - - isc_socket_attach(ifp->tcpsocket, &client->tcplistener); - isc_socket_attach(sock, &client->tcpsocket); - isc_socket_setname(client->tcpsocket, "worker-tcp", NULL); - (void)isc_socket_getpeername(client->tcpsocket, &client->peeraddr); - client->peeraddr_valid = true; - - INSIST(client->tcpmsg_valid == false); - dns_tcpmsg_init(client->mctx, client->tcpsocket, &client->tcpmsg); - client->tcpmsg_valid = true; - - INSIST(client->nctls == 0); - client->nctls++; - ev = &client->ctlevent; - isc_task_send(client->task, &ev); - - return (result); -} - -isc_result_t -ns__clientmgr_getclient(ns_clientmgr_t *manager, ns_interface_t *ifp, - bool tcp, ns_client_t **clientp) -{ - isc_result_t result = ISC_R_SUCCESS; - ns_client_t *client; - MTRACE("getclient"); - - REQUIRE(VALID_MANAGER(manager)); - REQUIRE(clientp != NULL && *clientp == NULL); - - if (manager->exiting) - return (ISC_R_SHUTTINGDOWN); - - client = NULL; - ISC_QUEUE_POP(manager->inactive, ilink, client); - if (client != NULL) - MTRACE("getclient (recycle)"); - else { - MTRACE("getclient (create)"); - - LOCK(&manager->lock); - result = client_create(manager, &client); - UNLOCK(&manager->lock); - if (result != ISC_R_SUCCESS) - return (result); - - LOCK(&manager->listlock); - ISC_LIST_APPEND(manager->clients, client, link); - UNLOCK(&manager->listlock); - } - - client->manager = manager; - ns_interface_attach(ifp, &client->interface); - client->state = NS_CLIENTSTATE_READY; - INSIST(client->recursionquota == NULL); - - client->dscp = ifp->dscp; - isc_refcount_increment(&client->references); - - if (tcp) { - client->attributes |= NS_CLIENTATTR_TCP; } - *clientp = client; - - return (result); -} - -isc_result_t -ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, - ns_interface_t *ifp, bool tcp) -{ - isc_result_t result = ISC_R_SUCCESS; - unsigned int disp; - - REQUIRE(VALID_MANAGER(manager)); - REQUIRE(n > 0); - - MTRACE("createclients"); - - for (disp = 0; disp < n; disp++) { - result = get_client(manager, ifp, ifp->udpdispatch[disp], tcp); - if (result != ISC_R_SUCCESS) - break; + oldrefs = isc_refcount_decrement(&manager->references); + if (oldrefs == 1) { + clientmgr_destroy(manager); } - return (result); + *managerp = NULL; } isc_sockaddr_t * @@ -3960,7 +2509,8 @@ ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr, dns_acl_t *acl, bool default_allow) { isc_result_t result; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(client->manager->interface->mgr); isc_netaddr_t tmpnetaddr; int match; diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index c75eafb6559..0ad452ad8a1 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -36,10 +36,10 @@ * notified of this by calling one of the following functions * exactly once in the context of its task: * \code - * ns_client_send() (sending a non-error response) + * ns_client_send() (sending a non-error response) * ns_client_sendraw() (sending a raw response) - * ns_client_error() (sending an error response) - * ns_client_next() (sending no response) + * ns_client_error() (sending an error response) + * ns_client_drop() (sending no response, logging the reason) *\endcode * This will release any resources used by the request and * and allow the ns_client_t to listen for the next request. @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -80,58 +81,141 @@ *** Types ***/ -/*% reference-counted TCP connection object */ -typedef struct ns_tcpconn { - isc_refcount_t refs; - isc_quota_t *tcpquota; - bool pipelined; -} ns_tcpconn_t; +#define NS_CLIENT_TCP_BUFFER_SIZE (65535 + 2) +#define NS_CLIENT_SEND_BUFFER_SIZE 4096 +#define NS_CLIENT_RECV_BUFFER_SIZE 4096 + +#define CLIENT_NMCTXS 100 +/*%< + * Number of 'mctx pools' for clients. (Should this be configurable?) + * When enabling threads, we use a pool of memory contexts shared by + * client objects, since concurrent access to a shared context would cause + * heavy contentions. The above constant is expected to be enough for + * completely avoiding contentions among threads for an authoritative-only + * server. + */ + +#define CLIENT_NTASKS 100 +/*%< + * Number of tasks to be used by clients - those are used only when recursing + */ + +/*! + * Client object states. Ordering is significant: higher-numbered + * states are generally "more active", meaning that the client can + * have more dynamically allocated data, outstanding events, etc. + * In the list below, any such properties listed for state N + * also apply to any state > N. + */ + +typedef enum { + NS_CLIENTSTATE_FREED = 0, + /*%< + * The client object no longer exists. + */ + + NS_CLIENTSTATE_INACTIVE = 1, + /*%< + * The client object exists and has a task and timer. + * Its "query" struct and sendbuf are initialized. + * It has a message and OPT, both in the reset state. + */ + + NS_CLIENTSTATE_READY = 2, + /*%< + * The client object is either a TCP or a UDP one, and + * it is associated with a network interface. It is on the + * client manager's list of active clients. + * + * If it is a TCP client object, it has a TCP listener socket + * and an outstanding TCP listen request. + * + * If it is a UDP client object, it has a UDP listener socket + * and an outstanding UDP receive request. + */ + + NS_CLIENTSTATE_WORKING = 3, + /*%< + * The client object has received a request and is working + * on it. It has a view, and it may have any of a non-reset OPT, + * recursion quota, and an outstanding write request. + */ + + NS_CLIENTSTATE_RECURSING = 4, + /*%< + * The client object is recursing. It will be on the + * 'recursing' list. + */ + + NS_CLIENTSTATE_MAX = 5 + /*%< + * Sentinel value used to indicate "no state". + */ +} ns_clientstate_t; + +typedef ISC_LIST(ns_client_t) client_list_t; + +/*% nameserver client manager structure */ +struct ns_clientmgr { + /* Unlocked. */ + unsigned int magic; + + isc_mem_t * mctx; + ns_server_t * sctx; + isc_taskmgr_t * taskmgr; + isc_timermgr_t * timermgr; + isc_task_t * excl; + isc_refcount_t references; + + /* Attached by clients, needed for e.g. recursion */ + isc_task_t ** taskpool; + + ns_interface_t *interface; + + /* Lock covers manager state. */ + isc_mutex_t lock; + bool exiting; + + /* Lock covers the recursing list */ + isc_mutex_t reclock; + client_list_t recursing; /*%< Recursing clients */ + +#if CLIENT_NMCTXS > 0 + /*%< mctx pool for clients. */ + unsigned int nextmctx; + isc_mem_t * mctxpool[CLIENT_NMCTXS]; +#endif +}; /*% nameserver client structure */ struct ns_client { unsigned int magic; isc_mem_t *mctx; + bool allocated; /* Do we need to free it? */ ns_server_t *sctx; ns_clientmgr_t *manager; - int state; - int newstate; + ns_clientstate_t state; int naccepts; int nreads; int nsends; int nrecvs; int nupdates; int nctls; - isc_refcount_t references; - bool tcpactive; - bool needshutdown; /* - * Used by clienttest to get - * the client to go from - * inactive to free state - * by shutting down the - * client's task. - */ + bool shuttingdown; unsigned int attributes; isc_task_t *task; dns_view_t *view; dns_dispatch_t *dispatch; - isc_socket_t *udpsocket; - isc_socket_t *tcplistener; - isc_socket_t *tcpsocket; + isc_nmhandle_t *handle; unsigned char *tcpbuf; - dns_tcpmsg_t tcpmsg; - bool tcpmsg_valid; - isc_timer_t *timer; - isc_timer_t *delaytimer; - bool timerset; dns_message_t *message; - isc_socketevent_t *sendevent; - isc_socketevent_t *recvevent; unsigned char *recvbuf; + unsigned char sendbuf[NS_CLIENT_SEND_BUFFER_SIZE]; dns_rdataset_t *opt; uint16_t udpsize; uint16_t extflags; int16_t ednsversion; /* -1 noedns */ - void (*next)(ns_client_t *); + void (*cleanup)(ns_client_t *); void (*shutdown)(void *arg, isc_result_t result); void *shutdown_arg; ns_query_t query; @@ -141,9 +225,7 @@ struct ns_client { dns_name_t signername; /*%< [T]SIG key name */ dns_name_t *signer; /*%< NULL if not valid sig */ bool mortal; /*%< Die after handling request */ - ns_tcpconn_t *tcpconn; isc_quota_t *recursionquota; - ns_interface_t *interface; isc_sockaddr_t peeraddr; bool peeraddr_valid; @@ -154,7 +236,6 @@ struct ns_client { struct in6_pktinfo pktinfo; isc_dscp_t dscp; - isc_event_t ctlevent; /*% * Information about recent FORMERR response(s), for * FORMERR loop avoidance. This is separate for each @@ -170,9 +251,7 @@ struct ns_client { /*% Callback function to send a response when unit testing */ void (*sendcb)(isc_buffer_t *buf); - ISC_LINK(ns_client_t) link; ISC_LINK(ns_client_t) rlink; - ISC_QLINK(ns_client_t) ilink; unsigned char cookie[8]; uint32_t expire; unsigned char *keytag; @@ -187,9 +266,6 @@ struct ns_client { int32_t rcode_override; }; -typedef ISC_QUEUE(ns_client_t) client_queue_t; -typedef ISC_LIST(ns_client_t) client_list_t; - #define NS_CLIENT_MAGIC ISC_MAGIC('N','S','C','c') #define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC) @@ -256,10 +332,10 @@ ns_client_error(ns_client_t *client, isc_result_t result); */ void -ns_client_next(ns_client_t *client, isc_result_t result); +ns_client_drop(ns_client_t *client, isc_result_t result); /*%< - * Finish processing the current client request, - * return no response to the client. + * Log the reason the current client request has failed; no response + * will be sent. */ bool @@ -268,18 +344,6 @@ ns_client_shuttingdown(ns_client_t *client); * Return true iff the client is currently shutting down. */ -void -ns_client_attach(ns_client_t *source, ns_client_t **target); -/*%< - * Attach '*targetp' to 'source'. - */ - -void -ns_client_detach(ns_client_t **clientp); -/*%< - * Detach '*clientp' from its client. - */ - isc_result_t ns_client_replace(ns_client_t *client); /*%< @@ -296,7 +360,8 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds); isc_result_t ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, ns_clientmgr_t **managerp); + isc_timermgr_t *timermgr, ns_interface_t *ifp, + ns_clientmgr_t **managerp); /*%< * Create a client manager. */ @@ -308,15 +373,6 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp); * managed by it. */ -isc_result_t -ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, - ns_interface_t *ifp, bool tcp); -/*%< - * Create up to 'n' clients listening on interface 'ifp'. - * If 'tcp' is true, the clients will listen for TCP connections, - * otherwise for UDP requests. - */ - isc_sockaddr_t * ns_client_getsockaddr(ns_client_t *client); /*%< @@ -427,16 +483,14 @@ isc_result_t ns_client_addopt(ns_client_t *client, dns_message_t *message, dns_rdataset_t **opt); -isc_result_t -ns__clientmgr_getclient(ns_clientmgr_t *manager, ns_interface_t *ifp, - bool tcp, ns_client_t **clientp); /* * Get a client object from the inactive queue, or create one, as needed. * (Not intended for use outside this module and associated tests.) */ void -ns__client_request(isc_task_t *task, isc_event_t *event); +ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg); + /* * Handle client requests. * (Not intended for use outside this module and associated tests.) @@ -508,4 +562,24 @@ ns_client_findversion(ns_client_t *client, dns_db_t *db); * allocated by ns_client_newdbversion(). */ +isc_result_t +ns__client_setup(ns_client_t *client, ns_clientmgr_t *manager, bool new); +/*%< + * Perform initial setup of an allocated client. + */ + +void +ns__client_reset_cb(void *client0); +/*%< + * Reset the client object so that it can be reused. + */ + +void +ns__client_put_cb(void *client0); +/*%< + * Free all resources allocated to this client object, so that + * it can be freed. + */ + + #endif /* NS_CLIENT_H */ diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 82d76f9e41d..0212460cc4d 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -66,16 +67,18 @@ /*% The nameserver interface structure */ struct ns_interface { unsigned int magic; /*%< Magic number. */ - ns_interfacemgr_t * mgr; /*%< Interface manager. */ + ns_interfacemgr_t *mgr; /*%< Interface manager. */ isc_mutex_t lock; isc_refcount_t references; unsigned int generation; /*%< Generation number. */ isc_sockaddr_t addr; /*%< Address and port. */ - unsigned int flags; /*%< Interface characteristics */ + unsigned int flags; /*%< Interface flags */ char name[32]; /*%< Null terminated. */ - dns_dispatch_t * udpdispatch[MAX_UDP_DISPATCH]; + dns_dispatch_t *udpdispatch[MAX_UDP_DISPATCH]; /*%< UDP dispatchers. */ - isc_socket_t * tcpsocket; /*%< TCP socket. */ + isc_socket_t *tcpsocket; /*%< TCP socket. */ + isc_nmsocket_t *udplistensocket; + isc_nmsocket_t *tcplistensocket; isc_dscp_t dscp; /*%< "listen-on" DSCP value */ isc_refcount_t ntcpaccepting; /*%< Number of clients ready to accept new @@ -86,7 +89,7 @@ struct ns_interface { (whether accepting or connected) */ int nudpdispatch; /*%< Number of UDP dispatches */ - ns_clientmgr_t * clientmgr; /*%< Client manager. */ + ns_clientmgr_t *clientmgr; /*%< Client manager. */ ISC_LINK(ns_interface_t) link; }; @@ -95,15 +98,11 @@ struct ns_interface { ***/ isc_result_t -ns_interfacemgr_create(isc_mem_t *mctx, - ns_server_t *sctx, - isc_taskmgr_t *taskmgr, - isc_timermgr_t *timermgr, - isc_socketmgr_t *socketmgr, - dns_dispatchmgr_t *dispatchmgr, - isc_task_t *task, - unsigned int udpdisp, - dns_geoip_databases_t *geoip, +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, ns_interfacemgr_t **mgrp); /*%< * Create a new interface manager. diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index c4a0f71ecda..fa27bdd4461 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -36,7 +36,6 @@ #define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */ #define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */ #define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */ -#define NS_SERVER_CLIENTTEST 0x00000010U /*%< -T clienttest */ #define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */ #define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */ #define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */ diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index a473d50eea9..0d932857bb6 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -72,6 +73,7 @@ struct ns_interfacemgr { isc_task_t * excl; /*%< Exclusive task. */ isc_timermgr_t * timermgr; /*%< Timer manager. */ isc_socketmgr_t * socketmgr; /*%< Socket manager. */ + isc_nm_t * nm; /*%< Net manager. */ dns_dispatchmgr_t * dispatchmgr; unsigned int generation; /*%< Current generation no. */ ns_listenlist_t * listenon4; @@ -172,6 +174,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, 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, @@ -208,6 +211,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, mgr->taskmgr = taskmgr; mgr->timermgr = timermgr; mgr->socketmgr = socketmgr; + mgr->nm = nm; mgr->dispatchmgr = dispatchmgr; mgr->generation = 1; mgr->listenon4 = NULL; @@ -249,8 +253,9 @@ ns_interfacemgr_create(isc_mem_t *mctx, } mgr->task = NULL; - if (mgr->route != NULL) + if (mgr->route != NULL) { isc_task_attach(task, &mgr->task); + } isc_refcount_init(&mgr->references, (mgr->route != NULL) ? 2 : 1); #else isc_refcount_init(&mgr->references, 1); @@ -379,30 +384,19 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, REQUIRE(NS_INTERFACEMGR_VALID(mgr)); ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); + *ifp = (ns_interface_t){ + .generation = mgr->generation, + .addr = *addr, + .dscp = -1 + }; - ifp->mgr = NULL; - ifp->generation = mgr->generation; - ifp->addr = *addr; - ifp->flags = 0; strlcpy(ifp->name, name, sizeof(ifp->name)); - ifp->clientmgr = NULL; isc_mutex_init(&ifp->lock); - result = ns_clientmgr_create(mgr->mctx, mgr->sctx, - mgr->taskmgr, mgr->timermgr, - &ifp->clientmgr); - if (result != ISC_R_SUCCESS) { - isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, - "ns_clientmgr_create() failed: %s", - isc_result_totext(result)); - goto clientmgr_create_failure; - } - - for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) + for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) { ifp->udpdispatch[disp] = NULL; - - ifp->tcpsocket = NULL; + } /* * Create a single TCP client object. It will replace itself @@ -413,10 +407,6 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, isc_refcount_init(&ifp->ntcpaccepting, 0); isc_refcount_init(&ifp->ntcpactive, 0); - ifp->nudpdispatch = 0; - - ifp->dscp = -1; - ISC_LINK_INIT(ifp, link); ns_interfacemgr_attach(mgr, &ifp->mgr); @@ -424,11 +414,22 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, isc_refcount_init(&ifp->references, 1); ifp->magic = IFACE_MAGIC; + + result = ns_clientmgr_create(mgr->mctx, mgr->sctx, + mgr->taskmgr, mgr->timermgr, ifp, + &ifp->clientmgr); + if (result != ISC_R_SUCCESS) { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, + "ns_clientmgr_create() failed: %s", + isc_result_totext(result)); + goto failure; + } + *ifpret = ifp; return (ISC_R_SUCCESS); - clientmgr_create_failure: + failure: isc_mutex_destroy(&ifp->lock); ifp->magic = 0; @@ -440,127 +441,43 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, static isc_result_t ns_interface_listenudp(ns_interface_t *ifp) { isc_result_t result; - unsigned int attrs; - unsigned int attrmask; - int disp, i; - - attrs = 0; - attrs |= DNS_DISPATCHATTR_UDP; - if (isc_sockaddr_pf(&ifp->addr) == AF_INET) - attrs |= DNS_DISPATCHATTR_IPV4; - else - attrs |= DNS_DISPATCHATTR_IPV6; - attrs |= DNS_DISPATCHATTR_NOLISTEN; - attrs |= DNS_DISPATCHATTR_CANREUSE; - attrmask = 0; - attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; - attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; - - ifp->nudpdispatch = ISC_MIN(ifp->mgr->udpdisp, MAX_UDP_DISPATCH); - for (disp = 0; disp < ifp->nudpdispatch; disp++) { - result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr, - ifp->mgr->socketmgr, - ifp->mgr->taskmgr, &ifp->addr, - 4096, UDPBUFFERS, - 32768, 8219, 8237, - attrs, attrmask, - &ifp->udpdispatch[disp], - disp == 0 - ? NULL - : ifp->udpdispatch[0]); - if (result != ISC_R_SUCCESS) { - isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, - "could not listen on UDP socket: %s", - isc_result_totext(result)); - goto udp_dispatch_failure; - } - - } - - result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch, - ifp, false); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "UDP ns_clientmgr_createclients(): %s", - isc_result_totext(result)); - goto addtodispatch_failure; - } - - return (ISC_R_SUCCESS); - - addtodispatch_failure: - for (i = disp - 1; i >= 0; i--) { - dns_dispatch_changeattributes(ifp->udpdispatch[i], 0, - DNS_DISPATCHATTR_NOLISTEN); - dns_dispatch_detach(&(ifp->udpdispatch[i])); - } - ifp->nudpdispatch = 0; - udp_dispatch_failure: + /* Reserve space for an ns_client_t with the netmgr handle */ + result = isc_nm_listenudp(ifp->mgr->nm, + (isc_nmiface_t *) &ifp->addr, + ns__client_request, ifp, + sizeof(ns_client_t), + &ifp->udplistensocket); return (result); } static isc_result_t -ns_interface_accepttcp(ns_interface_t *ifp) { +ns_interface_listentcp(ns_interface_t *ifp) { isc_result_t result; - /* - * Open a TCP socket. - */ - result = isc_socket_create(ifp->mgr->socketmgr, - isc_sockaddr_pf(&ifp->addr), - isc_sockettype_tcp, - &ifp->tcpsocket); + /* Reserve space for an ns_client_t with the netmgr handle */ + result = isc_nm_listentcpdns(ifp->mgr->nm, + (isc_nmiface_t *) &ifp->addr, + ns__client_request, ifp, + sizeof(ns_client_t), + &ifp->mgr->sctx->tcpquota, + &ifp->tcplistensocket); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating TCP socket: %s", isc_result_totext(result)); - goto tcp_socket_failure; } - isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL); + +#if 0 #ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(ifp->tcpsocket, true); #endif - result = isc_socket_bind(ifp->tcpsocket, &ifp->addr, - ISC_SOCKET_REUSEADDRESS); - if (result != ISC_R_SUCCESS) { - isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, - "binding TCP socket: %s", - isc_result_totext(result)); - goto tcp_bind_failure; - } if (ifp->dscp != -1) isc_socket_dscp(ifp->tcpsocket, ifp->dscp); - result = isc_socket_listen(ifp->tcpsocket, ifp->mgr->backlog); - if (result != ISC_R_SUCCESS) { - isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, - "listening on TCP socket: %s", - isc_result_totext(result)); - goto tcp_listen_failure; - } - - /* - * If/when there a multiple filters listen to the - * result. - */ (void)isc_socket_filter(ifp->tcpsocket, "dataready"); - - result = ns_clientmgr_createclients(ifp->clientmgr, 1, ifp, true); - if (result != ISC_R_SUCCESS) { - UNEXPECTED_ERROR(__FILE__, __LINE__, - "TCP ns_clientmgr_createclients(): %s", - isc_result_totext(result)); - goto accepttcp_failure; - } - return (ISC_R_SUCCESS); - - accepttcp_failure: - tcp_listen_failure: - tcp_bind_failure: - isc_socket_detach(&ifp->tcpsocket); - tcp_socket_failure: +#endif return (result); } @@ -591,7 +508,7 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, if (((mgr->sctx->options & NS_SERVER_NOTCP) == 0) && accept_tcp == true) { - result = ns_interface_accepttcp(ifp); + result = ns_interface_listentcp(ifp); if (result != ISC_R_SUCCESS) { if ((result == ISC_R_ADDRINUSE) && (addr_in_use != NULL)) @@ -617,8 +534,17 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, void ns_interface_shutdown(ns_interface_t *ifp) { - if (ifp->clientmgr != NULL) + if (ifp->udplistensocket != NULL) { + isc_nm_udp_stoplistening(ifp->udplistensocket); + isc_nmsocket_detach(&ifp->udplistensocket); + } + if (ifp->tcplistensocket != NULL) { + isc_nm_tcpdns_stoplistening(ifp->tcplistensocket); + isc_nmsocket_detach(&ifp->tcplistensocket); + } + if (ifp->clientmgr != NULL) { ns_clientmgr_destroy(&ifp->clientmgr); + } } static void diff --git a/lib/ns/notify.c b/lib/ns/notify.c index 714819d69be..be4ef5dca79 100644 --- a/lib/ns/notify.c +++ b/lib/ns/notify.c @@ -53,7 +53,8 @@ respond(ns_client_t *client, isc_result_t result) { if (msg_result != ISC_R_SUCCESS) msg_result = dns_message_reply(message, false); if (msg_result != ISC_R_SUCCESS) { - ns_client_next(client, msg_result); + ns_client_drop(client, msg_result); + isc_nmhandle_unref(client->handle); return; } message->rcode = rcode; @@ -61,7 +62,9 @@ respond(ns_client_t *client, isc_result_t result) { message->flags |= DNS_MESSAGEFLAG_AA; else message->flags &= ~DNS_MESSAGEFLAG_AA; + ns_client_send(client); + isc_nmhandle_unref(client->handle); } void diff --git a/lib/ns/query.c b/lib/ns/query.c index 4e43b1d92c9..7adf04d96f4 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -560,6 +560,7 @@ query_send(ns_client_t *client) { inc_stats(client, counter); ns_client_send(client); + isc_nmhandle_unref(client->handle); } static void @@ -585,17 +586,20 @@ query_error(ns_client_t *client, isc_result_t result, int line) { log_queryerror(client, result, line, loglevel); ns_client_error(client, result); + isc_nmhandle_unref(client->handle); } static void query_next(ns_client_t *client, isc_result_t result) { - if (result == DNS_R_DUPLICATE) + if (result == DNS_R_DUPLICATE) { inc_stats(client, ns_statscounter_duplicate); - else if (result == DNS_R_DROP) + } else if (result == DNS_R_DROP) { inc_stats(client, ns_statscounter_dropped); - else + } else { inc_stats(client, ns_statscounter_failure); - ns_client_next(client, result); + } + ns_client_drop(client, result); + isc_nmhandle_unref(client->handle); } static inline void @@ -655,7 +659,8 @@ query_reset(ns_client_t *client, bool everything) { */ for (dbversion = ISC_LIST_HEAD(client->query.activeversions); dbversion != NULL; - dbversion = dbversion_next) { + dbversion = dbversion_next) + { dbversion_next = ISC_LIST_NEXT(dbversion, link); dns_db_closeversion(dbversion->db, &dbversion->version, false); @@ -742,7 +747,7 @@ query_reset(ns_client_t *client, bool everything) { } static void -query_next_callback(ns_client_t *client) { +query_cleanup(ns_client_t *client) { query_reset(client, false); } @@ -2423,6 +2428,8 @@ free_devent(ns_client_t *client, isc_event_t **eventp, REQUIRE((void*)(*eventp) == (void *)(*deventp)); + CTRACE(ISC_LOG_DEBUG(3), "free_devent"); + if (devent->fetch != NULL) { dns_resolver_destroyfetch(&devent->fetch); } @@ -2438,12 +2445,14 @@ free_devent(ns_client_t *client, isc_event_t **eventp, if (devent->sigrdataset != NULL) { ns_client_putrdataset(client, &devent->sigrdataset); } + /* * If the two pointers are the same then leave the setting of * (*deventp) to NULL to isc_event_free. */ - if ((void *)eventp != (void *)deventp) + if ((void *)eventp != (void *)deventp) { (*deventp) = NULL; + } isc_event_free(eventp); } @@ -2459,14 +2468,17 @@ prefetch_done(isc_task_t *task, isc_event_t *event) { REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(task == client->task); + CTRACE(ISC_LOG_DEBUG(3), "prefetch_done"); + LOCK(&client->query.fetchlock); if (client->query.prefetch != NULL) { INSIST(devent->fetch == client->query.prefetch); client->query.prefetch = NULL; } UNLOCK(&client->query.fetchlock); + free_devent(client, &event, &devent); - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); } static void @@ -2476,40 +2488,38 @@ query_prefetch(ns_client_t *client, dns_name_t *qname, isc_result_t result; isc_sockaddr_t *peeraddr; dns_rdataset_t *tmprdataset; - ns_client_t *dummy = NULL; unsigned int options; + CTRACE(ISC_LOG_DEBUG(3), "query_prefetch"); + if (client->query.prefetch != NULL || client->view->prefetch_trigger == 0U || rdataset->ttl > client->view->prefetch_trigger || (rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0) + { return; + } if (client->recursionquota == NULL) { result = isc_quota_attach(&client->sctx->recursionquota, &client->recursionquota); - if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) { - ns_stats_increment(client->sctx->nsstats, - ns_statscounter_recursclients); - } - if (result == ISC_R_SUCCESS && !client->mortal && - !TCP(client)) - { - result = ns_client_replace(client); - } if (result != ISC_R_SUCCESS) { return; } } tmprdataset = ns_client_newrdataset(client); - if (tmprdataset == NULL) + if (tmprdataset == NULL) { return; - if (!TCP(client)) + } + + if (!TCP(client)) { peeraddr = &client->peeraddr; - else + } else { peeraddr = NULL; - ns_client_attach(client, &dummy); + } + + isc_nmhandle_ref(client->handle); options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH; result = dns_resolver_createfetch(client->view->resolver, qname, rdataset->type, NULL, NULL, @@ -2520,8 +2530,9 @@ query_prefetch(ns_client_t *client, dns_name_t *qname, &client->query.prefetch); if (result != ISC_R_SUCCESS) { ns_client_putrdataset(client, &tmprdataset); - ns_client_detach(&dummy); + isc_nmhandle_unref(client->handle); } + dns_rdataset_clearprefetch(rdataset); ns_stats_increment(client->sctx->nsstats, ns_statscounter_prefetch); @@ -2692,38 +2703,34 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) { isc_result_t result; isc_sockaddr_t *peeraddr; dns_rdataset_t *tmprdataset; - ns_client_t *dummy = NULL; unsigned int options; + CTRACE(ISC_LOG_DEBUG(3), "query_rpzfetch"); + if (client->query.prefetch != NULL) return; if (client->recursionquota == NULL) { result = isc_quota_attach(&client->sctx->recursionquota, &client->recursionquota); - if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) { - ns_stats_increment(client->sctx->nsstats, - ns_statscounter_recursclients); - } - if (result == ISC_R_SUCCESS && !client->mortal && - !TCP(client)) - { - result = ns_client_replace(client); - } if (result != ISC_R_SUCCESS) { return; } } tmprdataset = ns_client_newrdataset(client); - if (tmprdataset == NULL) + if (tmprdataset == NULL) { return; - if (!TCP(client)) + } + + if (!TCP(client)) { peeraddr = &client->peeraddr; - else + } else { peeraddr = NULL; - ns_client_attach(client, &dummy); + } + options = client->query.fetchoptions; + isc_nmhandle_ref(client->handle); result = dns_resolver_createfetch(client->view->resolver, qname, type, NULL, NULL, NULL, peeraddr, client->message->id, options, 0, @@ -2732,7 +2739,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) { &client->query.prefetch); if (result != ISC_R_SUCCESS) { ns_client_putrdataset(client, &tmprdataset); - ns_client_detach(&dummy); + isc_nmhandle_unref(client->handle); } } @@ -4644,7 +4651,8 @@ dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { isc_netaddr_t netaddr; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(client->manager->interface->mgr); dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64); unsigned int flags = 0; unsigned int i, count; @@ -5001,6 +5009,7 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, /* Set this first so CCTRACE will work */ qctx->client = client; + dns_view_attach(client->view, &qctx->view); CCTRACE(ISC_LOG_DEBUG(3), "qctx_init"); @@ -5078,9 +5087,6 @@ qctx_destroy(query_ctx_t *qctx) { CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx); dns_view_detach(&qctx->view); - if (qctx->detach_client) { - ns_client_detach(&qctx->client); - } } /*% @@ -5583,6 +5589,8 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { REQUIRE(task == client->task); REQUIRE(RECURSING(client)); + CTRACE(ISC_LOG_DEBUG(3), "fetch_callback"); + LOCK(&client->query.fetchlock); if (client->query.fetch != NULL) { /* @@ -5605,9 +5613,28 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { UNLOCK(&client->query.fetchlock); INSIST(client->query.fetch == NULL); - client->query.attributes &= ~NS_QUERYATTR_RECURSING; SAVE(fetch, devent->fetch); + /* + * We're done recursing, detach from quota and unlink from + * the manager's recursing-clients list. + */ + + if (client->recursionquota != NULL) { + isc_quota_detach(&client->recursionquota); + ns_stats_decrement(client->sctx->nsstats, + ns_statscounter_recursclients); + } + + LOCK(&client->manager->reclock); + if (ISC_LINK_LINKED(client, rlink)) { + ISC_LIST_UNLINK(client->manager->recursing, client, rlink); + } + UNLOCK(&client->manager->reclock); + + client->query.attributes &= ~NS_QUERYATTR_RECURSING; + client->state = NS_CLIENTSTATE_WORKING; + /* * If this client is shutting down, or this transaction * has timed out, do not resume the find. @@ -5621,10 +5648,6 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { } else { query_next(client, ISC_R_CANCELED); } - /* - * This may destroy the client. - */ - ns_client_detach(&client); } else { query_ctx_t qctx; @@ -5654,6 +5677,7 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { } dns_resolver_destroyfetch(&fetch); + isc_nmhandle_unref(client->handle); } /*% @@ -5733,8 +5757,9 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, recparam_update(&client->query.recparam, qtype, qname, qdomain); - if (!resuming) + if (!resuming) { inc_stats(client, ns_statscounter_recursion); + } /* * We are about to recurse, which means that this client will @@ -5793,22 +5818,10 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, } ns_client_killoldestquery(client); } - if (result == ISC_R_SUCCESS && !client->mortal && - !TCP(client)) { - result = ns_client_replace(client); - if (result != ISC_R_SUCCESS) { - ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_QUERY, - ISC_LOG_WARNING, - "ns_client_replace() failed: %s", - isc_result_totext(result)); - isc_quota_detach(&client->recursionquota); - ns_stats_decrement(client->sctx->nsstats, - ns_statscounter_recursclients); - } - } - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { return (result); + } + ns_client_recursing(client); } @@ -5841,6 +5854,7 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, peeraddr = &client->peeraddr; } + isc_nmhandle_ref(client->handle); result = dns_resolver_createfetch(client->view->resolver, qname, qtype, qdomain, nameservers, NULL, peeraddr, client->message->id, @@ -5849,6 +5863,7 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, client, rdataset, sigrdataset, &client->query.fetch); if (result != ISC_R_SUCCESS) { + isc_nmhandle_unref(client->handle); ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { ns_client_putrdataset(client, &sigrdataset); @@ -5879,6 +5894,8 @@ query_resume(query_ctx_t *qctx) { char tbuf[DNS_RDATATYPE_FORMATSIZE]; #endif + CCTRACE(ISC_LOG_DEBUG(3), "query_resume"); + CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx); qctx->want_restart = false; @@ -6320,6 +6337,8 @@ static isc_result_t query_checkrpz(query_ctx_t *qctx, isc_result_t result) { isc_result_t rresult; + CCTRACE(ISC_LOG_DEBUG(3), "query_checkrpz"); + rresult = rpz_rewrite(qctx->client, qctx->qtype, result, qctx->resuming, qctx->rdataset, qctx->sigrdataset); @@ -6902,6 +6921,8 @@ query_respond_any(query_ctx_t *qctx) { dns_rdatatype_t onetype = 0; /* type to use for minimal-any */ isc_buffer_t b; + CCTRACE(ISC_LOG_DEBUG(3), "query_respond_any"); + CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); result = dns_db_allrdatasets(qctx->db, qctx->node, @@ -7123,6 +7144,8 @@ static void query_getexpire(query_ctx_t *qctx) { dns_zone_t *raw = NULL, *mayberaw; + CCTRACE(ISC_LOG_DEBUG(3), "query_getexpire"); + if (qctx->zone == NULL || !qctx->is_zone || qctx->qtype != dns_rdatatype_soa || qctx->client->query.restarts != 0 || @@ -7177,6 +7200,8 @@ query_addanswer(query_ctx_t *qctx) { dns_rdataset_t **sigrdatasetp = NULL; isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_addanswer"); + CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx); if (qctx->dns64) { @@ -7237,6 +7262,8 @@ static isc_result_t query_respond(query_ctx_t *qctx) { isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_respond"); + /* * Check to see if the AAAA RRset has non-excluded addresses * in it. If not look for a A RRset. @@ -7332,7 +7359,8 @@ query_respond(query_ctx_t *qctx) { static isc_result_t query_dns64(query_ctx_t *qctx) { ns_client_t *client = qctx->client; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(client->manager->interface->mgr); dns_name_t *name, *mname; dns_rdata_t *dns64_rdata; dns_rdata_t rdata = DNS_RDATA_INIT; @@ -7677,6 +7705,8 @@ static isc_result_t query_notfound(query_ctx_t *qctx) { isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_notfound"); + CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx); INSIST(!qctx->is_zone); @@ -7915,6 +7945,8 @@ static isc_result_t query_delegation(query_ctx_t *qctx) { isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_delegation"); + CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx); qctx->authoritative = false; @@ -7989,6 +8021,8 @@ query_delegation_recurse(query_ctx_t *qctx) { isc_result_t result; dns_name_t *qname = qctx->client->query.qname; + CCTRACE(ISC_LOG_DEBUG(3), "query_delegation_recurse"); + if (!RECURSIONOK(qctx->client)) { return (ISC_R_COMPLETE); } @@ -8186,6 +8220,8 @@ static isc_result_t query_nodata(query_ctx_t *qctx, isc_result_t res) { isc_result_t result = res; + CCTRACE(ISC_LOG_DEBUG(3), "query_nodata"); + CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx); #ifdef dns64_bis_return_excluded_addresses @@ -8308,6 +8344,9 @@ query_nodata(query_ctx_t *qctx, isc_result_t res) { isc_result_t query_sign_nodata(query_ctx_t *qctx) { isc_result_t result; + + CCTRACE(ISC_LOG_DEBUG(3), "query_sign_nodata"); + /* * Look for a NSEC3 record if we don't have a NSEC record. */ @@ -8504,6 +8543,8 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { uint32_t ttl; isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain"); + CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx); INSIST(qctx->is_zone || REDIRECT(qctx->client)); @@ -8595,6 +8636,8 @@ static isc_result_t query_redirect(query_ctx_t *qctx) { isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_redirect"); + result = redirect(qctx->client, qctx->fname, qctx->rdataset, &qctx->node, &qctx->db, &qctx->version, qctx->type); @@ -8790,6 +8833,8 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, dns_rdataset_t *cloneset = NULL, *clonesigset = NULL; dns_rdataset_t **sigrdatasetp; + CCTRACE(ISC_LOG_DEBUG(3), "query_synthwildcard"); + /* * We want the answer to be first, so save the * NOQNAME proof's name now or else discard it. @@ -8943,6 +8988,8 @@ query_synthnxdomain(query_ctx_t *qctx, isc_result_t result; dns_rdataset_t *cloneset = NULL, *clonesigset = NULL; + CCTRACE(ISC_LOG_DEBUG(3), "query_synthnxdomain"); + /* * Detemine the correct TTL to use for the SOA and RRSIG */ @@ -9109,6 +9156,8 @@ query_coveringnsec(query_ctx_t *qctx) { isc_result_t result = ISC_R_SUCCESS; unsigned int dboptions = qctx->client->query.dboptions; + CCTRACE(ISC_LOG_DEBUG(3), "query_coveringnsec"); + dns_rdataset_init(&rdataset); dns_rdataset_init(&sigrdataset); @@ -9367,6 +9416,8 @@ query_ncache(query_ctx_t *qctx, isc_result_t result) { result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN); + CCTRACE(ISC_LOG_DEBUG(3), "query_ncache"); + CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx); qctx->authoritative = false; @@ -9402,6 +9453,8 @@ static isc_result_t query_zerottl_refetch(query_ctx_t *qctx) { isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_zerottl_refetch"); + if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) || qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client)) { @@ -9417,8 +9470,7 @@ query_zerottl_refetch(query_ctx_t *qctx) { NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx); - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; + qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; if (qctx->dns64) { qctx->client->query.attributes |= @@ -9450,6 +9502,8 @@ query_cname(query_ctx_t *qctx) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_cname_t cname; + CCTRACE(ISC_LOG_DEBUG(3), "query_cname"); + CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx); result = query_zerottl_refetch(qctx); @@ -9559,6 +9613,8 @@ query_dname(query_ctx_t *qctx) { isc_result_t result; unsigned int nlabels; + CCTRACE(ISC_LOG_DEBUG(3), "query_dname"); + CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx); /* @@ -9774,6 +9830,8 @@ static isc_result_t query_prepresponse(query_ctx_t *qctx) { isc_result_t result; + CCTRACE(ISC_LOG_DEBUG(3), "query_prepresponse"); + CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx); if (WANTDNSSEC(qctx->client) && @@ -10599,7 +10657,8 @@ static void query_setup_sortlist(query_ctx_t *qctx) { isc_netaddr_t netaddr; ns_client_t *client = qctx->client; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(client->manager->interface->mgr); const void *order_arg = NULL; isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); @@ -10932,7 +10991,6 @@ ns_query_start(ns_client_t *client) { isc_result_t result; dns_message_t *message; dns_rdataset_t *rdataset; - ns_client_t *qclient; dns_rdatatype_t qtype; unsigned int saved_extflags; unsigned int saved_flags; @@ -10945,26 +11003,10 @@ ns_query_start(ns_client_t *client) { CTRACE(ISC_LOG_DEBUG(3), "ns_query_start"); - /* - * Test only. - */ - if (((client->sctx->options & NS_SERVER_CLIENTTEST) != 0) && - !TCP(client)) - { - result = ns_client_replace(client); - if (result == ISC_R_SHUTTINGDOWN) { - ns_client_next(client, result); - return; - } else if (result != ISC_R_SUCCESS) { - query_error(client, result, __LINE__); - return; - } - } - /* * Ensure that appropriate cleanups occur. */ - client->next = query_next_callback; + client->cleanup = query_cleanup; if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) client->query.attributes |= NS_QUERYATTR_WANTRECURSION; @@ -11035,8 +11077,9 @@ ns_query_start(ns_client_t *client) { * section. */ query_error(client, DNS_R_FORMERR, __LINE__); - } else + } else { query_error(client, result, __LINE__); + } return; } @@ -11069,10 +11112,11 @@ ns_query_start(ns_client_t *client) { result = dns_tkey_processquery(client->message, client->sctx->tkeyctx, client->view->dynamickeys); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { query_send(client); - else + } else { query_error(client, result, __LINE__); + } return; default: /* TSIG, etc. */ query_error(client, DNS_R_FORMERR, __LINE__); @@ -11118,8 +11162,9 @@ ns_query_start(ns_client_t *client) { { client->query.dboptions |= DNS_DBFIND_PENDINGOK; client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE; - } else if (!client->view->enablevalidation) + } else if (!client->view->enablevalidation) { client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE; + } if (client->view->qminimization) { client->query.fetchoptions |= DNS_FETCHOPT_QMINIMIZE | @@ -11172,7 +11217,5 @@ ns_query_start(ns_client_t *client) { if (WANTDNSSEC(client) || WANTAD(client)) message->flags |= DNS_MESSAGEFLAG_AD; - qclient = NULL; - ns_client_attach(client, &qclient); - (void)query_setup(qclient, qtype); + (void)query_setup(client, qtype); } diff --git a/lib/ns/tests/Makefile.in b/lib/ns/tests/Makefile.in index 8b952a6375c..0ba61773ffe 100644 --- a/lib/ns/tests/Makefile.in +++ b/lib/ns/tests/Makefile.in @@ -15,6 +15,8 @@ VERSION=@BIND9_VERSION@ @BIND9_MAKE_INCLUDES@ +WRAP_OPTIONS = -Wl,--wrap=isc_nmhandle_unref + CINCLUDES = -I. -Iinclude ${NS_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \ ${OPENSSL_CFLAGS} \ @CMOCKA_CFLAGS@ @@ -29,6 +31,12 @@ NSDEPLIBS = ../libns.@A@ LIBS = @LIBS@ @CMOCKA_LIBS@ +SO_CFLAGS = @CFLAGS@ @SO_CFLAGS@ +SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ + +SO_OBJS = wrap.@O@ +SO_SRCS = wrap.c +SO_TARGETS = libwrap.la OBJS = nstest.@O@ SRCS = nstest.c \ @@ -41,29 +49,39 @@ SUBDIRS = TARGETS = listenlist_test@EXEEXT@ \ notify_test@EXEEXT@ \ plugin_test@EXEEXT@ \ - query_test@EXEEXT@ + query_test@EXEEXT@ \ + @SO_TARGETS@ + +LD_WRAP_TESTS=@LD_WRAP_TESTS@ @BIND9_MAKE_RULES@ -listenlist_test@EXEEXT@: listenlist_test.@O@ nstest.@O@ ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} +libwrap.la: wrap.@O@ + ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -Wl,-z,interpose -o $@ wrap.@O@ ${LIBS} + +listenlist_test@EXEEXT@: listenlist_test.@O@ nstest.@O@ libwrap.la ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} + if test "${LD_WRAP_TESTS}" = true -a -z "${LIBTOOL}"; then WRAP="${WRAP_OPTIONS}"; fi; \ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \ - ${LDFLAGS} -o $@ listenlist_test.@O@ nstest.@O@ \ - ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} + ${LDFLAGS} $${WRAP} -Wl,-rpath=${top_builddir}/lib/ns/tests -o $@ listenlist_test.@O@ nstest.@O@ \ + libwrap.la ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} -notify_test@EXEEXT@: notify_test.@O@ nstest.@O@ ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} +notify_test@EXEEXT@: notify_test.@O@ nstest.@O@ libwrap.la ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} + if test "${LD_WRAP_TESTS}" = true -a -z "${LIBTOOL}"; then WRAP="${WRAP_OPTIONS}"; fi; \ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \ - ${LDFLAGS} -o $@ notify_test.@O@ nstest.@O@ \ - ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} + ${LDFLAGS} $${WRAP} -Wl,-rpath=${top_builddir}/lib/ns/tests -o $@ notify_test.@O@ nstest.@O@ libwrap.la \ + libwrap.la ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} -plugin_test@EXEEXT@: plugin_test.@O@ nstest.@O@ ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} +plugin_test@EXEEXT@: plugin_test.@O@ nstest.@O@ libwrap.la ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} + if test "${LD_WRAP_TESTS}" = true -a -z "${LIBTOOL}"; then WRAP="${WRAP_OPTIONS}"; fi; \ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \ - ${LDFLAGS} -o $@ plugin_test.@O@ nstest.@O@ \ - ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} + ${LDFLAGS} $${WRAP} -Wl,-rpath=${top_builddir}/lib/ns/tests -o $@ plugin_test.@O@ nstest.@O@ \ + libwrap.la ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} -query_test@EXEEXT@: query_test.@O@ nstest.@O@ ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} +query_test@EXEEXT@: query_test.@O@ nstest.@O@ libwrap.la ${NSDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} + if test "${LD_WRAP_TESTS}" = true -a -z "${LIBTOOL}"; then WRAP="${WRAP_OPTIONS}"; fi; \ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \ - ${LDFLAGS} -o $@ query_test.@O@ nstest.@O@ \ - ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} + ${LDFLAGS} $${WRAP} -Wl,-rpath=${top_builddir}/lib/ns/tests -o $@ query_test.@O@ nstest.@O@ \ + libwrap.la ${NSLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} unit:: sh ${top_builddir}/unit/unittest.sh diff --git a/lib/ns/tests/listenlist_test.c b/lib/ns/tests/listenlist_test.c index 32466d1e0c2..ca8130b181d 100644 --- a/lib/ns/tests/listenlist_test.c +++ b/lib/ns/tests/listenlist_test.c @@ -119,6 +119,15 @@ main(void) { _setup, _teardown), }; + /* + * We disable this test when the address sanitizer is in + * the use, as libuv will trigger errors. + */ + if (getenv("ASAN_OPTIONS") != NULL) { + printf("1..0 # Skip ASAN is in use\n"); + return (0); + } + return (cmocka_run_group_tests(tests, NULL, NULL)); } #else /* HAVE_CMOCKA */ @@ -127,7 +136,7 @@ main(void) { int main(void) { - printf("1..0 # Skipped: cmocka not available\n"); + printf("1..0 # Skip cmocka not available\n"); return (0); } diff --git a/lib/ns/tests/notify_test.c b/lib/ns/tests/notify_test.c index 8cae1652093..7f3974dd67d 100644 --- a/lib/ns/tests/notify_test.c +++ b/lib/ns/tests/notify_test.c @@ -136,8 +136,7 @@ notify_start(void **state) { * Clean up */ ns_test_cleanup_zone(); - - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); } int @@ -147,6 +146,15 @@ main(void) { _setup, _teardown), }; + /* + * We disable this test when the address sanitizer is in + * the use, as libuv will trigger errors. + */ + if (getenv("ASAN_OPTIONS") != NULL) { + printf("1..0 # Skip ASAN is in use\n"); + return (0); + } + return (cmocka_run_group_tests(tests, NULL, NULL)); } #else /* HAVE_CMOCKA */ @@ -155,7 +163,7 @@ main(void) { int main(void) { - printf("1..0 # Skipped: cmocka not available\n"); + printf("1..0 # Skip cmocka not available\n"); return (0); } diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index cf7f00256e2..1d0354ff19c 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ isc_taskmgr_t *taskmgr = NULL; isc_task_t *maintask = NULL; isc_timermgr_t *timermgr = NULL; isc_socketmgr_t *socketmgr = NULL; +isc_nm_t *nm = NULL; dns_zonemgr_t *zonemgr = NULL; dns_dispatchmgr_t *dispatchmgr = NULL; ns_clientmgr_t *clientmgr = NULL; @@ -70,6 +72,37 @@ static bool test_running = false; static dns_zone_t *served_zone = NULL; +/* + * We don't want to use netmgr-based client accounting, we need to emulate it. + */ +atomic_uint_fast32_t client_refs[16]; +atomic_uintptr_t client_addrs[16]; + +void +__wrap_isc_nmhandle_unref(isc_nmhandle_t *handle); + +void +__wrap_isc_nmhandle_unref(isc_nmhandle_t *handle) { + ns_client_t *client = (ns_client_t *)handle; + int i; + + for (i = 0; i < 16; i++) { + if (atomic_load(&client_addrs[i]) == (uintptr_t) client) { + break; + } + } + REQUIRE(i < 16); + + if (atomic_fetch_sub(&client_refs[i], 1) == 1) { + dns_view_detach(&client->view); + client->state = 4; + ns__client_reset_cb(client); + ns__client_put_cb(client); + isc_mem_put(mctx, client, sizeof(ns_client_t)); + } + return; +} + /* * Logging categories: this needs to match the list in lib/ns/log.c. */ @@ -108,10 +141,6 @@ static void shutdown_managers(isc_task_t *task, isc_event_t *event) { UNUSED(task); - if (clientmgr != NULL) { - ns_clientmgr_destroy(&clientmgr); - } - if (interfacemgr != NULL) { ns_interfacemgr_shutdown(interfacemgr); ns_interfacemgr_detach(&interfacemgr); @@ -148,9 +177,22 @@ cleanup_managers(void) { if (sctx != NULL) { ns_server_detach(&sctx); } + if (interfacemgr != NULL) { + ns_interfacemgr_detach(&interfacemgr); + } if (socketmgr != NULL) { isc_socketmgr_destroy(&socketmgr); } + ns_test_nap(500000); + if (nm != NULL ){ + /* + * Force something in the workqueue as a workaround + * for libuv bug - not sending uv_close callback. + */ + isc_nm_pause(nm); + isc_nm_resume(nm); + isc_nm_detach(&nm); + } if (taskmgr != NULL) { isc_taskmgr_destroy(&taskmgr); } @@ -186,17 +228,16 @@ create_managers(void) { CHECK(isc_socketmgr_create(mctx, &socketmgr)); + nm = isc_nm_start(mctx, ncpus); + CHECK(ns_server_create(mctx, matchview, &sctx)); CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr, - socketmgr, dispatchmgr, maintask, + socketmgr, nm, dispatchmgr, maintask, ncpus, NULL, &interfacemgr)); - CHECK(ns_clientmgr_create(mctx, sctx, taskmgr, timermgr, - &clientmgr)); - CHECK(ns_listenlist_default(mctx, 5300, -1, true, &listenon)); ns_interfacemgr_setlistenon4(interfacemgr, listenon); ns_listenlist_detach(&listenon); @@ -212,6 +253,8 @@ create_managers(void) { * we'll just sleep for a bit and hope. */ ns_test_nap(500000); + ns_interface_t *ifp = ns__interfacemgr_getif(interfacemgr); + clientmgr = ifp->clientmgr; run_managers = true; @@ -510,16 +553,28 @@ ns_test_getclient(ns_interface_t *ifp0, bool tcp, ns_client_t **clientp) { isc_result_t result; - ns_interface_t *ifp = ifp0; + ns_client_t *client = isc_mem_get(mctx, sizeof(ns_client_t)); + int i; - if (ifp == NULL) { - ifp = ns__interfacemgr_getif(interfacemgr); - } - if (ifp == NULL) { - return (ISC_R_FAILURE); + UNUSED(ifp0); + UNUSED(tcp); + + result = ns__client_setup(client, clientmgr, true); + + for (i = 0; i < 16; i++) { + if (atomic_load(&client_addrs[i]) == (uintptr_t) NULL || + atomic_load(&client_addrs[i]) == (uintptr_t) client) + { + break; + } } + REQUIRE(i < 16); + + atomic_store(&client_refs[i], 2); + atomic_store(&client_addrs[i], (uintptr_t) client); + client->handle = (isc_nmhandle_t *) client; /* Hack */ + *clientp = client; - result = ns__clientmgr_getclient(clientmgr, ifp, tcp, clientp); return (result); } @@ -765,14 +820,14 @@ ns_test_qctx_create(const ns_test_qctx_create_params_t *params, * Reference count for "client" is now at 2, so decrement it in order * for it to drop to zero when "qctx" gets destroyed. */ - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); return (ISC_R_SUCCESS); destroy_query: dns_message_destroy(&client->message); detach_client: - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); return (result); } @@ -786,14 +841,15 @@ ns_test_qctx_destroy(query_ctx_t **qctxp) { qctx = *qctxp; - ns_client_detach(&qctx->client); - if (qctx->zone != NULL) { dns_zone_detach(&qctx->zone); } if (qctx->db != NULL) { dns_db_detach(&qctx->db); } + if (qctx->client != NULL) { + isc_nmhandle_unref(qctx->client->handle); + } isc_mem_put(mctx, qctx, sizeof(*qctx)); *qctxp = NULL; diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index 415de2a8874..3540a3f91e6 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -598,6 +598,15 @@ main(void) { _setup, _teardown), }; + /* + * We disable this test when the address sanitizer is in + * the use, as libuv will trigger errors. + */ + if (getenv("ASAN_OPTIONS") != NULL) { + printf("1..0 # Skip ASAN is in use\n"); + return (0); + } + return (cmocka_run_group_tests(tests, NULL, NULL)); } #else /* HAVE_CMOCKA */ @@ -606,7 +615,7 @@ main(void) { int main(void) { - printf("1..0 # Skipped: cmocka not available\n"); + printf("1..0 # Skip cmocka not available\n"); return (0); } diff --git a/lib/ns/tests/wrap.c b/lib/ns/tests/wrap.c new file mode 100644 index 00000000000..41b8449fc6f --- /dev/null +++ b/lib/ns/tests/wrap.c @@ -0,0 +1,40 @@ +/* + * 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 http://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 + +#include + +#include + +/* + * This overrides calls to isc_nmhandle_unref(), sending them to + * __wrap_isc_nmhandle_unref(), when libtool is in use and LD_WRAP + * can't be used. + */ + +extern void +__wrap_isc_nmhandle_unref(isc_nmhandle_t *handle); + +void +isc_nmhandle_unref(isc_nmhandle_t *handle) { + __wrap_isc_nmhandle_unref(handle); +} diff --git a/lib/ns/update.c b/lib/ns/update.c index 3baf428bd88..bdf55c10a9a 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -1529,7 +1529,6 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { isc_result_t result = ISC_R_SUCCESS; update_event_t *event = NULL; isc_task_t *zonetask = NULL; - ns_client_t *evclient; event = (update_event_t *) isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, @@ -1537,12 +1536,11 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { event->zone = zone; event->result = ISC_R_SUCCESS; - evclient = NULL; - ns_client_attach(client, &evclient); INSIST(client->nupdates == 0); client->nupdates++; - event->ev_arg = evclient; + event->ev_arg = client; + isc_nmhandle_ref(client->handle); dns_zone_gettask(zone, &zonetask); isc_task_send(zonetask, ISC_EVENT_PTR(&event)); @@ -1559,6 +1557,7 @@ respond(ns_client_t *client, isc_result_t result) { client->message->rcode = dns_result_torcode(result); ns_client_send(client); + isc_nmhandle_unref(client->handle); return; msg_failure: @@ -1566,7 +1565,8 @@ respond(ns_client_t *client, isc_result_t result) { ISC_LOG_ERROR, "could not create update response message: %s", isc_result_totext(msg_result)); - ns_client_next(client, msg_result); + ns_client_drop(client, msg_result); + isc_nmhandle_unref(client->handle); } void @@ -2518,7 +2518,8 @@ update_action(isc_task_t *task, isc_event_t *event) { dns_ttl_t maxttl = 0; uint32_t maxrecords; uint64_t records; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_aclenv_t *env = + ns_interfacemgr_getaclenv(client->manager->interface->mgr); INSIST(event->ev_type == DNS_EVENT_UPDATE); @@ -3389,7 +3390,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) { client->nupdates--; respond(client, uev->result); isc_event_free(&event); - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); } /*% @@ -3406,10 +3407,9 @@ forward_fail(isc_task_t *task, isc_event_t *event) { client->nupdates--; respond(client, DNS_R_SERVFAIL); isc_event_free(&event); - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); } - static void forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { update_event_t *uev = arg; @@ -3443,7 +3443,7 @@ forward_done(isc_task_t *task, isc_event_t *event) { ns_client_sendraw(client, uev->answer); dns_message_destroy(&uev->answer); isc_event_free(&event); - ns_client_detach(&client); + isc_nmhandle_unref(client->handle); } static void @@ -3461,8 +3461,10 @@ forward_action(isc_task_t *task, isc_event_t *event) { isc_task_send(client->task, &event); inc_stats(client, zone, ns_statscounter_updatefwdfail); dns_zone_detach(&zone); - } else + } else { inc_stats(client, zone, ns_statscounter_updatereqfwd); + } + isc_task_detach(&task); } @@ -3473,13 +3475,6 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { isc_result_t result = ISC_R_SUCCESS; update_event_t *event = NULL; isc_task_t *zonetask = NULL; - ns_client_t *evclient; - - /* - * This may take some time so replace this client. - */ - if (!client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0) - CHECK(ns_client_replace(client)); event = (update_event_t *) isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, @@ -3487,11 +3482,9 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { event->zone = zone; event->result = ISC_R_SUCCESS; - evclient = NULL; - ns_client_attach(client, &evclient); INSIST(client->nupdates == 0); client->nupdates++; - event->ev_arg = evclient; + event->ev_arg = client; dns_name_format(dns_zone_getorigin(zone), namebuf, sizeof(namebuf)); @@ -3503,10 +3496,11 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { namebuf, classbuf); dns_zone_gettask(zone, &zonetask); + isc_nmhandle_ref(client->handle); isc_task_send(zonetask, ISC_EVENT_PTR(&event)); - failure: - if (event != NULL) + if (event != NULL) { isc_event_free(ISC_EVENT_PTR(&event)); + } return (result); } diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index d221b0d5b2e..2105a3e4931 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -3,18 +3,19 @@ LIBRARY libns ; Exported Functions EXPORTS +ns__client_put_cb ns__client_request -ns__clientmgr_getclient +ns__client_reset_cb +ns__client_setup ns__interfacemgr_getif ns__interfacemgr_nextif ns__query_sfcache ns__query_start ns_client_aclmsg ns_client_addopt -ns_client_attach ns_client_checkacl ns_client_checkaclsilent -ns_client_detach +ns_client_drop ns_client_dumprecursing ns_client_error ns_client_findversion @@ -29,19 +30,16 @@ ns_client_newdbversion ns_client_newname ns_client_newnamebuf ns_client_newrdataset -ns_client_next ns_client_putrdataset ns_client_qnamereplace ns_client_recursing ns_client_releasename -ns_client_replace ns_client_send ns_client_sendraw ns_client_settimeout ns_client_shuttingdown ns_client_sourceip ns_clientmgr_create -ns_clientmgr_createclients ns_clientmgr_destroy ns_hook_add ns_hooktable_create diff --git a/lib/ns/win32/libns.vcxproj.filters b/lib/ns/win32/libns.vcxproj.filters index 499e7380f04..2931412cbf7 100644 --- a/lib/ns/win32/libns.vcxproj.filters +++ b/lib/ns/win32/libns.vcxproj.filters @@ -18,12 +18,6 @@ - - Library Source Files - - - Library Source Files - Source Files @@ -63,6 +57,12 @@ Source Files + + Source Files + + + Source Files + @@ -111,4 +111,4 @@ Header Files - + \ No newline at end of file diff --git a/lib/ns/xfrout.c b/lib/ns/xfrout.c index 7672f59d9a5..9c393c63acd 100644 --- a/lib/ns/xfrout.c +++ b/lib/ns/xfrout.c @@ -669,6 +669,7 @@ typedef struct { names and rdatas */ isc_buffer_t txlenbuf; /* Transmit length buffer */ isc_buffer_t txbuf; /* Transmit message buffer */ + size_t cbytes; /* Length of current message */ void *txmem; unsigned int txmemlen; dns_tsigkey_t *tsigkey; /* Key used to create TSIG */ @@ -682,24 +683,21 @@ typedef struct { struct xfr_stats stats; /*%< Transfer statistics */ } xfrout_ctx_t; -static isc_result_t +static void xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, dns_rdataclass_t qclass, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, rrstream_t *stream, dns_tsigkey_t *tsigkey, - isc_buffer_t *lasttsig, - bool verified_tsig, - unsigned int maxtime, - unsigned int idletime, - bool many_answers, - xfrout_ctx_t **xfrp); + isc_buffer_t *lasttsig, bool verified_tsig, + unsigned int maxtime, unsigned int idletime, + bool many_answers, xfrout_ctx_t **xfrp); static void sendstream(xfrout_ctx_t *xfr); static void -xfrout_senddone(isc_task_t *task, isc_event_t *event); +xfrout_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg); static void xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg); @@ -1067,29 +1065,26 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { if (is_dlz) { - CHECK(xfrout_ctx_create(mctx, client, request->id, - question_name, reqtype, question_class, - zone, db, ver, quota, stream, - dns_message_gettsigkey(request), - tsigbuf, - request->verified_sig, - 3600, - 3600, - (format == dns_many_answers) ? - true : false, - &xfr)); + xfrout_ctx_create(mctx, client, request->id, + question_name, reqtype, question_class, + zone, db, ver, quota, stream, + dns_message_gettsigkey(request), + tsigbuf, request->verified_sig, + 3600, 3600, + (format == dns_many_answers) + ? true : false, + &xfr); } else { - CHECK(xfrout_ctx_create(mctx, client, request->id, - question_name, reqtype, question_class, - zone, db, ver, quota, stream, - dns_message_gettsigkey(request), - tsigbuf, - request->verified_sig, - dns_zone_getmaxxfrout(zone), - dns_zone_getidleout(zone), - (format == dns_many_answers) ? - true : false, - &xfr)); + xfrout_ctx_create(mctx, client, request->id, + question_name, reqtype, question_class, + zone, db, ver, quota, stream, + dns_message_gettsigkey(request), + tsigbuf, request->verified_sig, + dns_zone_getmaxxfrout(zone), + dns_zone_getidleout(zone), + (format == dns_many_answers) + ? true : false, + &xfr); } xfr->mnemonic = mnemonic; @@ -1189,10 +1184,11 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3), "zone transfer setup failed"); ns_client_error(client, result); + isc_nmhandle_unref(client->handle); } } -static isc_result_t +static void xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, dns_rdataclass_t qclass, dns_zone_t *zone, @@ -1203,16 +1199,18 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, bool many_answers, xfrout_ctx_t **xfrp) { xfrout_ctx_t *xfr; - isc_result_t result; unsigned int len; void *mem; - INSIST(xfrp != NULL && *xfrp == NULL); + REQUIRE(xfrp != NULL && *xfrp == NULL); + + UNUSED(maxtime); + UNUSED(idletime); + xfr = isc_mem_get(mctx, sizeof(*xfr)); xfr->mctx = NULL; isc_mem_attach(mctx, &xfr->mctx); - xfr->client = NULL; - ns_client_attach(client, &xfr->client); + xfr->client = client; xfr->id = id; xfr->qname = qname; xfr->qtype = qtype; @@ -1271,8 +1269,10 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, xfr->txmem = mem; xfr->txmemlen = len; +#if 0 CHECK(dns_timer_setidle(xfr->client->timer, maxtime, idletime, false)); +#endif /* * Register a shutdown callback with the client, so that we @@ -1289,14 +1289,8 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, xfr->stream = stream; *xfrp = xfr; - return (ISC_R_SUCCESS); - -failure: - xfrout_ctx_destroy(&xfr); - return (result); } - /* * Arrange to send as much as we can of "stream" without blocking. * @@ -1310,8 +1304,6 @@ sendstream(xfrout_ctx_t *xfr) { dns_message_t *tcpmsg = NULL; dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ isc_result_t result; - isc_region_t used; - isc_region_t region; dns_rdataset_t *qrdataset; dns_name_t *msgname = NULL; dns_rdata_t *msgrdata = NULL; @@ -1320,7 +1312,6 @@ sendstream(xfrout_ctx_t *xfr) { dns_compress_t cctx; bool cleanup_cctx = false; bool is_tcp; - int n_rrs; isc_buffer_clear(&xfr->buf); @@ -1545,6 +1536,7 @@ sendstream(xfrout_ctx_t *xfr) { } if (is_tcp) { + isc_region_t used; CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); dns_compress_setsensitive(&cctx, true); cleanup_cctx = true; @@ -1556,22 +1548,20 @@ sendstream(xfrout_ctx_t *xfr) { cleanup_cctx = false; isc_buffer_usedregion(&xfr->txbuf, &used); - isc_buffer_putuint16(&xfr->txlenbuf, - (uint16_t)used.length); - region.base = xfr->txlenbuf.base; - region.length = 2 + used.length; + xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending TCP message of %d bytes", used.length); - CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ - ®ion, xfr->client->task, - xfrout_senddone, - xfr)); + + CHECK(isc_nm_send(xfr->client->handle, &used, + xfrout_senddone, xfr)); xfr->sends++; + xfr->cbytes = used.length; } else { xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); ns_client_send(xfr->client); xfr->stream->methods->pause(xfr->stream); + isc_nmhandle_unref(xfr->client->handle); xfrout_ctx_destroy(&xfr); return; } @@ -1615,7 +1605,6 @@ sendstream(xfrout_ctx_t *xfr) { static void xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { xfrout_ctx_t *xfr = *xfrp; - ns_client_t *client = NULL; INSIST(xfr->sends == 0); @@ -1639,28 +1628,18 @@ xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { if (xfr->db != NULL) dns_db_detach(&xfr->db); - /* - * We want to detch the client after we have released the memory - * context as ns_client_detach checks the memory reference count. - */ - ns_client_attach(xfr->client, &client); - ns_client_detach(&xfr->client); isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); - ns_client_detach(&client); *xfrp = NULL; } static void -xfrout_senddone(isc_task_t *task, isc_event_t *event) { - isc_socketevent_t *sev = (isc_socketevent_t *)event; - xfrout_ctx_t *xfr = (xfrout_ctx_t *)event->ev_arg; - isc_result_t evresult = sev->result; +xfrout_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) { + xfrout_ctx_t *xfr = (xfrout_ctx_t *)arg; - UNUSED(task); + REQUIRE((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0); - INSIST(event->ev_type == ISC_SOCKEVENT_SENDDONE); - INSIST((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0); + INSIST(handle == xfr->client->handle); xfr->sends--; INSIST(xfr->sends == 0); @@ -1669,20 +1648,23 @@ xfrout_senddone(isc_task_t *task, isc_event_t *event) { * Update transfer statistics if sending succeeded, accounting for the * two-byte TCP length prefix included in the number of bytes sent. */ - if (evresult == ISC_R_SUCCESS) { + if (result == ISC_R_SUCCESS) { xfr->stats.nmsg++; - xfr->stats.nbytes += sev->region.length - 2; + xfr->stats.nbytes += xfr->cbytes; } - isc_event_free(&event); - +#if 0 (void)isc_timer_touch(xfr->client->timer); +#endif + if (xfr->shuttingdown == true) { xfrout_maybe_destroy(xfr); - } else if (evresult != ISC_R_SUCCESS) { - xfrout_fail(xfr, evresult, "send"); + } else if (result != ISC_R_SUCCESS) { + xfrout_fail(xfr, result, "send"); } else if (xfr->end_of_stream == false) { sendstream(xfr); + /* Return now so we don't unref the handle */ + return; } else { /* End of zone transfer stream. */ uint64_t msecs, persec; @@ -1707,9 +1689,10 @@ xfrout_senddone(isc_task_t *task, isc_event_t *event) { (unsigned int) (msecs % 1000), (unsigned int) persec); - ns_client_next(xfr->client, ISC_R_SUCCESS); xfrout_ctx_destroy(&xfr); } + + isc_nmhandle_unref(handle); } static void @@ -1723,6 +1706,7 @@ xfrout_fail(xfrout_ctx_t *xfr, isc_result_t result, const char *msg) { static void xfrout_maybe_destroy(xfrout_ctx_t *xfr) { INSIST(xfr->shuttingdown == true); +#if 0 if (xfr->sends > 0) { /* * If we are currently sending, cancel it and wait for @@ -1731,9 +1715,13 @@ xfrout_maybe_destroy(xfrout_ctx_t *xfr) { isc_socket_cancel(xfr->client->tcpsocket, xfr->client->task, ISC_SOCKCANCEL_SEND); } else { - ns_client_next(xfr->client, ISC_R_CANCELED); +#endif + ns_client_drop(xfr->client, ISC_R_CANCELED); + isc_nmhandle_unref(xfr->client->handle); xfrout_ctx_destroy(&xfr); +#if 0 } +#endif } static void diff --git a/util/copyrights b/util/copyrights index 29b3c2efcd4..66eb5bed7dc 100644 --- a/util/copyrights +++ b/util/copyrights @@ -624,9 +624,8 @@ ./bin/tests/system/emptyzones/setup.sh SH 2014,2016,2018,2019 ./bin/tests/system/emptyzones/tests.sh SH 2014,2015,2016,2018,2019 ./bin/tests/system/feature-test.c C 2016,2017,2018,2019 -./bin/tests/system/fetchlimit/ans4/ans.pl PERL 2015,2016,2018,2019 +./bin/tests/system/fetchlimit/ans4/ans.pl PERL 2019 ./bin/tests/system/fetchlimit/clean.sh SH 2015,2016,2018,2019 -./bin/tests/system/fetchlimit/ns3/named.args X 2015,2018,2019 ./bin/tests/system/fetchlimit/prereq.sh SH 2018,2019 ./bin/tests/system/fetchlimit/setup.sh SH 2015,2016,2018,2019 ./bin/tests/system/fetchlimit/tests.sh SH 2015,2016,2018,2019 @@ -909,13 +908,12 @@ ./bin/tests/system/redirect/ns5/sign.sh SH 2019 ./bin/tests/system/redirect/setup.sh SH 2011,2012,2013,2014,2015,2016,2017,2018,2019 ./bin/tests/system/redirect/tests.sh SH 2011,2012,2013,2014,2015,2016,2018,2019 -./bin/tests/system/resolver/ans2/ans.pl PERL 2000,2001,2004,2007,2009,2010,2012,2016,2018,2019 +./bin/tests/system/resolver/ans2/ans.pl PERL 2019 ./bin/tests/system/resolver/ans3/ans.pl PERL 2000,2001,2004,2007,2009,2012,2016,2018,2019 ./bin/tests/system/resolver/ans8/ans.pl PERL 2017,2018,2019 ./bin/tests/system/resolver/clean.sh SH 2008,2009,2010,2011,2012,2013,2014,2015,2016,2018,2019 ./bin/tests/system/resolver/ns4/named.noaa TXT.BRIEF 2010,2016,2018,2019 ./bin/tests/system/resolver/ns6/keygen.sh SH 2010,2012,2014,2016,2017,2018,2019 -./bin/tests/system/resolver/ns7/named.args X 2011,2012,2014,2018,2019 ./bin/tests/system/resolver/prereq.sh SH 2000,2001,2004,2007,2012,2014,2016,2018,2019 ./bin/tests/system/resolver/setup.sh SH 2010,2011,2012,2013,2014,2016,2017,2018,2019 ./bin/tests/system/resolver/tests.sh SH 2000,2001,2004,2007,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 @@ -2515,6 +2513,7 @@ ./lib/ns/tests/plugin_test.c C 2019 ./lib/ns/tests/query_test.c C 2017,2018,2019 ./lib/ns/tests/testdata/notify/notify1.msg X 2017,2018,2019 +./lib/ns/tests/wrap.c C 2019 ./lib/ns/update.c C 2017,2018,2019 ./lib/ns/version.c C 2017,2018,2019 ./lib/ns/win32/DLLMain.c C 2017,2018,2019