summaryrefslogtreecommitdiffstats
path: root/bin/tests/optional
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
commit45d6379135504814ab723b57f0eb8be23393a51d (patch)
treed4f2ec4acca824a8446387a758b0ce4238a4dffa /bin/tests/optional
parentInitial commit. (diff)
downloadbind9-upstream.tar.xz
bind9-upstream.zip
Adding upstream version 1:9.16.44.upstream/1%9.16.44upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--bin/tests/optional/Kchild.example.+005+33180.key5
-rw-r--r--bin/tests/optional/Kchild.example.+005+33180.private13
-rw-r--r--bin/tests/optional/Makefile.in254
-rw-r--r--bin/tests/optional/adb_test.c410
-rw-r--r--bin/tests/optional/backtrace_test.c88
-rw-r--r--bin/tests/optional/byaddr_test.c250
-rw-r--r--bin/tests/optional/byname_test.c350
-rw-r--r--bin/tests/optional/db_test.c983
-rw-r--r--bin/tests/optional/fsaccess_test.c69
-rw-r--r--bin/tests/optional/gsstest.c550
-rw-r--r--bin/tests/optional/inter_test.c133
-rw-r--r--bin/tests/optional/lex_test.c159
-rw-r--r--bin/tests/optional/lfsr_test.c93
-rw-r--r--bin/tests/optional/log_test.c344
-rw-r--r--bin/tests/optional/master_test.c88
-rw-r--r--bin/tests/optional/mempool_test.c112
-rw-r--r--bin/tests/optional/name_test.c365
-rw-r--r--bin/tests/optional/nsecify.c217
-rw-r--r--bin/tests/optional/ratelimiter_test.c142
-rw-r--r--bin/tests/optional/rbt_test.c432
-rw-r--r--bin/tests/optional/rbt_test.out395
-rw-r--r--bin/tests/optional/rbt_test.txt87
-rw-r--r--bin/tests/optional/rwlock_test.c130
-rw-r--r--bin/tests/optional/serial_test.c45
-rw-r--r--bin/tests/optional/shutdown_test.c226
-rw-r--r--bin/tests/optional/sig0_test.c282
-rw-r--r--bin/tests/optional/sock_test.c394
-rw-r--r--bin/tests/optional/sym_test.c122
-rw-r--r--bin/tests/optional/task_test.c207
-rw-r--r--bin/tests/optional/timer_test.c184
-rw-r--r--bin/tests/optional/zone_test.c318
31 files changed, 7447 insertions, 0 deletions
diff --git a/bin/tests/optional/Kchild.example.+005+33180.key b/bin/tests/optional/Kchild.example.+005+33180.key
new file mode 100644
index 0000000..ab92a6a
--- /dev/null
+++ b/bin/tests/optional/Kchild.example.+005+33180.key
@@ -0,0 +1,5 @@
+; This is a zone-signing key, keyid 33180, for child.example.
+; Created: 20181025104746 (Thu Oct 25 12:47:46 2018)
+; Publish: 20181025104746 (Thu Oct 25 12:47:46 2018)
+; Activate: 20181025104746 (Thu Oct 25 12:47:46 2018)
+child.example. IN DNSKEY 256 3 5 AwEAAb9eatC8ASzDnRApcZuxyBrvJRANRQjCXQ1FWK+8vEyXV5NIE9Km hKIV2wbq2tLBPfjNQz4BTJ9RmDINf1RayDlt6L+IQV1JCaDaMjd1zU3n SQK18Y7fMu0ww4AMKOnoVRbkIxa3zlA0chImXcfPE0q2AvKBYLzPfkPO cfplAuRkLcGUxdADCipNzCOakpcd5gfm9Sa2HlaXcw3gyI1WcE8=
diff --git a/bin/tests/optional/Kchild.example.+005+33180.private b/bin/tests/optional/Kchild.example.+005+33180.private
new file mode 100644
index 0000000..83a50df
--- /dev/null
+++ b/bin/tests/optional/Kchild.example.+005+33180.private
@@ -0,0 +1,13 @@
+Private-key-format: v1.3
+Algorithm: 5 (RSASHA1)
+Modulus: v15q0LwBLMOdEClxm7HIGu8lEA1FCMJdDUVYr7y8TJdXk0gT0qaEohXbBura0sE9+M1DPgFMn1GYMg1/VFrIOW3ov4hBXUkJoNoyN3XNTedJArXxjt8y7TDDgAwo6ehVFuQjFrfOUDRyEiZdx88TSrYC8oFgvM9+Q85x+mUC5GQtwZTF0AMKKk3MI5qSlx3mB+b1JrYeVpdzDeDIjVZwTw==
+PublicExponent: AQAB
+PrivateExponent: WDsn9GU6BXGLENCK2MX3BLQN2oDDu24hiOTYJu5VwtpkPjuVKCIuNKzu9xmBGnqOIBBDWGsw8KOmEC247yOL/S53iRdBS8lI7yiqznc52RhlmrdPKXbNpVnPwil8wocw+oQYa7uvdPYxI2Yy3B/tRgUxlxSlc/LW/dr0BX2L7qr/aeOBeGSRUlCpc7tYU9a2RUaLpVxF6SlqicCpC91MAQ==
+Prime1: 466f+JL66Bl4qYnkj0s9+1N3pYmdcM9Ja1AN66X4VLslA9Cm1JEaC5V9HOptfcXUk0XYEVnKeKM2lIQnvcLG0yuQHIa+pGi7P8vgQfdaRUE=
+Prime2: 1yuUkTVRSbUWeUreEcHgeeBBJ61UshX7t07gnGgIr3artGdo2CVEb5//+2Mvj5bgjCQBvjBbmHNZrR0jKDRBTIGtqbBerOuhEN4AXdAEgY8=
+Exponent1: KzUXbJ/P973ltR7S/hKEV66WVRbRhvf/cdsGWULs5n+BXcD59/r1W19qF9OxJZ4mYjBt+ZT1pIEsuXB+7jcJbkelGJTFlwO9DTVOgJZFTkE=
+Exponent2: FTPsLertGbBIiKdB/sn2Dsx0Xy6LXAkihsu1AnSV9oRhIyPVhwcVGVLQ7Lq3YxThB648pbsqK3miapamcj3D+YAF1uTUT4Hgm0LlEll/OC0=
+Coefficient: Vulw9kmmjKc+wmOukLdzheoA2hNPDVtgiynfzHybyXdqvapCoK+ZVmNFzjO0M41ATcpvya3iX0bekMQqYnBhLURNZUIyqz2nGskOjV8I5Jg=
+Created: 20181025104746
+Publish: 20181025104746
+Activate: 20181025104746
diff --git a/bin/tests/optional/Makefile.in b/bin/tests/optional/Makefile.in
new file mode 100644
index 0000000..29e026f
--- /dev/null
+++ b/bin/tests/optional/Makefile.in
@@ -0,0 +1,254 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \
+ ${OPENSSL_CFLAGS} @DST_GSSAPI_INC@
+
+CDEFINES = @USE_GSSAPI@
+
+CWARNINGS =
+BACKTRACECFLAGS = @BACKTRACECFLAGS@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+
+DNSLIBS = ../../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@
+ISCLIBS = ../../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@
+ISCNOSYMLIBS = ../../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@
+ISCCFGLIBS = ../../../lib/isccfg/libisccfg.@A@
+
+DNSDEPLIBS = ../../../lib/dns/libdns.@A@
+ISCDEPLIBS = ../../../lib/isc/libisc.@A@
+ISCDEPNOSYMLIBS = ../../../lib/isc/libisc-nosymtbl.@A@
+ISCCFGDEPLIBS = ../../../lib/isccfg/libisccfg.@A@
+
+LIBS = @LIBS@
+
+SUBDIRS =
+
+# These programs are not built by default, but only when
+# configured with --enable-developer or built explicitly with
+# "make all_tests"
+
+TARGETS = @XTARGETS@
+XTARGETS = adb_test@EXEEXT@ \
+ byaddr_test@EXEEXT@ \
+ backtrace_test@EXEEXT@ \
+ backtrace_test_nosymtbl@EXEEXT@ \
+ byname_test@EXEEXT@ \
+ db_test@EXEEXT@ \
+ gsstest@EXEEXT@ \
+ fsaccess_test@EXEEXT@ \
+ inter_test@EXEEXT@ \
+ lex_test@EXEEXT@ \
+ lfsr_test@EXEEXT@ \
+ log_test@EXEEXT@ \
+ master_test@EXEEXT@ \
+ mempool_test@EXEEXT@ \
+ name_test@EXEEXT@ \
+ nsecify@EXEEXT@ \
+ ratelimiter_test@EXEEXT@ \
+ rbt_test@EXEEXT@ \
+ rwlock_test@EXEEXT@ \
+ serial_test@EXEEXT@ \
+ shutdown_test@EXEEXT@ \
+ sig0_test@EXEEXT@ \
+ sock_test@EXEEXT@ \
+ sym_test@EXEEXT@ \
+ task_test@EXEEXT@ \
+ timer_test@EXEEXT@ \
+ zone_test@EXEEXT@
+
+SRCS = ${XSRCS}
+XSRCS = adb_test.c \
+ byaddr_test.c \
+ backtrace_test.c \
+ byname_test.c \
+ db_test.c \
+ fsaccess_test.c \
+ gsstest.c \
+ inter_test.c \
+ lex_test.c \
+ lfsr_test.c \
+ log_test.c \
+ master_test.c \
+ mempool_test.c \
+ name_test.c \
+ nsecify.c \
+ ratelimiter_test.c \
+ rbt_test.c \
+ rwlock_test.c \
+ serial_test.c \
+ shutdown_test.c \
+ sig0_test.c \
+ sock_test.c \
+ sym_test.c \
+ task_test.c \
+ timer_test.c \
+ zone_test.c
+
+@BIND9_MAKE_RULES@
+
+# disable optimization for backtrace test to get the expected result
+BTTEST_CFLAGS = ${BACKTRACECFLAGS} ${EXT_CFLAGS} ${ALL_CPPFLAGS} -g \
+ ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS} ${PTHREAD_CFLAGS}
+
+all_tests: ${XTARGETS}
+
+adb_test@EXEEXT@: adb_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ adb_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+backtrace_test_nosymtbl@EXEEXT@: ${srcdir}/backtrace_test.c ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} -o $@ \
+ ${srcdir}/backtrace_test.c ${ISCLIBS} ${LIBS}
+
+backtrace_test@EXEEXT@: ${srcdir}/backtrace_test.c backtrace_test_nosymtbl@EXEEXT@
+ #first step: create a first symbol table
+ rm -f symtbl.c
+ if test X${MKSYMTBL_PROGRAM} != X; then \
+ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \
+ backtrace_test_nosymtbl@EXEEXT@; else \
+ cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi
+ #second step: build a binary with the first symbol table
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \
+ -o $@0 ${srcdir}/backtrace_test.c symtbl.c \
+ ${ISCNOSYMLIBS} ${LIBS}
+ rm -f symtbl.c
+ #third step: create a second symbol table
+ if test X${MKSYMTBL_PROGRAM} != X; then \
+ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl $@0; else \
+ cp ${top_srcdir}/lib/isc/backtrace-emptytbl.c symtbl.c; fi
+ #fourth step: build the final binary
+ rm -f $@0
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${BTTEST_CFLAGS} ${LDFLAGS} \
+ -o $@ ${srcdir}/backtrace_test.c symtbl.c ${ISCNOSYMLIBS} ${LIBS}
+ rm -f symtbl.c
+
+nsecify@EXEEXT@: nsecify.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsecify.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+byaddr_test@EXEEXT@: byaddr_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byaddr_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+byname_test@EXEEXT@: byname_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byname_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+lex_test@EXEEXT@: lex_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lex_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+lfsr_test@EXEEXT@: lfsr_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lfsr_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+log_test@EXEEXT@: log_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ log_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+name_test@EXEEXT@: name_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ name_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+entropy_test@EXEEXT@: entropy_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+entropy2_test@EXEEXT@: entropy2_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy2_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+sock_test@EXEEXT@: sock_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sock_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+sym_test@EXEEXT@: sym_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sym_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+task_test@EXEEXT@: task_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ task_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+shutdown_test@EXEEXT@: shutdown_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ shutdown_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+timer_test@EXEEXT@: timer_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ timer_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+ratelimiter_test@EXEEXT@: ratelimiter_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ratelimiter_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+rbt_test@EXEEXT@: rbt_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rbt_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+rwlock_test@EXEEXT@: rwlock_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+master_test@EXEEXT@: master_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ master_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ db_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+mempool_test@EXEEXT@: mempool_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ mempool_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+serial_test@EXEEXT@: serial_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ serial_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+zone_test@EXEEXT@: zone_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+fsaccess_test@EXEEXT@: fsaccess_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ fsaccess_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+inter_test@EXEEXT@: inter_test.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ inter_test.@O@ \
+ ${ISCLIBS} ${LIBS}
+
+sig0_test@EXEEXT@: sig0_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sig0_test.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+gsstest@EXEEXT@: gsstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \
+ -o $@ gsstest.@O@ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
+clean distclean::
+ rm -f ${TARGETS} ${XTARGETS}
+ rm -f backtrace_test_symtbl.c
+
+check: test
+
+test:
+ @for dir in $(TESTDIRS) ;\
+ do \
+ ( cd $$dir; $(MAKE) test ) ;\
+ done
diff --git a/bin/tests/optional/adb_test.c b/bin/tests/optional/adb_test.c
new file mode 100644
index 0000000..7e9e4ca
--- /dev/null
+++ b/bin/tests/optional/adb_test.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/buffer.h>
+#include <isc/hash.h>
+#include <isc/managers.h>
+#include <isc/print.h>
+#include <isc/socket.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/adb.h>
+#include <dns/cache.h>
+#include <dns/db.h>
+#include <dns/dispatch.h>
+#include <dns/log.h>
+#include <dns/result.h>
+#include <dns/rootns.h>
+
+typedef struct client client_t;
+struct client {
+ dns_name_t name;
+ const char *target;
+ ISC_LINK(client_t) link;
+ dns_adbfind_t *find;
+};
+
+static isc_mem_t *mctx = NULL;
+static isc_mempool_t *cmp = NULL;
+static isc_log_t *lctx = NULL;
+static isc_logconfig_t *lcfg = NULL;
+static isc_nm_t *netmgr = NULL;
+static isc_taskmgr_t *taskmgr = NULL;
+static isc_socketmgr_t *socketmgr = NULL;
+static isc_timermgr_t *timermgr = NULL;
+static dns_dispatchmgr_t *dispatchmgr = NULL;
+static isc_task_t *t1 = NULL, *t2 = NULL;
+static dns_view_t *view = NULL;
+static dns_db_t *rootdb = NULL;
+static ISC_LIST(client_t) clients;
+static isc_mutex_t client_lock;
+static isc_stdtime_t now;
+static dns_adb_t *adb = NULL;
+
+static void
+check_result(isc_result_t result, const char *format, ...)
+ ISC_FORMAT_PRINTF(2, 3);
+
+static void
+check_result(isc_result_t result, const char *format, ...) {
+ va_list args;
+
+ if (result == ISC_R_SUCCESS) {
+ return;
+ }
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, ": %s\n", isc_result_totext(result));
+ exit(1);
+}
+
+static client_t *
+new_client(void) {
+ client_t *client;
+
+ client = isc_mempool_get(cmp);
+ INSIST(client != NULL);
+ dns_name_init(&client->name, NULL);
+ ISC_LINK_INIT(client, link);
+ client->find = NULL;
+
+ return (client);
+}
+
+static void
+free_client(client_t **c) {
+ client_t *client;
+
+ INSIST(c != NULL);
+ client = *c;
+ *c = NULL;
+ INSIST(client != NULL);
+ dns_name_free(&client->name, mctx);
+ INSIST(!ISC_LINK_LINKED(client, link));
+ INSIST(client->find == NULL);
+
+ isc_mempool_put(cmp, client);
+}
+
+static void
+CLOCK(void) {
+ RUNTIME_CHECK(isc_mutex_lock(&client_lock) == ISC_R_SUCCESS);
+}
+
+static void
+CUNLOCK(void) {
+ RUNTIME_CHECK(isc_mutex_unlock(&client_lock) == ISC_R_SUCCESS);
+}
+
+static void
+lookup_callback(isc_task_t *task, isc_event_t *ev) {
+ client_t *client;
+
+ client = ev->ev_arg;
+ INSIST(client->find == ev->ev_sender);
+
+ printf("NAME %s:\n\tTask %p got event %p type %08x from %p, client "
+ "%p\n\terr4: %s err6: %s\n",
+ client->target, task, ev, ev->ev_type, client->find, client,
+ isc_result_totext(client->find->result_v4),
+ isc_result_totext(client->find->result_v6));
+
+ isc_event_free(&ev);
+ ev = NULL;
+
+ CLOCK();
+
+ dns_adb_dumpfind(client->find, stderr);
+ dns_adb_destroyfind(&client->find);
+
+ ISC_LIST_UNLINK(clients, client, link);
+ free_client(&client);
+
+ CUNLOCK();
+}
+
+static void
+create_managers(void) {
+ isc_result_t result;
+
+ result = isc_managers_create(mctx, 5, 0, &netmgr, &taskmgr);
+ check_result(result, "isc_managers_create");
+
+ result = isc_timermgr_create(mctx, &timermgr);
+ check_result(result, "isc_timermgr_create");
+
+ result = isc_socketmgr_create(mctx, &socketmgr);
+ check_result(result, "isc_socketmgr_create");
+
+ result = dns_dispatchmgr_create(mctx, &dispatchmgr);
+ check_result(result, "dns_dispatchmgr_create");
+}
+
+static void
+create_view(void) {
+ dns_cache_t *cache = NULL;
+ isc_result_t result;
+
+ /*
+ * View.
+ */
+ result = dns_view_create(mctx, dns_rdataclass_in, "_default", &view);
+ check_result(result, "dns_view_create");
+
+ /*
+ * Cache.
+ */
+ result = dns_cache_create(mctx, mctx, taskmgr, timermgr,
+ dns_rdataclass_in, "", "rbt", 0, NULL,
+ &cache);
+ check_result(result, "dns_cache_create");
+ dns_view_setcache(view, cache, false);
+ dns_cache_detach(&cache);
+
+ {
+ unsigned int attrs;
+ isc_sockaddr_t any4, any6;
+ dns_dispatch_t *disp4 = NULL;
+ dns_dispatch_t *disp6 = NULL;
+
+ isc_sockaddr_any(&any4);
+ isc_sockaddr_any6(&any6);
+
+ attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
+ RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr,
+ taskmgr, &any4, 512, 6, 1024,
+ 17, 19, attrs, attrs,
+ &disp4) == ISC_R_SUCCESS);
+ INSIST(disp4 != NULL);
+
+ attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP;
+ RUNTIME_CHECK(dns_dispatch_getudp(dispatchmgr, socketmgr,
+ taskmgr, &any6, 512, 6, 1024,
+ 17, 19, attrs, attrs,
+ &disp6) == ISC_R_SUCCESS);
+ INSIST(disp6 != NULL);
+
+ RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1,
+ socketmgr, timermgr, 0,
+ dispatchmgr, disp4,
+ disp6) == ISC_R_SUCCESS);
+ }
+
+ rootdb = NULL;
+ result = dns_rootns_create(mctx, dns_rdataclass_in, NULL, &rootdb);
+ check_result(result, "dns_rootns_create()");
+ dns_view_sethints(view, rootdb);
+ dns_db_detach(&rootdb);
+
+ dns_view_freeze(view);
+}
+
+static void
+lookup(const char *target) {
+ dns_name_t name;
+ unsigned char namedata[256];
+ client_t *client;
+ isc_buffer_t t, namebuf;
+ isc_result_t result;
+ unsigned int options;
+
+ INSIST(target != NULL);
+
+ client = new_client();
+ isc_buffer_constinit(&t, target, strlen(target));
+ isc_buffer_add(&t, strlen(target));
+ isc_buffer_init(&namebuf, namedata, sizeof(namedata));
+ dns_name_init(&name, NULL);
+ result = dns_name_fromtext(&name, &t, dns_rootname, 0, &namebuf);
+ check_result(result, "dns_name_fromtext %s", target);
+
+ dns_name_dup(&name, mctx, &client->name);
+
+ options = 0;
+ options |= DNS_ADBFIND_INET;
+ options |= DNS_ADBFIND_INET6;
+ options |= DNS_ADBFIND_WANTEVENT;
+ options |= DNS_ADBFIND_HINTOK;
+ options |= DNS_ADBFIND_GLUEOK;
+ result = dns_adb_createfind(
+ adb, t2, lookup_callback, client, &client->name, dns_rootname,
+ 0, options, now, NULL, view->dstport, 0, NULL, &client->find);
+ if (result != ISC_R_SUCCESS) {
+ printf("DNS_ADB_CREATEFIND -> %s\n", dns_result_totext(result));
+ }
+ dns_adb_dumpfind(client->find, stderr);
+
+ if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
+ client->target = target;
+ ISC_LIST_APPEND(clients, client, link);
+ } else {
+ printf("NAME %s: err4 %s, err6 %s\n", target,
+ isc_result_totext(client->find->result_v4),
+ isc_result_totext(client->find->result_v6));
+
+ dns_adb_destroyfind(&client->find);
+ free_client(&client);
+ }
+}
+
+int
+main(int argc, char **argv) {
+ isc_result_t result;
+ isc_logdestination_t destination;
+
+ UNUSED(argc);
+ UNUSED(argv);
+
+ dns_result_register();
+ result = isc_app_start();
+ check_result(result, "isc_app_start()");
+
+ isc_stdtime_get(&now);
+
+ isc_mutex_init(&client_lock);
+
+ ISC_LIST_INIT(clients);
+
+ /*
+ * EVERYTHING needs a memory context.
+ */
+ isc_mem_create(&mctx);
+
+ cmp = NULL;
+ isc_mempool_create(mctx, sizeof(client_t), &cmp);
+ isc_mempool_setname(cmp, "adb test clients");
+
+ isc_log_create(mctx, &lctx, &lcfg);
+ isc_log_setcontext(lctx);
+ dns_log_init(lctx);
+ dns_log_setcontext(lctx);
+
+ /*
+ * Create and install the default channel.
+ */
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME);
+
+ result = isc_log_usechannel(lcfg, "_default", NULL, NULL);
+ check_result(result, "isc_log_usechannel()");
+
+ /*
+ * Set the initial debug level.
+ */
+ isc_log_setdebuglevel(lctx, 2);
+
+ create_managers();
+
+ result = isc_task_create(taskmgr, 0, &t1);
+ check_result(result, "isc_task_create t1");
+ result = isc_task_create(taskmgr, 0, &t2);
+ check_result(result, "isc_task_create t2");
+
+ printf("task 1 = %p\n", t1);
+ printf("task 2 = %p\n", t2);
+
+ create_view();
+ RUNTIME_CHECK(view != NULL);
+
+ adb = view->adb;
+
+ /*
+ * Lock the entire client list here. This will cause all events
+ * for found names to block as well.
+ */
+ CLOCK();
+ lookup("f.root-servers.net."); /* Should be in hints */
+ lookup("www.iengines.com"); /* should fetch */
+ lookup("www.isc.org"); /* should fetch */
+ lookup("www.flame.org"); /* should fetch */
+ lookup("kechara.flame.org."); /* should fetch */
+ lookup("moghedien.flame.org."); /* should fetch */
+ lookup("mailrelay.flame.org."); /* should fetch */
+ lookup("ipv4v6.flame.org."); /* should fetch */
+ lookup("nonexistent.flame.org."); /* should fail to be found */
+ lookup("foobar.badns.flame.org."); /* should fail utterly (NS) */
+ lookup("i.root-servers.net."); /* Should be in hints */
+ lookup("www.firstcard.com.");
+ lookup("dns04.flame.org.");
+ CUNLOCK();
+
+ sleep(10);
+
+ dns_adb_dump(adb, stderr);
+
+ sleep(10);
+
+ CLOCK();
+ lookup("f.root-servers.net."); /* Should be in hints */
+ lookup("www.iengines.com"); /* should fetch */
+ lookup("www.isc.org"); /* should fetch */
+ lookup("www.flame.org"); /* should fetch */
+ lookup("kechara.flame.org."); /* should fetch */
+ lookup("moghedien.flame.org."); /* should fetch */
+ lookup("mailrelay.flame.org."); /* should fetch */
+ lookup("ipv4v6.flame.org."); /* should fetch */
+ lookup("nonexistent.flame.org."); /* should fail to be found */
+ lookup("foobar.badns.flame.org."); /* should fail utterly (NS) */
+ lookup("i.root-servers.net."); /* Should be in hints */
+ CUNLOCK();
+
+ sleep(20);
+
+ dns_adb_dump(adb, stderr);
+
+ isc_task_detach(&t1);
+ isc_task_detach(&t2);
+
+ isc_mem_stats(mctx, stdout);
+ dns_adb_dump(adb, stderr);
+
+ isc_app_run();
+
+ dns_adb_dump(adb, stderr);
+
+ dns_view_detach(&view);
+ adb = NULL;
+
+ fprintf(stderr, "Destroying socket manager\n");
+ isc_socketmgr_destroy(&socketmgr);
+ fprintf(stderr, "Destroying timer manager\n");
+ isc_timermgr_destroy(&timermgr);
+
+ fprintf(stderr, "Destroying task and network managers\n");
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_log_destroy(&lctx);
+
+ isc_mempool_destroy(&cmp);
+ isc_mem_stats(mctx, stdout);
+ isc_mem_destroy(&mctx);
+
+ isc_app_finish();
+
+ return (0);
+}
diff --git a/bin/tests/optional/backtrace_test.c b/bin/tests/optional/backtrace_test.c
new file mode 100644
index 0000000..2aa7979
--- /dev/null
+++ b/bin/tests/optional/backtrace_test.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/backtrace.h>
+#include <isc/print.h>
+#include <isc/result.h>
+
+const char *expected_symbols[] = { "func3", "func2", "func1", "main" };
+
+static int
+func3() {
+ void *tracebuf[16];
+ int i, nframes;
+ int error = 0;
+ const char *fname;
+ isc_result_t result;
+ unsigned long offset;
+
+ result = isc_backtrace_gettrace(tracebuf, 16, &nframes);
+ if (result != ISC_R_SUCCESS) {
+ printf("isc_backtrace_gettrace failed: %s\n",
+ isc_result_totext(result));
+ return (1);
+ }
+
+ if (nframes < 4) {
+ error++;
+ }
+
+ for (i = 0; i < 4 && i < nframes; i++) {
+ fname = NULL;
+ result = isc_backtrace_getsymbol(tracebuf[i], &fname, &offset);
+ if (result != ISC_R_SUCCESS) {
+ error++;
+ continue;
+ }
+ if (strcmp(fname, expected_symbols[i]) != 0) {
+ error++;
+ }
+ }
+
+ if (error) {
+ printf("Unexpected result:\n");
+ printf(" # of frames: %d (expected: at least 4)\n", nframes);
+ printf(" symbols:\n");
+ for (i = 0; i < nframes; i++) {
+ fname = NULL;
+ result = isc_backtrace_getsymbol(tracebuf[i], &fname,
+ &offset);
+ if (result == ISC_R_SUCCESS) {
+ printf(" [%d] %s\n", i, fname);
+ } else {
+ printf(" [%d] %p getsymbol failed: %s\n", i,
+ tracebuf[i], isc_result_totext(result));
+ }
+ }
+ }
+
+ return (error);
+}
+
+static int
+func2() {
+ return (func3());
+}
+
+static int
+func1() {
+ return (func2());
+}
+
+int
+main() {
+ return (func1());
+}
diff --git a/bin/tests/optional/byaddr_test.c b/bin/tests/optional/byaddr_test.c
new file mode 100644
index 0000000..7e24cfe
--- /dev/null
+++ b/bin/tests/optional/byaddr_test.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/app.h>
+#include <isc/commandline.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/byaddr.h>
+#include <dns/cache.h>
+#include <dns/dispatch.h>
+#include <dns/events.h>
+#include <dns/forward.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/view.h>
+
+static void
+done(isc_task_t *task, isc_event_t *event) {
+ dns_byaddrevent_t *bevent;
+ dns_byaddr_t *byaddr;
+ dns_name_t *name;
+
+ REQUIRE(event->ev_type == DNS_EVENT_BYADDRDONE);
+ bevent = (dns_byaddrevent_t *)event;
+
+ UNUSED(task);
+
+ printf("byaddr event result = %s\n", isc_result_totext(bevent->result));
+
+ if (bevent->result == ISC_R_SUCCESS) {
+ for (name = ISC_LIST_HEAD(bevent->names); name != NULL;
+ name = ISC_LIST_NEXT(name, link))
+ {
+ char text[DNS_NAME_FORMATSIZE];
+ dns_name_format(name, text, sizeof(text));
+ printf("%s\n", text);
+ }
+ }
+
+ byaddr = event->ev_sender;
+ dns_byaddr_destroy(&byaddr);
+ isc_event_free(&event);
+
+ isc_app_shutdown();
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_mem_t *mctx = NULL;
+ bool verbose = false;
+ unsigned int workers = 2;
+ isc_nm_t *netmgr = NULL;
+ isc_taskmgr_t *taskmgr = NULL;
+ isc_task_t *task = NULL;
+ isc_timermgr_t *timermgr = NULL;
+ dns_view_t *view = NULL;
+ int ch;
+ isc_socketmgr_t *socketmgr = NULL;
+ dns_dispatchmgr_t *dispatchmgr = NULL;
+ isc_netaddr_t na;
+ dns_byaddr_t *byaddr = NULL;
+ isc_result_t result;
+ unsigned int options = 0;
+ dns_cache_t *cache;
+
+ RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
+
+ dns_result_register();
+
+ isc_mem_create(&mctx);
+
+ while ((ch = isc_commandline_parse(argc, argv, "nvw:")) != -1) {
+ switch (ch) {
+ case 'n':
+ /*
+ * We only try nibbles, so do nothing for this option.
+ */
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'w':
+ workers = (unsigned int)atoi(isc_commandline_argument);
+ break;
+ }
+ }
+
+ if (verbose) {
+ printf("%u workers\n", workers);
+ printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4()));
+ printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6()));
+ }
+
+ RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr,
+ &taskmgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS);
+ isc_task_setname(task, "byaddr", NULL);
+
+ RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) ==
+ ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr,
+ dns_rdataclass_in, "", "rbt", 0, NULL,
+ &cache) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default",
+ &view) == ISC_R_SUCCESS);
+
+ {
+ unsigned int attrs;
+ dns_dispatch_t *disp4 = NULL;
+ dns_dispatch_t *disp6 = NULL;
+
+ if (isc_net_probeipv4() == ISC_R_SUCCESS) {
+ isc_sockaddr_t any4;
+
+ isc_sockaddr_any(&any4);
+
+ attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
+ RUNTIME_CHECK(
+ dns_dispatch_getudp(dispatchmgr, socketmgr,
+ taskmgr, &any4, 512, 6,
+ 1024, 17, 19, attrs, attrs,
+ &disp4) == ISC_R_SUCCESS);
+ INSIST(disp4 != NULL);
+ }
+
+ if (isc_net_probeipv6() == ISC_R_SUCCESS) {
+ isc_sockaddr_t any6;
+
+ isc_sockaddr_any6(&any6);
+
+ attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP;
+ RUNTIME_CHECK(
+ dns_dispatch_getudp(dispatchmgr, socketmgr,
+ taskmgr, &any6, 512, 6,
+ 1024, 17, 19, attrs, attrs,
+ &disp6) == ISC_R_SUCCESS);
+ INSIST(disp6 != NULL);
+ }
+
+ RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1,
+ socketmgr, timermgr, 0,
+ dispatchmgr, disp4,
+ disp6) == ISC_R_SUCCESS);
+
+ if (disp4 != NULL) {
+ dns_dispatch_detach(&disp4);
+ }
+ if (disp6 != NULL) {
+ dns_dispatch_detach(&disp6);
+ }
+ }
+
+ {
+ struct in_addr ina;
+ isc_sockaddr_t sa;
+ isc_sockaddrlist_t sal;
+
+ ISC_LIST_INIT(sal);
+ ina.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&sa, &ina, 53);
+ ISC_LIST_APPEND(sal, &sa, link);
+
+ RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname,
+ &sal, dns_fwdpolicy_only) ==
+ ISC_R_SUCCESS);
+ }
+
+ dns_view_setcache(view, cache, false);
+ dns_view_freeze(view);
+
+ dns_cache_detach(&cache);
+
+ printf("address = %s\n", argv[isc_commandline_index]);
+ na.family = AF_INET;
+ if (inet_pton(AF_INET, argv[isc_commandline_index],
+ (char *)&na.type.in) != 1)
+ {
+ na.family = AF_INET6;
+ if (inet_pton(AF_INET6, argv[isc_commandline_index],
+ (char *)&na.type.in6) != 1)
+ {
+ printf("unknown address format\n");
+ exit(1);
+ }
+ }
+
+ result = dns_byaddr_create(mctx, &na, view, options, task, done, NULL,
+ &byaddr);
+ if (result != ISC_R_SUCCESS) {
+ printf("dns_byaddr_create() returned %s\n",
+ isc_result_totext(result));
+ RUNTIME_CHECK(0);
+ }
+
+ (void)isc_app_run();
+
+ /*
+ * XXXRTH if we get a control-C before we get to isc_app_run(),
+ * we're in trouble (because we might try to destroy things before
+ * they've been created.
+ */
+
+ dns_view_detach(&view);
+
+ isc_task_shutdown(task);
+ isc_task_detach(&task);
+
+ dns_dispatchmgr_destroy(&dispatchmgr);
+
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_socketmgr_destroy(&socketmgr);
+ isc_timermgr_destroy(&timermgr);
+
+ if (verbose) {
+ isc_mem_stats(mctx, stdout);
+ }
+ isc_mem_destroy(&mctx);
+
+ isc_app_finish();
+
+ return (0);
+}
diff --git a/bin/tests/optional/byname_test.c b/bin/tests/optional/byname_test.c
new file mode 100644
index 0000000..fa76973
--- /dev/null
+++ b/bin/tests/optional/byname_test.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/app.h>
+#include <isc/commandline.h>
+#include <isc/hash.h>
+#include <isc/managers.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/adb.h>
+#include <dns/cache.h>
+#include <dns/dispatch.h>
+#include <dns/events.h>
+#include <dns/forward.h>
+#include <dns/log.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+
+static isc_mem_t *mctx = NULL;
+static isc_nm_t *netmgr = NULL;
+static isc_taskmgr_t *taskmgr = NULL;
+static dns_view_t *view = NULL;
+static dns_adbfind_t *find = NULL;
+static isc_task_t *task = NULL;
+static dns_fixedname_t fixed;
+static dns_fixedname_t target;
+static isc_log_t *lctx = NULL;
+static isc_logconfig_t *lcfg = NULL;
+static unsigned int level = 0;
+
+static void
+adb_callback(isc_task_t *task, isc_event_t *event);
+
+static void
+log_init(void) {
+ isc_logdestination_t destination;
+ unsigned int flags;
+
+ /*
+ * Setup a logging context.
+ */
+ isc_log_create(mctx, &lctx, &lcfg);
+ isc_log_setcontext(lctx);
+ dns_log_init(lctx);
+ dns_log_setcontext(lctx);
+
+ /*
+ * Create and install the default channel.
+ */
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ flags = ISC_LOG_PRINTTIME;
+ isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC, &destination, flags);
+
+ RUNTIME_CHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL) ==
+ ISC_R_SUCCESS);
+ isc_log_setdebuglevel(lctx, level);
+}
+
+static void
+print_addresses(dns_adbfind_t *adbfind) {
+ dns_adbaddrinfo_t *address;
+
+ for (address = ISC_LIST_HEAD(adbfind->list); address != NULL;
+ address = ISC_LIST_NEXT(address, publink))
+ {
+ isc_netaddr_t netaddr;
+ char text[ISC_NETADDR_FORMATSIZE];
+ isc_netaddr_fromsockaddr(&netaddr, &address->sockaddr);
+ isc_netaddr_format(&netaddr, text, sizeof(text));
+ printf("%s\n", text);
+ }
+}
+
+static void
+print_name(dns_name_t *name) {
+ char text[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(name, text, sizeof(text));
+ printf("%s\n", text);
+}
+
+static void
+do_find(bool want_event) {
+ isc_result_t result;
+ bool done = false;
+ unsigned int options;
+
+ options = DNS_ADBFIND_INET | DNS_ADBFIND_INET6;
+ if (want_event) {
+ options |= DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
+ }
+ dns_fixedname_init(&target);
+ result = dns_adb_createfind(view->adb, task, adb_callback, NULL,
+ dns_fixedname_name(&fixed), dns_rootname, 0,
+ options, 0, dns_fixedname_name(&target), 0,
+ 0, NULL, &find);
+ if (result == ISC_R_SUCCESS) {
+ if (!ISC_LIST_EMPTY(find->list)) {
+ /*
+ * We have at least some of the addresses for the
+ * name.
+ */
+ INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
+ print_addresses(find);
+ done = true;
+ } else {
+ /*
+ * We don't know any of the addresses for this
+ * name.
+ */
+ if ((find->options & DNS_ADBFIND_WANTEVENT) == 0) {
+ /*
+ * And ADB isn't going to send us any events
+ * either. This query loses.
+ */
+ done = true;
+ }
+ /*
+ * If the DNS_ADBFIND_WANTEVENT flag was set, we'll
+ * get an event when something happens.
+ */
+ }
+ } else if (result == DNS_R_ALIAS) {
+ print_name(dns_fixedname_name(&target));
+ done = true;
+ } else {
+ printf("dns_adb_createfind() returned %s\n",
+ isc_result_totext(result));
+ done = true;
+ }
+
+ if (done) {
+ if (find != NULL) {
+ dns_adb_destroyfind(&find);
+ }
+ isc_app_shutdown();
+ }
+}
+
+static void
+adb_callback(isc_task_t *etask, isc_event_t *event) {
+ unsigned int type = event->ev_type;
+
+ REQUIRE(etask == task);
+
+ isc_event_free(&event);
+ dns_adb_destroyfind(&find);
+
+ if (type == DNS_EVENT_ADBMOREADDRESSES) {
+ do_find(false);
+ } else if (type == DNS_EVENT_ADBNOMOREADDRESSES) {
+ printf("no more addresses\n");
+ isc_app_shutdown();
+ } else {
+ printf("unexpected ADB event type %u\n", type);
+ isc_app_shutdown();
+ }
+}
+
+static void
+run(isc_task_t *xtask, isc_event_t *event) {
+ UNUSED(xtask);
+ do_find(true);
+ isc_event_free(&event);
+}
+
+int
+main(int argc, char *argv[]) {
+ bool verbose = false;
+ unsigned int workers = 2;
+ isc_timermgr_t *timermgr = NULL;
+ int ch;
+ isc_socketmgr_t *socketmgr = NULL;
+ dns_dispatchmgr_t *dispatchmgr = NULL;
+ dns_cache_t *cache = NULL;
+ isc_buffer_t b;
+
+ RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
+
+ dns_result_register();
+
+ isc_mem_create(&mctx);
+
+ while ((ch = isc_commandline_parse(argc, argv, "d:vw:")) != -1) {
+ switch (ch) {
+ case 'd':
+ level = (unsigned int)atoi(isc_commandline_argument);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'w':
+ workers = (unsigned int)atoi(isc_commandline_argument);
+ break;
+ }
+ }
+
+ log_init();
+
+ if (verbose) {
+ printf("%u workers\n", workers);
+ printf("IPv4: %s\n", isc_result_totext(isc_net_probeipv4()));
+ printf("IPv6: %s\n", isc_result_totext(isc_net_probeipv6()));
+ }
+
+ RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr,
+ &taskmgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS);
+ isc_task_setname(task, "byname", NULL);
+
+ RUNTIME_CHECK(dns_dispatchmgr_create(mctx, &dispatchmgr) ==
+ ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(dns_cache_create(mctx, mctx, taskmgr, timermgr,
+ dns_rdataclass_in, "", "rbt", 0, NULL,
+ &cache) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(dns_view_create(mctx, dns_rdataclass_in, "default",
+ &view) == ISC_R_SUCCESS);
+
+ {
+ unsigned int attrs;
+ dns_dispatch_t *disp4 = NULL;
+ dns_dispatch_t *disp6 = NULL;
+
+ if (isc_net_probeipv4() == ISC_R_SUCCESS) {
+ isc_sockaddr_t any4;
+ isc_sockaddr_any(&any4);
+
+ attrs = DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_UDP;
+ RUNTIME_CHECK(
+ dns_dispatch_getudp(dispatchmgr, socketmgr,
+ taskmgr, &any4, 512, 6,
+ 1024, 17, 19, attrs, attrs,
+ &disp4) == ISC_R_SUCCESS);
+ INSIST(disp4 != NULL);
+ }
+
+ if (isc_net_probeipv6() == ISC_R_SUCCESS) {
+ isc_sockaddr_t any6;
+
+ isc_sockaddr_any6(&any6);
+
+ attrs = DNS_DISPATCHATTR_IPV6 | DNS_DISPATCHATTR_UDP;
+ RUNTIME_CHECK(
+ dns_dispatch_getudp(dispatchmgr, socketmgr,
+ taskmgr, &any6, 512, 6,
+ 1024, 17, 19, attrs, attrs,
+ &disp6) == ISC_R_SUCCESS);
+ INSIST(disp6 != NULL);
+ }
+
+ RUNTIME_CHECK(dns_view_createresolver(view, taskmgr, 10, 1,
+ socketmgr, timermgr, 0,
+ dispatchmgr, disp4,
+ disp6) == ISC_R_SUCCESS);
+
+ if (disp4 != NULL) {
+ dns_dispatch_detach(&disp4);
+ }
+ if (disp6 != NULL) {
+ dns_dispatch_detach(&disp6);
+ }
+ }
+
+ {
+ struct in_addr ina;
+ isc_sockaddr_t sa;
+ isc_sockaddrlist_t sal;
+
+ ISC_LIST_INIT(sal);
+ ina.s_addr = inet_addr("127.0.0.1");
+ isc_sockaddr_fromin(&sa, &ina, 53);
+ ISC_LIST_APPEND(sal, &sa, link);
+
+ REQUIRE(DNS_VIEW_VALID(view));
+ RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname,
+ &sal, dns_fwdpolicy_only) ==
+ ISC_R_SUCCESS);
+ }
+
+ dns_view_setcache(view, cache, false);
+ dns_view_freeze(view);
+
+ dns_cache_detach(&cache);
+
+ printf("name = %s\n", argv[isc_commandline_index]);
+ isc_buffer_init(&b, argv[isc_commandline_index],
+ strlen(argv[isc_commandline_index]));
+ isc_buffer_add(&b, strlen(argv[isc_commandline_index]));
+ dns_fixedname_init(&fixed);
+ dns_fixedname_init(&target);
+ RUNTIME_CHECK(dns_name_fromtext(dns_fixedname_name(&fixed), &b,
+ dns_rootname, 0,
+ NULL) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_app_onrun(mctx, task, run, NULL) == ISC_R_SUCCESS);
+
+ (void)isc_app_run();
+
+ dns_view_detach(&view);
+ isc_task_shutdown(task);
+ isc_task_detach(&task);
+
+ dns_dispatchmgr_destroy(&dispatchmgr);
+
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_socketmgr_destroy(&socketmgr);
+ isc_timermgr_destroy(&timermgr);
+
+ isc_log_destroy(&lctx);
+
+ if (verbose) {
+ isc_mem_stats(mctx, stdout);
+ }
+ isc_mem_destroy(&mctx);
+
+ isc_app_finish();
+
+ return (0);
+}
diff --git a/bin/tests/optional/db_test.c b/bin/tests/optional/db_test.c
new file mode 100644
index 0000000..05bd748
--- /dev/null
+++ b/bin/tests/optional/db_test.c
@@ -0,0 +1,983 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/commandline.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/dbtable.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/result.h>
+
+#define MAXHOLD 100
+#define MAXVERSIONS 100
+
+typedef struct dbinfo {
+ dns_db_t *db;
+ dns_dbversion_t *version;
+ dns_dbversion_t *wversion;
+ dns_dbversion_t *rversions[MAXVERSIONS];
+ int rcount;
+ dns_dbnode_t *hold_nodes[MAXHOLD];
+ int hold_count;
+ dns_dbiterator_t *dbiterator;
+ dns_dbversion_t *iversion;
+ int pause_every;
+ bool ascending;
+ ISC_LINK(struct dbinfo) link;
+} dbinfo;
+
+static isc_mem_t *mctx = NULL;
+static char dbtype[128];
+static dns_dbtable_t *dbtable;
+static ISC_LIST(dbinfo) dbs;
+static dbinfo *cache_dbi = NULL;
+static int pause_every = 0;
+static bool ascending = true;
+
+static void
+print_result(const char *message, isc_result_t result) {
+ if (message == NULL) {
+ message = "";
+ }
+ printf("%s%sresult %08x: %s\n", message, (*message == '\0') ? "" : " ",
+ result, isc_result_totext(result));
+}
+
+static void
+print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) {
+ isc_buffer_t text;
+ char t[1000];
+ isc_result_t result;
+ isc_region_t r;
+
+ isc_buffer_init(&text, t, sizeof(t));
+ result = dns_rdataset_totext(rdataset, name, false, false, &text);
+ isc_buffer_usedregion(&text, &r);
+ if (result == ISC_R_SUCCESS) {
+ printf("%.*s", (int)r.length, (char *)r.base);
+ } else {
+ print_result("", result);
+ }
+}
+
+static void
+print_rdatasets(dns_name_t *name, dns_rdatasetiter_t *rdsiter) {
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatasetiter_first(rdsiter);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ print_rdataset(name, &rdataset);
+ dns_rdataset_disassociate(&rdataset);
+ result = dns_rdatasetiter_next(rdsiter);
+ }
+ if (result != ISC_R_NOMORE) {
+ print_result("", result);
+ }
+}
+
+static dbinfo *
+select_db(char *origintext) {
+ dns_fixedname_t forigin;
+ dns_name_t *origin;
+ isc_buffer_t source;
+ size_t len;
+ dbinfo *dbi;
+ isc_result_t result;
+
+ if (strcasecmp(origintext, "cache") == 0) {
+ if (cache_dbi == NULL) {
+ printf("the cache does not exist\n");
+ }
+ return (cache_dbi);
+ }
+ len = strlen(origintext);
+ isc_buffer_init(&source, origintext, len);
+ isc_buffer_add(&source, len);
+ origin = dns_fixedname_initname(&forigin);
+ result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ print_result("bad name", result);
+ return (NULL);
+ }
+
+ for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL;
+ dbi = ISC_LIST_NEXT(dbi, link))
+ {
+ if (dns_name_compare(dns_db_origin(dbi->db), origin) == 0) {
+ break;
+ }
+ }
+
+ return (dbi);
+}
+
+static void
+list(dbinfo *dbi, char *seektext) {
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ dns_dbnode_t *node;
+ dns_rdatasetiter_t *rdsiter;
+ isc_result_t result;
+ int i;
+ size_t len;
+ dns_fixedname_t fseekname;
+ dns_name_t *seekname;
+ isc_buffer_t source;
+
+ name = dns_fixedname_initname(&fname);
+
+ if (dbi->dbiterator == NULL) {
+ INSIST(dbi->iversion == NULL);
+ if (dns_db_iszone(dbi->db)) {
+ if (dbi->version != NULL) {
+ dns_db_attachversion(dbi->db, dbi->version,
+ &dbi->iversion);
+ } else {
+ dns_db_currentversion(dbi->db, &dbi->iversion);
+ }
+ }
+
+ result = dns_db_createiterator(dbi->db, 0, &dbi->dbiterator);
+ if (result == ISC_R_SUCCESS) {
+ if (seektext != NULL) {
+ len = strlen(seektext);
+ isc_buffer_init(&source, seektext, len);
+ isc_buffer_add(&source, len);
+ seekname = dns_fixedname_initname(&fseekname);
+ result = dns_name_fromtext(
+ seekname, &source,
+ dns_db_origin(dbi->db), 0, NULL);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_seek(
+ dbi->dbiterator, seekname);
+ }
+ } else if (dbi->ascending) {
+ result = dns_dbiterator_first(dbi->dbiterator);
+ } else {
+ result = dns_dbiterator_last(dbi->dbiterator);
+ }
+ }
+ } else {
+ result = ISC_R_SUCCESS;
+ }
+
+ node = NULL;
+ rdsiter = NULL;
+ i = 0;
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(dbi->dbiterator, &node, name);
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ break;
+ }
+ result = dns_db_allrdatasets(dbi->db, node, dbi->iversion, 0, 0,
+ &rdsiter);
+ if (result != ISC_R_SUCCESS) {
+ dns_db_detachnode(dbi->db, &node);
+ break;
+ }
+ print_rdatasets(name, rdsiter);
+ dns_rdatasetiter_destroy(&rdsiter);
+ dns_db_detachnode(dbi->db, &node);
+ if (dbi->ascending) {
+ result = dns_dbiterator_next(dbi->dbiterator);
+ } else {
+ result = dns_dbiterator_prev(dbi->dbiterator);
+ }
+ i++;
+ if (result == ISC_R_SUCCESS && i == dbi->pause_every) {
+ printf("[more...]\n");
+ result = dns_dbiterator_pause(dbi->dbiterator);
+ if (result == ISC_R_SUCCESS) {
+ return;
+ }
+ }
+ }
+ if (result != ISC_R_NOMORE) {
+ print_result("", result);
+ }
+
+ dns_dbiterator_destroy(&dbi->dbiterator);
+ if (dbi->iversion != NULL) {
+ dns_db_closeversion(dbi->db, &dbi->iversion, false);
+ }
+}
+
+static isc_result_t
+load(const char *filename, const char *origintext, bool cache) {
+ dns_fixedname_t forigin;
+ dns_name_t *origin;
+ isc_result_t result;
+ isc_buffer_t source;
+ size_t len;
+ dbinfo *dbi;
+ unsigned int i;
+
+ dbi = isc_mem_get(mctx, sizeof(*dbi));
+
+ dbi->db = NULL;
+ dbi->version = NULL;
+ dbi->wversion = NULL;
+ for (i = 0; i < MAXVERSIONS; i++) {
+ dbi->rversions[i] = NULL;
+ }
+ dbi->hold_count = 0;
+ for (i = 0; i < MAXHOLD; i++) {
+ dbi->hold_nodes[i] = NULL;
+ }
+ dbi->dbiterator = NULL;
+ dbi->iversion = NULL;
+ dbi->pause_every = pause_every;
+ dbi->ascending = ascending;
+ ISC_LINK_INIT(dbi, link);
+
+ len = strlen(origintext);
+ isc_buffer_constinit(&source, origintext, len);
+ isc_buffer_add(&source, len);
+ origin = dns_fixedname_initname(&forigin);
+ result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, dbi, sizeof(*dbi));
+ return (result);
+ }
+
+ result = dns_db_create(mctx, dbtype, origin,
+ cache ? dns_dbtype_cache : dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &dbi->db);
+ if (result != ISC_R_SUCCESS) {
+ isc_mem_put(mctx, dbi, sizeof(*dbi));
+ return (result);
+ }
+
+ printf("loading %s (%s)\n", filename, origintext);
+ result = dns_db_load(dbi->db, filename, dns_masterformat_text, 0);
+ if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
+ dns_db_detach(&dbi->db);
+ isc_mem_put(mctx, dbi, sizeof(*dbi));
+ return (result);
+ }
+ printf("loaded\n");
+
+ if (cache) {
+ INSIST(cache_dbi == NULL);
+ dns_dbtable_adddefault(dbtable, dbi->db);
+ cache_dbi = dbi;
+ } else {
+ result = dns_dbtable_add(dbtable, dbi->db);
+ if (result != ISC_R_SUCCESS) {
+ dns_db_detach(&dbi->db);
+ isc_mem_put(mctx, dbi, sizeof(*dbi));
+ return (result);
+ }
+ }
+ ISC_LIST_APPEND(dbs, dbi, link);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+unload_all(void) {
+ dbinfo *dbi, *dbi_next;
+
+ for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL; dbi = dbi_next) {
+ dbi_next = ISC_LIST_NEXT(dbi, link);
+ if (dns_db_iszone(dbi->db)) {
+ dns_dbtable_remove(dbtable, dbi->db);
+ } else {
+ INSIST(dbi == cache_dbi);
+ dns_dbtable_removedefault(dbtable);
+ cache_dbi = NULL;
+ }
+ dns_db_detach(&dbi->db);
+ ISC_LIST_UNLINK(dbs, dbi, link);
+ isc_mem_put(mctx, dbi, sizeof(*dbi));
+ }
+}
+
+#define DBI_CHECK(dbi) \
+ if ((dbi) == NULL) { \
+ printf("You must first select a database with !DB\n"); \
+ continue; \
+ }
+
+int
+main(int argc, char *argv[]) {
+ dns_db_t *db;
+ dns_dbnode_t *node;
+ isc_result_t result;
+ dns_name_t name;
+ dns_offsets_t offsets;
+ size_t len;
+ isc_buffer_t source, target;
+ char s[1000];
+ char b[255];
+ dns_rdataset_t rdataset, sigrdataset;
+ int ch;
+ dns_rdatatype_t type = 1;
+ bool printnode = false;
+ bool addmode = false;
+ bool delmode = false;
+ bool holdmode = false;
+ bool verbose = false;
+ bool done = false;
+ bool quiet = false;
+ bool time_lookups = false;
+ bool found_as;
+ bool find_zonecut = false;
+ bool noexact_zonecut = false;
+ int i, v;
+ dns_rdatasetiter_t *rdsiter;
+ char t1[256];
+ char t2[256];
+ isc_buffer_t tb1, tb2;
+ isc_region_t r1, r2;
+ dns_fixedname_t foundname;
+ dns_name_t *fname;
+ unsigned int options = 0, zcoptions;
+ isc_time_t start, finish;
+ const char *origintext;
+ dbinfo *dbi;
+ dns_dbversion_t *version;
+ const dns_name_t *origin;
+ dns_trust_t trust = 0;
+ unsigned int addopts;
+ isc_log_t *lctx = NULL;
+ size_t n;
+
+ dns_result_register();
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(dns_dbtable_create(mctx, dns_rdataclass_in, &dbtable) ==
+ ISC_R_SUCCESS);
+
+ snprintf(dbtype, sizeof(dbtype), "rbt");
+ while ((ch = isc_commandline_parse(argc, argv, "c:d:t:z:P:Q:glpqvT")) !=
+ -1)
+ {
+ switch (ch) {
+ case 'c':
+ result = load(isc_commandline_argument, ".", true);
+ if (result != ISC_R_SUCCESS) {
+ printf("cache load(%s) %08x: %s\n",
+ isc_commandline_argument, result,
+ isc_result_totext(result));
+ }
+ break;
+ case 'd':
+ n = strlcpy(dbtype, isc_commandline_argument,
+ sizeof(dbtype));
+ if (n >= sizeof(dbtype)) {
+ fprintf(stderr, "bad db type '%s'\n",
+ isc_commandline_argument);
+ exit(1);
+ }
+ break;
+ case 'g':
+ options |= (DNS_DBFIND_GLUEOK |
+ DNS_DBFIND_VALIDATEGLUE);
+ break;
+ case 'l':
+ isc_log_create(mctx, &lctx, NULL);
+ isc_log_setcontext(lctx);
+ dns_log_init(lctx);
+ dns_log_setcontext(lctx);
+ break;
+ case 'q':
+ quiet = true;
+ verbose = false;
+ break;
+ case 'p':
+ printnode = true;
+ break;
+ case 'P':
+ pause_every = atoi(isc_commandline_argument);
+ break;
+ case 't':
+ type = atoi(isc_commandline_argument);
+ break;
+ case 'T':
+ time_lookups = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'z':
+ origintext = strrchr(isc_commandline_argument, '/');
+ if (origintext == NULL) {
+ origintext = isc_commandline_argument;
+ } else {
+ origintext++; /* Skip '/'. */
+ }
+ result = load(isc_commandline_argument, origintext,
+ false);
+ if (result != ISC_R_SUCCESS) {
+ printf("zone load(%s) %08x: %s\n",
+ isc_commandline_argument, result,
+ isc_result_totext(result));
+ }
+ break;
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+ POST(argv);
+
+ if (argc != 0) {
+ printf("ignoring trailing arguments\n");
+ }
+
+ /*
+ * Some final initialization...
+ */
+ fname = dns_fixedname_initname(&foundname);
+ dbi = NULL;
+ origin = dns_rootname;
+ version = NULL;
+
+ if (time_lookups) {
+ TIME_NOW(&start);
+ }
+
+ while (!done) {
+ if (!quiet) {
+ printf("\n");
+ }
+ if (fgets(s, sizeof(s), stdin) == NULL) {
+ done = true;
+ continue;
+ }
+ len = strlen(s);
+ if (len > 0U && s[len - 1] == '\n') {
+ s[len - 1] = '\0';
+ len--;
+ }
+ if (verbose && dbi != NULL) {
+ if (dbi->wversion != NULL) {
+ printf("future version (%p)\n", dbi->wversion);
+ }
+ for (i = 0; i < dbi->rcount; i++) {
+ if (dbi->rversions[i] != NULL) {
+ printf("open version %d (%p)\n", i,
+ dbi->rversions[i]);
+ }
+ }
+ }
+ dns_name_init(&name, offsets);
+ if (strcmp(s, "!R") == 0) {
+ DBI_CHECK(dbi);
+ if (dbi->rcount == MAXVERSIONS) {
+ printf("too many open versions\n");
+ continue;
+ }
+ dns_db_currentversion(dbi->db,
+ &dbi->rversions[dbi->rcount]);
+ printf("opened version %d\n", dbi->rcount);
+ dbi->version = dbi->rversions[dbi->rcount];
+ version = dbi->version;
+ dbi->rcount++;
+ continue;
+ } else if (strcmp(s, "!W") == 0) {
+ DBI_CHECK(dbi);
+ if (dbi->wversion != NULL) {
+ printf("using existing future version\n");
+ dbi->version = dbi->wversion;
+ version = dbi->version;
+ continue;
+ }
+ result = dns_db_newversion(dbi->db, &dbi->wversion);
+ if (result != ISC_R_SUCCESS) {
+ print_result("", result);
+ } else {
+ printf("newversion\n");
+ }
+ dbi->version = dbi->wversion;
+ version = dbi->version;
+ continue;
+ } else if (strcmp(s, "!C") == 0) {
+ DBI_CHECK(dbi);
+ addmode = false;
+ delmode = false;
+ if (dbi->version == NULL) {
+ continue;
+ }
+ if (dbi->version == dbi->wversion) {
+ printf("closing future version\n");
+ dbi->wversion = NULL;
+ } else {
+ for (i = 0; i < dbi->rcount; i++) {
+ if (dbi->version == dbi->rversions[i]) {
+ dbi->rversions[i] = NULL;
+ printf("closing open version "
+ "%d\n",
+ i);
+ break;
+ }
+ }
+ }
+ dns_db_closeversion(dbi->db, &dbi->version, true);
+ version = NULL;
+ continue;
+ } else if (strcmp(s, "!X") == 0) {
+ DBI_CHECK(dbi);
+ addmode = false;
+ delmode = false;
+ if (dbi->version == NULL) {
+ continue;
+ }
+ if (dbi->version == dbi->wversion) {
+ printf("aborting future version\n");
+ dbi->wversion = NULL;
+ } else {
+ for (i = 0; i < dbi->rcount; i++) {
+ if (dbi->version == dbi->rversions[i]) {
+ dbi->rversions[i] = NULL;
+ printf("closing open version "
+ "%d\n",
+ i);
+ break;
+ }
+ }
+ }
+ dns_db_closeversion(dbi->db, &dbi->version, false);
+ version = NULL;
+ continue;
+ } else if (strcmp(s, "!A") == 0) {
+ DBI_CHECK(dbi);
+ delmode = false;
+ if (addmode) {
+ addmode = false;
+ } else {
+ addmode = true;
+ }
+ printf("addmode = %s\n", addmode ? "TRUE" : "FALSE");
+ continue;
+ } else if (strcmp(s, "!D") == 0) {
+ DBI_CHECK(dbi);
+ addmode = false;
+ if (delmode) {
+ delmode = false;
+ } else {
+ delmode = true;
+ }
+ printf("delmode = %s\n", delmode ? "TRUE" : "FALSE");
+ continue;
+ } else if (strcmp(s, "!H") == 0) {
+ DBI_CHECK(dbi);
+ if (holdmode) {
+ holdmode = false;
+ } else {
+ holdmode = true;
+ }
+ printf("holdmode = %s\n", holdmode ? "TRUE" : "FALSE");
+ continue;
+ } else if (strcmp(s, "!HR") == 0) {
+ DBI_CHECK(dbi);
+ for (i = 0; i < dbi->hold_count; i++) {
+ dns_db_detachnode(dbi->db, &dbi->hold_nodes[i]);
+ }
+ dbi->hold_count = 0;
+ holdmode = false;
+ printf("held nodes have been detached\n");
+ continue;
+ } else if (strcmp(s, "!VC") == 0) {
+ DBI_CHECK(dbi);
+ printf("switching to current version\n");
+ dbi->version = NULL;
+ version = NULL;
+ continue;
+ } else if (strstr(s, "!V") == s) {
+ DBI_CHECK(dbi);
+ v = atoi(&s[2]);
+ if (v >= dbi->rcount || v < 0) {
+ printf("unknown open version %d\n", v);
+ continue;
+ }
+ if (dbi->rversions[v] == NULL) {
+ printf("version %d is not open\n", v);
+ continue;
+ }
+ printf("switching to open version %d\n", v);
+ dbi->version = dbi->rversions[v];
+ version = dbi->version;
+ continue;
+ } else if (strstr(s, "!TR") == s) {
+ trust = (unsigned int)atoi(&s[3]);
+ printf("trust level is now %u\n", (unsigned int)trust);
+ continue;
+ } else if (strstr(s, "!T") == s) {
+ type = (unsigned int)atoi(&s[2]);
+ printf("now searching for type %u\n", type);
+ continue;
+ } else if (strcmp(s, "!G") == 0) {
+ if ((options & DNS_DBFIND_GLUEOK) != 0) {
+ options &= ~DNS_DBFIND_GLUEOK;
+ } else {
+ options |= DNS_DBFIND_GLUEOK;
+ }
+ printf("glue ok = %s\n",
+ ((options & DNS_DBFIND_GLUEOK) != 0) ? "TRUE"
+ : "FALSE");
+ continue;
+ } else if (strcmp(s, "!GV") == 0) {
+ if ((options & DNS_DBFIND_VALIDATEGLUE) != 0) {
+ options &= ~DNS_DBFIND_VALIDATEGLUE;
+ } else {
+ options |= DNS_DBFIND_VALIDATEGLUE;
+ }
+ printf("validate glue = %s\n",
+ ((options & DNS_DBFIND_VALIDATEGLUE) != 0)
+ ? "TRUE"
+ : "FALSE");
+ continue;
+ } else if (strcmp(s, "!WC") == 0) {
+ if ((options & DNS_DBFIND_NOWILD) != 0) {
+ options &= ~DNS_DBFIND_NOWILD;
+ } else {
+ options |= DNS_DBFIND_NOWILD;
+ }
+ printf("wildcard matching = %s\n",
+ ((options & DNS_DBFIND_NOWILD) == 0) ? "TRUE"
+ : "FALSE");
+ continue;
+ } else if (strstr(s, "!LS ") == s) {
+ DBI_CHECK(dbi);
+ list(dbi, &s[4]);
+ continue;
+ } else if (strcmp(s, "!LS") == 0) {
+ DBI_CHECK(dbi);
+ list(dbi, NULL);
+ continue;
+ } else if (strstr(s, "!DU ") == s) {
+ DBI_CHECK(dbi);
+ result = dns_db_dump(dbi->db, dbi->version, s + 4);
+ if (result != ISC_R_SUCCESS) {
+ printf("\n");
+ print_result("", result);
+ }
+ continue;
+ } else if (strcmp(s, "!PN") == 0) {
+ if (printnode) {
+ printnode = false;
+ } else {
+ printnode = true;
+ }
+ printf("printnode = %s\n",
+ printnode ? "TRUE" : "FALSE");
+ continue;
+ } else if (strstr(s, "!P") == s) {
+ DBI_CHECK(dbi);
+ v = atoi(&s[2]);
+ dbi->pause_every = v;
+ continue;
+ } else if (strcmp(s, "!+") == 0) {
+ DBI_CHECK(dbi);
+ dbi->ascending = true;
+ continue;
+ } else if (strcmp(s, "!-") == 0) {
+ DBI_CHECK(dbi);
+ dbi->ascending = false;
+ continue;
+ } else if (strcmp(s, "!DB") == 0) {
+ dbi = NULL;
+ origin = dns_rootname;
+ version = NULL;
+ printf("now searching all databases\n");
+ continue;
+ } else if (strncmp(s, "!DB ", 4) == 0) {
+ dbi = select_db(s + 4);
+ if (dbi != NULL) {
+ db = dbi->db;
+ origin = dns_db_origin(dbi->db);
+ version = dbi->version;
+ addmode = false;
+ delmode = false;
+ holdmode = false;
+ } else {
+ db = NULL;
+ version = NULL;
+ origin = dns_rootname;
+ printf("database not found; "
+ "now searching all databases\n");
+ }
+ continue;
+ } else if (strcmp(s, "!ZC") == 0) {
+ if (find_zonecut) {
+ find_zonecut = false;
+ } else {
+ find_zonecut = true;
+ }
+ printf("find_zonecut = %s\n",
+ find_zonecut ? "TRUE" : "FALSE");
+ continue;
+ } else if (strcmp(s, "!NZ") == 0) {
+ if (noexact_zonecut) {
+ noexact_zonecut = false;
+ } else {
+ noexact_zonecut = true;
+ }
+ printf("noexact_zonecut = %s\n",
+ noexact_zonecut ? "TRUE" : "FALSE");
+ continue;
+ }
+
+ isc_buffer_init(&source, s, len);
+ isc_buffer_add(&source, len);
+ isc_buffer_init(&target, b, sizeof(b));
+ result = dns_name_fromtext(&name, &source, origin, 0, &target);
+ if (result != ISC_R_SUCCESS) {
+ print_result("bad name: ", result);
+ continue;
+ }
+
+ if (dbi == NULL) {
+ zcoptions = 0;
+ if (noexact_zonecut) {
+ zcoptions |= DNS_DBTABLEFIND_NOEXACT;
+ }
+ db = NULL;
+ result = dns_dbtable_find(dbtable, &name, zcoptions,
+ &db);
+ if (result != ISC_R_SUCCESS &&
+ result != DNS_R_PARTIALMATCH)
+ {
+ if (!quiet) {
+ printf("\n");
+ print_result("", result);
+ }
+ continue;
+ }
+ isc_buffer_init(&tb1, t1, sizeof(t1));
+ result = dns_name_totext(dns_db_origin(db), false,
+ &tb1);
+ if (result != ISC_R_SUCCESS) {
+ printf("\n");
+ print_result("", result);
+ dns_db_detach(&db);
+ continue;
+ }
+ isc_buffer_usedregion(&tb1, &r1);
+ printf("\ndatabase = %.*s (%s)\n", (int)r1.length,
+ r1.base, (dns_db_iszone(db)) ? "zone" : "cache");
+ }
+ node = NULL;
+ dns_rdataset_init(&rdataset);
+ dns_rdataset_init(&sigrdataset);
+
+ if (find_zonecut && dns_db_iscache(db)) {
+ zcoptions = options;
+ if (noexact_zonecut) {
+ zcoptions |= DNS_DBFIND_NOEXACT;
+ }
+ result = dns_db_findzonecut(db, &name, zcoptions, 0,
+ &node, fname, NULL,
+ &rdataset, &sigrdataset);
+ } else {
+ result = dns_db_find(db, &name, version, type, options,
+ 0, &node, fname, &rdataset,
+ &sigrdataset);
+ }
+
+ if (!quiet) {
+ if (dbi != NULL) {
+ printf("\n");
+ }
+ print_result("", result);
+ }
+
+ found_as = false;
+ switch (result) {
+ case ISC_R_SUCCESS:
+ case DNS_R_GLUE:
+ case DNS_R_CNAME:
+ case DNS_R_ZONECUT:
+ break;
+ case DNS_R_DNAME:
+ case DNS_R_DELEGATION:
+ found_as = true;
+ break;
+ case DNS_R_NXRRSET:
+ if (dns_rdataset_isassociated(&rdataset)) {
+ break;
+ }
+ if (dbi != NULL) {
+ if (holdmode) {
+ RUNTIME_CHECK(dbi->hold_count <
+ MAXHOLD);
+ dbi->hold_nodes[dbi->hold_count++] =
+ node;
+ node = NULL;
+ } else {
+ dns_db_detachnode(db, &node);
+ }
+ } else {
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ }
+ continue;
+ case DNS_R_NXDOMAIN:
+ if (dns_rdataset_isassociated(&rdataset)) {
+ break;
+ }
+ FALLTHROUGH;
+ default:
+ if (dbi == NULL) {
+ dns_db_detach(&db);
+ }
+ if (quiet) {
+ print_result("", result);
+ }
+ continue;
+ }
+ if (found_as && !quiet) {
+ isc_buffer_init(&tb1, t1, sizeof(t1));
+ isc_buffer_init(&tb2, t2, sizeof(t2));
+ result = dns_name_totext(&name, false, &tb1);
+ if (result != ISC_R_SUCCESS) {
+ print_result("", result);
+ dns_db_detachnode(db, &node);
+ if (dbi == NULL) {
+ dns_db_detach(&db);
+ }
+ continue;
+ }
+ result = dns_name_totext(fname, false, &tb2);
+ if (result != ISC_R_SUCCESS) {
+ print_result("", result);
+ dns_db_detachnode(db, &node);
+ if (dbi == NULL) {
+ dns_db_detach(&db);
+ }
+ continue;
+ }
+ isc_buffer_usedregion(&tb1, &r1);
+ isc_buffer_usedregion(&tb2, &r2);
+ printf("found %.*s as %.*s\n", (int)r1.length, r1.base,
+ (int)r2.length, r2.base);
+ }
+
+ if (printnode) {
+ dns_db_printnode(db, node, stdout);
+ }
+
+ if (!found_as && type == dns_rdatatype_any) {
+ rdsiter = NULL;
+ result = dns_db_allrdatasets(db, node, version, 0, 0,
+ &rdsiter);
+ if (result == ISC_R_SUCCESS) {
+ if (!quiet) {
+ print_rdatasets(fname, rdsiter);
+ }
+ dns_rdatasetiter_destroy(&rdsiter);
+ } else {
+ print_result("", result);
+ }
+ } else {
+ if (!quiet) {
+ print_rdataset(fname, &rdataset);
+ }
+ if (dns_rdataset_isassociated(&sigrdataset)) {
+ if (!quiet) {
+ print_rdataset(fname, &sigrdataset);
+ }
+ dns_rdataset_disassociate(&sigrdataset);
+ }
+ if (dbi != NULL && addmode && !found_as) {
+ rdataset.ttl++;
+ rdataset.trust = trust;
+ if (dns_db_iszone(db)) {
+ addopts = DNS_DBADD_MERGE;
+ } else {
+ addopts = 0;
+ }
+ result = dns_db_addrdataset(db, node, version,
+ 0, &rdataset,
+ addopts, NULL);
+ if (result != ISC_R_SUCCESS) {
+ print_result("", result);
+ }
+ if (printnode) {
+ dns_db_printnode(db, node, stdout);
+ }
+ } else if (dbi != NULL && delmode && !found_as) {
+ result = dns_db_deleterdataset(
+ db, node, version, type, 0);
+ if (result != ISC_R_SUCCESS) {
+ print_result("", result);
+ }
+ if (printnode) {
+ dns_db_printnode(db, node, stdout);
+ }
+ }
+ dns_rdataset_disassociate(&rdataset);
+ }
+
+ if (dbi != NULL) {
+ if (holdmode) {
+ RUNTIME_CHECK(dbi->hold_count < MAXHOLD);
+ dbi->hold_nodes[dbi->hold_count++] = node;
+ node = NULL;
+ } else {
+ dns_db_detachnode(db, &node);
+ }
+ } else {
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ }
+ }
+
+ if (time_lookups) {
+ uint64_t usec;
+
+ TIME_NOW(&finish);
+
+ usec = isc_time_microdiff(&finish, &start);
+
+ printf("elapsed time: %lu.%06lu seconds\n",
+ (unsigned long)(usec / 1000000),
+ (unsigned long)(usec % 1000000));
+ }
+
+ unload_all();
+
+ dns_dbtable_detach(&dbtable);
+
+ if (lctx != NULL) {
+ isc_log_destroy(&lctx);
+ }
+
+ if (!quiet) {
+ isc_mem_stats(mctx, stdout);
+ }
+
+ return (0);
+}
diff --git a/bin/tests/optional/fsaccess_test.c b/bin/tests/optional/fsaccess_test.c
new file mode 100644
index 0000000..db5d21e
--- /dev/null
+++ b/bin/tests/optional/fsaccess_test.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h> /* Non-portable. */
+#include <sys/types.h> /* Non-portable. */
+
+#include <isc/fsaccess.h>
+#include <isc/print.h>
+#include <isc/result.h>
+
+#define PATH "/tmp/fsaccess"
+
+int
+main(void) {
+ isc_fsaccess_t access;
+ isc_result_t result;
+ FILE *fp;
+ int n;
+
+ n = remove(PATH);
+ if (n != 0 && errno != ENOENT) {
+ fprintf(stderr, "unable to remove(%s)\n", PATH);
+ exit(1);
+ }
+ fp = fopen(PATH, "w");
+ if (fp == NULL) {
+ fprintf(stderr, "unable to fopen(%s)\n", PATH);
+ exit(1);
+ }
+ n = chmod(PATH, 0);
+ if (n != 0) {
+ fprintf(stderr, "unable chmod(%s, 0)\n", PATH);
+ exit(1);
+ }
+
+ access = 0;
+
+ isc_fsaccess_add(ISC_FSACCESS_OWNER | ISC_FSACCESS_GROUP,
+ ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, &access);
+
+ printf("fsaccess=%u\n", access);
+
+ isc_fsaccess_add(ISC_FSACCESS_OTHER, ISC_FSACCESS_READ, &access);
+
+ printf("fsaccess=%u\n", access);
+
+ result = isc_fsaccess_set(PATH, access);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "result = %s\n", isc_result_totext(result));
+ }
+ (void)fclose(fp);
+
+ return (0);
+}
diff --git a/bin/tests/optional/gsstest.c b/bin/tests/optional/gsstest.c
new file mode 100644
index 0000000..1cc18eb
--- /dev/null
+++ b/bin/tests/optional/gsstest.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/app.h>
+#include <isc/base64.h>
+#include <isc/log.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/sockaddr.h>
+#include <isc/socket.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/dispatch.h>
+#include <dns/dnssec.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+#include <dns/masterdump.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rdataset.h>
+#include <dns/request.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/tkey.h>
+#include <dns/tsig.h>
+#include <dns/types.h>
+#include <dns/view.h>
+
+#include <dst/result.h>
+
+#ifdef GSSAPI
+#include ISC_PLATFORM_GSSAPIHEADER
+
+#define CHECK(str, x) \
+ { \
+ if ((x) != ISC_R_SUCCESS) { \
+ fprintf(stderr, "I:%d:%s: %s\n", __LINE__, (str), \
+ isc_result_totext(x)); \
+ goto end; \
+ } \
+ }
+
+static dns_fixedname_t servername, gssname;
+
+static isc_mem_t *mctx = NULL;
+static dns_requestmgr_t *requestmgr = NULL;
+static isc_sockaddr_t address;
+
+static dns_tsig_keyring_t *ring = NULL;
+static dns_tsigkey_t *tsigkey = NULL;
+static dns_gss_ctx_id_t gssctx;
+static dns_gss_ctx_id_t *gssctxp = &gssctx;
+
+#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
+
+#define PORT 53
+#define TIMEOUT 30
+
+static void
+initctx1(isc_task_t *task, isc_event_t *event);
+static void
+sendquery(isc_task_t *task, isc_event_t *event);
+static void
+setup();
+
+static void
+console(isc_task_t *task, isc_event_t *event) {
+ char buf[32];
+ int c;
+
+ isc_event_t *ev = NULL;
+
+ isc_event_free(&event);
+
+ for (;;) {
+ printf("\nCommand => ");
+ c = scanf("%31s", buf);
+
+ if (c == EOF || strcmp(buf, "quit") == 0) {
+ isc_app_shutdown();
+ return;
+ }
+
+ if (strcmp(buf, "initctx") == 0) {
+ ev = isc_event_allocate(mctx, (void *)1, 1, initctx1,
+ NULL, sizeof(*event));
+ isc_task_send(task, &ev);
+ return;
+ }
+
+ if (strcmp(buf, "query") == 0) {
+ ev = isc_event_allocate(mctx, (void *)1, 1, sendquery,
+ NULL, sizeof(*event));
+ isc_task_send(task, &ev);
+ return;
+ }
+
+ printf("Unknown command\n");
+ }
+}
+
+static void
+recvresponse(isc_task_t *task, isc_event_t *event) {
+ dns_requestevent_t *reqev = (dns_requestevent_t *)event;
+ isc_result_t result, result2;
+ dns_message_t *query = NULL, *response = NULL;
+ isc_buffer_t outtoken;
+ isc_buffer_t outbuf;
+ char output[10 * 1024];
+
+ unsigned char array[DNS_NAME_MAXTEXT + 1];
+ isc_buffer_init(&outtoken, array, sizeof(array));
+
+ UNUSED(task);
+
+ REQUIRE(reqev != NULL);
+
+ query = reqev->ev_arg;
+
+ if (reqev->result != ISC_R_SUCCESS) {
+ fprintf(stderr, "I:request event result: %s\n",
+ isc_result_totext(reqev->result));
+ goto end;
+ }
+
+ response = NULL;
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+
+ printf("\nReceived Response:\n");
+
+ result2 = dns_request_getresponse(reqev->request, response,
+ DNS_MESSAGEPARSE_PRESERVEORDER);
+ isc_buffer_init(&outbuf, output, sizeof(output));
+ result = dns_message_totext(response, &dns_master_style_debug, 0,
+ &outbuf);
+ CHECK("dns_message_totext", result);
+ printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+ (char *)isc_buffer_base(&outbuf));
+
+ CHECK("dns_request_getresponse", result2);
+
+ if (response != NULL) {
+ dns_message_detach(&response);
+ }
+
+end:
+ if (query != NULL) {
+ dns_message_detach(&query);
+ }
+
+ if (reqev->request != NULL) {
+ dns_request_destroy(&reqev->request);
+ }
+
+ isc_event_free(&event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
+ sizeof(*event));
+ isc_task_send(task, &event);
+ return;
+}
+
+static void
+sendquery(isc_task_t *task, isc_event_t *event) {
+ dns_request_t *request = NULL;
+ dns_message_t *message = NULL;
+ dns_name_t *qname = NULL;
+ dns_rdataset_t *qrdataset = NULL;
+ isc_result_t result;
+ dns_fixedname_t queryname;
+ isc_buffer_t buf;
+ isc_buffer_t outbuf;
+ char output[10 * 1024];
+ static char host[256];
+ int c;
+
+ isc_event_free(&event);
+
+ printf("Query => ");
+ c = scanf("%255s", host);
+ if (c == EOF) {
+ return;
+ }
+
+ dns_fixedname_init(&queryname);
+ isc_buffer_init(&buf, host, strlen(host));
+ isc_buffer_add(&buf, strlen(host));
+ result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
+ dns_rootname, 0, NULL);
+ CHECK("dns_name_fromtext", result);
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
+
+ message->opcode = dns_opcode_query;
+ message->rdclass = dns_rdataclass_in;
+ message->id = (unsigned short)(random() & 0xFFFF);
+
+ result = dns_message_gettempname(message, &qname);
+ if (result != ISC_R_SUCCESS) {
+ goto end;
+ }
+
+ result = dns_message_gettemprdataset(message, &qrdataset);
+ if (result != ISC_R_SUCCESS) {
+ goto end;
+ }
+
+ dns_name_init(qname, NULL);
+ dns_name_clone(dns_fixedname_name(&queryname), qname);
+ dns_rdataset_makequestion(qrdataset, dns_rdataclass_in,
+ dns_rdatatype_a);
+ ISC_LIST_APPEND(qname->list, qrdataset, link);
+ dns_message_addname(message, qname, DNS_SECTION_QUESTION);
+
+ result = dns_request_create(requestmgr, message, &address, 0, tsigkey,
+ TIMEOUT, task, recvresponse, message,
+ &request);
+ CHECK("dns_request_create", result);
+
+ printf("Submitting query:\n");
+ isc_buffer_init(&outbuf, output, sizeof(output));
+ result = dns_message_totext(message, &dns_master_style_debug, 0,
+ &outbuf);
+ CHECK("dns_message_totext", result);
+ printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+ (char *)isc_buffer_base(&outbuf));
+
+ return;
+
+end:
+ if (qname != NULL) {
+ dns_message_puttempname(message, &qname);
+ }
+ if (qrdataset != NULL) {
+ dns_message_puttemprdataset(message, &qrdataset);
+ }
+ if (message != NULL) {
+ dns_message_detach(&message);
+ }
+}
+
+static void
+initctx2(isc_task_t *task, isc_event_t *event) {
+ dns_requestevent_t *reqev = (dns_requestevent_t *)event;
+ isc_result_t result;
+ dns_message_t *query = NULL, *response = NULL;
+ isc_buffer_t outtoken;
+ unsigned char array[DNS_NAME_MAXTEXT + 1];
+ dns_rdataset_t *rdataset;
+ dns_rdatatype_t qtype;
+ dns_name_t *question_name;
+
+ UNUSED(task);
+
+ REQUIRE(reqev != NULL);
+
+ query = reqev->ev_arg;
+
+ if (reqev->result != ISC_R_SUCCESS) {
+ fprintf(stderr, "I:request event result: %s\n",
+ isc_result_totext(reqev->result));
+ goto end;
+ }
+
+ response = NULL;
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+
+ result = dns_request_getresponse(reqev->request, response,
+ DNS_MESSAGEPARSE_PRESERVEORDER);
+ CHECK("dns_request_getresponse", result);
+
+ if (response->rcode != dns_rcode_noerror) {
+ result = ISC_RESULTCLASS_DNSRCODE + response->rcode;
+ fprintf(stderr, "I:response rcode: %s\n",
+ isc_result_totext(result));
+ goto end;
+ }
+
+ printf("Received token from server, calling gss_init_sec_context()\n");
+ isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1);
+ result = dns_tkey_processgssresponse(
+ query, response, dns_fixedname_name(&gssname), &gssctx,
+ &outtoken, &tsigkey, ring, NULL);
+ gssctx = *gssctxp;
+ CHECK("dns_tkey_processgssresponse", result);
+ printf("Context accepted\n");
+
+ question_name = NULL;
+ dns_message_currentname(response, DNS_SECTION_ANSWER, &question_name);
+ rdataset = ISC_LIST_HEAD(question_name->list);
+ INSIST(rdataset != NULL);
+ qtype = rdataset->type;
+ if (qtype == dns_rdatatype_tkey) {
+ printf("Received TKEY response from server\n");
+ printf("Context completed\n");
+ } else {
+ printf("Did not receive TKEY response from server\n");
+ printf("Context not completed\n");
+ dns_tsigkey_detach(&tsigkey);
+ tsigkey = NULL;
+ }
+
+ dns_message_detach(&response);
+
+end:
+ if (query != NULL) {
+ dns_message_detach(&query);
+ }
+
+ if (reqev->request != NULL) {
+ dns_request_destroy(&reqev->request);
+ }
+
+ isc_event_free(&event);
+
+ event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
+ sizeof(*event));
+ isc_task_send(task, &event);
+ return;
+}
+
+static void
+initctx1(isc_task_t *task, isc_event_t *event) {
+ char gssid[512];
+ char contextname[512];
+ isc_result_t result;
+ isc_buffer_t buf;
+ dns_message_t *query;
+ dns_request_t *request;
+ int c;
+
+ isc_event_free(&event);
+
+ printf("Initctx - GSS name => ");
+ c = scanf("%511s", gssid);
+ if (c == EOF) {
+ return;
+ }
+
+ snprintf(contextname, sizeof(contextname), "gsstest.context.%d.",
+ (int)time(NULL));
+
+ printf("Initctx - context name we're using: %s\n", contextname);
+
+ printf("Negotiating GSSAPI context: ");
+ printf("%s", gssid);
+ printf("\n");
+
+ /*
+ * Setup a GSSAPI context with the server
+ */
+ dns_fixedname_init(&servername);
+ isc_buffer_init(&buf, contextname, strlen(contextname));
+ isc_buffer_add(&buf, strlen(contextname));
+ result = dns_name_fromtext(dns_fixedname_name(&servername), &buf,
+ dns_rootname, 0, NULL);
+ CHECK("dns_name_fromtext", result);
+
+ /* Make name happen */
+ dns_fixedname_init(&gssname);
+ isc_buffer_init(&buf, gssid, strlen(gssid));
+ isc_buffer_add(&buf, strlen(gssid));
+ result = dns_name_fromtext(dns_fixedname_name(&gssname), &buf,
+ dns_rootname, 0, NULL);
+ CHECK("dns_name_fromtext", result);
+
+ query = NULL;
+ dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
+
+ printf("Calling gss_init_sec_context()\n");
+ gssctx = GSS_C_NO_CONTEXT;
+ result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername),
+ dns_fixedname_name(&gssname), NULL,
+ 36000, &gssctx, true, mctx, NULL);
+ CHECK("dns_tkey_buildgssquery", result);
+
+ printf("Sending context token to server\n");
+ request = NULL;
+ result = dns_request_create(requestmgr, query, &address, 0, NULL,
+ TIMEOUT, task, initctx2, query, &request);
+ CHECK("dns_request_create", result);
+
+ return;
+end:
+ event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
+ sizeof(*event));
+ isc_task_send(task, &event);
+ return;
+}
+
+static void
+setup(void) {
+ for (;;) {
+ char serveraddress[512];
+ struct in_addr inaddr;
+ int c;
+
+ printf("Server IP => ");
+ c = scanf("%511s", serveraddress);
+
+ if (c == EOF || strcmp(serveraddress, "quit") == 0) {
+ isc_app_shutdown();
+ return;
+ }
+
+ if (inet_pton(AF_INET, serveraddress, &inaddr) == 1) {
+ isc_sockaddr_fromin(&address, &inaddr, PORT);
+ return;
+ }
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_nm_t *netmgr = NULL;
+ isc_taskmgr_t *taskmgr = NULL;
+ isc_timermgr_t *timermgr = NULL;
+ isc_socketmgr_t *socketmgr = NULL;
+ isc_socket_t *sock = NULL;
+ unsigned int attrs, attrmask;
+ isc_sockaddr_t bind_any;
+ dns_dispatchmgr_t *dispatchmgr = NULL;
+ dns_dispatch_t *dispatchv4 = NULL;
+ dns_view_t *view = NULL;
+ isc_task_t *task = NULL;
+ isc_log_t *lctx = NULL;
+ isc_logconfig_t *lcfg = NULL;
+ isc_logdestination_t destination;
+
+ UNUSED(argv);
+ UNUSED(argc);
+
+ RUNCHECK(isc_app_start());
+
+ dns_result_register();
+
+ mctx = NULL;
+ isc_mem_create(&mctx);
+
+ isc_log_create(mctx, &lctx, &lcfg);
+ isc_log_setcontext(lctx);
+ dns_log_init(lctx);
+ dns_log_setcontext(lctx);
+
+ /*
+ * Create and install the default channel.
+ */
+ destination.file.stream = stderr;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ isc_log_createchannel(lcfg, "_default", ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC, &destination, ISC_LOG_PRINTTIME);
+
+ RUNCHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL));
+
+ isc_log_setdebuglevel(lctx, 9);
+
+ RUNCHECK(dst_lib_init(mctx, NULL));
+
+ RUNCHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr));
+ RUNCHECK(isc_task_create(taskmgr, 0, &task));
+ RUNCHECK(isc_timermgr_create(mctx, &timermgr));
+ RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
+ RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr));
+ isc_sockaddr_any(&bind_any);
+ attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY |
+ DNS_DISPATCHATTR_IPV4;
+ attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP |
+ DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
+ RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, &bind_any,
+ 4096, 4, 2, 3, 5, attrs, attrmask,
+ &dispatchv4));
+ RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
+ dispatchmgr, dispatchv4, NULL,
+ &requestmgr));
+
+ RUNCHECK(dns_tsigkeyring_create(mctx, &ring));
+
+ RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
+ dns_view_setkeyring(view, ring);
+
+ RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp,
+ &sock));
+
+ setup();
+
+ RUNCHECK(isc_app_onrun(mctx, task, console, NULL));
+
+ (void)isc_app_run();
+
+ if (tsigkey) {
+ dns_tsigkey_detach(&tsigkey);
+ }
+
+ dns_requestmgr_shutdown(requestmgr);
+ dns_requestmgr_detach(&requestmgr);
+
+ dns_dispatch_detach(&dispatchv4);
+ dns_dispatchmgr_destroy(&dispatchmgr);
+
+ isc_timermgr_destroy(&timermgr);
+
+ isc_task_detach(&task);
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_socket_detach(&sock);
+ isc_socketmgr_destroy(&socketmgr);
+
+ isc_mem_stats(mctx, stdout);
+
+ dns_view_detach(&view);
+
+ dst_lib_destroy();
+
+ isc_mem_stats(mctx, stdout);
+ isc_mem_destroy(&mctx);
+
+ isc_app_finish();
+
+ return (0);
+}
+#else /* ifdef GSSAPI */
+int
+main(int argc, char *argv[]) {
+ UNUSED(argc);
+ UNUSED(argv);
+ fprintf(stderr, "R:GSSAPIONLY\n");
+ return (0);
+}
+#endif /* ifdef GSSAPI */
diff --git a/bin/tests/optional/inter_test.c b/bin/tests/optional/inter_test.c
new file mode 100644
index 0000000..32fbb2e
--- /dev/null
+++ b/bin/tests/optional/inter_test.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <stdlib.h>
+
+#include <isc/interfaceiter.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+int
+main(int argc, char **argv) {
+ isc_mem_t *mctx = NULL;
+ isc_interfaceiter_t *iter = NULL;
+ isc_interface_t ifdata;
+ isc_result_t result;
+ const char *res;
+ char buf[128];
+
+ UNUSED(argc);
+ UNUSED(argv);
+
+ isc_mem_create(&mctx);
+ result = isc_interfaceiter_create(mctx, &iter);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+ result = isc_interfaceiter_first(iter);
+ while (result == ISC_R_SUCCESS) {
+ result = isc_interfaceiter_current(iter, &ifdata);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stdout, "isc_interfaceiter_current: %s",
+ isc_result_totext(result));
+ continue;
+ }
+ fprintf(stdout, "%s %u %x\n", ifdata.name, ifdata.af,
+ ifdata.flags);
+ INSIST(ifdata.af == AF_INET || ifdata.af == AF_INET6);
+ res = inet_ntop(ifdata.af, &ifdata.address.type, buf,
+ sizeof(buf));
+ if (ifdata.address.zone != 0) {
+ fprintf(stdout, "address = %s (zone %u)\n",
+ res == NULL ? "BAD" : res, ifdata.address.zone);
+ } else {
+ fprintf(stdout, "address = %s\n",
+ res == NULL ? "BAD" : res);
+ }
+ INSIST(ifdata.address.family == ifdata.af);
+ res = inet_ntop(ifdata.af, &ifdata.netmask.type, buf,
+ sizeof(buf));
+ fprintf(stdout, "netmask = %s\n", res == NULL ? "BAD" : res);
+ INSIST(ifdata.netmask.family == ifdata.af);
+ if ((ifdata.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ res = inet_ntop(ifdata.af, &ifdata.dstaddress.type, buf,
+ sizeof(buf));
+ fprintf(stdout, "dstaddress = %s\n",
+ res == NULL ? "BAD" : res);
+
+ INSIST(ifdata.dstaddress.family == ifdata.af);
+ }
+ result = isc_interfaceiter_next(iter);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
+ fprintf(stdout, "isc_interfaceiter_next: %s",
+ isc_result_totext(result));
+ continue;
+ }
+ }
+ isc_interfaceiter_destroy(&iter);
+
+ fprintf(stdout, "\nPass 2\n\n");
+
+ result = isc_interfaceiter_create(mctx, &iter);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+ result = isc_interfaceiter_first(iter);
+ while (result == ISC_R_SUCCESS) {
+ result = isc_interfaceiter_current(iter, &ifdata);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stdout, "isc_interfaceiter_current: %s",
+ isc_result_totext(result));
+ continue;
+ }
+ fprintf(stdout, "%s %u %x\n", ifdata.name, ifdata.af,
+ ifdata.flags);
+ INSIST(ifdata.af == AF_INET || ifdata.af == AF_INET6);
+ res = inet_ntop(ifdata.af, &ifdata.address.type, buf,
+ sizeof(buf));
+ if (ifdata.address.zone != 0) {
+ fprintf(stdout, "address = %s (zone %u)\n",
+ res == NULL ? "BAD" : res, ifdata.address.zone);
+ } else {
+ fprintf(stdout, "address = %s\n",
+ res == NULL ? "BAD" : res);
+ }
+ INSIST(ifdata.address.family == ifdata.af);
+ res = inet_ntop(ifdata.af, &ifdata.netmask.type, buf,
+ sizeof(buf));
+ fprintf(stdout, "netmask = %s\n", res == NULL ? "BAD" : res);
+ INSIST(ifdata.netmask.family == ifdata.af);
+ if ((ifdata.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ res = inet_ntop(ifdata.af, &ifdata.dstaddress.type, buf,
+ sizeof(buf));
+ fprintf(stdout, "dstaddress = %s\n",
+ res == NULL ? "BAD" : res);
+
+ INSIST(ifdata.dstaddress.family == ifdata.af);
+ }
+ result = isc_interfaceiter_next(iter);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
+ fprintf(stdout, "isc_interfaceiter_next: %s",
+ isc_result_totext(result));
+ continue;
+ }
+ }
+ isc_interfaceiter_destroy(&iter);
+cleanup:
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/lex_test.c b/bin/tests/optional/lex_test.c
new file mode 100644
index 0000000..e0e88f7
--- /dev/null
+++ b/bin/tests/optional/lex_test.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <isc/commandline.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+isc_mem_t *mctx;
+isc_lex_t *lex;
+
+isc_lexspecials_t specials;
+
+static void
+print_token(isc_token_t *tokenp, FILE *stream) {
+ switch (tokenp->type) {
+ case isc_tokentype_unknown:
+ fprintf(stream, "UNKNOWN");
+ break;
+ case isc_tokentype_string:
+ fprintf(stream, "STRING %.*s",
+ (int)tokenp->value.as_region.length,
+ tokenp->value.as_region.base);
+ break;
+ case isc_tokentype_number:
+ fprintf(stream, "NUMBER %lu", tokenp->value.as_ulong);
+ break;
+ case isc_tokentype_qstring:
+ fprintf(stream, "QSTRING \"%.*s\"",
+ (int)tokenp->value.as_region.length,
+ tokenp->value.as_region.base);
+ break;
+ case isc_tokentype_eol:
+ fprintf(stream, "EOL");
+ break;
+ case isc_tokentype_eof:
+ fprintf(stream, "EOF");
+ break;
+ case isc_tokentype_initialws:
+ fprintf(stream, "INITIALWS");
+ break;
+ case isc_tokentype_special:
+ fprintf(stream, "SPECIAL %c", tokenp->value.as_char);
+ break;
+ case isc_tokentype_nomore:
+ fprintf(stream, "NOMORE");
+ break;
+ default:
+ FATAL_ERROR(__FILE__, __LINE__, "Unexpected type %d",
+ tokenp->type);
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_token_t token;
+ isc_result_t result;
+ int quiet = 0;
+ int c;
+ int masterfile = 1;
+ int stats = 0;
+ unsigned int options = 0;
+ int done = 0;
+
+ while ((c = isc_commandline_parse(argc, argv, "qmcs")) != -1) {
+ switch (c) {
+ case 'q':
+ quiet = 1;
+ break;
+ case 'm':
+ masterfile = 1;
+ break;
+ case 'c':
+ masterfile = 0;
+ break;
+ case 's':
+ stats = 1;
+ break;
+ }
+ }
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS);
+
+ if (masterfile) {
+ /* Set up to lex DNS master file. */
+
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+ options = ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE |
+ ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING |
+ ISC_LEXOPT_NOMORE;
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+ } else {
+ /* Set up to lex DNS config file. */
+
+ specials['{'] = 1;
+ specials['}'] = 1;
+ specials[';'] = 1;
+ specials['/'] = 1;
+ specials['"'] = 1;
+ specials['!'] = 1;
+ specials['*'] = 1;
+ isc_lex_setspecials(lex, specials);
+ options = ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING |
+ ISC_LEXOPT_NUMBER | ISC_LEXOPT_NOMORE;
+ isc_lex_setcomments(lex, (ISC_LEXCOMMENT_C |
+ ISC_LEXCOMMENT_CPLUSPLUS |
+ ISC_LEXCOMMENT_SHELL));
+ }
+
+ RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS);
+
+ while ((result = isc_lex_gettoken(lex, options, &token)) ==
+ ISC_R_SUCCESS &&
+ !done)
+ {
+ if (!quiet) {
+ char *name = isc_lex_getsourcename(lex);
+ print_token(&token, stdout);
+ printf(" line = %lu file = %s\n",
+ isc_lex_getsourceline(lex),
+ (name == NULL) ? "<none>" : name);
+ }
+ if (token.type == isc_tokentype_eof) {
+ isc_lex_close(lex);
+ }
+ if (token.type == isc_tokentype_nomore) {
+ done = 1;
+ }
+ }
+ if (result != ISC_R_SUCCESS) {
+ printf("Result: %s\n", isc_result_totext(result));
+ }
+
+ isc_lex_close(lex);
+ isc_lex_destroy(&lex);
+ if (!quiet && stats) {
+ isc_mem_stats(mctx, stdout);
+ }
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/lfsr_test.c b/bin/tests/optional/lfsr_test.c
new file mode 100644
index 0000000..c1c99f0
--- /dev/null
+++ b/bin/tests/optional/lfsr_test.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <isc/lfsr.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+uint32_t state[1024 * 64];
+
+int
+main(int argc, char **argv) {
+ isc_lfsr_t lfsr1, lfsr2;
+ int i;
+ uint32_t temp;
+
+ UNUSED(argc);
+ UNUSED(argv);
+
+ /*
+ * Verify that returned values are reproducible.
+ */
+ isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL);
+ for (i = 0; i < 32; i++) {
+ isc_lfsr_generate(&lfsr1, &state[i], 4);
+ printf("lfsr1: state[%2d] = %08x\n", i, state[i]);
+ }
+ isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL);
+ for (i = 0; i < 32; i++) {
+ isc_lfsr_generate(&lfsr1, &temp, 4);
+ if (state[i] != temp) {
+ printf("lfsr1: state[%2d] = %08x, "
+ "but new state is %08x\n",
+ i, state[i], temp);
+ }
+ }
+
+ /*
+ * Now do the same with skipping.
+ */
+ isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL);
+ for (i = 0; i < 32; i++) {
+ isc_lfsr_generate(&lfsr1, &state[i], 4);
+ isc_lfsr_skip(&lfsr1, 32);
+ printf("lfsr1: state[%2d] = %08x\n", i, state[i]);
+ }
+ isc_lfsr_init(&lfsr1, 0, 32, 0x80000057U, 0, NULL, NULL);
+ for (i = 0; i < 32; i++) {
+ isc_lfsr_generate(&lfsr1, &temp, 4);
+ isc_lfsr_skip(&lfsr1, 32);
+ if (state[i] != temp) {
+ printf("lfsr1: state[%2d] = %08x, "
+ "but new state is %08x\n",
+ i, state[i], temp);
+ }
+ }
+
+ /*
+ * Try to find the period of the LFSR.
+ *
+ * x^16 + x^5 + x^3 + x^2 + 1
+ */
+ isc_lfsr_init(&lfsr2, 0, 16, 0x00008016U, 0, NULL, NULL);
+ for (i = 0; i < 32; i++) {
+ isc_lfsr_generate(&lfsr2, &state[i], 4);
+ printf("lfsr2: state[%2d] = %08x\n", i, state[i]);
+ }
+ isc_lfsr_init(&lfsr2, 0, 16, 0x00008016U, 0, NULL, NULL);
+ for (i = 0; i < 32; i++) {
+ isc_lfsr_generate(&lfsr2, &temp, 4);
+ if (state[i] != temp) {
+ printf("lfsr2: state[%2d] = %08x, "
+ "but new state is %08x\n",
+ i, state[i], temp);
+ }
+ }
+
+ return (0);
+}
diff --git a/bin/tests/optional/log_test.c b/bin/tests/optional/log_test.c
new file mode 100644
index 0000000..006b1e2
--- /dev/null
+++ b/bin/tests/optional/log_test.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/log.h>
+
+#define TEST_FILE "/tmp/test_log"
+#define SYSLOG_FILE "/var/log/daemon.log"
+#define FILE_VERSIONS 10
+
+char usage[] = "Usage: %s [-m] [-s syslog_logfile] [-r file_versions]\n";
+
+#define CHECK(expr) \
+ result = expr; \
+ if (result != ISC_R_SUCCESS) { \
+ fprintf(stderr, "%s: " #expr "%s: exiting\n", progname, \
+ isc_result_totext(result)); \
+ }
+
+int
+main(int argc, char **argv) {
+ const char *progname, *syslog_file, *message;
+ int ch, i, file_versions, stderr_line;
+ bool show_final_mem = false;
+ isc_log_t *lctx;
+ isc_logconfig_t *lcfg;
+ isc_mem_t *mctx;
+ isc_result_t result;
+ isc_logdestination_t destination;
+ const isc_logcategory_t *category;
+ const isc_logmodule_t *module;
+
+ progname = strrchr(*argv, '/');
+ if (progname != NULL) {
+ progname++;
+ } else {
+ progname = *argv;
+ }
+
+ syslog_file = SYSLOG_FILE;
+ file_versions = FILE_VERSIONS;
+
+ while ((ch = isc_commandline_parse(argc, argv, "ms:r:")) != -1) {
+ switch (ch) {
+ case 'm':
+ show_final_mem = true;
+ break;
+ case 's':
+ syslog_file = isc_commandline_argument;
+ break;
+ case 'r':
+ file_versions = atoi(isc_commandline_argument);
+ if (file_versions < 0 &&
+ file_versions != ISC_LOG_ROLLNEVER &&
+ file_versions != ISC_LOG_ROLLINFINITE)
+ {
+ fprintf(stderr,
+ "%s: file rotations must be "
+ "%d (ISC_LOG_ROLLNEVER),\n\t"
+ "%d (ISC_LOG_ROLLINFINITE) "
+ "or > 0\n",
+ progname, ISC_LOG_ROLLNEVER,
+ ISC_LOG_ROLLINFINITE);
+ exit(1);
+ }
+ break;
+ case '?':
+ fprintf(stderr, usage, progname);
+ exit(1);
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+ POST(argv);
+
+ if (argc > 0) {
+ fprintf(stderr, usage, progname);
+ exit(1);
+ }
+
+ fprintf(stderr, "EXPECT:\n%s%d%s%s%s",
+ "8 lines to stderr (first 4 numbered, #3 repeated)\n",
+ file_versions == 0 || file_versions == ISC_LOG_ROLLNEVER ? 1
+ : file_versions > 0 ? file_versions + 1
+ : FILE_VERSIONS + 1,
+ " " TEST_FILE " files, and\n", "2 lines to syslog\n",
+ "lines ending with exclamation marks are errors\n\n");
+
+ isc_log_opensyslog(progname, LOG_PID, LOG_DAEMON);
+
+ mctx = NULL;
+ lctx = NULL;
+ lcfg = NULL;
+
+ isc_mem_create(&mctx);
+ isc_log_create(mctx, &lctx, &lcfg);
+
+ isc_log_settag(lcfg, progname);
+
+ isc_log_setcontext(lctx);
+ dns_log_init(lctx);
+ dns_log_setcontext(lctx);
+
+ /*
+ * Test isc_log_categorybyname and isc_log_modulebyname.
+ */
+ category = isc_log_categorybyname(lctx, "notify");
+ if (category != NULL) {
+ fprintf(stderr, "%s category found. (expected)\n",
+ category->name);
+ } else {
+ fprintf(stderr, "notify category not found!\n");
+ }
+
+ module = isc_log_modulebyname(lctx, "xyzzy");
+ if (module != NULL) {
+ fprintf(stderr, "%s module found!\n", module->name);
+ } else {
+ fprintf(stderr, "xyzzy module not found. (expected)\n");
+ }
+
+ /*
+ * Create a file channel to test file opening, size limiting and
+ * version rolling.
+ */
+
+ destination.file.name = TEST_FILE;
+ destination.file.maximum_size = 1;
+ destination.file.versions = file_versions;
+
+ isc_log_createchannel(
+ lcfg, "file_test", ISC_LOG_TOFILE, ISC_LOG_INFO, &destination,
+ ISC_LOG_PRINTTIME | ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL |
+ ISC_LOG_PRINTCATEGORY | ISC_LOG_PRINTMODULE);
+
+ /*
+ * Create a dynamic debugging channel to a file descriptor.
+ */
+ destination.file.stream = stderr;
+
+ isc_log_createchannel(lcfg, "debug_test", ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC, &destination,
+ ISC_LOG_PRINTTIME | ISC_LOG_PRINTLEVEL |
+ ISC_LOG_DEBUGONLY);
+
+ /*
+ * Test the usability of the four predefined logging channels.
+ */
+ CHECK(isc_log_usechannel(lcfg, "default_syslog",
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE));
+ CHECK(isc_log_usechannel(lcfg, "default_stderr",
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE));
+ CHECK(isc_log_usechannel(lcfg, "default_debug",
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE));
+ CHECK(isc_log_usechannel(lcfg, "null", DNS_LOGCATEGORY_DATABASE, NULL));
+
+ /*
+ * Use the custom channels.
+ */
+ CHECK(isc_log_usechannel(lcfg, "file_test", DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_DB));
+
+ CHECK(isc_log_usechannel(lcfg, "debug_test", DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_RBTDB));
+
+ fprintf(stderr, "\n==> stderr begin\n");
+
+ /*
+ * Write to the internal default by testing both a category for which
+ * no channel has been specified and a category which was specified
+ * but not with the named module.
+ */
+ stderr_line = 1;
+
+ isc_log_write(lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_RBT,
+ ISC_LOG_CRITICAL, "%s (%d)",
+ "Unspecified category and unspecified module to stderr",
+ stderr_line++);
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBT,
+ ISC_LOG_CRITICAL, "%s (%d)",
+ "Specified category and unspecified module to stderr",
+ stderr_line++);
+
+ /*
+ * Write to default_syslog, default_stderr and default_debug.
+ */
+ isc_log_write(lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+ ISC_LOG_WARNING, "%s (%d twice)",
+ "Using the predefined channels to syslog+stderr",
+ stderr_line++);
+
+ /*
+ * Write to predefined null channel.
+ */
+ isc_log_write(lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_INFO, "This is to null and should not appear!");
+
+ /*
+ * Reset the internal default to use syslog instead of stderr,
+ * and test it.
+ */
+ CHECK(isc_log_usechannel(lcfg, "default_syslog",
+ ISC_LOGCATEGORY_DEFAULT, NULL));
+ isc_log_write(lctx, DNS_LOGCATEGORY_SECURITY, DNS_LOGMODULE_RBT,
+ ISC_LOG_ERROR, "%s%s",
+ "This message to the redefined default category should ",
+ "be second in syslog");
+ /*
+ * Write to the file channel.
+ */
+ if (file_versions >= 0 || file_versions == ISC_LOG_ROLLINFINITE) {
+ /*
+ * If file_versions is 0 or ISC_LOG_ROLLINFINITE, write
+ * the "should not appear" and "should be in file" messages
+ * to ensure they get rolled.
+ */
+ if (file_versions <= 0) {
+ file_versions = FILE_VERSIONS;
+ } else {
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_DB, ISC_LOG_NOTICE,
+ "This should be rolled over "
+ "and not appear!");
+ }
+
+ for (i = file_versions - 1; i >= 0; i--) {
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_DB, ISC_LOG_NOTICE,
+ "should be in file %d/%d", i,
+ file_versions - 1);
+ }
+
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DB,
+ ISC_LOG_NOTICE, "should be in base file");
+ } else {
+ file_versions = FILE_VERSIONS;
+ for (i = 1; i <= file_versions; i++) {
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_DB, ISC_LOG_NOTICE,
+ "This is message %d in the log file", i);
+ }
+ }
+
+ /*
+ * Write a debugging message to a category that has no
+ * debugging channels for the named module.
+ */
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DB,
+ ISC_LOG_DEBUG(1),
+ "This debug message should not appear!");
+
+ /*
+ * Write debugging messages to a dynamic debugging channel.
+ */
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_CRITICAL,
+ "This critical message should "
+ "not appear because the debug level is 0!");
+
+ isc_log_setdebuglevel(lctx, 3);
+
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_DEBUG(1), "%s (%d)",
+ "Dynamic debugging to stderr", stderr_line++);
+ isc_log_write(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_DEBUG(5),
+ "This debug level is too high and should not appear!");
+
+ /*
+ * Test out the duplicate filtering using the debug_test channel.
+ */
+ isc_log_setduplicateinterval(lcfg, 10);
+ message = "This message should appear only once on stderr";
+
+ isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_CRITICAL, "%s", message);
+ isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_CRITICAL, "%s", message);
+
+ isc_log_setduplicateinterval(lcfg, 1);
+ message = "This message should appear twice on stderr";
+
+ isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_CRITICAL, "%s", message);
+ sleep(2);
+ isc_log_write1(lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RBTDB,
+ ISC_LOG_CRITICAL, "%s", message);
+
+ /*
+ * Review where everything went.
+ * XXXDCL NT
+ */
+ fputc('\n', stderr);
+ if (system("head " TEST_FILE "*; rm -f " TEST_FILE "*") != 0) {
+ fprintf(stderr, "system(\"head " TEST_FILE "*; rm -f " TEST_FILE
+ "*\") failed\n");
+ goto cleanup;
+ }
+
+ /* This is highly system specific. */
+ if (freopen(syslog_file, "r", stdin) == NULL) {
+ fprintf(stderr, "freopen(%s, \"r\", stdin) failed\n",
+ syslog_file);
+ goto cleanup;
+ }
+ fprintf(stderr, "\n==> %s <==\n", syslog_file);
+ if (system("tail -2") != 0) {
+ fprintf(stderr, "system(\"tail -2\") failed\n");
+ goto cleanup;
+ }
+ fputc('\n', stderr);
+
+cleanup:
+ isc_log_destroy(&lctx);
+
+ if (show_final_mem) {
+ isc_mem_stats(mctx, stderr);
+ }
+
+ return (0);
+}
diff --git a/bin/tests/optional/master_test.c b/bin/tests/optional/master_test.c
new file mode 100644
index 0000000..1cd6ec7
--- /dev/null
+++ b/bin/tests/optional/master_test.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/util.h>
+
+#include <dns/callbacks.h>
+#include <dns/master.h>
+#include <dns/name.h>
+#include <dns/rdataset.h>
+#include <dns/result.h>
+
+isc_mem_t *mctx;
+
+static isc_result_t
+print_dataset(void *arg, const dns_name_t *owner, dns_rdataset_t *dataset) {
+ char buf[64 * 1024];
+ isc_buffer_t target;
+ isc_result_t result;
+
+ UNUSED(arg);
+
+ isc_buffer_init(&target, buf, 64 * 1024);
+ result = dns_rdataset_totext(dataset, owner, false, false, &target);
+ if (result == ISC_R_SUCCESS) {
+ fprintf(stdout, "%.*s\n", (int)target.used,
+ (char *)target.base);
+ } else {
+ fprintf(stdout, "dns_rdataset_totext: %s\n",
+ dns_result_totext(result));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_result_t result;
+ dns_name_t origin;
+ isc_buffer_t source;
+ isc_buffer_t target;
+ unsigned char name_buf[255];
+ dns_rdatacallbacks_t callbacks;
+
+ UNUSED(argc);
+
+ isc_mem_create(&mctx);
+
+ if (argv[1]) {
+ isc_buffer_init(&source, argv[1], strlen(argv[1]));
+ isc_buffer_add(&source, strlen(argv[1]));
+ isc_buffer_setactive(&source, strlen(argv[1]));
+ isc_buffer_init(&target, name_buf, 255);
+ dns_name_init(&origin, NULL);
+ result = dns_name_fromtext(&origin, &source, dns_rootname, 0,
+ &target);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stdout, "dns_name_fromtext: %s\n",
+ dns_result_totext(result));
+ exit(1);
+ }
+
+ dns_rdatacallbacks_init_stdio(&callbacks);
+ callbacks.add = print_dataset;
+
+ result = dns_master_loadfile(
+ argv[1], &origin, &origin, dns_rdataclass_in, 0, 0,
+ &callbacks, NULL, NULL, mctx, dns_masterformat_text, 0);
+ fprintf(stdout, "dns_master_loadfile: %s\n",
+ dns_result_totext(result));
+ }
+ return (0);
+}
diff --git a/bin/tests/optional/mempool_test.c b/bin/tests/optional/mempool_test.c
new file mode 100644
index 0000000..b3d04ee
--- /dev/null
+++ b/bin/tests/optional/mempool_test.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <isc/mem.h>
+#include <isc/util.h>
+
+isc_mem_t *mctx;
+
+int
+main(int argc, char *argv[]) {
+ void *items1[50];
+ void *items2[50];
+ void *tmp;
+ isc_mempool_t *mp1, *mp2;
+ unsigned int i, j;
+
+ UNUSED(argc);
+ UNUSED(argv);
+
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ mctx = NULL;
+ isc_mem_create(&mctx);
+
+ mp1 = NULL;
+ isc_mempool_create(mctx, 24, &mp1);
+
+ mp2 = NULL;
+ isc_mempool_create(mctx, 31, &mp2);
+
+ isc_mem_stats(mctx, stderr);
+
+ isc_mempool_setfreemax(mp1, 10);
+ isc_mempool_setfillcount(mp1, 10);
+ isc_mempool_setmaxalloc(mp1, 30);
+
+ /*
+ * Allocate 30 items from the pool. This is our max.
+ */
+ for (i = 0; i < 30; i++) {
+ items1[i] = isc_mempool_get(mp1);
+ RUNTIME_CHECK(items1[i] != NULL);
+ }
+
+ /*
+ * Try to allocate one more. This should fail.
+ */
+ tmp = isc_mempool_get(mp1);
+ RUNTIME_CHECK(tmp == NULL);
+
+ /*
+ * Free the first 11 items. Verify that there are 10 free items on
+ * the free list (which is our max).
+ */
+
+ for (i = 0; i < 11; i++) {
+ isc_mempool_put(mp1, items1[i]);
+ items1[i] = NULL;
+ }
+
+ RUNTIME_CHECK(isc_mempool_getfreecount(mp1) == 10);
+ RUNTIME_CHECK(isc_mempool_getallocated(mp1) == 19);
+
+ isc_mem_stats(mctx, stderr);
+
+ /*
+ * Now, beat up on mp2 for a while. Allocate 50 items, then free
+ * them, then allocate 50 more, etc.
+ */
+ isc_mempool_setfreemax(mp2, 25);
+ isc_mempool_setfillcount(mp2, 25);
+ for (j = 0; j < 5000; j++) {
+ for (i = 0; i < 50; i++) {
+ items2[i] = isc_mempool_get(mp2);
+ RUNTIME_CHECK(items2[i] != NULL);
+ }
+ for (i = 0; i < 50; i++) {
+ isc_mempool_put(mp2, items2[i]);
+ items2[i] = NULL;
+ }
+ }
+
+ /*
+ * Free all the other items and blow away this pool.
+ */
+ for (i = 11; i < 30; i++) {
+ isc_mempool_put(mp1, items1[i]);
+ items1[i] = NULL;
+ }
+
+ isc_mempool_destroy(&mp1);
+
+ isc_mem_stats(mctx, stderr);
+
+ isc_mempool_destroy(&mp2);
+
+ isc_mem_stats(mctx, stderr);
+
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/name_test.c b/bin/tests/optional/name_test.c
new file mode 100644
index 0000000..4c37441
--- /dev/null
+++ b/bin/tests/optional/name_test.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/commandline.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/result.h>
+
+static void
+print_wirename(isc_region_t *name) {
+ unsigned char *ccurr, *cend;
+
+ if (name->length == 0) {
+ printf("<empty wire name>\n");
+ return;
+ }
+ ccurr = name->base;
+ cend = ccurr + name->length;
+ while (ccurr != cend) {
+ printf("%02x ", *ccurr++);
+ }
+ printf("\n");
+}
+
+static void
+print_name(dns_name_t *name) {
+ isc_result_t result;
+ isc_buffer_t source;
+ isc_region_t r;
+ char s[1000];
+
+ isc_buffer_init(&source, s, sizeof(s));
+ if (dns_name_countlabels(name) > 0) {
+ result = dns_name_totext(name, false, &source);
+ } else {
+ result = ISC_R_SUCCESS;
+ }
+ if (result == ISC_R_SUCCESS) {
+ isc_buffer_usedregion(&source, &r);
+ if (r.length > 0) {
+ printf("%.*s\n", (int)r.length, r.base);
+ } else {
+ printf("<empty text name>\n");
+ }
+ } else {
+ printf("error: %s\n", dns_result_totext(result));
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ char s[1000];
+ isc_result_t result;
+ dns_fixedname_t wname, wname2, oname, compname, downname;
+ isc_buffer_t source;
+ isc_region_t r;
+ dns_name_t *name, *comp, *down;
+ const dns_name_t *origin;
+ unsigned int downcase = 0;
+ size_t len;
+ bool quiet = false;
+ bool concatenate = false;
+ bool got_name = false;
+ bool check_absolute = false;
+ bool check_wildcard = false;
+ bool test_downcase = false;
+ bool inplace = false;
+ bool want_split = false;
+ unsigned int labels, split_label = 0;
+ dns_fixedname_t fprefix, fsuffix;
+ dns_name_t *prefix, *suffix;
+ int ch;
+
+ while ((ch = isc_commandline_parse(argc, argv, "acdiqs:w")) != -1) {
+ switch (ch) {
+ case 'a':
+ check_absolute = true;
+ break;
+ case 'c':
+ concatenate = true;
+ break;
+ case 'd':
+ test_downcase = true;
+ break;
+ case 'i':
+ inplace = true;
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case 's':
+ want_split = true;
+ split_label = atoi(isc_commandline_argument);
+ break;
+ case 'w':
+ check_wildcard = true;
+ break;
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+
+ if (argc > 0) {
+ if (strcasecmp("none", argv[0]) == 0) {
+ origin = NULL;
+ } else {
+ len = strlen(argv[0]);
+ isc_buffer_init(&source, argv[0], len);
+ isc_buffer_add(&source, len);
+ dns_fixedname_init(&oname);
+ result = dns_name_fromtext(dns_fixedname_name(&oname),
+ &source, dns_rootname, 0,
+ NULL);
+ if (result != 0) {
+ fprintf(stderr,
+ "dns_name_fromtext() failed: %s\n",
+ dns_result_totext(result));
+ exit(1);
+ }
+ origin = dns_fixedname_name(&oname);
+ }
+ } else if (concatenate) {
+ origin = NULL;
+ } else {
+ origin = dns_rootname;
+ }
+
+ if (argc >= 1) {
+ if (strcasecmp("none", argv[1]) == 0) {
+ comp = NULL;
+ } else {
+ len = strlen(argv[1]);
+ isc_buffer_init(&source, argv[1], len);
+ isc_buffer_add(&source, len);
+ comp = dns_fixedname_initname(&compname);
+ result = dns_name_fromtext(comp, &source, origin, 0,
+ NULL);
+ if (result != 0) {
+ fprintf(stderr,
+ "dns_name_fromtext() failed: %s\n",
+ dns_result_totext(result));
+ exit(1);
+ }
+ }
+ } else {
+ comp = NULL;
+ }
+
+ name = dns_fixedname_initname(&wname);
+ dns_fixedname_init(&wname2);
+ while (fgets(s, sizeof(s), stdin) != NULL) {
+ len = strlen(s);
+ if (len > 0U && s[len - 1] == '\n') {
+ s[len - 1] = '\0';
+ len--;
+ }
+ isc_buffer_init(&source, s, len);
+ isc_buffer_add(&source, len);
+
+ if (len > 0U) {
+ result = dns_name_fromtext(name, &source, origin,
+ downcase, NULL);
+ } else {
+ if (name == dns_fixedname_name(&wname)) {
+ dns_fixedname_init(&wname);
+ } else {
+ dns_fixedname_init(&wname2);
+ }
+ result = ISC_R_SUCCESS;
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ printf("%s\n", dns_result_totext(result));
+ if (name == dns_fixedname_name(&wname)) {
+ dns_fixedname_init(&wname);
+ } else {
+ dns_fixedname_init(&wname2);
+ }
+ continue;
+ }
+
+ if (check_absolute && dns_name_countlabels(name) > 0) {
+ if (dns_name_isabsolute(name)) {
+ printf("absolute\n");
+ } else {
+ printf("relative\n");
+ }
+ }
+ if (check_wildcard && dns_name_countlabels(name) > 0) {
+ if (dns_name_iswildcard(name)) {
+ printf("wildcard\n");
+ } else {
+ printf("not wildcard\n");
+ }
+ }
+ dns_name_toregion(name, &r);
+ if (!quiet) {
+ print_wirename(&r);
+ printf("%u labels, %u bytes.\n",
+ dns_name_countlabels(name), r.length);
+ }
+
+ if (concatenate) {
+ if (got_name) {
+ printf("Concatenating.\n");
+ result = dns_name_concatenate(
+ dns_fixedname_name(&wname),
+ dns_fixedname_name(&wname2),
+ dns_fixedname_name(&wname2), NULL);
+ name = dns_fixedname_name(&wname2);
+ if (result == ISC_R_SUCCESS) {
+ if (check_absolute &&
+ dns_name_countlabels(name) > 0)
+ {
+ if (dns_name_isabsolute(name)) {
+ printf("absolute\n");
+ } else {
+ printf("relative\n");
+ }
+ }
+ if (check_wildcard &&
+ dns_name_countlabels(name) > 0)
+ {
+ if (dns_name_iswildcard(name)) {
+ printf("wildcard\n");
+ } else {
+ printf("not "
+ "wildcard\n");
+ }
+ }
+ dns_name_toregion(name, &r);
+ if (!quiet) {
+ print_wirename(&r);
+ printf("%u labels, "
+ "%u bytes.\n",
+ dns_name_countlabels(
+ name),
+ r.length);
+ }
+ } else {
+ printf("%s\n",
+ dns_result_totext(result));
+ }
+ got_name = false;
+ } else {
+ got_name = true;
+ }
+ }
+ isc_buffer_init(&source, s, sizeof(s));
+ if (dns_name_countlabels(name) > 0) {
+ result = dns_name_totext(name, false, &source);
+ } else {
+ result = ISC_R_SUCCESS;
+ }
+ if (result == ISC_R_SUCCESS) {
+ isc_buffer_usedregion(&source, &r);
+ if (r.length > 0) {
+ printf("%.*s\n", (int)r.length, r.base);
+ } else {
+ printf("<empty text name>\n");
+ }
+ if (!quiet) {
+ printf("%u bytes.\n", source.used);
+ }
+ } else {
+ printf("%s\n", dns_result_totext(result));
+ }
+
+ if (test_downcase) {
+ if (inplace) {
+ down = name;
+ } else {
+ down = dns_fixedname_initname(&downname);
+ }
+ result = dns_name_downcase(name, down, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+ if (!quiet) {
+ dns_name_toregion(down, &r);
+ print_wirename(&r);
+ printf("%u labels, %u bytes.\n",
+ dns_name_countlabels(down), r.length);
+ }
+ isc_buffer_init(&source, s, sizeof(s));
+ print_name(down);
+ }
+
+ if (comp != NULL && dns_name_countlabels(name) > 0) {
+ int order;
+ unsigned int nlabels;
+ dns_namereln_t namereln;
+
+ namereln = dns_name_fullcompare(name, comp, &order,
+ &nlabels);
+ if (!quiet) {
+ if (order < 0) {
+ printf("<");
+ } else if (order > 0) {
+ printf(">");
+ } else {
+ printf("=");
+ }
+ switch (namereln) {
+ case dns_namereln_contains:
+ printf(", contains");
+ break;
+ case dns_namereln_subdomain:
+ printf(", subdomain");
+ break;
+ case dns_namereln_commonancestor:
+ printf(", common ancestor");
+ break;
+ default:
+ break;
+ }
+ if (namereln != dns_namereln_none &&
+ namereln != dns_namereln_equal)
+ {
+ printf(", nlabels = %u", nlabels);
+ }
+ printf("\n");
+ }
+ printf("dns_name_equal() returns %s\n",
+ dns_name_equal(name, comp) ? "TRUE" : "FALSE");
+ }
+
+ labels = dns_name_countlabels(name);
+ if (want_split && split_label < labels) {
+ prefix = dns_fixedname_initname(&fprefix);
+ suffix = dns_fixedname_initname(&fsuffix);
+ printf("splitting at label %u: ", split_label);
+ dns_name_split(name, split_label, prefix, suffix);
+ printf("\n prefix = ");
+ print_name(prefix);
+ printf(" suffix = ");
+ print_name(suffix);
+ }
+
+ if (concatenate) {
+ if (got_name) {
+ name = dns_fixedname_name(&wname2);
+ } else {
+ name = dns_fixedname_name(&wname);
+ }
+ }
+ }
+
+ return (0);
+}
diff --git a/bin/tests/optional/nsecify.c b/bin/tests/optional/nsecify.c
new file mode 100644
index 0000000..357b47f
--- /dev/null
+++ b/bin/tests/optional/nsecify.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/fixedname.h>
+#include <dns/nsec.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/result.h>
+
+static isc_mem_t *mctx = NULL;
+
+ISC_PLATFORM_NORETURN_PRE static void
+fatal(const char *message) ISC_PLATFORM_NORETURN_POST;
+
+static void
+fatal(const char *message) {
+ fprintf(stderr, "%s\n", message);
+ exit(1);
+}
+
+static void
+check_result(isc_result_t result, const char *message) {
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "%s: %s\n", message, isc_result_totext(result));
+ exit(1);
+ }
+}
+
+static bool
+active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
+ dns_rdatasetiter_t *rdsiter;
+ bool active = false;
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+
+ dns_rdataset_init(&rdataset);
+ rdsiter = NULL;
+ result = dns_db_allrdatasets(db, node, version, 0, 0, &rdsiter);
+ check_result(result, "dns_db_allrdatasets()");
+ result = dns_rdatasetiter_first(rdsiter);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ if (rdataset.type != dns_rdatatype_nsec) {
+ active = true;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (!active) {
+ result = dns_rdatasetiter_next(rdsiter);
+ } else {
+ result = ISC_R_NOMORE;
+ }
+ }
+ if (result != ISC_R_NOMORE) {
+ fatal("rdataset iteration failed");
+ }
+ dns_rdatasetiter_destroy(&rdsiter);
+
+ if (!active) {
+ /*
+ * Make sure there is no NSEC record for this node.
+ */
+ result = dns_db_deleterdataset(db, node, version,
+ dns_rdatatype_nsec, 0);
+ if (result == DNS_R_UNCHANGED) {
+ result = ISC_R_SUCCESS;
+ }
+ check_result(result, "dns_db_deleterdataset");
+ }
+
+ return (active);
+}
+
+static isc_result_t
+next_active(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
+ dns_name_t *name, dns_dbnode_t **nodep) {
+ isc_result_t result;
+ bool active;
+
+ do {
+ active = false;
+ result = dns_dbiterator_current(dbiter, nodep, name);
+ if (result == ISC_R_SUCCESS) {
+ active = active_node(db, version, *nodep);
+ if (!active) {
+ dns_db_detachnode(db, nodep);
+ result = dns_dbiterator_next(dbiter);
+ }
+ }
+ } while (result == ISC_R_SUCCESS && !active);
+
+ return (result);
+}
+
+static void
+nsecify(char *filename) {
+ isc_result_t result;
+ dns_db_t *db;
+ dns_dbversion_t *wversion;
+ dns_dbnode_t *node, *nextnode;
+ const char *origintext;
+ dns_fixedname_t fname, fnextname;
+ dns_name_t *name, *nextname, *target;
+ isc_buffer_t b;
+ size_t len;
+ dns_dbiterator_t *dbiter;
+ char newfilename[1024];
+
+ name = dns_fixedname_initname(&fname);
+ nextname = dns_fixedname_initname(&fnextname);
+
+ origintext = strrchr(filename, '/');
+ if (origintext == NULL) {
+ origintext = filename;
+ } else {
+ origintext++; /* Skip '/'. */
+ }
+ len = strlen(origintext);
+ isc_buffer_constinit(&b, origintext, len);
+ isc_buffer_add(&b, len);
+ result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
+ check_result(result, "dns_name_fromtext()");
+
+ db = NULL;
+ result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db);
+ check_result(result, "dns_db_create()");
+ result = dns_db_load(db, filename, dns_masterformat_text, 0);
+ if (result == DNS_R_SEENINCLUDE) {
+ result = ISC_R_SUCCESS;
+ }
+ check_result(result, "dns_db_load()");
+ wversion = NULL;
+ result = dns_db_newversion(db, &wversion);
+ check_result(result, "dns_db_newversion()");
+ dbiter = NULL;
+ result = dns_db_createiterator(db, 0, &dbiter);
+ check_result(result, "dns_db_createiterator()");
+ result = dns_dbiterator_first(dbiter);
+ check_result(result, "dns_dbiterator_first()");
+ node = NULL;
+ result = next_active(db, wversion, dbiter, name, &node);
+ while (result == ISC_R_SUCCESS) {
+ nextnode = NULL;
+ result = dns_dbiterator_next(dbiter);
+ if (result == ISC_R_SUCCESS) {
+ result = next_active(db, wversion, dbiter, nextname,
+ &nextnode);
+ }
+ if (result == ISC_R_SUCCESS) {
+ target = nextname;
+ } else if (result == ISC_R_NOMORE) {
+ target = dns_db_origin(db);
+ } else {
+ target = NULL; /* Make compiler happy. */
+ fatal("db iteration failed");
+ }
+ dns_nsec_build(db, wversion, node, target, 3600); /* XXX BEW */
+ dns_db_detachnode(db, &node);
+ node = nextnode;
+ }
+ if (result != ISC_R_NOMORE) {
+ fatal("db iteration failed");
+ }
+ dns_dbiterator_destroy(&dbiter);
+ /*
+ * XXXRTH For now, we don't increment the SOA serial.
+ */
+ dns_db_closeversion(db, &wversion, true);
+ len = strlen(filename);
+ if (len + 4 + 1 > sizeof(newfilename)) {
+ fatal("filename too long");
+ }
+ snprintf(newfilename, sizeof(newfilename), "%s.new", filename);
+ result = dns_db_dump(db, NULL, newfilename);
+ check_result(result, "dns_db_dump");
+ dns_db_detach(&db);
+}
+
+int
+main(int argc, char *argv[]) {
+ int i;
+
+ dns_result_register();
+
+ isc_mem_create(&mctx);
+
+ argc--;
+ argv++;
+
+ for (i = 0; i < argc; i++) {
+ nsecify(argv[i]);
+ }
+
+ /* isc_mem_stats(mctx, stdout); */
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/ratelimiter_test.c b/bin/tests/optional/ratelimiter_test.c
new file mode 100644
index 0000000..c8972f8
--- /dev/null
+++ b/bin/tests/optional/ratelimiter_test.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <isc/app.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/ratelimiter.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+isc_ratelimiter_t *rlim = NULL;
+isc_nm_t *netmgr = NULL;
+isc_taskmgr_t *taskmgr = NULL;
+isc_timermgr_t *timermgr = NULL;
+isc_task_t *g_task = NULL;
+isc_mem_t *mctx = NULL;
+
+static void
+utick(isc_task_t *task, isc_event_t *event);
+static void
+shutdown_rl(isc_task_t *task, isc_event_t *event);
+static void
+shutdown_all(isc_task_t *task, isc_event_t *event);
+
+typedef struct {
+ int milliseconds;
+ void (*fun)(isc_task_t *, isc_event_t *);
+} schedule_t;
+
+schedule_t schedule[] = { { 100, utick }, { 200, utick },
+ { 300, utick }, { 3000, utick },
+ { 3100, utick }, { 3200, utick },
+ { 3300, shutdown_rl }, { 5000, utick },
+ { 6000, shutdown_all } };
+
+#define NEVENTS (int)(sizeof(schedule) / sizeof(schedule[0]))
+
+isc_timer_t *timers[NEVENTS];
+
+static void
+ltick(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+ printf("** ltick%s **\n",
+ (event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ? " ("
+ "canceled"
+ ")"
+ : "");
+ isc_event_free(&event);
+}
+
+static void
+utick(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ UNUSED(task);
+ event->ev_action = ltick;
+ event->ev_sender = NULL;
+ result = isc_ratelimiter_enqueue(rlim, g_task, &event);
+ printf("enqueue: %s\n", result == ISC_R_SUCCESS ? "ok" : "failed");
+}
+
+static void
+shutdown_rl(isc_task_t *task, isc_event_t *event) {
+ UNUSED(task);
+ UNUSED(event);
+ printf("shutdown ratelimiter\n");
+ isc_ratelimiter_shutdown(rlim);
+}
+
+static void
+shutdown_all(isc_task_t *task, isc_event_t *event) {
+ int i;
+ UNUSED(task);
+ UNUSED(event);
+ printf("shutdown all\n");
+ for (i = 0; i < NEVENTS; i++) {
+ isc_timer_destroy(&timers[i]);
+ }
+
+ isc_app_shutdown();
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_interval_t linterval;
+ int i;
+
+ UNUSED(argc);
+ UNUSED(argv);
+
+ isc_app_start();
+ isc_interval_set(&linterval, 1, 0);
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(isc_managers_create(mctx, 3, 0, &netmgr, &taskmgr) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &g_task) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_ratelimiter_create(mctx, timermgr, g_task, &rlim) ==
+ ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_ratelimiter_setinterval(rlim, &linterval) ==
+ ISC_R_SUCCESS);
+
+ for (i = 0; i < NEVENTS; i++) {
+ isc_interval_t uinterval;
+ int ms = schedule[i].milliseconds;
+ isc_interval_set(&uinterval, ms / 1000, (ms % 1000) * 1000000);
+ timers[i] = NULL;
+ RUNTIME_CHECK(isc_timer_create(timermgr, isc_timertype_once,
+ NULL, &uinterval, g_task,
+ schedule[i].fun, NULL,
+ &timers[i]) == ISC_R_SUCCESS);
+ }
+
+ isc_app_run();
+
+ isc_task_destroy(&g_task);
+
+ isc_ratelimiter_detach(&rlim);
+
+ isc_timermgr_destroy(&timermgr);
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_mem_stats(mctx, stdout);
+
+ isc_app_finish();
+ return (0);
+}
diff --git a/bin/tests/optional/rbt_test.c b/bin/tests/optional/rbt_test.c
new file mode 100644
index 0000000..735c229
--- /dev/null
+++ b/bin/tests/optional/rbt_test.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/rbt.h>
+#include <dns/result.h>
+
+const char *progname;
+isc_mem_t *mctx;
+
+#define DNSNAMELEN 255
+
+static dns_name_t *
+create_name(char *s) {
+ int length;
+ isc_result_t result;
+ isc_buffer_t source, target;
+ static dns_name_t *name;
+
+ if (s == NULL || *s == '\0') {
+ printf("missing name argument\n");
+ return (NULL);
+ }
+
+ length = strlen(s);
+
+ isc_buffer_init(&source, s, length);
+ isc_buffer_add(&source, length);
+
+ /*
+ * It isn't really necessary in this program to create individual
+ * memory spaces for each name structure and its associated character
+ * string. It is done here to provide a relatively easy way to test
+ * the callback from dns_rbt_deletename that is supposed to free the
+ * data associated with a node.
+ *
+ * The buffer for the actual name will immediately follow the
+ * name structure.
+ */
+ name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN);
+
+ dns_name_init(name, NULL);
+ isc_buffer_init(&target, name + 1, DNSNAMELEN);
+
+ result = dns_name_fromtext(name, &source, dns_rootname, 0, &target);
+
+ if (result != ISC_R_SUCCESS) {
+ printf("dns_name_fromtext(%s) failed: %s\n", s,
+ dns_result_totext(result));
+ return (NULL);
+ }
+
+ return (name);
+}
+
+static void
+delete_name(void *data, void *arg) {
+ dns_name_t *name;
+
+ UNUSED(arg);
+ name = data;
+ isc_mem_put(mctx, name, sizeof(*name) + DNSNAMELEN);
+}
+
+static void
+print_name(dns_name_t *name) {
+ isc_buffer_t target;
+ char buffer[1024];
+
+ isc_buffer_init(&target, buffer, sizeof(buffer));
+
+ /*
+ * false means absolute names have the final dot added.
+ */
+ dns_name_totext(name, false, &target);
+
+ printf("%.*s", (int)target.used, (char *)target.base);
+}
+
+static void
+detail(dns_rbt_t *rbt, dns_name_t *name) {
+ dns_name_t *foundname, *origin, *fullname;
+ dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
+ dns_rbtnode_t *node1, *node2;
+ dns_rbtnodechain_t chain;
+ isc_result_t result;
+ bool nodes_should_match = false;
+
+ dns_rbtnodechain_init(&chain);
+
+ origin = dns_fixedname_initname(&fixedorigin);
+ fullname = dns_fixedname_initname(&fixedfullname);
+ foundname = dns_fixedname_initname(&fixedfoundname);
+
+ node1 = node2 = NULL;
+
+ printf("checking chain information for ");
+ print_name(name);
+ printf("\n");
+
+ result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+
+ switch (result) {
+ case ISC_R_SUCCESS:
+ printf(" found exact.");
+ nodes_should_match = true;
+ break;
+ case DNS_R_PARTIALMATCH:
+ printf(" found parent.");
+ break;
+ case ISC_R_NOTFOUND:
+ printf(" name not found.");
+ break;
+ default:
+ printf(" unexpected result: %s\n", dns_result_totext(result));
+ return;
+ }
+
+ if (node1 != NULL && node1->data != NULL) {
+ printf(" data at node: ");
+ print_name(node1->data);
+ } else {
+ printf(" no data at node.");
+ }
+
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ printf("\n name from dns_rbt_findnode: ");
+ print_name(foundname);
+ }
+
+ result = dns_rbtnodechain_current(&chain, foundname, origin, &node2);
+
+ if (result == ISC_R_SUCCESS) {
+ printf("\n name from dns_rbtnodechain_current: ");
+
+ result = dns_name_concatenate(foundname, origin, fullname,
+ NULL);
+ if (result == ISC_R_SUCCESS) {
+ print_name(fullname);
+ } else {
+ printf("%s\n", dns_result_totext(result));
+ }
+ printf("\n (foundname = ");
+ print_name(foundname);
+ printf(", origin = ");
+ print_name(origin);
+ printf(")\n");
+ if (nodes_should_match && node1 != node2) {
+ printf(" nodes returned from each function "
+ "DO NOT match!\n");
+ }
+ } else {
+ printf("\n result from dns_rbtnodechain_current: %s\n",
+ dns_result_totext(result));
+ }
+
+ printf(" level_matches = %u, level_count = %u\n", chain.level_matches,
+ chain.level_count);
+}
+
+static void
+iterate(dns_rbt_t *rbt, bool forward) {
+ dns_name_t foundname, *origin;
+ dns_rbtnodechain_t chain;
+ dns_fixedname_t fixedorigin;
+ isc_result_t result;
+ isc_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin);
+
+ dns_rbtnodechain_init(&chain);
+
+ dns_name_init(&foundname, NULL);
+ origin = dns_fixedname_initname(&fixedorigin);
+
+ if (forward) {
+ printf("iterating forward\n");
+ move = dns_rbtnodechain_next;
+
+ result = dns_rbtnodechain_first(&chain, rbt, &foundname,
+ origin);
+ } else {
+ printf("iterating backward\n");
+ move = dns_rbtnodechain_prev;
+
+ result = dns_rbtnodechain_last(&chain, rbt, &foundname, origin);
+ }
+
+ if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+ printf("start not found!\n");
+ } else {
+ for (;;) {
+ if (result == DNS_R_NEWORIGIN) {
+ printf(" new origin: ");
+ print_name(origin);
+ printf("\n");
+ }
+
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NEWORIGIN)
+ {
+ print_name(&foundname);
+ printf("\n");
+ } else {
+ if (result != ISC_R_NOMORE) {
+ printf("UNEXPECTED ITERATION ERROR: %s",
+ dns_result_totext(result));
+ }
+ break;
+ }
+
+ result = move(&chain, &foundname, origin);
+ }
+ }
+}
+
+#define CMDCHECK(s) (strncasecmp(command, (s), length) == 0)
+#define PRINTERR(r) \
+ if (r != ISC_R_SUCCESS) \
+ printf("... %s\n", dns_result_totext(r));
+
+int
+main(int argc, char **argv) {
+ char *command, *arg, buffer[1024];
+ const char *whitespace;
+ dns_name_t *name, *foundname;
+ dns_fixedname_t fixedname;
+ dns_rbt_t *rbt = NULL;
+ int length, ch;
+ bool show_final_mem = false;
+ isc_result_t result;
+ void *data;
+
+ progname = strrchr(*argv, '/');
+ if (progname != NULL) {
+ progname++;
+ } else {
+ progname = *argv;
+ }
+
+ while ((ch = isc_commandline_parse(argc, argv, "m")) != -1) {
+ switch (ch) {
+ case 'm':
+ show_final_mem = true;
+ break;
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+ POST(argv);
+
+ if (argc > 1) {
+ printf("Usage: %s [-m]\n", progname);
+ exit(1);
+ }
+
+ setbuf(stdout, NULL);
+
+ /*
+ * So isc_mem_stats() can report any allocation leaks.
+ */
+ isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+
+ isc_mem_create(&mctx);
+
+ result = dns_rbt_create(mctx, delete_name, NULL, &rbt);
+ if (result != ISC_R_SUCCESS) {
+ printf("dns_rbt_create: %s: exiting\n",
+ dns_result_totext(result));
+ exit(1);
+ }
+
+ whitespace = " \t";
+
+ while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
+ length = strlen(buffer);
+
+ if (buffer[length - 1] != '\n') {
+ printf("line to long (%lu max), ignored\n",
+ (unsigned long)sizeof(buffer) - 2);
+ continue;
+ }
+
+ buffer[length - 1] = '\0';
+
+ command = buffer + strspn(buffer, whitespace);
+
+ if (*command == '#') {
+ continue;
+ }
+
+ arg = strpbrk(command, whitespace);
+ if (arg != NULL) {
+ *arg++ = '\0';
+ arg += strspn(arg, whitespace);
+ }
+
+ length = strlen(command);
+ if (*command != '\0') {
+ if (CMDCHECK("add")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("adding name %s\n", arg);
+ result = dns_rbt_addname(rbt, name,
+ name);
+ PRINTERR(result);
+ }
+ } else if (CMDCHECK("delete")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("deleting name %s\n", arg);
+ result = dns_rbt_deletename(rbt, name,
+ false);
+ PRINTERR(result);
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("nuke")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("nuking name %s "
+ "and its descendants\n",
+ arg);
+ result = dns_rbt_deletename(rbt, name,
+ true);
+ PRINTERR(result);
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("search")) {
+ name = create_name(arg);
+ if (name != NULL) {
+ printf("searching for name %s ... ",
+ arg);
+
+ foundname = dns_fixedname_initname(
+ &fixedname);
+ data = NULL;
+
+ result = dns_rbt_findname(
+ rbt, name, 0, foundname, &data);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ printf("found exact: ");
+ print_name(data);
+ putchar('\n');
+ break;
+ case DNS_R_PARTIALMATCH:
+ printf("found parent: ");
+ print_name(data);
+ printf("\n\t(foundname: ");
+ print_name(foundname);
+ printf(")\n");
+ break;
+ case ISC_R_NOTFOUND:
+ printf("NOT FOUND!\n");
+ break;
+ case ISC_R_NOMEMORY:
+ printf("OUT OF MEMORY!\n");
+ break;
+ default:
+ printf("UNEXPECTED RESULT\n");
+ }
+
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("check")) {
+ /*
+ * Or "chain". I know, I know. Lame name.
+ * I was having a hard time thinking of a
+ * name (especially one that did not have
+ * a conflicting first letter with another
+ * command) that would differentiate this
+ * from the search command.
+ *
+ * But it is just a test program, eh?
+ */
+ name = create_name(arg);
+ if (name != NULL) {
+ detail(rbt, name);
+
+ delete_name(name, NULL);
+ }
+ } else if (CMDCHECK("forward")) {
+ iterate(rbt, true);
+ } else if (CMDCHECK("backward")) {
+ iterate(rbt, false);
+ } else if (CMDCHECK("print")) {
+ if (arg == NULL || *arg == '\0') {
+ dns_rbt_printtext(rbt, NULL, stdout);
+ } else {
+ printf("usage: print\n");
+ }
+ } else if (CMDCHECK("quit")) {
+ if (arg == NULL || *arg == '\0') {
+ break;
+ } else {
+ printf("usage: quit\n");
+ }
+ } else {
+ printf("a(dd) NAME, d(elete) NAME, "
+ "s(earch) NAME, p(rint), or q(uit)\n");
+ }
+ }
+ }
+
+ dns_rbt_destroy(&rbt);
+
+ if (show_final_mem) {
+ isc_mem_stats(mctx, stderr);
+ }
+
+ return (0);
+}
diff --git a/bin/tests/optional/rbt_test.out b/bin/tests/optional/rbt_test.out
new file mode 100644
index 0000000..95bf4f9
--- /dev/null
+++ b/bin/tests/optional/rbt_test.out
@@ -0,0 +1,395 @@
+adding name a.vix.com
+adding name b.vix.com
+adding name c.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (RED from b)
+ NULL
+ NULL
+ c (RED from b)
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+adding name a.b.c.d.e.f.vix.com
+adding name b.b.c.d.e.f.vix.com
+adding name c.b.c.d.e.f.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (black from b)
+ NULL
+ NULL
+ c (black from b)
+ NULL
+ b.c.d.e.f (RED from c)
+ ++ BEG down from b.c.d.e.f
+ b (black)
+ a (RED from b)
+ NULL
+ NULL
+ c (RED from b)
+ NULL
+ NULL
+ -- END down from b.c.d.e.f
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+adding name a.d.e.f.vix.com
+adding name q.d.e.f.vix.com
+adding name d.e.f.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (black from b)
+ NULL
+ NULL
+ c (black from b)
+ NULL
+ d.e.f (RED from c)
+ ++ BEG down from d.e.f
+ b.c (black)
+ ++ BEG down from b.c
+ b (black)
+ a (RED from b)
+ NULL
+ NULL
+ c (RED from b)
+ NULL
+ NULL
+ -- END down from b.c
+ a (RED from b.c)
+ NULL
+ NULL
+ q (RED from b.c)
+ NULL
+ NULL
+ -- END down from d.e.f
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+adding name g.h.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (black from b)
+ NULL
+ NULL
+ d.e.f (black from b)
+ ++ BEG down from d.e.f
+ b.c (black)
+ ++ BEG down from b.c
+ b (black)
+ a (RED from b)
+ NULL
+ NULL
+ c (RED from b)
+ NULL
+ NULL
+ -- END down from b.c
+ a (RED from b.c)
+ NULL
+ NULL
+ q (RED from b.c)
+ NULL
+ NULL
+ -- END down from d.e.f
+ c (RED from d.e.f)
+ NULL
+ NULL
+ g.h (RED from d.e.f)
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+searching for name q.d.e.f.vix.com ... found exact: q.d.e.f.vix.com.
+searching for name just-parent.a.vix.com ... found parent: a.vix.com.
+ (foundname: a.vix.com.)
+searching for name no-real-parent.vix.com ... NOT FOUND!
+searching for name does.not.exist.at.all ... NOT FOUND!
+iterating forward
+ new origin: .
+vix.com
+ new origin: vix.com.
+a
+b
+c
+d.e.f
+ new origin: d.e.f.vix.com.
+a
+b.c
+ new origin: b.c.d.e.f.vix.com.
+a
+b
+c
+ new origin: d.e.f.vix.com.
+q
+ new origin: vix.com.
+g.h
+iterating backward
+ new origin: vix.com.
+g.h
+ new origin: d.e.f.vix.com.
+q
+ new origin: b.c.d.e.f.vix.com.
+c
+b
+a
+ new origin: d.e.f.vix.com.
+b.c
+a
+ new origin: vix.com.
+d.e.f
+c
+b
+a
+ new origin: .
+vix.com
+checking chain information for vix.com.
+ found exact. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: vix.com.
+ (foundname = vix.com, origin = .)
+ level_matches = 0, level_count = 0
+checking chain information for zzz.com.
+ name not found. no data at node.
+ name from dns_rbtnodechain_current: g.h.vix.com.
+ (foundname = g.h, origin = vix.com.)
+ level_matches = 0, level_count = 1
+checking chain information for 0.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: vix.com.
+ (foundname = vix.com, origin = .)
+ level_matches = 0, level_count = 0
+checking chain information for d.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: c.vix.com.
+ (foundname = c, origin = vix.com.)
+ level_matches = 0, level_count = 1
+checking chain information for f.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: c.vix.com.
+ (foundname = c, origin = vix.com.)
+ level_matches = 0, level_count = 1
+checking chain information for a.e.f.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: c.vix.com.
+ (foundname = c, origin = vix.com.)
+ level_matches = 0, level_count = 1
+checking chain information for z.e.f.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: q.d.e.f.vix.com.
+ (foundname = q, origin = d.e.f.vix.com.)
+ level_matches = 0, level_count = 2
+checking chain information for g.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: q.d.e.f.vix.com.
+ (foundname = q, origin = d.e.f.vix.com.)
+ level_matches = 0, level_count = 2
+checking chain information for i.vix.com.
+ found parent. no data at node.
+ name from dns_rbt_findnode: vix.com.
+ name from dns_rbtnodechain_current: g.h.vix.com.
+ (foundname = g.h, origin = vix.com.)
+ level_matches = 0, level_count = 1
+checking chain information for b.c.vix.com.
+ found parent. data at node: c.vix.com.
+ name from dns_rbt_findnode: c.vix.com.
+ name from dns_rbtnodechain_current: c.vix.com.
+ (foundname = c, origin = vix.com.)
+ level_matches = 1, level_count = 1
+nuking name d.e.f.vix.com and its descendants
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (black from b)
+ NULL
+ NULL
+ g.h (black from b)
+ c (RED from g.h)
+ NULL
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+adding name x.a.vix.com
+adding name y.x.a.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (black from b)
+ ++ BEG down from a
+ x (black)
+ ++ BEG down from x
+ y (black)
+ NULL
+ NULL
+ -- END down from x
+ NULL
+ NULL
+ -- END down from a
+ NULL
+ NULL
+ g.h (black from b)
+ c (RED from g.h)
+ NULL
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+deleting name a.vix.com
+deleting name x.a.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ b (black)
+ a (black from b)
+ ++ BEG down from a
+ x (black)
+ ++ BEG down from x
+ y (black)
+ NULL
+ NULL
+ -- END down from x
+ NULL
+ NULL
+ -- END down from a
+ NULL
+ NULL
+ g.h (black from b)
+ c (RED from g.h)
+ NULL
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+deleting name b.vix.com
+deleting name c.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ g.h (black)
+ a (RED from g.h)
+ ++ BEG down from a
+ x (black)
+ ++ BEG down from x
+ y (black)
+ NULL
+ NULL
+ -- END down from x
+ NULL
+ NULL
+ -- END down from a
+ NULL
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+deleting name y.x.a.vix.com
+vix.com. (black)
+ ++ BEG down from vix.com.
+ g.h (black)
+ a (RED from g.h)
+ ++ BEG down from a
+ x (black)
+ NULL
+ NULL
+ -- END down from a
+ NULL
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+deleting name g.h.vix.com.
+adding name \[b100000].vix.com.
+adding name \[b010000].vix.com.
+adding name \[b001000].vix.com.
+adding name \[b000100].vix.com.
+adding name \[b000010].vix.com.
+adding name \[b000001].vix.com.
+vix.com. (black)
+ ++ BEG down from vix.com.
+ \[x80/6] (black)
+ \[x0/1] (RED from \[x80/6])
+ ++ BEG down from \[x0/1]
+ \[x80/5] (black)
+ \[x0/1] (RED from \[x80/5])
+ ++ BEG down from \[x0/1]
+ \[x8/4] (black)
+ \[x0/1] (RED from \[x8/4])
+ ++ BEG down from \[x0/1]
+ \[x8/3] (black)
+ \[x0/1] (RED from \[x8/3])
+ ++ BEG down from \[x0/1]
+ \[x8/2] (black)
+ \[x4/2] (RED from \[x8/2])
+ NULL
+ NULL
+ NULL
+ -- END down from \[x0/1]
+ NULL
+ NULL
+ NULL
+ -- END down from \[x0/1]
+ NULL
+ NULL
+ NULL
+ -- END down from \[x0/1]
+ NULL
+ NULL
+ NULL
+ -- END down from \[x0/1]
+ NULL
+ NULL
+ a (RED from \[x80/6])
+ ++ BEG down from a
+ x (black)
+ NULL
+ NULL
+ -- END down from a
+ NULL
+ NULL
+ -- END down from vix.com.
+ NULL
+ NULL
+searching for name \[b000100].vix.com. ... found exact: \[x10/6].vix.com.
+adding name vix.com.
+nuking name vix.com. and its descendants
+adding name a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.
+adding name b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.
+b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. (black)
+ ++ BEG down from b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.
+ a (black)
+ NULL
+ NULL
+ -- END down from b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.
+ NULL
+ NULL
+adding name .
+nuking name . and its descendants
+adding name \[xFFFF/16].\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/256].com
+adding name \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com
+\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com. (black)
+ ++ BEG down from \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com.
+ \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/144] (black)
+ NULL
+ NULL
+ -- END down from \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com.
+ NULL
+ NULL
diff --git a/bin/tests/optional/rbt_test.txt b/bin/tests/optional/rbt_test.txt
new file mode 100644
index 0000000..e44d72e
--- /dev/null
+++ b/bin/tests/optional/rbt_test.txt
@@ -0,0 +1,87 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+add a.vix.com
+add b.vix.com
+add c.vix.com
+print
+add a.b.c.d.e.f.vix.com
+add b.b.c.d.e.f.vix.com
+add c.b.c.d.e.f.vix.com
+print
+add a.d.e.f.vix.com
+add q.d.e.f.vix.com
+add d.e.f.vix.com
+print
+add g.h.vix.com
+print
+search q.d.e.f.vix.com
+search just-parent.a.vix.com
+search no-real-parent.vix.com
+search does.not.exist.at.all
+forward
+backward
+# existing name
+check vix.com.
+# greater than stop node, which has down pointer
+check zzz.com.
+# less than lowest in level (would be left link from stop node)
+check 0.vix.com
+# greater than stop node, no down pointer
+check d.vix.com
+# superdomain stored in existing node
+check f.vix.com
+# common ancestor stored in existing node; existing is successor
+check a.e.f.vix.com
+# common ancestor stored in existing node; existing is less but not predecessor
+check z.e.f.vix.com
+#
+check g.vix.com
+#
+check i.vix.com
+#
+check b.c.vix.com
+nuke d.e.f.vix.com
+print
+add x.a.vix.com
+add y.x.a.vix.com
+print
+delete a.vix.com
+delete x.a.vix.com
+print
+delete b.vix.com
+delete c.vix.com
+print
+delete y.x.a.vix.com
+print
+delete g.h.vix.com.
+add \[b100000].vix.com.
+add \[b010000].vix.com.
+add \[b001000].vix.com.
+add \[b000100].vix.com.
+add \[b000010].vix.com.
+add \[b000001].vix.com.
+p
+search \[b000100].vix.com.
+# zap the entire tree
+add vix.com.
+nuke vix.com.
+add a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.
+add b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.
+print
+add .
+# zap it again
+nuke .
+# test splitting of maximal bitstring
+add \[xFFFF/16].\[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/256].com
+add \[xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/128].com
+print
+quit
diff --git a/bin/tests/optional/rwlock_test.c b/bin/tests/optional/rwlock_test.c
new file mode 100644
index 0000000..fc94eaf
--- /dev/null
+++ b/bin/tests/optional/rwlock_test.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/print.h>
+#include <isc/rwlock.h>
+#include <isc/string.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#ifdef WIN32
+#define sleep(x) Sleep(1000 * x)
+#endif /* ifdef WIN32 */
+
+isc_rwlock_t lock;
+
+static isc_threadresult_t
+#ifdef WIN32
+ WINAPI
+#endif /* ifdef WIN32 */
+ run1(void *arg) {
+ char *message = arg;
+
+ RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) ==
+ ISC_R_SUCCESS);
+ printf("%s got READ lock\n", message);
+ sleep(1);
+ printf("%s giving up READ lock\n", message);
+ RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) ==
+ ISC_R_SUCCESS);
+ printf("%s got READ lock\n", message);
+ sleep(1);
+ printf("%s giving up READ lock\n", message);
+ RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) ==
+ ISC_R_SUCCESS);
+ printf("%s got WRITE lock\n", message);
+ sleep(1);
+ printf("%s giving up WRITE lock\n", message);
+ RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) ==
+ ISC_R_SUCCESS);
+ return ((isc_threadresult_t)0);
+}
+
+static isc_threadresult_t
+#ifdef WIN32
+ WINAPI
+#endif /* ifdef WIN32 */
+ run2(void *arg) {
+ char *message = arg;
+
+ RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) ==
+ ISC_R_SUCCESS);
+ printf("%s got WRITE lock\n", message);
+ sleep(1);
+ printf("%s giving up WRITE lock\n", message);
+ RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_write) ==
+ ISC_R_SUCCESS);
+ printf("%s got WRITE lock\n", message);
+ sleep(1);
+ printf("%s giving up WRITE lock\n", message);
+ RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_write) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_rwlock_lock(&lock, isc_rwlocktype_read) ==
+ ISC_R_SUCCESS);
+ printf("%s got READ lock\n", message);
+ sleep(1);
+ printf("%s giving up READ lock\n", message);
+ RUNTIME_CHECK(isc_rwlock_unlock(&lock, isc_rwlocktype_read) ==
+ ISC_R_SUCCESS);
+ return ((isc_threadresult_t)0);
+}
+
+int
+main(int argc, char *argv[]) {
+ unsigned int nworkers;
+ unsigned int i;
+ isc_thread_t workers[100];
+ char name[100];
+ void *dupname;
+
+ if (argc > 1) {
+ nworkers = atoi(argv[1]);
+ } else {
+ nworkers = 2;
+ }
+ if (nworkers > 100) {
+ nworkers = 100;
+ }
+ printf("%u workers\n", nworkers);
+
+ isc_rwlock_init(&lock, 5, 10);
+
+ for (i = 0; i < nworkers; i++) {
+ snprintf(name, sizeof(name), "%02u", i);
+ dupname = strdup(name);
+ RUNTIME_CHECK(dupname != NULL);
+ if (i != 0 && i % 3 == 0) {
+ isc_thread_create(run1, dupname, &workers[i]);
+ } else {
+ isc_thread_create(run2, dupname, &workers[i]);
+ }
+ }
+
+ for (i = 0; i < nworkers; i++) {
+ isc_thread_join(workers[i], NULL);
+ }
+
+ isc_rwlock_destroy(&lock);
+
+ return (0);
+}
diff --git a/bin/tests/optional/serial_test.c b/bin/tests/optional/serial_test.c
new file mode 100644
index 0000000..c16acc0
--- /dev/null
+++ b/bin/tests/optional/serial_test.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/print.h>
+#include <isc/serial.h>
+
+int
+main() {
+ uint32_t a, b;
+ char buf[1024];
+ char *s, *e;
+
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ buf[sizeof(buf) - 1] = '\0';
+ s = buf;
+ a = strtoul(s, &e, 0);
+ if (s == e) {
+ continue;
+ }
+ s = e;
+ b = strtoul(s, &e, 0);
+ if (s == e) {
+ continue;
+ }
+ fprintf(stdout, "%u %u gt:%d lt:%d ge:%d le:%d eq:%d ne:%d\n",
+ a, b, isc_serial_gt(a, b), isc_serial_lt(a, b),
+ isc_serial_ge(a, b), isc_serial_le(a, b),
+ isc_serial_eq(a, b), isc_serial_ne(a, b));
+ }
+ return (0);
+}
diff --git a/bin/tests/optional/shutdown_test.c b/bin/tests/optional/shutdown_test.c
new file mode 100644
index 0000000..c8cf03c
--- /dev/null
+++ b/bin/tests/optional/shutdown_test.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/app.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+typedef struct {
+ isc_mem_t *mctx;
+ isc_task_t *task;
+ isc_timer_t *timer;
+ unsigned int ticks;
+ char name[16];
+ bool exiting;
+ isc_task_t *peer;
+} t_info;
+
+#define MAX_TASKS 3
+#define T2_SHUTDOWNOK (ISC_EVENTCLASS(1024) + 0)
+#define T2_SHUTDOWNDONE (ISC_EVENTCLASS(1024) + 1)
+#define FOO_EVENT (ISC_EVENTCLASS(1024) + 2)
+
+static t_info tasks[MAX_TASKS];
+static unsigned int task_count;
+static isc_nm_t *netmgr = NULL;
+static isc_taskmgr_t *taskmgr = NULL;
+static isc_timermgr_t *timer_manager;
+
+static void
+t1_shutdown(isc_task_t *task, isc_event_t *event) {
+ t_info *info = event->ev_arg;
+
+ printf("task %s (%p) t1_shutdown\n", info->name, task);
+ isc_task_detach(&info->task);
+ isc_event_free(&event);
+}
+
+static void
+t2_shutdown(isc_task_t *task, isc_event_t *event) {
+ t_info *info = event->ev_arg;
+
+ printf("task %s (%p) t2_shutdown\n", info->name, task);
+ info->exiting = true;
+ isc_event_free(&event);
+}
+
+static void
+shutdown_action(isc_task_t *task, isc_event_t *event) {
+ t_info *info = event->ev_arg;
+ isc_event_t *nevent;
+
+ INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
+
+ printf("task %s (%p) shutdown\n", info->name, task);
+ if (strcmp(info->name, "0") == 0) {
+ isc_timer_destroy(&info->timer);
+ nevent = isc_event_allocate(info->mctx, info, T2_SHUTDOWNOK,
+ t2_shutdown, &tasks[1],
+ sizeof(*event));
+ RUNTIME_CHECK(nevent != NULL);
+ info->exiting = true;
+ isc_task_sendanddetach(&info->peer, &nevent);
+ }
+ isc_event_free(&event);
+}
+
+static void
+foo_event(isc_task_t *task, isc_event_t *event) {
+ printf("task(%p) foo\n", task);
+ isc_event_free(&event);
+}
+
+static void
+tick(isc_task_t *task, isc_event_t *event) {
+ t_info *info = event->ev_arg;
+ isc_event_t *nevent;
+
+ INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
+
+ printf("task %s (%p) tick\n", info->name, task);
+
+ info->ticks++;
+ if (strcmp(info->name, "1") == 0) {
+ if (info->ticks == 10) {
+ isc_app_shutdown();
+ } else if (info->ticks >= 15 && info->exiting) {
+ isc_timer_destroy(&info->timer);
+ isc_task_detach(&info->task);
+ nevent = isc_event_allocate(
+ info->mctx, info, T2_SHUTDOWNDONE, t1_shutdown,
+ &tasks[0], sizeof(*event));
+ RUNTIME_CHECK(nevent != NULL);
+ isc_task_send(info->peer, &nevent);
+ isc_task_detach(&info->peer);
+ }
+ } else if (strcmp(info->name, "foo") == 0) {
+ isc_timer_destroy(&info->timer);
+ nevent = isc_event_allocate(info->mctx, info, FOO_EVENT,
+ foo_event, task, sizeof(*event));
+ RUNTIME_CHECK(nevent != NULL);
+ isc_task_sendanddetach(&task, &nevent);
+ }
+
+ isc_event_free(&event);
+}
+
+static t_info *
+new_task(isc_mem_t *mctx, const char *name) {
+ t_info *ti;
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ RUNTIME_CHECK(task_count < MAX_TASKS);
+ ti = &tasks[task_count];
+ ti->mctx = mctx;
+ ti->task = NULL;
+ ti->timer = NULL;
+ ti->ticks = 0;
+ if (name != NULL) {
+ INSIST(strlen(name) < sizeof(ti->name));
+ strlcpy(ti->name, name, sizeof(ti->name));
+ } else {
+ snprintf(ti->name, sizeof(ti->name), "%u", task_count);
+ }
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &ti->task) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(ti->task, shutdown_action, ti) ==
+ ISC_R_SUCCESS);
+
+ isc_time_settoepoch(&expires);
+ isc_interval_set(&interval, 1, 0);
+ RUNTIME_CHECK(isc_timer_create(timer_manager, isc_timertype_ticker,
+ &expires, &interval, ti->task, tick, ti,
+ &ti->timer) == ISC_R_SUCCESS);
+
+ task_count++;
+
+ return (ti);
+}
+
+int
+main(int argc, char *argv[]) {
+ unsigned int workers;
+ t_info *t1, *t2 = NULL;
+ isc_task_t *task = NULL;
+ isc_mem_t *mctx = NULL, *mctx2 = NULL;
+
+ RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
+
+ if (argc > 1) {
+ workers = atoi(argv[1]);
+ if (workers < 1) {
+ workers = 1;
+ }
+ if (workers > 8192) {
+ workers = 8192;
+ }
+ } else {
+ workers = 2;
+ }
+ printf("%u workers\n", workers);
+
+ isc_mem_create(&mctx);
+ isc_mem_create(&mctx2);
+ RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr,
+ &taskmgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timer_manager) ==
+ ISC_R_SUCCESS);
+
+ t1 = new_task(mctx, NULL);
+ t2 = new_task(mctx2, NULL);
+ isc_task_attach(t2->task, &t1->peer);
+ isc_task_attach(t1->task, &t2->peer);
+
+ /*
+ * Test run-triggered shutdown.
+ */
+ (void)new_task(mctx2, "foo");
+
+ /*
+ * Test implicit shutdown.
+ */
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS);
+ isc_task_detach(&task);
+
+ /*
+ * Test anti-zombie code.
+ */
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task) == ISC_R_SUCCESS);
+ isc_task_detach(&task);
+
+ RUNTIME_CHECK(isc_app_run() == ISC_R_SUCCESS);
+
+ isc_managers_destroy(&netmgr, &taskmgr);
+ isc_timermgr_destroy(&timer_manager);
+
+ printf("Statistics for mctx:\n");
+ isc_mem_stats(mctx, stdout);
+ isc_mem_destroy(&mctx);
+ printf("Statistics for mctx2:\n");
+ isc_mem_stats(mctx2, stdout);
+ isc_mem_destroy(&mctx2);
+
+ isc_app_finish();
+
+ return (0);
+}
diff --git a/bin/tests/optional/sig0_test.c b/bin/tests/optional/sig0_test.c
new file mode 100644
index 0000000..e419700
--- /dev/null
+++ b/bin/tests/optional/sig0_test.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/app.h>
+#include <isc/assertions.h>
+#include <isc/commandline.h>
+#include <isc/error.h>
+#include <isc/log.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/print.h>
+#include <isc/socket.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/dnssec.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/keyvalues.h>
+#include <dns/masterdump.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rdataset.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/types.h>
+
+#include <dst/dst.h>
+#include <dst/result.h>
+
+#define CHECK(str, x) \
+ { \
+ if ((x) != ISC_R_SUCCESS) { \
+ printf("%s: %s\n", (str), isc_result_totext(x)); \
+ exit(-1); \
+ } \
+ }
+
+isc_mutex_t lock;
+dst_key_t *key = NULL;
+isc_mem_t *mctx = NULL;
+unsigned char qdata[1024], rdata[1024];
+isc_buffer_t qbuffer, rbuffer;
+isc_nm_t *netmgr = NULL;
+isc_taskmgr_t *taskmgr = NULL;
+isc_task_t *task1 = NULL;
+isc_log_t *lctx = NULL;
+isc_logconfig_t *logconfig = NULL;
+isc_socket_t *s = NULL;
+isc_sockaddr_t address;
+char output[10 * 1024];
+isc_buffer_t outbuf;
+static const dns_master_style_t *style = &dns_master_style_debug;
+
+static void
+senddone(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+
+ REQUIRE(sevent != NULL);
+ REQUIRE(sevent->ev_type == ISC_SOCKEVENT_SENDDONE);
+ REQUIRE(task == task1);
+
+ printf("senddone\n");
+
+ isc_event_free(&event);
+}
+
+static void
+recvdone(isc_task_t *task, isc_event_t *event) {
+ isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+ isc_buffer_t source;
+ isc_result_t result;
+ dns_message_t *response = NULL;
+
+ REQUIRE(sevent != NULL);
+ REQUIRE(sevent->ev_type == ISC_SOCKEVENT_RECVDONE);
+ REQUIRE(task == task1);
+
+ printf("recvdone\n");
+ if (sevent->result != ISC_R_SUCCESS) {
+ printf("failed\n");
+ exit(-1);
+ }
+
+ isc_buffer_init(&source, sevent->region.base, sevent->region.length);
+ isc_buffer_add(&source, sevent->n);
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+ result = dns_message_parse(response, &source, 0);
+ CHECK("dns_message_parse", result);
+
+ isc_buffer_init(&outbuf, output, sizeof(output));
+ result = dns_message_totext(response, style, 0, &outbuf);
+ CHECK("dns_message_totext", result);
+ printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+ (char *)isc_buffer_base(&outbuf));
+
+ dns_message_detach(&response);
+ isc_event_free(&event);
+
+ isc_app_shutdown();
+}
+
+static void
+buildquery(void) {
+ isc_result_t result;
+ dns_rdataset_t *question = NULL;
+ dns_name_t *qname = NULL;
+ isc_region_t r, inr;
+ dns_message_t *query = NULL;
+ char nametext[] = "host.example";
+ isc_buffer_t namesrc, namedst;
+ unsigned char namedata[256];
+ isc_sockaddr_t sa;
+ dns_compress_t cctx;
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
+ result = dns_message_setsig0key(query, key);
+ CHECK("dns_message_setsig0key", result);
+
+ result = dns_message_gettemprdataset(query, &question);
+ CHECK("dns_message_gettemprdataset", result);
+ dns_rdataset_makequestion(question, dns_rdataclass_in, dns_rdatatype_a);
+ result = dns_message_gettempname(query, &qname);
+ CHECK("dns_message_gettempname", result);
+ isc_buffer_init(&namesrc, nametext, strlen(nametext));
+ isc_buffer_add(&namesrc, strlen(nametext));
+ isc_buffer_init(&namedst, namedata, sizeof(namedata));
+ dns_name_init(qname, NULL);
+ result = dns_name_fromtext(qname, &namesrc, dns_rootname, 0, &namedst);
+ CHECK("dns_name_fromtext", result);
+ ISC_LIST_APPEND(qname->list, question, link);
+ dns_message_addname(query, qname, DNS_SECTION_QUESTION);
+
+ isc_buffer_init(&qbuffer, qdata, sizeof(qdata));
+
+ result = dns_compress_init(&cctx, -1, mctx);
+ CHECK("dns_compress_init", result);
+ result = dns_message_renderbegin(query, &cctx, &qbuffer);
+ CHECK("dns_message_renderbegin", result);
+ result = dns_message_rendersection(query, DNS_SECTION_QUESTION, 0);
+ CHECK("dns_message_rendersection(question)", result);
+ result = dns_message_rendersection(query, DNS_SECTION_ANSWER, 0);
+ CHECK("dns_message_rendersection(answer)", result);
+ result = dns_message_rendersection(query, DNS_SECTION_AUTHORITY, 0);
+ CHECK("dns_message_rendersection(auth)", result);
+ result = dns_message_rendersection(query, DNS_SECTION_ADDITIONAL, 0);
+ CHECK("dns_message_rendersection(add)", result);
+ result = dns_message_renderend(query);
+ CHECK("dns_message_renderend", result);
+ dns_compress_invalidate(&cctx);
+
+ isc_buffer_init(&outbuf, output, sizeof(output));
+ result = dns_message_totext(query, style, 0, &outbuf);
+ CHECK("dns_message_totext", result);
+ printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+ (char *)isc_buffer_base(&outbuf));
+
+ isc_buffer_usedregion(&qbuffer, &r);
+ isc_sockaddr_any(&sa);
+ result = isc_socket_bind(s, &sa, 0);
+ CHECK("isc_socket_bind", result);
+ result = isc_socket_sendto(s, &r, task1, senddone, NULL, &address,
+ NULL);
+ CHECK("isc_socket_sendto", result);
+
+ inr.base = rdata;
+ inr.length = sizeof(rdata);
+ result = isc_socket_recv(s, &inr, 1, task1, recvdone, NULL);
+ CHECK("isc_socket_recv", result);
+ dns_message_detach(&query);
+}
+
+int
+main(int argc, char *argv[]) {
+ bool verbose = false;
+ isc_socketmgr_t *socketmgr = NULL;
+ isc_timermgr_t *timermgr = NULL;
+ struct in_addr inaddr;
+ dns_fixedname_t fname;
+ dns_name_t *name = NULL;
+ isc_buffer_t b;
+ int ch;
+ isc_result_t result;
+ in_port_t port = 53;
+
+ RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
+
+ isc_mutex_init(&lock);
+
+ mctx = NULL;
+ isc_mem_create(&mctx);
+
+ while ((ch = isc_commandline_parse(argc, argv, "vp:")) != -1) {
+ switch (ch) {
+ case 'v':
+ verbose = true;
+ break;
+ case 'p':
+ port = (unsigned int)atoi(isc_commandline_argument);
+ break;
+ }
+ }
+
+ RUNTIME_CHECK(dst_lib_init(mctx, NULL) == ISC_R_SUCCESS);
+
+ dns_result_register();
+ dst_result_register();
+
+ RUNTIME_CHECK(isc_managers_create(mctx, 2, 0, &netmgr, &taskmgr) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &task1) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timermgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
+
+ isc_log_create(mctx, &lctx, &logconfig);
+
+ RUNTIME_CHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp,
+ &s) == ISC_R_SUCCESS);
+
+ inaddr.s_addr = htonl(INADDR_LOOPBACK);
+ isc_sockaddr_fromin(&address, &inaddr, port);
+
+ name = dns_fixedname_initname(&fname);
+ isc_buffer_constinit(&b, "child.example.", strlen("child.example."));
+ isc_buffer_add(&b, strlen("child.example."));
+ result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
+ CHECK("dns_name_fromtext", result);
+
+ result = dst_key_fromfile(name, 33180, DNS_KEYALG_RSASHA1,
+ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, NULL,
+ mctx, &key);
+ CHECK("dst_key_fromfile", result);
+
+ buildquery();
+
+ (void)isc_app_run();
+
+ isc_task_shutdown(task1);
+ isc_task_detach(&task1);
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_socket_detach(&s);
+ isc_socketmgr_destroy(&socketmgr);
+ isc_timermgr_destroy(&timermgr);
+
+ dst_key_free(&key);
+
+ dst_lib_destroy();
+
+ isc_log_destroy(&lctx);
+
+ if (verbose) {
+ isc_mem_stats(mctx, stdout);
+ }
+ isc_mem_destroy(&mctx);
+
+ isc_mutex_destroy(&lock);
+
+ isc_app_finish();
+
+ return (0);
+}
diff --git a/bin/tests/optional/sock_test.c b/bin/tests/optional/sock_test.c
new file mode 100644
index 0000000..f88f76d
--- /dev/null
+++ b/bin/tests/optional/sock_test.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/socket.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+isc_mem_t *mctx = NULL;
+isc_nm_t *netmgr = NULL;
+isc_taskmgr_t *taskmgr = NULL;
+
+static void
+my_shutdown(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+
+ printf("shutdown %s (%p)\n", name, task);
+ fflush(stdout);
+ isc_event_free(&event);
+}
+
+static void
+my_send(isc_task_t *task, isc_event_t *event) {
+ isc_socket_t *sock;
+ isc_socketevent_t *dev;
+
+ sock = event->ev_sender;
+ dev = (isc_socketevent_t *)event;
+
+ printf("my_send: %s task %p\n\t(sock %p, base %p, length %u, n %u, "
+ "result %u)\n",
+ (char *)(event->ev_arg), task, sock, dev->region.base,
+ dev->region.length, dev->n, dev->result);
+
+ if (dev->result != ISC_R_SUCCESS) {
+ isc_socket_detach(&sock);
+ isc_task_shutdown(task);
+ }
+
+ if (dev->region.base != NULL) {
+ isc_mem_put(mctx, dev->region.base, dev->region.length);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+my_recv(isc_task_t *task, isc_event_t *event) {
+ isc_socket_t *sock;
+ isc_socketevent_t *dev;
+ isc_region_t region;
+ char buf[1024];
+ char host[256];
+
+ sock = event->ev_sender;
+ dev = (isc_socketevent_t *)event;
+
+ printf("Socket %s (sock %p, base %p, length %u, n %u, result %u)\n",
+ (char *)(event->ev_arg), sock, dev->region.base,
+ dev->region.length, dev->n, dev->result);
+ if (dev->address.type.sa.sa_family == AF_INET6) {
+ inet_ntop(AF_INET6, &dev->address.type.sin6.sin6_addr, host,
+ sizeof(host));
+ printf("\tFrom: %s port %d\n", host,
+ ntohs(dev->address.type.sin6.sin6_port));
+ } else {
+ inet_ntop(AF_INET, &dev->address.type.sin.sin_addr, host,
+ sizeof(host));
+ printf("\tFrom: %s port %d\n", host,
+ ntohs(dev->address.type.sin.sin_port));
+ }
+
+ if (dev->result != ISC_R_SUCCESS) {
+ isc_socket_detach(&sock);
+
+ if (dev->region.base != NULL) {
+ isc_mem_put(mctx, dev->region.base, dev->region.length);
+ }
+ isc_event_free(&event);
+
+ isc_task_shutdown(task);
+ return;
+ }
+
+ /*
+ * Echo the data back.
+ */
+ if (strcmp(event->ev_arg, "so2") != 0) {
+ region = dev->region;
+ snprintf(buf, sizeof(buf), "\r\nReceived: %.*s\r\n\r\n",
+ (int)dev->n, (char *)region.base);
+ region.base = isc_mem_get(mctx, strlen(buf) + 1);
+ {
+ region.length = strlen(buf) + 1;
+ strlcpy((char *)region.base, buf, region.length);
+ }
+ isc_socket_send(sock, &region, task, my_send, event->ev_arg);
+ } else {
+ region = dev->region;
+ printf("\r\nReceived: %.*s\r\n\r\n", (int)dev->n,
+ (char *)region.base);
+ }
+
+ isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg);
+
+ isc_event_free(&event);
+}
+
+static void
+my_http_get(isc_task_t *task, isc_event_t *event) {
+ isc_socket_t *sock;
+ isc_socketevent_t *dev;
+
+ sock = event->ev_sender;
+ dev = (isc_socketevent_t *)event;
+
+ printf("my_http_get: %s task %p\n\t(sock %p, base %p, length %u, "
+ "n %u, result %u)\n",
+ (char *)(event->ev_arg), task, sock, dev->region.base,
+ dev->region.length, dev->n, dev->result);
+
+ if (dev->result != ISC_R_SUCCESS) {
+ isc_socket_detach(&sock);
+ isc_task_shutdown(task);
+ if (dev->region.base != NULL) {
+ isc_mem_put(mctx, dev->region.base, dev->region.length);
+ }
+ isc_event_free(&event);
+ return;
+ }
+
+ isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg);
+
+ isc_event_free(&event);
+}
+
+static void
+my_connect(isc_task_t *task, isc_event_t *event) {
+ isc_socket_t *sock;
+ isc_socket_connev_t *dev;
+ isc_region_t region;
+ char buf[1024];
+
+ sock = event->ev_sender;
+ dev = (isc_socket_connev_t *)event;
+
+ printf("%s: Connection result: %u\n", (char *)(event->ev_arg),
+ dev->result);
+
+ if (dev->result != ISC_R_SUCCESS) {
+ isc_socket_detach(&sock);
+ isc_event_free(&event);
+ isc_task_shutdown(task);
+ return;
+ }
+
+ /*
+ * Send a GET string, and set up to receive (and just display)
+ * the result.
+ */
+ snprintf(buf, sizeof(buf),
+ "GET / HTTP/1.1\r\nHost: www.flame.org\r\n"
+ "Connection: Close\r\n\r\n");
+ region.base = isc_mem_get(mctx, strlen(buf) + 1);
+ {
+ region.length = strlen(buf) + 1;
+ strlcpy((char *)region.base, buf, region.length);
+ }
+
+ isc_socket_send(sock, &region, task, my_http_get, event->ev_arg);
+
+ isc_event_free(&event);
+}
+
+static void
+my_listen(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+ isc_socket_newconnev_t *dev = NULL;
+ isc_region_t region;
+ isc_socket_t *oldsock = NULL;
+ isc_task_t *newtask = NULL;
+
+ dev = (isc_socket_newconnev_t *)event;
+
+ printf("newcon %s (task %p, oldsock %p, newsock %p, result %u)\n", name,
+ task, event->ev_sender, dev->newsocket, dev->result);
+ fflush(stdout);
+
+ if (dev->result == ISC_R_SUCCESS) {
+ /*
+ * Queue another listen on this socket.
+ */
+ RUNTIME_CHECK(isc_socket_accept(event->ev_sender, task,
+ my_listen, event->ev_arg) ==
+ ISC_R_SUCCESS);
+
+ region.base = isc_mem_get(mctx, 20);
+ region.length = 20;
+
+ /*
+ * Create a new task for this socket, and queue up a
+ * recv on it.
+ */
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &newtask) ==
+ ISC_R_SUCCESS);
+ isc_socket_recv(dev->newsocket, &region, 1, newtask, my_recv,
+ event->ev_arg);
+ isc_task_detach(&newtask);
+ } else {
+ printf("detaching from socket %p\n", event->ev_sender);
+ oldsock = event->ev_sender;
+
+ isc_socket_detach(&oldsock);
+
+ isc_event_free(&event);
+ isc_task_shutdown(task);
+ return;
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+timeout(isc_task_t *task, isc_event_t *event) {
+ isc_socket_t *sock = event->ev_arg;
+
+ printf("Timeout, canceling IO on socket %p (task %p)\n", sock, task);
+
+ isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_ALL);
+ isc_timer_destroy((isc_timer_t **)&event->ev_sender);
+ isc_event_free(&event);
+}
+
+static char one[] = "1";
+static char two[] = "2";
+static char xso1[] = "so1";
+static char xso2[] = "so2";
+
+int
+main(int argc, char *argv[]) {
+ isc_task_t *t1 = NULL, *t2 = NULL;
+ isc_timermgr_t *timgr = NULL;
+ isc_time_t expires;
+ isc_interval_t interval;
+ isc_timer_t *ti1 = NULL;
+ unsigned int workers;
+ isc_socketmgr_t *socketmgr = NULL;
+ isc_socket_t *so1 = NULL, *so2 = NULL;
+ isc_sockaddr_t sockaddr;
+ struct in_addr ina;
+ struct in6_addr in6a;
+ isc_result_t result;
+ int pf;
+
+ if (argc > 1) {
+ workers = atoi(argv[1]);
+ if (workers < 1) {
+ workers = 1;
+ }
+ if (workers > 8192) {
+ workers = 8192;
+ }
+ } else {
+ workers = 2;
+ }
+ printf("%u workers\n", workers);
+
+ if (isc_net_probeipv6() == ISC_R_SUCCESS) {
+ pf = PF_INET6;
+ } else {
+ pf = PF_INET;
+ }
+
+ /*
+ * EVERYTHING needs a memory context.
+ */
+ isc_mem_create(&mctx);
+
+ /*
+ * The task manager is independent (other than memory context)
+ */
+ RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr,
+ &taskmgr) == ISC_R_SUCCESS);
+
+ /*
+ * Timer manager depends only on the memory context as well.
+ */
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, one) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, two) ==
+ ISC_R_SUCCESS);
+
+ printf("task 1 = %p\n", t1);
+ printf("task 2 = %p\n", t2);
+
+ RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
+
+ /*
+ * Open up a listener socket.
+ */
+
+ if (pf == PF_INET6) {
+ in6a = in6addr_any;
+ isc_sockaddr_fromin6(&sockaddr, &in6a, 5544);
+ } else {
+ ina.s_addr = INADDR_ANY;
+ isc_sockaddr_fromin(&sockaddr, &ina, 5544);
+ }
+ RUNTIME_CHECK(isc_socket_create(socketmgr, pf, isc_sockettype_tcp,
+ &so1) == ISC_R_SUCCESS);
+ result = isc_socket_bind(so1, &sockaddr, ISC_SOCKET_REUSEADDRESS);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_socket_listen(so1, 0) == ISC_R_SUCCESS);
+
+ /*
+ * Queue up the first accept event.
+ */
+ RUNTIME_CHECK(isc_socket_accept(so1, t1, my_listen, xso1) ==
+ ISC_R_SUCCESS);
+ isc_time_settoepoch(&expires);
+ isc_interval_set(&interval, 10, 0);
+ RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires,
+ &interval, t1, timeout, so1,
+ &ti1) == ISC_R_SUCCESS);
+
+ /*
+ * Open up a socket that will connect to www.flame.org, port 80.
+ * Why not. :)
+ */
+ ina.s_addr = inet_addr("204.152.184.97");
+ if (0 && pf == PF_INET6) {
+ isc_sockaddr_v6fromin(&sockaddr, &ina, 80);
+ } else {
+ isc_sockaddr_fromin(&sockaddr, &ina, 80);
+ }
+ RUNTIME_CHECK(isc_socket_create(socketmgr, isc_sockaddr_pf(&sockaddr),
+ isc_sockettype_tcp,
+ &so2) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_socket_connect(so2, &sockaddr, t2, my_connect,
+ xso2) == ISC_R_SUCCESS);
+
+ /*
+ * Detaching these is safe, since the socket will attach to the
+ * task for any outstanding requests.
+ */
+ isc_task_detach(&t1);
+ isc_task_detach(&t2);
+
+ /*
+ * Wait a short while.
+ */
+#ifndef WIN32
+ sleep(10);
+#else /* ifndef WIN32 */
+ Sleep(10000);
+#endif /* ifndef WIN32 */
+
+ fprintf(stderr, "Destroying socket manager\n");
+ isc_socketmgr_destroy(&socketmgr);
+
+ fprintf(stderr, "Destroying timer manager\n");
+ isc_timermgr_destroy(&timgr);
+
+ fprintf(stderr, "Destroying task manager\n");
+ isc_managers_destroy(&netmgr, &taskmgr);
+
+ isc_mem_stats(mctx, stdout);
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/sym_test.c b/bin/tests/optional/sym_test.c
new file mode 100644
index 0000000..81e2916
--- /dev/null
+++ b/bin/tests/optional/sym_test.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <isc/commandline.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/symtab.h>
+#include <isc/util.h>
+
+isc_mem_t *mctx;
+isc_symtab_t *st;
+
+static void
+undefine_action(char *key, unsigned int type, isc_symvalue_t value, void *arg) {
+ UNUSED(arg);
+
+ INSIST(type == 1);
+ isc_mem_free(mctx, key);
+ isc_mem_free(mctx, value.as_pointer);
+}
+
+int
+main(int argc, char *argv[]) {
+ char s[1000], *cp, *key;
+ size_t len;
+ isc_result_t result;
+ isc_symvalue_t value;
+ int trace = 0;
+ int c;
+ isc_symexists_t exists_policy = isc_symexists_reject;
+ bool case_sensitive = false;
+
+ while ((c = isc_commandline_parse(argc, argv, "tarc")) != -1) {
+ switch (c) {
+ case 't':
+ trace = 1;
+ break;
+ case 'a':
+ exists_policy = isc_symexists_add;
+ break;
+ case 'r':
+ exists_policy = isc_symexists_replace;
+ break;
+ case 'c':
+ case_sensitive = true;
+ break;
+ }
+ }
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(isc_symtab_create(mctx, 691, undefine_action, NULL,
+ case_sensitive, &st) == ISC_R_SUCCESS);
+
+ while (fgets(s, sizeof(s), stdin) != NULL) {
+ len = strlen(s);
+ if (len > 0U && s[len - 1] == '\n') {
+ s[len - 1] = '\0';
+ len--;
+ }
+
+ cp = s;
+
+ if (cp[0] == '!') {
+ cp++;
+ result = isc_symtab_undefine(st, cp, 1);
+ if (trace || result != ISC_R_SUCCESS) {
+ printf("undefine('%s'): %s\n", cp,
+ isc_result_totext(result));
+ }
+ } else {
+ key = cp;
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t') {
+ cp++;
+ }
+ if (*cp == '\0') {
+ result = isc_symtab_lookup(st, key, 0, &value);
+ if (trace || result != ISC_R_SUCCESS) {
+ printf("lookup('%s'): %s", key,
+ isc_result_totext(result));
+ if (result == ISC_R_SUCCESS) {
+ cp = value.as_pointer;
+ printf(", value == '%s'", cp);
+ }
+ printf("\n");
+ }
+ } else {
+ *cp++ = '\0';
+ key = isc_mem_strdup(mctx, key);
+ value.as_pointer = isc_mem_strdup(mctx, cp);
+ result = isc_symtab_define(st, key, 1, value,
+ exists_policy);
+ if (trace || result != ISC_R_SUCCESS) {
+ printf("define('%s', '%s'): %s\n", key,
+ cp, isc_result_totext(result));
+ if (result != ISC_R_SUCCESS) {
+ undefine_action(key, 1, value,
+ NULL);
+ }
+ }
+ }
+ }
+ }
+
+ isc_symtab_destroy(&st);
+ isc_mem_stats(mctx, stdout);
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/task_test.c b/bin/tests/optional/task_test.c
new file mode 100644
index 0000000..48e6bfd
--- /dev/null
+++ b/bin/tests/optional/task_test.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+isc_mem_t *mctx = NULL;
+
+static void
+my_callback(isc_task_t *task, isc_event_t *event) {
+ int i, j;
+ char *name = event->ev_arg;
+
+ j = 0;
+ for (i = 0; i < 1000000; i++) {
+ j += 100;
+ }
+ printf("task %s (%p): %d\n", name, task, j);
+ isc_event_free(&event);
+}
+
+static void
+my_shutdown(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+
+ printf("shutdown %s (%p)\n", name, task);
+ isc_event_free(&event);
+}
+
+static void
+my_tick(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+
+ printf("task %p tick %s\n", task, name);
+ isc_event_free(&event);
+}
+
+static char one[] = "1";
+static char two[] = "2";
+static char three[] = "3";
+static char four[] = "4";
+static char foo[] = "foo";
+static char bar[] = "bar";
+
+int
+main(int argc, char *argv[]) {
+ isc_nm_t *netmgr = NULL;
+ isc_taskmgr_t *taskmgr = NULL;
+ isc_task_t *t1 = NULL, *t2 = NULL;
+ isc_task_t *t3 = NULL, *t4 = NULL;
+ isc_event_t *event;
+ unsigned int workers;
+ isc_timermgr_t *timgr;
+ isc_timer_t *ti1, *ti2;
+ struct isc_interval interval;
+
+ if (argc > 1) {
+ workers = atoi(argv[1]);
+ if (workers < 1) {
+ workers = 1;
+ }
+ if (workers > 8192) {
+ workers = 8192;
+ }
+ } else {
+ workers = 2;
+ }
+ printf("%u workers\n", workers);
+
+ isc_mem_create(&mctx);
+
+ RUNTIME_CHECK(isc_managers_create(mctx, workers, 0, &netmgr,
+ &taskmgr) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t3) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t4) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_task_onshutdown(t1, my_shutdown, one) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t2, my_shutdown, two) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t3, my_shutdown, three) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t4, my_shutdown, four) ==
+ ISC_R_SUCCESS);
+
+ timgr = NULL;
+ RUNTIME_CHECK(isc_timermgr_create(mctx, &timgr) == ISC_R_SUCCESS);
+ ti1 = NULL;
+
+ isc_interval_set(&interval, 1, 0);
+ RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL,
+ &interval, t1, my_tick, foo,
+ &ti1) == ISC_R_SUCCESS);
+
+ ti2 = NULL;
+ isc_interval_set(&interval, 1, 0);
+ RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL,
+ &interval, t2, my_tick, bar,
+ &ti2) == ISC_R_SUCCESS);
+
+ printf("task 1 = %p\n", t1);
+ printf("task 2 = %p\n", t2);
+#ifndef WIN32
+ sleep(2);
+#else /* ifndef WIN32 */
+ Sleep(2000);
+#endif /* ifndef WIN32 */
+
+ /*
+ * Note: (void *)1 is used as a sender here, since some compilers
+ * don't like casting a function pointer to a (void *).
+ *
+ * In a real use, it is more likely the sender would be a
+ * structure (socket, timer, task, etc) but this is just a test
+ * program.
+ */
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, one,
+ sizeof(*event));
+ isc_task_send(t1, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, two,
+ sizeof(*event));
+ isc_task_send(t2, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, three,
+ sizeof(*event));
+ isc_task_send(t3, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, four,
+ sizeof(*event));
+ isc_task_send(t4, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, two,
+ sizeof(*event));
+ isc_task_send(t2, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, three,
+ sizeof(*event));
+ isc_task_send(t3, &event);
+ event = isc_event_allocate(mctx, (void *)1, 1, my_callback, four,
+ sizeof(*event));
+ isc_task_send(t4, &event);
+ isc_task_purgerange(t3, NULL, ISC_EVENTTYPE_FIRSTEVENT,
+ ISC_EVENTTYPE_LASTEVENT, NULL);
+
+ isc_task_detach(&t1);
+ isc_task_detach(&t2);
+ isc_task_detach(&t3);
+ isc_task_detach(&t4);
+
+#ifndef WIN32
+ sleep(10);
+#else /* ifndef WIN32 */
+ Sleep(10000);
+#endif /* ifndef WIN32 */
+ printf("destroy\n");
+ isc_timer_destroy(&ti1);
+ isc_timer_destroy(&ti2);
+ isc_timermgr_destroy(&timgr);
+ isc_managers_destroy(&netmgr, &taskmgr);
+ printf("destroyed\n");
+
+ isc_mem_stats(mctx, stdout);
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}
diff --git a/bin/tests/optional/timer_test.c b/bin/tests/optional/timer_test.c
new file mode 100644
index 0000000..0eb6e9f
--- /dev/null
+++ b/bin/tests/optional/timer_test.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+isc_mem_t *mctx1, *mctx2, *mctx3;
+isc_task_t *t1, *t2, *t3;
+isc_timer_t *ti1, *ti2, *ti3;
+int tick_count = 0;
+
+static void
+shutdown_task(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+
+ printf("task %p shutdown %s\n", task, name);
+ isc_event_free(&event);
+}
+
+static void
+tick(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+
+ INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
+
+ printf("task %s (%p) tick\n", name, task);
+
+ tick_count++;
+ if (ti3 != NULL && tick_count % 3 == 0) {
+ isc_timer_touch(ti3);
+ }
+
+ if (ti3 != NULL && tick_count == 7) {
+ isc_time_t expires;
+ isc_interval_t interval;
+
+ isc_interval_set(&interval, 5, 0);
+ (void)isc_time_nowplusinterval(&expires, &interval);
+ isc_interval_set(&interval, 4, 0);
+ printf("*** resetting ti3 ***\n");
+ RUNTIME_CHECK(isc_timer_reset(ti3, isc_timertype_once, &expires,
+ &interval,
+ true) == ISC_R_SUCCESS);
+ }
+
+ isc_event_free(&event);
+}
+
+static void
+timeout(isc_task_t *task, isc_event_t *event) {
+ char *name = event->ev_arg;
+ const char *type;
+
+ INSIST(event->ev_type == ISC_TIMEREVENT_IDLE ||
+ event->ev_type == ISC_TIMEREVENT_LIFE);
+
+ if (event->ev_type == ISC_TIMEREVENT_IDLE) {
+ type = "idle";
+ } else {
+ type = "life";
+ }
+ printf("task %s (%p) %s timeout\n", name, task, type);
+
+ if (strcmp(name, "3") == 0) {
+ printf("*** saving task 3 ***\n");
+ isc_event_free(&event);
+ return;
+ }
+
+ isc_event_free(&event);
+ isc_task_shutdown(task);
+}
+
+static char one[] = "1";
+static char two[] = "2";
+static char three[] = "3";
+
+int
+main(int argc, char *argv[]) {
+ isc_nm_t *netmgr = NULL;
+ isc_taskmgr_t *taskmgr = NULL;
+ isc_timermgr_t *timgr = NULL;
+ unsigned int workers;
+ isc_time_t expires, now;
+ isc_interval_t interval;
+
+ if (argc > 1) {
+ workers = atoi(argv[1]);
+ if (workers < 1) {
+ workers = 1;
+ }
+ if (workers > 8192) {
+ workers = 8192;
+ }
+ } else {
+ workers = 2;
+ }
+ printf("%u workers\n", workers);
+
+ isc_mem_create(&mctx1);
+ RUNTIME_CHECK(isc_managers_create(mctx1, workers, 0, &netmgr,
+ &taskmgr) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_timermgr_create(mctx1, &timgr) == ISC_R_SUCCESS);
+
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t1) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t2) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_create(taskmgr, 0, &t3) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t1, shutdown_task, one) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t2, shutdown_task, two) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_task_onshutdown(t3, shutdown_task, three) ==
+ ISC_R_SUCCESS);
+
+ printf("task 1: %p\n", t1);
+ printf("task 2: %p\n", t2);
+ printf("task 3: %p\n", t3);
+
+ TIME_NOW(&now);
+
+ isc_interval_set(&interval, 2, 0);
+ RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, NULL,
+ &interval, t2, timeout, two,
+ &ti2) == ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 1, 0);
+ RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_ticker, NULL,
+ &interval, t1, tick, one,
+ &ti1) == ISC_R_SUCCESS);
+
+ isc_interval_set(&interval, 10, 0);
+ RUNTIME_CHECK(isc_time_add(&now, &interval, &expires) == ISC_R_SUCCESS);
+ isc_interval_set(&interval, 2, 0);
+ RUNTIME_CHECK(isc_timer_create(timgr, isc_timertype_once, &expires,
+ &interval, t3, timeout, three,
+ &ti3) == ISC_R_SUCCESS);
+
+ isc_task_detach(&t1);
+ isc_task_detach(&t2);
+ isc_task_detach(&t3);
+
+#ifndef WIN32
+ sleep(15);
+#else /* ifndef WIN32 */
+ Sleep(15000);
+#endif /* ifndef WIN32 */
+ printf("destroy\n");
+ isc_timer_destroy(&ti1);
+ isc_timer_destroy(&ti2);
+ isc_timer_destroy(&ti3);
+#ifndef WIN32
+ sleep(2);
+#else /* ifndef WIN32 */
+ Sleep(2000);
+#endif /* ifndef WIN32 */
+ isc_timermgr_destroy(&timgr);
+ isc_managers_destroy(&netmgr, &taskmgr);
+ printf("destroyed\n");
+
+ printf("Statistics for mctx1:\n");
+ isc_mem_stats(mctx1, stdout);
+ isc_mem_destroy(&mctx1);
+
+ return (0);
+}
diff --git a/bin/tests/optional/zone_test.c b/bin/tests/optional/zone_test.c
new file mode 100644
index 0000000..05193f8
--- /dev/null
+++ b/bin/tests/optional/zone_test.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/commandline.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/socket.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/fixedname.h>
+#include <dns/rdataclass.h>
+#include <dns/rdataset.h>
+#include <dns/result.h>
+#include <dns/zone.h>
+
+static int debug = 0;
+static int quiet = 0;
+static int stats = 0;
+static isc_mem_t *mctx = NULL;
+dns_zone_t *zone = NULL;
+isc_nm_t *netmgr = NULL;
+isc_taskmgr_t *taskmgr = NULL;
+isc_timermgr_t *timermgr = NULL;
+isc_socketmgr_t *socketmgr = NULL;
+dns_zonemgr_t *zonemgr = NULL;
+dns_zonetype_t zonetype = dns_zone_primary;
+isc_sockaddr_t addr;
+
+#define ERRRET(result, function) \
+ do { \
+ if (result != ISC_R_SUCCESS) { \
+ fprintf(stderr, "%s() returned %s\n", function, \
+ dns_result_totext(result)); \
+ return; \
+ } \
+ } while (0)
+
+#define ERRCONT(result, function) \
+ if (result != ISC_R_SUCCESS) { \
+ fprintf(stderr, "%s() returned %s\n", function, \
+ dns_result_totext(result)); \
+ continue; \
+ } else \
+ (void)NULL
+
+static void
+usage(void) {
+ fprintf(stderr, "usage: zone_test [-dqsSM] [-c class] [-f file] "
+ "zone\n");
+ exit(1);
+}
+
+static void
+setup(const char *zonename, const char *filename, const char *classname) {
+ isc_result_t result;
+ dns_rdataclass_t rdclass;
+ isc_consttextregion_t region;
+ isc_buffer_t buffer;
+ dns_fixedname_t fixorigin;
+ dns_name_t *origin;
+ const char *rbt = "rbt";
+
+ if (debug) {
+ fprintf(stderr, "loading \"%s\" from \"%s\" class \"%s\"\n",
+ zonename, filename, classname);
+ }
+ result = dns_zone_create(&zone, mctx);
+ ERRRET(result, "dns_zone_new");
+
+ dns_zone_settype(zone, zonetype);
+
+ isc_buffer_constinit(&buffer, zonename, strlen(zonename));
+ isc_buffer_add(&buffer, strlen(zonename));
+ dns_fixedname_init(&fixorigin);
+ result = dns_name_fromtext(dns_fixedname_name(&fixorigin), &buffer,
+ dns_rootname, 0, NULL);
+ ERRRET(result, "dns_name_fromtext");
+ origin = dns_fixedname_name(&fixorigin);
+
+ result = dns_zone_setorigin(zone, origin);
+ ERRRET(result, "dns_zone_setorigin");
+
+ dns_zone_setdbtype(zone, 1, &rbt);
+
+ result = dns_zone_setfile(zone, filename, dns_masterformat_text,
+ &dns_master_style_default);
+ ERRRET(result, "dns_zone_setfile");
+
+ region.base = classname;
+ region.length = strlen(classname);
+ result = dns_rdataclass_fromtext(&rdclass,
+ (isc_textregion_t *)(void *)&region);
+ ERRRET(result, "dns_rdataclass_fromtext");
+
+ dns_zone_setclass(zone, rdclass);
+
+ if (zonetype == dns_zone_secondary) {
+ dns_zone_setprimaries(zone, &addr, 1);
+ }
+
+ result = dns_zone_load(zone, false);
+ ERRRET(result, "dns_zone_load");
+
+ result = dns_zonemgr_managezone(zonemgr, zone);
+ ERRRET(result, "dns_zonemgr_managezone");
+}
+
+static void
+print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) {
+ isc_buffer_t text;
+ char t[1000];
+ isc_result_t result;
+ isc_region_t r;
+
+ isc_buffer_init(&text, t, sizeof(t));
+ result = dns_rdataset_totext(rdataset, name, false, false, &text);
+ isc_buffer_usedregion(&text, &r);
+ if (result == ISC_R_SUCCESS) {
+ printf("%.*s", (int)r.length, (char *)r.base);
+ } else {
+ printf("%s\n", dns_result_totext(result));
+ }
+}
+
+static void
+query(void) {
+ char buf[1024];
+ dns_fixedname_t name;
+ dns_fixedname_t found;
+ dns_db_t *db;
+ isc_buffer_t buffer;
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ dns_rdataset_t sigset;
+ fd_set rfdset = { { 0 } };
+
+ db = NULL;
+ result = dns_zone_getdb(zone, &db);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "%s() returned %s\n", "dns_zone_getdb",
+ dns_result_totext(result));
+ return;
+ }
+
+ dns_fixedname_init(&found);
+ dns_rdataset_init(&rdataset);
+ dns_rdataset_init(&sigset);
+
+ do {
+ char *s;
+ fprintf(stdout, "zone_test ");
+ fflush(stdout);
+ FD_ZERO(&rfdset);
+ FD_SET(0, &rfdset);
+ select(1, &rfdset, NULL, NULL, NULL);
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ fprintf(stdout, "\n");
+ break;
+ }
+ buf[sizeof(buf) - 1] = '\0';
+
+ s = strchr(buf, '\n');
+ if (s != NULL) {
+ *s = '\0';
+ }
+ s = strchr(buf, '\r');
+ if (s != NULL) {
+ *s = '\0';
+ }
+ if (strcmp(buf, "dump") == 0) {
+ dns_zone_dumptostream(zone, stdout,
+ dns_masterformat_text,
+ &dns_master_style_default, 0);
+ continue;
+ }
+ if (strlen(buf) == 0U) {
+ continue;
+ }
+ dns_fixedname_init(&name);
+ isc_buffer_init(&buffer, buf, strlen(buf));
+ isc_buffer_add(&buffer, strlen(buf));
+ result = dns_name_fromtext(dns_fixedname_name(&name), &buffer,
+ dns_rootname, 0, NULL);
+ ERRCONT(result, "dns_name_fromtext");
+
+ result = dns_db_find(db, dns_fixedname_name(&name),
+ NULL /*version*/, dns_rdatatype_a,
+ 0 /*options*/, 0 /*time*/, NULL /*nodep*/,
+ dns_fixedname_name(&found), &rdataset,
+ &sigset);
+ fprintf(stderr, "%s() returned %s\n", "dns_db_find",
+ dns_result_totext(result));
+ switch (result) {
+ case DNS_R_DELEGATION:
+ print_rdataset(dns_fixedname_name(&found), &rdataset);
+ break;
+ case ISC_R_SUCCESS:
+ print_rdataset(dns_fixedname_name(&name), &rdataset);
+ break;
+ default:
+ break;
+ }
+
+ if (dns_rdataset_isassociated(&rdataset)) {
+ dns_rdataset_disassociate(&rdataset);
+ }
+ if (dns_rdataset_isassociated(&sigset)) {
+ dns_rdataset_disassociate(&sigset);
+ }
+ } while (1);
+ dns_rdataset_invalidate(&rdataset);
+ dns_db_detach(&db);
+}
+
+int
+main(int argc, char **argv) {
+ int c;
+ char *filename = NULL;
+ const char *classname = "IN";
+
+ while ((c = isc_commandline_parse(argc, argv, "cdf:m:qsMS")) != EOF) {
+ switch (c) {
+ case 'c':
+ classname = isc_commandline_argument;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'f':
+ if (filename != NULL) {
+ usage();
+ }
+ filename = isc_commandline_argument;
+ break;
+ case 'm':
+ memset(&addr, 0, sizeof(addr));
+ addr.type.sin.sin_family = AF_INET;
+ if (inet_pton(AF_INET, isc_commandline_argument,
+ &addr.type.sin.sin_addr) != 1)
+ {
+ fprintf(stderr, "bad master address '%s'\n",
+ isc_commandline_argument);
+ exit(1);
+ }
+ addr.type.sin.sin_port = htons(53);
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 's':
+ stats++;
+ break;
+ case 'S':
+ zonetype = dns_zone_secondary;
+ break;
+ case 'M':
+ zonetype = dns_zone_primary;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (argv[isc_commandline_index] == NULL) {
+ usage();
+ }
+
+ RUNTIME_CHECK(isc_app_start() == ISC_R_SUCCESS);
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(isc_managers_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);
+ RUNTIME_CHECK(dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
+ &zonemgr) == ISC_R_SUCCESS);
+ if (filename == NULL) {
+ filename = argv[isc_commandline_index];
+ }
+ setup(argv[isc_commandline_index], filename, classname);
+ query();
+ if (zone != NULL) {
+ dns_zone_detach(&zone);
+ }
+ dns_zonemgr_shutdown(zonemgr);
+ dns_zonemgr_detach(&zonemgr);
+ isc_socketmgr_destroy(&socketmgr);
+ isc_managers_destroy(&netmgr, &taskmgr);
+ isc_timermgr_destroy(&timermgr);
+ if (!quiet && stats) {
+ isc_mem_stats(mctx, stdout);
+ }
+ isc_mem_destroy(&mctx);
+
+ return (0);
+}