summaryrefslogtreecommitdiffstats
path: root/lib/isc/include
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/isc/include/isc/aes.h40
-rw-r--r--lib/isc/include/isc/align.h20
-rw-r--r--lib/isc/include/isc/app.h281
-rw-r--r--lib/isc/include/isc/assertions.h73
-rw-r--r--lib/isc/include/isc/astack.h49
-rw-r--r--lib/isc/include/isc/atomic.h79
-rw-r--r--lib/isc/include/isc/attributes.h82
-rw-r--r--lib/isc/include/isc/backtrace.h101
-rw-r--r--lib/isc/include/isc/barrier.h39
-rw-r--r--lib/isc/include/isc/base32.h143
-rw-r--r--lib/isc/include/isc/base64.h98
-rw-r--r--lib/isc/include/isc/buffer.h1023
-rw-r--r--lib/isc/include/isc/cmocka.h55
-rw-r--r--lib/isc/include/isc/commandline.h56
-rw-r--r--lib/isc/include/isc/condition.h53
-rw-r--r--lib/isc/include/isc/counter.h84
-rw-r--r--lib/isc/include/isc/crc64.h55
-rw-r--r--lib/isc/include/isc/deprecated.h20
-rw-r--r--lib/isc/include/isc/dir.h80
-rw-r--r--lib/isc/include/isc/endian.h166
-rw-r--r--lib/isc/include/isc/errno.h27
-rw-r--r--lib/isc/include/isc/error.h45
-rw-r--r--lib/isc/include/isc/event.h117
-rw-r--r--lib/isc/include/isc/eventclass.h45
-rw-r--r--lib/isc/include/isc/file.h381
-rw-r--r--lib/isc/include/isc/formatcheck.h33
-rw-r--r--lib/isc/include/isc/fuzz.h23
-rw-r--r--lib/isc/include/isc/glob.h43
-rw-r--r--lib/isc/include/isc/hash.h63
-rw-r--r--lib/isc/include/isc/heap.h161
-rw-r--r--lib/isc/include/isc/hex.h98
-rw-r--r--lib/isc/include/isc/hmac.h148
-rw-r--r--lib/isc/include/isc/ht.h191
-rw-r--r--lib/isc/include/isc/httpd.h63
-rw-r--r--lib/isc/include/isc/interfaceiter.h127
-rw-r--r--lib/isc/include/isc/iterated_hash.h38
-rw-r--r--lib/isc/include/isc/lang.h24
-rw-r--r--lib/isc/include/isc/lex.h444
-rw-r--r--lib/isc/include/isc/list.h229
-rw-r--r--lib/isc/include/isc/log.h853
-rw-r--r--lib/isc/include/isc/magic.h31
-rw-r--r--lib/isc/include/isc/managers.h30
-rw-r--r--lib/isc/include/isc/md.h204
-rw-r--r--lib/isc/include/isc/mem.h572
-rw-r--r--lib/isc/include/isc/meminfo.h30
-rw-r--r--lib/isc/include/isc/mutex.h50
-rw-r--r--lib/isc/include/isc/mutexblock.h54
-rw-r--r--lib/isc/include/isc/net.h292
-rw-r--r--lib/isc/include/isc/netaddr.h197
-rw-r--r--lib/isc/include/isc/netdb.h48
-rw-r--r--lib/isc/include/isc/netmgr.h811
-rw-r--r--lib/isc/include/isc/netscope.h36
-rw-r--r--lib/isc/include/isc/nonce.h33
-rw-r--r--lib/isc/include/isc/offset.h25
-rw-r--r--lib/isc/include/isc/once.h29
-rw-r--r--lib/isc/include/isc/os.h52
-rw-r--r--lib/isc/include/isc/parseint.h57
-rw-r--r--lib/isc/include/isc/pool.h138
-rw-r--r--lib/isc/include/isc/portset.h135
-rw-r--r--lib/isc/include/isc/print.h29
-rw-r--r--lib/isc/include/isc/quota.h154
-rw-r--r--lib/isc/include/isc/radix.h221
-rw-r--r--lib/isc/include/isc/random.h65
-rw-r--r--lib/isc/include/isc/ratelimiter.h145
-rw-r--r--lib/isc/include/isc/refcount.h244
-rw-r--r--lib/isc/include/isc/regex.h33
-rw-r--r--lib/isc/include/isc/region.h95
-rw-r--r--lib/isc/include/isc/resource.h87
-rw-r--r--lib/isc/include/isc/result.h293
-rw-r--r--lib/isc/include/isc/rwlock.h103
-rw-r--r--lib/isc/include/isc/safe.h44
-rw-r--r--lib/isc/include/isc/serial.h69
-rw-r--r--lib/isc/include/isc/siphash.h36
-rw-r--r--lib/isc/include/isc/sockaddr.h248
-rw-r--r--lib/isc/include/isc/stat.h44
-rw-r--r--lib/isc/include/isc/stats.h253
-rw-r--r--lib/isc/include/isc/stdatomic.h125
-rw-r--r--lib/isc/include/isc/stdio.h71
-rw-r--r--lib/isc/include/isc/stdtime.h61
-rw-r--r--lib/isc/include/isc/strerr.h29
-rw-r--r--lib/isc/include/isc/string.h42
-rw-r--r--lib/isc/include/isc/symtab.h135
-rw-r--r--lib/isc/include/isc/syslog.h38
-rw-r--r--lib/isc/include/isc/task.h646
-rw-r--r--lib/isc/include/isc/taskpool.h135
-rw-r--r--lib/isc/include/isc/thread.h53
-rw-r--r--lib/isc/include/isc/time.h468
-rw-r--r--lib/isc/include/isc/timer.h271
-rw-r--r--lib/isc/include/isc/tls.h587
-rw-r--r--lib/isc/include/isc/tm.h39
-rw-r--r--lib/isc/include/isc/types.h133
-rw-r--r--lib/isc/include/isc/url.h85
-rw-r--r--lib/isc/include/isc/utf8.h43
-rw-r--r--lib/isc/include/isc/util.h377
94 files changed, 14075 insertions, 0 deletions
diff --git a/lib/isc/include/isc/aes.h b/lib/isc/include/isc/aes.h
new file mode 100644
index 0000000..9657494
--- /dev/null
+++ b/lib/isc/include/isc/aes.h
@@ -0,0 +1,40 @@
+/*
+ * 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 isc/aes.h */
+
+#pragma once
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_AES128_KEYLENGTH 16U
+#define ISC_AES192_KEYLENGTH 24U
+#define ISC_AES256_KEYLENGTH 32U
+#define ISC_AES_BLOCK_LENGTH 16U
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_aes128_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out);
+
+void
+isc_aes192_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out);
+
+void
+isc_aes256_crypt(const unsigned char *key, const unsigned char *in,
+ unsigned char *out);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/align.h b/lib/isc/include/isc/align.h
new file mode 100644
index 0000000..7b72e9d
--- /dev/null
+++ b/lib/isc/include/isc/align.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifdef HAVE_STDALIGN_H
+#include <stdalign.h>
+#else /* ifdef HAVE_STDALIGN_H */
+#define alignas(x) __attribute__((__aligned__(x)))
+#endif /* ifdef HAVE_STDALIGN_H */
diff --git a/lib/isc/include/isc/app.h b/lib/isc/include/isc/app.h
new file mode 100644
index 0000000..1a42bd0
--- /dev/null
+++ b/lib/isc/include/isc/app.h
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/app.h
+ * \brief ISC Application Support
+ *
+ * Dealing with program termination can be difficult, especially in a
+ * multithreaded program. The routines in this module help coordinate
+ * the shutdown process. They are used as follows by the initial (main)
+ * thread of the application:
+ *
+ *\li isc_app_start(); Call very early in main(), before
+ * any other threads have been created.
+ *
+ *\li isc_app_run(); This will post any on-run events,
+ * and then block until application
+ * shutdown is requested. A shutdown
+ * request is made by calling
+ * isc_app_shutdown(), or by sending
+ * SIGINT or SIGTERM to the process.
+ * After isc_app_run() returns, the
+ * application should shutdown itself.
+ *
+ *\li isc_app_finish(); Call very late in main().
+ *
+ * Applications that want to use SIGHUP/isc_app_reload() to trigger reloading
+ * should check the result of isc_app_run() and call the reload routine if
+ * the result is ISC_R_RELOAD. They should then call isc_app_run() again
+ * to resume waiting for reload or termination.
+ *
+ * Use of this module is not required. In particular, isc_app_start() is
+ * NOT an ISC library initialization routine.
+ *
+ * This module also supports per-thread 'application contexts'. With this
+ * mode, a thread-based application will have a separate context, in which
+ * it uses other ISC library services such as tasks or timers. Signals are
+ * not caught in this mode, so that the application can handle the signals
+ * in its preferred way.
+ *
+ * \li MP:
+ * Clients must ensure that isc_app_start(), isc_app_run(), and
+ * isc_app_finish() are called at most once. isc_app_shutdown()
+ * is safe to use by any thread (provided isc_app_start() has been
+ * called previously).
+ *
+ * The same note applies to isc_app_ctxXXX() functions, but in this case
+ * it's a per-thread restriction. For example, a thread with an
+ * application context must ensure that isc_app_ctxstart() with the
+ * context is called at most once.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * None.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+#include <stdbool.h>
+
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+/***
+ *** Types
+ ***/
+
+typedef isc_event_t isc_appevent_t;
+
+#define ISC_APPEVENT_FIRSTEVENT (ISC_EVENTCLASS_APP + 0)
+#define ISC_APPEVENT_SHUTDOWN (ISC_EVENTCLASS_APP + 1)
+#define ISC_APPEVENT_LASTEVENT (ISC_EVENTCLASS_APP + 65535)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_app_ctxstart(isc_appctx_t *ctx);
+
+isc_result_t
+isc_app_start(void);
+/*!<
+ * \brief Start an ISC library application.
+ *
+ * Notes:
+ * This call should be made before any other ISC library call, and as
+ * close to the beginning of the application as possible.
+ *
+ * Requires:
+ *\li 'ctx' is a valid application context (for app_ctxstart()).
+ */
+
+isc_result_t
+isc_app_ctxonrun(isc_appctx_t *ctx, isc_mem_t *mctx, isc_task_t *task,
+ isc_taskaction_t action, void *arg);
+isc_result_t
+isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action,
+ void *arg);
+/*!<
+ * \brief Request delivery of an event when the application is run.
+ *
+ * Requires:
+ *\li isc_app_start() has been called.
+ *\li 'ctx' is a valid application context (for app_ctxonrun()).
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ */
+
+isc_result_t
+isc_app_ctxrun(isc_appctx_t *ctx);
+
+isc_result_t
+isc_app_run(void);
+/*!<
+ * \brief Run an ISC library application.
+ *
+ * Notes:
+ *\li The caller (typically the initial thread of an application) will
+ * block until shutdown is requested. When the call returns, the
+ * caller should start shutting down the application.
+ *
+ * Requires:
+ *\li isc_app_[ctx]start() has been called.
+ *
+ * Ensures:
+ *\li Any events requested via isc_app_onrun() will have been posted (in
+ * FIFO order) before isc_app_run() blocks.
+ *\li 'ctx' is a valid application context (for app_ctxrun()).
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS Shutdown has been requested.
+ *\li ISC_R_RELOAD Reload has been requested.
+ */
+
+bool
+isc_app_isrunning(void);
+/*!<
+ * \brief Return if the ISC library application is running.
+ *
+ * Returns:
+ *\li true App is running.
+ *\li false App is not running.
+ */
+
+void
+isc_app_ctxshutdown(isc_appctx_t *ctx);
+
+void
+isc_app_shutdown(void);
+/*!<
+ * \brief Request application shutdown.
+ *
+ * Notes:
+ *\li It is safe to call isc_app_shutdown() multiple times. Shutdown will
+ * only be triggered once.
+ *
+ * Requires:
+ *\li isc_app_[ctx]run() has been called.
+ *\li 'ctx' is a valid application context (for app_ctxshutdown()).
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_UNEXPECTED
+ */
+
+void
+isc_app_ctxsuspend(isc_appctx_t *ctx);
+/*!<
+ * \brief This has the same behavior as isc_app_ctxsuspend().
+ */
+
+void
+isc_app_reload(void);
+/*!<
+ * \brief Request application reload.
+ *
+ * Requires:
+ *\li isc_app_run() has been called.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_UNEXPECTED
+ */
+
+void
+isc_app_ctxfinish(isc_appctx_t *ctx);
+
+void
+isc_app_finish(void);
+/*!<
+ * \brief Finish an ISC library application.
+ *
+ * Notes:
+ *\li This call should be made at or near the end of main().
+ *
+ * Requires:
+ *\li isc_app_start() has been called.
+ *\li 'ctx' is a valid application context (for app_ctxfinish()).
+ *
+ * Ensures:
+ *\li Any resources allocated by isc_app_start() have been released.
+ */
+
+void
+isc_app_block(void);
+/*!<
+ * \brief Indicate that a blocking operation will be performed.
+ *
+ * Notes:
+ *\li If a blocking operation is in process, a call to isc_app_shutdown()
+ * or an external signal will abort the program, rather than allowing
+ * clean shutdown. This is primarily useful for reading user input.
+ *
+ * Requires:
+ * \li isc_app_start() has been called.
+ * \li No other blocking operations are in progress.
+ */
+
+void
+isc_app_unblock(void);
+/*!<
+ * \brief Indicate that a blocking operation is complete.
+ *
+ * Notes:
+ * \li When a blocking operation has completed, return the program to a
+ * state where a call to isc_app_shutdown() or an external signal will
+ * shutdown normally.
+ *
+ * Requires:
+ * \li isc_app_start() has been called.
+ * \li isc_app_block() has been called by the same thread.
+ */
+
+isc_result_t
+isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp);
+/*!<
+ * \brief Create an application context.
+ *
+ * Requires:
+ *\li 'mctx' is a valid memory context.
+ *\li 'ctxp' != NULL && *ctxp == NULL.
+ */
+
+void
+isc_appctx_destroy(isc_appctx_t **ctxp);
+/*!<
+ * \brief Destroy an application context.
+ *
+ * Requires:
+ *\li '*ctxp' is a valid application context.
+ *
+ * Ensures:
+ *\li *ctxp == NULL.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/assertions.h b/lib/isc/include/isc/assertions.h
new file mode 100644
index 0000000..7eafa16
--- /dev/null
+++ b/lib/isc/include/isc/assertions.h
@@ -0,0 +1,73 @@
+/*
+ * 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 isc/assertions.h
+ */
+
+#pragma once
+
+#include <isc/attributes.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% isc assertion type */
+typedef enum {
+ isc_assertiontype_require,
+ isc_assertiontype_ensure,
+ isc_assertiontype_insist,
+ isc_assertiontype_invariant
+} isc_assertiontype_t;
+
+typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t,
+ const char *);
+
+/* coverity[+kill] */
+noreturn void
+isc_assertion_failed(const char *, int, isc_assertiontype_t, const char *);
+
+void isc_assertion_setcallback(isc_assertioncallback_t);
+
+const char *
+isc_assertion_typetotext(isc_assertiontype_t type);
+
+#define ISC_REQUIRE(cond) \
+ ((void)((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_require, #cond), \
+ 0)))
+
+#define ISC_ENSURE(cond) \
+ ((void)((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_ensure, #cond), \
+ 0)))
+
+#define ISC_INSIST(cond) \
+ ((void)((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_insist, #cond), \
+ 0)))
+
+#define ISC_INVARIANT(cond) \
+ ((void)((cond) || \
+ ((isc_assertion_failed)(__FILE__, __LINE__, \
+ isc_assertiontype_invariant, #cond), \
+ 0)))
+
+#define ISC_UNREACHABLE() \
+ (isc_assertion_failed(__FILE__, __LINE__, isc_assertiontype_insist, \
+ "unreachable"), \
+ __builtin_unreachable())
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/astack.h b/lib/isc/include/isc/astack.h
new file mode 100644
index 0000000..a4f6762
--- /dev/null
+++ b/lib/isc/include/isc/astack.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+#include <isc/mem.h>
+#include <isc/types.h>
+
+isc_astack_t *
+isc_astack_new(isc_mem_t *mctx, size_t size);
+/*%<
+ * Allocate and initialize a new array stack of size 'size'.
+ */
+
+void
+isc_astack_destroy(isc_astack_t *stack);
+/*%<
+ * Free an array stack 'stack'.
+ *
+ * Requires:
+ * \li 'stack' is empty.
+ */
+
+bool
+isc_astack_trypush(isc_astack_t *stack, void *obj);
+/*%<
+ * Try to push 'obj' onto array stack 'astack'. On failure, either
+ * because the stack size limit has been reached or because another
+ * thread has already changed the stack pointer, return 'false'.
+ */
+
+void *
+isc_astack_pop(isc_astack_t *stack);
+/*%<
+ * Pop an object off of array stack 'stack'. If the stack is empty,
+ * return NULL.
+ */
diff --git a/lib/isc/include/isc/atomic.h b/lib/isc/include/isc/atomic.h
new file mode 100644
index 0000000..5a415bc
--- /dev/null
+++ b/lib/isc/include/isc/atomic.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if HAVE_STDATOMIC_H
+#include <stdatomic.h>
+#else
+#include <isc/stdatomic.h>
+#endif
+
+#include <isc/util.h>
+
+/*
+ * We define a few additional macros to make things easier
+ */
+
+/* Relaxed Memory Ordering */
+
+#define atomic_store_relaxed(o, v) \
+ atomic_store_explicit((o), (v), memory_order_relaxed)
+#define atomic_load_relaxed(o) atomic_load_explicit((o), memory_order_relaxed)
+#define atomic_fetch_add_relaxed(o, v) \
+ atomic_fetch_add_explicit((o), (v), memory_order_relaxed)
+#define atomic_fetch_sub_relaxed(o, v) \
+ atomic_fetch_sub_explicit((o), (v), memory_order_relaxed)
+#define atomic_fetch_or_relaxed(o, v) \
+ atomic_fetch_or_explicit((o), (v), memory_order_relaxed)
+#define atomic_fetch_and_relaxed(o, v) \
+ atomic_fetch_and_explicit((o), (v), memory_order_relaxed)
+#define atomic_exchange_relaxed(o, v) \
+ atomic_exchange_explicit((o), (v), memory_order_relaxed)
+#define atomic_compare_exchange_weak_relaxed(o, e, d) \
+ atomic_compare_exchange_weak_explicit( \
+ (o), (e), (d), memory_order_relaxed, memory_order_relaxed)
+#define atomic_compare_exchange_strong_relaxed(o, e, d) \
+ atomic_compare_exchange_strong_explicit( \
+ (o), (e), (d), memory_order_relaxed, memory_order_relaxed)
+#define atomic_compare_exchange_strong_acq_rel(o, e, d) \
+ atomic_compare_exchange_strong_explicit( \
+ (o), (e), (d), memory_order_acq_rel, memory_order_acquire)
+
+/* Acquire-Release Memory Ordering */
+
+#define atomic_store_release(o, v) \
+ atomic_store_explicit((o), (v), memory_order_release)
+#define atomic_load_acquire(o) atomic_load_explicit((o), memory_order_acquire)
+#define atomic_fetch_add_release(o, v) \
+ atomic_fetch_add_explicit((o), (v), memory_order_release)
+#define atomic_fetch_sub_release(o, v) \
+ atomic_fetch_sub_explicit((o), (v), memory_order_release)
+#define atomic_fetch_and_release(o, v) \
+ atomic_fetch_and_explicit((o), (v), memory_order_release)
+#define atomic_fetch_or_release(o, v) \
+ atomic_fetch_or_explicit((o), (v), memory_order_release)
+#define atomic_exchange_acq_rel(o, v) \
+ atomic_exchange_explicit((o), (v), memory_order_acq_rel)
+#define atomic_fetch_sub_acq_rel(o, v) \
+ atomic_fetch_sub_explicit((o), (v), memory_order_acq_rel)
+#define atomic_compare_exchange_weak_acq_rel(o, e, d) \
+ atomic_compare_exchange_weak_explicit( \
+ (o), (e), (d), memory_order_acq_rel, memory_order_acquire)
+#define atomic_compare_exchange_strong_acq_rel(o, e, d) \
+ atomic_compare_exchange_strong_explicit( \
+ (o), (e), (d), memory_order_acq_rel, memory_order_acquire)
+
+/* compare/exchange that MUST succeed */
+#define atomic_compare_exchange_enforced(o, e, d) \
+ RUNTIME_CHECK(atomic_compare_exchange_strong((o), (e), (d)))
diff --git a/lib/isc/include/isc/attributes.h b/lib/isc/include/isc/attributes.h
new file mode 100644
index 0000000..abe6152
--- /dev/null
+++ b/lib/isc/include/isc/attributes.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifdef HAVE_STDNORETURN_H
+#include <stdnoreturn.h>
+#elif HAVE_FUNC_ATTRIBUTE_NORETURN
+#define noreturn __attribute__((noreturn))
+#else
+#define noreturn
+#endif
+
+#if HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL
+#define ISC_ATTR_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define ISC_ATTR_RETURNS_NONNULL
+#endif
+
+#ifdef HAVE_FUNC_ATTRIBUTE_MALLOC
+/*
+ * Indicates that a function is malloc-like, i.e., that the
+ * pointer P returned by the function cannot alias any other
+ * pointer valid when the function returns.
+ */
+#define ISC_ATTR_MALLOC __attribute__((malloc))
+#if HAVE_MALLOC_EXT_ATTR
+/*
+ * Associates deallocator as a suitable deallocation function
+ * for pointers returned from the function marked with the attribute.
+ */
+#define ISC_ATTR_DEALLOCATOR(deallocator) __attribute__((malloc(deallocator)))
+/*
+ * Similar to ISC_ATTR_DEALLOCATOR, but allows to speficy an index "idx",
+ * which denotes the positional argument to which when the pointer is passed
+ * in calls to deallocator has the effect of deallocating it.
+ */
+#define ISC_ATTR_DEALLOCATOR_IDX(deallocator, idx) \
+ __attribute__((malloc(deallocator, idx)))
+/*
+ * Combines both ISC_ATTR_MALLOC and ISC_ATTR_DEALLOCATOR attributes.
+ */
+#define ISC_ATTR_MALLOC_DEALLOCATOR(deallocator) \
+ __attribute__((malloc, malloc(deallocator)))
+/*
+ * Similar to ISC_ATTR_MALLOC_DEALLOCATOR, but allows to speficy an index "idx",
+ * which denotes the positional argument to which when the pointer is passed
+ * in calls to deallocator has the effect of deallocating it.
+ */
+#define ISC_ATTR_MALLOC_DEALLOCATOR_IDX(deallocator, idx) \
+ __attribute__((malloc, malloc(deallocator, idx)))
+#else /* #ifdef HAVE_MALLOC_EXT_ATTR */
+/*
+ * There is support for malloc attribute but not for
+ * extended attributes, so macros that combine attribute malloc
+ * with a deallocator will only expand to malloc attribute.
+ */
+#define ISC_ATTR_DEALLOCATOR(deallocator)
+#define ISC_ATTR_DEALLOCATOR_IDX(deallocator, idx)
+#define ISC_ATTR_MALLOC_DEALLOCATOR(deallocator) ISC_ATTR_MALLOC
+#define ISC_ATTR_MALLOC_DEALLOCATOR_IDX(deallocator, idx) ISC_ATTR_MALLOC
+#endif
+#else /* #ifdef HAVE_FUNC_ATTRIBUTE_MALLOC */
+/*
+ * There is no support for malloc attribute.
+ */
+#define ISC_ATTR_MALLOC
+#define ISC_ATTR_DEALLOCATOR(deallocator)
+#define ISC_ATTR_DEALLOCATOR_IDX(deallocator, idx)
+#define ISC_ATTR_MALLOC_DEALLOCATOR(deallocator)
+#define ISC_ATTR_MALLOC_DEALLOCATOR_IDX(deallocator, idx)
+#endif /* HAVE_FUNC_ATTRIBUTE_MALLOC */
diff --git a/lib/isc/include/isc/backtrace.h b/lib/isc/include/isc/backtrace.h
new file mode 100644
index 0000000..f818c3b
--- /dev/null
+++ b/lib/isc/include/isc/backtrace.h
@@ -0,0 +1,101 @@
+/*
+ * 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 isc/backtrace.h
+ * \brief provide a back trace of the running process to help debug problems.
+ *
+ * This module tries to get a back trace of the process using some platform
+ * dependent way when available. It also manages an internal symbol table
+ * that maps function addresses used in the process to their textual symbols.
+ * This module is expected to be used to help debug when some fatal error
+ * happens.
+ *
+ * IMPORTANT NOTE: since the (major) intended use case of this module is
+ * dumping a back trace on a fatal error, normally followed by self termination,
+ * functions defined in this module generally doesn't employ assertion checks
+ * (if it did, a program bug could cause infinite recursive calls to a
+ * backtrace function).
+ */
+
+#pragma once
+
+/***
+ *** Imports
+ ***/
+#include <isc/types.h>
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+int
+isc_backtrace(void **addrs, int maxaddrs);
+/*%<
+ * Get a back trace of the running process above this function itself. On
+ * success, addrs[i] will store the address of the call point of the i-th
+ * stack frame (addrs[0] is the caller of this function). *nframes will store
+ * the total number of frames.
+ *
+ * Requires (note that these are not ensured by assertion checks, see above):
+ *
+ *\li 'addrs' is a valid array containing at least 'maxaddrs' void * entries.
+ *
+ *\li 'nframes' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_FAILURE
+ *\li #ISC_R_NOTFOUND
+ *\li #ISC_R_NOTIMPLEMENTED
+ */
+
+char **
+isc_backtrace_symbols(void *const *buffer, int size);
+/*
+ * isc_backtrace_symbols() attempts to transform a call stack obtained by
+ * backtrace() into an array of human-readable strings using dladdr(). The
+ * array of strings returned has size elements. It is allocated using
+ * malloc() and should be released using free(). There is no need to free
+ * the individual strings in the array.
+ *
+ * Notes:
+ *
+ *\li On Windows, this is shim implementation using SymFromAddr()
+ *\li On systems with backtrace_symbols(), it's just a thin wrapper
+ *\li Otherwise, it returns NULL
+ *\li See platform NOTES for backtrace_symbols
+ *
+ * Returns:
+ *
+ *\li On success, backtrace_symbols() returns a pointer to the array
+ *\li On error, NULL is returned.
+ */
+
+void
+isc_backtrace_symbols_fd(void *const *buffer, int size, int fd);
+/*
+ * isc_backtrace_symbols_fd() performs the same operation as
+ * isc_backtrace_symbols(), but the resulting strings are immediately written to
+ * the file descriptor fd, and are not returned. isc_backtrace_symbols_fd()
+ * does not call malloc(3), and so can be employed in situations where the
+ * latter function might fail.
+ *
+ * Notes:
+ *
+ *\li See isc_backtrace_symbols() notes
+ *\li See platform NOTES for backtrace_symbols_fd for caveats
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/barrier.h b/lib/isc/include/isc/barrier.h
new file mode 100644
index 0000000..a60472f
--- /dev/null
+++ b/lib/isc/include/isc/barrier.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <isc/util.h>
+
+#if HAVE_PTHREAD_BARRIER_INIT
+
+#include <pthread.h>
+
+#define isc_barrier_t pthread_barrier_t
+
+#define isc_barrier_init(barrier, count) \
+ pthread_barrier_init(barrier, NULL, count)
+#define isc_barrier_destroy(barrier) pthread_barrier_destroy(barrier)
+#define isc_barrier_wait(barrier) pthread_barrier_wait(barrier)
+
+#else
+
+#include <uv.h>
+
+#define isc_barrier_t uv_barrier_t
+
+#define isc_barrier_init(barrier, count) uv_barrier_init(barrier, count)
+#define isc_barrier_destroy(barrier) uv_barrier_destroy(barrier)
+#define isc_barrier_wait(barrier) uv_barrier_wait(barrier)
+
+#endif /* __SANITIZE_THREAD__ */
diff --git a/lib/isc/include/isc/base32.h b/lib/isc/include/isc/base32.h
new file mode 100644
index 0000000..1faa629
--- /dev/null
+++ b/lib/isc/include/isc/base32.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+/*
+ * Routines for manipulating base 32 and base 32 hex encoded data.
+ * Based on RFC 4648.
+ *
+ * Base 32 hex preserves the sort order of data when it is encoded /
+ * decoded.
+ *
+ * Base 32 hex "np" is base 32 hex but no padding is produced or accepted.
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
+ isc_buffer_t *target);
+isc_result_t
+isc_base32hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base32 encoded text.
+ *
+ * Notes:
+ *\li The base32 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the base32 encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_base32_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated string in base32, base32hex, or
+ * base32hex non-padded.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE32 -- 'cstr' is not a valid base32 encoding.
+ *
+ * Other error returns are any possible error code from:
+ *\li isc_lex_create(),
+ *\li isc_lex_openbuffer(),
+ *\li isc_base32_tobuffer().
+ */
+
+isc_result_t
+isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert text encoded in base32, base32hex, or base32hex
+ * non-padded from a lexer context into `target`. If 'length' is
+ * non-negative, it is the expected number of encoded octets to convert.
+ *
+ * If 'length' is -1 then 0 or more encoded octets are expected.
+ * If 'length' is -2 then 1 or more encoded octets are expected.
+ *
+ * Returns:
+ *\li #ISC_R_BADBASE32 -- invalid base32 encoding.
+ *\li #ISC_R_UNEXPECTEDEND: the text does not contain the expected
+ * number of encoded octets.
+ *
+ * Requires:
+ *\li 'lexer' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is -2, -1, or non-negative
+ *
+ * Ensures:
+ *\li target will contain the data represented by the base32 encoded
+ * string parsed by the lexer. No more than `length` octets will
+ * be read, if `length` is non-negative. The 'used' pointer in
+ * 'target' will be advanced as necessary.
+ */
+
+isc_result_t
+isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target);
+/*!<
+ * \brief Decode a packed (no white space permitted) region in
+ * base32, base32hex or base32hex non-padded.
+ *
+ * Requires:
+ *\li 'source' is a valid region.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE32 -- 'source' is not a valid base32 encoding.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/base64.h b/lib/isc/include/isc/base64.h
new file mode 100644
index 0000000..b1bc089
--- /dev/null
+++ b/lib/isc/include/isc/base64.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/base64.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base64_totext(isc_region_t *source, int wordlength, const char *wordbreak,
+ isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base64 encoded text.
+ *
+ * Notes:
+ *\li The base64 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the base64 encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_base64_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated base64 string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding.
+ *
+ * Other error returns are any possible error code from:
+ *\li isc_lex_create(),
+ *\li isc_lex_openbuffer(),
+ *\li isc_base64_tobuffer().
+ */
+
+isc_result_t
+isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert base64 encoded text from a lexer context into
+ * `target`. If 'length' is non-negative, it is the expected number of
+ * encoded octets to convert.
+ *
+ * If 'length' is -1 then 0 or more encoded octets are expected.
+ * If 'length' is -2 then 1 or more encoded octets are expected.
+ *
+ * Returns:
+ *\li #ISC_R_BADBASE64 -- invalid base64 encoding.
+ *\li #ISC_R_UNEXPECTEDEND: the text does not contain the expected
+ * number of encoded octets.
+ *
+ * Requires:
+ *\li 'lexer' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is -2, -1, or non-negative
+ *
+ * Ensures:
+ *\li target will contain the data represented by the base64 encoded
+ * string parsed by the lexer. No more than `length` octets will
+ * be read, if `length` is non-negative. The 'used' pointer in
+ * 'target' will be advanced as necessary.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/buffer.h b/lib/isc/include/isc/buffer.h
new file mode 100644
index 0000000..1be0081
--- /dev/null
+++ b/lib/isc/include/isc/buffer.h
@@ -0,0 +1,1023 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/buffer.h
+ *
+ * \brief A buffer is a region of memory, together with a set of related
+ * subregions. Buffers are used for parsing and I/O operations.
+ *
+ * The 'used region' and the 'available region' are disjoint, and their
+ * union is the buffer's region. The used region extends from the beginning
+ * of the buffer region to the last used byte. The available region
+ * extends from one byte greater than the last used byte to the end of the
+ * buffer's region. The size of the used region can be changed using various
+ * buffer commands. Initially, the used region is empty.
+ *
+ * The used region is further subdivided into two disjoint regions: the
+ * 'consumed region' and the 'remaining region'. The union of these two
+ * regions is the used region. The consumed region extends from the beginning
+ * of the used region to the byte before the 'current' offset (if any). The
+ * 'remaining' region extends from the current offset to the end of the used
+ * region. The size of the consumed region can be changed using various
+ * buffer commands. Initially, the consumed region is empty.
+ *
+ * The 'active region' is an (optional) subregion of the remaining region.
+ * It extends from the current offset to an offset in the remaining region
+ * that is selected with isc_buffer_setactive(). Initially, the active region
+ * is empty. If the current offset advances beyond the chosen offset, the
+ * active region will also be empty.
+ *
+ * \verbatim
+ * /------------entire length---------------\
+ * /----- used region -----\/-- available --\
+ * +----------------------------------------+
+ * | consumed | remaining | |
+ * +----------------------------------------+
+ * a b c d e
+ *
+ * a == base of buffer.
+ * b == current pointer. Can be anywhere between a and d.
+ * c == active pointer. Meaningful between b and d.
+ * d == used pointer.
+ * e == length of buffer.
+ *
+ * a-e == entire length of buffer.
+ * a-d == used region.
+ * a-b == consumed region.
+ * b-d == remaining region.
+ * b-c == optional active region.
+ *\endverbatim
+ *
+ * The following invariants are maintained by all routines:
+ *
+ *\code
+ * length > 0
+ *
+ * base is a valid pointer to length bytes of memory
+ *
+ * 0 <= used <= length
+ *
+ * 0 <= current <= used
+ *
+ * 0 <= active <= used
+ * (although active < current implies empty active region)
+ *\endcode
+ *
+ * \li MP:
+ * Buffers have no synchronization. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * Memory: 1 pointer + 6 unsigned integers per buffer.
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/list.h>
+#include <isc/magic.h>
+#include <isc/region.h>
+#include <isc/string.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*@{*/
+/*!
+ *** Magic numbers
+ ***/
+#define ISC_BUFFER_MAGIC 0x42756621U /* Buf!. */
+#define ISC_BUFFER_VALID(b) ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC)
+/*@}*/
+
+/*!
+ * Size granularity for dynamically resizable buffers; when reserving
+ * space in a buffer, we round the allocated buffer length up to the
+ * nearest * multiple of this value.
+ */
+#define ISC_BUFFER_INCR 2048
+
+/*
+ * The following macros MUST be used only on valid buffers. It is the
+ * caller's responsibility to ensure this by using the ISC_BUFFER_VALID
+ * check above, or by calling another isc_buffer_*() function (rather than
+ * another macro.)
+ */
+
+/*@{*/
+/*!
+ * Fundamental buffer elements. (A through E in the introductory comment.)
+ */
+#define isc_buffer_base(b) ((void *)(b)->base) /*a*/
+#define isc_buffer_current(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->current)) /*b*/
+#define isc_buffer_active(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->active)) /*c*/
+#define isc_buffer_used(b) \
+ ((void *)((unsigned char *)(b)->base + (b)->used)) /*d*/
+#define isc_buffer_length(b) ((b)->length) /*e*/
+/*@}*/
+
+/*@{*/
+/*!
+ * Derived lengths. (Described in the introductory comment.)
+ */
+#define isc_buffer_usedlength(b) ((b)->used) /* d-a */
+#define isc_buffer_consumedlength(b) ((b)->current) /* b-a */
+#define isc_buffer_remaininglength(b) ((b)->used - (b)->current) /* d-b */
+#define isc_buffer_activelength(b) ((b)->active - (b)->current) /* c-b */
+#define isc_buffer_availablelength(b) ((b)->length - (b)->used) /* e-d */
+/*@}*/
+
+/*!
+ * Note that the buffer structure is public. This is principally so buffer
+ * operations can be implemented using macros. Applications are strongly
+ * discouraged from directly manipulating the structure.
+ */
+
+struct isc_buffer {
+ unsigned int magic;
+ void *base;
+ /*@{*/
+ /*! The following integers are byte offsets from 'base'. */
+ unsigned int length;
+ unsigned int used;
+ unsigned int current;
+ unsigned int active;
+ /*@}*/
+ /*! linkable */
+ ISC_LINK(isc_buffer_t) link;
+ /*! private internal elements */
+ isc_mem_t *mctx;
+ /* automatically realloc buffer at put* */
+ bool autore;
+};
+
+/***
+ *** Functions
+ ***/
+
+void
+isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
+ unsigned int length);
+/*!<
+ * \brief Allocate a dynamic linkable buffer which has "length" bytes in the
+ * data region.
+ *
+ * Requires:
+ *\li "mctx" is valid.
+ *
+ *\li "dynbuffer" is non-NULL, and "*dynbuffer" is NULL.
+ *
+ * Note:
+ *\li Changing the buffer's length field is not permitted.
+ */
+
+isc_result_t
+isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size);
+/*!<
+ * \brief Make "size" bytes of space available in the buffer. The buffer
+ * pointer may move when you call this function.
+ *
+ * Requires:
+ *\li "dynbuffer" is not NULL.
+ *
+ *\li "*dynbuffer" is a valid dynamic buffer.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS - success
+ *\li ISC_R_NOMEMORY - no memory available
+ *
+ * Ensures:
+ *\li "*dynbuffer" will be valid on return and will contain all the
+ * original data. However, the buffer pointer may be moved during
+ * reallocation.
+ */
+
+void
+isc_buffer_free(isc_buffer_t **dynbuffer);
+/*!<
+ * \brief Release resources allocated for a dynamic buffer.
+ *
+ * Requires:
+ *\li "dynbuffer" is not NULL.
+ *
+ *\li "*dynbuffer" is a valid dynamic buffer.
+ *
+ * Ensures:
+ *\li "*dynbuffer" will be NULL on return, and all memory associated with
+ * the dynamic buffer is returned to the memory context used in
+ * isc_buffer_allocate().
+ */
+
+void
+isc__buffer_initnull(isc_buffer_t *b);
+
+void
+isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length);
+/*!<
+ * \brief Make 'b' refer to the 'length'-byte region starting at base.
+ * Any existing data will be copied.
+ *
+ * Requires:
+ *
+ *\li 'length' > 0 AND length >= previous length
+ *
+ *\li 'base' is a pointer to a sequence of 'length' bytes.
+ *
+ */
+
+void
+isc_buffer_setautorealloc(isc_buffer_t *b, bool enable);
+/*!<
+ * \brief Enable or disable autoreallocation on 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid dynamic buffer (b->mctx != NULL).
+ *
+ */
+
+void
+isc_buffer_compact(isc_buffer_t *b);
+/*!<
+ * \brief Compact the used region by moving the remaining region so it occurs
+ * at the start of the buffer. The used region is shrunk by the size of
+ * the consumed region, and the consumed region is then made empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li current == 0
+ *
+ *\li The size of the used region is now equal to the size of the remaining
+ * region (as it was before the call). The contents of the used region
+ * are those of the remaining region (as it was before the call).
+ */
+
+uint8_t
+isc_buffer_getuint8(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 8-bit integer from 'b' and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the remaining region of 'b' is at least 1.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 1.
+ *
+ * Returns:
+ *
+ *\li A 8-bit unsigned integer.
+ */
+
+uint16_t
+isc_buffer_getuint16(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 16-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the remaining region of 'b' is at least 2.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 2.
+ *
+ * Returns:
+ *
+ *\li A 16-bit unsigned integer.
+ */
+
+uint32_t
+isc_buffer_getuint32(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 32-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the remaining region of 'b' is at least 4.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 4.
+ *
+ * Returns:
+ *
+ *\li A 32-bit unsigned integer.
+ */
+
+uint64_t
+isc_buffer_getuint48(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 48-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the remaining region of 'b' is at least 6.
+ *
+ * Ensures:
+ *
+ *\li The current pointer in 'b' is advanced by 6.
+ *
+ * Returns:
+ *
+ *\li A 48-bit unsigned integer (stored in a 64-bit integer).
+ */
+
+void
+isc_buffer_putdecint(isc_buffer_t *b, int64_t v);
+/*!<
+ * \brief Put decimal representation of 'v' in b
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least strlen(dec('v'))
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by strlen(dec('v')).
+ */
+
+isc_result_t
+isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r);
+/*!<
+ * \brief Copy the contents of 'r' into 'b'.
+ *
+ * Notes:
+ *\li If 'b' has autoreallocation enabled, and the length of 'r' is greater
+ * than the length of the available region of 'b', 'b' is reallocated.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' is a valid region.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ *\li ISC_R_NOSPACE The available region of 'b' is not
+ * big enough.
+ */
+
+isc_result_t
+isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src);
+/*!<
+ * \brief Allocate 'dst' and copy used contents of 'src' into it.
+ *
+ * Requires:
+ *\li 'dstp' is not NULL and *dst is NULL.
+ *\li 'src' is a valid buffer.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS
+ */
+
+isc_result_t
+isc_buffer_printf(isc_buffer_t *b, const char *format, ...)
+ ISC_FORMAT_PRINTF(2, 3);
+/*!<
+ * \brief Append a formatted string to the used region of 'b'.
+ *
+ * Notes:
+ *
+ *\li The 'format' argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ *\li If 'b' has autoreallocation enabled, and the length of the formatted
+ * string is greater than the length of the available region of 'b', 'b'
+ * is reallocated.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ * Ensures:
+ *
+ *\li The used pointer in 'b' is advanced by the number of bytes appended
+ * (excluding the terminating NULL byte).
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS Operation succeeded.
+ *\li #ISC_R_NOSPACE 'b' does not allow reallocation and appending the
+ * formatted string to it would cause it to overflow.
+ *\li #ISC_R_NOMEMORY Reallocation failed.
+ *\li #ISC_R_FAILURE Other error occurred.
+ */
+
+/*
+ * Buffer functions implemented as inline.
+ */
+
+/*! \note
+ * XXXDCL Something more could be done with initializing buffers that
+ * point to const data. For example, isc_buffer_constinit() could
+ * set a new boolean flag in the buffer structure indicating whether
+ * the buffer was initialized with that function. Then if the
+ * boolean were true, the isc_buffer_put* functions could assert a
+ * contractual requirement for a non-const buffer.
+ *
+ * One drawback is that the isc_buffer_* functions that return
+ * pointers would still need to return non-const pointers to avoid compiler
+ * warnings, so it would be up to code that uses them to have to deal
+ * with the possibility that the buffer was initialized as const --
+ * a problem that they *already* have to deal with but have absolutely
+ * no ability to. With a new isc_buffer_isconst() function returning
+ * true/false, they could at least assert a contractual requirement for
+ * non-const buffers when needed.
+ */
+
+/*!
+ * \brief Make 'b' refer to the 'length'-byte region starting at 'base'.
+ *
+ * Requires:
+ *
+ *\li 'length' > 0
+ *
+ *\li 'base' is a pointer to a sequence of 'length' bytes.
+ */
+static inline void
+isc_buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
+ ISC_REQUIRE(b != NULL);
+
+ *b = (isc_buffer_t){ .base = base,
+ .length = length,
+ .magic = ISC_BUFFER_MAGIC };
+ ISC_LINK_INIT(b, link);
+}
+
+/*!
+ *\brief Initialize a buffer 'b' with a null data field and zero length.
+ * This can later be grown as needed and swapped in place.
+ */
+static inline void
+isc_buffer_initnull(isc_buffer_t *b) {
+ *b = (isc_buffer_t){ .magic = ISC_BUFFER_MAGIC };
+ ISC_LINK_INIT(b, link);
+}
+
+/*!
+ * \brief Make 'b' refer to the 'length'-byte constant region starting
+ * at 'base'.
+ *
+ * Requires:
+ *
+ *\li 'length' > 0
+ *\li 'base' is a pointer to a sequence of 'length' bytes.
+ */
+#define isc_buffer_constinit(_b, _d, _l) \
+ do { \
+ union { \
+ void *_var; \
+ const void *_const; \
+ } _deconst; \
+ _deconst._const = (_d); \
+ isc_buffer_init((_b), _deconst._var, (_l)); \
+ } while (0)
+
+/*!
+ * \brief Make 'b' an invalid buffer.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ * Ensures:
+ *\li Future attempts to use 'b' without calling isc_buffer_init() on
+ * it will cause an assertion failure.
+ */
+static inline void
+isc_buffer_invalidate(isc_buffer_t *b) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(!ISC_LINK_LINKED(b, link));
+ ISC_REQUIRE(b->mctx == NULL);
+
+ b->magic = 0;
+ b->base = NULL;
+ b->length = 0;
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+/*!
+ * \brief Make 'r' refer to the region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+static inline void
+isc_buffer_region(isc_buffer_t *b, isc_region_t *r) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(r != NULL);
+
+ r->base = b->base;
+ r->length = b->length;
+}
+
+/*!
+ * \brief Make 'r' refer to the used region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+static inline void
+isc_buffer_usedregion(const isc_buffer_t *b, isc_region_t *r) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(r != NULL);
+
+ r->base = b->base;
+ r->length = b->used;
+}
+
+/*!
+ * \brief Make 'r' refer to the available region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+static inline void
+isc_buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(r != NULL);
+
+ r->base = isc_buffer_used(b);
+ r->length = isc_buffer_availablelength(b);
+}
+
+/*!
+ * \brief Increase the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li used + n <= length
+ */
+static inline void
+isc_buffer_add(isc_buffer_t *b, unsigned int n) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(b->used + n <= b->length);
+
+ b->used += n;
+}
+
+/*!
+ * \brief Decrease the 'used' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li used >= n
+ */
+static inline void
+isc_buffer_subtract(isc_buffer_t *b, unsigned int n) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(b->used >= n);
+
+ b->used -= n;
+ if (b->current > b->used) {
+ b->current = b->used;
+ }
+ if (b->active > b->used) {
+ b->active = b->used;
+ }
+}
+
+/*!<
+ * \brief Make the used region empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li used = 0
+ */
+static inline void
+isc_buffer_clear(isc_buffer_t *b) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ b->used = 0;
+ b->current = 0;
+ b->active = 0;
+}
+
+/*!
+ * \brief Make 'r' refer to the consumed region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+static inline void
+isc_buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(r != NULL);
+
+ r->base = b->base;
+ r->length = b->current;
+}
+
+/*!
+ * \brief Make 'r' refer to the remaining region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+static inline void
+isc_buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(r != NULL);
+
+ r->base = isc_buffer_current(b);
+ r->length = isc_buffer_remaininglength(b);
+}
+
+/*!
+ * \brief Make 'r' refer to the active region of 'b'.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'r' points to a region structure.
+ */
+static inline void
+isc_buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(r != NULL);
+
+ if (b->current < b->active) {
+ r->base = isc_buffer_current(b);
+ r->length = isc_buffer_activelength(b);
+ } else {
+ r->base = NULL;
+ r->length = 0;
+ }
+}
+
+/*!
+ * \brief Sets the end of the active region 'n' bytes after current.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer.
+ *
+ *\li current + n <= used
+ */
+static inline void
+isc_buffer_setactive(isc_buffer_t *b, unsigned int n) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(b->current + n <= b->used);
+
+ b->active = b->current + n;
+}
+
+/*!<
+ * \brief Make the consumed region empty.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ * Ensures:
+ *
+ *\li current == 0
+ */
+static inline void
+isc_buffer_first(isc_buffer_t *b) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ b->current = 0;
+}
+
+/*!
+ * \brief Increase the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li current + n <= used
+ */
+static inline void
+isc_buffer_forward(isc_buffer_t *b, unsigned int n) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(b->current + n <= b->used);
+
+ b->current += n;
+}
+
+/*!
+ * \brief Decrease the 'consumed' region of 'b' by 'n' bytes.
+ *
+ * Requires:
+ *
+ *\li 'b' is a valid buffer
+ *
+ *\li n <= current
+ */
+static inline void
+isc_buffer_back(isc_buffer_t *b, unsigned int n) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(n <= b->current);
+
+ b->current -= n;
+}
+
+/*!
+ * \brief Store an unsigned 8-bit integer from 'val' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 1
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 1.
+ */
+static inline void
+isc_buffer_putuint8(isc_buffer_t *b, uint8_t val) {
+ unsigned char *cp;
+
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, 1) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= 1U);
+
+ cp = isc_buffer_used(b);
+ b->used++;
+ cp[0] = val;
+}
+
+/*!
+ * \brief Store an unsigned 16-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 2
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 2.
+ */
+static inline void
+isc_buffer_putuint16(isc_buffer_t *b, uint16_t val) {
+ unsigned char *cp;
+
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, 2) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= 2U);
+
+ cp = isc_buffer_used(b);
+ b->used += 2;
+ cp[0] = (unsigned char)(val >> 8);
+ cp[1] = (unsigned char)val;
+}
+
+/*!
+ * Store an unsigned 24-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 3
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 3.
+ */
+static inline void
+isc_buffer_putuint24(isc_buffer_t *b, uint32_t val) {
+ unsigned char *cp;
+
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, 3) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= 3U);
+
+ cp = isc_buffer_used(b);
+ b->used += 3;
+ cp[0] = (unsigned char)(val >> 16);
+ cp[1] = (unsigned char)(val >> 8);
+ cp[2] = (unsigned char)val;
+}
+
+/*!
+ * \brief Store an unsigned 32-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 4
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 4.
+ */
+static inline void
+isc_buffer_putuint32(isc_buffer_t *b, uint32_t val) {
+ unsigned char *cp;
+
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, 4) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= 4U);
+
+ cp = isc_buffer_used(b);
+ b->used += 4;
+ cp[0] = (unsigned char)(val >> 24);
+ cp[1] = (unsigned char)(val >> 16);
+ cp[2] = (unsigned char)(val >> 8);
+ cp[3] = (unsigned char)val;
+}
+
+/*!
+ * \brief Store an unsigned 48-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li The length of the available region of 'b' is at least 6
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 6.
+ */
+static inline void
+isc_buffer_putuint48(isc_buffer_t *b, uint64_t val) {
+ unsigned char *cp = NULL;
+
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, 6) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= 6U);
+
+ cp = isc_buffer_used(b);
+ b->used += 6;
+ cp[0] = (unsigned char)(val >> 40);
+ cp[1] = (unsigned char)(val >> 32);
+ cp[2] = (unsigned char)(val >> 24);
+ cp[3] = (unsigned char)(val >> 16);
+ cp[4] = (unsigned char)(val >> 8);
+ cp[5] = (unsigned char)val;
+}
+
+/*!
+ * \brief Copy 'length' bytes of memory at 'base' into 'b'.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'base' points to 'length' bytes of valid memory.
+ *
+ *\li The length of the available region of 'b' is at least 'length'
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 'length'.
+ */
+static inline void
+isc_buffer_putmem(isc_buffer_t *b, const unsigned char *base,
+ unsigned int length) {
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, length) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= (unsigned int)length);
+
+ if (length > 0U) {
+ memmove(isc_buffer_used(b), base, length);
+ b->used += length;
+ }
+}
+
+/*!
+ * \brief Copy 'source' into 'b', not including terminating NUL.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ *\li 'source' is a valid NULL terminated string.
+ *
+ *\li The length of the available region of 'b' is at least strlen('source')
+ * or the buffer has autoreallocation enabled.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by strlen('source').
+ */
+static inline void
+isc_buffer_putstr(isc_buffer_t *b, const char *source) {
+ unsigned int length;
+ unsigned char *cp;
+
+ ISC_REQUIRE(ISC_BUFFER_VALID(b));
+ ISC_REQUIRE(source != NULL);
+
+ length = (unsigned int)strlen(source);
+ if (b->autore) {
+ isc_buffer_t *tmp = b;
+ ISC_REQUIRE(isc_buffer_reserve(&tmp, length) == ISC_R_SUCCESS);
+ }
+
+ ISC_REQUIRE(isc_buffer_availablelength(b) >= length);
+
+ cp = isc_buffer_used(b);
+ memmove(cp, source, length);
+ b->used += length;
+}
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/cmocka.h b/lib/isc/include/isc/cmocka.h
new file mode 100644
index 0000000..de86d5a
--- /dev/null
+++ b/lib/isc/include/isc/cmocka.h
@@ -0,0 +1,55 @@
+/*
+ * 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 isc/cmocka.h */
+
+#pragma once
+
+#include <cmocka.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Copy the test identified by 'name' from 'tests' to 'selected'.
+ */
+#define cmocka_add_test_byname(tests, name, selected) \
+ _cmocka_add_test_byname(tests, sizeof(tests) / sizeof(tests[0]), name, \
+ selected, \
+ sizeof(selected) / sizeof(selected[0]))
+
+static inline bool
+_cmocka_add_test_byname(const struct CMUnitTest *tests, size_t ntests,
+ const char *name, struct CMUnitTest *selected,
+ size_t nselected) {
+ size_t i, j;
+
+ for (i = 0; i < ntests && tests[i].name != NULL; i++) {
+ if (strcmp(tests[i].name, name) != 0) {
+ continue;
+ }
+ for (j = 0; j < nselected && selected[j].name != NULL; j++) {
+ if (strcmp(tests[j].name, name) == 0) {
+ break;
+ }
+ }
+ if (j < nselected && selected[j].name == NULL) {
+ selected[j] = tests[i];
+ }
+ return (true);
+ }
+ return (false);
+}
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/commandline.h b/lib/isc/include/isc/commandline.h
new file mode 100644
index 0000000..ac72135
--- /dev/null
+++ b/lib/isc/include/isc/commandline.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/commandline.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+/*% Index into parent argv vector. */
+extern int isc_commandline_index;
+/*% Character checked for validity. */
+extern int isc_commandline_option;
+/*% Argument associated with option. */
+extern char *isc_commandline_argument;
+/*% For printing error messages. */
+extern char *isc_commandline_progname;
+/*% Print error message. */
+extern bool isc_commandline_errprint;
+/*% Reset getopt. */
+extern bool isc_commandline_reset;
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_commandline_parse(int argc, char *const *argv, const char *options);
+/*%<
+ * Parse a command line (similar to getopt())
+ */
+
+isc_result_t
+isc_commandline_strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp,
+ char ***argvp, unsigned int n);
+/*%<
+ * Tokenize the string "s" into whitespace-separated words,
+ * returning the number of words in '*argcp' and an array
+ * of pointers to the words in '*argvp'. The caller
+ * must free the array using isc_mem_free(). The string
+ * is modified in-place.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/condition.h b/lib/isc/include/isc/condition.h
new file mode 100644
index 0000000..0e1dcf1
--- /dev/null
+++ b/lib/isc/include/isc/condition.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <errno.h>
+
+#include <isc/error.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/result.h>
+#include <isc/strerr.h>
+#include <isc/string.h>
+#include <isc/types.h>
+
+typedef pthread_cond_t isc_condition_t;
+
+#define isc_condition_init(cond) \
+ if (pthread_cond_init(cond, NULL) != 0) { \
+ FATAL_SYSERROR(errno, "pthread_cond_init()"); \
+ }
+
+#define isc_condition_wait(cp, mp) \
+ ((pthread_cond_wait((cp), (mp)) == 0) ? ISC_R_SUCCESS \
+ : ISC_R_UNEXPECTED)
+
+#define isc_condition_signal(cp) \
+ ((pthread_cond_signal((cp)) == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_broadcast(cp) \
+ ((pthread_cond_broadcast((cp)) == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_condition_destroy(cp) \
+ ((pthread_cond_destroy((cp)) == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/counter.h b/lib/isc/include/isc/counter.h
new file mode 100644
index 0000000..820e4a2
--- /dev/null
+++ b/lib/isc/include/isc/counter.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/counter.h
+ *
+ * \brief The isc_counter_t object is a simplified version of the
+ * isc_quota_t object; it tracks the consumption of limited
+ * resources, returning an error condition when the quota is
+ * exceeded. However, unlike isc_quota_t, attaching and detaching
+ * from a counter object does not increment or decrement the counter.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+***** Types.
+*****/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp);
+/*%<
+ * Allocate and initialize a counter object.
+ */
+
+isc_result_t
+isc_counter_increment(isc_counter_t *counter);
+/*%<
+ * Increment the counter.
+ *
+ * If the counter limit is nonzero and has been reached, then
+ * return ISC_R_QUOTA, otherwise ISC_R_SUCCESS. (The counter is
+ * incremented regardless of return value.)
+ */
+
+unsigned int
+isc_counter_used(isc_counter_t *counter);
+/*%<
+ * Return the current counter value.
+ */
+
+void
+isc_counter_setlimit(isc_counter_t *counter, int limit);
+/*%<
+ * Set the counter limit.
+ */
+
+void
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp);
+/*%<
+ * Attach to a counter object, increasing its reference counter.
+ */
+
+void
+isc_counter_detach(isc_counter_t **counterp);
+/*%<
+ * Detach (and destroy if reference counter has dropped to zero)
+ * a counter object.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/crc64.h b/lib/isc/include/isc/crc64.h
new file mode 100644
index 0000000..4147672
--- /dev/null
+++ b/lib/isc/include/isc/crc64.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/crc64.h
+ * \brief CRC64 in C
+ */
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_crc64_init(uint64_t *crc);
+/*%
+ * Initialize a new CRC.
+ *
+ * Requires:
+ * * 'crc' is not NULL.
+ */
+
+void
+isc_crc64_update(uint64_t *crc, const void *data, size_t len);
+/*%
+ * Add data to the CRC.
+ *
+ * Requires:
+ * * 'crc' is not NULL.
+ * * 'data' is not NULL.
+ */
+
+void
+isc_crc64_final(uint64_t *crc);
+/*%
+ * Finalize the CRC.
+ *
+ * Requires:
+ * * 'crc' is not NULL.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/deprecated.h b/lib/isc/include/isc/deprecated.h
new file mode 100644
index 0000000..c83508d
--- /dev/null
+++ b/lib/isc/include/isc/deprecated.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if (__GNUC__ + 0) > 3
+#define ISC_DEPRECATED __attribute__((deprecated))
+#else /* if (__GNUC__ + 0) > 3 */
+#define ISC_DEPRECATED /* none */
+#endif /* __GNUC__ > 3*/
diff --git a/lib/isc/include/isc/dir.h b/lib/isc/include/isc/dir.h
new file mode 100644
index 0000000..c1ff2c7
--- /dev/null
+++ b/lib/isc/include/isc/dir.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <dirent.h>
+#include <limits.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#include <sys/types.h> /* Required on some systems. */
+
+#ifndef NAME_MAX
+#define NAME_MAX 256
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+/*% Directory Entry */
+typedef struct isc_direntry {
+ char name[NAME_MAX];
+ unsigned int length;
+} isc_direntry_t;
+
+/*% Directory */
+typedef struct isc_dir {
+ unsigned int magic;
+ char dirname[PATH_MAX];
+ isc_direntry_t entry;
+ DIR *handle;
+} isc_dir_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_dir_init(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname);
+
+isc_result_t
+isc_dir_read(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_reset(isc_dir_t *dir);
+
+void
+isc_dir_close(isc_dir_t *dir);
+
+isc_result_t
+isc_dir_chdir(const char *dirname);
+
+isc_result_t
+isc_dir_chroot(const char *dirname);
+
+isc_result_t
+isc_dir_createunique(char *templet);
+/*!<
+ * Use a templet (such as from isc_file_mktemplate()) to create a uniquely
+ * named, empty directory. The templet string is modified in place.
+ * If result == ISC_R_SUCCESS, it is the name of the directory that was
+ * created.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/endian.h b/lib/isc/include/isc/endian.h
new file mode 100644
index 0000000..be91b1d
--- /dev/null
+++ b/lib/isc/include/isc/endian.h
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__OpenBSD__) || defined(__bsdi__)
+
+#include <sys/endian.h>
+
+/*
+ * Recent BSDs should have [bl]e{16,32,64}toh() defined in <sys/endian.h>.
+ * Older ones might not, but these should have the alternatively named
+ * [bl]etoh{16,32,64}() functions defined.
+ */
+#ifndef be16toh
+#define be16toh(x) betoh16(x)
+#define le16toh(x) letoh16(x)
+#define be32toh(x) betoh32(x)
+#define le32toh(x) letoh32(x)
+#define be64toh(x) betoh64(x)
+#define le64toh(x) letoh64(x)
+#endif /* !be16toh */
+
+#elif defined __APPLE__
+
+/*
+ * macOS has its own byte-swapping routines, so use these.
+ */
+
+#include <libkern/OSByteOrder.h>
+
+#define htobe16(x) OSSwapHostToBigInt16(x)
+#define htole16(x) OSSwapHostToLittleInt16(x)
+#define be16toh(x) OSSwapBigToHostInt16(x)
+#define le16toh(x) OSSwapLittleToHostInt16(x)
+
+#define htobe32(x) OSSwapHostToBigInt32(x)
+#define htole32(x) OSSwapHostToLittleInt32(x)
+#define be32toh(x) OSSwapBigToHostInt32(x)
+#define le32toh(x) OSSwapLittleToHostInt32(x)
+
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#define htole64(x) OSSwapHostToLittleInt64(x)
+#define be64toh(x) OSSwapBigToHostInt64(x)
+#define le64toh(x) OSSwapLittleToHostInt64(x)
+
+#elif defined(sun) || defined(__sun) || defined(__SVR4)
+
+/*
+ * For Solaris, rely on the fallback definitions below, though use
+ * Solaris-specific versions of bswap_{16,32,64}().
+ */
+
+#include <sys/byteorder.h>
+
+#define bswap_16(x) BSWAP_16(x)
+#define bswap_32(x) BSWAP_32(x)
+#define bswap_64(x) BSWAP_64(x)
+
+#elif defined(__ANDROID__) || defined(__CYGWIN__) || defined(__GNUC__) || \
+ defined(__GNU__)
+
+#include <byteswap.h>
+#include <endian.h>
+
+#else /* if defined(__DragonFly__) || defined(__FreeBSD__) || \
+ * defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) */
+
+#endif /* Specific platform support */
+
+/*
+ * Fallback definitions.
+ */
+
+#include <inttypes.h>
+
+#ifndef bswap_16
+#define bswap_16(x) \
+ ((uint16_t)((((uint16_t)(x)&0xff00) >> 8) | \
+ (((uint16_t)(x)&0x00ff) << 8)))
+#endif /* !bswap_16 */
+
+#ifndef bswap_32
+#define bswap_32(x) \
+ ((uint32_t)((((uint32_t)(x)&0xff000000) >> 24) | \
+ (((uint32_t)(x)&0x00ff0000) >> 8) | \
+ (((uint32_t)(x)&0x0000ff00) << 8) | \
+ (((uint32_t)(x)&0x000000ff) << 24)))
+#endif /* !bswap_32 */
+
+#ifndef bswap_64
+#define bswap_64(x) \
+ ((uint64_t)((((uint64_t)(x)&0xff00000000000000ULL) >> 56) | \
+ (((uint64_t)(x)&0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x)&0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x)&0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x)&0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x)&0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x)&0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x)&0x00000000000000ffULL) << 56)))
+#endif /* !bswap_64 */
+
+#ifndef htobe16
+#if WORDS_BIGENDIAN
+
+#define htobe16(x) (x)
+#define htole16(x) bswap_16(x)
+#define be16toh(x) (x)
+#define le16toh(x) bswap_16(x)
+
+#else /* WORDS_BIGENDIAN */
+
+#define htobe16(x) bswap_16(x)
+#define htole16(x) (x)
+#define be16toh(x) bswap_16(x)
+#define le16toh(x) (x)
+
+#endif /* WORDS_BIGENDIAN */
+#endif /* !htobe16 */
+
+#ifndef htobe32
+#if WORDS_BIGENDIAN
+
+#define htobe32(x) (x)
+#define htole32(x) bswap_32(x)
+#define be32toh(x) (x)
+#define le32toh(x) bswap_32(x)
+
+#else /* WORDS_BIGENDIAN */
+
+#define htobe32(x) bswap_32(x)
+#define htole32(x) (x)
+#define be32toh(x) bswap_32(x)
+#define le32toh(x) (x)
+
+#endif /* WORDS_BIGENDIAN */
+#endif /* !htobe32 */
+
+#ifndef htobe64
+#if WORDS_BIGENDIAN
+
+#define htobe64(x) (x)
+#define htole64(x) bswap_64(x)
+#define be64toh(x) (x)
+#define le64toh(x) bswap_64(x)
+
+#else /* WORDS_BIGENDIAN */
+
+#define htobe64(x) bswap_64(x)
+#define htole64(x) (x)
+#define be64toh(x) bswap_64(x)
+#define le64toh(x) (x)
+
+#endif /* WORDS_BIGENDIAN */
+#endif /* !htobe64 */
diff --git a/lib/isc/include/isc/errno.h b/lib/isc/include/isc/errno.h
new file mode 100644
index 0000000..0151df3
--- /dev/null
+++ b/lib/isc/include/isc/errno.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/file.h */
+
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_errno_toresult(int err);
+/*!<
+ * \brief Convert a POSIX errno value to an ISC result code.
+ */
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/error.h b/lib/isc/include/isc/error.h
new file mode 100644
index 0000000..f4f6682
--- /dev/null
+++ b/lib/isc/include/isc/error.h
@@ -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.
+ */
+
+#pragma once
+
+/*! \file isc/error.h */
+
+#include <stdarg.h>
+
+#include <isc/attributes.h>
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef void (*isc_errorcallback_t)(const char *, int, const char *,
+ const char *, va_list);
+
+/*% set unexpected error */
+void isc_error_setunexpected(isc_errorcallback_t);
+
+/*% set fatal error */
+void isc_error_setfatal(isc_errorcallback_t);
+
+/*% unexpected error */
+void
+isc_error_unexpected(const char *, int, const char *, const char *, ...)
+ ISC_FORMAT_PRINTF(4, 5);
+
+/*% fatal error */
+noreturn void
+isc_error_fatal(const char *, int, const char *, const char *, ...)
+ ISC_FORMAT_PRINTF(4, 5);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/event.h b/lib/isc/include/isc/event.h
new file mode 100644
index 0000000..811bcd8
--- /dev/null
+++ b/lib/isc/include/isc/event.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/event.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*****
+***** Events.
+*****/
+
+typedef void (*isc_eventdestructor_t)(isc_event_t *);
+
+#define ISC_EVENT_COMMON(ltype) \
+ size_t ev_size; \
+ unsigned int ev_attributes; \
+ void *ev_tag; \
+ isc_eventtype_t ev_type; \
+ isc_taskaction_t ev_action; \
+ void *ev_arg; \
+ void *ev_sender; \
+ isc_eventdestructor_t ev_destroy; \
+ void *ev_destroy_arg; \
+ ISC_LINK(ltype) ev_link; \
+ ISC_LINK(ltype) ev_ratelink
+
+/*%
+ * Attributes matching a mask of 0x000000ff are reserved for the task library's
+ * definition. Attributes of 0xffffff00 may be used by the application
+ * or non-ISC libraries.
+ */
+#define ISC_EVENTATTR_NOPURGE 0x00000001
+
+/*%
+ * The ISC_EVENTATTR_CANCELED attribute is intended to indicate
+ * that an event is delivered as a result of a canceled operation
+ * rather than successful completion, by mutual agreement
+ * between the sender and receiver. It is not set or used by
+ * the task system.
+ */
+#define ISC_EVENTATTR_CANCELED 0x00000002
+
+#define ISC_EVENT_INIT(event, sz, at, ta, ty, ac, ar, sn, df, da) \
+ do { \
+ (event)->ev_size = (sz); \
+ (event)->ev_attributes = (at); \
+ (event)->ev_tag = (ta); \
+ (event)->ev_type = (ty); \
+ (event)->ev_action = (ac); \
+ (event)->ev_arg = (ar); \
+ (event)->ev_sender = (sn); \
+ (event)->ev_destroy = (df); \
+ (event)->ev_destroy_arg = (da); \
+ ISC_LINK_INIT((event), ev_link); \
+ ISC_LINK_INIT((event), ev_ratelink); \
+ } while (0)
+
+/*%
+ * This structure is public because "subclassing" it may be useful when
+ * defining new event types.
+ */
+struct isc_event {
+ ISC_EVENT_COMMON(struct isc_event);
+};
+
+#define ISC_EVENTTYPE_FIRSTEVENT 0x00000000
+#define ISC_EVENTTYPE_LASTEVENT 0xffffffff
+
+#define ISC_EVENT_PTR(p) ((isc_event_t **)(void *)(p))
+
+ISC_LANG_BEGINDECLS
+
+isc_event_t *
+isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, void *arg, size_t size);
+isc_event_t *
+isc_event_constallocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type,
+ isc_taskaction_t action, const void *arg, size_t size);
+/*%<
+ * Allocate an event structure.
+ *
+ * Allocate and initialize in a structure with initial elements
+ * defined by:
+ *
+ * \code
+ * struct {
+ * ISC_EVENT_COMMON(struct isc_event);
+ * ...
+ * };
+ * \endcode
+ *
+ * Requires:
+ *\li 'size' >= sizeof(struct isc_event)
+ *\li 'action' to be non NULL
+ *
+ * Returns:
+ *\li a pointer to a initialized structure of the requested size.
+ *\li NULL if unable to allocate memory.
+ */
+
+void
+isc_event_free(isc_event_t **);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/eventclass.h b/lib/isc/include/isc/eventclass.h
new file mode 100644
index 0000000..b8be2ff
--- /dev/null
+++ b/lib/isc/include/isc/eventclass.h
@@ -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.
+ */
+
+#pragma once
+
+/*! \file isc/eventclass.h
+ ***** Registry of Predefined Event Type Classes
+ *****/
+
+/*%
+ * An event class is an unsigned 16 bit number. Each class may contain up
+ * to 65536 events. An event type is formed by adding the event number
+ * within the class to the class number.
+ *
+ */
+
+#define ISC_EVENTCLASS(eclass) ((eclass) << 16)
+
+/*@{*/
+/*!
+ * Classes < 1024 are reserved for ISC use.
+ * Event classes >= 1024 and <= 65535 are reserved for application use.
+ */
+
+#define ISC_EVENTCLASS_TASK ISC_EVENTCLASS(0)
+#define ISC_EVENTCLASS_TIMER ISC_EVENTCLASS(1)
+#define ISC_EVENTCLASS_SOCKET ISC_EVENTCLASS(2)
+#define ISC_EVENTCLASS_FILE ISC_EVENTCLASS(3)
+#define ISC_EVENTCLASS_DNS ISC_EVENTCLASS(4)
+#define ISC_EVENTCLASS_APP ISC_EVENTCLASS(5)
+#define ISC_EVENTCLASS_OMAPI ISC_EVENTCLASS(6)
+#define ISC_EVENTCLASS_RATELIMITER ISC_EVENTCLASS(7)
+#define ISC_EVENTCLASS_ISCCC ISC_EVENTCLASS(8)
+#define ISC_EVENTCLASS_NS ISC_EVENTCLASS(9)
+/*@}*/
diff --git a/lib/isc/include/isc/file.h b/lib/isc/include/isc/file.h
new file mode 100644
index 0000000..f78c5c5
--- /dev/null
+++ b/lib/isc/include/isc/file.h
@@ -0,0 +1,381 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/file.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/stat.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time);
+
+isc_result_t
+isc_file_mode(const char *file, mode_t *modep);
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time);
+/*!<
+ * \brief Get the time of last modification of a file.
+ *
+ * Notes:
+ *\li The time that is set is relative to the (OS-specific) epoch, as are
+ * all isc_time_t structures.
+ *
+ * Requires:
+ *\li file != NULL.
+ *\li time != NULL.
+ *
+ * Ensures:
+ *\li If the file could not be accessed, 'time' is unchanged.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success.
+ *\li #ISC_R_NOTFOUND
+ * No such file exists.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_NOPERM
+ * The file's metainformation could not be retrieved because
+ * permission was denied to some part of the file's path.
+ *\li #ISC_R_IOERROR
+ * Hardware error interacting with the filesystem.
+ *\li #ISC_R_UNEXPECTED
+ * Something totally unexpected happened.
+ *
+ */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen);
+/*!<
+ * \brief Generate a template string suitable for use with
+ * isc_file_openunique().
+ *
+ * Notes:
+ *\li This function is intended to make creating temporary files
+ * portable between different operating systems.
+ *
+ *\li The path is prepended to an implementation-defined string and
+ * placed into buf. The string has no path characters in it,
+ * and its maximum length is 14 characters plus a NUL. Thus
+ * buflen should be at least strlen(path) + 15 characters or
+ * an error will be returned.
+ *
+ * Requires:
+ *\li buf != NULL.
+ *
+ * Ensures:
+ *\li If result == #ISC_R_SUCCESS:
+ * buf contains a string suitable for use as the template argument
+ * to isc_file_openunique().
+ *
+ *\li If result != #ISC_R_SUCCESS:
+ * buf is unchanged.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOSPACE buflen indicates buf is too small for the catenation
+ * of the path with the internal template string.
+ */
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp);
+isc_result_t
+isc_file_openuniqueprivate(char *templet, FILE **fp);
+isc_result_t
+isc_file_openuniquemode(char *templet, int mode, FILE **fp);
+isc_result_t
+isc_file_bopenunique(char *templet, FILE **fp);
+isc_result_t
+isc_file_bopenuniqueprivate(char *templet, FILE **fp);
+isc_result_t
+isc_file_bopenuniquemode(char *templet, int mode, FILE **fp);
+/*!<
+ * \brief Create and open a file with a unique name based on 'templet'.
+ * isc_file_bopen*() open the file in binary mode in Windows.
+ * isc_file_open*() open the file in text mode in Windows.
+ *
+ * Notes:
+ *\li 'template' is a reserved work in C++. If you want to complain
+ * about the spelling of 'templet', first look it up in the
+ * Merriam-Webster English dictionary. (http://www.m-w.com/)
+ *
+ *\li This function works by using the template to generate file names.
+ * The template must be a writable string, as it is modified in place.
+ * Trailing X characters in the file name (full file name on Unix,
+ * basename on Win32 -- eg, tmp-XXXXXX vs XXXXXX.tmp, respectively)
+ * are replaced with ASCII characters until a non-existent filename
+ * is found. If the template does not include pathname information,
+ * the files in the working directory of the program are searched.
+ *
+ *\li isc_file_mktemplate is a good, portable way to get a template.
+ *
+ * Requires:
+ *\li 'fp' is non-NULL and '*fp' is NULL.
+ *
+ *\li 'template' is non-NULL, and of a form suitable for use by
+ * the system as described above.
+ *
+ * Ensures:
+ *\li If result is #ISC_R_SUCCESS:
+ * *fp points to an stream opening in stdio's "w+" mode.
+ *
+ *\li If result is not #ISC_R_SUCCESS:
+ * *fp is NULL.
+ *
+ * No file is open. Even if one was created (but unable
+ * to be reopened as a stdio FILE pointer) then it has been
+ * removed.
+ *
+ *\li This function does *not* ensure that the template string has not been
+ * modified, even if the operation was unsuccessful.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success.
+ *\li #ISC_R_EXISTS
+ * No file with a unique name could be created based on the
+ * template.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_NOPERM
+ * The file could not be created because permission was denied
+ * to some part of the file's path.
+ *\li #ISC_R_IOERROR
+ * Hardware error interacting with the filesystem.
+ *\li #ISC_R_UNEXPECTED
+ * Something totally unexpected happened.
+ */
+
+isc_result_t
+isc_file_remove(const char *filename);
+/*!<
+ * \brief Remove the file named by 'filename'.
+ */
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname);
+/*!<
+ * \brief Rename the file 'oldname' to 'newname'.
+ */
+
+bool
+isc_file_exists(const char *pathname);
+/*!<
+ * \brief Return #true if the calling process can tell that the given file
+ * exists. Will not return true if the calling process has insufficient
+ * privileges to search the entire path.
+ */
+
+bool
+isc_file_isabsolute(const char *filename);
+/*!<
+ * \brief Return #true if the given file name is absolute.
+ */
+
+isc_result_t
+isc_file_isplainfile(const char *name);
+
+isc_result_t
+isc_file_isplainfilefd(int fd);
+/*!<
+ * \brief Check that the file is a plain file
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success. The file is a plain file.
+ *\li #ISC_R_INVALIDFILE
+ * The path specified was not usable by the operating system.
+ *\li #ISC_R_FILENOTFOUND
+ * The file does not exist. This return code comes from
+ * errno=ENOENT when stat returns -1. This code is mentioned
+ * here, because in logconf.c, it is the one rcode that is
+ * permitted in addition to ISC_R_SUCCESS. This is done since
+ * the next call in logconf.c is to isc_stdio_open(), which
+ * will create the file if it can.
+ *\li other ISC_R_* errors translated from errno
+ * These occur when stat returns -1 and an errno.
+ */
+
+isc_result_t
+isc_file_isdirectory(const char *name);
+/*!<
+ * \brief Check that 'name' exists and is a directory.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * Success, file is a directory.
+ *\li #ISC_R_INVALIDFILE
+ * File is not a directory.
+ *\li #ISC_R_FILENOTFOUND
+ * File does not exist.
+ *\li other ISC_R_* errors translated from errno
+ * These occur when stat returns -1 and an errno.
+ */
+
+bool
+isc_file_iscurrentdir(const char *filename);
+/*!<
+ * \brief Return #true if the given file name is the current directory (".").
+ */
+
+bool
+isc_file_ischdiridempotent(const char *filename);
+/*%<
+ * Return #true if calling chdir(filename) multiple times will give
+ * the same result as calling it once.
+ */
+
+const char *
+isc_file_basename(const char *filename);
+/*%<
+ * Return the final component of the path in the file name.
+ */
+
+isc_result_t
+isc_file_progname(const char *filename, char *buf, size_t buflen);
+/*!<
+ * \brief Given an operating system specific file name "filename"
+ * referring to a program, return the canonical program name.
+ *
+ * Any directory prefix or executable file name extension (if
+ * used on the OS in case) is stripped. On systems where program
+ * names are case insensitive, the name is canonicalized to all
+ * lower case. The name is written to 'buf', an array of 'buflen'
+ * chars, and null terminated.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE The name did not fit in 'buf'.
+ */
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen);
+/*%<
+ * Create an OS specific template using 'path' to define the directory
+ * 'templet' to describe the filename and store the result in 'buf'
+ * such that path can be renamed to buf atomically.
+ */
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet);
+/*%<
+ * Rename 'file' using 'templet' as a template for the new file name.
+ */
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen);
+/*%<
+ * Given a file name, return the fully qualified path to the file.
+ */
+
+/*
+ * XXX We should also have a isc_file_writeeopen() function
+ * for safely open a file in a publicly writable directory
+ * (see write_open() in BIND 8's ns_config.c).
+ */
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size);
+/*%<
+ * Truncate/extend the file specified to 'size' bytes.
+ */
+
+isc_result_t
+isc_file_safecreate(const char *filename, FILE **fp);
+/*%<
+ * Open 'filename' for writing, truncating if necessary. Ensure that
+ * if it existed it was a normal file. If creating the file, ensure
+ * that only the owner can read/write it.
+ */
+
+isc_result_t
+isc_file_splitpath(isc_mem_t *mctx, const char *path, char **dirname,
+ char const **basename);
+/*%<
+ * Split a path into dirname and basename. If 'path' contains no slash
+ * (or, on windows, backslash), then '*dirname' is set to ".".
+ *
+ * Allocates memory for '*dirname', which can be freed with isc_mem_free().
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ * - ISC_R_INVALIDFILE if 'path' is empty or ends with '/'
+ * - ISC_R_NOMEMORY if unable to allocate memory
+ */
+
+isc_result_t
+isc_file_getsize(const char *file, off_t *size);
+/*%<
+ * Return the size of the file (stored in the parameter pointed
+ * to by 'size') in bytes.
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ */
+
+isc_result_t
+isc_file_getsizefd(int fd, off_t *size);
+/*%<
+ * Return the size of the file (stored in the parameter pointed
+ * to by 'size') in bytes.
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ */
+
+isc_result_t
+isc_file_sanitize(const char *dir, const char *base, const char *ext,
+ char *path, size_t length);
+/*%<
+ * Generate a sanitized filename, such as for MKEYS or NZF files.
+ *
+ * Historically, MKEYS and NZF files used SHA256 hashes of the view
+ * name for the filename; this was to deal with the possibility of
+ * forbidden characters such as "/" being in a view name, and to
+ * avoid problems with case-insensitive file systems.
+ *
+ * Given a basename 'base' and an extension 'ext', this function checks
+ * for the existence of file using the old-style name format in directory
+ * 'dir'. If found, it returns the path to that file. If there is no
+ * file already in place, a new pathname is generated; if the basename
+ * contains any excluded characters, then a truncated SHA256 hash is
+ * used, otherwise the basename is used. The path name is copied
+ * into 'path', which must point to a buffer of at least 'length'
+ * bytes.
+ *
+ * Requires:
+ * - base != NULL
+ * - path != NULL
+ *
+ * Returns:
+ * - ISC_R_SUCCESS on success
+ * - ISC_R_NOSPACE if the resulting path would be longer than 'length'
+ */
+
+bool
+isc_file_isdirwritable(const char *path);
+/*%<
+ * Return true if the path is a directory and is writable
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/formatcheck.h b/lib/isc/include/isc/formatcheck.h
new file mode 100644
index 0000000..e3a37b0
--- /dev/null
+++ b/lib/isc/include/isc/formatcheck.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/formatcheck.h */
+
+/*%
+ * ISC_FORMAT_PRINTF().
+ *
+ * \li fmt is the location of the format string parameter.
+ * \li args is the location of the first argument (or 0 for no argument
+ * checking).
+ *
+ * Note:
+ * \li The first parameter is 1, not 0.
+ */
+#ifdef __GNUC__
+#define ISC_FORMAT_PRINTF(fmt, args) \
+ __attribute__((__format__(__printf__, fmt, args)))
+#else /* ifdef __GNUC__ */
+#define ISC_FORMAT_PRINTF(fmt, args)
+#endif /* ifdef __GNUC__ */
diff --git a/lib/isc/include/isc/fuzz.h b/lib/isc/include/isc/fuzz.h
new file mode 100644
index 0000000..ce322ea
--- /dev/null
+++ b/lib/isc/include/isc/fuzz.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+typedef enum {
+ isc_fuzz_none,
+ isc_fuzz_client,
+ isc_fuzz_tcpclient,
+ isc_fuzz_resolver,
+ isc_fuzz_http,
+ isc_fuzz_rndc
+} isc_fuzztype_t;
diff --git a/lib/isc/include/isc/glob.h b/lib/isc/include/isc/glob.h
new file mode 100644
index 0000000..c9e8d19
--- /dev/null
+++ b/lib/isc/include/isc/glob.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+#if HAVE_GLOB_H
+#include <glob.h>
+#else
+#include <stddef.h>
+
+#include <isc/mem.h>
+
+typedef struct {
+ size_t gl_pathc;
+ char **gl_pathv;
+ isc_mem_t *mctx;
+ void *reserved;
+} glob_t;
+
+#endif
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_glob(const char *pattern, glob_t *pglob);
+
+void
+isc_globfree(glob_t *pglob);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h
new file mode 100644
index 0000000..ee9e74f
--- /dev/null
+++ b/lib/isc/include/isc/hash.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "isc/lang.h"
+#include "isc/types.h"
+
+/***
+ *** Functions
+ ***/
+ISC_LANG_BEGINDECLS
+
+const void *
+isc_hash_get_initializer(void);
+
+void
+isc_hash_set_initializer(const void *initializer);
+
+#define isc_hash_function isc_hash64
+
+uint32_t
+isc_hash32(const void *data, const size_t length, const bool case_sensitive);
+uint64_t
+isc_hash64(const void *data, const size_t length, const bool case_sensitive);
+/*!<
+ * \brief Calculate a hash over data.
+ *
+ * This hash function is useful for hashtables. The hash function is
+ * opaque and not important to the caller. The returned hash values are
+ * non-deterministic and will have different mapping every time a
+ * process using this library is run, but will have uniform
+ * distribution.
+ *
+ * isc_hash_32/64() calculates the hash from start to end over the
+ * input data.
+ *
+ * 'data' is the data to be hashed.
+ *
+ * 'length' is the size of the data to be hashed.
+ *
+ * 'case_sensitive' specifies whether the hash key should be treated as
+ * case_sensitive values. It should typically be false if the hash key
+ * is a DNS name.
+ *
+ * Returns:
+ * \li 32 or 64-bit hash value
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/heap.h b/lib/isc/include/isc/heap.h
new file mode 100644
index 0000000..98ae74c
--- /dev/null
+++ b/lib/isc/include/isc/heap.h
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/heap.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * The comparison function returns true if the first argument has
+ * higher priority than the second argument, and false otherwise.
+ */
+typedef bool (*isc_heapcompare_t)(void *, void *);
+
+/*%
+ * The index function allows the client of the heap to receive a callback
+ * when an item's index number changes. This allows it to maintain
+ * sync with its external state, but still delete itself, since deletions
+ * from the heap require the index be provided.
+ */
+typedef void (*isc_heapindex_t)(void *, unsigned int);
+
+/*%
+ * The heapaction function is used when iterating over the heap.
+ *
+ * NOTE: The heap structure CANNOT BE MODIFIED during the call to
+ * isc_heap_foreach().
+ */
+typedef void (*isc_heapaction_t)(void *, void *);
+
+typedef struct isc_heap isc_heap_t;
+
+void
+isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare,
+ isc_heapindex_t index, unsigned int size_increment,
+ isc_heap_t **heapp);
+/*!<
+ * \brief Create a new heap. The heap is implemented using a space-efficient
+ * storage method. When the heap elements are deleted space is not freed
+ * but will be reused when new elements are inserted.
+ *
+ * Heap elements are indexed from 1.
+ *
+ * Requires:
+ *\li "mctx" is valid.
+ *\li "compare" is a function which takes two void * arguments and
+ * returns true if the first argument has a higher priority than
+ * the second, and false otherwise.
+ *\li "index" is a function which takes a void *, and an unsigned int
+ * argument. This function will be called whenever an element's
+ * index value changes, so it may continue to delete itself from the
+ * heap. This option may be NULL if this functionality is unneeded.
+ *\li "size_increment" is a hint about how large the heap should grow
+ * when resizing is needed. If this is 0, a default size will be
+ * used, which is currently 1024, allowing space for an additional 1024
+ * heap elements to be inserted before adding more space.
+ *\li "heapp" is not NULL, and "*heap" is NULL.
+ */
+
+void
+isc_heap_destroy(isc_heap_t **heapp);
+/*!<
+ * \brief Destroys a heap.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+void
+isc_heap_insert(isc_heap_t *heap, void *elt);
+/*!<
+ * \brief Inserts a new element into a heap.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ */
+
+void
+isc_heap_delete(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Deletes an element from a heap, by element index.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void
+isc_heap_increased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has increased.
+ * This function MUST be called whenever an element has increased in priority.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void
+isc_heap_decreased(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Indicates to the heap that an element's priority has decreased.
+ * This function MUST be called whenever an element has decreased in priority.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ */
+
+void *
+isc_heap_element(isc_heap_t *heap, unsigned int index);
+/*!<
+ * \brief Returns the element for a specific element index.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "index" is a valid element index, as provided by the "index" callback
+ * provided during heap creation.
+ *
+ * Returns:
+ *\li A pointer to the element for the element index.
+ */
+
+void
+isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap);
+/*!<
+ * \brief Iterate over the heap, calling an action for each element. The
+ * order of iteration is not sorted.
+ *
+ * Requires:
+ *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t.
+ *\li "action" is not NULL, and is a function which takes two arguments.
+ * The first is a void *, representing the element, and the second is
+ * "uap" as provided to isc_heap_foreach.
+ *\li "uap" is a caller-provided argument, and may be NULL.
+ *
+ * Note:
+ *\li The heap structure CANNOT be modified during this iteration. The only
+ * safe function to call while iterating the heap is isc_heap_element().
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/hex.h b/lib/isc/include/isc/hex.h
new file mode 100644
index 0000000..d5f714e
--- /dev/null
+++ b/lib/isc/include/isc/hex.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/hex.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_hex_totext(isc_region_t *source, int wordlength, const char *wordbreak,
+ isc_buffer_t *target);
+/*!<
+ * \brief Convert data into hex encoded text.
+ *
+ * Notes:
+ *\li The hex encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the hex encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated hex string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADHEX -- 'cstr' is not a valid hex encoding.
+ *
+ * Other error returns are any possible error code from:
+ * isc_lex_create(),
+ * isc_lex_openbuffer(),
+ * isc_hex_tobuffer().
+ */
+
+isc_result_t
+isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert hex-encoded text from a lexer context into
+ * `target`. If 'length' is non-negative, it is the expected number of
+ * encoded octets to convert.
+ *
+ * If 'length' is -1 then 0 or more encoded octets are expected.
+ * If 'length' is -2 then 1 or more encoded octets are expected.
+ *
+ * Returns:
+ *\li #ISC_R_BADHEX -- invalid hex encoding
+ *\li #ISC_R_UNEXPECTEDEND: the text does not contain the expected
+ * number of encoded octets.
+ *
+ * Requires:
+ *\li 'lexer' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is -2, -1, or non-negative
+ *
+ * Ensures:
+ *\li target will contain the data represented by the hex encoded
+ * string parsed by the lexer. No more than `length` octets will
+ * be read, if `length` is non-negative. The 'used' pointer in
+ * 'target' will be advanced as necessary.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/hmac.h b/lib/isc/include/isc/hmac.h
new file mode 100644
index 0000000..68b63d4
--- /dev/null
+++ b/lib/isc/include/isc/hmac.h
@@ -0,0 +1,148 @@
+/*
+ * 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 isc/hmac.h
+ * \brief This is the header for for message authentication code.
+ */
+
+#pragma once
+
+#include <isc/lang.h>
+#include <isc/md.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef void isc_hmac_t;
+
+/**
+ * isc_hmac:
+ * @type: the digest type
+ * @key: the key
+ * @keylen: the length of the key
+ * @buf: data to hash
+ * @len: length of the data to hash
+ * @digest: the output buffer
+ * @digestlen: in: the length of @digest
+ * out: the length of the data written to @digest
+ *
+ * This function computes the message authentication code using a digest type
+ * @type with key @key which is @keylen bytes long from data in @buf which is
+ * @len bytes long, and places the output into @digest, which must have space
+ * for the hash function output (use ISC_MAX_MD_SIZE if unsure). @digestlen
+ * is used to pass in the length of the digest buffer and returns the length
+ * of digest written to @digest.
+ */
+isc_result_t
+isc_hmac(const isc_md_type_t *type, const void *key, const size_t keylen,
+ const unsigned char *buf, const size_t len, unsigned char *digest,
+ unsigned int *digestlen);
+
+/**
+ * isc_hmac_new:
+ *
+ * This function allocates, initializes and returns HMAC context.
+ */
+isc_hmac_t *
+isc_hmac_new(void);
+
+/**
+ * isc_hmac_free:
+ * @md: HMAC context
+ *
+ * This function cleans up HMAC context and frees up the space allocated to it.
+ */
+void
+isc_hmac_free(isc_hmac_t *hmac);
+
+/**
+ * isc_hmac_init:
+ * @md: HMAC context
+ * @key: HMAC key
+ * @keylen: HMAC key length
+ * @type: digest type
+ *
+ * This function sets up HMAC context to use a hash function of @type and key
+ * @key which is @keylen bytes long.
+ */
+
+isc_result_t
+isc_hmac_init(isc_hmac_t *hmac, const void *key, const size_t keylen,
+ const isc_md_type_t *type);
+
+/**
+ * isc_hmac_reset:
+ * @hmac: HMAC context
+ *
+ * This function resets the HMAC context. This can be used to reuse an already
+ * existing context.
+ */
+isc_result_t
+isc_hmac_reset(isc_hmac_t *hmac);
+
+/**
+ * isc_hmac_update:
+ * @hmac: HMAC context
+ * @buf: data to hash
+ * @len: length of the data to hash
+ *
+ * This function can be called repeatedly with chunks of the message @buf to be
+ * authenticated which is @len bytes long.
+ */
+isc_result_t
+isc_hmac_update(isc_hmac_t *hmac, const unsigned char *buf, const size_t len);
+
+/**
+ * isc_hmac_final:
+ * @hmac: HMAC context
+ * @digest: the output buffer
+ * @digestlen: in: the length of @digest
+ * out: the length of the data written to @digest
+ *
+ * This function retrieves the message authentication code from @hmac and places
+ * it in @digest, which must have space for the hash function output. @digestlen
+ * is used to pass in the length of the digest buffer and returns the length
+ * of digest written to @digest. After calling this function no additional
+ * calls to isc_hmac_update() can be made.
+ */
+isc_result_t
+isc_hmac_final(isc_hmac_t *hmac, unsigned char *digest,
+ unsigned int *digestlen);
+
+/**
+ * isc_hmac_md_type:
+ * @hmac: HMAC context
+ *
+ * This function return the isc_md_type_t previously set for the supplied
+ * HMAC context or NULL if no isc_md_type_t has been set.
+ */
+const isc_md_type_t *
+isc_hmac_get_md_type(isc_hmac_t *hmac);
+
+/**
+ * isc_hmac_get_size:
+ *
+ * This function return the size of the message digest when passed an isc_hmac_t
+ * structure, i.e. the size of the hash.
+ */
+size_t
+isc_hmac_get_size(isc_hmac_t *hmac);
+
+/**
+ * isc_hmac_get_block_size:
+ *
+ * This function return the block size of the message digest when passed an
+ * isc_hmac_t structure.
+ */
+int
+isc_hmac_get_block_size(isc_hmac_t *hmac);
diff --git a/lib/isc/include/isc/ht.h b/lib/isc/include/isc/ht.h
new file mode 100644
index 0000000..163fbef
--- /dev/null
+++ b/lib/isc/include/isc/ht.h
@@ -0,0 +1,191 @@
+/*
+ * 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 */
+
+#pragma once
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef struct isc_ht isc_ht_t;
+typedef struct isc_ht_iter isc_ht_iter_t;
+
+enum { ISC_HT_CASE_SENSITIVE = 0x00, ISC_HT_CASE_INSENSITIVE = 0x01 };
+
+/*%
+ * Initialize hashtable at *htp, using memory context and size of (1<<bits)
+ *
+ * If 'options' contains ISC_HT_CASE_INSENSITIVE, then upper- and lower-case
+ * letters in key values will generate the same hash values; this can be used
+ * when the key for a hash table is a DNS name.
+ *
+ * Requires:
+ *\li 'htp' is not NULL and '*htp' is NULL.
+ *\li 'mctx' is a valid memory context.
+ *\li 'bits' >=1 and 'bits' <=32
+ *
+ */
+void
+isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits,
+ unsigned int options);
+
+/*%
+ * Destroy hashtable, freeing everything
+ *
+ * Requires:
+ * \li '*htp' is valid hashtable
+ */
+void
+isc_ht_destroy(isc_ht_t **htp);
+
+/*%
+ * Add a node to hashtable, pointed by binary key 'key' of size 'keysize';
+ * set its value to 'value'
+ *
+ * Requires:
+ *\li 'ht' is a valid hashtable
+ *\li write-lock
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- not enough memory to create pool
+ *\li #ISC_R_EXISTS -- node of the same key already exists
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+isc_result_t
+isc_ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
+ void *value);
+
+/*%
+ * Find a node matching 'key'/'keysize' in hashtable 'ht';
+ * if found, set '*valuep' to its value. (If 'valuep' is NULL,
+ * then simply return SUCCESS or NOTFOUND to indicate whether the
+ * key exists in the hashtable.)
+ *
+ * Requires:
+ * \li 'ht' is a valid hashtable
+ * \li read-lock
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOTFOUND -- key not found
+ */
+isc_result_t
+isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
+ const uint32_t keysize, void **valuep);
+
+/*%
+ * Delete node from hashtable
+ *
+ * Requires:
+ *\li ht is a valid hashtable
+ *\li write-lock
+ *
+ * Returns:
+ *\li #ISC_R_NOTFOUND -- key not found
+ *\li #ISC_R_SUCCESS -- all is well
+ */
+isc_result_t
+isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize);
+
+/*%
+ * Create an iterator for the hashtable; point '*itp' to it.
+ *
+ * Requires:
+ *\li 'ht' is a valid hashtable
+ *\li 'itp' is non NULL and '*itp' is NULL.
+ */
+void
+isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp);
+
+/*%
+ * Destroy the iterator '*itp', set it to NULL
+ *
+ * Requires:
+ *\li 'itp' is non NULL and '*itp' is non NULL.
+ */
+void
+isc_ht_iter_destroy(isc_ht_iter_t **itp);
+
+/*%
+ * Set an iterator to the first entry.
+ *
+ * Requires:
+ *\li 'it' is non NULL.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOMORE -- no data in the hashtable
+ */
+isc_result_t
+isc_ht_iter_first(isc_ht_iter_t *it);
+
+/*%
+ * Set an iterator to the next entry.
+ *
+ * Requires:
+ *\li 'it' is non NULL.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOMORE -- end of hashtable reached
+ */
+isc_result_t
+isc_ht_iter_next(isc_ht_iter_t *it);
+
+/*%
+ * Delete current entry and set an iterator to the next entry.
+ *
+ * Requires:
+ *\li 'it' is non NULL.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS -- success
+ * \li #ISC_R_NOMORE -- end of hashtable reached
+ */
+isc_result_t
+isc_ht_iter_delcurrent_next(isc_ht_iter_t *it);
+
+/*%
+ * Set 'value' to the current value under the iterator
+ *
+ * Requires:
+ *\li 'it' is non NULL.
+ *\li 'valuep' is non NULL and '*valuep' is NULL.
+ */
+void
+isc_ht_iter_current(isc_ht_iter_t *it, void **valuep);
+
+/*%
+ * Set 'key' and 'keysize to the current key and keysize for the value
+ * under the iterator
+ *
+ * Requires:
+ *\li 'it' is non NULL.
+ *\li 'key' is non NULL and '*key' is NULL.
+ *\li 'keysize' is non NULL.
+ */
+void
+isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize);
+
+/*%
+ * Returns the number of items in the hashtable.
+ *
+ * Requires:
+ *\li 'ht' is a valid hashtable
+ */
+size_t
+isc_ht_count(const isc_ht_t *ht);
diff --git a/lib/isc/include/isc/httpd.h b/lib/isc/include/isc/httpd.h
new file mode 100644
index 0000000..1f69a4c
--- /dev/null
+++ b/lib/isc/include/isc/httpd.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <stdbool.h>
+
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/mutex.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/types.h>
+#include <isc/url.h>
+
+#define HTTPD_EVENTCLASS ISC_EVENTCLASS(4300)
+#define HTTPD_SHUTDOWN (HTTPD_EVENTCLASS + 0x0001)
+
+#define ISC_HTTPDMGR_SHUTTINGDOWN 0x00000001
+
+typedef isc_result_t(isc_httpdaction_t)(
+ const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, void *arg,
+ unsigned int *retcode, const char **retmsg, const char **mimetype,
+ isc_buffer_t *body, isc_httpdfree_t **freecb, void **freecb_args);
+
+typedef bool(isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
+
+isc_result_t
+isc_httpdmgr_create(isc_nm_t *nm, isc_mem_t *mctx, isc_sockaddr_t *addr,
+ isc_httpdclientok_t *client_ok,
+ isc_httpdondestroy_t *ondestroy, void *cb_arg,
+ isc_httpdmgr_t **httpdmgrp);
+
+void
+isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdp);
+
+isc_result_t
+isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url, bool isstatic,
+ isc_httpdaction_t *func, void *arg);
+
+void
+isc_httpd_setfinishhook(void (*fn)(void));
+
+bool
+isc_httpdurl_isstatic(const isc_httpdurl_t *url);
+
+const isc_time_t *
+isc_httpdurl_loadtime(const isc_httpdurl_t *url);
+
+const isc_time_t *
+isc_httpd_if_modified_since(const isc_httpd_t *httpd);
diff --git a/lib/isc/include/isc/interfaceiter.h b/lib/isc/include/isc/interfaceiter.h
new file mode 100644
index 0000000..c696091
--- /dev/null
+++ b/lib/isc/include/isc/interfaceiter.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/interfaceiter.h
+ * \brief Iterates over the list of network interfaces.
+ *
+ * Interfaces whose address family is not supported are ignored and never
+ * returned by the iterator. Interfaces whose netmask, interface flags,
+ * or similar cannot be obtained are also ignored, and the failure is logged.
+ *
+ * Standards:
+ * The API for scanning varies greatly among operating systems.
+ * This module attempts to hide the differences.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/netaddr.h>
+#include <isc/types.h>
+
+/*!
+ * \brief Public structure describing a network interface.
+ */
+
+struct isc_interface {
+ char name[32]; /*%< Interface name, null-terminated. */
+ unsigned int af; /*%< Address family. */
+ isc_netaddr_t address; /*%< Local address. */
+ isc_netaddr_t netmask; /*%< Network mask. */
+ isc_netaddr_t dstaddress; /*%< Destination address
+ * (point-to-point
+ * only). */
+ uint32_t flags; /*%< Flags; see INTERFACE flags. */
+};
+
+/*@{*/
+/*! Interface flags. */
+
+#define INTERFACE_F_UP 0x00000001U
+#define INTERFACE_F_POINTTOPOINT 0x00000002U
+#define INTERFACE_F_LOOPBACK 0x00000004U
+/*@}*/
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp);
+/*!<
+ * \brief Create an iterator for traversing the operating system's list
+ * of network interfaces.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ *\li Various network-related errors
+ */
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter);
+/*!<
+ * \brief Position the iterator on the first interface.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOMORE There are no interfaces.
+ */
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter, isc_interface_t *ifdata);
+/*!<
+ * \brief Get information about the interface the iterator is currently
+ * positioned at and store it at *ifdata.
+ *
+ * Requires:
+ *\li The iterator has been successfully positioned using
+ * isc_interface_iter_first() / isc_interface_iter_next().
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ */
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter);
+/*!<
+ * \brief Position the iterator on the next interface.
+ *
+ * Requires:
+ * \li The iterator has been successfully positioned using
+ * isc_interface_iter_first() / isc_interface_iter_next().
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOMORE There are no more interfaces.
+ */
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp);
+/*!<
+ * \brief Destroy the iterator.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/iterated_hash.h b/lib/isc/include/isc/iterated_hash.h
new file mode 100644
index 0000000..b5d6ab6
--- /dev/null
+++ b/lib/isc/include/isc/iterated_hash.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <isc/lang.h>
+
+/*
+ * The maximal hash length that can be encoded in a name
+ * using base32hex. floor(255/8)*5
+ */
+#define NSEC3_MAX_HASH_LENGTH 155
+
+/*
+ * The maximum has that can be encoded in a single label using
+ * base32hex. floor(63/8)*5
+ */
+#define NSEC3_MAX_LABEL_HASH 35
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_iterated_hash(unsigned char *out, const unsigned int hashalg,
+ const int iterations, const unsigned char *salt,
+ const int saltlength, const unsigned char *in,
+ const int inlength);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/lang.h b/lib/isc/include/isc/lang.h
new file mode 100644
index 0000000..b7e88a5
--- /dev/null
+++ b/lib/isc/include/isc/lang.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/lang.h */
+
+#ifdef __cplusplus
+#define ISC_LANG_BEGINDECLS extern "C" {
+#define ISC_LANG_ENDDECLS }
+#else /* ifdef __cplusplus */
+#define ISC_LANG_BEGINDECLS
+#define ISC_LANG_ENDDECLS
+#endif /* ifdef __cplusplus */
diff --git a/lib/isc/include/isc/lex.h b/lib/isc/include/isc/lex.h
new file mode 100644
index 0000000..14b29cf
--- /dev/null
+++ b/lib/isc/include/isc/lex.h
@@ -0,0 +1,444 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/lex.h
+ * \brief The "lex" module provides a lightweight tokenizer. It can operate
+ * on files or buffers, and can handle "include". It is designed for
+ * parsing of DNS master files and the BIND configuration file, but
+ * should be general enough to tokenize other things, e.g. HTTP.
+ *
+ * \li MP:
+ * No synchronization is provided. Clients must ensure exclusive
+ * access.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/region.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Options
+ ***/
+
+/*@{*/
+/*!
+ * Various options for isc_lex_gettoken().
+ */
+
+#define ISC_LEXOPT_EOL 0x0001 /*%< Want end-of-line token. */
+#define ISC_LEXOPT_EOF 0x0002 /*%< Want end-of-file token. */
+#define ISC_LEXOPT_INITIALWS 0x0004 /*%< Want initial whitespace. */
+#define ISC_LEXOPT_NUMBER 0x0008 /*%< Recognize numbers. */
+#define ISC_LEXOPT_QSTRING 0x0010 /*%< Recognize qstrings. */
+/*@}*/
+
+/*@{*/
+/*!
+ * The ISC_LEXOPT_DNSMULTILINE option handles the processing of '(' and ')' in
+ * the DNS master file format. If this option is set, then the
+ * ISC_LEXOPT_INITIALWS and ISC_LEXOPT_EOL options will be ignored when
+ * the paren count is > 0. To use this option, '(' and ')' must be special
+ * characters.
+ */
+#define ISC_LEXOPT_DNSMULTILINE 0x0020 /*%< Handle '(' and ')'. */
+#define ISC_LEXOPT_NOMORE 0x0040 /*%< Want "no more" token. */
+
+#define ISC_LEXOPT_CNUMBER 0x0080 /*%< Recognize octal and hex. */
+#define ISC_LEXOPT_ESCAPE 0x0100 /*%< Recognize escapes. */
+#define ISC_LEXOPT_QSTRINGMULTILINE 0x0200 /*%< Allow multiline "" strings */
+#define ISC_LEXOPT_OCTAL 0x0400 /*%< Expect a octal number. */
+#define ISC_LEXOPT_BTEXT 0x0800 /*%< Bracketed text. */
+#define ISC_LEXOPT_VPAIR 0x1000 /*%< Recognize value pair. */
+#define ISC_LEXOPT_QVPAIR 0x2000 /*%< Recognize quoted value pair. */
+/*@}*/
+/*@{*/
+/*!
+ * Various commenting styles, which may be changed at any time with
+ * isc_lex_setcomments().
+ */
+
+#define ISC_LEXCOMMENT_C 0x01
+#define ISC_LEXCOMMENT_CPLUSPLUS 0x02
+#define ISC_LEXCOMMENT_SHELL 0x04
+#define ISC_LEXCOMMENT_DNSMASTERFILE 0x08
+/*@}*/
+
+/***
+ *** Types
+ ***/
+
+/*! Lex */
+
+typedef char isc_lexspecials_t[256];
+
+/* Tokens */
+
+typedef enum {
+ isc_tokentype_unknown = 0,
+ isc_tokentype_string = 1,
+ isc_tokentype_number = 2,
+ isc_tokentype_qstring = 3,
+ isc_tokentype_eol = 4,
+ isc_tokentype_eof = 5,
+ isc_tokentype_initialws = 6,
+ isc_tokentype_special = 7,
+ isc_tokentype_nomore = 8,
+ isc_tokentype_btext = 9,
+ isc_tokentype_vpair = 10,
+ isc_tokentype_qvpair = 11,
+} isc_tokentype_t;
+
+typedef union {
+ char as_char;
+ unsigned long as_ulong;
+ isc_region_t as_region;
+ isc_textregion_t as_textregion;
+ void *as_pointer;
+} isc_tokenvalue_t;
+
+typedef struct isc_token {
+ isc_tokentype_t type;
+ isc_tokenvalue_t value;
+} isc_token_t;
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp);
+/*%<
+ * Create a lexer.
+ *
+ * 'max_token' is a hint of the number of bytes in the largest token.
+ *
+ * Requires:
+ *\li '*lexp' is a valid lexer.
+ *
+ * Ensures:
+ *\li On success, *lexp is attached to the newly created lexer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+isc_lex_destroy(isc_lex_t **lexp);
+/*%<
+ * Destroy the lexer.
+ *
+ * Requires:
+ *\li '*lexp' is a valid lexer.
+ *
+ * Ensures:
+ *\li *lexp == NULL
+ */
+
+unsigned int
+isc_lex_getcomments(isc_lex_t *lex);
+/*%<
+ * Return the current lexer commenting styles.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li The commenting styles which are currently allowed.
+ */
+
+void
+isc_lex_setcomments(isc_lex_t *lex, unsigned int comments);
+/*%<
+ * Set allowed lexer commenting styles.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'comments' has meaningful values.
+ */
+
+void
+isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*%<
+ * Put the current list of specials into 'specials'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ */
+
+void
+isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials);
+/*!<
+ * The characters in 'specials' are returned as tokens. Along with
+ * whitespace, they delimit strings and numbers.
+ *
+ * Note:
+ *\li Comment processing takes precedence over special character
+ * recognition.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ */
+
+isc_result_t
+isc_lex_openfile(isc_lex_t *lex, const char *filename);
+/*%<
+ * Open 'filename' and make it the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li filename is a valid C string.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ *\li #ISC_R_NOTFOUND File not found
+ *\li #ISC_R_NOPERM No permission to open file
+ *\li #ISC_R_FAILURE Couldn't open file, not sure why
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_lex_openstream(isc_lex_t *lex, FILE *stream);
+/*%<
+ * Make 'stream' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'stream' is a valid C stream.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ */
+
+isc_result_t
+isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer);
+/*%<
+ * Make 'buffer' the current input source for 'lex'.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'buffer' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY Out of memory
+ */
+
+isc_result_t
+isc_lex_close(isc_lex_t *lex);
+/*%<
+ * Close the most recently opened object (i.e. file or buffer).
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMORE No more input sources
+ */
+
+isc_result_t
+isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp);
+/*%<
+ * Get the next token.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'options' contains valid options.
+ *
+ *\li '*tokenp' is a valid pointer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_UNEXPECTEDEND
+ *\li #ISC_R_NOMEMORY
+ *
+ * These two results are returned only if their corresponding lexer
+ * options are not set.
+ *
+ *\li #ISC_R_EOF End of input source
+ *\li #ISC_R_NOMORE No more input sources
+ */
+
+isc_result_t
+isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
+ isc_tokentype_t expect, bool eol);
+/*%<
+ * Get the next token from a DNS master file type stream. This is a
+ * convenience function that sets appropriate options and handles quoted
+ * strings and end of line correctly for master files. It also ungets
+ * unexpected tokens. If `eol` is set then expect end-of-line otherwise
+ * eol is a error.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+isc_result_t
+isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol);
+/*%<
+ * Get the next token from a DNS master file type stream. This is a
+ * convenience function that sets appropriate options and handles end
+ * of line correctly for master files. It also ungets unexpected tokens.
+ * If `eol` is set then expect end-of-line otherwise eol is a error.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'token' is a valid pointer
+ *
+ * Returns:
+ *
+ * \li any return code from isc_lex_gettoken().
+ */
+
+void
+isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp);
+/*%<
+ * Unget the current token.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'tokenp' points to a valid token.
+ *
+ *\li There is no ungotten token already.
+ */
+
+void
+isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r);
+/*%<
+ * Returns a region containing the text of the last token returned.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ *\li 'lex' has an input source.
+ *
+ *\li 'tokenp' points to a valid token.
+ *
+ *\li A token has been gotten and not ungotten.
+ */
+
+char *
+isc_lex_getsourcename(isc_lex_t *lex);
+/*%<
+ * Return the input source name.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li source name or NULL if no current source.
+ *\li result valid while current input source exists.
+ */
+
+unsigned long
+isc_lex_getsourceline(isc_lex_t *lex);
+/*%<
+ * Return the input source line number.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ *\li Current line number or 0 if no current source.
+ */
+
+isc_result_t
+isc_lex_setsourcename(isc_lex_t *lex, const char *name);
+/*%<
+ * Assigns a new name to the input source.
+ *
+ * Requires:
+ *
+ * \li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTFOUND - there are no sources.
+ */
+
+isc_result_t
+isc_lex_setsourceline(isc_lex_t *lex, unsigned long line);
+/*%<
+ * Assigns a new line number to the input source. This can be used
+ * when parsing a buffer that's been excerpted from the middle a file,
+ * allowing logged messages to display the correct line number,
+ * rather than the line number within the buffer.
+ *
+ * Requires:
+ *
+ * \li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND - there are no sources.
+ */
+
+bool
+isc_lex_isfile(isc_lex_t *lex);
+/*%<
+ * Return whether the current input source is a file.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer.
+ *
+ * Returns:
+ * \li #true if the current input is a file,
+ *\li #false otherwise.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/list.h b/lib/isc/include/isc/list.h
new file mode 100644
index 0000000..2cf4437
--- /dev/null
+++ b/lib/isc/include/isc/list.h
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <isc/assertions.h>
+
+#define ISC_LINK_TOMBSTONE(type) ((type *)-1)
+
+#define ISC_LIST_INITIALIZER \
+ { \
+ .head = NULL, .tail = NULL, \
+ }
+#define ISC_LINK_INITIALIZER_TYPE(type) \
+ { \
+ .prev = ISC_LINK_TOMBSTONE(type), \
+ .next = ISC_LINK_TOMBSTONE(type), \
+ }
+#define ISC_LINK_INITIALIZER ISC_LINK_INITIALIZER_TYPE(void)
+
+#ifdef ISC_LIST_CHECKINIT
+#define ISC_LINK_INSIST(x) ISC_INSIST(x)
+#else /* ifdef ISC_LIST_CHECKINIT */
+#define ISC_LINK_INSIST(x)
+#endif /* ifdef ISC_LIST_CHECKINIT */
+
+#define ISC_LIST(type) \
+ struct { \
+ type *head, *tail; \
+ }
+#define ISC_LIST_INIT(list) \
+ do { \
+ (list).head = NULL; \
+ (list).tail = NULL; \
+ } while (0)
+
+#define ISC_LINK(type) \
+ struct { \
+ type *prev, *next; \
+ }
+#define ISC_LINK_INIT_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = ISC_LINK_TOMBSTONE(type); \
+ (elt)->link.next = ISC_LINK_TOMBSTONE(type); \
+ } while (0)
+#define ISC_LINK_INIT(elt, link) ISC_LINK_INIT_TYPE(elt, link, void)
+#define ISC_LINK_LINKED_TYPE(elt, link, type) \
+ ((type *)((elt)->link.prev) != ISC_LINK_TOMBSTONE(type))
+#define ISC_LINK_LINKED(elt, link) ISC_LINK_LINKED_TYPE(elt, link, void)
+
+#define ISC_LIST_HEAD(list) ((list).head)
+#define ISC_LIST_TAIL(list) ((list).tail)
+#define ISC_LIST_EMPTY(list) ((list).head == NULL)
+
+#define __ISC_LIST_PREPENDUNSAFE(list, elt, link) \
+ do { \
+ if ((list).head != NULL) { \
+ (list).head->link.prev = (elt); \
+ } else { \
+ (list).tail = (elt); \
+ } \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+
+#define ISC_LIST_PREPEND(list, elt, link) \
+ do { \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_PREPENDUNSAFE(list, elt, link); \
+ } while (0)
+
+#define ISC_LIST_INITANDPREPEND(list, elt, link) \
+ __ISC_LIST_PREPENDUNSAFE(list, elt, link)
+
+#define __ISC_LIST_APPENDUNSAFE(list, elt, link) \
+ do { \
+ if ((list).tail != NULL) { \
+ (list).tail->link.next = (elt); \
+ } else { \
+ (list).head = (elt); \
+ } \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+
+#define ISC_LIST_APPEND(list, elt, link) \
+ do { \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link); \
+ } while (0)
+
+#define ISC_LIST_INITANDAPPEND(list, elt, link) \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link)
+
+#define __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) \
+ do { \
+ if ((elt)->link.next != NULL) { \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ } else { \
+ ISC_INSIST((list).tail == (elt)); \
+ (list).tail = (elt)->link.prev; \
+ } \
+ if ((elt)->link.prev != NULL) { \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ } else { \
+ ISC_INSIST((list).head == (elt)); \
+ (list).head = (elt)->link.next; \
+ } \
+ (elt)->link.prev = ISC_LINK_TOMBSTONE(type); \
+ (elt)->link.next = ISC_LINK_TOMBSTONE(type); \
+ ISC_INSIST((list).head != (elt)); \
+ ISC_INSIST((list).tail != (elt)); \
+ } while (0)
+
+#define __ISC_LIST_UNLINKUNSAFE(list, elt, link) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void)
+
+#define ISC_LIST_UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type); \
+ } while (0)
+#define ISC_LIST_UNLINK(list, elt, link) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, void)
+
+#define ISC_LIST_PREV(elt, link) ((elt)->link.prev)
+#define ISC_LIST_NEXT(elt, link) ((elt)->link.next)
+
+#define __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link) \
+ do { \
+ if ((before)->link.prev == NULL) { \
+ ISC_LIST_PREPEND(list, elt, link); \
+ } else { \
+ (elt)->link.prev = (before)->link.prev; \
+ (before)->link.prev = (elt); \
+ (elt)->link.prev->link.next = (elt); \
+ (elt)->link.next = (before); \
+ } \
+ } while (0)
+
+#define ISC_LIST_INSERTBEFORE(list, before, elt, link) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(before, link)); \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link); \
+ } while (0)
+
+#define __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link) \
+ do { \
+ if ((after)->link.next == NULL) { \
+ ISC_LIST_APPEND(list, elt, link); \
+ } else { \
+ (elt)->link.next = (after)->link.next; \
+ (after)->link.next = (elt); \
+ (elt)->link.next->link.prev = (elt); \
+ (elt)->link.prev = (after); \
+ } \
+ } while (0)
+
+#define ISC_LIST_INSERTAFTER(list, after, elt, link) \
+ do { \
+ ISC_LINK_INSIST(ISC_LINK_LINKED(after, link)); \
+ ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \
+ __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link); \
+ } while (0)
+
+#define ISC_LIST_APPENDLIST(list1, list2, link) \
+ do { \
+ if (ISC_LIST_EMPTY(list1)) { \
+ (list1) = (list2); \
+ } else if (!ISC_LIST_EMPTY(list2)) { \
+ (list1).tail->link.next = (list2).head; \
+ (list2).head->link.prev = (list1).tail; \
+ (list1).tail = (list2).tail; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define ISC_LIST_PREPENDLIST(list1, list2, link) \
+ do { \
+ if (ISC_LIST_EMPTY(list1)) { \
+ (list1) = (list2); \
+ } else if (!ISC_LIST_EMPTY(list2)) { \
+ (list2).tail->link.next = (list1).head; \
+ (list1).head->link.prev = (list2).tail; \
+ (list1).head = (list2).head; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
+#define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define __ISC_LIST_ENQUEUEUNSAFE(list, elt, link) \
+ __ISC_LIST_APPENDUNSAFE(list, elt, link)
+#define ISC_LIST_DEQUEUE(list, elt, link) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, void)
+#define ISC_LIST_DEQUEUE_TYPE(list, elt, link, type) \
+ ISC_LIST_UNLINK_TYPE(list, elt, link, type)
+#define __ISC_LIST_DEQUEUEUNSAFE(list, elt, link) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void)
+#define __ISC_LIST_DEQUEUEUNSAFE_TYPE(list, elt, link, type) \
+ __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type)
+
+#define ISC_LIST_MOVEUNSAFE(dest, src) \
+ { \
+ (dest).head = (src).head; \
+ (dest).tail = (src).tail; \
+ (src).head = NULL; \
+ (src).tail = NULL; \
+ }
+
+#define ISC_LIST_MOVE(dest, src) \
+ { \
+ INSIST(ISC_LIST_EMPTY(dest)); \
+ ISC_LIST_MOVEUNSAFE(dest, src); \
+ }
diff --git a/lib/isc/include/isc/log.h b/lib/isc/include/isc/log.h
new file mode 100644
index 0000000..54b4022
--- /dev/null
+++ b/lib/isc/include/isc/log.h
@@ -0,0 +1,853 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/log.h */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <syslog.h> /* XXXDCL NT */
+
+#include <isc/formatcheck.h>
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*@{*/
+/*!
+ * \brief Severity levels, patterned after Unix's syslog levels.
+ *
+ */
+#define ISC_LOG_DEBUG(level) (level)
+/*!
+ * #ISC_LOG_DYNAMIC can only be used for defining channels with
+ * isc_log_createchannel(), not to specify a level in isc_log_write().
+ */
+#define ISC_LOG_DYNAMIC 0
+#define ISC_LOG_INFO (-1)
+#define ISC_LOG_NOTICE (-2)
+#define ISC_LOG_WARNING (-3)
+#define ISC_LOG_ERROR (-4)
+#define ISC_LOG_CRITICAL (-5)
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Destinations.
+ */
+#define ISC_LOG_TONULL 1
+#define ISC_LOG_TOSYSLOG 2
+#define ISC_LOG_TOFILE 3
+#define ISC_LOG_TOFILEDESC 4
+/*@}*/
+
+/*@{*/
+/*%
+ * Channel flags.
+ */
+#define ISC_LOG_PRINTTIME 0x00001
+#define ISC_LOG_PRINTLEVEL 0x00002
+#define ISC_LOG_PRINTCATEGORY 0x00004
+#define ISC_LOG_PRINTMODULE 0x00008
+#define ISC_LOG_PRINTTAG 0x00010 /* tag and ":" */
+#define ISC_LOG_PRINTPREFIX 0x00020 /* tag only, no colon */
+#define ISC_LOG_PRINTALL 0x0003F
+#define ISC_LOG_BUFFERED 0x00040
+#define ISC_LOG_DEBUGONLY 0x01000
+#define ISC_LOG_OPENERR 0x08000 /* internal */
+#define ISC_LOG_ISO8601 0x10000 /* if PRINTTIME, use ISO8601 */
+#define ISC_LOG_UTC 0x20000 /* if PRINTTIME, use UTC */
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Other options.
+ *
+ * XXXDCL INFINITE doesn't yet work. Arguably it isn't needed, but
+ * since I am intend to make large number of versions work efficiently,
+ * INFINITE is going to be trivial to add to that.
+ */
+#define ISC_LOG_ROLLINFINITE (-1)
+#define ISC_LOG_ROLLNEVER (-2)
+#define ISC_LOG_MAX_VERSIONS 256
+/*@}*/
+
+/*@{*/
+/*!
+ * \brief Type of suffix used on rolled log files.
+ */
+typedef enum {
+ isc_log_rollsuffix_increment,
+ isc_log_rollsuffix_timestamp
+} isc_log_rollsuffix_t;
+/*@}*/
+
+/*!
+ * \brief Used to name the categories used by a library.
+ *
+ * An array of isc_logcategory
+ * structures names each category, and the id value is initialized by calling
+ * isc_log_registercategories.
+ */
+struct isc_logcategory {
+ const char *name;
+ unsigned int id;
+};
+
+/*%
+ * Similar to isc_logcategory, but for all the modules a library defines.
+ */
+struct isc_logmodule {
+ const char *name;
+ unsigned int id;
+};
+
+/*%
+ * The isc_logfile structure is initialized as part of an isc_logdestination
+ * before calling isc_log_createchannel().
+ *
+ * When defining an #ISC_LOG_TOFILE
+ * channel the name, versions and maximum_size should be set before calling
+ * isc_log_createchannel(). To define an #ISC_LOG_TOFILEDESC channel set only
+ * the stream before the call.
+ *
+ * Setting maximum_size to zero implies no maximum.
+ */
+typedef struct isc_logfile {
+ FILE *stream; /*%< Initialized to NULL for
+ * #ISC_LOG_TOFILE. */
+ const char *name; /*%< NULL for #ISC_LOG_TOFILEDESC. */
+ int versions; /* >= 0, #ISC_LOG_ROLLNEVER,
+ * #ISC_LOG_ROLLINFINITE. */
+ isc_log_rollsuffix_t suffix;
+ /*%
+ * stdio's ftell is standardized to return a long, which may well not
+ * be big enough for the largest file supportable by the operating
+ * system (though it is _probably_ big enough for the largest log
+ * anyone would want). st_size returned by fstat should be typedef'd
+ * to a size large enough for the largest possible file on a system.
+ */
+ isc_offset_t maximum_size;
+ bool maximum_reached; /*%< Private. */
+} isc_logfile_t;
+
+/*%
+ * Passed to isc_log_createchannel to define the attributes of either
+ * a stdio or a syslog log.
+ */
+typedef union isc_logdestination {
+ isc_logfile_t file;
+ int facility; /* XXXDCL NT */
+} isc_logdestination_t;
+
+/*@{*/
+/*%
+ * The built-in categories of libisc.
+ *
+ * Each library registering categories should provide library_LOGCATEGORY_name
+ * definitions with indexes into its isc_logcategory structure corresponding to
+ * the order of the names.
+ */
+extern isc_logcategory_t isc_categories[];
+extern isc_log_t *isc_lctx;
+extern isc_logmodule_t isc_modules[];
+/*@}*/
+
+/*@{*/
+/*%
+ * Do not log directly to DEFAULT. Use another category. When in doubt,
+ * use GENERAL.
+ */
+#define ISC_LOGCATEGORY_DEFAULT (&isc_categories[0])
+#define ISC_LOGCATEGORY_GENERAL (&isc_categories[1])
+#define ISC_LOGCATEGORY_SSLKEYLOG (&isc_categories[2])
+/*@}*/
+
+#define ISC_LOGMODULE_SOCKET (&isc_modules[0])
+#define ISC_LOGMODULE_TIME (&isc_modules[1])
+#define ISC_LOGMODULE_INTERFACE (&isc_modules[2])
+#define ISC_LOGMODULE_TIMER (&isc_modules[3])
+#define ISC_LOGMODULE_FILE (&isc_modules[4])
+#define ISC_LOGMODULE_NETMGR (&isc_modules[5])
+#define ISC_LOGMODULE_OTHER (&isc_modules[6])
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp);
+/*%<
+ * Establish a new logging context, with default channels.
+ *
+ * Notes:
+ *\li isc_log_create() calls isc_logconfig_create(), so see its comment
+ * below for more information.
+ *
+ * Requires:
+ *\li mctx is a valid memory context.
+ *\li lctxp is not null and *lctxp is null.
+ *\li lcfgp is null or lcfgp is not null and *lcfgp is null.
+ *
+ * Ensures:
+ *\li *lctxp will point to a valid logging context if all of the necessary
+ * memory was allocated, or NULL otherwise.
+ *\li *lcfgp will point to a valid logging configuration if all of the
+ * necessary memory was allocated, or NULL otherwise.
+ *\li On failure, no additional memory is allocated.
+ */
+
+void
+isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp);
+/*%<
+ * Create the data structure that holds all of the configurable information
+ * about where messages are actually supposed to be sent -- the information
+ * that could changed based on some configuration file, as opposed to the
+ * the category/module specification of isc_log_[v]write[1] that is compiled
+ * into a program, or the debug_level which is dynamic state information.
+ *
+ * Notes:
+ *\li It is necessary to specify the logging context the configuration
+ * will be used with because the number of categories and modules
+ * needs to be known in order to set the configuration. However,
+ * the configuration is not used by the logging context until the
+ * isc_logconfig_use function is called.
+ *
+ *\li The memory context used for operations that allocate memory for
+ * the configuration is that of the logging context, as specified
+ * in the isc_log_create call.
+ *
+ *\li Four default channels are established:
+ *\verbatim
+ * default_syslog
+ * - log to syslog's daemon facility #ISC_LOG_INFO or higher
+ * default_stderr
+ * - log to stderr #ISC_LOG_INFO or higher
+ * default_debug
+ * - log to stderr #ISC_LOG_DEBUG dynamically
+ * null
+ * - log nothing
+ *\endverbatim
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li lcftp is not null and *lcfgp is null.
+ *
+ * Ensures:
+ *\li *lcfgp will point to a valid logging context if all of the necessary
+ * memory was allocated, or NULL otherwise.
+ *\li On failure, no additional memory is allocated.
+ */
+
+void
+isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg);
+/*%<
+ * Associate a new configuration with a logging context.
+ *
+ * Notes:
+ *\li This is thread safe. The logging context will lock a mutex
+ * before attempting to swap in the new configuration, and isc_log_doit
+ * (the internal function used by all of isc_log_[v]write[1]) locks
+ * the same lock for the duration of its use of the configuration.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li lcfg is a valid logging configuration.
+ *\li lctx is the same configuration given to isc_logconfig_create
+ * when the configuration was created.
+ *
+ * Ensures:
+ *\li Future calls to isc_log_write will use the new configuration.
+ */
+
+void
+isc_log_destroy(isc_log_t **lctxp);
+/*%<
+ * Deallocate the memory associated with a logging context.
+ *
+ * Requires:
+ *\li *lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li All of the memory associated with the logging context is returned
+ * to the free memory pool.
+ *
+ *\li Any open files are closed.
+ *
+ *\li The logging context is marked as invalid.
+ */
+
+void
+isc_logconfig_destroy(isc_logconfig_t **lcfgp);
+/*%<
+ * Destroy a logging configuration.
+ *
+ * Requires:
+ *\li lcfgp is not null and *lcfgp is a valid logging configuration.
+ *\li The logging configuration is not in use by an existing logging context.
+ *
+ * Ensures:
+ *\li All memory allocated for the configuration is freed.
+ *
+ *\li The configuration is marked as invalid.
+ */
+
+void
+isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]);
+/*%<
+ * Identify logging categories a library will use.
+ *
+ * Notes:
+ *\li A category should only be registered once, but no mechanism enforces
+ * this rule.
+ *
+ *\li The end of the categories array is identified by a NULL name.
+ *
+ *\li Because the name is used by #ISC_LOG_PRINTCATEGORY, it should not
+ * be altered or destroyed after isc_log_registercategories().
+ *
+ *\li Because each element of the categories array is used by
+ * isc_log_categorybyname, it should not be altered or destroyed
+ * after registration.
+ *
+ *\li The value of the id integer in each structure is overwritten
+ * by this function, and so id need not be initialized to any particular
+ * value prior to the function call.
+ *
+ *\li A subsequent call to isc_log_registercategories with the same
+ * logging context (but new categories) will cause the last
+ * element of the categories array from the prior call to have
+ * its "name" member changed from NULL to point to the new
+ * categories array, and its "id" member set to UINT_MAX.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li categories != NULL.
+ *\li categories[0].name != NULL.
+ *
+ * Ensures:
+ * \li There are references to each category in the logging context,
+ * so they can be used with isc_log_usechannel() and isc_log_write().
+ */
+
+void
+isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]);
+/*%<
+ * Identify logging categories a library will use.
+ *
+ * Notes:
+ *\li A module should only be registered once, but no mechanism enforces
+ * this rule.
+ *
+ *\li The end of the modules array is identified by a NULL name.
+ *
+ *\li Because the name is used by #ISC_LOG_PRINTMODULE, it should not
+ * be altered or destroyed after isc_log_registermodules().
+ *
+ *\li Because each element of the modules array is used by
+ * isc_log_modulebyname, it should not be altered or destroyed
+ * after registration.
+ *
+ *\li The value of the id integer in each structure is overwritten
+ * by this function, and so id need not be initialized to any particular
+ * value prior to the function call.
+ *
+ *\li A subsequent call to isc_log_registermodules with the same
+ * logging context (but new modules) will cause the last
+ * element of the modules array from the prior call to have
+ * its "name" member changed from NULL to point to the new
+ * modules array, and its "id" member set to UINT_MAX.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *\li modules != NULL.
+ *\li modules[0].name != NULL;
+ *
+ * Ensures:
+ *\li Each module has a reference in the logging context, so they can be
+ * used with isc_log_usechannel() and isc_log_write().
+ */
+
+void
+isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
+ unsigned int type, int level,
+ const isc_logdestination_t *destination,
+ unsigned int flags);
+/*%<
+ * Specify the parameters of a logging channel.
+ *
+ * Notes:
+ *\li The name argument is copied to memory in the logging context, so
+ * it can be altered or destroyed after isc_log_createchannel().
+ *
+ *\li Defining a very large number of channels will have a performance
+ * impact on isc_log_usechannel(), since the names are searched
+ * linearly until a match is made. This same issue does not affect
+ * isc_log_write, however.
+ *
+ *\li Channel names can be redefined; this is primarily useful for programs
+ * that want their own definition of default_syslog, default_debug
+ * and default_stderr.
+ *
+ *\li Any channel that is redefined will not affect logging that was
+ * already directed to its original definition, _except_ for the
+ * default_stderr channel. This case is handled specially so that
+ * the default logging category can be changed by redefining
+ * default_stderr. (XXXDCL Though now that I think of it, the default
+ * logging category can be changed with only one additional function
+ * call by defining a new channel and then calling isc_log_usechannel()
+ * for #ISC_LOGCATEGORY_DEFAULT.)
+ *
+ *\li Specifying #ISC_LOG_PRINTTIME or #ISC_LOG_PRINTTAG for syslog is
+ * allowed, but probably not what you wanted to do.
+ *
+ * #ISC_LOG_DEBUGONLY will mark the channel as usable only when the
+ * debug level of the logging context (see isc_log_setdebuglevel)
+ * is non-zero.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ *\li name is not NULL.
+ *
+ *\li type is #ISC_LOG_TOSYSLOG, #ISC_LOG_TOFILE, #ISC_LOG_TOFILEDESC or
+ * #ISC_LOG_TONULL.
+ *
+ *\li destination is not NULL unless type is #ISC_LOG_TONULL.
+ *
+ *\li level is >= #ISC_LOG_CRITICAL (the most negative logging level).
+ *
+ *\li flags does not include any bits aside from the ISC_LOG_PRINT* bits,
+ * #ISC_LOG_DEBUGONLY or #ISC_LOG_BUFFERED.
+ *
+ * Ensures:
+ *\li #ISC_R_SUCCESS
+ * A channel with the given name is usable with
+ * isc_log_usechannel().
+ *
+ *\li #ISC_R_NOMEMORY or #ISC_R_UNEXPECTED
+ * No additional memory is being used by the logging context.
+ * Any channel that previously existed with the given name
+ * is not redefined.
+ */
+
+isc_result_t
+isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
+ const isc_logcategory_t *category,
+ const isc_logmodule_t *module);
+/*%<
+ * Associate a named logging channel with a category and module that
+ * will use it.
+ *
+ * Notes:
+ *\li The name is searched for linearly in the set of known channel names
+ * until a match is found. (Note the performance impact of a very large
+ * number of named channels.) When multiple channels of the same
+ * name are defined, the most recent definition is found.
+ *
+ *\li Specifying a very large number of channels for a category will have
+ * a moderate impact on performance in isc_log_write(), as each
+ * call looks up the category for the start of a linked list, which
+ * it follows all the way to the end to find matching modules. The
+ * test for matching modules is integral, though.
+ *
+ *\li If category is NULL, then the channel is associated with the indicated
+ * module for all known categories (including the "default" category).
+ *
+ *\li If module is NULL, then the channel is associated with every module
+ * that uses that category.
+ *
+ *\li Passing both category and module as NULL would make every log message
+ * use the indicated channel.
+ *
+ * \li Specifying a channel that is #ISC_LOG_TONULL for a category/module pair
+ * has no effect on any other channels associated with that pair,
+ * regardless of ordering. Thus you cannot use it to "mask out" one
+ * category/module pair when you have specified some other channel that
+ * is also used by that category/module pair.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ *\li category is NULL or has an id that is in the range of known ids.
+ *
+ * module is NULL or has an id that is in the range of known ids.
+ *
+ * Ensures:
+ *\li #ISC_R_SUCCESS
+ * The channel will be used by the indicated category/module
+ * arguments.
+ *
+ *\li #ISC_R_NOMEMORY
+ * If assignment for a specific category has been requested,
+ * the channel has not been associated with the indicated
+ * category/module arguments and no additional memory is
+ * used by the logging context.
+ * If assignment for all categories has been requested
+ * then _some_ may have succeeded (starting with category
+ * "default" and progressing through the order of categories
+ * passed to isc_log_registercategories()) and additional memory
+ * is being used by whatever assignments succeeded.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOMEMORY Resource limit: Out of memory
+ */
+
+/* Attention: next four comments PRECEDE code */
+/*!
+ * \brief
+ * Write a message to the log channels.
+ *
+ * Notes:
+ *\li lctx can be NULL; this is allowed so that programs which use
+ * libraries that use the ISC logging system are not required to
+ * also use it.
+ *
+ *\li The format argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li The category and module arguments must have ids that are in the
+ * range of known ids, as established by isc_log_registercategories()
+ * and isc_log_registermodules().
+ *
+ *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define
+ * channels, and explicit debugging level must be identified for
+ * isc_log_write() via ISC_LOG_DEBUG(level).
+ *
+ *\li format != NULL.
+ *
+ * Ensures:
+ *\li The log message is written to every channel associated with the
+ * indicated category/module pair.
+ *
+ * Returns:
+ *\li Nothing. Failure to log a message is not construed as a
+ * meaningful error.
+ */
+void
+isc_log_write(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+
+ ISC_FORMAT_PRINTF(5, 6);
+
+/*%
+ * Write a message to the log channels.
+ *
+ * Notes:
+ *\li lctx can be NULL; this is allowed so that programs which use
+ * libraries that use the ISC logging system are not required to
+ * also use it.
+ *
+ *\li The format argument is a printf(3) string, with additional arguments
+ * as necessary.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li The category and module arguments must have ids that are in the
+ * range of known ids, as established by isc_log_registercategories()
+ * and isc_log_registermodules().
+ *
+ *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define
+ * channels, and explicit debugging level must be identified for
+ * isc_log_write() via ISC_LOG_DEBUG(level).
+ *
+ *\li format != NULL.
+ *
+ * Ensures:
+ *\li The log message is written to every channel associated with the
+ * indicated category/module pair.
+ *
+ * Returns:
+ *\li Nothing. Failure to log a message is not construed as a
+ * meaningful error.
+ */
+void
+isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format,
+ va_list args)
+
+ ISC_FORMAT_PRINTF(5, 0);
+
+/*%
+ * Write a message to the log channels, pruning duplicates that occur within
+ * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval).
+ * This function is otherwise identical to isc_log_write().
+ */
+void
+isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format, ...)
+
+ ISC_FORMAT_PRINTF(5, 6);
+
+/*%
+ * Write a message to the log channels, pruning duplicates that occur within
+ * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval).
+ * This function is otherwise identical to isc_log_vwrite().
+ */
+void
+isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *format,
+ va_list args)
+
+ ISC_FORMAT_PRINTF(5, 0);
+
+void
+isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level);
+/*%<
+ * Set the debugging level used for logging.
+ *
+ * Notes:
+ *\li Setting the debugging level to 0 disables debugging log messages.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li The debugging level is set to the requested value.
+ */
+
+unsigned int
+isc_log_getdebuglevel(isc_log_t *lctx);
+/*%<
+ * Get the current debugging level.
+ *
+ * Notes:
+ *\li This is provided so that a program can have a notion of
+ * "increment debugging level" or "decrement debugging level"
+ * without needing to keep track of what the current level is.
+ *
+ *\li A return value of 0 indicates that debugging messages are disabled.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Ensures:
+ *\li The current logging debugging level is returned.
+ */
+
+bool
+isc_log_wouldlog(isc_log_t *lctx, int level);
+/*%<
+ * Determine whether logging something to 'lctx' at 'level' would
+ * actually cause something to be logged somewhere.
+ *
+ * If #false is returned, it is guaranteed that nothing would
+ * be logged, allowing the caller to omit unnecessary
+ * isc_log_write() calls and possible message preformatting.
+ */
+
+void
+isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval);
+/*%<
+ * Set the interval over which duplicate log messages will be ignored
+ * by isc_log_[v]write1(), in seconds.
+ *
+ * Notes:
+ *\li Increasing the duplicate interval from X to Y will not necessarily
+ * filter out duplicates of messages logged in Y - X seconds since the
+ * increase. (Example: Message1 is logged at midnight. Message2
+ * is logged at 00:01:00, when the interval is only 30 seconds, causing
+ * Message1 to be expired from the log message history. Then the interval
+ * is increased to 3000 (five minutes) and at 00:04:00 Message1 is logged
+ * again. It will appear the second time even though less than five
+ * passed since the first occurrence.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ */
+
+unsigned int
+isc_log_getduplicateinterval(isc_logconfig_t *lcfg);
+/*%<
+ * Get the current duplicate filtering interval.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ * Returns:
+ *\li The current duplicate filtering interval.
+ */
+
+void
+isc_log_settag(isc_logconfig_t *lcfg, const char *tag);
+/*%<
+ * Set the program name or other identifier for #ISC_LOG_PRINTTAG.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ * Notes:
+ *\li If this function has not set the tag to a non-NULL, non-empty value,
+ * then the #ISC_LOG_PRINTTAG channel flag will not print anything.
+ * Unlike some implementations of syslog on Unix systems, you *must* set
+ * the tag in order to get it logged. It is not implicitly derived from
+ * the program name (which is pretty impossible to infer portably).
+ *
+ *\li Setting the tag to NULL or the empty string will also cause the
+ * #ISC_LOG_PRINTTAG channel flag to not print anything. If tag equals the
+ * empty string, calls to isc_log_gettag will return NULL.
+ *
+ * XXXDCL when creating a new isc_logconfig_t, it might be nice if the tag
+ * of the currently active isc_logconfig_t was inherited. this does not
+ * currently happen.
+ */
+
+char *
+isc_log_gettag(isc_logconfig_t *lcfg);
+/*%<
+ * Get the current identifier printed with #ISC_LOG_PRINTTAG.
+ *
+ * Requires:
+ *\li lcfg is a valid logging configuration.
+ *
+ * Notes:
+ *\li Since isc_log_settag() will not associate a zero-length string
+ * with the logging configuration, attempts to do so will cause
+ * this function to return NULL. However, a determined programmer
+ * will observe that (currently) a tag of length greater than zero
+ * could be set, and then modified to be zero length.
+ *
+ * Returns:
+ *\li A pointer to the current identifier, or NULL if none has been set.
+ */
+
+void
+isc_log_opensyslog(const char *tag, int options, int facility);
+/*%<
+ * Initialize syslog logging.
+ *
+ * Notes:
+ *\li XXXDCL NT
+ * This is currently equivalent to openlog(), but is not going to remain
+ * that way. In the meantime, the arguments are all identical to
+ * those used by openlog(3), as follows:
+ *
+ * \code
+ * tag: The string to use in the position of the program
+ * name in syslog messages. Most (all?) syslogs
+ * will use basename(argv[0]) if tag is NULL.
+ *
+ * options: LOG_CONS, LOG_PID, LOG_NDELAY ... whatever your
+ * syslog supports.
+ *
+ * facility: The default syslog facility. This is irrelevant
+ * since isc_log_write will ALWAYS use the channel's
+ * declared facility.
+ * \endcode
+ *
+ *\li Zero effort has been made (yet) to accommodate systems with openlog()
+ * that only takes two arguments, or to identify valid syslog
+ * facilities or options for any given architecture.
+ *
+ *\li It is necessary to call isc_log_opensyslog() to initialize
+ * syslogging on machines which do not support network connections to
+ * syslogd because they require a Unix domain socket to be used. Since
+ * this is a chore to determine at run-time, it is suggested that it
+ * always be called by programs using the ISC logging system.
+ *
+ * Requires:
+ *\li Nothing.
+ *
+ * Ensures:
+ *\li openlog() is called to initialize the syslog system.
+ */
+
+void
+isc_log_closefilelogs(isc_log_t *lctx);
+/*%<
+ * Close all open files used by #ISC_LOG_TOFILE channels.
+ *
+ * Notes:
+ *\li This function is provided for programs that want to use their own
+ * log rolling mechanism rather than the one provided internally.
+ * For example, a program that wanted to keep daily logs would define
+ * a channel which used #ISC_LOG_ROLLNEVER, then once a day would
+ * rename the log file and call isc_log_closefilelogs().
+ *
+ *\li #ISC_LOG_TOFILEDESC channels are unaffected.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *
+ * Ensures:
+ *\li The open files are closed and will be reopened when they are
+ * next needed.
+ */
+
+isc_logcategory_t *
+isc_log_categorybyname(isc_log_t *lctx, const char *name);
+/*%<
+ * Find a category by its name.
+ *
+ * Notes:
+ *\li The string name of a category is not required to be unique.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *\li name is not NULL.
+ *
+ * Returns:
+ *\li A pointer to the _first_ isc_logcategory_t structure used by "name".
+ *
+ *\li NULL if no category exists by that name.
+ */
+
+isc_logmodule_t *
+isc_log_modulebyname(isc_log_t *lctx, const char *name);
+/*%<
+ * Find a module by its name.
+ *
+ * Notes:
+ *\li The string name of a module is not required to be unique.
+ *
+ * Requires:
+ *\li lctx is a valid context.
+ *\li name is not NULL.
+ *
+ * Returns:
+ *\li A pointer to the _first_ isc_logmodule_t structure used by "name".
+ *
+ *\li NULL if no module exists by that name.
+ */
+
+void
+isc_log_setcontext(isc_log_t *lctx);
+/*%<
+ * Sets the context used by the libisc for logging.
+ *
+ * Requires:
+ *\li lctx be a valid context.
+ */
+
+isc_result_t
+isc_logfile_roll(isc_logfile_t *file);
+/*%<
+ * Roll a logfile.
+ *
+ * Requires:
+ *\li file is not NULL.
+ */
+
+void
+isc_log_setforcelog(bool v);
+/*%<
+ * Turn forced logging on/off for the current thread. This can be used to
+ * temporarily increase the debug level to maximum for the duration of
+ * a single task event.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/magic.h b/lib/isc/include/isc/magic.h
new file mode 100644
index 0000000..5e2f184
--- /dev/null
+++ b/lib/isc/include/isc/magic.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/magic.h */
+
+typedef struct {
+ unsigned int magic;
+} isc__magic_t;
+
+/*%
+ * To use this macro the magic number MUST be the first thing in the
+ * structure, and MUST be of type "unsigned int".
+ * The intent of this is to allow magic numbers to be checked even though
+ * the object is otherwise opaque.
+ */
+#define ISC_MAGIC_VALID(a, b) \
+ ((a) != NULL && ((const isc__magic_t *)(a))->magic == (b))
+
+#define ISC_MAGIC(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
diff --git a/lib/isc/include/isc/managers.h b/lib/isc/include/isc/managers.h
new file mode 100644
index 0000000..774ed30
--- /dev/null
+++ b/lib/isc/include/isc/managers.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <isc/netmgr.h>
+#include <isc/result.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+
+typedef struct isc_managers isc_managers_t;
+
+isc_result_t
+isc_managers_create(isc_mem_t *mctx, size_t workers, size_t quantum,
+ isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp,
+ isc_timermgr_t **timermgrp);
+
+void
+isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp,
+ isc_timermgr_t **timermgrp);
diff --git a/lib/isc/include/isc/md.h b/lib/isc/include/isc/md.h
new file mode 100644
index 0000000..f52424b
--- /dev/null
+++ b/lib/isc/include/isc/md.h
@@ -0,0 +1,204 @@
+/*
+ * 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 isc/md.h
+ * \brief This is the header file for message digest algorithms.
+ */
+
+#pragma once
+
+#include <isc/lang.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef void isc_md_t;
+
+/**
+ * isc_md_type_t:
+ * @ISC_MD_MD5: MD5
+ * @ISC_MD_SHA1: SHA-1
+ * @ISC_MD_SHA224: SHA-224
+ * @ISC_MD_SHA256: SHA-256
+ * @ISC_MD_SHA384: SHA-384
+ * @ISC_MD_SHA512: SHA-512
+ *
+ * Enumeration of supported message digest algorithms.
+ */
+typedef void isc_md_type_t;
+
+#define ISC_MD_MD5 isc__md_md5()
+#define ISC_MD_SHA1 isc__md_sha1()
+#define ISC_MD_SHA224 isc__md_sha224()
+#define ISC_MD_SHA256 isc__md_sha256()
+#define ISC_MD_SHA384 isc__md_sha384()
+#define ISC_MD_SHA512 isc__md_sha512()
+
+const isc_md_type_t *
+isc__md_md5(void);
+const isc_md_type_t *
+isc__md_sha1(void);
+const isc_md_type_t *
+isc__md_sha224(void);
+const isc_md_type_t *
+isc__md_sha256(void);
+const isc_md_type_t *
+isc__md_sha384(void);
+const isc_md_type_t *
+isc__md_sha512(void);
+
+#define ISC_MD5_DIGESTLENGTH isc_md_type_get_size(ISC_MD_MD5)
+#define ISC_MD5_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_MD5)
+#define ISC_SHA1_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA1)
+#define ISC_SHA1_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA1)
+#define ISC_SHA224_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA224)
+#define ISC_SHA224_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA224)
+#define ISC_SHA256_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA256)
+#define ISC_SHA256_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA256)
+#define ISC_SHA384_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA384)
+#define ISC_SHA384_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA384)
+#define ISC_SHA512_DIGESTLENGTH isc_md_type_get_size(ISC_MD_SHA512)
+#define ISC_SHA512_BLOCK_LENGTH isc_md_type_get_block_size(ISC_MD_SHA512)
+
+#define ISC_MAX_MD_SIZE 64U /* EVP_MAX_MD_SIZE */
+#define ISC_MAX_BLOCK_SIZE 128U /* ISC_SHA512_BLOCK_LENGTH */
+
+/**
+ * isc_md:
+ * @type: the digest type
+ * @buf: the data to hash
+ * @len: the length of the data to hash
+ * @digest: the output buffer
+ * @digestlen: the length of the data written to @digest
+ *
+ * This function hashes @len bytes of data at @buf and places the result in
+ * @digest. If the @digestlen parameter is not NULL then the number of bytes of
+ * data written (i.e. the length of the digest) will be written to the integer
+ * at @digestlen, at most ISC_MAX_MD_SIZE bytes will be written.
+ */
+isc_result_t
+isc_md(const isc_md_type_t *type, const unsigned char *buf, const size_t len,
+ unsigned char *digest, unsigned int *digestlen);
+
+/**
+ * isc_md_new:
+ *
+ * This function allocates, initializes and returns a digest context.
+ */
+isc_md_t *
+isc_md_new(void);
+
+/**
+ * isc_md_free:
+ * @md: message digest context
+ *
+ * This function cleans up digest context ctx and frees up the space allocated
+ * to it.
+ */
+void
+isc_md_free(isc_md_t *);
+
+/**
+ * isc_md_init:
+ * @md: message digest context
+ * @type: digest type
+ *
+ * This function sets up digest context @md to use a digest @type. @md must be
+ * initialized before calling this function.
+ */
+isc_result_t
+isc_md_init(isc_md_t *, const isc_md_type_t *md_type);
+
+/**
+ * isc_md_reset:
+ * @md: message digest context
+ *
+ * This function resets the digest context ctx. This can be used to reuse an
+ * already existing context.
+ */
+isc_result_t
+isc_md_reset(isc_md_t *md);
+
+/**
+ * isc_md_update:
+ * @md: message digest context
+ * @buf: data to hash
+ * @len: length of the data to hash
+ *
+ * This function hashes @len bytes of data at @buf into the digest context @md.
+ * This function can be called several times on the same @md to hash additional
+ * data.
+ */
+isc_result_t
+isc_md_update(isc_md_t *md, const unsigned char *buf, const size_t len);
+
+/**
+ * isc_md_final:
+ * @md: message digest context
+ * @digest: the output buffer
+ * @digestlen: the length of the data written to @digest
+ *
+ * This function retrieves the digest value from @md and places it in @digest.
+ * If the @digestlen parameter is not NULL then the number of bytes of data
+ * written (i.e. the length of the digest) will be written to the integer at
+ * @digestlen, at most ISC_MAX_MD_SIZE bytes will be written. After calling
+ * this function no additional calls to isc_md_update() can be made.
+ */
+isc_result_t
+isc_md_final(isc_md_t *md, unsigned char *digest, unsigned int *digestlen);
+
+/**
+ * isc_md_get_type:
+ * @md: message digest contezt
+ *
+ * This function return the isc_md_type_t previously set for the supplied
+ * message digest context or NULL if no isc_md_type_t has been set.
+ */
+const isc_md_type_t *
+isc_md_get_md_type(isc_md_t *md);
+
+/**
+ * isc_md_size:
+ *
+ * This function return the size of the message digest when passed an isc_md_t
+ * structure, i.e. the size of the hash.
+ */
+size_t
+isc_md_get_size(isc_md_t *md);
+
+/**
+ * isc_md_block_size:
+ *
+ * This function return the block size of the message digest when passed an
+ * isc_md_t structure.
+ */
+size_t
+isc_md_get_block_size(isc_md_t *md);
+
+/**
+ * isc_md_size:
+ *
+ * This function return the size of the message digest when passed an
+ * isc_md_type_t , i.e. the size of the hash.
+ */
+size_t
+isc_md_type_get_size(const isc_md_type_t *md_type);
+
+/**
+ * isc_md_block_size:
+ *
+ * This function return the block size of the message digest when passed an
+ * isc_md_type_t.
+ */
+size_t
+isc_md_type_get_block_size(const isc_md_type_t *md_type);
diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h
new file mode 100644
index 0000000..bd59f73
--- /dev/null
+++ b/lib/isc/include/isc/mem.h
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/mem.h */
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <isc/attributes.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define ISC_MEM_LOWATER 0
+#define ISC_MEM_HIWATER 1
+typedef void (*isc_mem_water_t)(void *, int);
+
+/*%
+ * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
+ * allocation and freeing by file and line number.
+ */
+#ifndef ISC_MEM_TRACKLINES
+#define ISC_MEM_TRACKLINES 0
+#endif /* ifndef ISC_MEM_TRACKLINES */
+
+extern unsigned int isc_mem_debugging;
+extern unsigned int isc_mem_defaultflags;
+
+/*@{*/
+#define ISC_MEM_DEBUGTRACE 0x00000001U
+#define ISC_MEM_DEBUGRECORD 0x00000002U
+#define ISC_MEM_DEBUGUSAGE 0x00000004U
+#define ISC_MEM_DEBUGALL 0x0000001FU
+/*!<
+ * The variable isc_mem_debugging holds a set of flags for
+ * turning certain memory debugging options on or off at
+ * runtime. It is initialized to the value ISC_MEM_DEGBUGGING,
+ * which is 0 by default but may be overridden at compile time.
+ * The following flags can be specified:
+ *
+ * \li #ISC_MEM_DEBUGTRACE
+ * Log each allocation and free to isc_lctx.
+ *
+ * \li #ISC_MEM_DEBUGRECORD
+ * Remember each allocation, and match them up on free.
+ * Crash if a free doesn't match an allocation.
+ *
+ * \li #ISC_MEM_DEBUGUSAGE
+ * If a hi_water mark is set, print the maximum inuse memory
+ * every time it is raised once it exceeds the hi_water mark.
+ */
+/*@}*/
+
+#if ISC_MEM_TRACKLINES
+#define _ISC_MEM_FILELINE , __FILE__, __LINE__
+#define _ISC_MEM_FLARG , const char *, unsigned int
+#else /* if ISC_MEM_TRACKLINES */
+#define _ISC_MEM_FILELINE
+#define _ISC_MEM_FLARG
+#endif /* if ISC_MEM_TRACKLINES */
+
+/*
+ * Flags for isc_mem_create() calls.
+ */
+#define ISC_MEMFLAG_RESERVED1 0x00000001 /* reserved, obsoleted, don't use */
+#define ISC_MEMFLAG_RESERVED2 0x00000002 /* reserved, obsoleted, don't use */
+#define ISC_MEMFLAG_FILL \
+ 0x00000004 /* fill with pattern after alloc and frees */
+
+/*%
+ * Define ISC_MEM_DEFAULTFILL=1 to turn filling the memory with pattern
+ * after alloc and free.
+ */
+#if ISC_MEM_DEFAULTFILL
+#define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_FILL
+#else /* if !ISC_MEM_USE_INTERNAL_MALLOC */
+#define ISC_MEMFLAG_DEFAULT 0
+#endif /* if !ISC_MEM_USE_INTERNAL_MALLOC */
+
+/*%
+ * isc_mem_putanddetach() is a convenience function for use where you
+ * have a structure with an attached memory context.
+ *
+ * Given:
+ *
+ * \code
+ * struct {
+ * ...
+ * isc_mem_t *mctx;
+ * ...
+ * } *ptr;
+ *
+ * isc_mem_t *mctx;
+ *
+ * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr));
+ * \endcode
+ *
+ * is the equivalent of:
+ *
+ * \code
+ * mctx = NULL;
+ * isc_mem_attach(ptr->mctx, &mctx);
+ * isc_mem_detach(&ptr->mctx);
+ * isc_mem_put(mctx, ptr, sizeof(*ptr));
+ * isc_mem_detach(&mctx);
+ * \endcode
+ */
+
+/*%
+ * These functions are actually implemented in isc__mem_<function>
+ * (two underscores). The single-underscore macros are used to pass
+ * __FILE__ and __LINE__, and in the case of the put functions, to
+ * set the pointer being freed to NULL in the calling function.
+ *
+ * Many of these functions have a further isc___mem_<function>
+ * (three underscores) implementation, which is called indirectly
+ * via the isc_memmethods structure in the mctx so that dynamically
+ * loaded modules can use them even if named is statically linked.
+ */
+
+#define ISCMEMFUNC(sfx) isc__mem_##sfx
+#define ISCMEMPOOLFUNC(sfx) isc__mempool_##sfx
+
+#define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s), 0 _ISC_MEM_FILELINE)
+#define isc_mem_get_aligned(c, s, a) \
+ ISCMEMFUNC(get)((c), (s), (a)_ISC_MEM_FILELINE)
+#define isc_mem_reget(c, p, o, n) \
+ ISCMEMFUNC(reget)((c), (p), (o), (n), 0 _ISC_MEM_FILELINE)
+#define isc_mem_reget_aligned(c, p, o, n, a) \
+ ISCMEMFUNC(reget)((c), (p), (o), (n), (a)_ISC_MEM_FILELINE)
+#define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s)_ISC_MEM_FILELINE)
+#define isc_mem_reallocate(c, p, s) \
+ ISCMEMFUNC(reallocate)((c), (p), (s)_ISC_MEM_FILELINE)
+#define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p)_ISC_MEM_FILELINE)
+#define isc_mem_strndup(c, p, l) \
+ ISCMEMFUNC(strndup)((c), (p), (l)_ISC_MEM_FILELINE)
+#define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c)_ISC_MEM_FILELINE)
+
+#define isc_mem_put(c, p, s) \
+ do { \
+ ISCMEMFUNC(put)((c), (p), (s), 0 _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_put_aligned(c, p, s, a) \
+ do { \
+ ISCMEMFUNC(put) \
+ ((c), (p), (s), (a)_ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_putanddetach(c, p, s) \
+ do { \
+ ISCMEMFUNC(putanddetach)((c), (p), (s), 0 _ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_putanddetach_aligned(c, p, s, a) \
+ do { \
+ ISCMEMFUNC(putanddetach) \
+ ((c), (p), (s), (a)_ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mem_free(c, p) \
+ do { \
+ ISCMEMFUNC(free)((c), (p)_ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+#define isc_mempool_put(c, p) \
+ do { \
+ ISCMEMPOOLFUNC(put)((c), (p)_ISC_MEM_FILELINE); \
+ (p) = NULL; \
+ } while (0)
+
+/*@{*/
+#define isc_mem_create(cp) ISCMEMFUNC(create)((cp)_ISC_MEM_FILELINE)
+void ISCMEMFUNC(create)(isc_mem_t **_ISC_MEM_FLARG);
+
+/*!<
+ * \brief Create a memory context.
+ *
+ * Requires:
+ * mctxp != NULL && *mctxp == NULL */
+/*@}*/
+
+#define isc_mem_create_arena(cp) isc__mem_create_arena((cp)_ISC_MEM_FILELINE)
+void
+isc__mem_create_arena(isc_mem_t **_ISC_MEM_FLARG);
+/*!<
+ * \brief Create a memory context that routs all its operations to a
+ * dedicated jemalloc arena (when available). When jemalloc is not
+ * available, the function is, effectively, an alias to
+ * isc_mem_create().
+ *
+ * Requires:
+ * mctxp != NULL && *mctxp == NULL */
+/*@}*/
+
+isc_result_t
+isc_mem_arena_set_muzzy_decay_ms(isc_mem_t *mctx, const ssize_t decay_ms);
+
+isc_result_t
+isc_mem_arena_set_dirty_decay_ms(isc_mem_t *mctx, const ssize_t decay_ms);
+/*!<
+ * \brief These two functions set the given parameters on the
+ * jemalloc arena associated with the memory context (if there is
+ * one). When jemalloc is not available, these are no-op.
+ *
+ * NOTE: The "muzzy_decay_ms" and "dirty_decay_ms" are the most common
+ * parameters to adjust when the defaults do not work well (per the
+ * official jemalloc tuning guide:
+ * https://github.com/jemalloc/jemalloc/blob/dev/TUNING.md).
+ *
+ * Requires:
+ * mctx - a valid memory context.
+ */
+/*@}*/
+
+void
+isc_mem_attach(isc_mem_t *, isc_mem_t **);
+
+/*@{*/
+void
+isc_mem_attach(isc_mem_t *, isc_mem_t **);
+#define isc_mem_detach(cp) ISCMEMFUNC(detach)((cp)_ISC_MEM_FILELINE)
+void ISCMEMFUNC(detach)(isc_mem_t **_ISC_MEM_FLARG);
+/*!<
+ * \brief Attach to / detach from a memory context.
+ *
+ * This is intended for applications that use multiple memory contexts
+ * in such a way that it is not obvious when the last allocations from
+ * a given context has been freed and destroying the context is safe.
+ *
+ * Most applications do not need to call these functions as they can
+ * simply create a single memory context at the beginning of main()
+ * and destroy it at the end of main(), thereby guaranteeing that it
+ * is not destroyed while there are outstanding allocations.
+ */
+/*@}*/
+
+#define isc_mem_destroy(cp) ISCMEMFUNC(destroy)((cp)_ISC_MEM_FILELINE)
+void ISCMEMFUNC(destroy)(isc_mem_t **_ISC_MEM_FLARG);
+/*%<
+ * Destroy a memory context.
+ */
+
+void
+isc_mem_stats(isc_mem_t *mctx, FILE *out);
+/*%<
+ * Print memory usage statistics for 'mctx' on the stream 'out'.
+ */
+
+void
+isc_mem_setdestroycheck(isc_mem_t *mctx, bool on);
+/*%<
+ * If 'on' is true, 'mctx' will check for memory leaks when
+ * destroyed and abort the program if any are present.
+ */
+
+size_t
+isc_mem_inuse(isc_mem_t *mctx);
+/*%<
+ * Get an estimate of the amount of memory in use in 'mctx', in bytes.
+ * This includes quantization overhead, but does not include memory
+ * allocated from the system but not yet used.
+ */
+
+size_t
+isc_mem_maxinuse(isc_mem_t *mctx);
+/*%<
+ * Get an estimate of the largest amount of memory that has been in
+ * use in 'mctx' at any time.
+ */
+
+size_t
+isc_mem_total(isc_mem_t *mctx);
+/*%<
+ * Get the total amount of memory in 'mctx', in bytes, including memory
+ * not yet used.
+ */
+
+size_t
+isc_mem_malloced(isc_mem_t *ctx);
+/*%<
+ * Get an estimate of the amount of memory allocated in 'mctx', in bytes.
+ */
+
+size_t
+isc_mem_maxmalloced(isc_mem_t *ctx);
+/*%<
+ * Get an estimate of the largest amount of memory that has been
+ * allocated in 'mctx' at any time.
+ */
+
+bool
+isc_mem_isovermem(isc_mem_t *mctx);
+/*%<
+ * Return true iff the memory context is in "over memory" state, i.e.,
+ * a hiwater mark has been set and the used amount of memory has exceeds
+ * the mark.
+ */
+
+void
+isc_mem_clearwater(isc_mem_t *mctx);
+void
+isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
+ size_t hiwater, size_t lowater);
+/*%<
+ * Set high and low water marks for this memory context.
+ *
+ * When the memory usage of 'mctx' exceeds 'hiwater',
+ * '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs
+ * to call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the
+ * state change. 'water' may be called multiple times.
+ *
+ * When the usage drops below 'lowater', 'water' will again be called,
+ * this time with #ISC_MEM_LOWATER. 'water' need to calls
+ * isc_mem_waterack() with #ISC_MEM_LOWATER to acknowledge the change.
+ *
+ * static void
+ * water(void *arg, int mark) {
+ * struct foo *foo = arg;
+ *
+ * LOCK(&foo->marklock);
+ * if (foo->mark != mark) {
+ * foo->mark = mark;
+ * ....
+ * isc_mem_waterack(foo->mctx, mark);
+ * }
+ * UNLOCK(&foo->marklock);
+ * }
+ *
+ * if 'water' is set to NULL, the 'hiwater' and 'lowater' must set to 0, and
+ * high- and low-water processing are disabled for this memory context. There's
+ * a convenient function isc_mem_clearwater().
+ *
+ * Requires:
+ *
+ *\li If 'water' is NULL, 'hiwater' and 'lowater' must be set to 0.
+ *\li If 'water' and 'water_arg' have previously been set, they are
+ unchanged.
+ *\li 'hiwater' >= 'lowater'
+ */
+
+void
+isc_mem_waterack(isc_mem_t *ctx, int mark);
+/*%<
+ * Called to acknowledge changes in signaled by calls to 'water'.
+ */
+
+void
+isc_mem_checkdestroyed(FILE *file);
+/*%<
+ * Check that all memory contexts have been destroyed.
+ * Prints out those that have not been.
+ * Fatally fails if there are still active contexts.
+ */
+
+unsigned int
+isc_mem_references(isc_mem_t *ctx);
+/*%<
+ * Return the current reference count.
+ */
+
+void
+isc_mem_setname(isc_mem_t *ctx, const char *name);
+/*%<
+ * Name 'ctx'.
+ *
+ * Notes:
+ *
+ *\li Only the first 15 characters of 'name' will be copied.
+ *
+ * Requires:
+ *
+ *\li 'ctx' is a valid ctx.
+ */
+
+const char *
+isc_mem_getname(isc_mem_t *ctx);
+/*%<
+ * Get the name of 'ctx', as previously set using isc_mem_setname().
+ *
+ * Requires:
+ *\li 'ctx' is a valid ctx.
+ *
+ * Returns:
+ *\li A non-NULL pointer to a null-terminated string.
+ * If the ctx has not been named, the string is
+ * empty.
+ */
+
+#ifdef HAVE_LIBXML2
+int
+isc_mem_renderxml(void *writer0);
+/*%<
+ * Render all contexts' statistics and status in XML for writer.
+ */
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON_C
+isc_result_t
+isc_mem_renderjson(void *memobj0);
+/*%<
+ * Render all contexts' statistics and status in JSON.
+ */
+#endif /* HAVE_JSON_C */
+
+/*
+ * Memory pools
+ */
+
+#define isc_mempool_create(c, s, mp) \
+ isc__mempool_create((c), (s), (mp)_ISC_MEM_FILELINE)
+void
+isc__mempool_create(isc_mem_t *restrict mctx, const size_t element_size,
+ isc_mempool_t **mpctxp _ISC_MEM_FLARG);
+/*%<
+ * Create a memory pool.
+ *
+ * Requires:
+ *\li mctx is a valid memory context.
+ *\li size > 0
+ *\li mpctxp != NULL and *mpctxp == NULL
+ *
+ * Defaults:
+ *\li freemax = 1
+ *\li fillcount = 1
+ *
+ * Returns:
+ *\li #ISC_R_NOMEMORY -- not enough memory to create pool
+ *\li #ISC_R_SUCCESS -- all is well.
+ */
+
+#define isc_mempool_destroy(mp) isc__mempool_destroy((mp)_ISC_MEM_FILELINE)
+void
+isc__mempool_destroy(isc_mempool_t **restrict mpctxp _ISC_MEM_FLARG);
+/*%<
+ * Destroy a memory pool.
+ *
+ * Requires:
+ *\li mpctxp != NULL && *mpctxp is a valid pool.
+ *\li The pool has no un"put" allocations outstanding
+ */
+
+void
+isc_mempool_setname(isc_mempool_t *restrict mpctx, const char *name);
+/*%<
+ * Associate a name with a memory pool. At most 15 characters may be
+ *used.
+ *
+ * Requires:
+ *\li mpctx is a valid pool.
+ *\li name != NULL;
+ */
+
+/*
+ * The following functions get/set various parameters. Note that due to
+ * the unlocked nature of pools these are potentially random values
+ *unless the imposed externally provided locking protocols are followed.
+ *
+ * Also note that the quota limits will not always take immediate
+ * effect.
+ *
+ * All functions require (in addition to other requirements):
+ * mpctx is a valid memory pool
+ */
+
+unsigned int
+isc_mempool_getfreemax(isc_mempool_t *restrict mpctx);
+/*%<
+ * Returns the maximum allowed size of the free list.
+ */
+
+void
+isc_mempool_setfreemax(isc_mempool_t *restrict mpctx, const unsigned int limit);
+/*%<
+ * Sets the maximum allowed size of the free list.
+ */
+
+unsigned int
+isc_mempool_getfreecount(isc_mempool_t *restrict mpctx);
+/*%<
+ * Returns current size of the free list.
+ */
+
+unsigned int
+isc_mempool_getallocated(isc_mempool_t *restrict mpctx);
+/*%<
+ * Returns the number of items allocated from this pool.
+ */
+
+unsigned int
+isc_mempool_getfillcount(isc_mempool_t *restrict mpctx);
+/*%<
+ * Returns the number of items allocated as a block from the parent
+ * memory context when the free list is empty.
+ */
+
+void
+isc_mempool_setfillcount(isc_mempool_t *restrict mpctx,
+ const unsigned int limit);
+/*%<
+ * Sets the fillcount.
+ *
+ * Additional requirements:
+ *\li limit > 0
+ */
+
+#if defined(UNIT_TESTING) && defined(malloc)
+/*
+ * cmocka.h redefined malloc as a macro, we #undef it
+ * to avoid replacing ISC_ATTR_MALLOC with garbage.
+ */
+#pragma push_macro("malloc")
+#undef malloc
+#define POP_MALLOC_MACRO 1
+#endif
+
+/*
+ * Pseudo-private functions for use via macros. Do not call directly.
+ */
+void ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t,
+ size_t _ISC_MEM_FLARG);
+void ISCMEMFUNC(put)(isc_mem_t *, void *, size_t, size_t _ISC_MEM_FLARG);
+void ISCMEMFUNC(free)(isc_mem_t *, void *_ISC_MEM_FLARG);
+
+ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(put), 2)
+void *ISCMEMFUNC(get)(isc_mem_t *, size_t, size_t _ISC_MEM_FLARG);
+
+ISC_ATTR_DEALLOCATOR_IDX(ISCMEMFUNC(put), 2)
+void *ISCMEMFUNC(reget)(isc_mem_t *, void *, size_t, size_t,
+ size_t _ISC_MEM_FLARG);
+
+ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
+void *ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG);
+
+ISC_ATTR_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
+void *ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
+
+ISC_ATTR_RETURNS_NONNULL
+ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
+char *ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG);
+
+ISC_ATTR_RETURNS_NONNULL
+ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
+char *ISCMEMFUNC(strndup)(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG);
+
+ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMPOOLFUNC(put), 2)
+void *ISCMEMPOOLFUNC(get)(isc_mempool_t *_ISC_MEM_FLARG);
+
+void ISCMEMPOOLFUNC(put)(isc_mempool_t *, void *_ISC_MEM_FLARG);
+
+#ifdef POP_MALLOC_MACRO
+/*
+ * Restore cmocka.h macro for malloc.
+ */
+#pragma pop_macro("malloc")
+#endif
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/meminfo.h b/lib/isc/include/isc/meminfo.h
new file mode 100644
index 0000000..fc39e26
--- /dev/null
+++ b/lib/isc/include/isc/meminfo.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+uint64_t
+isc_meminfo_totalphys(void);
+/*%<
+ * Return total available physical memory in bytes, or 0 if this cannot
+ * be determined
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/mutex.h b/lib/isc/include/isc/mutex.h
new file mode 100644
index 0000000..b794216
--- /dev/null
+++ b/lib/isc/include/isc/mutex.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <pthread.h>
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h> /* for ISC_R_ codes */
+
+ISC_LANG_BEGINDECLS
+
+typedef pthread_mutex_t isc_mutex_t;
+
+int
+isc__mutex_init(isc_mutex_t *mp);
+
+#define isc_mutex_init(mp) \
+ do { \
+ int _err = isc__mutex_init((mp)); \
+ if (_err != 0) { \
+ FATAL_SYSERROR(_err, "pthread_mutex_init()"); \
+ } \
+ } while (0)
+
+#define isc_mutex_lock(mp) \
+ ((pthread_mutex_lock((mp)) == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_mutex_unlock(mp) \
+ ((pthread_mutex_unlock((mp)) == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
+
+#define isc_mutex_trylock(mp) \
+ ((pthread_mutex_trylock((mp)) == 0) ? ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+
+#define isc_mutex_destroy(mp) RUNTIME_CHECK(pthread_mutex_destroy((mp)) == 0)
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/mutexblock.h b/lib/isc/include/isc/mutexblock.h
new file mode 100644
index 0000000..f5f2e32
--- /dev/null
+++ b/lib/isc/include/isc/mutexblock.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/mutexblock.h */
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_mutexblock_init(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Initialize a block of locks. If an error occurs all initialized locks
+ * will be destroyed, if possible.
+ *
+ * Requires:
+ *
+ *\li block != NULL
+ *
+ *\li count > 0
+ *
+ */
+
+void
+isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count);
+/*%<
+ * Destroy a block of locks.
+ *
+ * Requires:
+ *
+ *\li block != NULL
+ *
+ *\li count > 0
+ *
+ *\li Each lock in the block be initialized via isc_mutex_init() or
+ * the whole block was initialized via isc_mutex_initblock().
+ *
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/net.h b/lib/isc/include/isc/net.h
new file mode 100644
index 0000000..1a3ce63
--- /dev/null
+++ b/lib/isc/include/isc/net.h
@@ -0,0 +1,292 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * Basic Networking Types
+ *
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ *\li struct in_addr
+ *\li struct in6_addr
+ *\li struct in6_pktinfo
+ *\li struct sockaddr
+ *\li struct sockaddr_in
+ *\li struct sockaddr_in6
+ *\li struct sockaddr_storage
+ *\li in_port_t
+ *
+ * It ensures that the AF_ and PF_ macros are defined.
+ *
+ * It declares ntoh[sl]() and hton[sl]().
+ *
+ * It declares inet_ntop(), and inet_pton().
+ *
+ * It ensures that #INADDR_LOOPBACK, #INADDR_ANY, #IN6ADDR_ANY_INIT,
+ * IN6ADDR_V4MAPPED_INIT, in6addr_any, and in6addr_loopback are available.
+ *
+ * It ensures that IN_MULTICAST() is available to check for multicast
+ * addresses.
+ *
+ * MP:
+ *\li No impact.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li N/A.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li BSD Socket API
+ *\li RFC2553
+ */
+
+/***
+ *** Imports.
+ ***/
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <arpa/inet.h> /* Contractual promise. */
+#include <net/if.h>
+#include <netinet/in.h> /* Contractual promise. */
+#include <sys/socket.h> /* Contractual promise. */
+#include <sys/types.h>
+
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+/*% IPv6 address loopback init */
+#define IN6ADDR_LOOPBACK_INIT \
+ { \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \
+ } \
+ } \
+ }
+#else /* ifdef s6_addr */
+#define IN6ADDR_LOOPBACK_INIT \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \
+ } \
+ }
+#endif /* ifdef s6_addr */
+#endif /* ifndef IN6ADDR_LOOPBACK_INIT */
+
+#ifndef IN6ADDR_V4MAPPED_INIT
+#ifdef s6_addr
+/*% IPv6 v4mapped prefix init */
+#define IN6ADDR_V4MAPPED_INIT \
+ { \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, \
+ 0, 0, 0 \
+ } \
+ } \
+ }
+#else /* ifdef s6_addr */
+#define IN6ADDR_V4MAPPED_INIT \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 \
+ } \
+ }
+#endif /* ifdef s6_addr */
+#endif /* ifndef IN6ADDR_V4MAPPED_INIT */
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+/*% Is IPv6 address V4 mapped? */
+#define IN6_IS_ADDR_V4MAPPED(x) \
+ (memcmp((x)->s6_addr, in6addr_any.s6_addr, 10) == 0 && \
+ (x)->s6_addr[10] == 0xff && (x)->s6_addr[11] == 0xff)
+#endif /* ifndef IN6_IS_ADDR_V4MAPPED */
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+/*% Is IPv6 address V4 compatible? */
+#define IN6_IS_ADDR_V4COMPAT(x) \
+ (memcmp((x)->s6_addr, in6addr_any.s6_addr, 12) == 0 && \
+ ((x)->s6_addr[12] != 0 || (x)->s6_addr[13] != 0 || \
+ (x)->s6_addr[14] != 0 || \
+ ((x)->s6_addr[15] != 0 && (x)->s6_addr[15] != 1)))
+#endif /* ifndef IN6_IS_ADDR_V4COMPAT */
+
+#ifndef IN6_IS_ADDR_MULTICAST
+/*% Is IPv6 address multicast? */
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
+#endif /* ifndef IN6_IS_ADDR_MULTICAST */
+
+#ifndef IN6_IS_ADDR_LINKLOCAL
+/*% Is IPv6 address linklocal? */
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif /* ifndef IN6_IS_ADDR_LINKLOCAL */
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+/*% is IPv6 address sitelocal? */
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif /* ifndef IN6_IS_ADDR_SITELOCAL */
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+/*% is IPv6 address loopback? */
+#define IN6_IS_ADDR_LOOPBACK(x) \
+ (memcmp((x)->s6_addr, in6addr_loopback.s6_addr, 16) == 0)
+#endif /* ifndef IN6_IS_ADDR_LOOPBACK */
+
+#ifndef AF_INET6
+/*% IPv6 */
+#define AF_INET6 99
+#endif /* ifndef AF_INET6 */
+
+#ifndef PF_INET6
+/*% IPv6 */
+#define PF_INET6 AF_INET6
+#endif /* ifndef PF_INET6 */
+
+#ifndef INADDR_ANY
+/*% inaddr any */
+#define INADDR_ANY 0x00000000UL
+#endif /* ifndef INADDR_ANY */
+
+#ifndef INADDR_LOOPBACK
+/*% inaddr loopback */
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif /* ifndef INADDR_LOOPBACK */
+
+#ifndef MSG_TRUNC
+/*%
+ * If this system does not have MSG_TRUNC (as returned from recvmsg())
+ * ISC_PLATFORM_RECVOVERFLOW will be defined. This will enable the MSG_TRUNC
+ * faking code in socket.c.
+ */
+#define ISC_PLATFORM_RECVOVERFLOW
+#endif /* ifndef MSG_TRUNC */
+
+/*% IP address. */
+#define ISC__IPADDR(x) ((uint32_t)htonl((uint32_t)(x)))
+
+/*% Is IP address multicast? */
+#define ISC_IPADDR_ISMULTICAST(i) \
+ (((uint32_t)(i)&ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xe0000000))
+
+#define ISC_IPADDR_ISEXPERIMENTAL(i) \
+ (((uint32_t)(i)&ISC__IPADDR(0xf0000000)) == ISC__IPADDR(0xf0000000))
+
+/***
+ *** Functions.
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_net_probeipv4(void);
+/*%<
+ * Check if the system's kernel supports IPv4.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS IPv4 is supported.
+ *\li #ISC_R_NOTFOUND IPv4 is not supported.
+ *\li #ISC_R_DISABLED IPv4 is disabled.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeipv6(void);
+/*%<
+ * Check if the system's kernel supports IPv6.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS IPv6 is supported.
+ *\li #ISC_R_NOTFOUND IPv6 is not supported.
+ *\li #ISC_R_DISABLED IPv6 is disabled.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*%<
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS the option is supported for both TCP and UDP.
+ *\li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ *\li #ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void);
+/*
+ * Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option
+ * for UDP sockets.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS the option is supported.
+ * \li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * \li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_net_disableipv4(void);
+
+void
+isc_net_disableipv6(void);
+
+void
+isc_net_enableipv4(void);
+
+void
+isc_net_enableipv6(void);
+
+isc_result_t
+isc_net_probeunix(void);
+/*
+ * Returns whether UNIX domain sockets are supported.
+ */
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high);
+/*%<
+ * Returns system's default range of ephemeral UDP ports, if defined.
+ * If the range is not available or unknown, ISC_NET_PORTRANGELOW and
+ * ISC_NET_PORTRANGEHIGH will be returned.
+ *
+ * Requires:
+ *
+ *\li 'low' and 'high' must be non NULL.
+ *
+ * Returns:
+ *
+ *\li *low and *high will be the ports specifying the low and high ends of
+ * the range.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/netaddr.h b/lib/isc/include/isc/netaddr.h
new file mode 100644
index 0000000..112051f
--- /dev/null
+++ b/lib/isc/include/isc/netaddr.h
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/netaddr.h */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+
+#include <sys/types.h>
+#include <sys/un.h>
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Any updates to this structure should also be applied in
+ * contrib/modules/dlz/dlz_minmal.h.
+ */
+struct isc_netaddr {
+ unsigned int family;
+ union {
+ struct in_addr in;
+ struct in6_addr in6;
+ char un[sizeof(((struct sockaddr_un *)0)->sun_path)];
+ } type;
+ uint32_t zone;
+};
+
+struct isc_netprefix {
+ isc_netaddr_t addr;
+ unsigned int prefixlen;
+};
+
+bool
+isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b);
+
+/*%<
+ * Compare network addresses 'a' and 'b'. Return #true if
+ * they are equal, #false if not.
+ */
+
+bool
+isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
+ unsigned int prefixlen);
+/*%<
+ * Compare the 'prefixlen' most significant bits of the network
+ * addresses 'a' and 'b'. If 'b''s scope is zero then 'a''s scope is
+ * ignored. Return #true if they are equal, #false if not.
+ */
+
+isc_result_t
+isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp);
+/*%<
+ * Convert a netmask in 's' into a prefix length in '*lenp'.
+ * The mask should consist of zero or more '1' bits in the
+ * most significant part of the address, followed by '0' bits.
+ * If this is not the case, #ISC_R_MASKNONCONTIG is returned.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_MASKNONCONTIG
+ */
+
+isc_result_t
+isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target);
+/*%<
+ * Append a text representation of 'sockaddr' to the buffer 'target'.
+ * The text is NOT null terminated. Handles IPv4 and IPv6 addresses.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOSPACE The text or the null termination did not fit.
+ *\li #ISC_R_FAILURE Unspecified failure
+ */
+
+void
+isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the network address '*na'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+#define ISC_NETADDR_FORMATSIZE \
+ sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS")
+/*%<
+ * Minimum size of array to pass to isc_netaddr_format().
+ */
+
+void
+isc_netaddr_fromsockaddr(isc_netaddr_t *netaddr, const isc_sockaddr_t *source);
+
+void
+isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina);
+
+void
+isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6);
+
+isc_result_t
+isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path);
+
+void
+isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone);
+
+uint32_t
+isc_netaddr_getzone(const isc_netaddr_t *netaddr);
+
+void
+isc_netaddr_any(isc_netaddr_t *netaddr);
+/*%<
+ * Return the IPv4 wildcard address.
+ */
+
+void
+isc_netaddr_any6(isc_netaddr_t *netaddr);
+/*%<
+ * Return the IPv6 wildcard address.
+ */
+
+void
+isc_netaddr_unspec(isc_netaddr_t *netaddr);
+/*%<
+ * Initialize as AF_UNSPEC address.
+ */
+
+bool
+isc_netaddr_ismulticast(const isc_netaddr_t *na);
+/*%<
+ * Returns true if the address is a multicast address.
+ */
+
+bool
+isc_netaddr_isexperimental(const isc_netaddr_t *na);
+/*%<
+ * Returns true if the address is a experimental (CLASS E) address.
+ */
+
+bool
+isc_netaddr_islinklocal(const isc_netaddr_t *na);
+/*%<
+ * Returns #true if the address is a link local address.
+ */
+
+bool
+isc_netaddr_issitelocal(const isc_netaddr_t *na);
+/*%<
+ * Returns #true if the address is a site local address.
+ */
+
+bool
+isc_netaddr_isnetzero(const isc_netaddr_t *na);
+/*%<
+ * Returns #true if the address is in net zero.
+ */
+
+void
+isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s);
+/*%<
+ * Convert an IPv6 v4mapped address into an IPv4 address.
+ */
+
+isc_result_t
+isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen);
+/*
+ * Test whether the netaddr 'na' and 'prefixlen' are consistent.
+ * e.g. prefixlen within range.
+ * na does not have bits set which are not covered by the prefixlen.
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_RANGE prefixlen out of range
+ * ISC_R_NOTIMPLEMENTED unsupported family
+ * ISC_R_FAILURE extra bits.
+ */
+
+bool
+isc_netaddr_isloopback(const isc_netaddr_t *na);
+/*
+ * Test whether the netaddr 'na' is a loopback IPv4 or IPv6 address (in
+ * 127.0.0.0/8 or ::1).
+ */
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/netdb.h b/lib/isc/include/isc/netdb.h
new file mode 100644
index 0000000..93799d7
--- /dev/null
+++ b/lib/isc/include/isc/netdb.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ *\li No impact.
+ *
+ * Reliability:
+ *\li No anticipated impact.
+ *
+ * Resources:
+ *\li N/A.
+ *
+ * Security:
+ *\li No anticipated impact.
+ *
+ * Standards:
+ *\li BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <netdb.h>
+
+#include <isc/net.h>
diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h
new file mode 100644
index 0000000..eff33f6
--- /dev/null
+++ b/lib/isc/include/isc/netmgr.h
@@ -0,0 +1,811 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+
+#include <isc/mem.h>
+#include <isc/region.h>
+#include <isc/result.h>
+#include <isc/tls.h>
+#include <isc/types.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
+#define HAVE_SO_REUSEPORT_LB 1
+#endif
+
+/*
+ * Replacement for isc_sockettype_t provided by socket.h.
+ */
+typedef enum {
+ isc_socktype_tcp = 1,
+ isc_socktype_udp = 2,
+ isc_socktype_unix = 3,
+ isc_socktype_raw = 4
+} isc_socktype_t;
+
+typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *cbarg);
+/*%<
+ * Callback function to be used when receiving a packet.
+ *
+ * 'handle' the handle that can be used to send back the answer.
+ * 'eresult' the result of the event.
+ * 'region' contains the received data, if any. It will be freed
+ * after return by caller.
+ * 'cbarg' the callback argument passed to isc_nm_listenudp(),
+ * isc_nm_listentcpdns(), or isc_nm_read().
+ */
+typedef isc_result_t (*isc_nm_accept_cb_t)(isc_nmhandle_t *handle,
+ isc_result_t result, void *cbarg);
+/*%<
+ * Callback function to be used when accepting a connection. (This differs
+ * from isc_nm_cb_t below in that it returns a result code.)
+ *
+ * 'handle' the handle that can be used to send back the answer.
+ * 'eresult' the result of the event.
+ * 'cbarg' the callback argument passed to isc_nm_listentcp() or
+ * isc_nm_listentcpdns().
+ */
+
+typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
+ void *cbarg);
+/*%<
+ * Callback function for other network completion events (send, connect).
+ *
+ * 'handle' the handle on which the event took place.
+ * 'eresult' the result of the event.
+ * 'cbarg' the callback argument passed to isc_nm_send(),
+ * isc_nm_tcp_connect(), or isc_nm_listentcp()
+ */
+
+typedef void (*isc_nm_opaquecb_t)(void *arg);
+/*%<
+ * Opaque callback function, used for isc_nmhandle 'reset' and 'free'
+ * callbacks.
+ */
+
+typedef void (*isc_nm_workcb_t)(void *arg);
+typedef void (*isc_nm_after_workcb_t)(void *arg, isc_result_t result);
+/*%<
+ * Callback functions for libuv threadpool work (see uv_work_t)
+ */
+
+void
+isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst);
+void
+isc_nm_detach(isc_nm_t **mgr0);
+/*%<
+ * Attach/detach a network manager. When all references have been
+ * released, the network manager is shut down, freeing all resources.
+ * Destroy is working the same way as detach, but it actively waits
+ * for all other references to be gone.
+ */
+
+/* Return thread ID of current thread, or ISC_NETMGR_TID_UNKNOWN */
+int
+isc_nm_tid(void);
+
+void
+isc_nmsocket_close(isc_nmsocket_t **sockp);
+/*%<
+ * isc_nmsocket_close() detaches a listening socket that was
+ * created by isc_nm_listenudp(), isc_nm_listentcp(), or
+ * isc_nm_listentcpdns(). Once there are no remaining child
+ * sockets with active handles, the socket will be closed.
+ */
+
+void
+isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
+/*%<
+ * Asynchronously replace the TLS context within the listener socket object.
+ * The function is intended to be used during reconfiguration.
+ *
+ * Requires:
+ * \li 'listener' is a pointer to a valid network manager listener socket
+ object with TLS support;
+ * \li 'tlsctx' is a valid pointer to a TLS context object.
+ */
+
+void
+isc_nmsocket_set_max_streams(isc_nmsocket_t *listener,
+ const uint32_t max_streams);
+/*%<
+ * Set the maximum allowed number of concurrent streams for accepted
+ * client connections. The implementation might be asynchronous
+ * depending on the listener socket type.
+ *
+ * The call is a no-op for any listener socket type that does not
+ * support concept of multiple sessions per a client
+ * connection. Currently, it works only for HTTP/2 listeners.
+ *
+ * Setting 'max_streams' to '0' instructs the listener that there is
+ * no limit for concurrent streams.
+ *
+ * Requires:
+ * \li 'listener' is a pointer to a valid network manager listener socket.
+ */
+
+#ifdef NETMGR_TRACE
+#define isc_nmhandle_attach(handle, dest) \
+ isc__nmhandle_attach(handle, dest, __FILE__, __LINE__, __func__)
+#define isc_nmhandle_detach(handlep) \
+ isc__nmhandle_detach(handlep, __FILE__, __LINE__, __func__)
+#define FLARG , const char *file, unsigned int line, const char *func
+#else
+#define isc_nmhandle_attach(handle, dest) isc__nmhandle_attach(handle, dest)
+#define isc_nmhandle_detach(handlep) isc__nmhandle_detach(handlep)
+#define FLARG
+#endif
+
+void
+isc__nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **dest FLARG);
+void
+isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG);
+/*%<
+ * Increment/decrement the reference counter in a netmgr handle,
+ * but (unlike the attach/detach functions) do not change the pointer
+ * value. If reference counters drop to zero, the handle can be
+ * marked inactive, possibly triggering deletion of its associated
+ * socket.
+ *
+ * (This will be used to prevent a client from being cleaned up when
+ * it's passed to an isc_task event handler. The libuv code would not
+ * otherwise know that the handle was in use and might free it, along
+ * with the client.)
+ */
+#undef FLARG
+
+void *
+isc_nmhandle_getdata(isc_nmhandle_t *handle);
+
+void *
+isc_nmhandle_getextra(isc_nmhandle_t *handle);
+
+bool
+isc_nmhandle_is_stream(isc_nmhandle_t *handle);
+
+void
+isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg,
+ isc_nm_opaquecb_t doreset, isc_nm_opaquecb_t dofree);
+/*%<
+ * isc_nmhandle_t has a void* opaque field (for example, ns_client_t).
+ * We reuse handle and `opaque` can also be reused between calls.
+ * This function sets this field and two callbacks:
+ * - doreset resets the `opaque` to initial state
+ * - dofree frees everything associated with `opaque`
+ */
+
+void
+isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
+void
+isc_nmhandle_cleartimeout(isc_nmhandle_t *handle);
+/*%<
+ * Set/clear the read/recv timeout for the socket connected to 'handle'
+ * to 'timeout' (in milliseconds), and reset the timer.
+ *
+ * When this is called on a 'wrapper' socket handle (for example,
+ * a TCPDNS socket wrapping a TCP connection), the timer is set for
+ * both socket layers.
+ */
+bool
+isc_nmhandle_timer_running(isc_nmhandle_t *handle);
+/*%<
+ * Return true if the timer for the socket connected to 'handle'
+ * is running.
+ */
+
+void
+isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value);
+/*%<
+ * Enable/disable keepalive on this connection by setting it to 'value'.
+ *
+ * When keepalive is active, we switch to using the keepalive timeout
+ * to determine when to close a connection, rather than the idle timeout.
+ *
+ * This applies only to TCP-based DNS connections (i.e., TCPDNS or
+ * TLSDNS). On other types of connection it has no effect.
+ */
+
+isc_sockaddr_t
+isc_nmhandle_peeraddr(isc_nmhandle_t *handle);
+/*%<
+ * Return the peer address for the given handle.
+ */
+isc_sockaddr_t
+isc_nmhandle_localaddr(isc_nmhandle_t *handle);
+/*%<
+ * Return the local address for the given handle.
+ */
+
+isc_nm_t *
+isc_nmhandle_netmgr(isc_nmhandle_t *handle);
+/*%<
+ * Return a pointer to the netmgr object for the given handle.
+ */
+
+isc_result_t
+isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
+ void *cbarg, size_t extrasize, isc_nmsocket_t **sockp);
+/*%<
+ * Start listening for UDP packets on interface 'iface' using net manager
+ * 'mgr'.
+ *
+ * On success, 'sockp' will be updated to contain a new listening UDP socket.
+ *
+ * When a packet is received on the socket, 'cb' will be called with 'cbarg'
+ * as its argument.
+ *
+ * When handles are allocated for the socket, 'extrasize' additional bytes
+ * can be allocated along with the handle for an associated object, which
+ * can then be freed automatically when the handle is destroyed.
+ */
+
+void
+isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
+ isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
+ size_t extrahandlesize);
+/*%<
+ * Open a UDP socket, bind to 'local' and connect to 'peer', and
+ * immediately call 'cb' with a handle so that the caller can begin
+ * sending packets over UDP.
+ *
+ * When handles are allocated for the socket, 'extrasize' additional bytes
+ * can be allocated along with the handle for an associated object, which
+ * can then be freed automatically when the handle is destroyed.
+ *
+ * 'timeout' specifies the timeout interval in milliseconds.
+ *
+ * The connected socket can only be accessed via the handle passed to
+ * 'cb'.
+ */
+
+isc_result_t
+isc_nm_routeconnect(isc_nm_t *mgr, isc_nm_cb_t cb, void *cbarg,
+ size_t extrahandlesize);
+/*%<
+ * Open a route/netlink socket and call 'cb', so the caller can be
+ * begin listening for interface changes. This behaves similarly to
+ * isc_nm_udpconnect().
+ *
+ * Returns ISC_R_NOTIMPLEMENTED on systems where route/netlink sockets
+ * are not supported.
+ */
+
+void
+isc_nm_stoplistening(isc_nmsocket_t *sock);
+/*%<
+ * Stop listening on socket 'sock'.
+ */
+
+void
+isc_nm_pause(isc_nm_t *mgr);
+/*%<
+ * Pause all processing, equivalent to taskmgr exclusive tasks.
+ * It won't return until all workers have been paused.
+ */
+
+void
+isc_nm_resume(isc_nm_t *mgr);
+/*%<
+ * Resume paused processing. It will return immediately after signalling
+ * workers to resume.
+ */
+
+void
+isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
+/*
+ * Begin (or continue) reading on the socket associated with 'handle', and
+ * update its recv callback to 'cb', which will be called as soon as there
+ * is data to process.
+ */
+
+void
+isc_nm_pauseread(isc_nmhandle_t *handle);
+/*%<
+ * Pause reading on this handle's socket, but remember the callback.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle.
+ */
+
+void
+isc_nm_cancelread(isc_nmhandle_t *handle);
+/*%<
+ * Cancel reading on a connected socket. Calls the read/recv callback on
+ * active handles with a result code of ISC_R_CANCELED.
+ *
+ * Requires:
+ * \li 'sock' is a valid netmgr socket
+ * \li ...for which a read/recv callback has been defined.
+ */
+
+void
+isc_nm_resumeread(isc_nmhandle_t *handle);
+/*%<
+ * Resume reading on the handle's socket.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle.
+ * \li ...for a socket with a defined read/recv callback.
+ */
+
+void
+isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
+ void *cbarg);
+/*%<
+ * Send the data in 'region' via 'handle'. Afterward, the callback 'cb' is
+ * called with the argument 'cbarg'.
+ *
+ * 'region' is not copied; it has to be allocated beforehand and freed
+ * in 'cb'.
+ */
+
+isc_result_t
+isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface,
+ isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_nmsocket_t **sockp);
+/*%<
+ * Start listening for raw messages over the TCP interface 'iface', using
+ * net manager 'mgr'.
+ *
+ * On success, 'sockp' will be updated to contain a new listening TCP
+ * socket.
+ *
+ * When connection is accepted on the socket, 'accept_cb' will be called with
+ * 'accept_cbarg' as its argument. The callback is expected to start a read.
+ *
+ * When handles are allocated for the socket, 'extrasize' additional bytes
+ * will be allocated along with the handle for an associated object.
+ *
+ * If 'quota' is not NULL, then the socket is attached to the specified
+ * quota. This allows us to enforce TCP client quota limits.
+ *
+ */
+
+void
+isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
+ isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
+ size_t extrahandlesize);
+/*%<
+ * Create a socket using netmgr 'mgr', bind it to the address 'local',
+ * and connect it to the address 'peer'.
+ *
+ * When the connection is complete or has timed out, call 'cb' with
+ * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
+ * with the handle to use for an associated object.
+ *
+ * 'timeout' specifies the timeout interval in milliseconds.
+ *
+ * The connected socket can only be accessed via the handle passed to
+ * 'cb'.
+ */
+
+isc_result_t
+isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
+ isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
+ isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_nmsocket_t **sockp);
+/*%<
+ * Start listening for DNS messages over the TCP interface 'iface', using
+ * net manager 'mgr'.
+ *
+ * On success, 'sockp' will be updated to contain a new listening TCPDNS
+ * socket. This is a wrapper around a raw TCP socket, which sends and
+ * receives DNS messages via that socket. It handles message buffering
+ * and pipelining, and automatically prepends messages with a two-byte
+ * length field.
+ *
+ * When a complete DNS message is received on the socket, 'cb' will be
+ * called with 'cbarg' as its argument.
+ *
+ * When a new TCPDNS connection is accepted, 'accept_cb' will be called
+ * with 'accept_cbarg' as its argument.
+ *
+ * When handles are allocated for the socket, 'extrasize' additional bytes
+ * will be allocated along with the handle for an associated object
+ * (typically ns_client).
+ *
+ * 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
+ */
+
+isc_result_t
+isc_nm_listentlsdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
+ isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
+ isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);
+/*%<
+ * Same as isc_nm_listentcpdns but for an SSL (DoT) socket.
+ */
+
+void
+isc_nm_sequential(isc_nmhandle_t *handle);
+/*%<
+ * Disable pipelining on this connection. Each DNS packet will be only
+ * processed after the previous completes.
+ *
+ * The socket must be unpaused after the query is processed. This is done
+ * the response is sent, or if we're dropping the query, it will be done
+ * when a handle is fully dereferenced by calling the socket's
+ * closehandle_cb callback.
+ *
+ * Note: This can only be run while a message is being processed; if it is
+ * run before any messages are read, no messages will be read.
+ *
+ * Also note: once this has been set, it cannot be reversed for a given
+ * connection.
+ */
+
+void
+isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
+ uint32_t keepalive, uint32_t advertised);
+/*%<
+ * Sets the initial, idle, and keepalive timeout values (in milliseconds) to use
+ * for TCP connections, and the timeout value to advertise in responses using
+ * the EDNS TCP Keepalive option (which should ordinarily be the same
+ * as 'keepalive'), in milliseconds.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr.
+ */
+
+void
+isc_nm_setnetbuffers(isc_nm_t *mgr, int32_t recv_tcp, int32_t send_tcp,
+ int32_t recv_udp, int32_t send_udp);
+/*%<
+ * If not 0, sets the SO_RCVBUF and SO_SNDBUF socket options for TCP and UDP
+ * respectively.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr.
+ */
+
+bool
+isc_nm_getloadbalancesockets(isc_nm_t *mgr);
+void
+isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled);
+/*%<
+ * Get and set value of load balancing of the sockets.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr.
+ */
+
+void
+isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
+ uint32_t *keepalive, uint32_t *advertised);
+/*%<
+ * Gets the initial, idle, keepalive, or advertised timeout values,
+ * in milliseconds.
+ *
+ * Any integer pointer parameter not set to NULL will be updated to
+ * contain the corresponding timeout value.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr.
+ */
+
+void
+isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
+/*%<
+ * Simulate a broken firewall that blocks UDP messages larger than a given
+ * size.
+ */
+
+void
+isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
+/*%<
+ * Set a socket statistics counter set 'stats' for 'mgr'.
+ *
+ * Requires:
+ *\li 'mgr' is valid and doesn't have stats already set.
+ *
+ *\li stats is a valid set of statistics counters supporting the
+ * full range of socket-related stats counter numbers.
+ */
+
+isc_result_t
+isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type);
+/*%<
+ * Check whether the specified address is available on the local system
+ * by opening a socket and immediately closing it.
+ *
+ * Requires:
+ *\li 'addr' is not NULL.
+ */
+
+void
+isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
+ isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
+ size_t extrahandlesize);
+void
+isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
+ isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
+ size_t extrahandlesize, isc_tlsctx_t *sslctx,
+ isc_tlsctx_client_session_cache_t *client_sess_cache);
+/*%<
+ * Establish a DNS client connection via a TCP or TLS connection, bound to
+ * the address 'local' and connected to the address 'peer'.
+ *
+ * When the connection is complete or has timed out, call 'cb' with
+ * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
+ * with the handle to use for an associated object.
+ *
+ * 'timeout' specifies the timeout interval in milliseconds.
+ *
+ * The connected socket can only be accessed via the handle passed to
+ * 'cb'.
+ */
+
+/*%<
+ * Returns 'true' iff 'handle' is associated with a socket of type
+ * 'isc_nm_tlsdnssocket'.
+ */
+
+bool
+isc_nm_is_http_handle(isc_nmhandle_t *handle);
+/*%<
+ * Returns 'true' iff 'handle' is associated with a socket of type
+ * 'isc_nm_httpsocket'.
+ */
+
+#if HAVE_LIBNGHTTP2
+
+#define ISC_NM_HTTP_DEFAULT_PATH "/dns-query"
+
+isc_result_t
+isc_nm_listentls(isc_nm_t *mgr, isc_sockaddr_t *iface,
+ isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);
+
+void
+isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
+ isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx,
+ isc_tlsctx_client_session_cache_t *client_sess_cache,
+ unsigned int timeout, size_t extrahandlesize);
+
+void
+isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
+ const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
+ isc_tlsctx_t *ctx,
+ isc_tlsctx_client_session_cache_t *client_sess_cache,
+ unsigned int timeout, size_t extrahandlesize);
+
+isc_result_t
+isc_nm_listenhttp(isc_nm_t *mgr, isc_sockaddr_t *iface, int backlog,
+ isc_quota_t *quota, isc_tlsctx_t *ctx,
+ isc_nm_http_endpoints_t *eps, uint32_t max_concurrent_streams,
+ isc_nmsocket_t **sockp);
+
+isc_nm_http_endpoints_t *
+isc_nm_http_endpoints_new(isc_mem_t *mctx);
+/*%<
+ * Create a new, empty HTTP endpoints set object.
+ *
+ * Requires:
+ * \li 'mctx' a valid memory context object.
+ */
+
+isc_result_t
+isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps,
+ const char *uri, const isc_nm_recv_cb_t cb,
+ void *cbarg, const size_t extrahandlesize);
+/*%< Adds a new endpoint to the given HTTP endpoints set object.
+ *
+ * NOTE: adding an endpoint is allowed only if the endpoint object has
+ * not been passed to isc_nm_listenhttp() yet.
+ *
+ * Requires:
+ * \li 'eps' is a valid pointer to a valid isc_nm_http_endpoints_t
+ * object;
+ * \li 'uri' is a valid pointer to a string of length > 0;
+ * \li 'cb' is a valid pointer to a read callback function.
+ */
+
+void
+isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t *source,
+ isc_nm_http_endpoints_t **targetp);
+/*%<
+ * Attaches to an HTTP endpoints set object.
+ *
+ * Requires:
+ * \li 'source' is a non-NULL pointer to a valid
+ * isc_nm_http_endpoints_t object;
+ * \li 'target' is a pointer to a pointer, containing NULL.
+ */
+
+void
+isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp);
+/*%<
+ * Detaches from an HTTP endpoints set object. When reference count
+ * reaches 0, the object get deleted.
+ *
+ * Requires:
+ * \li 'epsp' is a pointer to a pointer to a valid
+ * isc_nm_http_endpoints_t object.
+ */
+
+bool
+isc_nm_http_path_isvalid(const char *path);
+/*%<
+ * Returns 'true' if 'path' matches the format requirements for
+ * the path component of a URI as defined in RFC 3986 section 3.3.
+ */
+
+void
+isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa,
+ const char *hostname, const uint16_t http_port,
+ const char *abs_path, char *outbuf,
+ const size_t outbuf_len);
+/*%<
+ * Makes a URI connection string out of na isc_sockaddr_t object 'sa'
+ * or the specified 'hostname' and 'http_port'.
+ *
+ * Requires:
+ * \li 'abs_path' is a valid absolute HTTP path string;
+ * \li 'outbuf' is a valid pointer to a buffer which will get the result;
+ * \li 'outbuf_len' is a size of the result buffer and is greater than zero.
+ */
+
+void
+isc_nm_http_set_endpoints(isc_nmsocket_t *listener,
+ isc_nm_http_endpoints_t *eps);
+/*%<
+ * Asynchronously replace the set of HTTP endpoints (paths) within
+ * the listener socket object. The function is intended to be used
+ * during reconfiguration.
+ *
+ * Requires:
+ * \li 'listener' is a pointer to a valid network manager HTTP listener socket;
+ * \li 'eps' is a valid pointer to an HTTP endpoints set.
+ */
+
+#endif /* HAVE_LIBNGHTTP2 */
+
+void
+isc_nm_bad_request(isc_nmhandle_t *handle);
+/*%<
+ * Perform a transport protocol specific action on the handle in case of a
+ * bad/malformed incoming DNS message.
+ *
+ * NOTE: The function currently is no-op for any protocol except HTTP/2.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle object.
+ */
+
+isc_result_t
+isc_nm_xfr_checkperm(isc_nmhandle_t *handle);
+/*%<
+ * Check if it is permitted to do a zone transfer over the given handle.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS Success, permission check passed successfully
+ * \li #ISC_R_DOTALPNERROR No permission because of ALPN tag mismatch
+ * \li #ISC_R_NOPERM No permission because of other restrictions
+ * \li any other result indicates failure (i.e. no permission)
+ *
+ * Requires:
+ * \li 'handle' is a valid connection handle.
+ */
+
+void
+isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl);
+/*%<
+ * Set the minimal time to live from the server's response Answer
+ * section as a hint to the underlying transport.
+ *
+ * NOTE: The function currently is no-op for any protocol except HTTP/2.
+ *
+ * Requires:
+ *
+ * \li 'handle' is a valid netmgr handle object associated with an accepted
+ * connection.
+ */
+
+isc_nmsocket_type
+isc_nm_socket_type(const isc_nmhandle_t *handle);
+/*%<
+ * Returns the handle's underlying socket type.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle object.
+ */
+
+bool
+isc_nm_has_encryption(const isc_nmhandle_t *handle);
+/*%<
+ * Returns 'true' iff the handle's underlying transport does encryption.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle object.
+ */
+
+const char *
+isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
+/*%<
+ * Returns user-readable message describing TLS peer's certificate
+ * validation result. Returns 'NULL' for the transport handles for
+ * which peer verification was not performed.
+ *
+ * Requires:
+ * \li 'handle' is a valid netmgr handle object.
+ */
+
+void
+isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid);
+/*%<
+ * Enqueue the 'task' onto the netmgr ievents queue.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr object
+ * \li 'task' is a valid task
+ * \li 'threadid' is either the preferred netmgr tid or -1, in which case
+ * tid will be picked randomly. The threadid is capped (by modulo) to
+ * maximum number of 'workers' as specifed in isc_nm_start()
+ */
+
+void
+isc_nm_work_offload(isc_nm_t *mgr, isc_nm_workcb_t work_cb,
+ isc_nm_after_workcb_t after_work_cb, void *data);
+/*%<
+ * Schedules a job to be handled by the libuv thread pool (see uv_work_t).
+ * The function specified in `work_cb` will be run by a thread in the
+ * thread pool; when complete, the `after_work_cb` function will run.
+ *
+ * Requires:
+ * \li 'mgr' is a valid netmgr object.
+ * \li We are currently running in a network manager thread.
+ */
+
+void
+isc__nm_force_tid(int tid);
+/*%<
+ * Force the thread ID to 'tid'. This is STRICTLY for use in unit
+ * tests and should not be used in any production code.
+ */
+
+void
+isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout);
+
+/*
+ * Timer related functions
+ */
+
+typedef struct isc_nm_timer isc_nm_timer_t;
+
+typedef void (*isc_nm_timer_cb)(void *, isc_result_t);
+
+void
+isc_nm_timer_create(isc_nmhandle_t *, isc_nm_timer_cb, void *,
+ isc_nm_timer_t **);
+
+void
+isc_nm_timer_attach(isc_nm_timer_t *, isc_nm_timer_t **);
+
+void
+isc_nm_timer_detach(isc_nm_timer_t **);
+
+void
+isc_nm_timer_start(isc_nm_timer_t *, uint64_t);
+
+void
+isc_nm_timer_stop(isc_nm_timer_t *);
diff --git a/lib/isc/include/isc/netscope.h b/lib/isc/include/isc/netscope.h
new file mode 100644
index 0000000..307864a
--- /dev/null
+++ b/lib/isc/include/isc/netscope.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/netscope.h */
+
+#include <inttypes.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%
+ * Convert a string of an IPv6 scope zone to zone index. If the conversion
+ * succeeds, 'zoneid' will store the index value.
+ *
+ * XXXJT: when a standard interface for this purpose is defined,
+ * we should use it.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS: conversion succeeds
+ * \li ISC_R_FAILURE: conversion fails
+ */
+isc_result_t
+isc_netscope_pton(int af, char *scopename, void *addr, uint32_t *zoneid);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/nonce.h b/lib/isc/include/isc/nonce.h
new file mode 100644
index 0000000..b593e41
--- /dev/null
+++ b/lib/isc/include/isc/nonce.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+
+#include <isc/lang.h>
+
+/*! \file isc/nonce.h
+ * \brief Provides a function for generating an arbitrarily long nonce.
+ */
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_nonce_buf(void *buf, size_t buflen);
+/*!<
+ * Fill 'buf', up to 'buflen' bytes, with random data from the
+ * crypto provider's random function.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/offset.h b/lib/isc/include/isc/offset.h
new file mode 100644
index 0000000..2b62e2a
--- /dev/null
+++ b/lib/isc/include/isc/offset.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file
+ * \brief
+ * File offsets are operating-system dependent.
+ */
+#include <limits.h> /* Required for CHAR_BIT. */
+#include <stddef.h> /* For Linux Standard Base. */
+
+#include <sys/types.h>
+
+typedef off_t isc_offset_t;
diff --git a/lib/isc/include/isc/once.h b/lib/isc/include/isc/once.h
new file mode 100644
index 0000000..7d341ca
--- /dev/null
+++ b/lib/isc/include/isc/once.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <pthread.h>
+
+#include <isc/result.h>
+
+typedef pthread_once_t isc_once_t;
+
+#define ISC_ONCE_INIT PTHREAD_ONCE_INIT
+
+/* XXX We could do fancier error handling... */
+
+#define isc_once_do(op, f) \
+ ((pthread_once((op), (f)) == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED)
diff --git a/lib/isc/include/isc/os.h b/lib/isc/include/isc/os.h
new file mode 100644
index 0000000..fd7e5cf
--- /dev/null
+++ b/lib/isc/include/isc/os.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/os.h */
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <sys/stat.h>
+
+ISC_LANG_BEGINDECLS
+
+/*%<
+ * Hardcode the L1 cacheline size of the CPU to 64, this is checked in
+ * the os.c library constructor if operating system provide means to
+ * get the L1 cacheline size using sysconf().
+ */
+#define ISC_OS_CACHELINE_SIZE 64
+
+unsigned int
+isc_os_ncpus(void);
+/*%<
+ * Return the number of CPUs available on the system, or 1 if this cannot
+ * be determined.
+ */
+
+unsigned long
+isc_os_cacheline(void);
+/*%<
+ * Return L1 cacheline size of the CPU.
+ * If L1 cache is greater than ISC_OS_CACHELINE_SIZE, ensure it is used
+ * instead of constant. Is common on ppc64le architecture.
+ */
+
+mode_t
+isc_os_umask(void);
+/*%<
+ * Return umask of the current process as initialized at the program start
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/parseint.h b/lib/isc/include/isc/parseint.h
new file mode 100644
index 0000000..aa54772
--- /dev/null
+++ b/lib/isc/include/isc/parseint.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/parseint.h
+ * \brief Parse integers, in a saner way than atoi() or strtoul() do.
+ */
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_parse_uint32(uint32_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint16(uint16_t *uip, const char *string, int base);
+
+isc_result_t
+isc_parse_uint8(uint8_t *uip, const char *string, int base);
+/*%<
+ * Parse the null-terminated string 'string' containing a base 'base'
+ * integer, storing the result in '*uip'.
+ * The base is interpreted
+ * as in strtoul(). Unlike strtoul(), leading whitespace, minus or
+ * plus signs are not accepted, and all errors (including overflow)
+ * are reported uniformly through the return value.
+ *
+ * Requires:
+ *\li 'string' points to a null-terminated string
+ *\li 0 <= 'base' <= 36
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_BADNUMBER The string is not numeric (in the given base)
+ *\li #ISC_R_RANGE The number is not representable as the requested type.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/pool.h b/lib/isc/include/isc/pool.h
new file mode 100644
index 0000000..90b8934
--- /dev/null
+++ b/lib/isc/include/isc/pool.h
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/pool.h
+ * \brief An object pool is a mechanism for sharing a small pool of
+ * fungible objects among a large number of objects that depend on them.
+ *
+ * This is useful, for example, when it causes performance problems for
+ * large number of zones to share a single memory context or task object,
+ * but it would create a different set of problems for them each to have an
+ * independent task or memory context.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+***** Types.
+*****/
+
+typedef void (*isc_pooldeallocator_t)(void **object);
+
+typedef isc_result_t (*isc_poolinitializer_t)(void **target, void *arg);
+
+typedef struct isc_pool isc_pool_t;
+
+/*****
+***** Functions.
+*****/
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count, isc_pooldeallocator_t free,
+ isc_poolinitializer_t init, void *initarg, isc_pool_t **poolp);
+/*%<
+ * Create a pool of "count" object pointers. If 'free' is not NULL,
+ * it points to a function that will detach the objects. 'init'
+ * points to a function that will initialize the arguments, and
+ * 'arg' to an argument to be passed into that function (for example,
+ * a relevant manager or context object).
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li init != NULL
+ *
+ *\li poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*poolp' points to the new object pool.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void *
+isc_pool_get(isc_pool_t *pool);
+/*%<
+ * Returns a pointer to an object from the pool. Currently the object
+ * is chosen from the pool at random. (This may be changed in the future
+ * to something that guaratees balance.)
+ */
+
+int
+isc_pool_count(isc_pool_t *pool);
+/*%<
+ * Returns the number of objcts in the pool 'pool'.
+ */
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count, isc_pool_t **targetp);
+
+/*%<
+ * If 'size' is larger than the number of objects in the pool pointed to by
+ * 'sourcep', then a new pool of size 'count' is allocated, the existing
+ * objects are copied into it, additional ones created to bring the
+ * total number up to 'count', and the resulting pool is attached to
+ * 'targetp'.
+ *
+ * If 'count' is less than or equal to the number of objects in 'source', then
+ * 'sourcep' is attached to 'targetp' without any other action being taken.
+ *
+ * In either case, 'sourcep' is detached.
+ *
+ * Requires:
+ *
+ * \li 'sourcep' is not NULL and '*source' is not NULL
+ * \li 'targetp' is not NULL and '*source' is NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*targetp' points to a valid task pool.
+ * \li On success, '*sourcep' points to NULL.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+void
+isc_pool_destroy(isc_pool_t **poolp);
+/*%<
+ * Destroy a task pool. The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/portset.h b/lib/isc/include/isc/portset.h
new file mode 100644
index 0000000..fa5d51e
--- /dev/null
+++ b/lib/isc/include/isc/portset.h
@@ -0,0 +1,135 @@
+/*
+ * 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 isc/portset.h
+ * \brief Transport Protocol Port Manipulation Module
+ *
+ * This module provides simple utilities to handle a set of transport protocol
+ * (UDP or TCP) port numbers, e.g., for creating an ACL list. An isc_portset_t
+ * object is an opaque instance of a port set, for which the user can add or
+ * remove a specific port or a range of consecutive ports. This object is
+ * expected to be used as a temporary work space only, and does not protect
+ * simultaneous access from multiple threads. Therefore it must not be stored
+ * in a place that can be accessed from multiple threads.
+ */
+
+#pragma once
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/net.h>
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp);
+/*%<
+ * Create a port set and initialize it as an empty set.
+ *
+ * Requires:
+ *\li 'mctx' to be valid.
+ *\li 'portsetp' to be non NULL and '*portsetp' to be NULL;
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ */
+
+void
+isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp);
+/*%<
+ * Destroy a port set.
+ *
+ * Requires:
+ *\li 'mctx' to be valid and must be the same context given when the port set
+ * was created.
+ *\li '*portsetp' to be a valid set.
+ */
+
+bool
+isc_portset_isset(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Test whether the given port is stored in the portset.
+ *
+ * Requires:
+ *\li 'portset' to be a valid set.
+ *
+ * Returns
+ * \li #true if the port is found, false otherwise.
+ */
+
+unsigned int
+isc_portset_nports(isc_portset_t *portset);
+/*%<
+ * Provides the number of ports stored in the given portset.
+ *
+ * Requires:
+ *\li 'portset' to be a valid set.
+ *
+ * Returns
+ * \li the number of ports stored in portset.
+ */
+
+void
+isc_portset_add(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Add the given port to the portset. The port may or may not be stored in
+ * the portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ */
+
+void
+isc_portset_remove(isc_portset_t *portset, in_port_t port);
+/*%<
+ * Remove the given port to the portset. The port may or may not be stored in
+ * the portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ */
+
+void
+isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
+ in_port_t port_hi);
+/*%<
+ * Add a subset of [port_lo, port_hi] (inclusive) to the portset. Ports in the
+ * subset may or may not be stored in portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li port_lo <= port_hi
+ */
+
+void
+isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
+ in_port_t port_hi);
+/*%<
+ * Subtract a subset of [port_lo, port_hi] (inclusive) from the portset. Ports
+ * in the subset may or may not be stored in portset.
+ *
+ * Requires:
+ *\li 'portlist' to be valid.
+ *\li port_lo <= port_hi
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/print.h b/lib/isc/include/isc/print.h
new file mode 100644
index 0000000..d48bf70
--- /dev/null
+++ b/lib/isc/include/isc/print.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/print.h */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/formatcheck.h> /* Required for ISC_FORMAT_PRINTF() macro. */
+#include <isc/lang.h>
+
+/***
+ *** Functions
+ ***/
+
+#include <stdio.h>
diff --git a/lib/isc/include/isc/quota.h b/lib/isc/include/isc/quota.h
new file mode 100644
index 0000000..2a25fa1
--- /dev/null
+++ b/lib/isc/include/isc/quota.h
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/quota.h
+ *
+ * \brief The isc_quota_t object is a simple helper object for implementing
+ * quotas on things like the number of simultaneous connections to
+ * a server. It keeps track of the amount of quota in use, and
+ * encapsulates the locking necessary to allow multiple tasks to
+ * share a quota.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/atomic.h>
+#include <isc/lang.h>
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+***** Types.
+*****/
+
+ISC_LANG_BEGINDECLS
+
+/*% isc_quota_cb - quota callback structure */
+typedef struct isc_quota_cb isc_quota_cb_t;
+typedef void (*isc_quota_cb_func_t)(isc_quota_t *quota, void *data);
+struct isc_quota_cb {
+ int magic;
+ isc_quota_cb_func_t cb_func;
+ void *data;
+ ISC_LINK(isc_quota_cb_t) link;
+};
+
+/*% isc_quota structure */
+struct isc_quota {
+ int magic;
+ atomic_uint_fast32_t max;
+ atomic_uint_fast32_t used;
+ atomic_uint_fast32_t soft;
+ atomic_uint_fast32_t waiting;
+ isc_mutex_t cblock;
+ ISC_LIST(isc_quota_cb_t) cbs;
+ ISC_LINK(isc_quota_t) link;
+};
+
+void
+isc_quota_init(isc_quota_t *quota, unsigned int max);
+/*%<
+ * Initialize a quota object.
+ */
+
+void
+isc_quota_destroy(isc_quota_t *quota);
+/*%<
+ * Destroy a quota object.
+ */
+
+void
+isc_quota_soft(isc_quota_t *quota, unsigned int soft);
+/*%<
+ * Set a soft quota.
+ */
+
+void
+isc_quota_max(isc_quota_t *quota, unsigned int max);
+/*%<
+ * Re-set a maximum quota.
+ */
+
+unsigned int
+isc_quota_getmax(isc_quota_t *quota);
+/*%<
+ * Get the maximum quota.
+ */
+
+unsigned int
+isc_quota_getsoft(isc_quota_t *quota);
+/*%<
+ * Get the soft quota.
+ */
+
+unsigned int
+isc_quota_getused(isc_quota_t *quota);
+/*%<
+ * Get the current usage of quota.
+ */
+
+isc_result_t
+isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
+/*%<
+ *
+ * Attempt to reserve one unit of 'quota', and also attaches '*p' to the quota
+ * if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS Success
+ * \li #ISC_R_SOFTQUOTA Success soft quota reached
+ * \li #ISC_R_QUOTA Quota is full
+ */
+
+isc_result_t
+isc_quota_attach_cb(isc_quota_t *quota, isc_quota_t **p, isc_quota_cb_t *cb);
+/*%<
+ *
+ * Like isc_quota_attach(), but if there's no quota left then cb->cb_func will
+ * be called when we are attached to quota.
+ *
+ * Note: It's the caller's responsibility to make sure that we don't end up
+ * with a huge number of callbacks waiting, making it easy to create a
+ * resource exhaustion attack. For example, in the case of TCP listening,
+ * we simply don't accept new connections when the quota is exceeded, so
+ * the number of callbacks waiting in the queue will be limited by the
+ * listen() backlog.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS Success
+ * \li #ISC_R_SOFTQUOTA Success soft quota reached
+ * \li #ISC_R_QUOTA Quota is full
+ */
+
+void
+isc_quota_cb_init(isc_quota_cb_t *cb, isc_quota_cb_func_t cb_func, void *data);
+/*%<
+ * Initialize isc_quota_cb_t - setup the list, set the callback and data.
+ */
+
+void
+isc_quota_detach(isc_quota_t **p);
+/*%<
+ * Release one unit of quota, and also detaches '*p' from the quota.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h
new file mode 100644
index 0000000..9a91118
--- /dev/null
+++ b/lib/isc/include/isc/radix.h
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <isc/magic.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/refcount.h>
+#include <isc/types.h>
+
+#define NETADDR_TO_PREFIX_T(na, pt, bits) \
+ do { \
+ const void *p = na; \
+ memset(&(pt), 0, sizeof(pt)); \
+ if (p != NULL) { \
+ (pt).family = (na)->family; \
+ (pt).bitlen = (bits); \
+ if ((pt).family == AF_INET6) { \
+ memmove(&(pt).add.sin6, &(na)->type.in6, \
+ ((bits) + 7) / 8); \
+ } else \
+ memmove(&(pt).add.sin, &(na)->type.in, \
+ ((bits) + 7) / 8); \
+ } else { \
+ (pt).family = AF_UNSPEC; \
+ (pt).bitlen = 0; \
+ } \
+ isc_refcount_init(&(pt).refcount, 0); \
+ } while (0)
+
+typedef struct isc_prefix {
+ isc_mem_t *mctx;
+ unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for
+ * "any" */
+ unsigned int bitlen; /* 0 for "any" */
+ isc_refcount_t refcount;
+ union {
+ struct in_addr sin;
+ struct in6_addr sin6;
+ } add;
+} isc_prefix_t;
+
+typedef void (*isc_radix_destroyfunc_t)(void *);
+typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **);
+
+#define isc_prefix_tochar(prefix) ((char *)&(prefix)->add.sin)
+#define isc_prefix_touchar(prefix) ((u_char *)&(prefix)->add.sin)
+
+/*
+ * We need "first match" when we search the radix tree to preserve
+ * compatibility with the existing ACL implementation. Radix trees
+ * naturally lend themselves to "best match". In order to get "first match"
+ * behavior, we keep track of the order in which entries are added to the
+ * tree--and when a search is made, we find all matching entries, and
+ * return the one that was added first.
+ *
+ * An IPv4 prefix and an IPv6 prefix may share a radix tree node if they
+ * have the same length and bit pattern (e.g., 127/8 and 7f::/8). To
+ * disambiguate between them, node_num and data are two-element arrays:
+ *
+ * - node_num[0] and data[0] are used for IPv4 client addresses
+ * - node_num[1] and data[1] are used for IPv6 client addresses
+ *
+ * A prefix of 0/0 (aka "any" or "none"), is always stored as IPv4,
+ * but matches all IPv6 addresses too.
+ */
+
+#define RADIX_V4 0
+#define RADIX_V6 1
+#define RADIX_FAMILIES 2
+
+#define ISC_RADIX_FAMILY(p) (((p)->family == AF_INET6) ? RADIX_V6 : RADIX_V4)
+
+typedef struct isc_radix_node {
+ isc_mem_t *mctx;
+ uint32_t bit; /* bit length of the prefix */
+ isc_prefix_t *prefix; /* who we are in radix tree */
+ struct isc_radix_node *l, *r; /* left and right children */
+ struct isc_radix_node *parent; /* may be used */
+ void *data[RADIX_FAMILIES]; /* pointers to IPv4
+ * and IPV6 data */
+ int node_num[RADIX_FAMILIES]; /* which node
+ * this was in
+ * the tree,
+ * or -1 for glue
+ * nodes */
+} isc_radix_node_t;
+
+#define RADIX_TREE_MAGIC ISC_MAGIC('R', 'd', 'x', 'T');
+#define RADIX_TREE_VALID(a) ISC_MAGIC_VALID(a, RADIX_TREE_MAGIC);
+
+typedef struct isc_radix_tree {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_radix_node_t *head;
+ uint32_t maxbits; /* for IP, 32 bit addresses */
+ int num_active_node; /* for debugging purposes */
+ int num_added_node; /* total number of nodes */
+} isc_radix_tree_t;
+
+isc_result_t
+isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target,
+ isc_prefix_t *prefix);
+/*%<
+ * Search 'radix' for the best match to 'prefix'.
+ * Return the node found in '*target'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'target' is not NULL and "*target" is NULL.
+ * \li 'prefix' to be valid.
+ *
+ * Returns:
+ * \li ISC_R_NOTFOUND
+ * \li ISC_R_SUCCESS
+ */
+
+isc_result_t
+isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
+ isc_radix_node_t *source, isc_prefix_t *prefix);
+/*%<
+ * Insert 'source' or 'prefix' into the radix tree 'radix'.
+ * Return the node added in 'target'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'target' is not NULL and "*target" is NULL.
+ * \li 'prefix' to be valid or 'source' to be non NULL and contain
+ * a valid prefix.
+ *
+ * Returns:
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node);
+/*%<
+ * Remove the node 'node' from the radix tree 'radix'.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'node' to be valid.
+ */
+
+isc_result_t
+isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits);
+/*%<
+ * Create a radix tree with a maximum depth of 'maxbits';
+ *
+ * Requires:
+ * \li 'mctx' to be valid.
+ * \li 'target' to be non NULL and '*target' to be NULL.
+ * \li 'maxbits' to be less than or equal to RADIX_MAXBITS.
+ *
+ * Returns:
+ * \li ISC_R_NOMEMORY
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func);
+/*%<
+ * Destroy a radix tree optionally calling 'func' to clean up node data.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ */
+
+void
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func);
+/*%<
+ * Walk a radix tree calling 'func' to process node data.
+ *
+ * Requires:
+ * \li 'radix' to be valid.
+ * \li 'func' to point to a function.
+ */
+
+#define RADIX_MAXBITS 128
+#define RADIX_NBIT(x) (0x80 >> ((x)&0x7f))
+#define RADIX_NBYTE(x) ((x) >> 3)
+
+#define RADIX_WALK(Xhead, Xnode) \
+ do { \
+ isc_radix_node_t *Xstack[RADIX_MAXBITS + 1]; \
+ isc_radix_node_t **Xsp = Xstack; \
+ isc_radix_node_t *Xrn = (Xhead); \
+ while ((Xnode = Xrn)) { \
+ if (Xnode->prefix)
+
+#define RADIX_WALK_END \
+ if (Xrn->l) { \
+ if (Xrn->r) { \
+ *Xsp++ = Xrn->r; \
+ } \
+ Xrn = Xrn->l; \
+ } else if (Xrn->r) { \
+ Xrn = Xrn->r; \
+ } else if (Xsp != Xstack) { \
+ Xrn = *(--Xsp); \
+ } else { \
+ Xrn = (isc_radix_node_t *)0; \
+ } \
+ } \
+ } \
+ while (0)
diff --git a/lib/isc/include/isc/random.h b/lib/isc/include/isc/random.h
new file mode 100644
index 0000000..1e30d0c
--- /dev/null
+++ b/lib/isc/include/isc/random.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/random.h
+ * \brief Implements wrapper around a non-cryptographically secure
+ * pseudo-random number generator.
+ *
+ */
+
+ISC_LANG_BEGINDECLS
+
+uint8_t
+isc_random8(void);
+/*!<
+ * \brief Returns a single 8-bit random value.
+ */
+
+uint16_t
+isc_random16(void);
+/*!<
+ * \brief Returns a single 16-bit random value.
+ */
+
+uint32_t
+isc_random32(void);
+/*!<
+ * \brief Returns a single 32-bit random value.
+ */
+
+void
+isc_random_buf(void *buf, size_t buflen);
+/*!<
+ * \brief Fills the region buf of length buflen with random data.
+ */
+
+uint32_t
+isc_random_uniform(uint32_t upper_bound);
+/*!<
+ * \brief Will return a single 32-bit value, uniformly distributed but
+ * less than upper_bound. This is recommended over
+ * constructions like ``isc_random() % upper_bound'' as it
+ * avoids "modulo bias" when the upper bound is not a power of
+ * two. In the worst case, this function may require multiple
+ * iterations to ensure uniformity.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h
new file mode 100644
index 0000000..45ec447
--- /dev/null
+++ b/lib/isc/include/isc/ratelimiter.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/ratelimiter.h
+ * \brief A rate limiter is a mechanism for dispatching events at a limited
+ * rate. This is intended to be used when sending zone maintenance
+ * SOA queries, NOTIFY messages, etc.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+***** Functions.
+*****/
+
+isc_result_t
+isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
+ isc_task_t *task, isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Create a rate limiter. The execution interval is initially undefined.
+ */
+
+isc_result_t
+isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval);
+/*!<
+ * Set the minimum interval between event executions.
+ * The interval value is copied, so the caller need not preserve it.
+ *
+ * Requires:
+ * '*interval' is a nonzero interval.
+ */
+
+void
+isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, uint32_t perint);
+/*%<
+ * Set the number of events processed per interval timer tick.
+ * If 'perint' is zero it is treated as 1.
+ */
+
+void
+isc_ratelimiter_setpushpop(isc_ratelimiter_t *rl, bool pushpop);
+/*%<
+ * Set / clear the ratelimiter to from push pop mode rather
+ * first in - first out mode (default).
+ */
+
+isc_result_t
+isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
+ isc_event_t **eventp);
+/*%<
+ * Queue an event for rate-limited execution.
+ *
+ * This is similar
+ * to doing an isc_task_send() to the 'task', except that the
+ * execution may be delayed to achieve the desired rate of
+ * execution.
+ *
+ * '(*eventp)->ev_sender' is used to hold the task. The caller
+ * must ensure that the task exists until the event is delivered.
+ *
+ * Requires:
+ *\li An interval has been set by calling
+ * isc_ratelimiter_setinterval().
+ *
+ *\li 'task' to be non NULL.
+ *\li '(*eventp)->ev_sender' to be NULL.
+ */
+
+isc_result_t
+isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event);
+/*
+ * Dequeue a event off the ratelimiter queue.
+ *
+ * Returns:
+ * \li ISC_R_NOTFOUND if the event is no longer linked to the rate limiter.
+ * \li ISC_R_SUCCESS
+ */
+
+void
+isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter);
+/*%<
+ * Shut down a rate limiter.
+ *
+ * Ensures:
+ *\li All events that have not yet been
+ * dispatched to the task are dispatched immediately with
+ * the #ISC_EVENTATTR_CANCELED bit set in ev_attributes.
+ *
+ *\li Further attempts to enqueue events will fail with
+ * #ISC_R_SHUTTINGDOWN.
+ *
+ *\li The rate limiter is no longer attached to its task.
+ */
+
+void
+isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target);
+/*%<
+ * Attach to a rate limiter.
+ */
+
+void
+isc_ratelimiter_detach(isc_ratelimiter_t **ratelimiterp);
+/*%<
+ * Detach from a rate limiter.
+ */
+
+isc_result_t
+isc_ratelimiter_stall(isc_ratelimiter_t *rl);
+/*%<
+ * Stall event processing.
+ */
+
+isc_result_t
+isc_ratelimiter_release(isc_ratelimiter_t *rl);
+/*%<
+ * Release a stalled rate limiter.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/refcount.h b/lib/isc/include/isc/refcount.h
new file mode 100644
index 0000000..6b1f7cd
--- /dev/null
+++ b/lib/isc/include/isc/refcount.h
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+#include <isc/assertions.h>
+#include <isc/atomic.h>
+#include <isc/error.h>
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*! \file isc/refcount.h
+ * \brief Implements a locked reference counter.
+ *
+ * These macros uses C11(-like) atomic functions to implement reference
+ * counting. The isc_refcount_t type must not be accessed directly.
+ */
+
+ISC_LANG_BEGINDECLS
+
+typedef atomic_uint_fast32_t isc_refcount_t;
+
+/** \def isc_refcount_init(ref, n)
+ * \brief Initialize the reference counter.
+ * \param[in] ref pointer to reference counter.
+ * \param[in] n an initial number of references.
+ * \return nothing.
+ *
+ * \warning No memory barrier are being imposed here.
+ */
+#define isc_refcount_init(target, value) atomic_init(target, value)
+
+/** \def isc_refcount_current(ref)
+ * \brief Returns current number of references.
+ * \param[in] ref pointer to reference counter.
+ * \returns current value of reference counter.
+ *
+ * Undo implicit promotion to 64 bits in our Windows implementation of
+ * atomic_load_explicit() by casting to uint_fast32_t.
+ */
+
+#define isc_refcount_current(target) (uint_fast32_t) atomic_load_acquire(target)
+
+/** \def isc_refcount_destroy(ref)
+ * \brief a destructor that makes sure that all references were cleared.
+ * \param[in] ref pointer to reference counter.
+ * \returns nothing.
+ */
+#define isc_refcount_destroy(target) \
+ ISC_REQUIRE(isc_refcount_current(target) == 0)
+
+/** \def isc_refcount_increment0(ref)
+ * \brief increases reference counter by 1.
+ * \param[in] ref pointer to reference counter.
+ * \returns previous value of reference counter.
+ */
+#if _MSC_VER
+static inline uint_fast32_t
+isc_refcount_increment0(isc_refcount_t *target) {
+ uint_fast32_t __v;
+ __v = (uint_fast32_t)atomic_fetch_add_relaxed(target, 1);
+ INSIST(__v < UINT32_MAX);
+ return (__v);
+}
+#else /* _MSC_VER */
+#define isc_refcount_increment0(target) \
+ ({ \
+ uint_fast32_t __v; \
+ __v = atomic_fetch_add_relaxed(target, 1); \
+ INSIST(__v < UINT32_MAX); \
+ __v; \
+ })
+#endif /* _MSC_VER */
+
+/** \def isc_refcount_increment(ref)
+ * \brief increases reference counter by 1.
+ * \param[in] ref pointer to reference counter.
+ * \returns previous value of reference counter.
+ */
+#if _MSC_VER
+static inline uint_fast32_t
+isc_refcount_increment(isc_refcount_t *target) {
+ uint_fast32_t __v;
+ __v = (uint_fast32_t)atomic_fetch_add_relaxed(target, 1);
+ INSIST(__v > 0 && __v < UINT32_MAX);
+ return (__v);
+}
+#else /* _MSC_VER */
+#define isc_refcount_increment(target) \
+ ({ \
+ uint_fast32_t __v; \
+ __v = atomic_fetch_add_relaxed(target, 1); \
+ INSIST(__v > 0 && __v < UINT32_MAX); \
+ __v; \
+ })
+#endif /* _MSC_VER */
+
+/** \def isc_refcount_decrement(ref)
+ * \brief decreases reference counter by 1.
+ * \param[in] ref pointer to reference counter.
+ * \returns previous value of reference counter.
+ */
+#if _MSC_VER
+static inline uint_fast32_t
+isc_refcount_decrement(isc_refcount_t *target) {
+ uint_fast32_t __v;
+ __v = (uint_fast32_t)atomic_fetch_sub_acq_rel(target, 1);
+ INSIST(__v > 0);
+ return (__v);
+}
+#else /* _MSC_VER */
+#define isc_refcount_decrement(target) \
+ ({ \
+ uint_fast32_t __v; \
+ __v = atomic_fetch_sub_acq_rel(target, 1); \
+ INSIST(__v > 0); \
+ __v; \
+ })
+#endif /* _MSC_VER */
+
+#define isc_refcount_decrementz(target) \
+ do { \
+ uint_fast32_t _refs = isc_refcount_decrement(target); \
+ ISC_INSIST(_refs == 1); \
+ } while (0)
+
+#define isc_refcount_decrement1(target) \
+ do { \
+ uint_fast32_t _refs = isc_refcount_decrement(target); \
+ ISC_INSIST(_refs > 1); \
+ } while (0)
+
+#define isc_refcount_decrement0(target) \
+ do { \
+ uint_fast32_t _refs = isc_refcount_decrement(target); \
+ ISC_INSIST(_refs > 0); \
+ } while (0)
+
+#define ISC_REFCOUNT_TRACE_DECL(name) \
+ name##_t *name##__ref(name##_t *ptr, const char *func, \
+ const char *file, unsigned int line); \
+ void name##__unref(name##_t *ptr, const char *func, const char *file, \
+ unsigned int line); \
+ void name##__attach(name##_t *ptr, name##_t **ptrp, const char *func, \
+ const char *file, unsigned int line); \
+ void name##__detach(name##_t **ptrp, const char *func, \
+ const char *file, unsigned int line)
+
+#define ISC_REFCOUNT_TRACE_IMPL(name, destroy) \
+ name##_t *name##__ref(name##_t *ptr, const char *func, \
+ const char *file, unsigned int line) { \
+ REQUIRE(ptr != NULL); \
+ uint_fast32_t refs = \
+ isc_refcount_increment(&ptr->references) + 1; \
+ fprintf(stderr, \
+ "%s:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", \
+ __func__, func, file, line, ptr, refs); \
+ return (ptr); \
+ } \
+ \
+ void name##__unref(name##_t *ptr, const char *func, const char *file, \
+ unsigned int line) { \
+ REQUIRE(ptr != NULL); \
+ uint_fast32_t refs = \
+ isc_refcount_decrement(&ptr->references) - 1; \
+ if (refs == 0) { \
+ destroy(ptr); \
+ } \
+ fprintf(stderr, \
+ "%s:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", \
+ __func__, func, file, line, ptr, refs); \
+ } \
+ void name##__attach(name##_t *ptr, name##_t **ptrp, const char *func, \
+ const char *file, unsigned int line) { \
+ REQUIRE(ptrp != NULL && *ptrp == NULL); \
+ uint_fast32_t refs = \
+ isc_refcount_increment(&ptr->references) + 1; \
+ fprintf(stderr, \
+ "%s:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", \
+ __func__, func, file, line, ptr, refs); \
+ *ptrp = ptr; \
+ } \
+ \
+ void name##__detach(name##_t **ptrp, const char *func, \
+ const char *file, unsigned int line) { \
+ REQUIRE(ptrp != NULL && *ptrp != NULL); \
+ name##_t *ptr = *ptrp; \
+ *ptrp = NULL; \
+ uint_fast32_t refs = \
+ isc_refcount_decrement(&ptr->references) - 1; \
+ if (refs == 0) { \
+ destroy(ptr); \
+ } \
+ fprintf(stderr, \
+ "%s:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", \
+ __func__, func, file, line, ptr, refs); \
+ }
+
+#define ISC_REFCOUNT_DECL(name) \
+ name##_t *name##_ref(name##_t *ptr); \
+ void name##_unref(name##_t *ptr); \
+ void name##_attach(name##_t *ptr, name##_t **ptrp); \
+ void name##_detach(name##_t **ptrp)
+
+#define ISC_REFCOUNT_IMPL(name, destroy) \
+ name##_t *name##_ref(name##_t *ptr) { \
+ REQUIRE(ptr != NULL); \
+ isc_refcount_increment(&ptr->references); \
+ return (ptr); \
+ } \
+ \
+ void name##_unref(name##_t *ptr) { \
+ REQUIRE(ptr != NULL); \
+ if (isc_refcount_decrement(&ptr->references) == 1) { \
+ destroy(ptr); \
+ } \
+ } \
+ void name##_attach(name##_t *ptr, name##_t **ptrp) { \
+ REQUIRE(ptrp != NULL && *ptrp == NULL); \
+ name##_ref(ptr); \
+ *ptrp = ptr; \
+ } \
+ \
+ void name##_detach(name##_t **ptrp) { \
+ REQUIRE(ptrp != NULL && *ptrp != NULL); \
+ name##_t *ptr = *ptrp; \
+ *ptrp = NULL; \
+ name##_unref(ptr); \
+ }
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/regex.h b/lib/isc/include/isc/regex.h
new file mode 100644
index 0000000..989d7b1
--- /dev/null
+++ b/lib/isc/include/isc/regex.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/regex.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_regex_validate(const char *expression);
+/*%<
+ * Check a regular expression for syntactic correctness.
+ *
+ * Returns:
+ *\li -1 on error.
+ *\li the number of groups in the expression.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/region.h b/lib/isc/include/isc/region.h
new file mode 100644
index 0000000..6f775cf
--- /dev/null
+++ b/lib/isc/include/isc/region.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/region.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+struct isc_region {
+ unsigned char *base;
+ unsigned int length;
+};
+
+struct isc_textregion {
+ char *base;
+ unsigned int length;
+};
+
+/* XXXDCL questionable ... bears discussion. we have been putting off
+ * discussing the region api.
+ */
+struct isc_constregion {
+ const void *base;
+ unsigned int length;
+};
+
+struct isc_consttextregion {
+ const char *base;
+ unsigned int length;
+};
+
+/*@{*/
+/*!
+ * The region structure is not opaque, and is usually directly manipulated.
+ * Some macros are defined below for convenience.
+ */
+
+#define isc_region_consume(r, l) \
+ do { \
+ isc_region_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+
+#define isc_textregion_consume(r, l) \
+ do { \
+ isc_textregion_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+
+#define isc_constregion_consume(r, l) \
+ do { \
+ isc_constregion_t *_r = (r); \
+ unsigned int _l = (l); \
+ INSIST(_r->length >= _l); \
+ _r->base += _l; \
+ _r->length -= _l; \
+ } while (0)
+/*@}*/
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_region_compare(isc_region_t *r1, isc_region_t *r2);
+/*%<
+ * Compares the contents of two regions
+ *
+ * Requires:
+ *\li 'r1' is a valid region
+ *\li 'r2' is a valid region
+ *
+ * Returns:
+ *\li < 0 if r1 is lexicographically less than r2
+ *\li = 0 if r1 is lexicographically identical to r2
+ *\li > 0 if r1 is lexicographically greater than r2
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/resource.h b/lib/isc/include/isc/resource.h
new file mode 100644
index 0000000..dc4b2b1
--- /dev/null
+++ b/lib/isc/include/isc/resource.h
@@ -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.
+ */
+
+#pragma once
+
+/*! \file isc/resource.h */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_RESOURCE_UNLIMITED ((isc_resourcevalue_t)UINT64_MAX)
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value);
+/*%<
+ * Set the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li If 'value' exceeds the maximum possible on the operating system,
+ * it is silently limited to that maximum -- or to "infinity", if
+ * the operating system has that concept. #ISC_RESOURCE_UNLIMITED
+ * can be used to explicitly ask for the maximum.
+ *
+ * Requires:
+ *\li 'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ *\li #ISC_R_NOPERM The calling process did not have adequate permission
+ * to change the resource limit.
+ */
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Get the maximum limit for a system resource.
+ *
+ * Notes:
+ *\li 'value' is set to the maximum limit.
+ *
+ *\li #ISC_RESOURCE_UNLIMITED is the maximum value of isc_resourcevalue_t.
+ *
+ *\li On many (all?) Unix systems, RLIM_INFINITY is a valid value that is
+ * significantly less than #ISC_RESOURCE_UNLIMITED, but which in practice
+ * behaves the same.
+ *
+ *\li The current ISC libdns configuration file parser assigns a value
+ * of UINT32_MAX for a size_spec of "unlimited" and ISC_UNIT32_MAX - 1
+ * for "default", the latter of which is supposed to represent "the
+ * limit that was in force when the server started". Since these are
+ * valid values in the middle of the range of isc_resourcevalue_t,
+ * there is the possibility for confusion over what exactly those
+ * particular values are supposed to represent in a particular context --
+ * discrete integral values or generalized concepts.
+ *
+ * Requires:
+ *\li 'resource' is a valid member of the isc_resource_t enumeration.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ */
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value);
+/*%<
+ * Same as isc_resource_getlimit(), but returns the current (soft) limit.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success.
+ *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
new file mode 100644
index 0000000..a43772e
--- /dev/null
+++ b/lib/isc/include/isc/result.h
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/result.h */
+
+#include <inttypes.h>
+
+#include <isc/lang.h>
+
+typedef enum isc_result {
+ ISC_R_SUCCESS, /*%< success */
+ ISC_R_NOMEMORY, /*%< out of memory */
+ ISC_R_TIMEDOUT, /*%< timed out */
+ ISC_R_NOTHREADS, /*%< no available threads */
+ ISC_R_ADDRNOTAVAIL, /*%< address not available */
+ ISC_R_ADDRINUSE, /*%< address in use */
+ ISC_R_NOPERM, /*%< permission denied */
+ ISC_R_NOCONN, /*%< no pending connections */
+ ISC_R_NETUNREACH, /*%< network unreachable */
+ ISC_R_HOSTUNREACH, /*%< host unreachable */
+ ISC_R_NETDOWN, /*%< network down */
+ ISC_R_HOSTDOWN, /*%< host down */
+ ISC_R_CONNREFUSED, /*%< connection refused */
+ ISC_R_NORESOURCES, /*%< not enough free resources */
+ ISC_R_EOF, /*%< end of file */
+ ISC_R_BOUND, /*%< socket already bound */
+ ISC_R_RELOAD, /*%< reload */
+ ISC_R_SUSPEND = ISC_R_RELOAD, /*%< alias of 'reload' */
+ ISC_R_LOCKBUSY, /*%< lock busy */
+ ISC_R_EXISTS, /*%< already exists */
+ ISC_R_NOSPACE, /*%< ran out of space */
+ ISC_R_CANCELED, /*%< operation canceled */
+ ISC_R_NOTBOUND, /*%< socket is not bound */
+ ISC_R_SHUTTINGDOWN, /*%< shutting down */
+ ISC_R_NOTFOUND, /*%< not found */
+ ISC_R_UNEXPECTEDEND, /*%< unexpected end of input */
+ ISC_R_FAILURE, /*%< generic failure */
+ ISC_R_IOERROR, /*%< I/O error */
+ ISC_R_NOTIMPLEMENTED, /*%< not implemented */
+ ISC_R_UNBALANCED, /*%< unbalanced parentheses */
+ ISC_R_NOMORE, /*%< no more */
+ ISC_R_INVALIDFILE, /*%< invalid file */
+ ISC_R_BADBASE64, /*%< bad base64 encoding */
+ ISC_R_UNEXPECTEDTOKEN, /*%< unexpected token */
+ ISC_R_QUOTA, /*%< quota reached */
+ ISC_R_UNEXPECTED, /*%< unexpected error */
+ ISC_R_ALREADYRUNNING, /*%< already running */
+ ISC_R_IGNORE, /*%< ignore */
+ ISC_R_MASKNONCONTIG, /*%< addr mask not contiguous */
+ ISC_R_FILENOTFOUND, /*%< file not found */
+ ISC_R_FILEEXISTS, /*%< file already exists */
+ ISC_R_NOTCONNECTED, /*%< socket is not connected */
+ ISC_R_RANGE, /*%< out of range */
+ ISC_R_NOENTROPY, /*%< out of entropy */
+ ISC_R_MULTICAST, /*%< invalid use of multicast */
+ ISC_R_NOTFILE, /*%< not a file */
+ ISC_R_NOTDIRECTORY, /*%< not a directory */
+ ISC_R_EMPTY, /*%< queue is empty */
+ ISC_R_FAMILYMISMATCH, /*%< address family mismatch */
+ ISC_R_FAMILYNOSUPPORT, /*%< AF not supported */
+ ISC_R_BADHEX, /*%< bad hex encoding */
+ ISC_R_TOOMANYOPENFILES, /*%< too many open files */
+ ISC_R_NOTBLOCKING, /*%< not blocking */
+ ISC_R_UNBALANCEDQUOTES, /*%< unbalanced quotes */
+ ISC_R_INPROGRESS, /*%< operation in progress */
+ ISC_R_CONNECTIONRESET, /*%< connection reset */
+ ISC_R_SOFTQUOTA, /*%< soft quota reached */
+ ISC_R_BADNUMBER, /*%< not a valid number */
+ ISC_R_DISABLED, /*%< disabled */
+ ISC_R_MAXSIZE, /*%< max size */
+ ISC_R_BADADDRESSFORM, /*%< invalid address format */
+ ISC_R_BADBASE32, /*%< bad base32 encoding */
+ ISC_R_UNSET, /*%< unset */
+ ISC_R_MULTIPLE, /*%< multiple */
+ ISC_R_WOULDBLOCK, /*%< would block */
+ ISC_R_COMPLETE, /*%< complete */
+ ISC_R_CRYPTOFAILURE, /*%< cryptography library failure */
+ ISC_R_DISCQUOTA, /*%< disc quota */
+ ISC_R_DISCFULL, /*%< disc full */
+ ISC_R_DEFAULT, /*%< default */
+ ISC_R_IPV4PREFIX, /*%< IPv4 prefix */
+ ISC_R_TLSERROR, /*%< TLS error */
+ ISC_R_TLSBADPEERCERT, /*%< TLS peer certificate verification failed */
+ ISC_R_HTTP2ALPNERROR, /*%< ALPN for HTTP/2 failed */
+ ISC_R_DOTALPNERROR, /*%< ALPN for DoT failed */
+ ISC_R_INVALIDPROTO, /*%< invalid protocol */
+
+ DNS_R_LABELTOOLONG,
+ DNS_R_BADESCAPE,
+ DNS_R_EMPTYLABEL,
+ DNS_R_BADDOTTEDQUAD,
+ DNS_R_INVALIDNS,
+ DNS_R_UNKNOWN,
+ DNS_R_BADLABELTYPE,
+ DNS_R_BADPOINTER,
+ DNS_R_TOOMANYHOPS,
+ DNS_R_DISALLOWED,
+ DNS_R_EXTRATOKEN,
+ DNS_R_EXTRADATA,
+ DNS_R_TEXTTOOLONG,
+ DNS_R_NOTZONETOP,
+ DNS_R_SYNTAX,
+ DNS_R_BADCKSUM,
+ DNS_R_BADAAAA,
+ DNS_R_NOOWNER,
+ DNS_R_NOTTL,
+ DNS_R_BADCLASS,
+ DNS_R_NAMETOOLONG,
+ DNS_R_PARTIALMATCH,
+ DNS_R_NEWORIGIN,
+ DNS_R_UNCHANGED,
+ DNS_R_BADTTL,
+ DNS_R_NOREDATA,
+ DNS_R_CONTINUE,
+ DNS_R_DELEGATION,
+ DNS_R_GLUE,
+ DNS_R_DNAME,
+ DNS_R_CNAME,
+ DNS_R_BADDB,
+ DNS_R_ZONECUT,
+ DNS_R_BADZONE,
+ DNS_R_MOREDATA,
+ DNS_R_UPTODATE,
+ DNS_R_TSIGVERIFYFAILURE,
+ DNS_R_TSIGERRORSET,
+ DNS_R_SIGINVALID,
+ DNS_R_SIGEXPIRED,
+ DNS_R_SIGFUTURE,
+ DNS_R_KEYUNAUTHORIZED,
+ DNS_R_INVALIDTIME,
+ DNS_R_EXPECTEDTSIG,
+ DNS_R_UNEXPECTEDTSIG,
+ DNS_R_INVALIDTKEY,
+ DNS_R_HINT,
+ DNS_R_DROP,
+ DNS_R_NOTLOADED,
+ DNS_R_NCACHENXDOMAIN,
+ DNS_R_NCACHENXRRSET,
+ DNS_R_WAIT,
+ DNS_R_NOTVERIFIEDYET,
+ DNS_R_NOIDENTITY,
+ DNS_R_NOJOURNAL,
+ DNS_R_ALIAS,
+ DNS_R_USETCP,
+ DNS_R_NOVALIDSIG,
+ DNS_R_NOVALIDNSEC,
+ DNS_R_NOTINSECURE,
+ DNS_R_UNKNOWNSERVICE,
+ DNS_R_RECOVERABLE,
+ DNS_R_UNKNOWNOPT,
+ DNS_R_UNEXPECTEDID,
+ DNS_R_SEENINCLUDE,
+ DNS_R_NOTEXACT,
+ DNS_R_BLACKHOLED,
+ DNS_R_BADALG,
+ DNS_R_METATYPE,
+ DNS_R_CNAMEANDOTHER,
+ DNS_R_SINGLETON,
+ DNS_R_HINTNXRRSET,
+ DNS_R_NOMASTERFILE,
+ DNS_R_UNKNOWNPROTO,
+ DNS_R_CLOCKSKEW,
+ DNS_R_BADIXFR,
+ DNS_R_NOTAUTHORITATIVE,
+ DNS_R_NOVALIDKEY,
+ DNS_R_OBSOLETE,
+ DNS_R_FROZEN,
+ DNS_R_UNKNOWNFLAG,
+ DNS_R_EXPECTEDRESPONSE,
+ DNS_R_NOVALIDDS,
+ DNS_R_NSISADDRESS,
+ DNS_R_REMOTEFORMERR,
+ DNS_R_TRUNCATEDTCP,
+ DNS_R_LAME,
+ DNS_R_UNEXPECTEDRCODE,
+ DNS_R_UNEXPECTEDOPCODE,
+ DNS_R_CHASEDSSERVERS,
+ DNS_R_EMPTYNAME,
+ DNS_R_EMPTYWILD,
+ DNS_R_BADBITMAP,
+ DNS_R_FROMWILDCARD,
+ DNS_R_BADOWNERNAME,
+ DNS_R_BADNAME,
+ DNS_R_DYNAMIC,
+ DNS_R_UNKNOWNCOMMAND,
+ DNS_R_MUSTBESECURE,
+ DNS_R_COVERINGNSEC,
+ DNS_R_MXISADDRESS,
+ DNS_R_DUPLICATE,
+ DNS_R_INVALIDNSEC3,
+ DNS_R_NOTPRIMARY,
+ DNS_R_BROKENCHAIN,
+ DNS_R_EXPIRED,
+ DNS_R_NOTDYNAMIC,
+ DNS_R_BADEUI,
+ DNS_R_NTACOVERED,
+ DNS_R_BADCDS,
+ DNS_R_BADCDNSKEY,
+ DNS_R_OPTERR,
+ DNS_R_BADDNSTAP,
+ DNS_R_BADTSIG,
+ DNS_R_BADSIG0,
+ DNS_R_TOOMANYRECORDS,
+ DNS_R_VERIFYFAILURE,
+ DNS_R_ATZONETOP,
+ DNS_R_NOKEYMATCH,
+ DNS_R_TOOMANYKEYS,
+ DNS_R_KEYNOTACTIVE,
+ DNS_R_NSEC3ITERRANGE,
+ DNS_R_NSEC3SALTRANGE,
+ DNS_R_NSEC3BADALG,
+ DNS_R_NSEC3RESALT,
+ DNS_R_INCONSISTENTRR,
+ DNS_R_NOALPN,
+
+ DST_R_UNSUPPORTEDALG,
+ DST_R_CRYPTOFAILURE,
+ /* compat */
+ DST_R_OPENSSLFAILURE = DST_R_CRYPTOFAILURE,
+ DST_R_NOCRYPTO,
+ DST_R_NULLKEY,
+ DST_R_INVALIDPUBLICKEY,
+ DST_R_INVALIDPRIVATEKEY,
+ DST_R_WRITEERROR,
+ DST_R_INVALIDPARAM,
+ DST_R_SIGNFAILURE,
+ DST_R_VERIFYFAILURE,
+ DST_R_NOTPUBLICKEY,
+ DST_R_NOTPRIVATEKEY,
+ DST_R_KEYCANNOTCOMPUTESECRET,
+ DST_R_COMPUTESECRETFAILURE,
+ DST_R_NORANDOMNESS,
+ DST_R_BADKEYTYPE,
+ DST_R_NOENGINE,
+ DST_R_EXTERNALKEY,
+
+ DNS_R_NOERROR,
+ DNS_R_FORMERR,
+ DNS_R_SERVFAIL,
+ DNS_R_NXDOMAIN,
+ DNS_R_NOTIMP,
+ DNS_R_REFUSED,
+ DNS_R_YXDOMAIN,
+ DNS_R_YXRRSET,
+ DNS_R_NXRRSET,
+ DNS_R_NOTAUTH,
+ DNS_R_NOTZONE,
+ DNS_R_RCODE11,
+ DNS_R_RCODE12,
+ DNS_R_RCODE13,
+ DNS_R_RCODE14,
+ DNS_R_RCODE15,
+ DNS_R_BADVERS,
+ DNS_R_BADCOOKIE = DNS_R_NOERROR + 23,
+
+ ISCCC_R_UNKNOWNVERSION,
+ ISCCC_R_SYNTAX,
+ ISCCC_R_BADAUTH,
+ ISCCC_R_EXPIRED,
+ ISCCC_R_CLOCKSKEW,
+ ISCCC_R_DUPLICATE,
+ ISCCC_R_MAXDEPTH,
+
+ ISC_R_NRESULTS, /*% The number of results. */
+ ISC_R_MAKE_ENUM_32BIT = INT32_MAX,
+} isc_result_t;
+
+ISC_LANG_BEGINDECLS
+
+const char *isc_result_totext(isc_result_t);
+/*%<
+ * Convert an isc_result_t into a string message describing the result.
+ */
+
+const char *isc_result_toid(isc_result_t);
+/*%<
+ * Convert an isc_result_t into a string identifier such as
+ * "ISC_R_SUCCESS".
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h
new file mode 100644
index 0000000..a0d7083
--- /dev/null
+++ b/lib/isc/include/isc/rwlock.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+/*! \file isc/rwlock.h */
+
+#include <isc/atomic.h>
+#include <isc/condition.h>
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef enum {
+ isc_rwlocktype_none = 0,
+ isc_rwlocktype_read,
+ isc_rwlocktype_write
+} isc_rwlocktype_t;
+
+#if USE_PTHREAD_RWLOCK
+#include <pthread.h>
+
+struct isc_rwlock {
+ pthread_rwlock_t rwlock;
+ atomic_bool downgrade;
+};
+
+#else /* USE_PTHREAD_RWLOCK */
+
+struct isc_rwlock {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mutex_t lock;
+ atomic_int_fast32_t spins;
+
+ /*
+ * When some atomic instructions with hardware assistance are
+ * available, rwlock will use those so that concurrent readers do not
+ * interfere with each other through mutex as long as no writers
+ * appear, massively reducing the lock overhead in the typical case.
+ *
+ * The basic algorithm of this approach is the "simple
+ * writer-preference lock" shown in the following URL:
+ * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html
+ * but our implementation does not rely on the spin lock unlike the
+ * original algorithm to be more portable as a user space application.
+ */
+
+ /* Read or modified atomically. */
+ atomic_int_fast32_t write_requests;
+ atomic_int_fast32_t write_completions;
+ atomic_int_fast32_t cnt_and_flag;
+
+ /* Locked by lock. */
+ isc_condition_t readable;
+ isc_condition_t writeable;
+ unsigned int readers_waiting;
+
+ /* Locked by rwlock itself. */
+ atomic_uint_fast32_t write_granted;
+
+ /* Unlocked. */
+ unsigned int write_quota;
+};
+
+#endif /* USE_PTHREAD_RWLOCK */
+
+void
+isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
+ unsigned int write_quota);
+
+isc_result_t
+isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+
+isc_result_t
+isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_downgrade(isc_rwlock_t *rwl);
+
+void
+isc_rwlock_destroy(isc_rwlock_t *rwl);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/safe.h b/lib/isc/include/isc/safe.h
new file mode 100644
index 0000000..35e7759
--- /dev/null
+++ b/lib/isc/include/isc/safe.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/safe.h */
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+int
+isc_safe_memequal(const void *, const void *, size_t);
+
+/*%<
+ * Returns true iff. two blocks of memory are equal, otherwise
+ * false.
+ *
+ */
+
+void
+isc_safe_memwipe(void *, size_t);
+
+/*%<
+ * Clear the memory of length `len` pointed to by `ptr`.
+ *
+ * Some crypto code calls memset() on stack allocated buffers just
+ * before return so that they are wiped. Such memset() calls can be
+ * optimized away by the compiler. We provide this external non-inline C
+ * function to perform the memset operation so that the compiler cannot
+ * infer about what the function does and optimize the call away.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/serial.h b/lib/isc/include/isc/serial.h
new file mode 100644
index 0000000..b7bfa5f
--- /dev/null
+++ b/lib/isc/include/isc/serial.h
@@ -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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*! \file isc/serial.h
+ * \brief Implement 32 bit serial space arithmetic comparison functions.
+ * Note: Undefined results are returned as false.
+ */
+
+/***
+ *** Functions
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+bool
+isc_serial_lt(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' < 'b' otherwise false.
+ */
+
+bool
+isc_serial_gt(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' > 'b' otherwise false.
+ */
+
+bool
+isc_serial_le(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' <= 'b' otherwise false.
+ */
+
+bool
+isc_serial_ge(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' >= 'b' otherwise false.
+ */
+
+bool
+isc_serial_eq(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' == 'b' otherwise false.
+ */
+
+bool
+isc_serial_ne(uint32_t a, uint32_t b);
+/*%<
+ * Return true if 'a' != 'b' otherwise false.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/siphash.h b/lib/isc/include/isc/siphash.h
new file mode 100644
index 0000000..69d4742
--- /dev/null
+++ b/lib/isc/include/isc/siphash.h
@@ -0,0 +1,36 @@
+/*
+ * 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 isc/siphash.h */
+
+#pragma once
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#define ISC_SIPHASH24_KEY_LENGTH 128 / 8
+#define ISC_SIPHASH24_TAG_LENGTH 64 / 8
+
+#define ISC_HALFSIPHASH24_KEY_LENGTH 64 / 8
+#define ISC_HALFSIPHASH24_TAG_LENGTH 32 / 8
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_siphash24(const uint8_t *key, const uint8_t *in, const size_t inlen,
+ uint8_t *out);
+void
+isc_halfsiphash24(const uint8_t *key, const uint8_t *in, const size_t inlen,
+ uint8_t *out);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/sockaddr.h b/lib/isc/include/isc/sockaddr.h
new file mode 100644
index 0000000..9f3986b
--- /dev/null
+++ b/lib/isc/include/isc/sockaddr.h
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/sockaddr.h */
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/net.h>
+#include <isc/types.h>
+
+#include <sys/un.h>
+
+/*
+ * Any updates to this structure should also be applied in
+ * contrib/modules/dlz/dlz_minmal.h.
+ */
+struct isc_sockaddr {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_storage ss;
+ struct sockaddr_un sunix;
+ } type;
+ unsigned int length; /* XXXRTH beginning? */
+ ISC_LINK(struct isc_sockaddr) link;
+};
+
+#define ISC_SOCKADDR_CMPADDR \
+ 0x0001 /*%< compare the address \
+ * sin_addr/sin6_addr */
+#define ISC_SOCKADDR_CMPPORT \
+ 0x0002 /*%< compare the port \
+ * sin_port/sin6_port */
+#define ISC_SOCKADDR_CMPSCOPE \
+ 0x0004 /*%< compare the scope \
+ * sin6_scope */
+#define ISC_SOCKADDR_CMPSCOPEZERO \
+ 0x0008 /*%< when comparing scopes \
+ * zero scopes always match */
+
+ISC_LANG_BEGINDECLS
+
+bool
+isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int flags);
+/*%<
+ * Compare the elements of the two address ('a' and 'b') as specified
+ * by 'flags' and report if they are equal or not.
+ *
+ * 'flags' is set from ISC_SOCKADDR_CMP*.
+ */
+
+bool
+isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
+/*%<
+ * Return true iff the socket addresses 'a' and 'b' are equal.
+ */
+
+bool
+isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b);
+/*%<
+ * Return true iff the address parts of the socket addresses
+ * 'a' and 'b' are equal, ignoring the ports.
+ */
+
+bool
+isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
+ unsigned int prefixlen);
+/*%<
+ * Return true iff the most significant 'prefixlen' bits of the
+ * socket addresses 'a' and 'b' are equal, ignoring the ports.
+ * If 'b''s scope is zero then 'a''s scope will be ignored.
+ */
+
+unsigned int
+isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only);
+/*%<
+ * Return a hash value for the socket address 'sockaddr'. If 'address_only'
+ * is true, the hash value will not depend on the port.
+ *
+ * IPv6 addresses containing mapped IPv4 addresses generate the same hash
+ * value as the equivalent IPv4 address.
+ */
+
+void
+isc_sockaddr_any(isc_sockaddr_t *sockaddr);
+/*%<
+ * Return the IPv4 wildcard address.
+ */
+
+void
+isc_sockaddr_any6(isc_sockaddr_t *sockaddr);
+/*%<
+ * Return the IPv6 wildcard address.
+ */
+
+void
+isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int family);
+/*%<
+ * Set '*sockaddr' to the wildcard address of protocol family
+ * 'family'.
+ *
+ * Requires:
+ * \li 'family' is AF_INET or AF_INET6.
+ */
+
+void
+isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an IPv4 address and port.
+ */
+
+void
+isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an IPv6 address and port.
+ */
+
+void
+isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
+ in_port_t port);
+/*%<
+ * Construct an IPv6 isc_sockaddr_t representing a mapped IPv4 address.
+ */
+
+void
+isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
+ in_port_t port);
+/*%<
+ * Construct an isc_sockaddr_t from an isc_netaddr_t and port.
+ */
+
+int
+isc_sockaddr_pf(const isc_sockaddr_t *sockaddr);
+/*%<
+ * Get the protocol family of 'sockaddr'.
+ *
+ * Requires:
+ *
+ *\li 'sockaddr' is a valid sockaddr with an address family of AF_INET
+ * or AF_INET6.
+ *
+ * Returns:
+ *
+ *\li The protocol family of 'sockaddr', e.g. PF_INET or PF_INET6.
+ */
+
+void
+isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port);
+/*%<
+ * Set the port of 'sockaddr' to 'port'.
+ */
+
+in_port_t
+isc_sockaddr_getport(const isc_sockaddr_t *sockaddr);
+/*%<
+ * Get the port stored in 'sockaddr'.
+ */
+
+isc_result_t
+isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target);
+/*%<
+ * Append a text representation of 'sockaddr' to the buffer 'target'.
+ * The text will include both the IP address (v4 or v6) and the port.
+ * The text is null terminated, but the terminating null is not
+ * part of the buffer's used region.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE The text or the null termination did not fit.
+ */
+
+void
+isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size);
+/*%<
+ * Format a human-readable representation of the socket address '*sa'
+ * into the character array 'array', which is of size 'size'.
+ * The resulting string is guaranteed to be null-terminated.
+ */
+
+bool
+isc_sockaddr_ismulticast(const isc_sockaddr_t *sa);
+/*%<
+ * Returns #true if the address is a multicast address.
+ */
+
+bool
+isc_sockaddr_isexperimental(const isc_sockaddr_t *sa);
+/*
+ * Returns true if the address is a experimental (CLASS E) address.
+ */
+
+bool
+isc_sockaddr_islinklocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns true if the address is a link local address.
+ */
+
+bool
+isc_sockaddr_issitelocal(const isc_sockaddr_t *sa);
+/*%<
+ * Returns true if the address is a sitelocal address.
+ */
+
+bool
+isc_sockaddr_isnetzero(const isc_sockaddr_t *sa);
+/*%<
+ * Returns true if the address is in net zero.
+ */
+
+isc_result_t
+isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path);
+/*
+ * Create a UNIX domain sockaddr that refers to path.
+ *
+ * Returns:
+ * \li ISC_R_NOSPACE
+ * \li ISC_R_NOTIMPLEMENTED
+ * \li ISC_R_SUCCESS
+ */
+
+isc_result_t
+isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa);
+
+#define ISC_SOCKADDR_FORMATSIZE \
+ sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS#" \
+ "YYYYY")
+/*%<
+ * Minimum size of array to pass to isc_sockaddr_format().
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/stat.h b/lib/isc/include/isc/stat.h
new file mode 100644
index 0000000..fad37c9
--- /dev/null
+++ b/lib/isc/include/isc/stat.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*
+ * Portable <sys/stat.h> support.
+ *
+ * This module is responsible for defining S_IS??? macros.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <sys/stat.h>
+#include <sys/types.h>
diff --git a/lib/isc/include/isc/stats.h b/lib/isc/include/isc/stats.h
new file mode 100644
index 0000000..5bed7d5
--- /dev/null
+++ b/lib/isc/include/isc/stats.h
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/stats.h */
+
+#include <inttypes.h>
+
+#include <isc/types.h>
+
+/*%
+ * Statistics counters. Used as isc_statscounter_t values.
+ */
+enum {
+ /*%
+ * Socket statistics counters.
+ */
+ isc_sockstatscounter_udp4open = 0,
+ isc_sockstatscounter_udp6open = 1,
+ isc_sockstatscounter_tcp4open = 2,
+ isc_sockstatscounter_tcp6open = 3,
+ isc_sockstatscounter_unixopen = 4,
+
+ isc_sockstatscounter_udp4openfail = 5,
+ isc_sockstatscounter_udp6openfail = 6,
+ isc_sockstatscounter_tcp4openfail = 7,
+ isc_sockstatscounter_tcp6openfail = 8,
+ isc_sockstatscounter_unixopenfail = 9,
+
+ isc_sockstatscounter_udp4close = 10,
+ isc_sockstatscounter_udp6close = 11,
+ isc_sockstatscounter_tcp4close = 12,
+ isc_sockstatscounter_tcp6close = 13,
+ isc_sockstatscounter_unixclose = 14,
+ isc_sockstatscounter_fdwatchclose = 15,
+
+ isc_sockstatscounter_udp4bindfail = 16,
+ isc_sockstatscounter_udp6bindfail = 17,
+ isc_sockstatscounter_tcp4bindfail = 18,
+ isc_sockstatscounter_tcp6bindfail = 19,
+ isc_sockstatscounter_unixbindfail = 20,
+ isc_sockstatscounter_fdwatchbindfail = 21,
+
+ isc_sockstatscounter_udp4connect = 22,
+ isc_sockstatscounter_udp6connect = 23,
+ isc_sockstatscounter_tcp4connect = 24,
+ isc_sockstatscounter_tcp6connect = 25,
+ isc_sockstatscounter_unixconnect = 26,
+ isc_sockstatscounter_fdwatchconnect = 27,
+
+ isc_sockstatscounter_udp4connectfail = 28,
+ isc_sockstatscounter_udp6connectfail = 29,
+ isc_sockstatscounter_tcp4connectfail = 30,
+ isc_sockstatscounter_tcp6connectfail = 31,
+ isc_sockstatscounter_unixconnectfail = 32,
+ isc_sockstatscounter_fdwatchconnectfail = 33,
+
+ isc_sockstatscounter_tcp4accept = 34,
+ isc_sockstatscounter_tcp6accept = 35,
+ isc_sockstatscounter_unixaccept = 36,
+
+ isc_sockstatscounter_tcp4acceptfail = 37,
+ isc_sockstatscounter_tcp6acceptfail = 38,
+ isc_sockstatscounter_unixacceptfail = 39,
+
+ isc_sockstatscounter_udp4sendfail = 40,
+ isc_sockstatscounter_udp6sendfail = 41,
+ isc_sockstatscounter_tcp4sendfail = 42,
+ isc_sockstatscounter_tcp6sendfail = 43,
+ isc_sockstatscounter_unixsendfail = 44,
+ isc_sockstatscounter_fdwatchsendfail = 45,
+
+ isc_sockstatscounter_udp4recvfail = 46,
+ isc_sockstatscounter_udp6recvfail = 47,
+ isc_sockstatscounter_tcp4recvfail = 48,
+ isc_sockstatscounter_tcp6recvfail = 49,
+ isc_sockstatscounter_unixrecvfail = 50,
+ isc_sockstatscounter_fdwatchrecvfail = 51,
+
+ isc_sockstatscounter_udp4active = 52,
+ isc_sockstatscounter_udp6active = 53,
+ isc_sockstatscounter_tcp4active = 54,
+ isc_sockstatscounter_tcp6active = 55,
+ isc_sockstatscounter_unixactive = 56,
+
+ isc_sockstatscounter_rawopen = 57,
+ isc_sockstatscounter_rawopenfail = 58,
+ isc_sockstatscounter_rawclose = 59,
+ isc_sockstatscounter_rawrecvfail = 60,
+ isc_sockstatscounter_rawactive = 61,
+
+ isc_sockstatscounter_max = 62
+};
+
+ISC_LANG_BEGINDECLS
+
+/*%<
+ * Flag(s) for isc_stats_dump().
+ */
+#define ISC_STATSDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */
+
+/*%<
+ * Dump callback type.
+ */
+typedef void (*isc_stats_dumper_t)(isc_statscounter_t, uint64_t, void *);
+
+isc_result_t
+isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters);
+/*%<
+ * Create a statistics counter structure of general type. It counts a general
+ * set of counters indexed by an ID between 0 and ncounters -1.
+ *
+ * Requires:
+ *\li 'mctx' must be a valid memory context.
+ *
+ *\li 'statsp' != NULL && '*statsp' == NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS -- all ok
+ *
+ *\li anything else -- failure
+ */
+
+void
+isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp);
+/*%<
+ * Attach to a statistics set.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ *\li 'statsp' != NULL && '*statsp' == NULL
+ */
+
+void
+isc_stats_detach(isc_stats_t **statsp);
+/*%<
+ * Detaches from the statistics set.
+ *
+ * Requires:
+ *\li 'statsp' != NULL and '*statsp' is a valid isc_stats_t.
+ */
+
+int
+isc_stats_ncounters(isc_stats_t *stats);
+/*%<
+ * Returns the number of counters contained in stats.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ */
+
+void
+isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Increment the counter-th counter of stats.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ *\li counter is less than the maximum available ID for the stats specified
+ * on creation.
+ */
+
+void
+isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Decrement the counter-th counter of stats.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg,
+ unsigned int options);
+/*%<
+ * Dump the current statistics counters in a specified way. For each counter
+ * in stats, dump_fn is called with its current value and the given argument
+ * arg. By default counters that have a value of 0 is skipped; if options has
+ * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_set(isc_stats_t *stats, uint64_t val, isc_statscounter_t counter);
+/*%<
+ * Set the given counter to the specified value.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_set(isc_stats_t *stats, uint64_t val, isc_statscounter_t counter);
+/*%<
+ * Set the given counter to the specified value.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ */
+
+void
+isc_stats_update_if_greater(isc_stats_t *stats, isc_statscounter_t counter,
+ isc_statscounter_t value);
+/*%<
+ * Atomically assigns 'value' to 'counter' if value > counter.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ *\li counter is less than the maximum available ID for the stats specified
+ * on creation.
+ */
+
+isc_statscounter_t
+isc_stats_get_counter(isc_stats_t *stats, isc_statscounter_t counter);
+/*%<
+ * Returns value currently stored in counter.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *
+ *\li counter is less than the maximum available ID for the stats specified
+ * on creation.
+ */
+
+void
+isc_stats_resize(isc_stats_t **stats, int ncounters);
+/*%<
+ * Resize a statistics counter structure of general type. The new set of
+ * counters are indexed by an ID between 0 and ncounters -1.
+ *
+ * Requires:
+ *\li 'stats' is a valid isc_stats_t.
+ *\li 'ncounters' is a non-zero positive number.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/stdatomic.h b/lib/isc/include/isc/stdatomic.h
new file mode 100644
index 0000000..7c2e21c
--- /dev/null
+++ b/lib/isc/include/isc/stdatomic.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#if HAVE_UCHAR_H
+#include <uchar.h>
+#endif /* HAVE_UCHAR_H */
+
+/* GCC 4.7.0 introduced __atomic builtins, but not the __GNUC_ATOMICS define */
+#if !defined(__GNUC_ATOMICS) && __GNUC__ == 4 && __GNUC_MINOR__ >= 7
+#define __GNUC_ATOMICS
+#endif
+
+#if !defined(__GNUC_ATOMICS)
+#error "isc/stdatomic.h does not support your compiler"
+#endif /* if !defined(__GNUC_ATOMICS) */
+
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+#ifndef HAVE_UCHAR_H
+typedef uint_least16_t char16_t;
+typedef uint_least32_t char32_t;
+#endif /* HAVE_UCHAR_H */
+
+typedef bool atomic_bool;
+typedef char atomic_char;
+typedef signed char atomic_schar;
+typedef unsigned char atomic_uchar;
+typedef short atomic_short;
+typedef unsigned short atomic_ushort;
+typedef int atomic_int;
+typedef unsigned int atomic_uint;
+typedef long atomic_long;
+typedef unsigned long atomic_ulong;
+typedef long long atomic_llong;
+typedef unsigned long long atomic_ullong;
+typedef char16_t atomic_char16_t;
+typedef char32_t atomic_char32_t;
+typedef wchar_t atomic_wchar_t;
+typedef int_least8_t atomic_int_least8_t;
+typedef uint_least8_t atomic_uint_least8_t;
+typedef int_least16_t atomic_int_least16_t;
+typedef uint_least16_t atomic_uint_least16_t;
+typedef int_least32_t atomic_int_least32_t;
+typedef uint_least32_t atomic_uint_least32_t;
+typedef int_least64_t atomic_int_least64_t;
+typedef uint_least64_t atomic_uint_least64_t;
+typedef int_fast8_t atomic_int_fast8_t;
+typedef uint_fast8_t atomic_uint_fast8_t;
+typedef int_fast16_t atomic_int_fast16_t;
+typedef uint_fast16_t atomic_uint_fast16_t;
+typedef int_fast32_t atomic_int_fast32_t;
+typedef uint_fast32_t atomic_uint_fast32_t;
+typedef int_fast64_t atomic_int_fast64_t;
+typedef uint_fast64_t atomic_uint_fast64_t;
+typedef intptr_t atomic_intptr_t;
+typedef uintptr_t atomic_uintptr_t;
+typedef size_t atomic_size_t;
+typedef ptrdiff_t atomic_ptrdiff_t;
+typedef intmax_t atomic_intmax_t;
+typedef uintmax_t atomic_uintmax_t;
+
+#define atomic_init(obj, desired) (*obj = desired)
+#define atomic_load_explicit(obj, order) __atomic_load_n(obj, order)
+#define atomic_store_explicit(obj, desired, order) \
+ __atomic_store_n(obj, desired, order)
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ __atomic_fetch_add(obj, arg, order)
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ __atomic_fetch_sub(obj, arg, order)
+#define atomic_fetch_and_explicit(obj, arg, order) \
+ __atomic_fetch_and(obj, arg, order)
+#define atomic_fetch_or_explicit(obj, arg, order) \
+ __atomic_fetch_or(obj, arg, order)
+#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, \
+ fail) \
+ __atomic_compare_exchange_n(obj, expected, desired, 0, succ, fail)
+#define atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, \
+ fail) \
+ __atomic_compare_exchange_n(obj, expected, desired, 1, succ, fail)
+#define atomic_exchange_explicit(obj, desired, order) \
+ __atomic_exchange_n(obj, desired, order)
+
+#define atomic_load(obj) atomic_load_explicit(obj, memory_order_seq_cst)
+#define atomic_store(obj, arg) \
+ atomic_store_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_fetch_add(obj, arg) \
+ atomic_fetch_add_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_fetch_sub(obj, arg) \
+ atomic_fetch_sub_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_fetch_and(obj, arg) \
+ atomic_fetch_and_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_fetch_or(obj, arg) \
+ atomic_fetch_or_explicit(obj, arg, memory_order_seq_cst)
+#define atomic_compare_exchange_strong(obj, expected, desired) \
+ atomic_compare_exchange_strong_explicit(obj, expected, desired, \
+ memory_order_seq_cst, \
+ memory_order_seq_cst)
+#define atomic_compare_exchange_weak(obj, expected, desired) \
+ atomic_compare_exchange_weak_explicit(obj, expected, desired, \
+ memory_order_seq_cst, \
+ memory_order_seq_cst)
+#define atomic_exchange(obj, desired) \
+ atomic_exchange_explicit(obj, desired, memory_order_seq_cst)
diff --git a/lib/isc/include/isc/stdio.h b/lib/isc/include/isc/stdio.h
new file mode 100644
index 0000000..c8bac4d
--- /dev/null
+++ b/lib/isc/include/isc/stdio.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/stdio.h */
+
+/*%
+ * These functions are wrappers around the corresponding stdio functions.
+ *
+ * They return a detailed error code in the form of an an isc_result_t. ANSI C
+ * does not guarantee that stdio functions set errno, hence these functions
+ * must use platform dependent methods (e.g., the POSIX errno) to construct the
+ * error code.
+ */
+
+#include <stdio.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+/*% Open */
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp);
+
+/*% Close */
+isc_result_t
+isc_stdio_close(FILE *f);
+
+/*% Seek */
+isc_result_t
+isc_stdio_seek(FILE *f, off_t offset, int whence);
+
+/*% Tell */
+isc_result_t
+isc_stdio_tell(FILE *f, off_t *offsetp);
+
+/*% Read */
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret);
+
+/*% Write */
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret);
+
+/*% Flush */
+isc_result_t
+isc_stdio_flush(FILE *f);
+
+isc_result_t
+isc_stdio_sync(FILE *f);
+/*%<
+ * Invoke fsync() on the file descriptor underlying an stdio stream, or an
+ * equivalent system-dependent operation. Note that this function has no
+ * direct counterpart in the stdio library.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/stdtime.h b/lib/isc/include/isc/stdtime.h
new file mode 100644
index 0000000..45ec50f
--- /dev/null
+++ b/lib/isc/include/isc/stdtime.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <isc/lang.h>
+
+/*%
+ * It's public information that 'isc_stdtime_t' is an unsigned integral type.
+ * Applications that want maximum portability should not assume anything
+ * about its size.
+ */
+typedef uint32_t isc_stdtime_t;
+
+ISC_LANG_BEGINDECLS
+/* */
+void
+isc_stdtime_get(isc_stdtime_t *t);
+/*%<
+ * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+void
+isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen);
+/*
+ * Convert 't' into a null-terminated string of the form
+ * "Wed Jun 30 21:49:08 1993". Store the string in the 'out'
+ * buffer.
+ *
+ * Requires:
+ *
+ * 't' is a valid time.
+ * 'out' is a valid pointer.
+ * 'outlen' is at least 26.
+ */
+
+#define isc_stdtime_convert32(t, t32p) (*(t32p) = t)
+/*
+ * Convert the standard time to its 32-bit version.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/strerr.h b/lib/isc/include/isc/strerr.h
new file mode 100644
index 0000000..563ff48
--- /dev/null
+++ b/lib/isc/include/isc/strerr.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/strerr.h */
+
+#include <isc/string.h>
+
+/***
+ *** Default strerror_r buffer size
+ ***/
+
+#define ISC_STRERRORSIZE 128
+
+#if defined(strerror_r)
+#undef strerror_r
+#endif /* if defined(strerror_r) */
+#define strerror_r isc_string_strerror_r
diff --git a/lib/isc/include/isc/string.h b/lib/isc/include/isc/string.h
new file mode 100644
index 0000000..fbf6129
--- /dev/null
+++ b/lib/isc/include/isc/string.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/string.h */
+
+#include <string.h>
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+#if !defined(HAVE_STRLCPY)
+size_t
+strlcpy(char *dst, const char *src, size_t size);
+#endif /* !defined(HAVE_STRLCPY) */
+
+#if !defined(HAVE_STRLCAT)
+size_t
+strlcat(char *dst, const char *src, size_t size);
+#endif /* if !defined(HAVE_STRLCAT) */
+
+#if !defined(HAVE_STRNSTR)
+char *
+strnstr(const char *s, const char *find, size_t slen);
+#endif /* if !defined(HAVE_STRNSTR) */
+
+int
+isc_string_strerror_r(int errnum, char *buf, size_t buflen);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/symtab.h b/lib/isc/include/isc/symtab.h
new file mode 100644
index 0000000..2be3a8b
--- /dev/null
+++ b/lib/isc/include/isc/symtab.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/symtab.h
+ * \brief Provides a simple memory-based symbol table.
+ *
+ * Keys are C strings, and key comparisons are case-insensitive. A type may
+ * be specified when looking up, defining, or undefining. A type value of
+ * 0 means "match any type"; any other value will only match the given
+ * type.
+ *
+ * It's possible that a client will attempt to define a <key, type, value>
+ * tuple when a tuple with the given key and type already exists in the table.
+ * What to do in this case is specified by the client. Possible policies are:
+ *
+ *\li #isc_symexists_reject Disallow the define, returning #ISC_R_EXISTS
+ *\li #isc_symexists_replace Replace the old value with the new. The
+ * undefine action (if provided) will be called
+ * with the old <key, type, value> tuple.
+ *\li #isc_symexists_add Add the new tuple, leaving the old tuple in
+ * the table. Subsequent lookups will retrieve
+ * the most-recently-defined tuple.
+ *
+ * A lookup of a key using type 0 will return the most-recently defined
+ * symbol with that key. An undefine of a key using type 0 will undefine the
+ * most-recently defined symbol with that key. Trying to define a key with
+ * type 0 is illegal.
+ *
+ * The symbol table library does not make a copy the key field, so the
+ * caller must ensure that any key it passes to isc_symtab_define() will not
+ * change until it calls isc_symtab_undefine() or isc_symtab_destroy().
+ *
+ * A user-specified action will be called (if provided) when a symbol is
+ * undefined. It can be used to free memory associated with keys and/or
+ * values.
+ *
+ * A symbol table is implemented as a hash table of lists; the size of the
+ * hash table is set by the 'size' parameter to isc_symtbl_create(). When
+ * the number of entries in the symbol table reaches three quarters of this
+ * value, the hash table is reallocated with size doubled, in order to
+ * optimize lookup performance. This has a negative effect on insertion
+ * performance, which can be mitigated by sizing the table appropriately
+ * when creating it.
+ *
+ * \li MP:
+ * The callers of this module must ensure any required synchronization.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/*
+ *** Symbol Tables.
+ ***/
+/*% Symbol table value. */
+typedef union isc_symvalue {
+ void *as_pointer;
+ const void *as_cpointer;
+ int as_integer;
+ unsigned int as_uinteger;
+} isc_symvalue_t;
+
+typedef void (*isc_symtabaction_t)(char *key, unsigned int type,
+ isc_symvalue_t value, void *userarg);
+/*% Symbol table exists. */
+typedef enum {
+ isc_symexists_reject = 0, /*%< Disallow the define */
+ isc_symexists_replace = 1, /*%< Replace the old value with the new */
+ isc_symexists_add = 2 /*%< Add the new tuple */
+} isc_symexists_t;
+
+ISC_LANG_BEGINDECLS
+
+/*% Create a symbol table. */
+isc_result_t
+isc_symtab_create(isc_mem_t *mctx, unsigned int size,
+ isc_symtabaction_t undefine_action, void *undefine_arg,
+ bool case_sensitive, isc_symtab_t **symtabp);
+
+/*% Destroy a symbol table. */
+void
+isc_symtab_destroy(isc_symtab_t **symtabp);
+
+/*% Lookup a symbol table. */
+isc_result_t
+isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t *value);
+
+/*% Define a symbol table. */
+isc_result_t
+isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
+ isc_symvalue_t value, isc_symexists_t exists_policy);
+
+/*% Undefine a symbol table. */
+isc_result_t
+isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type);
+
+/*% Return the number of items in a symbol table. */
+unsigned int
+isc_symtab_count(isc_symtab_t *symtab);
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/syslog.h b/lib/isc/include/isc/syslog.h
new file mode 100644
index 0000000..021f7fa
--- /dev/null
+++ b/lib/isc/include/isc/syslog.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp);
+/*%<
+ * Convert 'str' to the appropriate syslog facility constant.
+ *
+ * Requires:
+ *
+ *\li 'str' is not NULL
+ *\li 'facilityp' is not NULL
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h
new file mode 100644
index 0000000..75b7cdb
--- /dev/null
+++ b/lib/isc/include/isc/task.h
@@ -0,0 +1,646 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/task.h
+ * \brief The task system provides a lightweight execution context, which is
+ * basically an event queue.
+ *
+ * When a task's event queue is non-empty, the
+ * task is runnable. A small work crew of threads, typically one per CPU,
+ * execute runnable tasks by dispatching the events on the tasks' event
+ * queues. Context switching between tasks is fast.
+ *
+ * \li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * The caller must ensure that isc_taskmgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ *
+ * \section purge Purging and Unsending
+ *
+ * Events which have been queued for a task but not delivered may be removed
+ * from the task's event queue by purging or unsending.
+ *
+ * With both types, the caller specifies a matching pattern that selects
+ * events based upon their sender, type, and tag.
+ *
+ * Purging calls isc_event_free() on the matching events.
+ *
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/netmgr.h>
+#include <isc/stdtime.h>
+#include <isc/types.h>
+
+#define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0)
+#define ISC_TASKEVENT_SHUTDOWN (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_TEST (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535)
+
+/*****
+ ***** Tasks.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+typedef enum {
+ isc_taskmgrmode_normal = 0,
+ isc_taskmgrmode_privileged
+} isc_taskmgrmode_t;
+
+isc_result_t
+isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
+ isc_task_t **taskp);
+isc_result_t
+isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum,
+ isc_task_t **taskp, int threadid);
+/*%<
+ * Create a task, optionally bound to a particular threadid.
+ *
+ * Notes:
+ *
+ *\li If 'quantum' is non-zero, then only that many events can be dispatched
+ * before the task must yield to other tasks waiting to execute. If
+ * quantum is zero, then the default quantum of the task manager will
+ * be used.
+ *
+ *\li The 'quantum' option may be removed from isc_task_create() in the
+ * future. If this happens, isc_task_getquantum() and
+ * isc_task_setquantum() will be provided.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid task manager.
+ *
+ *\li taskp != NULL && *taskp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*taskp' is bound to the new task.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ *\li #ISC_R_SHUTTINGDOWN
+ */
+
+void
+isc_task_ready(isc_task_t *task);
+/*%<
+ * Enqueue the task onto netmgr queue.
+ */
+
+isc_result_t
+isc_task_run(isc_task_t *task);
+/*%<
+ * Run all the queued events for the 'task', returning
+ * when the queue is empty or the number of events executed
+ * exceeds the 'quantum' specified when the task was created.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_QUOTA
+ */
+
+void
+isc_task_attach(isc_task_t *source, isc_task_t **targetp);
+/*%<
+ * Attach *targetp to source.
+ *
+ * Requires:
+ *
+ *\li 'source' is a valid task.
+ *
+ *\li 'targetp' points to a NULL isc_task_t *.
+ *
+ * Ensures:
+ *
+ *\li *targetp is attached to source.
+ */
+
+void
+isc_task_detach(isc_task_t **taskp);
+/*%<
+ * Detach *taskp from its task.
+ *
+ * Requires:
+ *
+ *\li '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li *taskp is NULL.
+ *
+ *\li If '*taskp' is the last reference to the task, the task is idle (has
+ * an empty event queue), and has not been shutdown, the task will be
+ * shutdown.
+ *
+ *\li If '*taskp' is the last reference to the task and
+ * the task has been shutdown,
+ * all resources used by the task will be freed.
+ */
+
+void
+isc_task_send(isc_task_t *task, isc_event_t **eventp);
+
+void
+isc_task_sendto(isc_task_t *task, isc_event_t **eventp, int c);
+/*%<
+ * Send '*event' to 'task', if task is idle try starting it on cpu 'c'
+ * If 'c' is smaller than 0 then cpu is selected randomly.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *\li eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ */
+
+void
+isc_task_sendtoanddetach(isc_task_t **taskp, isc_event_t **eventp, int c);
+
+void
+isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp);
+/*%<
+ * Send '*event' to '*taskp' and then detach '*taskp' from its
+ * task. If task is idle try starting it on cpu 'c'
+ * If 'c' is smaller than 0 then cpu is selected randomly.
+ *
+ * Requires:
+ *
+ *\li '*taskp' is a valid task.
+ *\li eventp != NULL && *eventp != NULL.
+ *
+ * Ensures:
+ *
+ *\li *eventp == NULL.
+ *
+ *\li *taskp == NULL.
+ *
+ *\li If '*taskp' is the last reference to the task, the task is
+ * idle (has an empty event queue), and has not been shutdown,
+ * the task will be shutdown.
+ *
+ *\li If '*taskp' is the last reference to the task and
+ * the task has been shutdown,
+ * all resources used by the task will be freed.
+ */
+
+unsigned int
+isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first,
+ isc_eventtype_t last, void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li last >= first
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is >= first and <= last, and whose tag is 'tag' will be purged,
+ * unless they are marked as unpurgable.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events purged.
+ */
+
+unsigned int
+isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag);
+/*%<
+ * Purge events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li This function is equivalent to
+ *
+ *\code
+ * isc_task_purgerange(task, sender, type, type, tag);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is 'type', and whose tag is 'tag' will be purged, unless they
+ * are marked as unpurgable.
+ *
+ *\li A sender of NULL will match any sender. A NULL tag matches any
+ * tag.
+ *
+ * Returns:
+ *
+ *\li The number of events purged.
+ */
+
+bool
+isc_task_purgeevent(isc_task_t *task, isc_event_t *event);
+/*%<
+ * Purge 'event' from a task's event queue.
+ *
+ * XXXRTH: WARNING: This method may be removed before beta.
+ *
+ * Notes:
+ *
+ *\li If 'event' is on the task's event queue, it will be purged,
+ * unless it is marked as unpurgeable. 'event' does not have to be
+ * on the task's event queue; in fact, it can even be an invalid
+ * pointer. Purging only occurs if the event is actually on the task's
+ * event queue.
+ *
+ * \li Purging never changes the state of the task.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li 'event' is not in the event queue for 'task'.
+ *
+ * Returns:
+ *
+ *\li #true The event was purged.
+ *\li #false The event was not in the event queue,
+ * or was marked unpurgeable.
+ */
+
+unsigned int
+isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag,
+ isc_eventlist_t *events);
+/*%<
+ * Remove events from a task's event queue.
+ *
+ * Notes:
+ *
+ *\li This function is equivalent to
+ *
+ *\code
+ * isc_task_unsendrange(task, sender, type, type, tag, events);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li *events is a valid list.
+ *
+ * Ensures:
+ *
+ *\li Events in the event queue of 'task' whose sender is 'sender', whose
+ * type is 'type', and whose tag is 'tag' will be dequeued and appended
+ * to *events.
+ *
+ * Returns:
+ *
+ *\li The number of events unsent.
+ */
+
+isc_result_t
+isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, void *arg);
+/*%<
+ * Send a shutdown event with action 'action' and argument 'arg' when
+ * 'task' is shutdown.
+ *
+ * Notes:
+ *
+ *\li Shutdown events are posted in LIFO order.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ *\li 'action' is a valid task action.
+ *
+ * Ensures:
+ *
+ *\li When the task is shutdown, shutdown events requested with
+ * isc_task_onshutdown() will be appended to the task's event queue.
+ *
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_SHUTTINGDOWN Task is shutting down.
+ */
+
+void
+isc_task_shutdown(isc_task_t *task);
+/*%<
+ * Shutdown 'task'.
+ *
+ * Notes:
+ *
+ *\li Shutting down a task causes any shutdown events requested with
+ * isc_task_onshutdown() to be posted (in LIFO order). The task
+ * moves into a "shutting down" mode which prevents further calls
+ * to isc_task_onshutdown().
+ *
+ *\li Trying to shutdown a task that has already been shutdown has no
+ * effect.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Any shutdown events requested with isc_task_onshutdown() have been
+ * posted (in LIFO order).
+ */
+
+void
+isc_task_destroy(isc_task_t **taskp);
+/*%<
+ * Destroy '*taskp'.
+ *
+ * Notes:
+ *
+ *\li This call is equivalent to:
+ *
+ *\code
+ * isc_task_shutdown(*taskp);
+ * isc_task_detach(taskp);
+ *\endcode
+ *
+ * Requires:
+ *
+ * '*taskp' is a valid task.
+ *
+ * Ensures:
+ *
+ *\li Any shutdown events requested with isc_task_onshutdown() have been
+ * posted (in LIFO order).
+ *
+ *\li *taskp == NULL
+ *
+ *\li If '*taskp' is the last reference to the task,
+ * all resources used by the task will be freed.
+ */
+
+void
+isc_task_setname(isc_task_t *task, const char *name, void *tag);
+/*%<
+ * Name 'task'.
+ *
+ * Notes:
+ *
+ *\li Only the first 15 characters of 'name' will be copied.
+ *
+ *\li Naming a task is currently only useful for debugging purposes.
+ *
+ * Requires:
+ *
+ *\li 'task' is a valid task.
+ */
+
+const char *
+isc_task_getname(isc_task_t *task);
+/*%<
+ * Get the name of 'task', as previously set using isc_task_setname().
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ *
+ * Returns:
+ *\li A non-NULL pointer to a null-terminated string.
+ * If the task has not been named, the string is
+ * empty.
+ *
+ */
+
+isc_nm_t *
+isc_task_getnetmgr(isc_task_t *task);
+
+void *
+isc_task_gettag(isc_task_t *task);
+/*%<
+ * Get the tag value for 'task', as previously set using isc_task_settag().
+ *
+ * Notes:
+ *\li This function is for debugging purposes only.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+void
+isc_task_setquantum(isc_task_t *task, unsigned int quantum);
+/*%<
+ * Set future 'task' quantum to 'quantum'. The current 'task' quantum will be
+ * kept for the current isc_task_run() loop, and will be changed for the next
+ * run. Therefore, the function is save to use from the event callback as it
+ * will not affect the current event loop processing.
+ */
+
+isc_result_t
+isc_task_beginexclusive(isc_task_t *task);
+/*%<
+ * Request exclusive access for 'task', which must be the calling
+ * task. Waits for any other concurrently executing tasks to finish their
+ * current event, and prevents any new events from executing in any of the
+ * tasks sharing a task manager with 'task'.
+ * It also pauses processing of network events in netmgr if it was provided
+ * when taskmgr was created.
+ *
+ * The exclusive access must be relinquished by calling
+ * isc_task_endexclusive() before returning from the current event handler.
+ *
+ * Requires:
+ *\li 'task' is the calling task.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS The current task now has exclusive access.
+ *\li #ISC_R_LOCKBUSY Another task has already requested exclusive
+ * access.
+ */
+
+void
+isc_task_endexclusive(isc_task_t *task);
+/*%<
+ * Relinquish the exclusive access obtained by isc_task_beginexclusive(),
+ * allowing other tasks to execute.
+ *
+ * Requires:
+ *\li 'task' is the calling task, and has obtained
+ * exclusive access by calling isc_task_spl().
+ */
+
+bool
+isc_task_exiting(isc_task_t *t);
+/*%<
+ * Returns true if the task is in the process of shutting down,
+ * false otherwise.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+void
+isc_task_setprivilege(isc_task_t *task, bool priv);
+/*%<
+ * Set or unset the task's "privileged" flag depending on the value of
+ * 'priv'.
+ *
+ * Under normal circumstances this flag has no effect on the task behavior,
+ * but when the task manager has been set to privileged execution mode via
+ * isc_taskmgr_setmode(), only tasks with the flag set will be executed,
+ * and all other tasks will wait until they're done. Once all privileged
+ * tasks have finished executing, the task manager resumes running
+ * non-privileged tasks.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+bool
+isc_task_getprivilege(isc_task_t *task);
+/*%<
+ * Returns the current value of the task's privilege flag.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+bool
+isc_task_privileged(isc_task_t *task);
+/*%<
+ * Returns true if the task's privilege flag is set *and* the task
+ * manager is currently in privileged mode.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+/*****
+ ***** Task Manager.
+ *****/
+
+void
+isc_taskmgr_attach(isc_taskmgr_t *, isc_taskmgr_t **);
+void
+isc_taskmgr_detach(isc_taskmgr_t **);
+/*%<
+ * Attach/detach the task manager.
+ */
+
+void
+isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode);
+isc_taskmgrmode_t
+isc_taskmgr_mode(isc_taskmgr_t *manager);
+/*%<
+ * Set/get the operating mode of the task manager. Valid modes are:
+ *
+ *\li isc_taskmgrmode_normal
+ *\li isc_taskmgrmode_privileged
+ *
+ * In privileged execution mode, only tasks that have had the "privilege"
+ * flag set via isc_task_setprivilege() can be executed. When all such
+ * tasks are complete, non-privileged tasks resume running. The task calling
+ * this function should be in task-exclusive mode; the privileged tasks
+ * will be run after isc_task_endexclusive() is called.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid task manager.
+ */
+
+void
+isc_taskmgr_setexcltask(isc_taskmgr_t *mgr, isc_task_t *task);
+/*%<
+ * Set a task which will be used for all task-exclusive operations.
+ *
+ * Requires:
+ *\li 'manager' is a valid task manager.
+ *
+ *\li 'task' is a valid task.
+ */
+
+isc_result_t
+isc_taskmgr_excltask(isc_taskmgr_t *mgr, isc_task_t **taskp);
+/*%<
+ * Attach '*taskp' to the task set by isc_taskmgr_getexcltask().
+ * This task should be used whenever running in task-exclusive mode,
+ * so as to prevent deadlock between two exclusive tasks.
+ *
+ * Requires:
+ *\li 'manager' is a valid task manager.
+ *
+ *\li taskp != NULL && *taskp == NULL
+ */
+
+#ifdef HAVE_LIBXML2
+int
+isc_taskmgr_renderxml(isc_taskmgr_t *mgr, void *writer0);
+#endif /* ifdef HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON_C
+isc_result_t
+isc_taskmgr_renderjson(isc_taskmgr_t *mgr, void *tasksobj0);
+#endif /* HAVE_JSON_C */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/taskpool.h b/lib/isc/include/isc/taskpool.h
new file mode 100644
index 0000000..cde2287
--- /dev/null
+++ b/lib/isc/include/isc/taskpool.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/taskpool.h
+ * \brief A task pool is a mechanism for sharing a small number of tasks
+ * among a large number of objects such that each object is
+ * assigned a unique task, but each task may be shared by several
+ * objects.
+ *
+ * Task pools are used to let objects that can exist in large
+ * numbers (e.g., zones) use tasks for synchronization without
+ * the memory overhead and unfair scheduling competition that
+ * could result from creating a separate task for each object.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/task.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+***** Types.
+*****/
+
+typedef struct isc_taskpool isc_taskpool_t;
+
+/*****
+***** Functions.
+*****/
+
+isc_result_t
+isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks,
+ unsigned int quantum, bool priv, isc_taskpool_t **poolp);
+/*%<
+ * Create a task pool of "ntasks" tasks, each with quantum
+ * "quantum".
+ *
+ * Requires:
+ *
+ *\li 'tmgr' is a valid task manager.
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li On success, '*taskp' points to the new task pool.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li #ISC_R_UNEXPECTED
+ */
+
+void
+isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp);
+/*%<
+ * Attach to a task from the pool. Currently the next task is chosen
+ * from the pool at random. (This may be changed in the future to
+ * something that guaratees balance.)
+ */
+
+int
+isc_taskpool_size(isc_taskpool_t *pool);
+/*%<
+ * Returns the number of tasks in the task pool 'pool'.
+ */
+
+isc_result_t
+isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size, bool priv,
+ isc_taskpool_t **targetp);
+
+/*%<
+ * If 'size' is larger than the number of tasks in the pool pointed to by
+ * 'sourcep', then a new taskpool of size 'size' is allocated, the existing
+ * tasks from are moved into it, additional tasks are created to bring the
+ * total number up to 'size', and the resulting pool is attached to
+ * 'targetp'.
+ *
+ * If 'size' is less than or equal to the tasks in pool 'source', then
+ * 'sourcep' is attached to 'targetp' without any other action being taken.
+ *
+ * In either case, 'sourcep' is detached.
+ *
+ * Requires:
+ *
+ * \li 'sourcep' is not NULL and '*source' is not NULL
+ * \li 'targetp' is not NULL and '*source' is NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*targetp' points to a valid task pool.
+ * \li On success, '*sourcep' points to NULL.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+void
+isc_taskpool_destroy(isc_taskpool_t **poolp);
+/*%<
+ * Destroy a task pool. The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/thread.h b/lib/isc/include/isc/thread.h
new file mode 100644
index 0000000..a70e2c7
--- /dev/null
+++ b/lib/isc/include/isc/thread.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <pthread.h>
+#if HAVE_THREADS_H
+#include <threads.h>
+#endif
+
+#if defined(HAVE_PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif /* if defined(HAVE_PTHREAD_NP_H) */
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+extern thread_local size_t isc_tid_v;
+
+ISC_LANG_BEGINDECLS
+
+typedef pthread_t isc_thread_t;
+typedef void *isc_threadresult_t;
+typedef void *isc_threadarg_t;
+typedef isc_threadresult_t (*isc_threadfunc_t)(isc_threadarg_t);
+
+void
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+void
+isc_thread_join(isc_thread_t thread, isc_threadresult_t *result);
+
+void
+isc_thread_yield(void);
+
+void
+isc_thread_setname(isc_thread_t thread, const char *name);
+
+#define isc_thread_self (uintptr_t) pthread_self
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/time.h b/lib/isc/include/isc/time.h
new file mode 100644
index 0000000..9c9da37
--- /dev/null
+++ b/lib/isc/include/isc/time.h
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+enum {
+ MS_PER_SEC = 1000, /*%< Milliseonds per second. */
+ US_PER_MS = 1000, /*%< Microseconds per millisecond. */
+ US_PER_SEC = 1000 * 1000, /*%< Microseconds per second. */
+ NS_PER_US = 1000, /*%< Nanoseconds per millisecond. */
+ NS_PER_MS = 1000 * 1000, /*%< Nanoseconds per microsecond. */
+ NS_PER_SEC = 1000 * 1000 * 1000, /*%< Nanoseconds per second. */
+};
+
+/***
+ *** Intervals
+ ***/
+
+/*!
+ * \brief
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+struct isc_interval {
+ unsigned int seconds;
+ unsigned int nanoseconds;
+};
+
+extern const isc_interval_t *const isc_interval_zero;
+
+/*
+ * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially
+ * more for other locales to handle longer national abbreviations when
+ * expanding strftime's %a and %b.
+ */
+#define ISC_FORMATHTTPTIMESTAMP_SIZE 50
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_interval_set(isc_interval_t *i, unsigned int seconds,
+ unsigned int nanoseconds);
+/*%<
+ * Set 'i' to a value representing an interval of 'seconds' seconds and
+ * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
+ * isc_time_subtract().
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+bool
+isc_interval_iszero(const isc_interval_t *i);
+/*%<
+ * Returns true iff. 'i' is the zero interval.
+ *
+ * Requires:
+ *
+ *\li 'i' is a valid pointer.
+ */
+
+unsigned int
+isc_interval_ms(const isc_interval_t *i);
+/*%<
+ * Returns interval 'i' expressed as a number of milliseconds.
+ *
+ * Requires:
+ *
+ *\li 'i' is a valid pointer.
+ */
+
+/***
+ *** Absolute Times
+ ***/
+
+/*%
+ * The contents of this structure are private, and MUST NOT be accessed
+ * directly by callers.
+ *
+ * The contents are exposed only to allow callers to avoid dynamic allocation.
+ */
+
+struct isc_time {
+ unsigned int seconds;
+ unsigned int nanoseconds;
+};
+
+extern const isc_time_t *const isc_time_epoch;
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
+/*%<
+ * Set 't' to a value which represents the given number of seconds and
+ * nanoseconds since 00:00:00 January 1, 1970, UTC.
+ *
+ * Notes:
+ *\li The Unix version of this call is equivalent to:
+ *\code
+ * isc_time_settoepoch(t);
+ * isc_interval_set(i, seconds, nanoseconds);
+ * isc_time_add(t, i, t);
+ *\endcode
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *\li nanoseconds < 1000000000.
+ */
+
+void
+isc_time_settoepoch(isc_time_t *t);
+/*%<
+ * Set 't' to the time of the epoch.
+ *
+ * Notes:
+ *\li The date of the epoch is platform-dependent.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+bool
+isc_time_isepoch(const isc_time_t *t);
+/*%<
+ * Returns true iff. 't' is the epoch ("time zero").
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_now(isc_time_t *t);
+/*%<
+ * Set 't' to the current absolute time.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The time from the system is too large to be represented
+ * in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_now_hires(isc_time_t *t);
+/*%<
+ * Set 't' to the current absolute time. Uses higher resolution clocks
+ * recommended when microsecond accuracy is required.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The time from the system is too large to be represented
+ * in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i);
+/*%<
+ * Set *t to the current absolute time + i.
+ *
+ * Note:
+ *\li This call is equivalent to:
+ *
+ *\code
+ * isc_time_now(t);
+ * isc_time_add(t, i, t);
+ *\endcode
+ *
+ * Requires:
+ *
+ *\li 't' and 'i' are valid pointers.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ * Getting the time from the system failed.
+ *\li Out of range
+ * The interval added to the time from the system is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2);
+/*%<
+ * Compare the times referenced by 't1' and 't2'
+ *
+ * Requires:
+ *
+ *\li 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *
+ *\li -1 t1 < t2 (comparing times, not pointers)
+ *\li 0 t1 = t2
+ *\li 1 t1 > t2
+ */
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
+/*%<
+ * Add 'i' to 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *\li 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ * The interval added to the time is too large to
+ * be represented in the current definition of isc_time_t.
+ */
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result);
+/*%<
+ * Subtract 'i' from 't', storing the result in 'result'.
+ *
+ * Requires:
+ *
+ *\li 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ * The interval is larger than the time since the epoch.
+ */
+
+uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2);
+/*%<
+ * Find the difference in microseconds between time t1 and time t2.
+ * t2 is the subtrahend of t1; ie, difference = t1 - t2.
+ *
+ * Requires:
+ *
+ *\li 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *\li The difference of t1 - t2, or 0 if t1 <= t2.
+ */
+
+uint32_t
+isc_time_seconds(const isc_time_t *t);
+/*%<
+ * Return the number of seconds since the epoch stored in a time structure.
+ *
+ * Requires:
+ *
+ *\li 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp);
+/*%<
+ * Ensure the number of seconds in an isc_time_t is representable by a time_t.
+ *
+ * Notes:
+ *\li The number of seconds stored in an isc_time_t might be larger
+ * than the number of seconds a time_t is able to handle. Since
+ * time_t is mostly opaque according to the ANSI/ISO standard
+ * (essentially, all you can be sure of is that it is an arithmetic type,
+ * not even necessarily integral), it can be tricky to ensure that
+ * the isc_time_t is in the range a time_t can handle. Use this
+ * function in place of isc_time_seconds() any time you need to set a
+ * time_t from an isc_time_t.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Returns:
+ *\li Success
+ *\li Out of range
+ */
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t);
+/*%<
+ * Return the number of nanoseconds stored in a time structure.
+ *
+ * Notes:
+ *\li This is the number of nanoseconds in excess of the number
+ * of seconds since the epoch; it will always be less than one
+ * full second.
+ *
+ * Requires:
+ *\li 't' is a valid pointer.
+ *
+ * Ensures:
+ *\li The returned value is less than 1*10^9.
+ */
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "30-Aug-2000 04:06:47.997" and the local time zone.
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+isc_result_t
+isc_time_parsehttptimestamp(char *input, isc_time_t *t);
+/*%<
+ * Parse the time in 'input' into the isc_time_t pointed to by 't',
+ * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ *
+ * Requires:
+ *\li 'buf' and 't' are not NULL.
+ */
+
+void
+isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601Lus(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.ssssss"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.ssssssZ"
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+void
+isc_time_formatshorttimestamp(const isc_time_t *t, char *buf, unsigned int len);
+/*%<
+ * Format the time 't' into the buffer 'buf' of length 'len',
+ * using the format "yyyymmddhhmmsssss" useful for file timestamping.
+ * If the text does not fit in the buffer, the result is indeterminate,
+ * but is always guaranteed to be null terminated.
+ *
+ * Requires:
+ *\li 'len' > 0
+ *\li 'buf' points to an array of at least len chars
+ *
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/timer.h b/lib/isc/include/isc/timer.h
new file mode 100644
index 0000000..815cf42
--- /dev/null
+++ b/lib/isc/include/isc/timer.h
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file isc/timer.h
+ * \brief Provides timers which are event sources in the task system.
+ *
+ * Three types of timers are supported:
+ *
+ *\li 'ticker' timers generate a periodic tick event.
+ *
+ *\li 'once' timers generate an idle timeout event if they are idle for too
+ * long, and generate a life timeout event if their lifetime expires.
+ * They are used to implement both (possibly expiring) idle timers and
+ * 'one-shot' timers.
+ *
+ *\li 'limited' timers generate a periodic tick event until they reach
+ * their lifetime when they generate a life timeout event.
+ *
+ *\li 'inactive' timers generate no events.
+ *
+ * Timers can change type. It is typical to create a timer as
+ * an 'inactive' timer and then change it into a 'ticker' or
+ * 'once' timer.
+ *
+ *\li MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ * Clients of this module must not be holding a timer's task's lock when
+ * making a call that affects that timer. Failure to follow this rule
+ * can result in deadlock.
+ * The caller must ensure that isc_timermgr_destroy() is called only
+ * once for a given manager.
+ *
+ * \li Reliability:
+ * No anticipated impact.
+ *
+ * \li Resources:
+ * TBS
+ *
+ * \li Security:
+ * No anticipated impact.
+ *
+ * \li Standards:
+ * None.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/event.h>
+#include <isc/eventclass.h>
+#include <isc/lang.h>
+#include <isc/time.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Types
+ ***/
+
+/*% Timer Type */
+typedef enum {
+ isc_timertype_undefined = -1, /*%< Undefined */
+ isc_timertype_ticker = 0, /*%< Ticker */
+ isc_timertype_once = 1, /*%< Once */
+ isc_timertype_limited = 2, /*%< Limited */
+ isc_timertype_inactive = 3 /*%< Inactive */
+} isc_timertype_t;
+
+typedef struct isc_timerevent isc_timerevent_t;
+
+struct isc_timerevent {
+ struct isc_event common;
+ isc_time_t due;
+ ISC_LINK(isc_timerevent_t) ev_timerlink;
+};
+
+#define ISC_TIMEREVENT_FIRSTEVENT (ISC_EVENTCLASS_TIMER + 0)
+#define ISC_TIMEREVENT_TICK (ISC_EVENTCLASS_TIMER + 1)
+#define ISC_TIMEREVENT_IDLE (ISC_EVENTCLASS_TIMER + 2)
+#define ISC_TIMEREVENT_LIFE (ISC_EVENTCLASS_TIMER + 3)
+#define ISC_TIMEREVENT_LASTEVENT (ISC_EVENTCLASS_TIMER + 65535)
+
+/***
+ *** Timer and Timer Manager Functions
+ ***
+ *** Note: all Ensures conditions apply only if the result is success for
+ *** those functions which return an isc_result_t.
+ ***/
+
+isc_result_t
+isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_timer_t **timerp);
+/*%<
+ * Create a new 'type' timer managed by 'manager'. The timers parameters
+ * are specified by 'expires' and 'interval'. Events will be posted to
+ * 'task' and when dispatched 'action' will be called with 'arg' as the
+ * arg value. The new timer is returned in 'timerp'.
+ *
+ * Notes:
+ *
+ *\li For ticker timers, the timer will generate a 'tick' event every
+ * 'interval' seconds. The value of 'expires' is ignored.
+ *
+ *\li For once timers, 'expires' specifies the time when a life timeout
+ * event should be generated. If 'expires' is 0 (the epoch), then no life
+ * timeout will be generated. 'interval' specifies how long the timer
+ * can be idle before it generates an idle timeout. If 0, then no
+ * idle timeout will be generated.
+ *
+ *\li If 'expires' is NULL, the epoch will be used.
+ *
+ * If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid manager
+ *
+ *\li 'task' is a valid task
+ *
+ *\li 'action' is a valid action
+ *
+ *\li 'expires' points to a valid time, or is NULL.
+ *
+ *\li 'interval' points to a valid interval, or is NULL.
+ *
+ *\li type == isc_timertype_inactive ||
+ * ('expires' and 'interval' are not both 0)
+ *
+ *\li 'timerp' is a valid pointer, and *timerp == NULL
+ *
+ * Ensures:
+ *
+ *\li '*timerp' is attached to the newly created timer
+ *
+ *\li The timer is attached to the task
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+isc_result_t
+isc_timer_reset(isc_timer_t *timer, isc_timertype_t type,
+ const isc_time_t *expires, const isc_interval_t *interval,
+ bool purge);
+/*%<
+ * Change the timer's type, expires, and interval values to the given
+ * values. If 'purge' is TRUE, any pending events from this timer
+ * are purged from its task's event queue.
+ *
+ * Notes:
+ *
+ *\li If 'expires' is NULL, the epoch will be used.
+ *
+ *\li If 'interval' is NULL, the zero interval will be used.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid timer
+ *
+ *\li The same requirements that isc_timer_create() imposes on 'type',
+ * 'expires' and 'interval' apply.
+ *
+ * Ensures:
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li No memory
+ *\li Unexpected error
+ */
+
+isc_result_t
+isc_timer_touch(isc_timer_t *timer);
+/*%<
+ * Set the last-touched time of 'timer' to the current time.
+ *
+ * Requires:
+ *
+ *\li 'timer' is a valid once timer.
+ *
+ * Ensures:
+ *
+ *\li An idle timeout will not be generated until at least Now + the
+ * timer's interval if 'timer' is a once timer with a non-zero
+ * interval.
+ *
+ * Returns:
+ *
+ *\li Success
+ *\li Unexpected error
+ */
+
+void
+isc_timer_destroy(isc_timer_t **timerp);
+/*%<
+ * Destroy *timerp.
+ *
+ * Requires:
+ *
+ *\li 'timerp' points to a valid timer.
+ *
+ * Ensures:
+ *
+ *\li *timerp is NULL.
+ *
+ *\code
+ * The timer will be shutdown
+ *
+ * The timer will detach from its task
+ *
+ * All resources used by the timer have been freed
+ *
+ * Any events already posted by the timer will be purged.
+ * Therefore, if isc_timer_destroy() is called in the context
+ * of the timer's task, it is guaranteed that no more
+ * timer event callbacks will run after the call.
+ *
+ * If this function is called from the timer event callback
+ * the event itself must be destroyed before the timer
+ * itself.
+ *\endcode
+ */
+
+isc_timertype_t
+isc_timer_gettype(isc_timer_t *timer);
+/*%<
+ * Return the timer type.
+ *
+ * Requires:
+ *
+ *\li 'timer' to be a valid timer.
+ */
+
+void
+isc_timermgr_poke(isc_timermgr_t *m);
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/tls.h b/lib/isc/include/isc/tls.h
new file mode 100644
index 0000000..efffffb
--- /dev/null
+++ b/lib/isc/include/isc/tls.h
@@ -0,0 +1,587 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <isc/mem.h>
+#include <isc/region.h>
+#include <isc/result.h>
+#include <isc/types.h>
+
+typedef struct ssl_ctx_st isc_tlsctx_t;
+typedef struct ssl_st isc_tls_t;
+
+typedef struct x509_store_st isc_tls_cert_store_t;
+
+void
+isc_tlsctx_free(isc_tlsctx_t **ctpx);
+/*%<
+ * Free a TLS client or server context.
+ *
+ * Requires:
+ *\li 'ctxp' != NULL and '*ctxp' != NULL.
+ */
+
+void
+isc_tlsctx_attach(isc_tlsctx_t *src, isc_tlsctx_t **ptarget);
+/*%<
+ * Attach to the TLS context.
+ *
+ * Requires:
+ *\li 'src' != NULL;
+ *\li 'ptarget' != NULL;
+ *\li '*ptarget' == NULL.
+ */
+
+isc_result_t
+isc_tlsctx_createserver(const char *keyfile, const char *certfile,
+ isc_tlsctx_t **ctxp);
+/*%<
+ * Set up a TLS server context, using the key and certificate specified in
+ * 'keyfile' and 'certfile', or a self-generated ephemeral key and
+ * certificdate if both 'keyfile' and 'certfile' are NULL.
+ *
+ * Requires:
+ *\li 'ctxp' != NULL and '*ctxp' == NULL.
+ *\li 'keyfile' and 'certfile' are either both NULL or both non-NULL.
+ */
+
+isc_result_t
+isc_tlsctx_createclient(isc_tlsctx_t **ctxp);
+/*%<
+ * Set up a TLS client context.
+ *
+ * Requires:
+ *\li 'ctxp' != NULL and '*ctxp' == NULL.
+ */
+
+isc_result_t
+isc_tlsctx_load_certificate(isc_tlsctx_t *ctx, const char *keyfile,
+ const char *certfile);
+/*%<
+ * Load a TLS certificate into a TLS context.
+ *
+ * Requires:
+ *\li 'ctx' != NULL;
+ *\li 'keyfile' and 'certfile' are both non-NULL.
+ */
+
+typedef enum isc_tls_protocol_version {
+ /* these must be the powers of two */
+ ISC_TLS_PROTO_VER_1_2 = 1 << 0,
+ ISC_TLS_PROTO_VER_1_3 = 1 << 1,
+ ISC_TLS_PROTO_VER_UNDEFINED,
+} isc_tls_protocol_version_t;
+
+void
+isc_tlsctx_set_protocols(isc_tlsctx_t *ctx, const uint32_t tls_versions);
+/*%<
+ * Sets the supported TLS protocol versions via the 'tls_versions' bit
+ * set argument (see `isc_tls_protocol_version_t` enum for the
+ * expected values).
+ *
+ * Requires:
+ *\li 'ctx' != NULL;
+ *\li 'tls_versions' != 0.
+ */
+
+bool
+isc_tls_protocol_supported(const isc_tls_protocol_version_t tls_ver);
+/*%<
+ * Check in runtime that the specified TLS protocol versions is supported.
+ */
+
+isc_tls_protocol_version_t
+isc_tls_protocol_name_to_version(const char *name);
+/*%<
+ * Convert the protocol version string into the version of
+ * 'isc_tls_protocol_version_t' type.
+ * Requires:
+ *\li 'name' != NULL.
+ */
+
+bool
+isc_tlsctx_load_dhparams(isc_tlsctx_t *ctx, const char *dhparams_file);
+/*%<
+ * Load Diffie-Hellman parameters file and apply it to the given TLS context
+ * 'ctx'.
+ *
+ * Requires:
+ * \li 'ctx' != NULL;
+ * \li 'dhaprams_file' a valid pointer to a non empty string.
+ */
+
+bool
+isc_tls_cipherlist_valid(const char *cipherlist);
+/*%<
+ * Check if cipher list string is valid.
+ *
+ * Requires:
+ * \li 'cipherlist' a valid pointer to a non empty string.
+ */
+
+void
+isc_tlsctx_set_cipherlist(isc_tlsctx_t *ctx, const char *cipherlist);
+/*%<
+ * Set cipher list string for on the given TLS context 'ctx'.
+ *
+ * Requires:
+ * \li 'ctx' != NULL;
+ * \li 'cipherlist' a valid pointer to a non empty string.
+ */
+
+void
+isc_tlsctx_prefer_server_ciphers(isc_tlsctx_t *ctx, const bool prefer);
+/*%<
+ * Make the given TLS context 'ctx' to prefer or to not prefer
+ * server side ciphers during the ciphers negotiation.
+ *
+ * Requires:
+ * \li 'ctx' != NULL.
+ */
+
+void
+isc_tlsctx_session_tickets(isc_tlsctx_t *ctx, const bool use);
+/*%<
+ * Enable/Disable stateless session resumptions tickets on the given
+ * TLS context 'ctx' (see RFC5077).
+ *
+ * Requires:
+ * \li 'ctx' != NULL.
+ */
+
+isc_tls_t *
+isc_tls_create(isc_tlsctx_t *ctx);
+/*%<
+ * Set up the structure to hold data for a new TLS connection.
+ *
+ * Requires:
+ *\li 'ctx' != NULL.
+ */
+
+void
+isc_tls_free(isc_tls_t **tlsp);
+/*%<
+ * Free a TLS structure.
+ *
+ * Requires:
+ *\li 'tlsp' != NULL and '*tlsp' != NULL.
+ */
+
+const char *
+isc_tls_verify_peer_result_string(isc_tls_t *tls);
+/*%<
+ * Return a user readable description of a remote peer's certificate
+ * validation.
+ *
+ * Requires:
+ *\li 'tls' != NULL.
+ */
+
+#if HAVE_LIBNGHTTP2
+void
+isc_tlsctx_enable_http2client_alpn(isc_tlsctx_t *ctx);
+void
+isc_tlsctx_enable_http2server_alpn(isc_tlsctx_t *ctx);
+/*%<
+ * Enable HTTP/2 Application Layer Protocol Negotation for 'ctx'.
+ *
+ * Requires:
+ *\li 'ctx' is not NULL.
+ */
+#endif /* HAVE_LIBNGHTTP2 */
+
+void
+isc_tls_get_selected_alpn(isc_tls_t *tls, const unsigned char **alpn,
+ unsigned int *alpnlen);
+
+#define ISC_TLS_DOT_PROTO_ALPN_ID "dot"
+#define ISC_TLS_DOT_PROTO_ALPN_ID_LEN 3
+
+void
+isc_tlsctx_enable_dot_client_alpn(isc_tlsctx_t *ctx);
+void
+isc_tlsctx_enable_dot_server_alpn(isc_tlsctx_t *ctx);
+/*%<
+ * Enable DoT Application Layer Protocol Negotation for 'ctx'.
+ *
+ * Requires:
+ *\li 'ctx' is not NULL.
+ */
+
+isc_result_t
+isc_tlsctx_enable_peer_verification(isc_tlsctx_t *ctx, const bool is_server,
+ isc_tls_cert_store_t *store,
+ const char *hostname,
+ bool hostname_ignore_subject);
+/*%<
+ * Enable peer certificate and, optionally, hostname (for client contexts)
+ * verification.
+ *
+ * Requires:
+ *\li 'ctx' is not NULL;
+ *\li 'store' is not NULL.
+ */
+
+isc_result_t
+isc_tlsctx_load_client_ca_names(isc_tlsctx_t *ctx, const char *ca_bundle_file);
+/*%<
+ * Load the list of CA-certificate names from a CA-bundle file to
+ * send by the server to a client when requesting a peer certificate.
+ * Usually used in conjunction with
+ * isc_tlsctx_enable_peer_validation().
+ *
+ * Requires:
+ *\li 'ctx' is not NULL;
+ *\li 'ca_bundle_file' is not NULL.
+ */
+
+isc_result_t
+isc_tls_cert_store_create(const char *ca_bundle_filename,
+ isc_tls_cert_store_t **pstore);
+/*%<
+ * Create X509 certificate store. The 'ca_bundle_filename' might be
+ * 'NULL' or an empty string, which means use the default system wide
+ * bundle/directory.
+ *
+ * Requires:
+ *\li 'pstore' is a valid pointer to a pointer containing 'NULL'.
+ */
+
+void
+isc_tls_cert_store_free(isc_tls_cert_store_t **pstore);
+/*%<
+ * Free X509 certificate store.
+ *
+ * Requires:
+ *\li 'pstore' is a valid pointer to a pointer containing a non-'NULL' value.
+ */
+
+typedef struct isc_tlsctx_client_session_cache isc_tlsctx_client_session_cache_t;
+/*%<
+ * TLS client session cache is an object which allows efficient
+ * storing and retrieval of previously saved TLS sessions so that they
+ * can be resumed. This object is supposed to be a foundation for
+ * implementing TLS session resumption - a standard technique to
+ * reduce the cost of re-establishing a connection to the remote
+ * server endpoint.
+ *
+ * OpenSSL does server-side TLS session caching transparently by
+ * default. However, on the client-side, a TLS session to resume must
+ * be manually specified when establishing the TLS connection. The TLS
+ * client session cache is precisely the foundation for that.
+ *
+ * The cache has been designed to have the following characteristics:
+ *
+ * - Fixed maximal number of entries to not keep too many obsolete
+ * sessions within the cache;
+ *
+ * - The cache is indexed by character string keys. Each string is a
+ * key representing a remote endpoint (unique remote endpoint name,
+ * e.g. combination of the remote IP address and port);
+ *
+ * - Least Recently Used (LRU) cache replacement policy while allowing
+ * easy removal of obsolete entries;
+ *
+ * - Ability to store multiple TLS sessions associated with the given
+ * key (remote endpoint name). This characteristic is important if
+ * multiple connections to the same remote server can be established;
+ *
+ * - Ability to efficiently retrieve the most recent TLS sessions
+ * associated with the key (remote endpoint name).
+ *
+ * Because of these characteristics, the cache will end up having the
+ * necessary amount of resumable TLS session parameters to the most
+ * used remote endpoints ("hot entries") after a short period of
+ * initial use ("warmup").
+ *
+ * Attempting to resume TLS sessions is an optimisation, which is not
+ * guaranteed to succeed because it requires the same session to be
+ * present in the server session caches. If it is not the case, the
+ * usual handshake procedure takes place. However, when session
+ * resumption is successful, it reduces the amount of the
+ * computational resources required as well as the amount of data to
+ * be transmitted when (re)establishing the connection. Also, it
+ * reduces round trip time (by reducing the number of packets to
+ * transmit).
+ *
+ * This optimisation is important in the context of DNS because the
+ * amount of data within the full handshake messages might be
+ * comparable to or surpass the size of a typical DNS message.
+ */
+
+void
+isc_tlsctx_client_session_cache_create(
+ isc_mem_t *mctx, isc_tlsctx_t *ctx, const size_t max_entries,
+ isc_tlsctx_client_session_cache_t **cachep);
+/*%<
+ * Create a new TLS client session cache object.
+ *
+ * Requires:
+ *\li 'mctx' is a valid memory context object;
+ *\li 'ctx' is a valid TLS context object;
+ *\li 'max_entries' is a positive number;
+ *\li 'cachep' is a valid pointer to a pointer which must be equal to NULL.
+ */
+
+void
+isc_tlsctx_client_session_cache_attach(
+ isc_tlsctx_client_session_cache_t *source,
+ isc_tlsctx_client_session_cache_t **targetp);
+/*%<
+ * Create a reference to the TLS client session cache object.
+ *
+ * Requires:
+ *\li 'source' is a valid TLS client session cache object;
+ *\li 'targetp' is a valid pointer to a pointer which must equal NULL.
+ */
+
+void
+isc_tlsctx_client_session_cache_detach(
+ isc_tlsctx_client_session_cache_t **cachep);
+/*%<
+ * Remove a reference to the TLS client session cache object.
+ *
+ * Requires:
+ *\li 'cachep' is a pointer to a pointer to a valid TLS client session cache
+ *object.
+ */
+
+void
+isc_tlsctx_client_session_cache_keep(isc_tlsctx_client_session_cache_t *cache,
+ char *remote_peer_name, isc_tls_t *tls);
+/*%<
+ * Add a resumable TLS client session within 'tls' to the TLS client
+ * session cache object 'cache' and associate it with
+ * 'remote_server_name' string. Also, the oldest entry from the cache
+ * might get removed if the cache is full.
+ *
+ * Requires:
+ *\li 'cache' is a pointer to a valid TLS client session cache object;
+ *\li 'remote_peer_name' is a pointer to a non empty character string;
+ *\li 'tls' is a valid, non-'NULL' pointer to a TLS connection state object.
+ */
+
+void
+isc_tlsctx_client_session_cache_keep_sockaddr(
+ isc_tlsctx_client_session_cache_t *cache, isc_sockaddr_t *remote_peer,
+ isc_tls_t *tls);
+/*%<
+ * The same as 'isc_tlsctx_client_session_cache_keep()', but uses a
+ * 'isc_sockaddr_t' as a key, instead of a character string.
+ *
+ * Requires:
+ *\li 'remote_peer' is a valid, non-'NULL', pointer to an 'isc_sockaddr_t'
+ *object.
+ */
+
+void
+isc_tlsctx_client_session_cache_reuse(isc_tlsctx_client_session_cache_t *cache,
+ char *remote_server_name, isc_tls_t *tls);
+/*%
+ * Try to restore a previously stored TLS session denoted by a remote
+ * server name as a key ('remote_server_name') into the given TLS
+ * connection state object ('tls'). The successfully restored session
+ * gets removed from the cache.
+ *
+ * Requires:
+ *\li 'cache' is a pointer to a valid TLS client session cache object;
+ *\li 'remote_peer_name' is a pointer to a non empty character string;
+ *\li 'tls' is a valid, non-'NULL' pointer to a TLS connection state object.
+ */
+
+void
+isc_tlsctx_client_session_cache_reuse_sockaddr(
+ isc_tlsctx_client_session_cache_t *cache, isc_sockaddr_t *remote_peer,
+ isc_tls_t *tls);
+/*%<
+ * The same as 'isc_tlsctx_client_session_cache_reuse()', but uses a
+ * 'isc_sockaddr_t' as a key, instead of a character string.
+ *
+ * Requires:
+ *\li 'remote_peer' is a valid, non-'NULL' pointer to an 'isc_sockaddr_t'
+ *object.
+ */
+
+const isc_tlsctx_t *
+isc_tlsctx_client_session_cache_getctx(isc_tlsctx_client_session_cache_t *cache);
+/*%<
+ * Returns a TLS context associated with the given TLS client
+ * session cache object. The function is intended to be used to
+ * implement the sanity checks ('INSIST()'s and 'REQUIRE()'s).
+ *
+ * Requires:
+ *\li 'cache' is a pointer to a valid TLS client session cache object.
+ */
+
+#define ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE (150)
+/*%<
+ * The default maximum size of a TLS client session cache. The value
+ * should be large enough to hold enough sessions to successfully
+ * re-establish connections to the most remote TLS servers, but not
+ * too big to avoid keeping too much obsolete sessions.
+ */
+
+typedef struct isc_tlsctx_cache isc_tlsctx_cache_t;
+/*%<
+ * The TLS context cache is an object which allows retrieving a
+ * previously created TLS context based on the following tuple:
+ *
+ * 1. The name of a TLS entry, as defined in the configuration file;
+ * 2. A transport type. Currently, only TLS (DoT) and HTTPS (DoH) are
+ * supported;
+ * 3. An IP address family (AF_INET or AF_INET6).
+ *
+ * There are multiple uses for this object:
+ *
+ * First, it allows reuse of client-side contexts during zone transfers.
+ * That, in turn, allows use of session caches associated with these
+ * contexts, which enables TLS session resumption, making establishment
+ * of XoT connections faster and computationally cheaper.
+ *
+ * Second, it can be extended to be used as storage for TLS context related
+ * data, as defined in 'tls' statements in the configuration file (for
+ * example, CA-bundle intermediate certificate storage, client-side contexts
+ * with pre-loaded certificates in a case of Mutual TLS, etc). This will
+ * be used to implement Strict/Mutual TLS.
+ *
+ * Third, it avoids creating an excessive number of server-side TLS
+ * contexts, which might help to reduce the number of contexts
+ * created during server initialisation and reconfiguration.
+ */
+
+typedef enum {
+ isc_tlsctx_cache_none = 0,
+ isc_tlsctx_cache_tls,
+ isc_tlsctx_cache_https,
+ isc_tlsctx_cache_count
+} isc_tlsctx_cache_transport_t;
+/*%< TLS context cache transport type values. */
+
+void
+isc_tlsctx_cache_create(isc_mem_t *mctx, isc_tlsctx_cache_t **cachep);
+/*%<
+ * Create a new TLS context cache object.
+ *
+ * Requires:
+ *\li 'mctx' is a valid memory context;
+ *\li 'cachep' is a valid pointer to a pointer which must be equal to NULL.
+ */
+
+void
+isc_tlsctx_cache_attach(isc_tlsctx_cache_t *source,
+ isc_tlsctx_cache_t **targetp);
+/*%<
+ * Create a reference to the TLS context cache object.
+ *
+ * Requires:
+ *\li 'source' is a valid TLS context cache object;
+ *\li 'targetp' is a valid pointer to a pointer which must equal NULL.
+ */
+
+void
+isc_tlsctx_cache_detach(isc_tlsctx_cache_t **cachep);
+/*%<
+ * Remove a reference to the TLS context cache object.
+ *
+ * Requires:
+ *\li 'cachep' is a pointer to a pointer to a valid TLS
+ * context cache object.
+ */
+
+isc_result_t
+isc_tlsctx_cache_add(
+ isc_tlsctx_cache_t *cache, const char *name,
+ const isc_tlsctx_cache_transport_t transport, const uint16_t family,
+ isc_tlsctx_t *ctx, isc_tls_cert_store_t *store,
+ isc_tlsctx_client_session_cache_t *client_sess_cache,
+ isc_tlsctx_t **pfound, isc_tls_cert_store_t **pfound_store,
+ isc_tlsctx_client_session_cache_t **pfound_client_sess_cache);
+/*%<
+ *
+ * Add a new TLS context and its associated data to the TLS context
+ * cache. 'pfound' is an optional pointer, which can be used to
+ * retrieve an already existing TLS context object in a case it
+ * exists.
+ *
+ * The passed certificates store object ('store') possession is
+ * transferred to the cache object in a case of success. In some cases
+ * it might be destroyed immediately upon the call completion.
+ *
+ * The possession of the passed TLS client session cache
+ * ('client_sess_cache') is also transferred to the cache object in a
+ * case of success.
+ *
+ * Requires:
+ *\li 'cache' is a valid pointer to a TLS context cache object;
+ *\li 'name' is a valid pointer to a non-empty string;
+ *\li 'transport' is a valid transport identifier (currently only
+ * TLS/DoT and HTTPS/DoH are supported);
+ *\li 'family' - either 'AF_INET' or 'AF_INET6';
+ *\li 'ctx' - a valid pointer to a valid TLS context object;
+ *\li 'store' - a valid pointer to a valid TLS certificates store object or
+ * 'NULL';
+ *\li 'client_sess_cache' - a valid pointer to a valid TLS client sessions
+ *cache object or 'NULL.
+ *
+ * Returns:
+ *\li #ISC_R_EXISTS - node of the same key already exists;
+ *\li #ISC_R_SUCCESS - the new entry has been added successfully.
+ */
+
+isc_result_t
+isc_tlsctx_cache_find(
+ isc_tlsctx_cache_t *cache, const char *name,
+ const isc_tlsctx_cache_transport_t transport, const uint16_t family,
+ isc_tlsctx_t **pctx, isc_tls_cert_store_t **pstore,
+ isc_tlsctx_client_session_cache_t **pfound_client_sess_cache);
+/*%<
+ * Look up a TLS context and its associated data in the TLS context cache.
+ *
+ * Requires:
+ *\li 'cache' is a valid pointer to a TLS context cache object;
+ *\li 'name' is a valid pointer to a non empty string;
+ *\li 'transport' - a valid transport identifier (currently only
+ * TLS/DoT and HTTPS/DoH are supported;
+ *\li 'family' - either 'AF_INET' or 'AF_INET6';
+ *\li 'pctx' - a valid pointer to a non-NULL pointer;
+ *\li 'pstore' - a valid pointer to a non-NULL pointer or 'NULL'.
+ *\li 'pfound_client_sess_cache' - a valid pointer to a non-NULL pointer or
+ *'NULL'.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS - the context has been found;
+ *\li #ISC_R_NOTFOUND - the context has not been found. In such a case,
+ * 'pstore' still might get initialised as there is one to many
+ * relation between stores and contexts.
+ */
+
+void
+isc_tlsctx_set_random_session_id_context(isc_tlsctx_t *ctx);
+/*%<
+ * Set context within which session can be reused to a randomly
+ * generated value. This one is used for TLS session resumption using
+ * session IDs. See OpenSSL documentation for
+ * 'SSL_CTX_set_session_id_context()'.
+ *
+ * It might be worth noting that usually session ID contexts are kept
+ * static for an application and particular certificate
+ * combination. However, for the cases when exporting server side TLS
+ * session cache to/loading from external memory is not required, we
+ * might use random IDs just fine. See,
+ * e.g. 'ngx_ssl_session_id_context()' in NGINX for an example of how
+ * a session ID might be obtained.
+ *
+ * Requires:
+ *\li 'ctx' - a valid non-NULL pointer;
+ */
diff --git a/lib/isc/include/isc/tm.h b/lib/isc/include/isc/tm.h
new file mode 100644
index 0000000..58feec4
--- /dev/null
+++ b/lib/isc/include/isc/tm.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*! \file isc/tm.h
+ * Provides portable conversion routines for struct tm.
+ */
+#include <time.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+time_t
+isc_tm_timegm(struct tm *tm);
+/*
+ * Convert a tm structure to time_t, using UTC rather than the local
+ * time zone.
+ */
+
+char *
+isc_tm_strptime(const char *buf, const char *fmt, struct tm *tm);
+/*
+ * Parse a formatted date string into struct tm.
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h
new file mode 100644
index 0000000..7e0fc02
--- /dev/null
+++ b/lib/isc/include/isc/types.h
@@ -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.
+ */
+
+#pragma once
+
+#include <isc/result.h>
+
+/*! \file isc/types.h
+ * \brief
+ * OS-specific types, from the OS-specific include directories.
+ */
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/offset.h>
+
+/*
+ * XXXDCL This is just for ISC_LIST and ISC_LINK, but gets all of the other
+ * list macros too.
+ */
+#include <isc/list.h>
+
+/* Core Types. Alphabetized by defined type. */
+
+typedef struct isc_astack isc_astack_t; /*%< Array-based fast stack */
+typedef struct isc_appctx isc_appctx_t; /*%< Application context */
+typedef struct isc_buffer isc_buffer_t; /*%< Buffer */
+typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */
+typedef struct isc_constregion isc_constregion_t; /*%< Const region */
+typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region
+ */
+typedef struct isc_counter isc_counter_t; /*%< Counter */
+typedef struct isc_event isc_event_t; /*%< Event */
+typedef ISC_LIST(isc_event_t) isc_eventlist_t; /*%< Event List */
+typedef unsigned int isc_eventtype_t; /*%< Event Type */
+typedef struct isc_hash isc_hash_t; /*%< Hash */
+typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */
+typedef void(isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function
+ */
+typedef struct isc_httpdmgr isc_httpdmgr_t; /*%< HTTP manager */
+typedef struct isc_httpdurl isc_httpdurl_t; /*%< HTTP URL */
+typedef void(isc_httpdondestroy_t)(void *); /*%< Callback on destroying httpd */
+typedef struct isc_interface isc_interface_t; /*%< Interface */
+typedef struct isc_interfaceiter isc_interfaceiter_t; /*%< Interface Iterator */
+typedef struct isc_interval isc_interval_t; /*%< Interval */
+typedef struct isc_lex isc_lex_t; /*%< Lex */
+typedef struct isc_log isc_log_t; /*%< Log */
+typedef struct isc_logcategory isc_logcategory_t; /*%< Log Category */
+typedef struct isc_logconfig isc_logconfig_t; /*%< Log Configuration */
+typedef struct isc_logmodule isc_logmodule_t; /*%< Log Module */
+typedef struct isc_mem isc_mem_t; /*%< Memory */
+typedef struct isc_mempool isc_mempool_t; /*%< Memory Pool */
+typedef struct isc_netaddr isc_netaddr_t; /*%< Net Address */
+typedef struct isc_netprefix isc_netprefix_t; /*%< Net Prefix */
+typedef struct isc_nm isc_nm_t; /*%< Network manager */
+typedef struct isc_nmsocket isc_nmsocket_t; /*%< Network manager socket */
+typedef struct isc_nmhandle isc_nmhandle_t; /*%< Network manager handle */
+typedef struct isc_portset isc_portset_t; /*%< Port Set */
+typedef struct isc_quota isc_quota_t; /*%< Quota */
+typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */
+typedef struct isc_region isc_region_t; /*%< Region */
+typedef uint64_t isc_resourcevalue_t; /*%< Resource Value */
+typedef struct isc_rwlock isc_rwlock_t; /*%< Read Write Lock */
+typedef struct isc_sockaddr isc_sockaddr_t; /*%< Socket Address */
+typedef ISC_LIST(isc_sockaddr_t) isc_sockaddrlist_t; /*%< Socket Address List
+ * */
+typedef struct isc_stats isc_stats_t; /*%< Statistics */
+typedef int_fast64_t isc_statscounter_t;
+typedef struct isc_symtab isc_symtab_t; /*%< Symbol Table */
+typedef struct isc_task isc_task_t; /*%< Task */
+typedef ISC_LIST(isc_task_t) isc_tasklist_t; /*%< Task List */
+typedef struct isc_taskmgr isc_taskmgr_t; /*%< Task Manager */
+typedef struct isc_textregion isc_textregion_t; /*%< Text Region */
+typedef struct isc_time isc_time_t; /*%< Time */
+typedef struct isc_timer isc_timer_t; /*%< Timer */
+typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */
+
+#if HAVE_LIBNGHTTP2
+typedef struct isc_nm_http_endpoints isc_nm_http_endpoints_t;
+/*%< HTTP endpoints set */
+#endif /* HAVE_LIBNGHTTP2 */
+
+typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
+
+/*% Resource */
+typedef enum {
+ isc_resource_coresize = 1,
+ isc_resource_cputime,
+ isc_resource_datasize,
+ isc_resource_filesize,
+ isc_resource_lockedmemory,
+ isc_resource_openfiles,
+ isc_resource_processes,
+ isc_resource_residentsize,
+ isc_resource_stacksize
+} isc_resource_t;
+
+/*% Statistics formats (text file or XML) */
+typedef enum {
+ isc_statsformat_file,
+ isc_statsformat_xml,
+ isc_statsformat_json
+} isc_statsformat_t;
+
+typedef enum isc_nmsocket_type {
+ isc_nm_nonesocket = 0,
+ isc_nm_udpsocket = 1 << 1,
+ isc_nm_tcpsocket = 1 << 2,
+ isc_nm_tcpdnssocket = 1 << 3,
+ isc_nm_tlssocket = 1 << 4,
+ isc_nm_tlsdnssocket = 1 << 5,
+ isc_nm_httpsocket = 1 << 6,
+ isc_nm_maxsocket,
+
+ isc_nm_udplistener, /* Aggregate of nm_udpsocks */
+ isc_nm_tcplistener,
+ isc_nm_tlslistener,
+ isc_nm_tcpdnslistener,
+ isc_nm_tlsdnslistener,
+ isc_nm_httplistener
+} isc_nmsocket_type;
+
+typedef isc_nmsocket_type isc_nmsocket_type_t;
diff --git a/lib/isc/include/isc/url.h b/lib/isc/include/isc/url.h
new file mode 100644
index 0000000..d3b935b
--- /dev/null
+++ b/lib/isc/include/isc/url.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0 and MIT
+ *
+ * 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.
+ */
+
+/*
+ * Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <isc/result.h>
+
+/*
+ * Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
+ * faster
+ */
+#ifndef HTTP_PARSER_STRICT
+#define HTTP_PARSER_STRICT 1
+#endif
+
+typedef enum {
+ ISC_UF_SCHEMA = 0,
+ ISC_UF_HOST = 1,
+ ISC_UF_PORT = 2,
+ ISC_UF_PATH = 3,
+ ISC_UF_QUERY = 4,
+ ISC_UF_FRAGMENT = 5,
+ ISC_UF_USERINFO = 6,
+ ISC_UF_MAX = 7
+} isc_url_field_t;
+
+/* Result structure for isc_url_parse().
+ *
+ * Callers should index into field_data[] with UF_* values iff field_set
+ * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
+ * because we probably have padding left over), we convert any port to
+ * a uint16_t.
+ */
+typedef struct {
+ uint16_t field_set; /* Bitmask of (1 << UF_*) values */
+ uint16_t port; /* Converted UF_PORT string */
+
+ struct {
+ uint16_t off; /* Offset into buffer in which field starts */
+ uint16_t len; /* Length of run in buffer */
+ } field_data[ISC_UF_MAX];
+} isc_url_parser_t;
+
+isc_result_t
+isc_url_parse(const char *buf, size_t buflen, bool is_connect,
+ isc_url_parser_t *up);
+/*%<
+ * Parse a URL; return nonzero on failure
+ */
diff --git a/lib/isc/include/isc/utf8.h b/lib/isc/include/isc/utf8.h
new file mode 100644
index 0000000..5643c5d
--- /dev/null
+++ b/lib/isc/include/isc/utf8.h
@@ -0,0 +1,43 @@
+/*
+ * 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 isc/utf8.h */
+
+#pragma once
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+bool
+isc_utf8_bom(const unsigned char *buf, size_t len);
+/*<
+ * Returns 'true' if the string of bytes in 'buf' starts
+ * with an UTF-8 Byte Order Mark.
+ *
+ * Requires:
+ *\li 'buf' != NULL
+ */
+
+bool
+isc_utf8_valid(const unsigned char *buf, size_t len);
+/*<
+ * Returns 'true' if the string of bytes in 'buf' is a valid UTF-8
+ * byte sequence otherwise 'false' is returned.
+ *
+ * Requires:
+ *\li 'buf' != NULL
+ */
+
+ISC_LANG_ENDDECLS
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
new file mode 100644
index 0000000..922661b
--- /dev/null
+++ b/lib/isc/include/isc/util.h
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+/*! \file isc/util.h
+ * NOTE:
+ *
+ * This file is not to be included from any <isc/???.h> (or other) library
+ * files.
+ *
+ * \brief
+ * Including this file puts several macros in your name space that are
+ * not protected (as all the other ISC functions/macros do) by prepending
+ * ISC_ or isc_ to the name.
+ */
+
+/***
+ *** Clang Compatibility Macros
+ ***/
+
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif /* if !defined(__has_attribute) */
+
+#if !defined(__has_c_attribute)
+#define __has_c_attribute(x) 0
+#endif /* if !defined(__has_c_attribute) */
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif /* if !defined(__has_feature) */
+
+/***
+ *** General Macros.
+ ***/
+
+/*%
+ * Use this to hide unused function arguments.
+ * \code
+ * int
+ * foo(char *bar)
+ * {
+ * UNUSED(bar);
+ * }
+ * \endcode
+ */
+#define UNUSED(x) (void)(x)
+
+#if __GNUC__ >= 8 && !defined(__clang__)
+#define ISC_NONSTRING __attribute__((nonstring))
+#else /* if __GNUC__ >= 8 && !defined(__clang__) */
+#define ISC_NONSTRING
+#endif /* __GNUC__ */
+
+#if __has_c_attribute(fallthrough)
+#define FALLTHROUGH [[fallthrough]]
+#elif __GNUC__ >= 7 && !defined(__clang__)
+#define FALLTHROUGH __attribute__((fallthrough))
+#else
+/* clang-format off */
+#define FALLTHROUGH do {} while (0) /* FALLTHROUGH */
+/* clang-format on */
+#endif
+
+#if HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR && HAVE_FUNC_ATTRIBUTE_DESTRUCTOR
+#define ISC_CONSTRUCTOR __attribute__((constructor))
+#define ISC_DESTRUCTOR __attribute__((destructor))
+#else
+#define ISC_CONSTRUCTOR
+#define ISC_DESTRUCTOR
+#endif
+
+/*%
+ * The opposite: silent warnings about stored values which are never read.
+ */
+#define POST(x) (void)(x)
+
+#define ISC_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define ISC_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#define ISC_CLAMP(v, x, y) ((v) < (x) ? (x) : ((v) > (y) ? (y) : (v)))
+
+/*%
+ * Use this to remove the const qualifier of a variable to assign it to
+ * a non-const variable or pass it as a non-const function argument ...
+ * but only when you are sure it won't then be changed!
+ * This is necessary to sometimes shut up some compilers
+ * (as with gcc -Wcast-qual) when there is just no other good way to avoid the
+ * situation.
+ */
+#define DE_CONST(konst, var) \
+ do { \
+ union { \
+ const void *k; \
+ void *v; \
+ } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+/*%
+ * Use this in translation units that would otherwise be empty, to
+ * suppress compiler warnings.
+ */
+#define EMPTY_TRANSLATION_UNIT extern int isc__empty;
+
+/*%
+ * We use macros instead of calling the routines directly because
+ * the capital letters make the locking stand out.
+ * We RUNTIME_CHECK for success since in general there's no way
+ * for us to continue if they fail.
+ */
+
+#ifdef ISC_UTIL_TRACEON
+#define ISC_UTIL_TRACE(a) a
+#include <stdio.h> /* Required for fprintf/stderr when tracing. */
+#else /* ifdef ISC_UTIL_TRACEON */
+#define ISC_UTIL_TRACE(a)
+#endif /* ifdef ISC_UTIL_TRACEON */
+
+#include <isc/result.h> /* Contractual promise. */
+
+#define LOCK(lp) \
+ do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "LOCKING %p %s %d\n", (lp), \
+ __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_mutex_lock((lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "LOCKED %p %s %d\n", (lp), \
+ __FILE__, __LINE__)); \
+ } while (0)
+#define UNLOCK(lp) \
+ do { \
+ RUNTIME_CHECK(isc_mutex_unlock((lp)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "UNLOCKED %p %s %d\n", (lp), \
+ __FILE__, __LINE__)); \
+ } while (0)
+
+#define BROADCAST(cvp) \
+ do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "BROADCAST %p %s %d\n", (cvp), \
+ __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_broadcast((cvp)) == \
+ ISC_R_SUCCESS); \
+ } while (0)
+#define SIGNAL(cvp) \
+ do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "SIGNAL %p %s %d\n", (cvp), \
+ __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_signal((cvp)) == ISC_R_SUCCESS); \
+ } while (0)
+#define WAIT(cvp, lp) \
+ do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "WAIT %p LOCK %p %s %d\n", \
+ (cvp), (lp), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_condition_wait((cvp), (lp)) == \
+ ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "WAITED %p LOCKED %p %s %d\n", \
+ (cvp), (lp), __FILE__, __LINE__)); \
+ } while (0)
+
+/*
+ * isc_condition_waituntil can return ISC_R_TIMEDOUT, so we
+ * don't RUNTIME_CHECK the result.
+ *
+ * XXX Also, can't really debug this then...
+ */
+
+#define WAITUNTIL(cvp, lp, tp) isc_condition_waituntil((cvp), (lp), (tp))
+
+#define RWLOCK(lp, t) \
+ do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "RWLOCK %p, %d %s %d\n", (lp), \
+ (t), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_rwlock_lock((lp), (t)) == ISC_R_SUCCESS); \
+ ISC_UTIL_TRACE(fprintf(stderr, "RWLOCKED %p, %d %s %d\n", \
+ (lp), (t), __FILE__, __LINE__)); \
+ } while (0)
+#define RWUNLOCK(lp, t) \
+ do { \
+ ISC_UTIL_TRACE(fprintf(stderr, "RWUNLOCK %p, %d %s %d\n", \
+ (lp), (t), __FILE__, __LINE__)); \
+ RUNTIME_CHECK(isc_rwlock_unlock((lp), (t)) == ISC_R_SUCCESS); \
+ } while (0)
+
+/*
+ * List Macros.
+ */
+#include <isc/list.h> /* Contractual promise. */
+
+#define LIST(type) ISC_LIST(type)
+#define INIT_LIST(type) ISC_LIST_INIT(type)
+#define LINK(type) ISC_LINK(type)
+#define INIT_LINK(elt, link) ISC_LINK_INIT(elt, link)
+#define HEAD(list) ISC_LIST_HEAD(list)
+#define TAIL(list) ISC_LIST_TAIL(list)
+#define EMPTY(list) ISC_LIST_EMPTY(list)
+#define PREV(elt, link) ISC_LIST_PREV(elt, link)
+#define NEXT(elt, link) ISC_LIST_NEXT(elt, link)
+#define APPEND(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define PREPEND(list, elt, link) ISC_LIST_PREPEND(list, elt, link)
+#define UNLINK(list, elt, link) ISC_LIST_UNLINK(list, elt, link)
+#define ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) ISC_LIST_UNLINK(list, elt, link)
+#define INSERTBEFORE(li, b, e, ln) ISC_LIST_INSERTBEFORE(li, b, e, ln)
+#define INSERTAFTER(li, a, e, ln) ISC_LIST_INSERTAFTER(li, a, e, ln)
+#define APPENDLIST(list1, list2, link) ISC_LIST_APPENDLIST(list1, list2, link)
+
+/*%
+ * Performance
+ */
+
+/* GCC defines __SANITIZE_ADDRESS__, so reuse the macro for clang */
+#if __has_feature(address_sanitizer)
+#define __SANITIZE_ADDRESS__ 1
+#endif /* if __has_feature(address_sanitizer) */
+
+#if __has_feature(thread_sanitizer)
+#define __SANITIZE_THREAD__ 1
+#endif /* if __has_feature(thread_sanitizer) */
+
+#if __SANITIZE_THREAD__
+#define ISC_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
+#else /* if __SANITIZE_THREAD__ */
+#define ISC_NO_SANITIZE_THREAD
+#endif /* if __SANITIZE_THREAD__ */
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6)
+#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
+#elif __has_feature(c_static_assert)
+#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
+#else /* if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6) */
+
+/* Courtesy of Joseph Quinsey: https://godbolt.org/z/K9RvWS */
+#define TOKENPASTE(a, b) a##b /* "##" is the "Token Pasting Operator" */
+#define EXPAND_THEN_PASTE(a, b) TOKENPASTE(a, b) /* expand then paste */
+#define STATIC_ASSERT(x, msg) \
+ enum { EXPAND_THEN_PASTE(ASSERT_line_, __LINE__) = 1 / ((msg) && (x)) }
+#endif /* if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6) */
+
+#ifdef UNIT_TESTING
+extern void
+mock_assert(const int result, const char *const expression,
+ const char *const file, const int line);
+/*
+ * Allow clang to determine that the following code is not reached
+ * by calling abort() if the condition fails. The abort() will
+ * never be executed as mock_assert() and _assert_true() longjmp
+ * or exit if the condition is false.
+ */
+#define REQUIRE(expression) \
+ ((!(expression)) \
+ ? (mock_assert(0, #expression, __FILE__, __LINE__), abort()) \
+ : (void)0)
+#define ENSURE(expression) \
+ ((!(int)(expression)) \
+ ? (mock_assert(0, #expression, __FILE__, __LINE__), abort()) \
+ : (void)0)
+#define INSIST(expression) \
+ ((!(expression)) \
+ ? (mock_assert(0, #expression, __FILE__, __LINE__), abort()) \
+ : (void)0)
+#define INVARIANT(expression) \
+ ((!(expression)) \
+ ? (mock_assert(0, #expression, __FILE__, __LINE__), abort()) \
+ : (void)0)
+#define UNREACHABLE() \
+ (mock_assert(0, "unreachable", __FILE__, __LINE__), abort())
+#define _assert_true(c, e, f, l) \
+ ((c) ? (void)0 : (_assert_true(0, e, f, l), abort()))
+#define _assert_int_equal(a, b, f, l) \
+ (((a) == (b)) ? (void)0 : (_assert_int_equal(a, b, f, l), abort()))
+#define _assert_int_not_equal(a, b, f, l) \
+ (((a) != (b)) ? (void)0 : (_assert_int_not_equal(a, b, f, l), abort()))
+#else /* UNIT_TESTING */
+
+/*
+ * Assertions
+ */
+#include <isc/assertions.h> /* Contractual promise. */
+
+/*% Require Assertion */
+#define REQUIRE(e) ISC_REQUIRE(e)
+/*% Ensure Assertion */
+#define ENSURE(e) ISC_ENSURE(e)
+/*% Insist Assertion */
+#define INSIST(e) ISC_INSIST(e)
+/*% Invariant Assertion */
+#define INVARIANT(e) ISC_INVARIANT(e)
+
+#define UNREACHABLE() ISC_UNREACHABLE()
+
+#endif /* UNIT_TESTING */
+
+/*
+ * Errors
+ */
+#include <isc/error.h> /* Contractual promise. */
+#include <isc/strerr.h> /* for ISC_STRERRORSIZE */
+
+#define UNEXPECTED_ERROR(...) \
+ isc_error_unexpected(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+#define FATAL_ERROR(...) \
+ isc_error_fatal(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+#define REPORT_SYSERROR(report, err, fmt, ...) \
+ { \
+ char strerr[ISC_STRERRORSIZE]; \
+ strerror_r(err, strerr, sizeof(strerr)); \
+ report(__FILE__, __LINE__, __func__, fmt ": %s (%d)", \
+ ##__VA_ARGS__, strerr, err); \
+ }
+
+#define UNEXPECTED_SYSERROR(err, ...) \
+ REPORT_SYSERROR(isc_error_unexpected, err, __VA_ARGS__)
+
+#define FATAL_SYSERROR(err, ...) \
+ REPORT_SYSERROR(isc_error_fatal, err, __VA_ARGS__)
+
+#ifdef UNIT_TESTING
+
+#define RUNTIME_CHECK(cond) \
+ ((cond) ? (void)0 \
+ : (mock_assert(0, #cond, __FILE__, __LINE__), abort()))
+
+#else /* UNIT_TESTING */
+
+#define RUNTIME_CHECK(cond) \
+ ((cond) ? (void)0 : FATAL_ERROR("RUNTIME_CHECK(%s) failed", #cond))
+
+#endif /* UNIT_TESTING */
+
+/*%
+ * Time
+ */
+#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
+#define TIME_NOW_HIRES(tp) \
+ RUNTIME_CHECK(isc_time_now_hires((tp)) == ISC_R_SUCCESS)
+
+/*%
+ * Alignment
+ */
+#ifdef __GNUC__
+#define ISC_ALIGN(x, a) (((x) + (a)-1) & ~((typeof(x))(a)-1))
+#else /* ifdef __GNUC__ */
+#define ISC_ALIGN(x, a) (((x) + (a)-1) & ~((uintmax_t)(a)-1))
+#endif /* ifdef __GNUC__ */
+
+/*%
+ * Misc
+ */
+#include <isc/deprecated.h>
+
+/*%
+ * Swap
+ */
+#define ISC_SWAP(a, b) \
+ { \
+ typeof(a) __tmp_swap = a; \
+ a = b; \
+ b = __tmp_swap; \
+ }