mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 05:57:52 +00:00
Merge branch '29-libuv-network-manager' into 'master'
libuv-based network manager Closes #29 See merge request isc-projects/bind9!2528
This commit is contained in:
commit
25800c892f
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@
|
||||
*.rej
|
||||
*.so
|
||||
*_test
|
||||
*.ipch # vscode/intellisense precompiled header
|
||||
*~
|
||||
.ccache/
|
||||
.cproject
|
||||
|
@ -675,6 +675,7 @@ unit:gcc:bionic:amd64:
|
||||
asan:sid:amd64:
|
||||
variables:
|
||||
CC: gcc
|
||||
ASAN_OPTIONS: "detect_leaks=0"
|
||||
CFLAGS: "-Wall -Wextra -O2 -g -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
|
||||
LDFLAGS: "-fsanitize=address,undefined"
|
||||
EXTRA_CONFIGURE: "--with-libidn2"
|
||||
@ -901,6 +902,7 @@ msvc:windows:amd64:
|
||||
"with-vcredist=C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Redist/MSVC/14.16.27012/vcredist_x64.exe"
|
||||
"with-openssl=C:/OpenSSL"
|
||||
"with-libxml2=C:/libxml2"
|
||||
"with-libuv=C:/libuv"
|
||||
"without-python"
|
||||
"with-system-tests"
|
||||
x64'
|
||||
|
11
CHANGES
11
CHANGES
@ -1,3 +1,14 @@
|
||||
5317. [func] A new asynchronous network communications system
|
||||
based on libuv is now used for listening for
|
||||
incoming requests and responding to them. (The
|
||||
old isc_socket API remains in use for sending
|
||||
iterative queries and processing responses; this
|
||||
will be changed too in a later release.)
|
||||
|
||||
This change will make it easier to improve
|
||||
performance and implement new protocol layers
|
||||
(e.g., DNS over TLS) in the future. [GL #29]
|
||||
|
||||
5316. [func] A new "dnssec-policy" option has been added to
|
||||
named.conf to implement a key and signing policy
|
||||
(KASP) for zones. When this option is in use,
|
||||
|
@ -129,8 +129,9 @@ include:
|
||||
|
||||
* New "dnssec-policy" statement to configure a key and signing policy
|
||||
for zones, enabling automatic key regeneration and rollover.
|
||||
* A new network manager based on libuv.
|
||||
* Support for the new GeoIP2 geolocation API
|
||||
* Improved DNSSEC key configuration using `dnssec-keys`
|
||||
* Improved DNSSEC trust anchor configuration using `dnssec-keys`
|
||||
* YAML output for `dig`, `mdig`, and `delv`.
|
||||
|
||||
### <a name="build"/> Building BIND
|
||||
|
@ -1379,7 +1379,7 @@ setup_libs(void) {
|
||||
|
||||
isc_log_setdebuglevel(lctx, 0);
|
||||
|
||||
result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
|
||||
result = isc_taskmgr_create(mctx, 1, 0, NULL, &taskmgr);
|
||||
check_result(result, "isc_taskmgr_create");
|
||||
|
||||
result = isc_task_create(taskmgr, 0, &global_task);
|
||||
|
@ -3797,7 +3797,7 @@ main(int argc, char *argv[]) {
|
||||
print_time(outfp);
|
||||
print_version(outfp);
|
||||
|
||||
result = isc_taskmgr_create(mctx, ntasks, 0, &taskmgr);
|
||||
result = isc_taskmgr_create(mctx, ntasks, 0, NULL, &taskmgr);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
fatal("failed to create task manager: %s",
|
||||
isc_result_totext(result));
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/net.h>
|
||||
#include <isc/netmgr.h>
|
||||
|
||||
#include <isccfg/aclconf.h>
|
||||
#include <isccfg/cfg.h>
|
||||
@ -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);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <isc/file.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/httpd.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/os.h>
|
||||
#include <isc/platform.h>
|
||||
#include <isc/print.h>
|
||||
@ -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");
|
||||
|
||||
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_taskmgr);
|
||||
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)
|
||||
|
@ -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);
|
||||
|
@ -906,7 +906,7 @@ setup_system(void) {
|
||||
result = isc_timermgr_create(gmctx, &timermgr);
|
||||
check_result(result, "dns_timermgr_create");
|
||||
|
||||
result = isc_taskmgr_create(gmctx, 1, 0, &taskmgr);
|
||||
result = isc_taskmgr_create(gmctx, 1, 0, NULL, &taskmgr);
|
||||
check_result(result, "isc_taskmgr_create");
|
||||
|
||||
result = isc_task_create(taskmgr, 0, &global_task);
|
||||
|
@ -936,11 +936,14 @@ main(int argc, char **argv) {
|
||||
serial = isc_random32();
|
||||
|
||||
isc_mem_create(&rndc_mctx);
|
||||
DO("create socket manager", isc_socketmgr_create(rndc_mctx, &socketmgr));
|
||||
DO("create task manager", isc_taskmgr_create(rndc_mctx, 1, 0, &taskmgr));
|
||||
DO("create socket manager", isc_socketmgr_create(rndc_mctx,
|
||||
&socketmgr));
|
||||
DO("create task manager", isc_taskmgr_create(rndc_mctx, 1, 0,
|
||||
NULL, &taskmgr));
|
||||
DO("create task", isc_task_create(taskmgr, 0, &task));
|
||||
|
||||
DO("create logging context", isc_log_create(rndc_mctx, &log, &logconfig));
|
||||
DO("create logging context", isc_log_create(rndc_mctx, &log,
|
||||
&logconfig));
|
||||
isc_log_setcontext(log);
|
||||
DO("setting log tag", isc_log_settag(logconfig, progname));
|
||||
logdest.file.stream = stderr;
|
||||
|
@ -144,7 +144,7 @@ create_managers(void) {
|
||||
isc_result_t result;
|
||||
|
||||
taskmgr = NULL;
|
||||
result = isc_taskmgr_create(mctx, 5, 0, &taskmgr);
|
||||
result = isc_taskmgr_create(mctx, 5, 0, NULL, &taskmgr);
|
||||
check_result(result, "isc_taskmgr_create");
|
||||
|
||||
timermgr = NULL;
|
||||
|
@ -112,7 +112,7 @@ main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &taskmgr)
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, NULL, &taskmgr)
|
||||
== ISC_R_SUCCESS);
|
||||
task = NULL;
|
||||
RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task)
|
||||
|
@ -226,7 +226,7 @@ main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &taskmgr) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, NULL, &taskmgr) ==
|
||||
ISC_R_SUCCESS);
|
||||
task = NULL;
|
||||
RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) ==
|
||||
|
@ -470,7 +470,7 @@ main(int argc, char *argv[]) {
|
||||
RUNCHECK(dst_lib_init(mctx, NULL));
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, NULL, &taskmgr));
|
||||
task = NULL;
|
||||
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
||||
timermgr = NULL;
|
||||
|
@ -102,7 +102,7 @@ main(int argc, char *argv[]) {
|
||||
isc_interval_set(&linterval, 1, 0);
|
||||
|
||||
isc_mem_create(&mctx);
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 3, 0, &taskmgr) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 3, 0, NULL, &taskmgr) ==
|
||||
ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) ==
|
||||
ISC_R_SUCCESS);
|
||||
|
@ -181,7 +181,7 @@ main(int argc, char *argv[]) {
|
||||
isc_mem_create(&mctx);
|
||||
mctx2 = NULL;
|
||||
isc_mem_create(&mctx2);
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &task_manager) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, NULL, &task_manager) ==
|
||||
ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_timermgr_create(mctx, &timer_manager) ==
|
||||
ISC_R_SUCCESS);
|
||||
|
@ -226,7 +226,7 @@ main(int argc, char *argv[]) {
|
||||
dst_result_register();
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 2, 0, &taskmgr) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 2, 0, NULL, &taskmgr) ==
|
||||
ISC_R_SUCCESS);
|
||||
task1 = NULL;
|
||||
RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task1) == ISC_R_SUCCESS);
|
||||
|
@ -292,7 +292,7 @@ main(int argc, char *argv[]) {
|
||||
* The task manager is independent (other than memory context)
|
||||
*/
|
||||
manager = NULL;
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &manager) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, NULL, &manager) ==
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
/*
|
||||
|
@ -79,7 +79,7 @@ main(int argc, char *argv[]) {
|
||||
|
||||
isc_mem_create(&mctx);
|
||||
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &manager) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, NULL, &manager) ==
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
RUNTIME_CHECK(isc_task_create(manager, 0, &t1) == ISC_R_SUCCESS);
|
||||
|
@ -108,7 +108,7 @@ main(int argc, char *argv[]) {
|
||||
printf("%u workers\n", workers);
|
||||
|
||||
isc_mem_create(&mctx1);
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx1, workers, 0, &manager) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx1, workers, 0, NULL, &manager) ==
|
||||
ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_timermgr_create(mctx1, &timgr) == ISC_R_SUCCESS);
|
||||
|
||||
|
@ -280,7 +280,7 @@ main(int argc, char **argv) {
|
||||
|
||||
RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
|
||||
isc_mem_create(&mctx);
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 2, 0, &taskmgr) ==
|
||||
RUNTIME_CHECK(isc_taskmgr_create(mctx, 2, 0, NULL, &taskmgr) ==
|
||||
ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
|
||||
RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -696,11 +696,17 @@ $RNDCCMD 10.53.0.3 addzone "test4.baz" '{ type master; file "e.db"; };' > /dev/n
|
||||
$RNDCCMD 10.53.0.3 addzone "test5.baz" '{ type master; file "e.db"; };' > /dev/null 2>&1 || ret=1
|
||||
$PERL $SYSTEMTESTTOP/stop.pl addzone ns3
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} addzone ns3 || ret=1
|
||||
$DIG $DIGOPTS @10.53.0.3 version.bind txt ch > dig.out.test$n || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
n=`expr $n + 1`
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
iret=0
|
||||
$DIG $DIGOPTS @10.53.0.3 version.bind txt ch > dig.out.test$n || iret=1
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || iret=1
|
||||
[ "$iret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ "$iret" -ne 0 ] && ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
n=`expr $n + 1`
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -124,13 +124,13 @@ add_name(struct dlz_example_data *state, struct record *list,
|
||||
strlen(data) >= sizeof(list[i].data))
|
||||
return (ISC_R_NOSPACE);
|
||||
|
||||
strncpy(list[i].name, name, sizeof(list[i].name));
|
||||
strncpy(list[i].name, name, sizeof(list[i].name) - 1);
|
||||
list[i].name[sizeof(list[i].name) - 1] = '\0';
|
||||
|
||||
strncpy(list[i].type, type, sizeof(list[i].type));
|
||||
strncpy(list[i].type, type, sizeof(list[i].type) - 1);
|
||||
list[i].type[sizeof(list[i].type) - 1] = '\0';
|
||||
|
||||
strncpy(list[i].data, data, sizeof(list[i].data));
|
||||
strncpy(list[i].data, data, sizeof(list[i].data) - 1);
|
||||
list[i].data[sizeof(list[i].data) - 1] = '\0';
|
||||
|
||||
list[i].ttl = ttl;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -20,7 +20,6 @@ rm -f dig.out.*
|
||||
DIGOPTS="+tcp +noau +noadd +nosea +nostat +nocmd +dnssec -p 5300"
|
||||
|
||||
# Check the example. domain
|
||||
|
||||
echo "I:checking that positive validation works ($n)"
|
||||
ret=0
|
||||
$DIG $DIGOPTS . @10.53.0.1 soa > dig.out.ns1.test$n || ret=1
|
||||
|
@ -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
|
@ -98,10 +98,15 @@ status=`expr $status + $ret`
|
||||
|
||||
echo_i "checking that forward only zone overrides empty zone"
|
||||
ret=0
|
||||
$DIG $DIGOPTS 1.0.10.in-addr.arpa TXT @10.53.0.4 > dig.out.f2
|
||||
grep "status: NOERROR" dig.out.f2 > /dev/null || ret=1
|
||||
$DIG $DIGOPTS 2.0.10.in-addr.arpa TXT @10.53.0.4 > dig.out.f2
|
||||
grep "status: NXDOMAIN" dig.out.f2 > /dev/null || ret=1
|
||||
# retry loop in case the server restart above causes transient failure
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
$DIG $DIGOPTS 1.0.10.in-addr.arpa TXT @10.53.0.4 > dig.out.f2
|
||||
grep "status: NOERROR" dig.out.f2 > /dev/null || ret=1
|
||||
$DIG $DIGOPTS 2.0.10.in-addr.arpa TXT @10.53.0.4 > dig.out.f2
|
||||
grep "status: NXDOMAIN" dig.out.f2 > /dev/null || ret=1
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
|
@ -14,6 +14,7 @@ rm -f ns*/named.run
|
||||
rm -f ns*/named.lock
|
||||
|
||||
# build.sh
|
||||
rm -f ns1/named_dump.db*
|
||||
rm -f ns6/K*
|
||||
rm -f ns6/dsset-*
|
||||
rm -f ns6/edns512.db
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -259,8 +259,13 @@ $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} legacy ns1
|
||||
|
||||
n=`expr $n + 1`
|
||||
echo_i "checking recursive lookup to edns 512 + no tcp + trust anchor fails ($n)"
|
||||
ret=0
|
||||
resolution_fails edns512-notcp. || ret=1
|
||||
# retry loop in case the server restart above causes transient failure
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
ret=0
|
||||
resolution_fails edns512-notcp. || ret=1
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -506,7 +506,6 @@ grep "add nsec3param.test. 0 IN TYPE65534 .# 6 000140000400" jp.out.ns3.$n > /de
|
||||
if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $ret + $status`; fi
|
||||
|
||||
|
||||
|
||||
ret=0
|
||||
echo_i "testing that rndc stop updates the master file"
|
||||
$NSUPDATE -k ns1/ddns.key <<END > /dev/null || ret=1
|
||||
@ -514,16 +513,24 @@ server 10.53.0.1 ${PORT}
|
||||
update add updated4.example.nil. 600 A 10.10.10.3
|
||||
send
|
||||
END
|
||||
sleep 3
|
||||
$PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} nsupdate ns1
|
||||
sleep 3
|
||||
# Removing the journal file and restarting the server means
|
||||
# that the data served by the new server process are exactly
|
||||
# those dumped to the master file by "rndc stop".
|
||||
rm -f ns1/*jnl
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} nsupdate ns1
|
||||
$DIG $DIGOPTS +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd updated4.example.nil.\
|
||||
@10.53.0.1 a > dig.out.ns1 || status=1
|
||||
digcomp knowngood.ns1.afterstop dig.out.ns1 || ret=1
|
||||
[ $ret = 0 ] || { echo_i "failed"; status=1; }
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
iret=0
|
||||
$DIG $DIGOPTS +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd \
|
||||
updated4.example.nil. @10.53.0.1 a > dig.out.ns1 || iret=1
|
||||
digcomp knowngood.ns1.afterstop dig.out.ns1 || iret=1
|
||||
[ "$iret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ "$iret" -ne 0 ] && ret=1
|
||||
[ "$ret" -eq 0 ] || { echo_i "failed"; status=1; }
|
||||
|
||||
ret=0
|
||||
echo_i "check that 'nsupdate -l' with a missing keyfile reports the missing file"
|
||||
|
@ -61,9 +61,14 @@ $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} nzd2nzf ns1
|
||||
|
||||
n=`expr $n + 1`
|
||||
echo_i "querying for zone data from migrated zone config ($n)"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.1 a.added.example a > dig.out.ns1.$n || ret=1
|
||||
grep 'status: NOERROR' dig.out.ns1.$n > /dev/null || ret=1
|
||||
# retry loop in case the server restart above causes transient failures
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.1 a.added.example a > dig.out.ns1.$n || ret=1
|
||||
grep 'status: NOERROR' dig.out.ns1.$n > /dev/null || ret=1
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
n=`expr $n + 1`
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
@ -277,7 +277,7 @@ main(int argc, char *argv[]) {
|
||||
RUNCHECK(dst_lib_init(mctx, NULL));
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, NULL, &taskmgr));
|
||||
task = NULL;
|
||||
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
||||
timermgr = 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
|
@ -12,7 +12,7 @@
|
||||
// NS7
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.7 port @PORT@ dscp 13;
|
||||
query-source address 10.53.0.7 dscp 13;
|
||||
notify-source 10.53.0.7 dscp 14;
|
||||
transfer-source 10.53.0.7 dscp 15;
|
||||
port @PORT@;
|
||||
|
@ -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
|
||||
|
@ -219,6 +219,7 @@ restart () {
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} rpz ns$1
|
||||
load_db
|
||||
dnsrps_loaded
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# $1=server and irrelevant args
|
||||
@ -465,6 +466,7 @@ for mode in native dnsrps; do
|
||||
else
|
||||
echo_i "running DNSRPS sub-test"
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} rpz
|
||||
sleep 3
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
@ -135,6 +135,7 @@ for mode in native dnsrps; do
|
||||
else
|
||||
echo_i "running DNSRPS sub-test"
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} rpzrecurse
|
||||
sleep 3
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
@ -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",
|
||||
|
@ -71,7 +71,7 @@ $RNDCCMD -s 10.53.0.3 stats > /dev/null 2>&1
|
||||
[ -f ns3/named.stats ] || ret=1
|
||||
if [ ! "$CYGWIN" ]; then
|
||||
nsock0nstat=`grep "UDP/IPv4 sockets active" ns3/named.stats | awk '{print $1}'`
|
||||
[ 0 -ne ${nsock0nstat:-0} ] || ret=1
|
||||
[ 0 -eq ${nsock0nstat:-0} ] || ret=1
|
||||
fi
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
@ -107,7 +107,7 @@ if [ ! "$CYGWIN" ]; then
|
||||
ret=0
|
||||
echo_i "verifying active sockets output in named.stats ($n)"
|
||||
nsock1nstat=`grep "UDP/IPv4 sockets active" ns3/named.stats | awk '{print $1}'`
|
||||
[ `expr $nsock1nstat - $nsock0nstat` -eq 1 ] || ret=1
|
||||
[ `expr ${nsock1nstat:-0} - ${nsock0nstat:-0}` -eq 1 ] || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
n=`expr $n + 1`
|
||||
|
@ -42,7 +42,7 @@ import time
|
||||
|
||||
# Timeout for establishing all connections requested by a single 'open' command.
|
||||
OPEN_TIMEOUT = 2
|
||||
|
||||
VERSION_QUERY = b'\x00\x1e\xaf\xb8\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07version\x04bind\x00\x00\x10\x00\x03'
|
||||
|
||||
def log(msg):
|
||||
print(datetime.datetime.now().strftime('%d-%b-%Y %H:%M:%S.%f ') + msg)
|
||||
@ -84,6 +84,7 @@ def open_connections(active_conns, count, host, port):
|
||||
log('%s for socket %s' % (errno.errorcode[err], sock))
|
||||
errors.append(sock)
|
||||
else:
|
||||
sock.send(VERSION_QUERY)
|
||||
active_conns.append(sock)
|
||||
|
||||
if errors:
|
||||
|
@ -163,8 +163,12 @@ check_stats_limit() {
|
||||
assert_int_equal "${TCP_HIGH}" "${TCP_LIMIT}" "TCP high-water value" || return 1
|
||||
}
|
||||
retry 2 check_stats_limit || ret=1
|
||||
close_connections $((TCP_LIMIT + 1))
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
# wait for connections to close
|
||||
sleep 5
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
@ -236,7 +236,7 @@ main(int argc, char *argv[]) {
|
||||
RUNCHECK(dst_lib_init(mctx, NULL));
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, NULL, &taskmgr));
|
||||
task = NULL;
|
||||
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
||||
timermgr = NULL;
|
||||
|
@ -175,7 +175,7 @@ main(int argc, char **argv) {
|
||||
RUNCHECK(dst_lib_init(mctx, NULL));
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, NULL, &taskmgr));
|
||||
task = NULL;
|
||||
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
||||
timermgr = NULL;
|
||||
|
@ -122,16 +122,24 @@ do
|
||||
done
|
||||
|
||||
echo_i "checking large unknown record loading on master"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.1 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF -s large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.1 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF -s large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ $ret = 0 ] || echo_i "failed"
|
||||
status=`expr $status + $ret`
|
||||
|
||||
echo_i "checking large unknown record loading on slave"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.2 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF -s large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.2 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF -s large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ $ret = 0 ] || echo_i "failed"
|
||||
status=`expr $status + $ret`
|
||||
|
||||
@ -139,10 +147,16 @@ echo_i "stop and restart slave"
|
||||
$PERL $SYSTEMTESTTOP/stop.pl unknown ns2
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} unknown ns2
|
||||
|
||||
# server may be answering queries before zones are loaded,
|
||||
# so retry a few times if this query fails
|
||||
echo_i "checking large unknown record loading on slave"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.2 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF -s large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.2 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF -s large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ $ret = 0 ] || echo_i "failed"
|
||||
status=`expr $status + $ret`
|
||||
|
||||
@ -157,10 +171,16 @@ echo_i "stop and restart inline slave"
|
||||
$PERL $SYSTEMTESTTOP/stop.pl unknown ns3
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} unknown ns3
|
||||
|
||||
# server may be answering queries before zones are loaded,
|
||||
# so retry a few times if this query fails
|
||||
echo_i "checking large unknown record loading on inline slave"
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.3 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
ret=0
|
||||
$DIG $DIGOPTS @10.53.0.3 +tcp +short large.example TYPE45234 > dig.out || { ret=1 ; echo_i "dig failed" ; }
|
||||
$DIFF large.out dig.out > /dev/null || { ret=1 ; echo_i "$DIFF failed"; }
|
||||
[ "$ret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ $ret = 0 ] || echo_i "failed"
|
||||
status=`expr $status + $ret`
|
||||
|
||||
|
@ -17,7 +17,7 @@ options {
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
listen-on-v6 { none; };
|
||||
recursion yes;
|
||||
recursion no;
|
||||
notify yes;
|
||||
};
|
||||
|
||||
|
@ -21,8 +21,6 @@ DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}"
|
||||
status=0
|
||||
n=1
|
||||
|
||||
sleep 5
|
||||
|
||||
echo_i "waiting for servers to be ready for testing ($n)"
|
||||
for i in 1 2 3 4 5 6 7 8 9 10
|
||||
do
|
||||
|
@ -431,11 +431,17 @@ $DIG -p ${PORT} txt mapped @10.53.0.3 > dig.out.1.$n
|
||||
grep "status: NOERROR," dig.out.1.$n > /dev/null || tmp=1
|
||||
$PERL $SYSTEMTESTTOP/stop.pl xfer ns3
|
||||
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} xfer ns3
|
||||
$DIG -p ${PORT} txt mapped @10.53.0.3 > dig.out.2.$n
|
||||
grep "status: NOERROR," dig.out.2.$n > /dev/null || tmp=1
|
||||
$DIG -p ${PORT} axfr mapped @10.53.0.3 > dig.out.3.$n
|
||||
digcomp knowngood.mapped dig.out.3.$n || tmp=1
|
||||
if test $tmp != 0 ; then echo_i "failed"; fi
|
||||
for try in 0 1 2 3 4 5 6 7 8 9; do
|
||||
iret=0
|
||||
$DIG -p ${PORT} txt mapped @10.53.0.3 > dig.out.2.$n
|
||||
grep "status: NOERROR," dig.out.2.$n > /dev/null || iret=1
|
||||
$DIG -p ${PORT} axfr mapped @10.53.0.3 > dig.out.3.$n
|
||||
digcomp knowngood.mapped dig.out.3.$n || iret=1
|
||||
[ "$iret" -eq 0 ] && break
|
||||
sleep 1
|
||||
done
|
||||
[ "$iret" -eq 0 ] || tmp=1
|
||||
[ "$tmp" -ne 0 ] && echo_i "failed"
|
||||
status=`expr $status + $tmp`
|
||||
|
||||
n=`expr $n + 1`
|
||||
|
@ -2047,7 +2047,7 @@ main(int argc, char *argv[]) {
|
||||
fatal("can't choose between IPv4 and IPv6");
|
||||
|
||||
taskmgr = NULL;
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
|
||||
RUNCHECK(isc_taskmgr_create(mctx, 1, 0, NULL, &taskmgr));
|
||||
task = NULL;
|
||||
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
||||
timermgr = NULL;
|
||||
|
@ -366,6 +366,9 @@
|
||||
/* define if struct stat has st_mtim.tv_nsec field */
|
||||
#undef HAVE_STAT_NSEC
|
||||
|
||||
/* Define to 1 if you have the <stdalign.h> header file. */
|
||||
#undef HAVE_STDALIGN_H
|
||||
|
||||
/* Define to 1 if you have the <stdatomic.h> header file. */
|
||||
#undef HAVE_STDATOMIC_H
|
||||
|
||||
|
197
configure
vendored
197
configure
vendored
@ -747,6 +747,8 @@ OPENSSL_LIBS
|
||||
OPENSSL_CFLAGS
|
||||
INSTALL_LIBRARY
|
||||
ALWAYS_DEFINES
|
||||
LIBUV_LIBS
|
||||
LIBUV_CFLAGS
|
||||
PTHREAD_CFLAGS
|
||||
PTHREAD_LIBS
|
||||
PTHREAD_CC
|
||||
@ -848,6 +850,7 @@ infodir
|
||||
docdir
|
||||
oldincludedir
|
||||
includedir
|
||||
runstatedir
|
||||
localstatedir
|
||||
sharedstatedir
|
||||
sysconfdir
|
||||
@ -967,6 +970,8 @@ PKG_CONFIG_LIBDIR
|
||||
MAXMINDDB_CFLAGS
|
||||
MAXMINDDB_LIBS
|
||||
MAXMINDDB_PREFIX
|
||||
LIBUV_CFLAGS
|
||||
LIBUV_LIBS
|
||||
OPENSSL_CFLAGS
|
||||
OPENSSL_LIBS
|
||||
LIBXML2_CFLAGS
|
||||
@ -1018,6 +1023,7 @@ datadir='${datarootdir}'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
runstatedir='${localstatedir}/run'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
|
||||
@ -1270,6 +1276,15 @@ do
|
||||
| -silent | --silent | --silen | --sile | --sil)
|
||||
silent=yes ;;
|
||||
|
||||
-runstatedir | --runstatedir | --runstatedi | --runstated \
|
||||
| --runstate | --runstat | --runsta | --runst | --runs \
|
||||
| --run | --ru | --r)
|
||||
ac_prev=runstatedir ;;
|
||||
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
|
||||
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
|
||||
| --run=* | --ru=* | --r=*)
|
||||
runstatedir=$ac_optarg ;;
|
||||
|
||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||
ac_prev=sbindir ;;
|
||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||
@ -1407,7 +1422,7 @@ fi
|
||||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||
libdir localedir mandir
|
||||
libdir localedir mandir runstatedir
|
||||
do
|
||||
eval ac_val=\$$ac_var
|
||||
# Remove trailing slashes.
|
||||
@ -1560,6 +1575,7 @@ Fine tuning of the installation directories:
|
||||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||
--includedir=DIR C header files [PREFIX/include]
|
||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||
@ -1726,6 +1742,9 @@ Some influential environment variables:
|
||||
linker flags for MAXMINDDB, overriding pkg-config
|
||||
MAXMINDDB_PREFIX
|
||||
value of prefix for libmaxminddb, overriding pkg-config
|
||||
LIBUV_CFLAGS
|
||||
C compiler flags for LIBUV, overriding pkg-config
|
||||
LIBUV_LIBS linker flags for LIBUV, overriding pkg-config
|
||||
OPENSSL_CFLAGS
|
||||
C compiler flags for OPENSSL, overriding pkg-config
|
||||
OPENSSL_LIBS
|
||||
@ -4000,7 +4019,7 @@ else
|
||||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
@ -4046,7 +4065,7 @@ else
|
||||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
@ -4070,7 +4089,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
@ -4115,7 +4134,7 @@ else
|
||||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
@ -4139,7 +4158,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
@ -15768,6 +15787,154 @@ fi
|
||||
done
|
||||
|
||||
|
||||
# libuv
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libuv" >&5
|
||||
$as_echo_n "checking for libuv... " >&6; }
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libuv >= 1.0.0" >&5
|
||||
$as_echo_n "checking for libuv >= 1.0.0... " >&6; }
|
||||
|
||||
if test -n "$LIBUV_CFLAGS"; then
|
||||
pkg_cv_LIBUV_CFLAGS="$LIBUV_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libuv >= 1.0.0\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libuv >= 1.0.0") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_LIBUV_CFLAGS=`$PKG_CONFIG --cflags "libuv >= 1.0.0" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$LIBUV_LIBS"; then
|
||||
pkg_cv_LIBUV_LIBS="$LIBUV_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libuv >= 1.0.0\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libuv >= 1.0.0") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_LIBUV_LIBS=`$PKG_CONFIG --libs "libuv >= 1.0.0" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
LIBUV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libuv >= 1.0.0" 2>&1`
|
||||
else
|
||||
LIBUV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libuv >= 1.0.0" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$LIBUV_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "libuv not found" "$LINENO" 5
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
as_fn_error $? "libuv not found" "$LINENO" 5
|
||||
else
|
||||
LIBUV_CFLAGS=$pkg_cv_LIBUV_CFLAGS
|
||||
LIBUV_LIBS=$pkg_cv_LIBUV_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
|
||||
fi
|
||||
|
||||
|
||||
CCASFLAGS_libuv_ax_save_flags=$CCASFLAGS
|
||||
|
||||
|
||||
|
||||
CFLAGS_libuv_ax_save_flags=$CFLAGS
|
||||
|
||||
|
||||
|
||||
CPPFLAGS_libuv_ax_save_flags=$CPPFLAGS
|
||||
|
||||
|
||||
|
||||
CXXFLAGS_libuv_ax_save_flags=$CXXFLAGS
|
||||
|
||||
|
||||
|
||||
ERLCFLAGS_libuv_ax_save_flags=$ERLCFLAGS
|
||||
|
||||
|
||||
|
||||
FCFLAGS_libuv_ax_save_flags=$FCFLAGS
|
||||
|
||||
|
||||
|
||||
FCLIBS_libuv_ax_save_flags=$FCLIBS
|
||||
|
||||
|
||||
|
||||
FFLAGS_libuv_ax_save_flags=$FFLAGS
|
||||
|
||||
|
||||
|
||||
FLIBS_libuv_ax_save_flags=$FLIBS
|
||||
|
||||
|
||||
|
||||
GCJFLAGS_libuv_ax_save_flags=$GCJFLAGS
|
||||
|
||||
|
||||
|
||||
JAVACFLAGS_libuv_ax_save_flags=$JAVACFLAGS
|
||||
|
||||
|
||||
|
||||
LDFLAGS_libuv_ax_save_flags=$LDFLAGS
|
||||
|
||||
|
||||
|
||||
LIBS_libuv_ax_save_flags=$LIBS
|
||||
|
||||
|
||||
|
||||
OBJCFLAGS_libuv_ax_save_flags=$OBJCFLAGS
|
||||
|
||||
|
||||
|
||||
OBJCXXFLAGS_libuv_ax_save_flags=$OBJCXXFLAGS
|
||||
|
||||
|
||||
|
||||
UPCFLAGS_libuv_ax_save_flags=$UPCFLAGS
|
||||
|
||||
|
||||
|
||||
VALAFLAGS_libuv_ax_save_flags=$VALAFLAGS
|
||||
|
||||
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS $LIBUV_CFLAGS"
|
||||
LIBS="$LIBS $LIBUV_LIBS"
|
||||
|
||||
#
|
||||
# flockfile is usually provided by pthreads
|
||||
#
|
||||
@ -18149,7 +18316,7 @@ fi ;; #(
|
||||
esac
|
||||
|
||||
if test "$GCC" = "yes"; then :
|
||||
STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith"
|
||||
STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith -Wno-missing-field-initializers"
|
||||
|
||||
fi
|
||||
|
||||
@ -19672,6 +19839,19 @@ done
|
||||
|
||||
LIBS="$LIBS $ISC_ATOMIC_LIBS"
|
||||
|
||||
for ac_header in stdalign.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "stdalign.h" "ac_cv_header_stdalign_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_stdalign_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_STDALIGN_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
|
||||
for ac_header in uchar.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "uchar.h" "ac_cv_header_uchar_h" "$ac_includes_default"
|
||||
@ -23306,7 +23486,7 @@ ac_config_commands="$ac_config_commands chmod"
|
||||
# elsewhere if there's a good reason for doing so.
|
||||
#
|
||||
|
||||
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/plugins/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile"
|
||||
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/plugins/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/netmgr/Makefile lib/isc/tests/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile"
|
||||
|
||||
|
||||
#
|
||||
@ -24406,6 +24586,7 @@ do
|
||||
"lib/isc/include/isc/platform.h") CONFIG_FILES="$CONFIG_FILES lib/isc/include/isc/platform.h" ;;
|
||||
"lib/isc/include/pk11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/include/pk11/Makefile" ;;
|
||||
"lib/isc/include/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/include/pkcs11/Makefile" ;;
|
||||
"lib/isc/netmgr/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/netmgr/Makefile" ;;
|
||||
"lib/isc/tests/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/tests/Makefile" ;;
|
||||
"lib/isc/unix/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/unix/Makefile" ;;
|
||||
"lib/isc/unix/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/unix/include/Makefile" ;;
|
||||
|
14
configure.ac
14
configure.ac
@ -641,6 +641,15 @@ AC_CHECK_FUNCS([pthread_setaffinity_np cpuset_setaffinity processor_bind sched_s
|
||||
AC_CHECK_FUNCS([pthread_setname_np pthread_set_name_np])
|
||||
AC_CHECK_HEADERS([pthread_np.h], [], [], [#include <pthread.h>])
|
||||
|
||||
# libuv
|
||||
AC_MSG_CHECKING(for libuv)
|
||||
PKG_CHECK_MODULES([LIBUV], [libuv >= 1.0.0], [],
|
||||
[AC_MSG_ERROR([libuv not found])])
|
||||
AX_SAVE_FLAGS([libuv])
|
||||
|
||||
CFLAGS="$CFLAGS $LIBUV_CFLAGS"
|
||||
LIBS="$LIBS $LIBUV_LIBS"
|
||||
|
||||
#
|
||||
# flockfile is usually provided by pthreads
|
||||
#
|
||||
@ -1321,7 +1330,7 @@ AS_CASE([$host],
|
||||
[MKDEPCFLAGS="-xM"])])
|
||||
|
||||
AS_IF([test "$GCC" = "yes"],
|
||||
[STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith"]
|
||||
[STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith -Wno-missing-field-initializers"]
|
||||
)
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],
|
||||
@ -1796,6 +1805,8 @@ AC_CHECK_HEADERS(
|
||||
])
|
||||
LIBS="$LIBS $ISC_ATOMIC_LIBS"
|
||||
|
||||
AC_CHECK_HEADERS([stdalign.h])
|
||||
|
||||
AC_CHECK_HEADERS([uchar.h])
|
||||
|
||||
#
|
||||
@ -2817,6 +2828,7 @@ AC_CONFIG_FILES([
|
||||
lib/isc/include/isc/platform.h
|
||||
lib/isc/include/pk11/Makefile
|
||||
lib/isc/include/pkcs11/Makefile
|
||||
lib/isc/netmgr/Makefile
|
||||
lib/isc/tests/Makefile
|
||||
lib/isc/unix/Makefile
|
||||
lib/isc/unix/include/Makefile
|
||||
|
@ -11,6 +11,16 @@
|
||||
|
||||
<section xml:id="relnotes_changes"><info><title>Feature Changes</title></info>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
A new asynchronous network communications system based on
|
||||
<command>libuv</command> is now used by <command>named</command>
|
||||
for listening for incoming requests and responding to them.
|
||||
This change will make it easier to improve performance and
|
||||
implement new protocol layers (for example, DNS over TLS) in
|
||||
the future. [GL #29]
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<command>named</command> will now log a warning if
|
||||
|
96
doc/design/netmgr.md
Normal file
96
doc/design/netmgr.md
Normal file
@ -0,0 +1,96 @@
|
||||
# Netmgr
|
||||
|
||||
Netmgr (aka rainbow duck) is the new networking system for BIND. It's based
|
||||
on libuv, although it does not expose any of the libuv API, in order to
|
||||
keep the API agnostic of underlying library.
|
||||
|
||||
## A bit of history
|
||||
|
||||
Networking in BIND9 up to 9.12 works with a single event loop (epoll() on
|
||||
Linux, kqueue on FreeBSD, etc).
|
||||
|
||||
When a client wants to read from a socket, it creates a socket event
|
||||
associated with a task that will receive this event. An
|
||||
`isc_socket_{read,write,etc.}` operation tries to read directly from
|
||||
the socket; if it succeeds, it sends the socket event to the task
|
||||
provided by the callee. If it doesn't, it adds an event to an event
|
||||
loop, and when this event is received the listener is re-set, and an
|
||||
internal task is launched to read the data from the socket. After the
|
||||
internal task is done, it launches the task from socket event provided
|
||||
by the callee. This means that a simple socket operation causes a
|
||||
lot of context switches.
|
||||
|
||||
9.14 fixed some of these issues by having multiple event loops in separate
|
||||
threads (one per CPU), that can read the data immediately and then call
|
||||
the socket event, but this is still sub-optimal.
|
||||
|
||||
## Basic concepts
|
||||
|
||||
### `isc_nm_t`
|
||||
|
||||
The `isc_nm_t` structure represents the network manager itself. It
|
||||
contains a configurable number (generally the same as the number of CPUs)
|
||||
of 'networker' objects, each of which represents a thread for executing
|
||||
networking events.
|
||||
|
||||
The manager contains flags to indicate whether it has been paused or
|
||||
interlocked, and counters for the number of workers running and the
|
||||
number of workers paused.
|
||||
|
||||
Each networker object contains a queue of incoming asynchronous events
|
||||
and a pool of buffers into which messages will be copied when received.
|
||||
|
||||
### `isc_nmsocket_t`
|
||||
|
||||
`isc_nmsocket_t` is a wrapper around a libuv socket. It is configured
|
||||
with
|
||||
|
||||
### `isc_nmhandle_t`
|
||||
|
||||
An `isc_nmhandle_t` object represents an interface that can be read or
|
||||
written. For TCP it's a socket, and for UDP it's a socket with a peer
|
||||
address. It is always associated with one and only one `isc_nmsocket_t`
|
||||
object.
|
||||
|
||||
When a handle object is allocated, it may be allocated with a block of
|
||||
'extra' space in which another object will be stored that is associated
|
||||
with that handle: for example, an `ns_client_t` structure storing
|
||||
information about an incoming request.
|
||||
|
||||
The handle is reference counted; when references drop to zero it calls
|
||||
the 'reset' callback for its associated object and places itself onto
|
||||
a stack of inactive handles in its corresponding `isc_nmsocket_t`
|
||||
structure so it can be quickly reused when the next incoming message
|
||||
is received. When the handle is freed (which may happen if the socket's
|
||||
inactive-handles stack is full or when the socket is destroyed) then the
|
||||
associated object's 'put' callback will be called to free any resources
|
||||
it allocated.
|
||||
|
||||
## UDP listening
|
||||
|
||||
UDP listener sockets automatically create an array of 'child' sockets,
|
||||
each associated with one networker, and all listening on the same address
|
||||
via `SO_REUSEADDR`. (The parent's reference counter is used for all the
|
||||
parent and child sockets together; none are destroyed until there are no
|
||||
remaining referenes to any of tem.)
|
||||
|
||||
## TCP listening
|
||||
|
||||
A TCP listener socket cannot listen on multiple threads in parallel,
|
||||
so receiving a TCP connection can cause a context switch, but this is
|
||||
expected to be rare enough not to impact performance significantly.
|
||||
|
||||
When connected, a TCP socket will attach to the system-wide TCP clients
|
||||
quota.
|
||||
|
||||
## TCP listening for DNS
|
||||
|
||||
A TCPDNS listener is a wrapper around a TCP socket which specifically
|
||||
handles DNS traffic, including the two-byte length field that prepends DNS
|
||||
messages over TCP.
|
||||
|
||||
Other wrapper socket types can be added in the future, such as a TLS socket
|
||||
wrapper to implement encryption or an HTTP wrapper to implement the HTTP
|
||||
protocol. This will enable the system to have a transport-neutral network
|
||||
manager socket over which DNS can be sent without knowing anything about
|
||||
transport, encryption, etc.
|
@ -654,10 +654,6 @@ Items can be removed from the list using `ISC_LIST_UNLINK`:
|
||||
|
||||
ISC_LIST_UNLINK(foolist, foo, link);
|
||||
|
||||
A similar but smaller set of `ISC_QUEUE` macros, including `ISC_QUEUE_PUSH`
|
||||
and `ISC_QUEUE_POP`, are provided to implement strict FIFO lists, with
|
||||
built-in fine-grained locking.
|
||||
|
||||
#### <a name="names"></a>Names
|
||||
|
||||
The `dns_name` API has facilities for processing DNS names and labels,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -116,7 +116,7 @@ create_managers(void) {
|
||||
isc_result_t result;
|
||||
ncpus = isc_os_ncpus();
|
||||
|
||||
CHECK(isc_taskmgr_create(dt_mctx, ncpus, 0, &taskmgr));
|
||||
CHECK(isc_taskmgr_create(dt_mctx, ncpus, 0, NULL, &taskmgr));
|
||||
CHECK(isc_timermgr_create(dt_mctx, &timermgr));
|
||||
CHECK(isc_socketmgr_create(dt_mctx, &socketmgr));
|
||||
CHECK(isc_task_create(taskmgr, 0, &maintask));
|
||||
|
@ -46,18 +46,20 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/errno.@O@ \
|
||||
|
||||
# Alphabetically
|
||||
OBJS = pk11.@O@ pk11_result.@O@ \
|
||||
aes.@O@ app.@O@ assertions.@O@ \
|
||||
aes.@O@ app.@O@ assertions.@O@ astack.@O@ \
|
||||
backtrace.@O@ base32.@O@ base64.@O@ \
|
||||
bind9.@O@ buffer.@O@ bufferlist.@O@ \
|
||||
commandline.@O@ counter.@O@ crc64.@O@ error.@O@ entropy.@O@ \
|
||||
event.@O@ hash.@O@ ht.@O@ heap.@O@ hex.@O@ hmac.@O@ \
|
||||
httpd.@O@ iterated_hash.@O@ \
|
||||
event.@O@ hash.@O@ ht.@O@ heap.@O@ hex.@O@ \
|
||||
hmac.@O@ hp.@O@ httpd.@O@ iterated_hash.@O@ \
|
||||
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
|
||||
md.@O@ mem.@O@ mutexblock.@O@ \
|
||||
netmgr/netmgr.@O@ netmgr/tcp.@O@ netmgr/udp.@O@ \
|
||||
netmgr/tcpdns.@O@ netmgr/uverr2result.@O@ \
|
||||
netaddr.@O@ netscope.@O@ nonce.@O@ openssl_shim.@O@ pool.@O@ \
|
||||
parseint.@O@ portset.@O@ quota.@O@ radix.@O@ random.@O@ \
|
||||
ratelimiter.@O@ region.@O@ regex.@O@ result.@O@ \
|
||||
rwlock.@O@ \
|
||||
parseint.@O@ portset.@O@ queue.@O@ quota.@O@ \
|
||||
radix.@O@ random.@O@ ratelimiter.@O@ \
|
||||
region.@O@ regex.@O@ result.@O@ rwlock.@O@ \
|
||||
serial.@O@ siphash.@O@ sockaddr.@O@ stats.@O@ \
|
||||
string.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
|
||||
tm.@O@ timer.@O@ version.@O@ \
|
||||
@ -66,15 +68,15 @@ SYMTBLOBJS = backtrace-emptytbl.@O@
|
||||
|
||||
# Alphabetically
|
||||
SRCS = pk11.c pk11_result.c \
|
||||
aes.c app.c assertions.c \
|
||||
aes.c app.c assertions.c astack.c \
|
||||
backtrace.c base32.c base64.c bind9.c \
|
||||
buffer.c bufferlist.c commandline.c counter.c crc64.c \
|
||||
entropy.c error.c event.c hash.c ht.c heap.c hex.c hmac.c \
|
||||
httpd.c iterated_hash.c \
|
||||
entropy.c error.c event.c hash.c ht.c heap.c \
|
||||
hex.c hmac.c hp.c httpd.c iterated_hash.c \
|
||||
lex.c lfsr.c lib.c log.c \
|
||||
md.c mem.c mutexblock.c \
|
||||
netaddr.c netscope.c nonce.c openssl_shim.c pool.c \
|
||||
parseint.c portset.c quota.c radix.c random.c \
|
||||
parseint.c portset.c queue.c quota.c radix.c random.c \
|
||||
ratelimiter.c region.c regex.c result.c rwlock.c \
|
||||
serial.c siphash.c sockaddr.c stats.c string.c \
|
||||
symtab.c task.c taskpool.c timer.c \
|
||||
@ -86,7 +88,7 @@ LIBS = ${OPENSSL_LIBS} @LIBS@
|
||||
# Attempt to disable parallel processing.
|
||||
.NOTPARALLEL:
|
||||
.NO_PARALLEL:
|
||||
SUBDIRS = include unix pthreads
|
||||
SUBDIRS = include netmgr unix pthreads
|
||||
TARGETS = timestamp
|
||||
TESTDIRS = @UNITTESTS@
|
||||
|
||||
|
80
lib/isc/astack.c
Normal file
80
lib/isc/astack.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/astack.h>
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
struct isc_astack {
|
||||
isc_mem_t *mctx;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
isc_mutex_t lock;
|
||||
uintptr_t nodes[];
|
||||
};
|
||||
|
||||
isc_astack_t *
|
||||
isc_astack_new(isc_mem_t *mctx, size_t size) {
|
||||
isc_astack_t *stack =
|
||||
isc_mem_get(mctx,
|
||||
sizeof(isc_astack_t) + size * sizeof(uintptr_t));
|
||||
|
||||
stack->mctx = NULL;
|
||||
isc_mem_attach(mctx, &stack->mctx);
|
||||
stack->size = size;
|
||||
stack->pos = 0;
|
||||
memset(stack->nodes, 0, size * sizeof(uintptr_t));
|
||||
isc_mutex_init(&stack->lock);
|
||||
return (stack);
|
||||
}
|
||||
|
||||
bool
|
||||
isc_astack_trypush(isc_astack_t *stack, void *obj) {
|
||||
if (isc_mutex_trylock(&stack->lock) == false) {
|
||||
if (stack->pos >= stack->size) {
|
||||
isc_mutex_unlock(&stack->lock);
|
||||
return (false);
|
||||
}
|
||||
stack->nodes[stack->pos++] = (uintptr_t) obj;
|
||||
isc_mutex_unlock(&stack->lock);
|
||||
return (true);
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
isc_astack_pop(isc_astack_t *stack) {
|
||||
isc_mutex_lock(&stack->lock);
|
||||
uintptr_t rv;
|
||||
if (stack->pos == 0) {
|
||||
rv = 0;
|
||||
} else {
|
||||
rv = stack->nodes[--stack->pos];
|
||||
}
|
||||
isc_mutex_unlock(&stack->lock);
|
||||
return ((void*) rv);
|
||||
}
|
||||
|
||||
void
|
||||
isc_astack_destroy(isc_astack_t *stack) {
|
||||
REQUIRE(stack->pos == 0);
|
||||
|
||||
isc_mem_putanddetach(&stack->mctx, stack,
|
||||
sizeof(struct isc_astack) +
|
||||
stack->size * sizeof(uintptr_t));
|
||||
}
|
222
lib/isc/hp.c
Normal file
222
lib/isc/hp.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Hazard Pointer implementation.
|
||||
*
|
||||
* This work is based on C++ code available from:
|
||||
* https://github.com/pramalhe/ConcurrencyFreaks/
|
||||
*
|
||||
* Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Concurrency Freaks nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER>
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/hp.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#define HP_MAX_THREADS 128
|
||||
#define HP_MAX_HPS 4 /* This is named 'K' in the HP paper */
|
||||
#define CLPAD (128 / sizeof(uintptr_t))
|
||||
#define HP_THRESHOLD_R 0 /* This is named 'R' in the HP paper */
|
||||
|
||||
/* Maximum number of retired objects per thread */
|
||||
#define MAX_RETIRED (HP_MAX_THREADS * HP_MAX_HPS)
|
||||
|
||||
#define TID_UNKNOWN -1
|
||||
|
||||
static atomic_int_fast32_t tid_v_base;
|
||||
static bool tid_v_initialized;
|
||||
|
||||
#if defined(HAVE_TLS)
|
||||
#if defined(HAVE_THREAD_LOCAL)
|
||||
#include <threads.h>
|
||||
static thread_local int tid_v = TID_UNKNOWN;
|
||||
#elif defined(HAVE___THREAD)
|
||||
static __thread int tid_v = TID_UNKNOWN;
|
||||
#elif defined(HAVE___DECLSPEC_THREAD)
|
||||
static __declspec( thread ) int tid_v = TID_UNKNOWN;
|
||||
#else /* if defined(HAVE_THREAD_LOCAL) */
|
||||
#error "Unknown method for defining a TLS variable!"
|
||||
#endif /* if defined(HAVE_THREAD_LOCAL) */
|
||||
#else /* if defined(HAVE_TLS) */
|
||||
#error "Thread-local storage support is required!"
|
||||
#endif /* if defined(HAVE_TLS) */
|
||||
|
||||
typedef struct retirelist {
|
||||
int size;
|
||||
uintptr_t list[MAX_RETIRED];
|
||||
} retirelist_t;
|
||||
|
||||
struct isc_hp {
|
||||
int max_hps;
|
||||
isc_mem_t *mctx;
|
||||
atomic_uintptr_t *hp[HP_MAX_THREADS];
|
||||
retirelist_t *rl[HP_MAX_THREADS];
|
||||
isc_hp_deletefunc_t *deletefunc;
|
||||
};
|
||||
|
||||
static inline int
|
||||
tid() {
|
||||
if (!tid_v_initialized) {
|
||||
atomic_init(&tid_v_base, 0);
|
||||
tid_v_initialized = true;
|
||||
}
|
||||
if (tid_v == TID_UNKNOWN) {
|
||||
tid_v = atomic_fetch_add(&tid_v_base, 1);
|
||||
REQUIRE(tid_v < HP_MAX_THREADS);
|
||||
}
|
||||
|
||||
return (tid_v);
|
||||
}
|
||||
|
||||
isc_hp_t *
|
||||
isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) {
|
||||
isc_hp_t *hp = isc_mem_get(mctx, sizeof(*hp));
|
||||
|
||||
if (max_hps == 0) {
|
||||
max_hps = HP_MAX_HPS;
|
||||
}
|
||||
|
||||
*hp = (isc_hp_t){
|
||||
.max_hps = max_hps,
|
||||
.deletefunc = deletefunc
|
||||
};
|
||||
|
||||
isc_mem_attach(mctx, &hp->mctx);
|
||||
|
||||
for (int i = 0; i < HP_MAX_THREADS; i++) {
|
||||
hp->hp[i] = isc_mem_get(mctx, CLPAD * 2 * sizeof(hp->hp[i][0]));
|
||||
hp->rl[i] = isc_mem_get(mctx, sizeof(*hp->rl[0]));
|
||||
*hp->rl[i] = (retirelist_t) { .size = 0 };
|
||||
|
||||
for (int j = 0; j < hp->max_hps; j++) {
|
||||
atomic_init(&hp->hp[i][j], 0);
|
||||
}
|
||||
}
|
||||
|
||||
return (hp);
|
||||
}
|
||||
|
||||
void
|
||||
isc_hp_destroy(isc_hp_t *hp) {
|
||||
for (int i = 0; i < HP_MAX_THREADS; i++) {
|
||||
isc_mem_put(hp->mctx, hp->hp[i],
|
||||
CLPAD * 2 * sizeof(uintptr_t));
|
||||
|
||||
for (int j = 0; j < hp->rl[i]->size; j++) {
|
||||
void *data = (void *)hp->rl[i]->list[j];
|
||||
hp->deletefunc(data);
|
||||
}
|
||||
|
||||
isc_mem_put(hp->mctx, hp->rl[i], sizeof(*hp->rl[0]));
|
||||
}
|
||||
|
||||
isc_mem_putanddetach(&hp->mctx, hp, sizeof(*hp));
|
||||
}
|
||||
|
||||
void
|
||||
isc_hp_clear(isc_hp_t *hp) {
|
||||
for (int i = 0; i < hp->max_hps; i++) {
|
||||
atomic_store_release(&hp->hp[tid()][i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
void isc_hp_clear_one(isc_hp_t *hp, int ihp) {
|
||||
atomic_store_release(&hp->hp[tid()][ihp], 0);
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
isc_hp_protect(isc_hp_t *hp, int ihp, atomic_uintptr_t *atom) {
|
||||
uintptr_t n = 0;
|
||||
uintptr_t ret;
|
||||
while ((ret = atomic_load(atom)) != n) {
|
||||
atomic_store(&hp->hp[tid()][ihp], ret);
|
||||
n = ret;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
isc_hp_protect_ptr(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) {
|
||||
atomic_store(&hp->hp[tid()][ihp], atomic_load(&ptr));
|
||||
return (atomic_load(&ptr));
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) {
|
||||
atomic_store_release(&hp->hp[tid()][ihp], atomic_load(&ptr));
|
||||
return (atomic_load(&ptr));
|
||||
}
|
||||
|
||||
void
|
||||
isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) {
|
||||
hp->rl[tid()]->list[hp->rl[tid()]->size++] = ptr;
|
||||
INSIST(hp->rl[tid()]->size < MAX_RETIRED);
|
||||
|
||||
if (hp->rl[tid()]->size < HP_THRESHOLD_R) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int iret = 0; iret < hp->rl[tid()]->size; iret++) {
|
||||
uintptr_t obj = hp->rl[tid()]->list[iret];
|
||||
bool can_delete = true;
|
||||
for (int itid = 0;
|
||||
itid < HP_MAX_THREADS && can_delete;
|
||||
itid++)
|
||||
{
|
||||
for (int ihp = hp->max_hps-1; ihp >= 0; ihp--) {
|
||||
if (atomic_load(&hp->hp[itid][ihp]) == obj) {
|
||||
can_delete = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (can_delete) {
|
||||
size_t bytes = (hp->rl[tid()]->size - iret) *
|
||||
sizeof(hp->rl[tid()]->list[0]);
|
||||
memmove(&hp->rl[tid()]->list[iret],
|
||||
&hp->rl[tid()]->list[iret + 1],
|
||||
bytes);
|
||||
hp->rl[tid()]->size--;
|
||||
hp->deletefunc((void *)obj);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,12 +18,12 @@ VERSION=@BIND9_VERSION@
|
||||
# machine generated. The latter are handled specially in the
|
||||
# install target below.
|
||||
#
|
||||
HEADERS = aes.h app.h assertions.h atomic.h backtrace.h \
|
||||
HEADERS = aes.h app.h assertions.h astack.h atomic.h backtrace.h \
|
||||
base32.h base64.h bind9.h buffer.h bufferlist.h \
|
||||
commandline.h counter.h crc64.h deprecated.h \
|
||||
endian.h errno.h error.h event.h eventclass.h \
|
||||
file.h formatcheck.h fsaccess.h fuzz.h \
|
||||
hash.h heap.h hex.h hmac.h ht.h httpd.h \
|
||||
hash.h heap.h hex.h hmac.h hp.h ht.h httpd.h \
|
||||
interfaceiter.h iterated_hash.h \
|
||||
lang.h lex.h lfsr.h lib.h likely.h list.h log.h \
|
||||
magic.h md.h mem.h meminfo.h mutexblock.h \
|
||||
|
44
lib/isc/include/isc/astack.h
Normal file
44
lib/isc/include/isc/astack.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
isc_astack_t *
|
||||
isc_astack_new(isc_mem_t *mctx, size_t size);
|
||||
/*%<
|
||||
* Allocate and initialize a new array stack of size 'size'.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_astack_destroy(isc_astack_t *stack);
|
||||
/*%<
|
||||
* Free an array stack 'stack'.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'stack' is empty.
|
||||
*/
|
||||
|
||||
bool
|
||||
isc_astack_trypush(isc_astack_t *stack, void *obj);
|
||||
/*%<
|
||||
* Try to push 'obj' onto array stack 'astack'. On failure, either
|
||||
* because the stack size limit has been reached or because another
|
||||
* thread has already changed the stack pointer, return 'false'.
|
||||
*/
|
||||
|
||||
void *
|
||||
isc_astack_pop(isc_astack_t *stack);
|
||||
/*%<
|
||||
* Pop an object off of array stack 'stack'. If the stack is empty,
|
||||
* return NULL.
|
||||
*/
|
130
lib/isc/include/isc/hp.h
Normal file
130
lib/isc/include/isc/hp.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Hazard Pointer implementation.
|
||||
*
|
||||
* This work is based on C++ code available from:
|
||||
* https://github.com/pramalhe/ConcurrencyFreaks/
|
||||
*
|
||||
* Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Concurrency Freaks nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER>
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
/*%
|
||||
* Hazard pointers are a mechanism for protecting objects in memory
|
||||
* from being deleted by other threads while in use. This allows
|
||||
* safe lock-free data structures.
|
||||
*
|
||||
* This is an adaptation of the ConcurrencyFreaks implementation in C.
|
||||
* More details available at https://github.com/pramalhe/ConcurrencyFreaks,
|
||||
* in the file HazardPointers.hpp.
|
||||
*/
|
||||
|
||||
typedef void
|
||||
(isc_hp_deletefunc_t)(void *);
|
||||
|
||||
isc_hp_t *
|
||||
isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc);
|
||||
/*%<
|
||||
* Create a new hazard pointer array of size 'max_hps' (or a reasonable
|
||||
* default value if 'max_hps' is 0). The function 'deletefunc' will be
|
||||
* used to delete objects protected by hazard pointers when it becomes
|
||||
* safe to retire them.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_hp_destroy(isc_hp_t *hp);
|
||||
/*%<
|
||||
* Destroy a hazard pointer array and clean up all objects protected
|
||||
* by hazard pointers.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_hp_clear(isc_hp_t *hp);
|
||||
/*%<
|
||||
* Clear all hazard pointers in the array for the current thread.
|
||||
*
|
||||
* Progress condition: wait-free bounded (by max_hps)
|
||||
*/
|
||||
|
||||
void
|
||||
isc_hp_clear_one(isc_hp_t *hp, int ihp);
|
||||
/*%<
|
||||
* Clear a specified hazard pointer in the array for the current thread.
|
||||
*
|
||||
* Progress condition: wait-free population oblivious.
|
||||
*/
|
||||
|
||||
uintptr_t
|
||||
isc_hp_protect(isc_hp_t *hp, int ihp, atomic_uintptr_t *atom);
|
||||
/*%<
|
||||
* Protect an object referenced by 'atom' with a hazard pointer for the
|
||||
* current thread.
|
||||
*
|
||||
* Progress condition: lock-free.
|
||||
*/
|
||||
|
||||
uintptr_t
|
||||
isc_hp_protect_ptr(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr);
|
||||
/*%<
|
||||
* This returns the same value that is passed as ptr, which is sometimes
|
||||
* useful.
|
||||
*
|
||||
* Progress condition: wait-free population oblivious.
|
||||
*/
|
||||
|
||||
uintptr_t
|
||||
isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr);
|
||||
/*%<
|
||||
* Same as isc_hp_protect_ptr(), but explicitly uses memory_order_release.
|
||||
*
|
||||
* Progress condition: wait-free population oblivious.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_hp_retire(isc_hp_t *hp, uintptr_t ptr);
|
||||
/*%<
|
||||
* Retire an object that is no longer in use by any thread, calling
|
||||
* the delete function that was specified in isc_hp_new().
|
||||
*
|
||||
* Progress condition: wait-free bounded (by the number of threads squared)
|
||||
*/
|
@ -93,6 +93,11 @@ typedef struct atomic_uint_fast64 {
|
||||
uint64_t v;
|
||||
} atomic_uint_fast64_t;
|
||||
|
||||
typedef struct atomic_uintptr {
|
||||
isc_mutex_t m;
|
||||
uintptr_t v;
|
||||
} atomic_uintptr_t;
|
||||
|
||||
typedef struct atomic_bool_s {
|
||||
isc_mutex_t m;
|
||||
bool v;
|
||||
@ -198,3 +203,14 @@ typedef struct atomic_bool_s {
|
||||
atomic_compare_exchange_weak_explicit(obj, expected, desired, \
|
||||
memory_order_seq_cst, \
|
||||
memory_order_seq_cst)
|
||||
#define atomic_exchange_explicit(obj, desired, order) \
|
||||
({ \
|
||||
typeof((obj)->v) ___v; \
|
||||
REQUIRE(isc_mutex_lock(&(obj)->m) == ISC_R_SUCCESS); \
|
||||
___v = (obj)->v; \
|
||||
(obj)->v = desired; \
|
||||
REQUIRE(isc_mutex_unlock(&(obj)->m) == ISC_R_SUCCESS); \
|
||||
___v; \
|
||||
})
|
||||
#define atomic_exchange(obj, desired) \
|
||||
atomic_exchange_explicit(obj, desired, memory_order_seq_cst)
|
||||
|
284
lib/isc/include/isc/netmgr.h
Normal file
284
lib/isc/include/isc/netmgr.h
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
typedef enum {
|
||||
NMEV_READ,
|
||||
NMEV_WRITE,
|
||||
NMEV_ACCEPT,
|
||||
NMEV_CONNECTED,
|
||||
NMEV_CANCELLED,
|
||||
NMEV_SHUTDOWN
|
||||
} isc_nm_eventtype;
|
||||
|
||||
isc_nm_t *
|
||||
isc_nm_start(isc_mem_t *mctx, uint32_t workers);
|
||||
/*%<
|
||||
* Creates a new network manager with 'workers' worker threads,
|
||||
* and starts it running.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst);
|
||||
void
|
||||
isc_nm_detach(isc_nm_t **mgr0);
|
||||
void
|
||||
isc_nm_destroy(isc_nm_t **mgr0);
|
||||
/*%<
|
||||
* Attach/detach a network manager. When all references have been
|
||||
* released, the network manager is shut down, freeing all resources.
|
||||
* Destroy is working the same way as detach, but it actively waits
|
||||
* for all other references to be gone.
|
||||
*/
|
||||
|
||||
/* Return thread id of current thread, or ISC_NETMGR_TID_UNKNOWN */
|
||||
int
|
||||
isc_nm_tid(void);
|
||||
|
||||
/*
|
||||
* isc_nm_freehandle frees a handle, releasing resources
|
||||
*/
|
||||
void
|
||||
isc_nm_freehandle(isc_nmhandle_t *handle);
|
||||
|
||||
void
|
||||
isc_nmsocket_attach(isc_nmsocket_t *sock, isc_nmsocket_t **target);
|
||||
/*%<
|
||||
* isc_nmsocket_attach attaches to a socket, increasing refcount
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nmsocket_close(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc_nmsocket_detach(isc_nmsocket_t **socketp);
|
||||
/*%<
|
||||
* isc_nmsocket_detach detaches from socket, decreasing refcount
|
||||
* and possibly destroying the socket if it's no longer referenced.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nmhandle_ref(isc_nmhandle_t *handle);
|
||||
void
|
||||
isc_nmhandle_unref(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Increment/decrement the reference counter in a netmgr handle,
|
||||
* but (unlike the attach/detach functions) do not change the pointer
|
||||
* value. If reference counters drop to zero, the handle can be
|
||||
* marked inactive, possibly triggering deletion of its associated
|
||||
* socket.
|
||||
*
|
||||
* (This will be used to prevent a client from being cleaned up when
|
||||
* it's passed to an isc_task event handler. The libuv code would not
|
||||
* otherwise know that the handle was in use and might free it, along
|
||||
* with the client.)
|
||||
*/
|
||||
|
||||
void *
|
||||
isc_nmhandle_getdata(isc_nmhandle_t *handle);
|
||||
|
||||
void *
|
||||
isc_nmhandle_getextra(isc_nmhandle_t *handle);
|
||||
|
||||
typedef void (*isc_nm_opaquecb)(void *arg);
|
||||
|
||||
bool
|
||||
isc_nmhandle_is_stream(isc_nmhandle_t *handle);
|
||||
|
||||
/*
|
||||
* isc_nmhandle_t has a void * opaque field (usually - ns_client_t).
|
||||
* We reuse handle and `opaque` can also be reused between calls.
|
||||
* This function sets this field and two callbacks:
|
||||
* - doreset resets the `opaque` to initial state
|
||||
* - dofree frees everything associated with `opaque`
|
||||
*/
|
||||
void
|
||||
isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg,
|
||||
isc_nm_opaquecb doreset, isc_nm_opaquecb dofree);
|
||||
|
||||
isc_sockaddr_t
|
||||
isc_nmhandle_peeraddr(isc_nmhandle_t *handle);
|
||||
isc_sockaddr_t
|
||||
isc_nmhandle_localaddr(isc_nmhandle_t *handle);
|
||||
|
||||
typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
void *cbarg);
|
||||
/*%<
|
||||
* Callback function to be used when receiving a packet.
|
||||
*
|
||||
* 'handle' the handle that can be used to send back the answer.
|
||||
* 'region' contains the received data. It will be freed after
|
||||
* return by caller.
|
||||
* 'cbarg' the callback argument passed to isc_nm_listenudp(),
|
||||
* isc_nm_listentcpdns(), or isc_nm_read().
|
||||
*/
|
||||
|
||||
typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
|
||||
void *cbarg);
|
||||
/*%<
|
||||
* Callback function for other network completion events (send, connect,
|
||||
* accept).
|
||||
*
|
||||
* 'handle' the handle on which the event took place.
|
||||
* 'result' the result of the event.
|
||||
* 'cbarg' the callback argument passed to isc_nm_send(),
|
||||
* isc_nm_tcp_connect(), or isc_nm_listentcp()
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_recv_cb_t cb, void *cbarg,
|
||||
size_t extrasize, isc_nmsocket_t **sockp);
|
||||
/*%<
|
||||
* Start listening for UDP packets on interface 'iface' using net manager
|
||||
* 'mgr'.
|
||||
*
|
||||
* On success, 'sockp' will be updated to contain a new listening UDP socket.
|
||||
*
|
||||
* When a packet is received on the socket, 'cb' will be called with 'cbarg'
|
||||
* as its argument.
|
||||
*
|
||||
* When handles are allocated for the socket, 'extrasize' additional bytes
|
||||
* will be allocated along with the handle for an associated object
|
||||
* (typically ns_client).
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_udp_stoplistening(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Stop listening for UDP packets on socket 'sock'.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_pause(isc_nm_t *mgr);
|
||||
/*%<
|
||||
* Pause all processing, equivalent to taskmgr exclusive tasks.
|
||||
* It won't return until all workers have been paused.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_resume(isc_nm_t *mgr);
|
||||
/*%<
|
||||
* Resume paused processing. It will return immediately
|
||||
* after signalling workers to resume.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
|
||||
|
||||
isc_result_t
|
||||
isc_nm_pauseread(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Pause reading on this socket, while still remembering the callback.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_resumeread(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Resume reading from socket.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'sock' is a valid netmgr socket
|
||||
* \li ...for which a read/recv callback has been defined.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Send the data in 'region' via 'handle'. Afterward, the callback 'cb' is
|
||||
* called with the argument 'cbarg'.
|
||||
*
|
||||
* 'region' is not copied; it has to be allocated beforehand and freed
|
||||
* in 'cb'.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_cb_t cb, void *cbarg,
|
||||
size_t extrahandlesize, isc_quota_t *quota,
|
||||
isc_nmsocket_t **rv);
|
||||
/*%<
|
||||
* Start listening for raw messages over the TCP interface 'iface', using
|
||||
* net manager 'mgr'.
|
||||
*
|
||||
* On success, 'sockp' will be updated to contain a new listening TCP
|
||||
* socket.
|
||||
*
|
||||
* When a message is received on the socket, 'cb' will be called with 'cbarg'
|
||||
* as its argument.
|
||||
*
|
||||
* When handles are allocated for the socket, 'extrasize' additional bytes
|
||||
* will be allocated along with the handle for an associated object.
|
||||
*
|
||||
* If 'quota' is not NULL, then the socket is attached to the specified
|
||||
* quota. This allows us to enforce TCP client quota limits.
|
||||
*
|
||||
* NOTE: This is currently only called inside isc_nm_listentcpdns(), which
|
||||
* creates a 'wrapper' socket that sends and receives DNS messages -
|
||||
* prepended with a two-byte length field - and handles buffering.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_tcp_stoplistening(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Stop listening on TCP socket 'sock'.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_recv_cb_t cb, void *arg,
|
||||
size_t extrahandlesize, isc_quota_t *quota,
|
||||
isc_nmsocket_t **sockp);
|
||||
/*%<
|
||||
* Start listening for DNS messages over the TCP interface 'iface', using
|
||||
* net manager 'mgr'.
|
||||
*
|
||||
* On success, 'sockp' will be updated to contain a new listening TCPDNS
|
||||
* socket. This is a wrapper around a TCP socket, and handles DNS length
|
||||
* processing.
|
||||
*
|
||||
* When a complete DNS message is received on the socket, 'cb' will be
|
||||
* called with 'cbarg' as its argument.
|
||||
*
|
||||
* When handles are allocated for the socket, 'extrasize' additional bytes
|
||||
* will be allocated along with the handle for an associated object
|
||||
* (typically ns_client).
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Stop listening on TCPDNS socket 'sock'.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_tcpdns_sequential(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Disable pipelining on this connection. Each DNS packet
|
||||
* will be only processed after the previous completes.
|
||||
*
|
||||
* This cannot be reversed once set for a given connection
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
|
||||
/*%<
|
||||
* Simulate a broken firewall that blocks UDP messages larger
|
||||
* than a given size.
|
||||
*/
|
@ -9,153 +9,46 @@
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <isc/mem.h>
|
||||
|
||||
/*
|
||||
* This is a generic implementation of a two-lock concurrent queue.
|
||||
* There are built-in mutex locks for the head and tail of the queue,
|
||||
* allowing elements to be safely added and removed at the same time.
|
||||
typedef struct isc_queue isc_queue_t;
|
||||
|
||||
isc_queue_t *
|
||||
isc_queue_new(isc_mem_t *mctx, int max_threads);
|
||||
/*%<
|
||||
* Create a new fetch-and-add array queue.
|
||||
*
|
||||
* NULL is "end of list"
|
||||
* -1 is "not linked"
|
||||
* 'max_threads' is currently unused. In the future it can be used
|
||||
* to pass a maximum threads parameter when creating hazard pointers,
|
||||
* but currently `isc_hp_t` uses a hard-coded value.
|
||||
*/
|
||||
|
||||
#ifndef ISC_QUEUE_H
|
||||
#define ISC_QUEUE_H 1
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/mutex.h>
|
||||
|
||||
#ifdef ISC_QUEUE_CHECKINIT
|
||||
#define ISC_QLINK_INSIST(x) ISC_INSIST(x)
|
||||
#else
|
||||
#define ISC_QLINK_INSIST(x) (void)0
|
||||
#endif
|
||||
|
||||
#define ISC_QLINK(type) struct { type *prev, *next; }
|
||||
|
||||
#define ISC_QLINK_INIT(elt, link) \
|
||||
do { \
|
||||
(elt)->link.next = (elt)->link.prev = (void *)(-1); \
|
||||
} while(0)
|
||||
|
||||
#define ISC_QLINK_LINKED(elt, link) ((void*)(elt)->link.next != (void*)(-1))
|
||||
|
||||
#define ISC_QUEUE(type) struct { \
|
||||
type *head, *tail; \
|
||||
isc_mutex_t headlock, taillock; \
|
||||
}
|
||||
|
||||
#define ISC_QUEUE_INIT(queue, link) \
|
||||
do { \
|
||||
isc_mutex_init(&(queue).taillock); \
|
||||
isc_mutex_init(&(queue).headlock); \
|
||||
(queue).tail = (queue).head = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define ISC_QUEUE_EMPTY(queue) ((queue).head == NULL)
|
||||
|
||||
#define ISC_QUEUE_DESTROY(queue) \
|
||||
do { \
|
||||
ISC_QLINK_INSIST(ISC_QUEUE_EMPTY(queue)); \
|
||||
isc_mutex_destroy(&(queue).taillock); \
|
||||
isc_mutex_destroy(&(queue).headlock); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* queues are meant to separate the locks at either end. For best effect, that
|
||||
* means keeping the ends separate - i.e. non-empty queues work best.
|
||||
*
|
||||
* a push to an empty queue has to take the pop lock to update
|
||||
* the pop side of the queue.
|
||||
* Popping the last entry has to take the push lock to update
|
||||
* the push side of the queue.
|
||||
*
|
||||
* The order is (pop, push), because a pop is presumably in the
|
||||
* latency path and a push is when we're done.
|
||||
*
|
||||
* We do an MT hot test in push to see if we need both locks, so we can
|
||||
* acquire them in order. Hopefully that makes the case where we get
|
||||
* the push lock and find we need the pop lock (and have to release it) rare.
|
||||
*
|
||||
* > 1 entry - no collision, push works on one end, pop on the other
|
||||
* 0 entry - headlock race
|
||||
* pop wins - return(NULL), push adds new as both head/tail
|
||||
* push wins - updates head/tail, becomes 1 entry case.
|
||||
* 1 entry - taillock race
|
||||
* pop wins - return(pop) sets head/tail NULL, becomes 0 entry case
|
||||
* push wins - updates {head,tail}->link.next, pop updates head
|
||||
* with new ->link.next and doesn't update tail
|
||||
void
|
||||
isc_queue_enqueue(isc_queue_t *queue, uintptr_t item);
|
||||
/*%<
|
||||
* Enqueue an object pointer 'item' at the tail of the queue.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'item' is not null.
|
||||
*/
|
||||
#define ISC_QUEUE_PUSH(queue, elt, link) \
|
||||
do { \
|
||||
bool headlocked = false; \
|
||||
ISC_QLINK_INSIST(!ISC_QLINK_LINKED(elt, link)); \
|
||||
if ((queue).head == NULL) { \
|
||||
LOCK(&(queue).headlock); \
|
||||
headlocked = true; \
|
||||
} \
|
||||
LOCK(&(queue).taillock); \
|
||||
if ((queue).tail == NULL && !headlocked) { \
|
||||
UNLOCK(&(queue).taillock); \
|
||||
LOCK(&(queue).headlock); \
|
||||
LOCK(&(queue).taillock); \
|
||||
headlocked = true; \
|
||||
} \
|
||||
(elt)->link.prev = (queue).tail; \
|
||||
(elt)->link.next = NULL; \
|
||||
if ((queue).tail != NULL) \
|
||||
(queue).tail->link.next = (elt); \
|
||||
(queue).tail = (elt); \
|
||||
UNLOCK(&(queue).taillock); \
|
||||
if (headlocked) { \
|
||||
if ((queue).head == NULL) \
|
||||
(queue).head = (elt); \
|
||||
UNLOCK(&(queue).headlock); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ISC_QUEUE_POP(queue, link, ret) \
|
||||
do { \
|
||||
LOCK(&(queue).headlock); \
|
||||
ret = (queue).head; \
|
||||
while (ret != NULL) { \
|
||||
if (ret->link.next == NULL) { \
|
||||
LOCK(&(queue).taillock); \
|
||||
if (ret->link.next == NULL) { \
|
||||
(queue).head = (queue).tail = NULL; \
|
||||
UNLOCK(&(queue).taillock); \
|
||||
break; \
|
||||
}\
|
||||
UNLOCK(&(queue).taillock); \
|
||||
} \
|
||||
(queue).head = ret->link.next; \
|
||||
(queue).head->link.prev = NULL; \
|
||||
break; \
|
||||
} \
|
||||
UNLOCK(&(queue).headlock); \
|
||||
if (ret != NULL) \
|
||||
(ret)->link.next = (ret)->link.prev = (void *)(-1); \
|
||||
} while(0)
|
||||
uintptr_t
|
||||
isc_queue_dequeue(isc_queue_t *queue);
|
||||
/*%<
|
||||
* Remove an object pointer from the head of the queue and return the
|
||||
* pointer. If the queue is empty, return `nulluintptr` (the uintptr_t
|
||||
* representation of NULL).
|
||||
*
|
||||
* Requires:
|
||||
* \li 'queue' is not null.
|
||||
*/
|
||||
|
||||
#define ISC_QUEUE_UNLINK(queue, elt, link) \
|
||||
do { \
|
||||
ISC_QLINK_INSIST(ISC_QLINK_LINKED(elt, link)); \
|
||||
LOCK(&(queue).headlock); \
|
||||
LOCK(&(queue).taillock); \
|
||||
if ((elt)->link.prev == NULL) \
|
||||
(queue).head = (elt)->link.next; \
|
||||
else \
|
||||
(elt)->link.prev->link.next = (elt)->link.next; \
|
||||
if ((elt)->link.next == NULL) \
|
||||
(queue).tail = (elt)->link.prev; \
|
||||
else \
|
||||
(elt)->link.next->link.prev = (elt)->link.prev; \
|
||||
UNLOCK(&(queue).taillock); \
|
||||
UNLOCK(&(queue).headlock); \
|
||||
(elt)->link.next = (elt)->link.prev = (void *)(-1); \
|
||||
} while(0)
|
||||
|
||||
#endif /* ISC_QUEUE_H */
|
||||
void
|
||||
isc_queue_destroy(isc_queue_t *queue);
|
||||
/*%<
|
||||
* Destroy a queue.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'queue' is not null.
|
||||
*/
|
||||
|
@ -9,7 +9,6 @@
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ISC_RESULT_H
|
||||
#define ISC_RESULT_H 1
|
||||
|
||||
|
@ -230,6 +230,10 @@ isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path);
|
||||
* \li ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa);
|
||||
|
||||
|
||||
#define ISC_SOCKADDR_FORMATSIZE \
|
||||
sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS#YYYYY")
|
||||
/*%<
|
||||
|
@ -524,7 +524,7 @@ isc_result_t
|
||||
isc_socket_filter(isc_socket_t *sock, const char *filter);
|
||||
/*%<
|
||||
* Inform the kernel that it should perform accept filtering.
|
||||
* If filter is NULL the current filter will be removed.:w
|
||||
* If filter is NULL the current filter will be removed.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
|
@ -78,6 +78,7 @@
|
||||
#include <isc/eventclass.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
#define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0)
|
||||
@ -544,6 +545,8 @@ isc_task_beginexclusive(isc_task_t *task);
|
||||
* task. Waits for any other concurrently executing tasks to finish their
|
||||
* current event, and prevents any new events from executing in any of the
|
||||
* tasks sharing a task manager with 'task'.
|
||||
* It also pauses processing of network events in netmgr if it was provided
|
||||
* when taskmgr was created.
|
||||
*
|
||||
* The exclusive access must be relinquished by calling
|
||||
* isc_task_endexclusive() before returning from the current event handler.
|
||||
@ -568,6 +571,22 @@ isc_task_endexclusive(isc_task_t *task);
|
||||
* exclusive access by calling isc_task_spl().
|
||||
*/
|
||||
|
||||
void
|
||||
isc_task_pause(isc_task_t *task0);
|
||||
void
|
||||
isc_task_unpause(isc_task_t *task0);
|
||||
/*%<
|
||||
* Pause/unpause this task. Pausing a task removes it from the ready
|
||||
* queue if it is present there; this ensures that the task will not
|
||||
* run again until unpaused. This is necessary when the libuv network
|
||||
* thread executes a function which schedules task manager events; this
|
||||
* prevents the task manager from executing the next event in a task
|
||||
* before the network thread has finished.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'task' is a valid task, and is not already paused or shutting down.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t);
|
||||
void
|
||||
@ -633,7 +652,8 @@ isc_taskmgr_createinctx(isc_mem_t *mctx,
|
||||
isc_taskmgr_t **managerp);
|
||||
isc_result_t
|
||||
isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
|
||||
unsigned int default_quantum, isc_taskmgr_t **managerp);
|
||||
unsigned int default_quantum,
|
||||
isc_nm_t *nm, isc_taskmgr_t **managerp);
|
||||
/*%<
|
||||
* Create a new task manager. isc_taskmgr_createinctx() also associates
|
||||
* the new manager with the specified application context.
|
||||
@ -650,6 +670,9 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
|
||||
* quantum value when tasks are created. If zero, then an implementation
|
||||
* defined default quantum will be used.
|
||||
*
|
||||
*\li If 'nm' is set then netmgr is paused when an exclusive task mode
|
||||
* is requested.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'mctx' is a valid memory context.
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
/* Core Types. Alphabetized by defined type. */
|
||||
|
||||
typedef struct isc_astack isc_astack_t; /*%< Array-based fast stack */
|
||||
typedef struct isc_appctx isc_appctx_t; /*%< Application context */
|
||||
typedef struct isc_backtrace_symmap isc_backtrace_symmap_t; /*%< Symbol Table Entry */
|
||||
typedef struct isc_buffer isc_buffer_t; /*%< Buffer */
|
||||
@ -43,6 +44,8 @@ typedef ISC_LIST(isc_event_t) isc_eventlist_t; /*%< Event List */
|
||||
typedef unsigned int isc_eventtype_t; /*%< Event Type */
|
||||
typedef uint32_t isc_fsaccess_t; /*%< FS Access */
|
||||
typedef struct isc_hash isc_hash_t; /*%< Hash */
|
||||
typedef struct isc_hp isc_hp_t; /*%< Hazard
|
||||
pointer */
|
||||
typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */
|
||||
typedef void (isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function */
|
||||
typedef struct isc_httpdmgr isc_httpdmgr_t; /*%< HTTP manager */
|
||||
@ -59,6 +62,10 @@ typedef struct isc_logmodule isc_logmodule_t; /*%< Log Module */
|
||||
typedef struct isc_mem isc_mem_t; /*%< Memory */
|
||||
typedef struct isc_mempool isc_mempool_t; /*%< Memory Pool */
|
||||
typedef struct isc_netaddr isc_netaddr_t; /*%< Net Address */
|
||||
typedef struct isc_nm isc_nm_t; /*%< Network manager */
|
||||
typedef struct isc_nmsocket isc_nmsocket_t; /*%< Network manager socket */
|
||||
typedef struct isc_nmiface isc_nmiface_t; /*%< Network manager interface. */
|
||||
typedef struct isc_nmhandle isc_nmhandle_t; /*%< Network manager handle */
|
||||
typedef struct isc_portset isc_portset_t; /*%< Port Set */
|
||||
typedef struct isc_quota isc_quota_t; /*%< Quota */
|
||||
typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <isc/lang.h>
|
||||
#include <isc/resultclass.h>
|
||||
#include <isc/types.h>
|
||||
|
||||
/*
|
||||
* Nothing in this file truly depends on <isc/result.h>, but the
|
||||
|
33
lib/isc/netmgr/Makefile.in
Normal file
33
lib/isc/netmgr/Makefile.in
Normal file
@ -0,0 +1,33 @@
|
||||
# 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.
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
CINCLUDES = -I${srcdir}/../include \
|
||||
-I${srcdir}/../unix/include \
|
||||
-I${srcdir}/../pthreads/include \
|
||||
-I${srcdir}/.. \
|
||||
${OPENSSL_CFLAGS} \
|
||||
${JSON_C_CFLAGS} \
|
||||
${LIBXML2_CFLAGS}
|
||||
|
||||
CDEFINES =
|
||||
CWARNINGS =
|
||||
|
||||
# Alphabetically
|
||||
OBJS = netmgr.@O@ tcp.@O@ udp.@O@ tcpdns.@O@ uverr2result.@O@
|
||||
|
||||
# Alphabetically
|
||||
SRCS = netmgr.c tcp.c udp.c tcpdns.c uverr2result.c
|
||||
|
||||
TARGETS = ${OBJS}
|
||||
|
||||
@BIND9_MAKE_RULES@
|
547
lib/isc/netmgr/netmgr-int.h
Normal file
547
lib/isc/netmgr/netmgr-int.h
Normal file
@ -0,0 +1,547 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include <isc/astack.h>
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/condition.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/queue.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#define ISC_NETMGR_TID_UNKNOWN -1
|
||||
#define ISC_NETMGR_TID_NOTLS -2
|
||||
|
||||
/*
|
||||
* Single network event loop worker.
|
||||
*/
|
||||
typedef struct isc__networker {
|
||||
isc_nm_t * mgr;
|
||||
int id; /* thread id */
|
||||
uv_loop_t loop; /* libuv loop structure */
|
||||
uv_async_t async; /* async channel to send
|
||||
* data to this networker */
|
||||
isc_mutex_t lock;
|
||||
isc_mempool_t *mpool_bufs;
|
||||
isc_condition_t cond;
|
||||
bool paused;
|
||||
bool finished;
|
||||
isc_thread_t thread;
|
||||
isc_queue_t *ievents; /* incoming async events */
|
||||
isc_refcount_t references;
|
||||
atomic_int_fast64_t pktcount;
|
||||
char udprecvbuf[65536];
|
||||
bool udprecvbuf_inuse;
|
||||
} isc__networker_t;
|
||||
|
||||
/*
|
||||
* A general handle for a connection bound to a networker. For UDP
|
||||
* connections we have peer address here, so both TCP and UDP can be
|
||||
* handled with a simple send-like function
|
||||
*/
|
||||
#define NMHANDLE_MAGIC ISC_MAGIC('N', 'M', 'H', 'D')
|
||||
#define VALID_NMHANDLE(t) ISC_MAGIC_VALID(t, \
|
||||
NMHANDLE_MAGIC)
|
||||
|
||||
typedef void (*isc__nm_closecb)(isc_nmhandle_t *);
|
||||
|
||||
struct isc_nmhandle {
|
||||
int magic;
|
||||
isc_refcount_t references;
|
||||
|
||||
/*
|
||||
* The socket is not 'attached' in the traditional
|
||||
* reference-counting sense. Instead, we keep all handles in an
|
||||
* array in the socket object. This way, we don't have circular
|
||||
* dependencies and we can close all handles when we're destroying
|
||||
* the socket.
|
||||
*/
|
||||
isc_nmsocket_t *sock;
|
||||
size_t ah_pos; /* Position in the socket's
|
||||
* 'active handles' array */
|
||||
|
||||
/*
|
||||
* The handle is 'inflight' if netmgr is not currently processing
|
||||
* it in any way - it might mean that e.g. a recursive resolution
|
||||
* is happening. For an inflight handle we must wait for the
|
||||
* calling code to finish before we can free it.
|
||||
*/
|
||||
atomic_bool inflight;
|
||||
|
||||
isc_sockaddr_t peer;
|
||||
isc_sockaddr_t local;
|
||||
isc_nm_opaquecb doreset; /* reset extra callback, external */
|
||||
isc_nm_opaquecb dofree; /* free extra callback, external */
|
||||
void * opaque;
|
||||
char extra[];
|
||||
};
|
||||
|
||||
/*
|
||||
* An interface - an address we can listen on.
|
||||
*/
|
||||
struct isc_nmiface {
|
||||
isc_sockaddr_t addr;
|
||||
};
|
||||
|
||||
typedef enum isc__netievent_type {
|
||||
netievent_stop,
|
||||
netievent_udplisten,
|
||||
netievent_udpstoplisten,
|
||||
netievent_udpsend,
|
||||
netievent_udprecv,
|
||||
netievent_tcpconnect,
|
||||
netievent_tcpsend,
|
||||
netievent_tcprecv,
|
||||
netievent_tcpstartread,
|
||||
netievent_tcppauseread,
|
||||
netievent_tcplisten,
|
||||
netievent_tcpstoplisten,
|
||||
netievent_tcpclose,
|
||||
} isc__netievent_type;
|
||||
|
||||
typedef struct isc__netievent_stop {
|
||||
isc__netievent_type type;
|
||||
} isc__netievent_stop_t;
|
||||
|
||||
/*
|
||||
* We have to split it because we can read and write on a socket
|
||||
* simultaneously.
|
||||
*/
|
||||
typedef union {
|
||||
isc_nm_recv_cb_t recv;
|
||||
isc_nm_cb_t accept;
|
||||
} isc__nm_readcb_t;
|
||||
|
||||
typedef union {
|
||||
isc_nm_cb_t send;
|
||||
isc_nm_cb_t connect;
|
||||
} isc__nm_writecb_t;
|
||||
|
||||
typedef union {
|
||||
isc_nm_recv_cb_t recv;
|
||||
isc_nm_cb_t accept;
|
||||
isc_nm_cb_t send;
|
||||
isc_nm_cb_t connect;
|
||||
} isc__nm_cb_t;
|
||||
|
||||
/*
|
||||
* Wrapper around uv_req_t with 'our' fields in it. req->data should
|
||||
* always point to its parent. Note that we always allocate more than
|
||||
* sizeof(struct) because we make room for different req types;
|
||||
*/
|
||||
#define UVREQ_MAGIC ISC_MAGIC('N', 'M', 'U', 'R')
|
||||
#define VALID_UVREQ(t) ISC_MAGIC_VALID(t, UVREQ_MAGIC)
|
||||
|
||||
typedef struct isc__nm_uvreq {
|
||||
int magic;
|
||||
isc_nmsocket_t * sock;
|
||||
isc_nmhandle_t * handle;
|
||||
uv_buf_t uvbuf; /* translated isc_region_t, to be
|
||||
sent or received */
|
||||
isc_sockaddr_t local; /* local address */
|
||||
isc_sockaddr_t peer; /* peer address */
|
||||
isc__nm_cb_t cb; /* callback */
|
||||
void * cbarg; /* callback argument */
|
||||
union {
|
||||
uv_req_t req;
|
||||
uv_getaddrinfo_t getaddrinfo;
|
||||
uv_getnameinfo_t getnameinfo;
|
||||
uv_shutdown_t shutdown;
|
||||
uv_write_t write;
|
||||
uv_connect_t connect;
|
||||
uv_udp_send_t udp_send;
|
||||
uv_fs_t fs;
|
||||
uv_work_t work;
|
||||
} uv_req;
|
||||
} isc__nm_uvreq_t;
|
||||
|
||||
typedef struct isc__netievent__socket {
|
||||
isc__netievent_type type;
|
||||
isc_nmsocket_t *sock;
|
||||
} isc__netievent__socket_t;
|
||||
|
||||
typedef isc__netievent__socket_t isc__netievent_udplisten_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_udpstoplisten_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpstoplisten_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_tcpclose_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_startread_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_pauseread_t;
|
||||
typedef isc__netievent__socket_t isc__netievent_resumeread_t;
|
||||
|
||||
typedef struct isc__netievent__socket_req {
|
||||
isc__netievent_type type;
|
||||
isc_nmsocket_t *sock;
|
||||
isc__nm_uvreq_t *req;
|
||||
} isc__netievent__socket_req_t;
|
||||
|
||||
typedef isc__netievent__socket_req_t isc__netievent_tcpconnect_t;
|
||||
typedef isc__netievent__socket_req_t isc__netievent_tcplisten_t;
|
||||
typedef isc__netievent__socket_req_t isc__netievent_tcpsend_t;
|
||||
|
||||
typedef struct isc__netievent_udpsend {
|
||||
isc__netievent_type type;
|
||||
isc_nmsocket_t *sock;
|
||||
isc_sockaddr_t peer;
|
||||
isc__nm_uvreq_t *req;
|
||||
} isc__netievent_udpsend_t;
|
||||
|
||||
typedef struct isc__netievent {
|
||||
isc__netievent_type type;
|
||||
} isc__netievent_t;
|
||||
|
||||
typedef union {
|
||||
isc__netievent_t ni;
|
||||
isc__netievent_stop_t nis;
|
||||
isc__netievent_udplisten_t niul;
|
||||
isc__netievent_udpsend_t nius;
|
||||
} isc__netievent_storage_t;
|
||||
|
||||
/*
|
||||
* Network manager
|
||||
*/
|
||||
#define NM_MAGIC ISC_MAGIC('N', 'E', 'T', 'M')
|
||||
#define VALID_NM(t) ISC_MAGIC_VALID(t, NM_MAGIC)
|
||||
|
||||
struct isc_nm {
|
||||
int magic;
|
||||
isc_refcount_t references;
|
||||
isc_mem_t *mctx;
|
||||
uint32_t nworkers;
|
||||
isc_mutex_t lock;
|
||||
isc_condition_t wkstatecond;
|
||||
isc__networker_t *workers;
|
||||
atomic_uint_fast32_t workers_running;
|
||||
atomic_uint_fast32_t workers_paused;
|
||||
atomic_uint_fast32_t maxudp;
|
||||
atomic_bool paused;
|
||||
|
||||
/*
|
||||
* A worker is actively waiting for other workers, for example to
|
||||
* stop listening; that means no other thread can do the same thing
|
||||
* or pause, or we'll deadlock. We have to either re-enqueue our
|
||||
* event or wait for the other one to finish if we want to pause.
|
||||
*/
|
||||
atomic_bool interlocked;
|
||||
};
|
||||
|
||||
typedef enum isc_nmsocket_type {
|
||||
isc_nm_udpsocket,
|
||||
isc_nm_udplistener, /* Aggregate of nm_udpsocks */
|
||||
isc_nm_tcpsocket,
|
||||
isc_nm_tcplistener,
|
||||
isc_nm_tcpdnslistener,
|
||||
isc_nm_tcpdnssocket
|
||||
} isc_nmsocket_type;
|
||||
|
||||
/*%
|
||||
* A universal structure for either a single socket or a group of
|
||||
* dup'd/SO_REUSE_PORT-using sockets listening on the same interface.
|
||||
*/
|
||||
#define NMSOCK_MAGIC ISC_MAGIC('N', 'M', 'S', 'K')
|
||||
#define VALID_NMSOCK(t) ISC_MAGIC_VALID(t, NMSOCK_MAGIC)
|
||||
|
||||
struct isc_nmsocket {
|
||||
/*% Unlocked, RO */
|
||||
int magic;
|
||||
int tid;
|
||||
isc_nmsocket_type type;
|
||||
isc_nm_t *mgr;
|
||||
isc_nmsocket_t *parent;
|
||||
isc_quota_t *quota;
|
||||
bool overquota;
|
||||
|
||||
/*% outer socket is for 'wrapped' sockets - e.g. tcpdns in tcp */
|
||||
isc_nmsocket_t *outer;
|
||||
|
||||
/*% server socket for connections */
|
||||
isc_nmsocket_t *server;
|
||||
|
||||
/*% children sockets for multi-socket setups */
|
||||
isc_nmsocket_t *children;
|
||||
int nchildren;
|
||||
isc_nmiface_t *iface;
|
||||
isc_nmhandle_t *tcphandle;
|
||||
|
||||
/*% extra data allocated at the end of each isc_nmhandle_t */
|
||||
size_t extrahandlesize;
|
||||
|
||||
/*% libuv data */
|
||||
uv_os_sock_t fd;
|
||||
union uv_any_handle uv_handle;
|
||||
|
||||
isc_sockaddr_t peer;
|
||||
|
||||
/* Atomic */
|
||||
/*% Number of running (e.g. listening) children sockets */
|
||||
atomic_int_fast32_t rchildren;
|
||||
|
||||
/*%
|
||||
* Socket if active if it's listening, working, etc., if we're
|
||||
* closing a socket it doesn't make any sense to e.g. still
|
||||
* push handles or reqs for reuse
|
||||
*/
|
||||
atomic_bool active;
|
||||
atomic_bool destroying;
|
||||
|
||||
/*%
|
||||
* Socket is closed if it's not active and all the possible
|
||||
* callbacks were fired, there are no active handles, etc.
|
||||
* active==false, closed==false means the socket is closing.
|
||||
*/
|
||||
atomic_bool closed;
|
||||
atomic_bool listening;
|
||||
isc_refcount_t references;
|
||||
|
||||
/*%
|
||||
* TCPDNS socket is not pipelining.
|
||||
*/
|
||||
atomic_bool sequential;
|
||||
/*%
|
||||
* TCPDNS socket in sequential mode is currently processing a packet,
|
||||
* we need to wait until it finishes.
|
||||
*/
|
||||
atomic_bool processing;
|
||||
|
||||
/*%
|
||||
* 'spare' handles for that can be reused to avoid allocations,
|
||||
* for UDP.
|
||||
*/
|
||||
isc_astack_t *inactivehandles;
|
||||
isc_astack_t *inactivereqs;
|
||||
|
||||
/* Used for active/rchildren during shutdown */
|
||||
isc_mutex_t lock;
|
||||
isc_condition_t cond;
|
||||
|
||||
/*%
|
||||
* List of active handles.
|
||||
* ah_size - size of ah_frees and ah_handles
|
||||
* ah_cpos - current position in ah_frees;
|
||||
* ah_handles - array of *handles.
|
||||
* Adding a handle
|
||||
* - if ah_cpos == ah_size, realloc
|
||||
* - x = ah_frees[ah_cpos]
|
||||
* - ah_frees[ah_cpos++] = 0;
|
||||
* - ah_handles[x] = handle
|
||||
* - x must be stored with the handle!
|
||||
* Removing a handle:
|
||||
* - ah_frees[--ah_cpos] = x
|
||||
* - ah_handles[x] = NULL;
|
||||
*
|
||||
* XXXWPK for now this is locked with socket->lock, but we might want
|
||||
* to change it to something lockless
|
||||
*/
|
||||
size_t ah_size;
|
||||
size_t ah_cpos;
|
||||
size_t *ah_frees;
|
||||
isc_nmhandle_t **ah_handles;
|
||||
|
||||
/* Buffer for TCPDNS processing, optional */
|
||||
size_t buf_size;
|
||||
size_t buf_len;
|
||||
unsigned char *buf;
|
||||
|
||||
isc__nm_readcb_t rcb;
|
||||
void *rcbarg;
|
||||
};
|
||||
|
||||
bool
|
||||
isc__nm_in_netthread(void);
|
||||
/*%
|
||||
* Returns 'true' if we're in the network thread.
|
||||
*/
|
||||
|
||||
void *
|
||||
isc__nm_get_ievent(isc_nm_t *mgr, isc__netievent_type type);
|
||||
/*%<
|
||||
* Allocate an ievent and set the type.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event);
|
||||
/*%<
|
||||
* Enqueue an ievent onto a specific worker queue. (This the only safe
|
||||
* way to use an isc__networker_t from another thread.)
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf);
|
||||
/*%<
|
||||
* Allocator for recv operations.
|
||||
*
|
||||
* Note that as currently implemented, this doesn't actually
|
||||
* allocate anything, it just assigns the the isc__networker's UDP
|
||||
* receive buffer to a socket, and marks it as "in use".
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf);
|
||||
/*%<
|
||||
* Free a buffer allocated for a receive operation.
|
||||
*
|
||||
* Note that as currently implemented, this doesn't actually
|
||||
* free anything, marks the isc__networker's UDP receive buffer
|
||||
* as "not in use".
|
||||
*/
|
||||
|
||||
|
||||
isc_nmhandle_t *
|
||||
isc__nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
|
||||
isc_sockaddr_t *local);
|
||||
/*%<
|
||||
* Get a handle for the socket 'sock', allocating a new one
|
||||
* if there isn't one availbale in 'sock->inactivehandles'.
|
||||
*
|
||||
* If 'peer' is not NULL, set the handle's peer address to 'peer',
|
||||
* otherwise set it to 'sock->peer'.
|
||||
*
|
||||
* If 'local' is not NULL, set the handle's local address to 'local',
|
||||
* otherwise set it to 'sock->iface->addr'.
|
||||
*/
|
||||
|
||||
isc__nm_uvreq_t *
|
||||
isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Get a UV request structure for the socket 'sock', allocating a
|
||||
* new one if there isn't one availbale in 'sock->inactivereqs'.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_uvreq_put(isc__nm_uvreq_t **req, isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Completes the use of a UV request structure, setting '*req' to NULL.
|
||||
*
|
||||
* The UV request is pushed onto the 'sock->inactivereqs' stack or,
|
||||
* if that doesn't work, freed.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr,
|
||||
isc_nmsocket_type type);
|
||||
/*%<
|
||||
* Initialize socket 'sock', attach it to 'mgr', and set it to type 'type'.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nmsocket_prep_destroy(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Market 'sock' as inactive, close it if necessary, and destroy it
|
||||
* if there are no remaining references or active handles.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Back-end implemenation of isc_nm_send() for UDP handles.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
|
||||
void
|
||||
isc__nm_async_udpstoplisten(isc__networker_t *worker,
|
||||
isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
/*%<
|
||||
* Callback handlers for asynchronous UDP events (listen, stoplisten, send).
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Back-end implemenation of isc_nm_send() for TCP handles.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcp_close(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Close a TCP socket.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_tcpstoplisten(isc__networker_t *worker,
|
||||
isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_resumeread(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
void
|
||||
isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ievent0);
|
||||
/*%<
|
||||
* Callback handlers for asynchronous TCP events (connect, listen,
|
||||
* stoplisten, send, read, pauseread, resumeread, close).
|
||||
*/
|
||||
|
||||
|
||||
isc_result_t
|
||||
isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Back-end implemenation of isc_nm_send() for TCPDNS handles.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcpdns_close(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Close a TCPDNS socket.
|
||||
*/
|
||||
|
||||
#define isc__nm_uverr2result(x) \
|
||||
isc___nm_uverr2result(x, true, __FILE__, __LINE__)
|
||||
isc_result_t
|
||||
isc___nm_uverr2result(int uverr, bool dolog,
|
||||
const char *file, unsigned int line);
|
||||
/*%<
|
||||
* Convert a libuv error value into an isc_result_t. The
|
||||
* list of supported error values is not complete; new users
|
||||
* of this function should add any expected errors that are
|
||||
* not already there.
|
||||
*/
|
||||
|
||||
bool
|
||||
isc__nm_acquire_interlocked(isc_nm_t *mgr);
|
||||
/*%<
|
||||
* Try to acquire interlocked state; return true if successful.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_drop_interlocked(isc_nm_t *mgr);
|
||||
/*%<
|
||||
* Drop interlocked state; signal waiters.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_acquire_interlocked_force(isc_nm_t *mgr);
|
||||
/*%<
|
||||
* Actively wait for interlocked state.
|
||||
*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user