summaryrefslogtreecommitdiffstats
path: root/lib/isc/win32
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
commit45d6379135504814ab723b57f0eb8be23393a51d (patch)
treed4f2ec4acca824a8446387a758b0ce4238a4dffa /lib/isc/win32
parentInitial commit. (diff)
downloadbind9-upstream.tar.xz
bind9-upstream.zip
Adding upstream version 1:9.16.44.upstream/1%9.16.44upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/isc/win32')
-rw-r--r--lib/isc/win32/.dir-locals.el35
-rw-r--r--lib/isc/win32/DLLMain.c52
-rw-r--r--lib/isc/win32/Makefile.in36
-rw-r--r--lib/isc/win32/condition.c255
-rw-r--r--lib/isc/win32/dir.c314
-rw-r--r--lib/isc/win32/errno.c21
-rw-r--r--lib/isc/win32/errno2result.c118
-rw-r--r--lib/isc/win32/errno2result.h35
-rw-r--r--lib/isc/win32/file.c1003
-rw-r--r--lib/isc/win32/fsaccess.c404
l---------lib/isc/win32/include/.clang-format1
-rw-r--r--lib/isc/win32/include/Makefile.in19
-rw-r--r--lib/isc/win32/include/isc/Makefile.in32
-rw-r--r--lib/isc/win32/include/isc/align.h15
-rw-r--r--lib/isc/win32/include/isc/bind_registry.h42
-rw-r--r--lib/isc/win32/include/isc/bindevt.h83
-rw-r--r--lib/isc/win32/include/isc/condition.h60
-rw-r--r--lib/isc/win32/include/isc/dir.h73
-rw-r--r--lib/isc/win32/include/isc/ipv6.h130
-rw-r--r--lib/isc/win32/include/isc/mutex.h47
-rw-r--r--lib/isc/win32/include/isc/net.h402
-rw-r--r--lib/isc/win32/include/isc/netdb.h48
-rw-r--r--lib/isc/win32/include/isc/ntgroups.h28
-rw-r--r--lib/isc/win32/include/isc/ntpaths.h66
-rw-r--r--lib/isc/win32/include/isc/offset.h26
-rw-r--r--lib/isc/win32/include/isc/once.h40
-rw-r--r--lib/isc/win32/include/isc/platform.h.in132
-rw-r--r--lib/isc/win32/include/isc/stat.h58
-rw-r--r--lib/isc/win32/include/isc/stdatomic.h595
-rw-r--r--lib/isc/win32/include/isc/stdtime.h62
-rw-r--r--lib/isc/win32/include/isc/syslog.h39
-rw-r--r--lib/isc/win32/include/isc/thread.h103
-rw-r--r--lib/isc/win32/include/isc/time.h468
-rw-r--r--lib/isc/win32/include/isc/win32os.h41
-rw-r--r--lib/isc/win32/interfaceiter.c550
-rw-r--r--lib/isc/win32/ipv6.c18
-rw-r--r--lib/isc/win32/libgen.h22
-rw-r--r--lib/isc/win32/libisc.def.exclude42
-rw-r--r--lib/isc/win32/libisc.def.in805
-rw-r--r--lib/isc/win32/libisc.vcxproj.filters.in671
-rw-r--r--lib/isc/win32/libisc.vcxproj.in483
-rw-r--r--lib/isc/win32/libisc.vcxproj.user3
-rw-r--r--lib/isc/win32/meminfo.c26
-rw-r--r--lib/isc/win32/net.c301
-rw-r--r--lib/isc/win32/netdb.h182
-rw-r--r--lib/isc/win32/ntgroups.c215
-rw-r--r--lib/isc/win32/ntpaths.c151
-rw-r--r--lib/isc/win32/once.c43
-rw-r--r--lib/isc/win32/os.c41
-rw-r--r--lib/isc/win32/pk11_api.c706
-rw-r--r--lib/isc/win32/resource.c66
-rw-r--r--lib/isc/win32/socket.c3965
-rw-r--r--lib/isc/win32/stdio.c158
-rw-r--r--lib/isc/win32/stdtime.c43
-rw-r--r--lib/isc/win32/syslog.c171
-rw-r--r--lib/isc/win32/syslog.h70
-rw-r--r--lib/isc/win32/thread.c82
-rw-r--r--lib/isc/win32/time.c651
-rw-r--r--lib/isc/win32/unistd.h55
-rw-r--r--lib/isc/win32/version.c18
-rw-r--r--lib/isc/win32/win32os.c113
61 files changed, 14534 insertions, 0 deletions
diff --git a/lib/isc/win32/.dir-locals.el b/lib/isc/win32/.dir-locals.el
new file mode 100644
index 0000000..b16a1be
--- /dev/null
+++ b/lib/isc/win32/.dir-locals.el
@@ -0,0 +1,35 @@
+;;; Directory Local Variables
+;;; For more information see (info "(emacs) Directory Variables")
+
+((c-mode .
+ ((eval .
+ (set (make-local-variable 'directory-of-current-dir-locals-file)
+ (file-name-directory (locate-dominating-file default-directory ".dir-locals.el"))
+ )
+ )
+ (eval .
+ (set (make-local-variable 'include-directories)
+ (list
+ (expand-file-name
+ (concat directory-of-current-dir-locals-file "../../../"))
+ (expand-file-name
+ (concat directory-of-current-dir-locals-file "include"))
+ (expand-file-name
+ (concat directory-of-current-dir-locals-file "../include"))
+ (expand-file-name
+ (concat directory-of-current-dir-locals-file "../"))
+ (expand-file-name
+ (concat directory-of-current-dir-locals-file "./"))
+ (expand-file-name
+ (concat directory-of-current-dir-locals-file "../../dns/include"))
+ (expand-file-name "/usr/local/opt/openssl@1.1/include")
+ (expand-file-name "/usr/local/opt/libxml2/include/libxml2")
+ (expand-file-name "/usr/local/include")
+ )
+ )
+ )
+
+ (eval setq flycheck-clang-include-path include-directories)
+ (eval setq flycheck-cpp-include-path include-directories)
+ )
+ ))
diff --git a/lib/isc/win32/DLLMain.c b/lib/isc/win32/DLLMain.c
new file mode 100644
index 0000000..abaaf40
--- /dev/null
+++ b/lib/isc/win32/DLLMain.c
@@ -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.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#include "lib_p.h"
+
+/*
+ * Called when we enter the DLL
+ */
+__declspec(dllexport) BOOL WINAPI
+ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
+ switch (fdwReason) {
+ /*
+ * The DLL is loading due to process initialization or a call to
+ * LoadLibrary.
+ */
+ case DLL_PROCESS_ATTACH:
+ isc__initialize();
+ break;
+
+ /*
+ * The DLL is unloading from a process due to process
+ * termination or a call to FreeLibrary.
+ */
+ case DLL_PROCESS_DETACH:
+ isc__shutdown();
+ break;
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+
+ default:
+ break;
+ }
+ return (TRUE);
+}
diff --git a/lib/isc/win32/Makefile.in b/lib/isc/win32/Makefile.in
new file mode 100644
index 0000000..e8377ff
--- /dev/null
+++ b/lib/isc/win32/Makefile.in
@@ -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.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+CINCLUDES = -I${srcdir}/.. \
+ -I./include \
+ -I${srcdir}/include \
+ -I${srcdir}/../include
+CDEFINES =
+CWARNINGS =
+
+# Alphabetically
+OBJS = condition.@O@ dir.@O@ errno.@O@ file.@O@ \
+ meminfo.@O@ fsaccess.@O@ \
+ once.@O@ stdtime.@O@ thread.@O@ time.@O@ pk11_api.@O@
+
+# Alphabetically
+SRCS = condition.c dir.c errno.c file.c \
+ meminfo.c once.c fsaccess.c \
+ stdtime.c thread.c time.c pk11_api.c
+
+SUBDIRS = include
+TARGETS = ${OBJS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/win32/condition.c b/lib/isc/win32/condition.c
new file mode 100644
index 0000000..ca11bce
--- /dev/null
+++ b/lib/isc/win32/condition.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/assertions.h>
+#include <isc/condition.h>
+#include <isc/error.h>
+#include <isc/strerr.h>
+#include <isc/thread.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#define LSIGNAL 0
+#define LBROADCAST 1
+
+void
+isc_condition_init(isc_condition_t *cond) {
+ HANDLE h;
+
+ REQUIRE(cond != NULL);
+
+ cond->waiters = 0;
+ /*
+ * This handle is shared across all threads
+ */
+ h = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (h == NULL) {
+ char strbuf[ISC_STRERRORSIZE];
+ DWORD err = GetLastError();
+ strerror_r(err, strbuf, sizeof(strbuf));
+ isc_error_fatal(__FILE__, __LINE__, "CreateEvent failed: %s",
+ strbuf);
+ }
+ cond->events[LSIGNAL] = h;
+
+ /*
+ * The threadlist will hold the actual events needed
+ * for the wait condition
+ */
+ ISC_LIST_INIT(cond->threadlist);
+}
+
+/*
+ * Add the thread to the threadlist along with the required events
+ */
+static isc_result_t
+register_thread(unsigned long thrd, isc_condition_t *gblcond,
+ isc_condition_thread_t **localcond) {
+ HANDLE hc;
+ isc_condition_thread_t *newthread;
+
+ REQUIRE(localcond != NULL && *localcond == NULL);
+
+ newthread = malloc(sizeof(isc_condition_thread_t));
+ if (newthread == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ /*
+ * Create the thread-specific handle
+ */
+ hc = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (hc == NULL) {
+ free(newthread);
+ return (ISC_R_UNEXPECTED);
+ }
+
+ /*
+ * Add the thread ID and handles to list of threads for broadcast
+ */
+ newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL];
+ newthread->handle[LBROADCAST] = hc;
+ newthread->th = thrd;
+
+ /*
+ * The thread is holding the manager lock so this is safe
+ */
+ ISC_LINK_INIT(newthread, link);
+ ISC_LIST_APPEND(gblcond->threadlist, newthread, link);
+ *localcond = newthread;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+find_thread_condition(uintptr_t thrd, isc_condition_t *cond,
+ isc_condition_thread_t **threadcondp) {
+ isc_condition_thread_t *threadcond;
+
+ REQUIRE(threadcondp != NULL && *threadcondp == NULL);
+
+ /*
+ * Look for the thread ID.
+ */
+ for (threadcond = ISC_LIST_HEAD(cond->threadlist); threadcond != NULL;
+ threadcond = ISC_LIST_NEXT(threadcond, link))
+ {
+ if (threadcond->th == thrd) {
+ *threadcondp = threadcond;
+ return (ISC_R_SUCCESS);
+ }
+ }
+
+ /*
+ * Not found, so add it.
+ */
+ return (register_thread(thrd, cond, threadcondp));
+}
+
+isc_result_t
+isc_condition_signal(isc_condition_t *cond) {
+ /*
+ * Unlike pthreads, the caller MUST hold the lock associated with
+ * the condition variable when calling us.
+ */
+ REQUIRE(cond != NULL);
+
+ if (!SetEvent(cond->events[LSIGNAL])) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_broadcast(isc_condition_t *cond) {
+ isc_condition_thread_t *threadcond;
+ bool failed = false;
+
+ /*
+ * Unlike pthreads, the caller MUST hold the lock associated with
+ * the condition variable when calling us.
+ */
+ REQUIRE(cond != NULL);
+
+ /*
+ * Notify every thread registered for this
+ */
+ for (threadcond = ISC_LIST_HEAD(cond->threadlist); threadcond != NULL;
+ threadcond = ISC_LIST_NEXT(threadcond, link))
+ {
+ if (!SetEvent(threadcond->handle[LBROADCAST])) {
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_destroy(isc_condition_t *cond) {
+ isc_condition_thread_t *next, *threadcond;
+
+ REQUIRE(cond != NULL);
+ REQUIRE(cond->waiters == 0);
+
+ (void)CloseHandle(cond->events[LSIGNAL]);
+
+ /*
+ * Delete the threadlist
+ */
+ threadcond = ISC_LIST_HEAD(cond->threadlist);
+
+ while (threadcond != NULL) {
+ next = ISC_LIST_NEXT(threadcond, link);
+ DEQUEUE(cond->threadlist, threadcond, link);
+ (void)CloseHandle(threadcond->handle[LBROADCAST]);
+ free(threadcond);
+ threadcond = next;
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is always called when the mutex (lock) is held, but because
+ * we are waiting we need to release it and reacquire it as soon as the wait
+ * is over. This allows other threads to make use of the object guarded
+ * by the mutex but it should never try to delete it as long as the
+ * number of waiters > 0. Always reacquire the mutex regardless of the
+ * result of the wait. Note that EnterCriticalSection will wait to acquire
+ * the mutex.
+ */
+static isc_result_t
+wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) {
+ DWORD result;
+ isc_result_t tresult;
+ isc_condition_thread_t *threadcond = NULL;
+
+ /*
+ * Get the thread events needed for the wait
+ */
+ tresult = find_thread_condition(isc_thread_self(), cond, &threadcond);
+ if (tresult != ISC_R_SUCCESS) {
+ return (tresult);
+ }
+
+ cond->waiters++;
+ LeaveCriticalSection(mutex);
+ result = WaitForMultipleObjects(2, threadcond->handle, FALSE,
+ milliseconds);
+ EnterCriticalSection(mutex);
+ cond->waiters--;
+ if (result == WAIT_FAILED) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+ if (result == WAIT_TIMEOUT) {
+ return (ISC_R_TIMEDOUT);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) {
+ return (wait(cond, mutex, INFINITE));
+}
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex,
+ isc_time_t *t) {
+ DWORD milliseconds;
+ uint64_t microseconds;
+ isc_time_t now;
+
+ if (isc_time_now(&now) != ISC_R_SUCCESS) {
+ /* XXX */
+ return (ISC_R_UNEXPECTED);
+ }
+
+ microseconds = isc_time_microdiff(t, &now);
+ if (microseconds > 0xFFFFFFFFi64 * 1000) {
+ milliseconds = 0xFFFFFFFF;
+ } else {
+ milliseconds = (DWORD)(microseconds / 1000);
+ }
+
+ return (wait(cond, mutex, milliseconds));
+}
diff --git a/lib/isc/win32/dir.c b/lib/isc/win32/dir.c
new file mode 100644
index 0000000..9a512da
--- /dev/null
+++ b/lib/isc/win32/dir.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <direct.h>
+#include <io.h>
+#include <process.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <isc/assertions.h>
+#include <isc/dir.h>
+#include <isc/magic.h>
+#include <isc/print.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*')
+#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
+
+static isc_result_t
+start_directory(isc_dir_t *p);
+
+void
+isc_dir_init(isc_dir_t *dir) {
+ REQUIRE(dir != NULL);
+
+ dir->dirname[0] = '\0';
+
+ dir->entry.name[0] = '\0';
+ dir->entry.length = 0;
+ memset(&(dir->entry.find_data), 0, sizeof(dir->entry.find_data));
+
+ dir->entry_filled = false;
+ dir->search_handle = INVALID_HANDLE_VALUE;
+
+ dir->magic = ISC_DIR_MAGIC;
+}
+
+/*
+ * Allocate workspace and open directory stream. If either one fails,
+ * NULL will be returned.
+ */
+isc_result_t
+isc_dir_open(isc_dir_t *dir, const char *dirname) {
+ char *p;
+ isc_result_t result;
+
+ REQUIRE(dirname != NULL);
+ REQUIRE(VALID_DIR(dir) && dir->search_handle == INVALID_HANDLE_VALUE);
+
+ /*
+ * Copy directory name. Need to have enough space for the name,
+ * a possible path separator, the wildcard, and the final NUL.
+ */
+ if (strlen(dirname) + 3 > sizeof(dir->dirname)) {
+ /* XXXDCL ? */
+ return (ISC_R_NOSPACE);
+ }
+ strlcpy(dir->dirname, dirname, sizeof(dir->dirname));
+
+ /*
+ * Append path separator, if needed, and "*".
+ */
+ p = dir->dirname + strlen(dir->dirname);
+ if (dir->dirname < p && *(p - 1) != '\\' && *(p - 1) != ':') {
+ *p++ = '\\';
+ }
+ *p++ = '*';
+ *p = '\0';
+
+ /*
+ * Open stream.
+ */
+ result = start_directory(dir);
+
+ return (result);
+}
+
+/*
+ * Return previously retrieved file or get next one. Unix's dirent has
+ * separate open and read functions, but the Win32 and DOS interfaces open
+ * the dir stream and reads the first file in one operation.
+ */
+isc_result_t
+isc_dir_read(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+
+ if (dir->entry_filled) {
+ /*
+ * start_directory() already filled in the first entry.
+ */
+ dir->entry_filled = false;
+ } else {
+ /*
+ * Fetch next file in directory.
+ */
+ if (FindNextFile(dir->search_handle, &dir->entry.find_data) ==
+ FALSE)
+ {
+ /*
+ * Either the last file has been processed or
+ * an error has occurred. The former is not
+ * really an error, but the latter is.
+ */
+ if (GetLastError() == ERROR_NO_MORE_FILES) {
+ return (ISC_R_NOMORE);
+ } else {
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+ }
+
+ /*
+ * Make sure that the space for the name is long enough.
+ */
+ strlcpy(dir->entry.name, dir->entry.find_data.cFileName,
+ sizeof(dir->entry.name));
+ dir->entry.length = strlen(dir->entry.name);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Close directory stream.
+ */
+void
+isc_dir_close(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+
+ FindClose(dir->search_handle);
+ dir->search_handle = INVALID_HANDLE_VALUE;
+}
+
+/*
+ * Reposition directory stream at start.
+ */
+isc_result_t
+isc_dir_reset(isc_dir_t *dir) {
+ isc_result_t result;
+
+ REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE);
+ REQUIRE(dir->dirname != NULL);
+
+ /*
+ * NT cannot reposition the seek pointer to the beginning of the
+ * the directory stream, but rather the directory needs to be
+ * closed and reopened. The latter might fail.
+ */
+
+ isc_dir_close(dir);
+
+ result = start_directory(dir);
+
+ return (result);
+}
+
+/*
+ * Initialize isc_dir_t structure with new directory. The function
+ * returns 0 on failure and nonzero on success.
+ *
+ * Note:
+ * - Be sure to close previous stream before opening new one
+ */
+static isc_result_t
+start_directory(isc_dir_t *dir) {
+ REQUIRE(VALID_DIR(dir));
+ REQUIRE(dir->search_handle == INVALID_HANDLE_VALUE);
+
+ dir->entry_filled = false;
+
+ /*
+ * Open stream and retrieve first file.
+ */
+ dir->search_handle = FindFirstFile(dir->dirname, &dir->entry.find_data);
+
+ if (dir->search_handle == INVALID_HANDLE_VALUE) {
+ /*
+ * Something went wrong but we don't know what. GetLastError()
+ * could give us more information about the error, but the
+ * MSDN documentation is frustratingly thin about what
+ * possible errors could have resulted. (Score one for
+ * the Unix manual pages.) So there is just this lame error
+ * instead of being able to differentiate ISC_R_NOTFOUND
+ * from ISC_R_UNEXPECTED.
+ */
+ return (ISC_R_FAILURE);
+ }
+
+ /*
+ * Make sure that the space for the name is long enough.
+ */
+ INSIST(sizeof(dir->entry.name) >
+ strlen(dir->entry.find_data.cFileName));
+
+ /*
+ * Fill in the data for the first entry of the directory.
+ */
+ strlcpy(dir->entry.name, dir->entry.find_data.cFileName,
+ sizeof(dir->entry.name));
+ dir->entry.length = strlen(dir->entry.name);
+
+ dir->entry_filled = true;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chdir(const char *dirname) {
+ /*
+ * Change the current directory to 'dirname'.
+ */
+
+ REQUIRE(dirname != NULL);
+
+ if (chdir(dirname) < 0) {
+ return (isc__errno2result(errno));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_dir_chroot(const char *dirname) {
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+isc_dir_createunique(char *templet) {
+ isc_result_t result;
+ char *x;
+ char *p;
+ int i;
+ int pid;
+
+ REQUIRE(templet != NULL);
+
+ /*
+ * mkdtemp is not portable, so this emulates it.
+ */
+
+ pid = getpid();
+
+ /*
+ * Replace trailing Xs with the process-id, zero-filled.
+ */
+ for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
+ x--, pid /= 10)
+ {
+ *x = pid % 10 + '0';
+ }
+
+ x++; /* Set x to start of ex-Xs. */
+
+ do {
+ i = mkdir(templet);
+ if (i == 0) {
+ i = chmod(templet, 0700);
+ }
+
+ if (i == 0 || errno != EEXIST) {
+ break;
+ }
+
+ /*
+ * The BSD algorithm.
+ */
+ p = x;
+ while (*p != '\0') {
+ if (isdigit((unsigned char)*p)) {
+ *p = 'a';
+ } else if (*p != 'z') {
+ ++*p;
+ } else {
+ /*
+ * Reset character and move to next.
+ */
+ *p++ = 'a';
+ continue;
+ }
+
+ break;
+ }
+
+ if (*p == '\0') {
+ /*
+ * Tried all combinations. errno should already
+ * be EEXIST, but ensure it is anyway for
+ * isc__errno2result().
+ */
+ errno = EEXIST;
+ break;
+ }
+ } while (1);
+
+ if (i == -1) {
+ result = isc__errno2result(errno);
+ } else {
+ result = ISC_R_SUCCESS;
+ }
+
+ return (result);
+}
diff --git a/lib/isc/win32/errno.c b/lib/isc/win32/errno.c
new file mode 100644
index 0000000..fd6899f
--- /dev/null
+++ b/lib/isc/win32/errno.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include "errno2result.h"
+
+isc_result_t
+isc_errno_toresult(int err) {
+ return (isc__errno2resultx(err, false, 0, 0));
+}
diff --git a/lib/isc/win32/errno2result.c b/lib/isc/win32/errno2result.c
new file mode 100644
index 0000000..593c27b
--- /dev/null
+++ b/lib/isc/win32/errno2result.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include "errno2result.h"
+#include <stdbool.h>
+#include <winsock2.h>
+
+#include <isc/result.h>
+#include <isc/strerr.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*
+ * Convert a POSIX errno value into an isc_result_t. The
+ * list of supported errno values is not complete; new users
+ * of this function should add any expected errors that are
+ * not already there.
+ */
+isc_result_t
+isc__errno2resultx(int posixerrno, bool dolog, const char *file, int line) {
+ char strbuf[ISC_STRERRORSIZE];
+
+ switch (posixerrno) {
+ case ENOTDIR:
+ case WSAELOOP:
+ case WSAEINVAL:
+ case EINVAL: /* XXX sometimes this is not for files */
+ case ENAMETOOLONG:
+ case WSAENAMETOOLONG:
+ case EBADF:
+ case WSAEBADF:
+ return (ISC_R_INVALIDFILE);
+ case ENOENT:
+ return (ISC_R_FILENOTFOUND);
+ case EACCES:
+ case WSAEACCES:
+ case EPERM:
+ return (ISC_R_NOPERM);
+ case EEXIST:
+ return (ISC_R_FILEEXISTS);
+ case EIO:
+ return (ISC_R_IOERROR);
+ case ENOMEM:
+ return (ISC_R_NOMEMORY);
+#ifdef EOVERFLOW
+ case EOVERFLOW:
+ return (ISC_R_RANGE);
+#endif /* ifdef EOVERFLOW */
+ case ENFILE:
+ case EMFILE:
+ case WSAEMFILE:
+ return (ISC_R_TOOMANYOPENFILES);
+ case ENOSPC:
+ return (ISC_R_DISCFULL);
+ case ERROR_CANCELLED:
+ return (ISC_R_CANCELED);
+ case ERROR_CONNECTION_REFUSED:
+ case WSAECONNREFUSED:
+ return (ISC_R_CONNREFUSED);
+ case WSAENOTCONN:
+ case ERROR_CONNECTION_INVALID:
+ return (ISC_R_NOTCONNECTED);
+ case ERROR_HOST_UNREACHABLE:
+ case WSAEHOSTUNREACH:
+ return (ISC_R_HOSTUNREACH);
+ case ERROR_NETWORK_UNREACHABLE:
+ case WSAENETUNREACH:
+ return (ISC_R_NETUNREACH);
+ case ERROR_NO_NETWORK:
+ return (ISC_R_NETUNREACH);
+ case ERROR_PORT_UNREACHABLE:
+ return (ISC_R_HOSTUNREACH);
+ case ERROR_SEM_TIMEOUT:
+ return (ISC_R_TIMEDOUT);
+ case WSAECONNRESET:
+ case WSAENETRESET:
+ case WSAECONNABORTED:
+ case WSAEDISCON:
+ case ERROR_OPERATION_ABORTED:
+ case ERROR_CONNECTION_ABORTED:
+ case ERROR_REQUEST_ABORTED:
+ return (ISC_R_CONNECTIONRESET);
+ case WSAEADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case ERROR_NETNAME_DELETED:
+ case WSAENETDOWN:
+ return (ISC_R_NETUNREACH);
+ case WSAEHOSTDOWN:
+ return (ISC_R_HOSTUNREACH);
+ case WSAENOBUFS:
+ return (ISC_R_NORESOURCES);
+ default:
+ if (dolog) {
+ strerror_r(posixerrno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(file, line,
+ "unable to convert errno "
+ "to isc_result: %d: %s",
+ posixerrno, strbuf);
+ }
+ /*
+ * XXXDCL would be nice if perhaps this function could
+ * return the system's error string, so the caller
+ * might have something more descriptive than "unexpected
+ * error" to log with.
+ */
+ return (ISC_R_UNEXPECTED);
+ }
+}
diff --git a/lib/isc/win32/errno2result.h b/lib/isc/win32/errno2result.h
new file mode 100644
index 0000000..ce2d72e
--- /dev/null
+++ b/lib/isc/win32/errno2result.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef UNIX_ERRNO2RESULT_H
+#define UNIX_ERRNO2RESULT_H 1
+
+/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */
+
+#include <errno.h> /* Provides errno. */
+#include <stdbool.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+#define isc__errno2result(posixerrno) \
+ isc__errno2resultx(posixerrno, true, __FILE__, __LINE__)
+
+isc_result_t
+isc__errno2resultx(int posixerrno, bool dolog, const char *file, int line);
+
+ISC_LANG_ENDDECLS
+
+#endif /* UNIX_ERRNO2RESULT_H */
diff --git a/lib/isc/win32/file.c b/lib/isc/win32/file.c
new file mode 100644
index 0000000..32f6a19
--- /dev/null
+++ b/lib/isc/win32/file.c
@@ -0,0 +1,1003 @@
+/*
+ * 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.
+ */
+
+#undef rename
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <io.h>
+#include <limits.h>
+#include <process.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+
+#include <isc/file.h>
+#include <isc/md.h>
+#include <isc/mem.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/result.h>
+#include <isc/stat.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+static const char alphnum[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv"
+ "wxyz0123456789";
+
+/*
+ * Emulate UNIX mkstemp, which returns an open FD to the new file
+ *
+ */
+static int
+gettemp(char *path, bool binary, int *doopen) {
+ char *start, *trv;
+ struct stat sbuf;
+ int flags = O_CREAT | O_EXCL | O_RDWR;
+
+ if (binary) {
+ flags |= _O_BINARY;
+ }
+
+ trv = strrchr(path, 'X');
+ trv++;
+ /* extra X's get set to 0's */
+ while (*--trv == 'X') {
+ uint32_t which = isc_random_uniform(sizeof(alphnum) - 1);
+ *trv = alphnum[which];
+ }
+ /*
+ * check the target directory; if you have six X's and it
+ * doesn't exist this runs for a *very* long time.
+ */
+ for (start = trv + 1;; --trv) {
+ if (trv <= path) {
+ break;
+ }
+ if (*trv == '\\') {
+ *trv = '\0';
+ if (stat(path, &sbuf)) {
+ return (0);
+ }
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return (0);
+ }
+ *trv = '\\';
+ break;
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen = open(path, flags,
+ _S_IREAD | _S_IWRITE)) >= 0)
+ {
+ return (1);
+ }
+ if (errno != EEXIST) {
+ return (0);
+ }
+ } else if (stat(path, &sbuf)) {
+ return (errno == ENOENT ? 1 : 0);
+ }
+
+ /* tricky little algorithm for backward compatibility */
+ for (trv = start;;) {
+ if (!*trv) {
+ return (0);
+ }
+ if (*trv == 'z') {
+ *trv++ = 'a';
+ } else {
+ if (isdigit((unsigned char)*trv)) {
+ *trv = 'a';
+ } else {
+ ++*trv;
+ }
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
+
+static int
+mkstemp(char *path, bool binary) {
+ int fd;
+
+ return (gettemp(path, binary, &fd) ? fd : -1);
+}
+
+/*
+ * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
+ * it might be good to provide a mechanism that allows for the results
+ * of a previous stat() to be used again without having to do another stat,
+ * such as perl's mechanism of using "_" in place of a file name to indicate
+ * that the results of the last stat should be used. But then you get into
+ * annoying MP issues. BTW, Win32 has stat().
+ */
+static isc_result_t
+file_stats(const char *file, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(stats != NULL);
+
+ if (stat(file, stats) != 0) {
+ result = isc__errno2result(errno);
+ }
+
+ return (result);
+}
+
+static isc_result_t
+fd_stats(int fd, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(stats != NULL);
+
+ if (fstat(fd, stats) != 0) {
+ result = isc__errno2result(errno);
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_file_getsizefd(int fd, off_t *size) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(size != NULL);
+
+ result = fd_stats(fd, &stats);
+
+ if (result == ISC_R_SUCCESS) {
+ *size = stats.st_size;
+ }
+ return (result);
+}
+
+isc_result_t
+isc_file_mode(const char *file, mode_t *modep) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(modep != NULL);
+
+ result = file_stats(file, &stats);
+ if (result == ISC_R_SUCCESS) {
+ *modep = (stats.st_mode & 07777);
+ }
+ return (result);
+}
+
+/*
+ * isc_file_safemovefile is needed to be defined here to ensure that
+ * any file with the new name is renamed to a backup name and then the
+ * rename is done. If all goes well then the backup can be deleted,
+ * otherwise it gets renamed back.
+ */
+
+int
+isc_file_safemovefile(const char *oldname, const char *newname) {
+ BOOL filestatus;
+ char buf[512];
+ struct stat sbuf;
+ BOOL exists = FALSE;
+ int tmpfd;
+
+ /*
+ * Make sure we have something to do
+ */
+ if (stat(oldname, &sbuf) != 0) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * Rename to a backup the new file if it still exists
+ */
+ if (stat(newname, &sbuf) == 0) {
+ exists = TRUE;
+ strlcpy(buf, newname, sizeof(buf));
+ strlcat(buf, ".XXXXX", sizeof(buf));
+ tmpfd = mkstemp(buf, true);
+ if (tmpfd > 0) {
+ _close(tmpfd);
+ }
+ (void)DeleteFile(buf);
+ _chmod(newname, _S_IREAD | _S_IWRITE);
+
+ filestatus = MoveFile(newname, buf);
+ }
+ /* Now rename the file to the new name
+ */
+ _chmod(oldname, _S_IREAD | _S_IWRITE);
+
+ filestatus = MoveFile(oldname, newname);
+ if (filestatus == 0) {
+ /*
+ * Try to rename the backup back to the original name
+ * if the backup got created
+ */
+ if (exists == TRUE) {
+ filestatus = MoveFile(buf, newname);
+ if (filestatus == 0) {
+ errno = EACCES;
+ }
+ }
+ return (-1);
+ }
+
+ /*
+ * Delete the backup file if it got created
+ */
+ if (exists == TRUE) {
+ (void)DeleteFile(buf);
+ }
+ return (0);
+}
+
+isc_result_t
+isc_file_getmodtime(const char *file, isc_time_t *time) {
+ int fh;
+
+ REQUIRE(file != NULL);
+ REQUIRE(time != NULL);
+
+ if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0) {
+ return (isc__errno2result(errno));
+ }
+
+ if (!GetFileTime((HANDLE)_get_osfhandle(fh), NULL, NULL,
+ &time->absolute))
+ {
+ close(fh);
+ errno = EINVAL;
+ return (isc__errno2result(errno));
+ }
+ close(fh);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_getsize(const char *file, off_t *size) {
+ isc_result_t result;
+ struct stat stats;
+
+ REQUIRE(file != NULL);
+ REQUIRE(size != NULL);
+
+ result = file_stats(file, &stats);
+
+ if (result == ISC_R_SUCCESS) {
+ *size = stats.st_size;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_file_settime(const char *file, isc_time_t *time) {
+ int fh;
+
+ REQUIRE(file != NULL && time != NULL);
+
+ if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0) {
+ return (isc__errno2result(errno));
+ }
+
+ /*
+ * Set the date via the filedate system call and return. Failing
+ * this call implies the new file times are not supported by the
+ * underlying file system.
+ */
+ if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &time->absolute,
+ &time->absolute))
+ {
+ close(fh);
+ errno = EINVAL;
+ return (isc__errno2result(errno));
+ }
+
+ close(fh);
+ return (ISC_R_SUCCESS);
+}
+
+#undef TEMPLATE
+#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */
+
+isc_result_t
+isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
+ return (isc_file_template(path, TEMPLATE, buf, buflen));
+}
+
+isc_result_t
+isc_file_template(const char *path, const char *templet, char *buf,
+ size_t buflen) {
+ char *s;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(buf != NULL);
+
+ if (path == NULL) {
+ path = "";
+ }
+
+ s = strrchr(templet, '\\');
+ if (s != NULL) {
+ templet = s + 1;
+ }
+
+ s = strrchr(path, '\\');
+
+ if (s != NULL) {
+ size_t prefixlen = s - path + 1;
+ if ((prefixlen + strlen(templet) + 1) > buflen) {
+ return (ISC_R_NOSPACE);
+ }
+
+ /* Copy 'prefixlen' bytes and NUL terminate. */
+ strlcpy(buf, path, ISC_MIN(prefixlen + 1, buflen));
+ strlcat(buf, templet, buflen);
+ } else {
+ if ((strlen(templet) + 1) > buflen) {
+ return (ISC_R_NOSPACE);
+ }
+
+ strlcpy(buf, templet, buflen);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_renameunique(const char *file, char *templet) {
+ int fd;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(templet != NULL);
+
+ fd = mkstemp(templet, true);
+ if (fd == -1) {
+ result = isc__errno2result(errno);
+ } else {
+ close(fd);
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ int res;
+ res = isc_file_safemovefile(file, templet);
+ if (res != 0) {
+ result = isc__errno2result(errno);
+ (void)unlink(templet);
+ }
+ }
+ return (result);
+}
+
+static isc_result_t
+openuniquemode(char *templet, int mode, bool binary, FILE **fp) {
+ int fd;
+ FILE *f;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(templet != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ /*
+ * Win32 does not have mkstemp. Using emulation above.
+ */
+ fd = mkstemp(templet, binary);
+
+ if (fd == -1) {
+ result = isc__errno2result(errno);
+ }
+ if (result == ISC_R_SUCCESS) {
+#if 1
+ UNUSED(mode);
+#else /* if 1 */
+ (void)fchmod(fd, mode);
+#endif /* if 1 */
+ f = fdopen(fd, binary ? "wb+" : "w+");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ (void)remove(templet);
+ (void)close(fd);
+ } else {
+ *fp = f;
+ }
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_file_openuniqueprivate(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, false, fp));
+}
+
+isc_result_t
+isc_file_openunique(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, false, fp));
+}
+
+isc_result_t
+isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
+ return (openuniquemode(templet, mode, false, fp));
+}
+
+isc_result_t
+isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, true, fp));
+}
+
+isc_result_t
+isc_file_bopenunique(char *templet, FILE **fp) {
+ int mode = _S_IREAD | _S_IWRITE;
+ return (openuniquemode(templet, mode, true, fp));
+}
+
+isc_result_t
+isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
+ return (openuniquemode(templet, mode, true, fp));
+}
+
+isc_result_t
+isc_file_remove(const char *filename) {
+ int r;
+
+ REQUIRE(filename != NULL);
+
+ r = unlink(filename);
+ if (r == 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+isc_result_t
+isc_file_rename(const char *oldname, const char *newname) {
+ int r;
+
+ REQUIRE(oldname != NULL);
+ REQUIRE(newname != NULL);
+
+ r = isc_file_safemovefile(oldname, newname);
+ if (r == 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+bool
+isc_file_exists(const char *pathname) {
+ struct stat stats;
+
+ REQUIRE(pathname != NULL);
+
+ return (file_stats(pathname, &stats) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isplainfile(const char *filename) {
+ /*
+ * This function returns success if filename is a plain file.
+ */
+ struct stat filestat;
+ memset(&filestat, 0, sizeof(struct stat));
+
+ if ((stat(filename, &filestat)) == -1) {
+ return (isc__errno2result(errno));
+ }
+
+ if (!S_ISREG(filestat.st_mode)) {
+ return (ISC_R_INVALIDFILE);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isplainfilefd(int fd) {
+ /*
+ * This function returns success if filename is a plain file.
+ */
+ struct stat filestat;
+ memset(&filestat, 0, sizeof(struct stat));
+
+ if ((fstat(fd, &filestat)) == -1) {
+ return (isc__errno2result(errno));
+ }
+
+ if (!S_ISREG(filestat.st_mode)) {
+ return (ISC_R_INVALIDFILE);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_isdirectory(const char *filename) {
+ /*
+ * This function returns success if filename is a directory.
+ */
+ struct stat filestat;
+ memset(&filestat, 0, sizeof(struct stat));
+
+ if ((stat(filename, &filestat)) == -1) {
+ return (isc__errno2result(errno));
+ }
+
+ if (!S_ISDIR(filestat.st_mode)) {
+ return (ISC_R_INVALIDFILE);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+bool
+isc_file_isabsolute(const char *filename) {
+ REQUIRE(filename != NULL);
+ /*
+ * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
+ * the UNC style file specs
+ */
+ if ((filename[0] == '\\') && (filename[1] == '\\')) {
+ return (true);
+ }
+ if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\') {
+ return (true);
+ }
+ if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') {
+ return (true);
+ }
+ return (false);
+}
+
+bool
+isc_file_iscurrentdir(const char *filename) {
+ REQUIRE(filename != NULL);
+ return (filename[0] == '.' && filename[1] == '\0');
+}
+
+bool
+isc_file_ischdiridempotent(const char *filename) {
+ REQUIRE(filename != NULL);
+
+ if (isc_file_isabsolute(filename)) {
+ return (true);
+ }
+ if (filename[0] == '\\') {
+ return (true);
+ }
+ if (filename[0] == '/') {
+ return (true);
+ }
+ if (isc_file_iscurrentdir(filename)) {
+ return (true);
+ }
+ return (false);
+}
+
+const char *
+isc_file_basename(const char *filename) {
+ char *s;
+
+ REQUIRE(filename != NULL);
+
+ s = strrchr(filename, '\\');
+ if (s == NULL) {
+ return (filename);
+ }
+ return (s + 1);
+}
+
+isc_result_t
+isc_file_progname(const char *filename, char *progname, size_t namelen) {
+ const char *s;
+ const char *p;
+ size_t len;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(progname != NULL);
+
+ /*
+ * Strip the path from the name
+ */
+ s = isc_file_basename(filename);
+ if (s == NULL) {
+ return (ISC_R_NOSPACE);
+ }
+
+ /*
+ * Strip any and all suffixes
+ */
+ p = strchr(s, '.');
+ if (p == NULL) {
+ if (namelen <= strlen(s)) {
+ return (ISC_R_NOSPACE);
+ }
+
+ strlcpy(progname, s, namelen);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * Copy the result to the buffer
+ */
+ len = p - s;
+ if (len >= namelen) {
+ return (ISC_R_NOSPACE);
+ }
+
+ /* Copy up to 'len' bytes and NUL terminate. */
+ strlcpy(progname, s, ISC_MIN(len + 1, namelen));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
+ char *ptrname;
+ DWORD retval;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(path != NULL);
+
+ retval = GetFullPathName(filename, (DWORD)pathlen, path, &ptrname);
+
+ /* Something went wrong in getting the path */
+ if (retval == 0) {
+ return (ISC_R_NOTFOUND);
+ }
+ /* Caller needs to provide a larger buffer to contain the string */
+ if (retval >= pathlen) {
+ return (ISC_R_NOSPACE);
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_truncate(const char *filename, isc_offset_t size) {
+ int fh;
+
+ REQUIRE(filename != NULL && size >= 0);
+
+ if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0) {
+ return (isc__errno2result(errno));
+ }
+
+ if (_chsize(fh, size) != 0) {
+ close(fh);
+ return (isc__errno2result(errno));
+ }
+ close(fh);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_safecreate(const char *filename, FILE **fp) {
+ isc_result_t result;
+ int flags;
+ struct stat sb;
+ FILE *f;
+ int fd;
+
+ REQUIRE(filename != NULL);
+ REQUIRE(fp != NULL && *fp == NULL);
+
+ result = file_stats(filename, &sb);
+ if (result == ISC_R_SUCCESS) {
+ if ((sb.st_mode & S_IFREG) == 0) {
+ return (ISC_R_INVALIDFILE);
+ }
+ flags = O_WRONLY | O_TRUNC;
+ } else if (result == ISC_R_FILENOTFOUND) {
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+ } else {
+ return (result);
+ }
+
+ fd = open(filename, flags, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ return (isc__errno2result(errno));
+ }
+
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ result = isc__errno2result(errno);
+ close(fd);
+ return (result);
+ }
+
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_splitpath(isc_mem_t *mctx, const char *path, char **dirname,
+ char const **basename) {
+ char *dir;
+ const char *file, *slash;
+ char *backslash;
+
+ slash = strrchr(path, '/');
+
+ backslash = strrchr(path, '\\');
+ if ((slash != NULL && backslash != NULL && backslash > slash) ||
+ (slash == NULL && backslash != NULL))
+ {
+ slash = backslash;
+ }
+
+ if (slash == path) {
+ file = ++slash;
+ dir = isc_mem_strdup(mctx, "/");
+ } else if (slash != NULL) {
+ file = ++slash;
+ dir = isc_mem_allocate(mctx, slash - path);
+ strlcpy(dir, path, slash - path);
+ } else {
+ file = path;
+ dir = isc_mem_strdup(mctx, ".");
+ }
+
+ if (dir == NULL) {
+ return (ISC_R_NOMEMORY);
+ }
+
+ if (*file == '\0') {
+ isc_mem_free(mctx, dir);
+ return (ISC_R_INVALIDFILE);
+ }
+
+ *dirname = dir;
+ *basename = file;
+
+ return (ISC_R_SUCCESS);
+}
+
+void *
+isc_file_mmap(void *addr, size_t len, int prot, int flags, int fd,
+ off_t offset) {
+ void *buf;
+ ssize_t ret;
+ off_t end;
+
+ UNUSED(addr);
+ UNUSED(prot);
+ UNUSED(flags);
+
+ end = lseek(fd, 0, SEEK_END);
+ lseek(fd, offset, SEEK_SET);
+ if (end - offset < (off_t)len) {
+ len = end - offset;
+ }
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ return (NULL);
+ }
+
+ ret = read(fd, buf, (unsigned int)len);
+ if (ret != (ssize_t)len) {
+ free(buf);
+ buf = NULL;
+ }
+
+ return (buf);
+}
+
+int
+isc_file_munmap(void *addr, size_t len) {
+ UNUSED(len);
+ free(addr);
+ return (0);
+}
+
+#define DISALLOW "\\/:ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+static isc_result_t
+digest2hex(unsigned char *digest, unsigned int digestlen, char *hash,
+ size_t hashlen) {
+ unsigned int i;
+ int ret;
+ for (i = 0; i < digestlen; i++) {
+ size_t left = hashlen - i * 2;
+ ret = snprintf(hash + i * 2, left, "%02x", digest[i]);
+ if (ret < 0 || (size_t)ret >= left) {
+ return (ISC_R_NOSPACE);
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_file_sanitize(const char *dir, const char *base, const char *ext,
+ char *path, size_t length) {
+ char buf[PATH_MAX];
+ unsigned char digest[ISC_MAX_MD_SIZE];
+ unsigned int digestlen;
+ char hash[ISC_MAX_MD_SIZE * 2 + 1];
+ size_t l = 0;
+ isc_result_t err;
+
+ REQUIRE(base != NULL);
+ REQUIRE(path != NULL);
+
+ l = strlen(base) + 1;
+
+ /*
+ * allow room for a full sha256 hash (64 chars
+ * plus null terminator)
+ */
+ if (l < 65) {
+ l = 65;
+ }
+
+ if (dir != NULL) {
+ l += strlen(dir) + 1;
+ }
+ if (ext != NULL) {
+ l += strlen(ext) + 1;
+ }
+
+ if (l > length || l > PATH_MAX) {
+ return (ISC_R_NOSPACE);
+ }
+
+ /* Check whether the full-length SHA256 hash filename exists */
+ err = isc_md(ISC_MD_SHA256, (const unsigned char *)base, strlen(base),
+ digest, &digestlen);
+ if (err != ISC_R_SUCCESS) {
+ return (err);
+ }
+
+ err = digest2hex(digest, digestlen, hash, sizeof(hash));
+ if (err != ISC_R_SUCCESS) {
+ return (err);
+ }
+
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s", dir != NULL ? dir : "",
+ dir != NULL ? "/" : "", hash, ext != NULL ? "." : "",
+ ext != NULL ? ext : "");
+ if (isc_file_exists(buf)) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ /* Check for a truncated SHA256 hash filename */
+ hash[16] = '\0';
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s", dir != NULL ? dir : "",
+ dir != NULL ? "/" : "", hash, ext != NULL ? "." : "",
+ ext != NULL ? ext : "");
+ if (isc_file_exists(buf)) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ /*
+ * If neither hash filename already exists, then we'll use
+ * the original base name if it has no disallowed characters,
+ * or the truncated hash name if it does.
+ */
+ if (strpbrk(base, DISALLOW) != NULL) {
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+ }
+
+ snprintf(buf, sizeof(buf), "%s%s%s%s%s", dir != NULL ? dir : "",
+ dir != NULL ? "/" : "", base, ext != NULL ? "." : "",
+ ext != NULL ? ext : "");
+ strlcpy(path, buf, length);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Based on http://blog.aaronballman.com/2011/08/how-to-check-access-rights/
+ */
+bool
+isc_file_isdirwritable(const char *path) {
+ DWORD length = 0;
+ HANDLE hToken = NULL;
+ PSECURITY_DESCRIPTOR security = NULL;
+ bool answer = false;
+
+ if (isc_file_isdirectory(path) != ISC_R_SUCCESS) {
+ return (answer);
+ }
+
+ /*
+ * Figure out buffer size. GetFileSecurity() should not succeed.
+ */
+ if (GetFileSecurity(path,
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ NULL, 0, &length))
+ {
+ return (answer);
+ }
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ return (answer);
+ }
+
+ security = malloc(length);
+ if (security == NULL) {
+ return (answer);
+ }
+
+ /*
+ * GetFileSecurity() should succeed.
+ */
+ if (!GetFileSecurity(path,
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION,
+ security, length, &length))
+ {
+ return (answer);
+ }
+
+ if (OpenProcessToken(GetCurrentProcess(),
+ TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE |
+ STANDARD_RIGHTS_READ,
+ &hToken))
+ {
+ HANDLE hImpersonatedToken = NULL;
+
+ if (DuplicateToken(hToken, SecurityImpersonation,
+ &hImpersonatedToken))
+ {
+ GENERIC_MAPPING mapping;
+ PRIVILEGE_SET privileges = { 0 };
+ DWORD grantedAccess = 0;
+ DWORD privilegesLength = sizeof(privileges);
+ BOOL result = FALSE;
+ DWORD genericAccessRights = GENERIC_WRITE;
+
+ mapping.GenericRead = FILE_GENERIC_READ;
+ mapping.GenericWrite = FILE_GENERIC_WRITE;
+ mapping.GenericExecute = FILE_GENERIC_EXECUTE;
+ mapping.GenericAll = FILE_ALL_ACCESS;
+
+ MapGenericMask(&genericAccessRights, &mapping);
+ if (AccessCheck(security, hImpersonatedToken,
+ genericAccessRights, &mapping,
+ &privileges, &privilegesLength,
+ &grantedAccess, &result))
+ {
+ answer = result;
+ }
+ CloseHandle(hImpersonatedToken);
+ }
+ CloseHandle(hToken);
+ }
+ free(security);
+ return (answer);
+}
diff --git a/lib/isc/win32/fsaccess.c b/lib/isc/win32/fsaccess.c
new file mode 100644
index 0000000..909f9e5
--- /dev/null
+++ b/lib/isc/win32/fsaccess.c
@@ -0,0 +1,404 @@
+/*
+ * 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.
+ */
+
+/*
+ * Note that Win32 does not have the concept of files having access
+ * and ownership bits. The FAT File system only has a readonly flag
+ * for everyone and that's all. NTFS uses ACL's which is a totally
+ * different concept of controlling access.
+ *
+ * This code needs to be revisited to set up proper access control for
+ * NTFS file systems. Nothing can be done for FAT file systems.
+ */
+
+#include <aclapi.h>
+#include <errno.h>
+#include <io.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <isc/file.h>
+#include <isc/stat.h>
+#include <isc/string.h>
+
+#include "errno2result.h"
+
+/*
+ * The OS-independent part of the API is in lib/isc.
+ */
+#include "../fsaccess.c"
+
+/* Store the user account name locally */
+static char username[255] = "\0";
+static DWORD namelen = 0;
+
+/*
+ * In order to set or retrieve access information, we need to obtain
+ * the File System type. These could be UNC-type shares.
+ */
+
+BOOL
+is_ntfs(const char *file) {
+ char drive[255];
+ char FSType[20];
+ char tmpbuf[256];
+ char *machinename;
+ char *sharename;
+ char filename[1024];
+ char *last;
+
+ REQUIRE(filename != NULL);
+
+ if (isc_file_absolutepath(file, filename, sizeof(filename)) !=
+ ISC_R_SUCCESS)
+ {
+ return (FALSE);
+ }
+
+ /*
+ * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
+ * the UNC style file specs
+ */
+ if (isalpha(filename[0]) && filename[1] == ':' &&
+ (filename[2] == '\\' || filename[2] == '/'))
+ {
+ /* Copy 'c:\' or 'c:/' and NUL terminate. */
+ strlcpy(drive, filename, ISC_MIN(3 + 1, sizeof(drive)));
+ } else if ((filename[0] == '\\') && (filename[1] == '\\')) {
+ /* Find the machine and share name and rebuild the UNC */
+ strlcpy(tmpbuf, filename, sizeof(tmpbuf));
+ machinename = strtok_r(tmpbuf, "\\", &last);
+ sharename = strtok_r(NULL, "\\", &last);
+ strlcpy(drive, "\\\\", sizeof(drive));
+ strlcat(drive, machinename, sizeof(drive));
+ strlcat(drive, "\\", sizeof(drive));
+ strlcat(drive, sharename, sizeof(drive));
+ strlcat(drive, "\\", sizeof(drive));
+ } else { /* Not determinable */
+ return (FALSE);
+ }
+
+ GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType,
+ sizeof(FSType));
+ if (strcmp(FSType, "NTFS") == 0) {
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/*
+ * If it's not NTFS, we assume that it is FAT and proceed
+ * with almost nothing to do. Only the write flag can be set or
+ * cleared.
+ */
+isc_result_t
+FAT_fsaccess_set(const char *path, isc_fsaccess_t access) {
+ int mode;
+ isc_fsaccess_t bits;
+
+ /*
+ * Done with checking bad bits. Set mode_t.
+ */
+ mode = 0;
+
+#define SET_AND_CLEAR1(modebit) \
+ if ((access & bits) != 0) { \
+ mode |= modebit; \
+ access &= ~bits; \
+ }
+#define SET_AND_CLEAR(user, group, other) \
+ SET_AND_CLEAR1(user); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(group); \
+ bits <<= STEP; \
+ SET_AND_CLEAR1(other);
+
+ bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
+
+ SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
+
+ bits = ISC_FSACCESS_WRITE | ISC_FSACCESS_CREATECHILD |
+ ISC_FSACCESS_DELETECHILD;
+
+ SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
+
+ INSIST(access == 0);
+
+ if (_chmod(path, mode) < 0) {
+ return (isc__errno2result(errno));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+NTFS_Access_Control(const char *filename, const char *user, int access,
+ bool isdir) {
+ SECURITY_DESCRIPTOR sd;
+ BYTE aclBuffer[1024];
+ PACL pacl = (PACL)&aclBuffer;
+ BYTE sidBuffer[100];
+ PSID psid = (PSID)&sidBuffer;
+ DWORD sidBufferSize = sizeof(sidBuffer);
+ BYTE adminSidBuffer[100];
+ PSID padminsid = (PSID)&adminSidBuffer;
+ DWORD adminSidBufferSize = sizeof(adminSidBuffer);
+ BYTE otherSidBuffer[100];
+ PSID pothersid = (PSID)&otherSidBuffer;
+ DWORD otherSidBufferSize = sizeof(otherSidBuffer);
+ char domainBuffer[100];
+ DWORD domainBufferSize = sizeof(domainBuffer);
+ SID_NAME_USE snu;
+ DWORD NTFSbits;
+ int caccess;
+
+ /* Initialize an ACL */
+ if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
+ return (ISC_R_NOPERM);
+ }
+ if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION)) {
+ return (ISC_R_NOPERM);
+ }
+ if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
+ &domainBufferSize, &snu))
+ {
+ return (ISC_R_NOPERM);
+ }
+ domainBufferSize = sizeof(domainBuffer);
+ if (!LookupAccountName(0, "Administrators", padminsid,
+ &adminSidBufferSize, domainBuffer,
+ &domainBufferSize, &snu))
+ {
+ (void)GetLastError();
+ return (ISC_R_NOPERM);
+ }
+ domainBufferSize = sizeof(domainBuffer);
+ if (!LookupAccountName(0, "Everyone", pothersid, &otherSidBufferSize,
+ domainBuffer, &domainBufferSize, &snu))
+ {
+ (void)GetLastError();
+ return (ISC_R_NOPERM);
+ }
+
+ caccess = access;
+ /* Owner check */
+
+ NTFSbits = 0;
+ if ((caccess & ISC_FSACCESS_READ) != 0) {
+ NTFSbits |= FILE_GENERIC_READ;
+ }
+ if ((caccess & ISC_FSACCESS_WRITE) != 0) {
+ NTFSbits |= FILE_GENERIC_WRITE;
+ }
+ if ((caccess & ISC_FSACCESS_EXECUTE) != 0) {
+ NTFSbits |= FILE_GENERIC_EXECUTE;
+ }
+
+ /* For directories check the directory-specific bits */
+ if (isdir) {
+ if ((caccess & ISC_FSACCESS_CREATECHILD) != 0) {
+ NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE;
+ }
+ if ((caccess & ISC_FSACCESS_DELETECHILD) != 0) {
+ NTFSbits |= FILE_DELETE_CHILD;
+ }
+ if ((caccess & ISC_FSACCESS_LISTDIRECTORY) != 0) {
+ NTFSbits |= FILE_LIST_DIRECTORY;
+ }
+ if ((caccess & ISC_FSACCESS_ACCESSCHILD) != 0) {
+ NTFSbits |= FILE_TRAVERSE;
+ }
+ }
+
+ if (NTFSbits ==
+ (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE))
+ {
+ NTFSbits |= FILE_ALL_ACCESS;
+ }
+ /*
+ * Owner and Administrator also get STANDARD_RIGHTS_ALL
+ * to ensure that they have full control
+ */
+
+ NTFSbits |= STANDARD_RIGHTS_ALL;
+
+ /* Add the ACE to the ACL */
+ if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid)) {
+ return (ISC_R_NOPERM);
+ }
+ if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid)) {
+ return (ISC_R_NOPERM);
+ }
+
+ /*
+ * Group is ignored since we can be in multiple groups or no group
+ * and its meaning is not clear on Win32
+ */
+
+ caccess = caccess >> STEP;
+
+ /*
+ * Other check. We translate this to be the same as Everyone
+ */
+
+ caccess = caccess >> STEP;
+
+ NTFSbits = 0;
+ if ((caccess & ISC_FSACCESS_READ) != 0) {
+ NTFSbits |= FILE_GENERIC_READ;
+ }
+ if ((caccess & ISC_FSACCESS_WRITE) != 0) {
+ NTFSbits |= FILE_GENERIC_WRITE;
+ }
+ if ((caccess & ISC_FSACCESS_EXECUTE) != 0) {
+ NTFSbits |= FILE_GENERIC_EXECUTE;
+ }
+
+ /* For directories check the directory-specific bits */
+ if (isdir == TRUE) {
+ if ((caccess & ISC_FSACCESS_CREATECHILD) != 0) {
+ NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE;
+ }
+ if ((caccess & ISC_FSACCESS_DELETECHILD) != 0) {
+ NTFSbits |= FILE_DELETE_CHILD;
+ }
+ if ((caccess & ISC_FSACCESS_LISTDIRECTORY) != 0) {
+ NTFSbits |= FILE_LIST_DIRECTORY;
+ }
+ if ((caccess & ISC_FSACCESS_ACCESSCHILD) != 0) {
+ NTFSbits |= FILE_TRAVERSE;
+ }
+ }
+ /* Add the ACE to the ACL */
+ if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, pothersid)) {
+ return (ISC_R_NOPERM);
+ }
+
+ if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) {
+ return (ISC_R_NOPERM);
+ }
+ if (!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) {
+ return (ISC_R_NOPERM);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+NTFS_fsaccess_set(const char *path, isc_fsaccess_t access, bool isdir) {
+ /*
+ * For NTFS we first need to get the name of the account under
+ * which BIND is running
+ */
+ if (namelen == 0) {
+ namelen = sizeof(username);
+ if (GetUserName(username, &namelen) == 0) {
+ return (ISC_R_FAILURE);
+ }
+ }
+ return (NTFS_Access_Control(path, username, access, isdir));
+}
+
+isc_result_t
+isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
+ struct stat statb;
+ bool is_dir = false;
+ isc_result_t result;
+
+ if (stat(path, &statb) != 0) {
+ return (isc__errno2result(errno));
+ }
+
+ if ((statb.st_mode & S_IFDIR) != 0) {
+ is_dir = true;
+ } else if ((statb.st_mode & S_IFREG) == 0) {
+ return (ISC_R_INVALIDFILE);
+ }
+
+ result = check_bad_bits(access, is_dir);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ /*
+ * Determine if this is a FAT or NTFS disk and
+ * call the appropriate function to set the permissions
+ */
+ if (is_ntfs(path)) {
+ return (NTFS_fsaccess_set(path, access, is_dir));
+ } else {
+ return (FAT_fsaccess_set(path, access));
+ }
+}
+
+isc_result_t
+isc_fsaccess_changeowner(const char *filename, const char *user) {
+ SECURITY_DESCRIPTOR psd;
+ BYTE sidBuffer[500];
+ BYTE groupBuffer[500];
+ PSID psid = (PSID)&sidBuffer;
+ DWORD sidBufferSize = sizeof(sidBuffer);
+ char domainBuffer[100];
+ DWORD domainBufferSize = sizeof(domainBuffer);
+ SID_NAME_USE snu;
+ PSID pSidGroup = (PSID)&groupBuffer;
+ DWORD groupBufferSize = sizeof(groupBuffer);
+
+ /*
+ * Determine if this is a FAT or NTFS disk and
+ * call the appropriate function to set the ownership
+ * FAT disks do not have ownership attributes so it's
+ * a noop.
+ */
+ if (is_ntfs(filename) == FALSE) {
+ return (ISC_R_SUCCESS);
+ }
+
+ if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION)) {
+ return (ISC_R_NOPERM);
+ }
+
+ if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
+ &domainBufferSize, &snu))
+ {
+ return (ISC_R_NOPERM);
+ }
+
+ /* Make sure administrators can get to it */
+ domainBufferSize = sizeof(domainBuffer);
+ if (!LookupAccountName(0, "Administrators", pSidGroup, &groupBufferSize,
+ domainBuffer, &domainBufferSize, &snu))
+ {
+ return (ISC_R_NOPERM);
+ }
+
+ if (!SetSecurityDescriptorOwner(&psd, psid, FALSE)) {
+ return (ISC_R_NOPERM);
+ }
+
+ if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE)) {
+ return (ISC_R_NOPERM);
+ }
+
+ if (!SetFileSecurity(filename,
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION,
+ &psd))
+ {
+ return (ISC_R_NOPERM);
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/include/.clang-format b/lib/isc/win32/include/.clang-format
new file mode 120000
index 0000000..e919bba
--- /dev/null
+++ b/lib/isc/win32/include/.clang-format
@@ -0,0 +1 @@
+../../../../.clang-format.headers \ No newline at end of file
diff --git a/lib/isc/win32/include/Makefile.in b/lib/isc/win32/include/Makefile.in
new file mode 100644
index 0000000..60a0a67
--- /dev/null
+++ b/lib/isc/win32/include/Makefile.in
@@ -0,0 +1,19 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+SUBDIRS = isc
+TARGETS =
+
+@BIND9_MAKE_RULES@
diff --git a/lib/isc/win32/include/isc/Makefile.in b/lib/isc/win32/include/isc/Makefile.in
new file mode 100644
index 0000000..7718caa
--- /dev/null
+++ b/lib/isc/win32/include/isc/Makefile.in
@@ -0,0 +1,32 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+VERSION=@BIND9_VERSION@
+
+HEADERS = align.h dir.h mutex.h net.h netdb.h once.h \
+ stat.h stdtime.h thread.h time.h
+
+SUBDIRS =
+TARGETS =
+
+@BIND9_MAKE_RULES@
+
+installdirs:
+ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}\isc
+
+install:: installdirs
+ for i in $(HEADERS); do \
+ $(INSTALL_DATA) $(srcdir)\$$i $(includedir)\isc || exit 1; \
+ done
diff --git a/lib/isc/win32/include/isc/align.h b/lib/isc/win32/include/isc/align.h
new file mode 100644
index 0000000..6e98665
--- /dev/null
+++ b/lib/isc/win32/include/isc/align.h
@@ -0,0 +1,15 @@
+/*
+ * 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
+#define alignas(x) __declspec(align(x))
diff --git a/lib/isc/win32/include/isc/bind_registry.h b/lib/isc/win32/include/isc/bind_registry.h
new file mode 100644
index 0000000..6c997d6
--- /dev/null
+++ b/lib/isc/win32/include/isc/bind_registry.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.
+ */
+
+#ifndef ISC_BINDREGISTRY_H
+#define ISC_BINDREGISTRY_H
+
+/*
+ * BIND makes use of the following Registry keys in various places, especially
+ * during startup and installation
+ */
+
+#define BIND_SUBKEY "Software\\ISC\\BIND"
+#define BIND_SESSION "CurrentSession"
+#define BIND_SESSION_SUBKEY "Software\\ISC\\BIND\\CurrentSession"
+#define BIND_UNINSTALL_SUBKEY \
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ISC BIND"
+
+#define EVENTLOG_APP_SUBKEY \
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"
+#define BIND_MESSAGE_SUBKEY \
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\named"
+#define BIND_MESSAGE_NAME "named"
+
+#define BIND_SERVICE_SUBKEY "SYSTEM\\CurrentControlSet\\Services\\named"
+
+#define BIND_CONFIGFILE 0
+#define BIND_DEBUGLEVEL 1
+#define BIND_QUERYLOG 2
+#define BIND_FOREGROUND 3
+#define BIND_PORT 4
+
+#endif /* ISC_BINDREGISTRY_H */
diff --git a/lib/isc/win32/include/isc/bindevt.h b/lib/isc/win32/include/isc/bindevt.h
new file mode 100644
index 0000000..406efe3
--- /dev/null
+++ b/lib/isc/win32/include/isc/bindevt.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_BINDEVT_H
+#define ISC_BINDEVT_H 1
+
+/*
+ * This is used for the event log for both logging the messages and
+ * later on by the event viewer when looking at the events
+ */
+
+/*
+ * Values are 32 bit values laid out as follows:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-+-----------------------+-------------------------------+
+ * |Sev|C|R| Facility | Code |
+ * +---+-+-+-----------------------+-------------------------------+
+ *
+ * where
+ *
+ * Sev - is the severity code
+ *
+ * 00 - Success
+ * 01 - Informational
+ * 10 - Warning
+ * 11 - Error
+ *
+ * C - is the Customer code flag
+ *
+ * R - is a reserved bit
+ *
+ * Facility - is the facility code
+ *
+ * Code - is the facility's status code
+ *
+ *
+ * Define the facility codes
+ */
+
+/*
+ * Define the severity codes
+ */
+
+/*
+ * MessageId: BIND_ERR_MSG
+ *
+ * MessageText:
+ *
+ * %1
+ */
+#define BIND_ERR_MSG ((DWORD)0xC0000001L)
+
+/*
+ * MessageId: BIND_WARN_MSG
+ *
+ * MessageText:
+ *
+ * %1
+ */
+#define BIND_WARN_MSG ((DWORD)0x80000002L)
+
+/*
+ * MessageId: BIND_INFO_MSG
+ *
+ * MessageText:
+ *
+ * %1
+ */
+#define BIND_INFO_MSG ((DWORD)0x40000003L)
+
+#endif /* ISC_BINDEVT_H */
diff --git a/lib/isc/win32/include/isc/condition.h b/lib/isc/win32/include/isc/condition.h
new file mode 100644
index 0000000..738419c
--- /dev/null
+++ b/lib/isc/win32/include/isc/condition.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_CONDITION_H
+#define ISC_CONDITION_H 1
+
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/thread.h>
+#include <isc/types.h>
+
+typedef struct isc_condition_thread isc_condition_thread_t;
+
+struct isc_condition_thread {
+ uintptr_t th;
+ HANDLE handle[2];
+ ISC_LINK(isc_condition_thread_t) link;
+};
+
+typedef struct isc_condition {
+ HANDLE events[2];
+ unsigned int waiters;
+ ISC_LIST(isc_condition_thread_t) threadlist;
+} isc_condition_t;
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_condition_init(isc_condition_t *);
+
+isc_result_t
+isc_condition_wait(isc_condition_t *, isc_mutex_t *);
+
+isc_result_t
+isc_condition_signal(isc_condition_t *);
+
+isc_result_t
+isc_condition_broadcast(isc_condition_t *);
+
+isc_result_t
+isc_condition_destroy(isc_condition_t *);
+
+isc_result_t
+isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_CONDITION_H */
diff --git a/lib/isc/win32/include/isc/dir.h b/lib/isc/win32/include/isc/dir.h
new file mode 100644
index 0000000..f0050dd
--- /dev/null
+++ b/lib/isc/win32/include/isc/dir.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.
+ */
+
+#ifndef ISC_DIR_H
+#define ISC_DIR_H 1
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/platform.h>
+#include <isc/result.h>
+
+typedef struct {
+ char name[NAME_MAX];
+ unsigned int length;
+ WIN32_FIND_DATA find_data;
+} isc_direntry_t;
+
+typedef struct {
+ unsigned int magic;
+ char dirname[PATH_MAX];
+ isc_direntry_t entry;
+ bool entry_filled;
+ HANDLE search_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
+
+#endif /* ISC_DIR_H */
diff --git a/lib/isc/win32/include/isc/ipv6.h b/lib/isc/win32/include/isc/ipv6.h
new file mode 100644
index 0000000..4ab567a
--- /dev/null
+++ b/lib/isc/win32/include/isc/ipv6.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef ISC_IPV6_H
+#define ISC_IPV6_H 1
+
+/*****
+***** Module Info
+*****/
+
+/*
+ * IPv6 definitions for systems which do not support IPv6.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * RFC2553.
+ */
+
+#if _MSC_VER < 1300
+#define in6_addr in_addr6
+#endif /* if _MSC_VER < 1300 */
+
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \
+ } \
+ }
+#endif /* ifndef IN6ADDR_ANY_INIT */
+#ifndef IN6ADDR_LOOPBACK_INIT
+#define IN6ADDR_LOOPBACK_INIT \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \
+ } \
+ }
+#endif /* ifndef IN6ADDR_LOOPBACK_INIT */
+#ifndef IN6ADDR_V4MAPPED_INIT
+#define IN6ADDR_V4MAPPED_INIT \
+ { \
+ { \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 \
+ } \
+ }
+#endif /* ifndef IN6ADDR_V4MAPPED_INIT */
+
+LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_in6addr_any;
+LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_in6addr_loopback;
+
+/*
+ * Unspecified
+ */
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (*((u_long *)((a)->s6_addr)) == 0 && \
+ *((u_long *)((a)->s6_addr) + 1) == 0 && \
+ *((u_long *)((a)->s6_addr) + 2) == 0 && \
+ *((u_long *)((a)->s6_addr) + 3) == 0)
+#endif /* ifndef IN6_IS_ADDR_UNSPECIFIED */
+
+/*
+ * Loopback
+ */
+#ifndef IN6_IS_ADDR_LOOPBACK
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (*((u_long *)((a)->s6_addr)) == 0 && \
+ *((u_long *)((a)->s6_addr) + 1) == 0 && \
+ *((u_long *)((a)->s6_addr) + 2) == 0 && \
+ *((u_long *)((a)->s6_addr) + 3) == htonl(1))
+#endif /* ifndef IN6_IS_ADDR_LOOPBACK */
+
+/*
+ * IPv4 compatible
+ */
+#define IN6_IS_ADDR_V4COMPAT(a) \
+ (*((u_long *)((a)->s6_addr)) == 0 && \
+ *((u_long *)((a)->s6_addr) + 1) == 0 && \
+ *((u_long *)((a)->s6_addr) + 2) == 0 && \
+ *((u_long *)((a)->s6_addr) + 3) != 0 && \
+ *((u_long *)((a)->s6_addr) + 3) != htonl(1))
+
+/*
+ * Mapped
+ */
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ (*((u_long *)((a)->s6_addr)) == 0 && \
+ *((u_long *)((a)->s6_addr) + 1) == 0 && \
+ *((u_long *)((a)->s6_addr) + 2) == htonl(0x0000ffff))
+
+/*
+ * Multicast
+ */
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xffU)
+
+/*
+ * Unicast link / site local.
+ */
+#ifndef IN6_IS_ADDR_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
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif /* ifndef IN6_IS_ADDR_SITELOCAL */
+
+#endif /* ISC_IPV6_H */
diff --git a/lib/isc/win32/include/isc/mutex.h b/lib/isc/win32/include/isc/mutex.h
new file mode 100644
index 0000000..3fcc538
--- /dev/null
+++ b/lib/isc/win32/include/isc/mutex.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_MUTEX_H
+#define ISC_MUTEX_H 1
+
+#include <windows.h>
+
+#include <isc/net.h>
+#include <isc/result.h>
+
+typedef CRITICAL_SECTION isc_mutex_t;
+
+/*
+ * This definition is here since some versions of WINBASE.H
+ * omits it for some reason.
+ */
+#if (_WIN32_WINNT < 0x0400)
+WINBASEAPI BOOL WINAPI
+TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+#endif /* _WIN32_WINNT < 0x0400 */
+
+#define isc_mutex_init(mp) InitializeCriticalSection((mp))
+#define isc_mutex_lock(mp) (EnterCriticalSection((mp)), ISC_R_SUCCESS)
+#define isc_mutex_unlock(mp) (LeaveCriticalSection((mp)), ISC_R_SUCCESS)
+#define isc_mutex_trylock(mp) \
+ (TryEnterCriticalSection((mp)) ? ISC_R_SUCCESS : ISC_R_LOCKBUSY)
+#define isc_mutex_destroy(mp) (DeleteCriticalSection((mp)))
+
+/*
+ * This is a placeholder for now since we are not keeping any mutex stats
+ */
+#define isc_mutex_stats(fp) \
+ do { \
+ } while (0)
+
+#endif /* ISC_MUTEX_H */
diff --git a/lib/isc/win32/include/isc/net.h b/lib/isc/win32/include/isc/net.h
new file mode 100644
index 0000000..391614e
--- /dev/null
+++ b/lib/isc/win32/include/isc/net.h
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_NET_H
+#define ISC_NET_H 1
+
+/*****
+***** Module Info
+*****/
+
+/*
+ * Basic Networking Types
+ *
+ * This module is responsible for defining the following basic networking
+ * types:
+ *
+ * struct in_addr
+ * struct in6_addr
+ * struct in6_pktinfo
+ * struct sockaddr
+ * struct sockaddr_in
+ * struct sockaddr_in6
+ * 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_ANY, IN6ADDR_ANY_INIT, in6addr_any, and
+ * in6addr_loopback are available.
+ *
+ * It ensures that IN_MULTICAST() is available to check for multicast
+ * addresses.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * BSD Socket API
+ * RFC2553
+ */
+
+/***
+ *** Imports.
+ ***/
+#include <inttypes.h>
+
+#include <isc/platform.h>
+
+/*
+ * Because of some sort of problem in the MS header files, this cannot
+ * be simple "#include <winsock2.h>", because winsock2.h tries to include
+ * windows.h, which then generates an error out of mswsock.h. _You_
+ * figure it out.
+ */
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
+#endif /* ifndef _WINSOCKAPI_ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <isc/ipv6.h>
+#include <isc/lang.h>
+#include <isc/types.h>
+
+#include <sys/types.h>
+
+/*
+ * This is here because named client, interfacemgr.c, etc. use the name as
+ * a variable
+ */
+#undef interface
+
+#ifndef INADDR_ANY
+#define INADDR_ANY 0x00000000UL
+#endif /* ifndef INADDR_ANY */
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif /* ifndef INADDR_LOOPBACK */
+
+#if _MSC_VER < 1300
+#define in6addr_any isc_in6addr_any
+#define in6addr_loopback isc_in6addr_loopback
+#endif /* if _MSC_VER < 1300 */
+
+/*
+ * Ensure type in_port_t is defined.
+ */
+typedef uint16_t in_port_t;
+
+/*
+ * 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.
+ */
+#ifndef MSG_TRUNC
+#define ISC_PLATFORM_RECVOVERFLOW
+#endif /* ifndef MSG_TRUNC */
+
+#define ISC__IPADDR(x) ((uint32_t)htonl((uint32_t)(x)))
+
+#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))
+
+/*
+ * Fix the FD_SET and FD_CLR Macros to properly cast
+ */
+#undef FD_CLR
+#define FD_CLR(fd, set) \
+ do { \
+ u_int __i; \
+ for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \
+ if (((fd_set FAR *)(set))->fd_array[__i] == \
+ (SOCKET)fd) { \
+ while (__i < \
+ ((fd_set FAR *)(set))->fd_count - 1) \
+ { \
+ ((fd_set FAR *)(set))->fd_array[__i] = \
+ ((fd_set FAR *)(set)) \
+ ->fd_array[__i + 1]; \
+ __i++; \
+ } \
+ ((fd_set FAR *)(set))->fd_count--; \
+ break; \
+ } \
+ } \
+ } while (0)
+
+#undef FD_SET
+#define FD_SET(fd, set) \
+ do { \
+ u_int __i; \
+ for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \
+ if (((fd_set FAR *)(set))->fd_array[__i] == \
+ (SOCKET)(fd)) \
+ { \
+ break; \
+ } \
+ } \
+ if (__i == ((fd_set FAR *)(set))->fd_count) { \
+ if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { \
+ ((fd_set FAR *)(set))->fd_array[__i] = \
+ (SOCKET)(fd); \
+ ((fd_set FAR *)(set))->fd_count++; \
+ } \
+ } \
+ } while (0)
+
+/*
+ * Windows Sockets errors redefined as regular Berkeley error constants.
+ * These are usually commented out in Windows NT to avoid conflicts with
+ * errno.h. Use the WSA constants instead.
+ */
+
+#include <errno.h>
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif /* ifndef EWOULDBLOCK */
+#ifndef EINPROGRESS
+#define EINPROGRESS WSAEINPROGRESS
+#endif /* ifndef EINPROGRESS */
+#ifndef EALREADY
+#define EALREADY WSAEALREADY
+#endif /* ifndef EALREADY */
+#ifndef ENOTSOCK
+#define ENOTSOCK WSAENOTSOCK
+#endif /* ifndef ENOTSOCK */
+#ifndef EDESTADDRREQ
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#endif /* ifndef EDESTADDRREQ */
+#ifndef EMSGSIZE
+#define EMSGSIZE WSAEMSGSIZE
+#endif /* ifndef EMSGSIZE */
+#ifndef EPROTOTYPE
+#define EPROTOTYPE WSAEPROTOTYPE
+#endif /* ifndef EPROTOTYPE */
+#ifndef ENOPROTOOPT
+#define ENOPROTOOPT WSAENOPROTOOPT
+#endif /* ifndef ENOPROTOOPT */
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#endif /* ifndef EPROTONOSUPPORT */
+#ifndef ESOCKTNOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#endif /* ifndef ESOCKTNOSUPPORT */
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#endif /* ifndef EOPNOTSUPP */
+#ifndef EPFNOSUPPORT
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#endif /* ifndef EPFNOSUPPORT */
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif /* ifndef EAFNOSUPPORT */
+#ifndef EADDRINUSE
+#define EADDRINUSE WSAEADDRINUSE
+#endif /* ifndef EADDRINUSE */
+#ifndef EADDRNOTAVAIL
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#endif /* ifndef EADDRNOTAVAIL */
+#ifndef ENETDOWN
+#define ENETDOWN WSAENETDOWN
+#endif /* ifndef ENETDOWN */
+#ifndef ENETUNREACH
+#define ENETUNREACH WSAENETUNREACH
+#endif /* ifndef ENETUNREACH */
+#ifndef ENETRESET
+#define ENETRESET WSAENETRESET
+#endif /* ifndef ENETRESET */
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif /* ifndef ECONNABORTED */
+#ifndef ECONNRESET
+#define ECONNRESET WSAECONNRESET
+#endif /* ifndef ECONNRESET */
+#ifndef ENOBUFS
+#define ENOBUFS WSAENOBUFS
+#endif /* ifndef ENOBUFS */
+#ifndef EISCONN
+#define EISCONN WSAEISCONN
+#endif /* ifndef EISCONN */
+#ifndef ENOTCONN
+#define ENOTCONN WSAENOTCONN
+#endif /* ifndef ENOTCONN */
+#ifndef ESHUTDOWN
+#define ESHUTDOWN WSAESHUTDOWN
+#endif /* ifndef ESHUTDOWN */
+#ifndef ETOOMANYREFS
+#define ETOOMANYREFS WSAETOOMANYREFS
+#endif /* ifndef ETOOMANYREFS */
+#ifndef ETIMEDOUT
+#define ETIMEDOUT WSAETIMEDOUT
+#endif /* ifndef ETIMEDOUT */
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif /* ifndef ECONNREFUSED */
+#ifndef ELOOP
+#define ELOOP WSAELOOP
+#endif /* ifndef ELOOP */
+#ifndef EHOSTDOWN
+#define EHOSTDOWN WSAEHOSTDOWN
+#endif /* ifndef EHOSTDOWN */
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif /* ifndef EHOSTUNREACH */
+#ifndef EPROCLIM
+#define EPROCLIM WSAEPROCLIM
+#endif /* ifndef EPROCLIM */
+#ifndef EUSERS
+#define EUSERS WSAEUSERS
+#endif /* ifndef EUSERS */
+#ifndef EDQUOT
+#define EDQUOT WSAEDQUOT
+#endif /* ifndef EDQUOT */
+#ifndef ESTALE
+#define ESTALE WSAESTALE
+#endif /* ifndef ESTALE */
+#ifndef EREMOTE
+#define EREMOTE WSAEREMOTE
+#endif /* ifndef EREMOTE */
+
+/***
+ *** Functions.
+ ***/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_net_probeipv4(void);
+/*
+ * Check if the system's kernel supports IPv4.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS IPv4 is supported.
+ * ISC_R_NOTFOUND IPv4 is not supported.
+ * ISC_R_DISABLED IPv4 is disabled.
+ * ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeipv6(void);
+/*
+ * Check if the system's kernel supports IPv6.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS IPv6 is supported.
+ * ISC_R_NOTFOUND IPv6 is not supported.
+ * ISC_R_DISABLED IPv6 is disabled.
+ * ISC_R_UNEXPECTED
+ */
+
+isc_result_t
+isc_net_probeunix(void);
+/*
+ * Check if UNIX domain sockets are supported.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS
+ * ISC_R_NOTFOUND
+ */
+
+#define ISC_NET_DSCPRECVV4 0x01 /* Can receive sent DSCP value IPv4 */
+#define ISC_NET_DSCPRECVV6 0x02 /* Can receive sent DSCP value IPv6 */
+#define ISC_NET_DSCPSETV4 0x04 /* Can set DSCP on socket IPv4 */
+#define ISC_NET_DSCPSETV6 0x08 /* Can set DSCP on socket IPv6 */
+#define ISC_NET_DSCPPKTV4 0x10 /* Can set DSCP on per packet IPv4 */
+#define ISC_NET_DSCPPKTV6 0x20 /* Can set DSCP on per packet IPv6 */
+#define ISC_NET_DSCPALL 0x3f /* All valid flags */
+
+unsigned int
+isc_net_probedscp(void);
+/*%<
+ * Probe the level of DSCP support.
+ */
+
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS the option is supported for both TCP and UDP.
+ * ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * 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:
+ *
+ * ISC_R_SUCCESS the option is supported.
+ * ISC_R_NOTFOUND IPv6 itself or the option is not supported.
+ * 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_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
+
+#endif /* ISC_NET_H */
diff --git a/lib/isc/win32/include/isc/netdb.h b/lib/isc/win32/include/isc/netdb.h
new file mode 100644
index 0000000..e37ecb5
--- /dev/null
+++ b/lib/isc/win32/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.
+ */
+
+#ifndef ISC_NETDB_H
+#define ISC_NETDB_H 1
+
+/*****
+***** Module Info
+*****/
+
+/*
+ * Portable netdb.h support.
+ *
+ * This module is responsible for defining the get<x>by<y> APIs.
+ *
+ * MP:
+ * No impact.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * N/A.
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * BSD API
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/net.h>
+
+#endif /* ISC_NETDB_H */
diff --git a/lib/isc/win32/include/isc/ntgroups.h b/lib/isc/win32/include/isc/ntgroups.h
new file mode 100644
index 0000000..496f84a
--- /dev/null
+++ b/lib/isc/win32/include/isc/ntgroups.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_NTGROUPS_H
+#define ISC_NTGROUPS_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_ntsecurity_getaccountgroups(char *name, char **Groups,
+ unsigned int maxgroups, unsigned int *total);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NTGROUPS_H */
diff --git a/lib/isc/win32/include/isc/ntpaths.h b/lib/isc/win32/include/isc/ntpaths.h
new file mode 100644
index 0000000..37c915d
--- /dev/null
+++ b/lib/isc/win32/include/isc/ntpaths.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*
+ * Windows-specific path definitions
+ * These routines are used to set up and return system-specific path
+ * information about the files enumerated in NtPaths
+ */
+
+#ifndef ISC_NTPATHS_H
+#define ISC_NTPATHS_H
+
+#include <isc/lang.h>
+
+/*
+ * Index of paths needed
+ */
+enum NtPaths {
+ NAMED_CONF_PATH,
+ RESOLV_CONF_PATH,
+ RNDC_CONF_PATH,
+ NAMED_PID_PATH,
+ NAMED_LOCK_PATH,
+ LOCAL_STATE_DIR,
+ SYS_CONF_DIR,
+ RNDC_KEY_PATH,
+ SESSION_KEY_PATH,
+ BIND_KEYS_PATH
+};
+
+/*
+ * Define macros to get the path of the config files
+ */
+#define NAMED_CONFFILE isc_ntpaths_get(NAMED_CONF_PATH)
+#define RNDC_CONFFILE isc_ntpaths_get(RNDC_CONF_PATH)
+#define RNDC_KEYFILE isc_ntpaths_get(RNDC_KEY_PATH)
+#define SESSION_KEYFILE isc_ntpaths_get(SESSION_KEY_PATH)
+#define RESOLV_CONF isc_ntpaths_get(RESOLV_CONF_PATH)
+
+/*
+ * Information about where the files are on disk
+ */
+#define NAMED_LOCALSTATEDIR "/dns/bin"
+#define NAMED_SYSCONFDIR "/dns/etc"
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_ntpaths_init(void);
+
+char *
+isc_ntpaths_get(int);
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_NTPATHS_H */
diff --git a/lib/isc/win32/include/isc/offset.h b/lib/isc/win32/include/isc/offset.h
new file mode 100644
index 0000000..f09cfdb
--- /dev/null
+++ b/lib/isc/win32/include/isc/offset.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_OFFSET_H
+#define ISC_OFFSET_H 1
+
+/*
+ * File offsets are operating-system dependent.
+ */
+#include <limits.h> /* Required for CHAR_BIT. */
+
+#include <sys/types.h>
+
+typedef _off_t isc_offset_t;
+
+#endif /* ISC_OFFSET_H */
diff --git a/lib/isc/win32/include/isc/once.h b/lib/isc/win32/include/isc/once.h
new file mode 100644
index 0000000..d2d841f
--- /dev/null
+++ b/lib/isc/win32/include/isc/once.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.
+ */
+
+#ifndef ISC_ONCE_H
+#define ISC_ONCE_H 1
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+ISC_LANG_BEGINDECLS
+
+typedef struct {
+ int status;
+ int counter;
+} isc_once_t;
+
+#define ISC_ONCE_INIT_NEEDED 0
+#define ISC_ONCE_INIT_DONE 1
+
+#define ISC_ONCE_INIT \
+ { \
+ ISC_ONCE_INIT_NEEDED, 1 \
+ }
+
+isc_result_t
+isc_once_do(isc_once_t *controller, void (*function)(void));
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ONCE_H */
diff --git a/lib/isc/win32/include/isc/platform.h.in b/lib/isc/win32/include/isc/platform.h.in
new file mode 100644
index 0000000..b3fad9c
--- /dev/null
+++ b/lib/isc/win32/include/isc/platform.h.in
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H 1
+
+/*****
+ ***** Platform-dependent defines.
+ *****/
+
+#if _MSC_VER > 1400
+#define HAVE_TLS 1
+#define HAVE___DECLSPEC_THREAD 1
+#endif
+
+/*
+ * Some compatibility cludges
+ */
+
+#if defined(_WIN32) || defined(_WIN64)
+/* We are on Windows */
+# define strtok_r strtok_s
+
+#define ISC_STRERRORSIZE 128
+
+#ifndef strtoull
+#define strtoull _strtoui64
+#endif
+
+#include <stdint.h>
+#if _MSC_VER < 1914
+typedef uint32_t socklen_t;
+#endif
+
+#endif
+
+#define __builtin_unreachable() __assume(0)
+
+/*
+ * Remove __attribute__ ((foo)) on Windows
+ */
+
+#define __attribute__(attribute) /* do nothing */
+
+/*
+ * Limits
+ */
+
+#ifndef NAME_MAX
+#define NAME_MAX _MAX_FNAME
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _MAX_PATH
+#endif
+
+/***
+ *** Network.
+ ***/
+
+#undef MSG_TRUNC
+
+typedef uint16_t sa_family_t;
+
+/*
+ * Define if the platform has <sys/un.h>.
+ */
+#undef ISC_PLATFORM_HAVESYSUNH
+
+/*
+ * Defines for the noreturn attribute.
+ */
+#define ISC_PLATFORM_NORETURN_PRE __declspec(noreturn)
+#define ISC_PLATFORM_NORETURN_POST
+
+/*
+ * Set up a macro for importing and exporting from the DLL
+ */
+
+#ifdef LIBISC_EXPORTS
+#define LIBISC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBDNS_EXPORTS
+#define LIBDNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBDNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBISCCC_EXPORTS
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBISCCFG_EXPORTS
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBNS_EXPORTS
+#define LIBNS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBNS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBBIND9_EXPORTS
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#ifdef LIBTESTS_EXPORTS
+#define LIBTESTS_EXTERNAL_DATA __declspec(dllexport)
+#else
+#define LIBTESTS_EXTERNAL_DATA __declspec(dllimport)
+#endif
+
+#endif /* ISC_PLATFORM_H */
diff --git a/lib/isc/win32/include/isc/stat.h b/lib/isc/win32/include/isc/stat.h
new file mode 100644
index 0000000..63577f9
--- /dev/null
+++ b/lib/isc/win32/include/isc/stat.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_STAT_H
+#define ISC_STAT_H 1
+
+#include <sys/stat.h>
+
+/*
+ * Windows doesn't typedef this.
+ */
+typedef unsigned short mode_t;
+
+/* open() under unix allows setting of read/write permissions
+ * at the owner, group and other levels. These don't exist in NT
+ * We'll just map them all to the NT equivalent
+ */
+
+#define S_IREAD _S_IREAD /* read permission, owner */
+#define S_IWRITE _S_IWRITE /* write permission, owner */
+#define S_IRUSR _S_IREAD /* Owner read permission */
+#define S_IWUSR _S_IWRITE /* Owner write permission */
+#define S_IRGRP _S_IREAD /* Group read permission */
+#define S_IWGRP _S_IWRITE /* Group write permission */
+#define S_IROTH _S_IREAD /* Other read permission */
+#define S_IWOTH _S_IWRITE /* Other write permission */
+
+#ifndef S_IFMT
+#define S_IFMT _S_IFMT
+#endif /* ifndef S_IFMT */
+#ifndef S_IFDIR
+#define S_IFDIR _S_IFDIR
+#endif /* ifndef S_IFDIR */
+#ifndef S_IFCHR
+#define S_IFCHR _S_IFCHR
+#endif /* ifndef S_IFCHR */
+#ifndef S_IFREG
+#define S_IFREG _S_IFREG
+#endif /* ifndef S_IFREG */
+
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
+#endif /* ifndef S_ISDIR */
+#ifndef S_ISREG
+#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
+#endif /* ifndef S_ISREG */
+
+#endif /* ISC_STAT_H */
diff --git a/lib/isc/win32/include/isc/stdatomic.h b/lib/isc/win32/include/isc/stdatomic.h
new file mode 100644
index 0000000..dd5293f
--- /dev/null
+++ b/lib/isc/win32/include/isc/stdatomic.h
@@ -0,0 +1,595 @@
+/*
+ * 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
+
+#define WIN32_LEAN_AND_MEAN
+#include <intrin.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <uchar.h>
+#include <windows.h>
+
+#pragma warning(disable : 4133)
+#pragma warning(disable : 4090)
+
+#define InterlockedExchangeAdd8 _InterlockedExchangeAdd8
+#define InterlockedCompareExchange8 _InterlockedCompareExchange8
+
+#pragma intrinsic(_InterlockedCompareExchange8, _InterlockedExchangeAdd8)
+
+#include <isc/util.h>
+
+#ifndef __ATOMIC_RELAXED
+#define __ATOMIC_RELAXED 0
+#endif /* ifndef __ATOMIC_RELAXED */
+#ifndef __ATOMIC_CONSUME
+#define __ATOMIC_CONSUME 1
+#endif /* ifndef __ATOMIC_CONSUME */
+#ifndef __ATOMIC_ACQUIRE
+#define __ATOMIC_ACQUIRE 2
+#endif /* ifndef __ATOMIC_ACQUIRE */
+#ifndef __ATOMIC_RELEASE
+#define __ATOMIC_RELEASE 3
+#endif /* ifndef __ATOMIC_RELEASE */
+#ifndef __ATOMIC_ACQ_REL
+#define __ATOMIC_ACQ_REL 4
+#endif /* ifndef __ATOMIC_ACQ_REL */
+#ifndef __ATOMIC_SEQ_CST
+#define __ATOMIC_SEQ_CST 5
+#endif /* ifndef __ATOMIC_SEQ_CST */
+
+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
+};
+
+typedef enum memory_order memory_order;
+
+/*
+ * If you add a type with different sizeof() length,
+ * you need to implement atomic_<foo>_explicitNN macros.
+ */
+
+typedef bool volatile atomic_bool;
+typedef char volatile atomic_char;
+typedef signed char volatile atomic_schar;
+typedef unsigned char volatile atomic_uchar;
+typedef short volatile atomic_short;
+typedef unsigned short volatile atomic_ushort;
+typedef int volatile atomic_int;
+typedef unsigned int volatile atomic_uint;
+typedef long volatile atomic_long;
+typedef unsigned long volatile atomic_ulong;
+typedef long long volatile atomic_llong;
+typedef unsigned long long volatile atomic_ullong;
+typedef char16_t volatile atomic_char16_t;
+typedef char32_t volatile atomic_char32_t;
+typedef wchar_t volatile atomic_wchar_t;
+typedef int_least8_t volatile atomic_int_least8_t;
+typedef uint_least8_t volatile atomic_uint_least8_t;
+typedef int_least16_t volatile atomic_int_least16_t;
+typedef uint_least16_t volatile atomic_uint_least16_t;
+typedef int_least32_t volatile atomic_int_least32_t;
+typedef uint_least32_t volatile atomic_uint_least32_t;
+typedef int_least64_t volatile atomic_int_least64_t;
+typedef uint_least64_t volatile atomic_uint_least64_t;
+typedef int_fast8_t volatile atomic_int_fast8_t;
+typedef uint_fast8_t volatile atomic_uint_fast8_t;
+typedef int_fast16_t volatile atomic_int_fast16_t;
+typedef uint_fast16_t volatile atomic_uint_fast16_t;
+typedef int_fast32_t volatile atomic_int_fast32_t;
+typedef uint_fast32_t volatile atomic_uint_fast32_t;
+typedef int_fast64_t volatile atomic_int_fast64_t;
+typedef uint_fast64_t volatile atomic_uint_fast64_t;
+typedef intptr_t volatile atomic_intptr_t;
+typedef uintptr_t volatile atomic_uintptr_t;
+typedef size_t volatile atomic_size_t;
+typedef ptrdiff_t volatile atomic_ptrdiff_t;
+typedef intmax_t volatile atomic_intmax_t;
+typedef uintmax_t volatile atomic_uintmax_t;
+
+#define atomic_init(obj, desired) (*(obj) = (desired))
+
+#define atomic_store_explicit8(obj, desired, order) \
+ (void)InterlockedExchange8((atomic_int_fast8_t *)obj, desired)
+
+#define atomic_store_explicit16(obj, desired, order) \
+ (order == memory_order_relaxed \
+ ? (void)InterlockedExchangeNoFence16((atomic_short *)obj, \
+ desired) \
+ : (order == memory_order_acquire \
+ ? (void)InterlockedExchangeAcquire16( \
+ (atomic_short *)obj, desired) \
+ : (void)InterlockedExchange16((atomic_short *)obj, \
+ desired)))
+
+#define atomic_store_explicit32(obj, desired, order) \
+ (order == memory_order_relaxed \
+ ? (void)InterlockedExchangeNoFence( \
+ (atomic_int_fast32_t *)obj, desired) \
+ : (order == memory_order_acquire \
+ ? (void)InterlockedExchangeAcquire( \
+ (atomic_int_fast32_t *)obj, desired) \
+ : (void)InterlockedExchange( \
+ (atomic_int_fast32_t *)obj, desired)))
+
+#ifdef _WIN64
+#define atomic_store_explicit64(obj, desired, order) \
+ (order == memory_order_relaxed \
+ ? (void)InterlockedExchangeNoFence64( \
+ (atomic_int_fast64_t *)obj, desired) \
+ : (order == memory_order_acquire \
+ ? (void)InterlockedExchangeAcquire64( \
+ (atomic_int_fast64_t *)obj, desired) \
+ : (void)InterlockedExchange64( \
+ (atomic_int_fast64_t *)obj, desired)))
+#else /* ifdef _WIN64 */
+#define atomic_store_explicit64(obj, desired, order) \
+ (void)InterlockedExchange64((atomic_int_fast64_t *)obj, desired)
+#endif /* ifdef _WIN64 */
+
+static inline void
+atomic_store_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_store_explicit(obj, desired, order) \
+ (sizeof(*(obj)) == 8 \
+ ? atomic_store_explicit64(obj, desired, order) \
+ : (sizeof(*(obj)) == 4 \
+ ? atomic_store_explicit32(obj, desired, order) \
+ : (sizeof(*(obj)) == 2 \
+ ? atomic_store_explicit16(obj, desired, \
+ order) \
+ : (sizeof(*(obj)) == 1 \
+ ? atomic_store_explicit8( \
+ obj, desired, \
+ order) \
+ : atomic_store_abort()))))
+
+#define atomic_store(obj, desired) \
+ atomic_store_explicit(obj, desired, memory_order_seq_cst)
+
+#define atomic_load_explicit8(obj, order) \
+ (int8_t) InterlockedOr8((atomic_int_fast8_t *)obj, 0)
+
+#define atomic_load_explicit16(obj, order) \
+ (short)InterlockedOr16((atomic_short *)obj, 0)
+
+#define atomic_load_explicit32(obj, order) \
+ (order == memory_order_relaxed \
+ ? (int32_t)InterlockedOrNoFence((atomic_int_fast32_t *)obj, \
+ 0) \
+ : (order == memory_order_acquire \
+ ? (int32_t)InterlockedOrAcquire( \
+ (atomic_int_fast32_t *)obj, 0) \
+ : (order == memory_order_release \
+ ? (int32_t)InterlockedOrRelease( \
+ (atomic_int_fast32_t *)obj, 0) \
+ : (int32_t)InterlockedOr( \
+ (atomic_int_fast32_t *)obj, \
+ 0))))
+
+#ifdef _WIN64
+#define atomic_load_explicit64(obj, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedOr64NoFence((atomic_int_fast64_t *)obj, 0) \
+ : (order == memory_order_acquire \
+ ? InterlockedOr64Acquire( \
+ (atomic_int_fast64_t *)obj, 0) \
+ : (order == memory_order_release \
+ ? InterlockedOr64Release( \
+ (atomic_int_fast64_t *)obj, 0) \
+ : InterlockedOr64( \
+ (atomic_int_fast64_t *)obj, \
+ 0))))
+#else /* ifdef _WIN64 */
+#define atomic_load_explicit64(obj, order) \
+ InterlockedOr64((atomic_int_fast64_t *)obj, 0)
+#endif /* ifdef _WIN64 */
+
+static inline int8_t
+atomic_load_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_load_explicit(obj, order) \
+ (((sizeof(*(obj)) == 8) \
+ ? atomic_load_explicit64(obj, order) \
+ : ((sizeof(*(obj)) == 4) \
+ ? atomic_load_explicit32(obj, order) \
+ : ((sizeof(*(obj)) == 2) \
+ ? atomic_load_explicit16(obj, order) \
+ : ((sizeof(*(obj)) == 1) \
+ ? atomic_load_explicit8( \
+ obj, order) \
+ : atomic_load_abort())))) & \
+ ((sizeof(*(obj)) == 8) \
+ ? 0xffffffffffffffffULL \
+ : ((sizeof(*(obj)) == 4) \
+ ? 0xffffffffULL \
+ : ((sizeof(*(obj)) == 2) \
+ ? 0xffffULL \
+ : ((sizeof(*(obj)) == 1) \
+ ? 0xffULL \
+ : atomic_load_abort())))))
+
+#define atomic_load(obj) atomic_load_explicit(obj, memory_order_seq_cst)
+
+#define atomic_fetch_add_explicit8(obj, arg, order) \
+ InterlockedExchangeAdd8((atomic_int_fast8_t *)obj, arg)
+
+#define atomic_fetch_add_explicit16(obj, arg, order) \
+ InterlockedExchangeAdd16((atomic_short *)obj, arg)
+
+#define atomic_fetch_add_explicit32(obj, arg, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedExchangeAddNoFence((atomic_int_fast32_t *)obj, \
+ arg) \
+ : (order == memory_order_acquire \
+ ? InterlockedExchangeAddAcquire( \
+ (atomic_int_fast32_t *)obj, arg) \
+ : (order == memory_order_release \
+ ? InterlockedExchangeAddRelease( \
+ (atomic_int_fast32_t *)obj, \
+ arg) \
+ : InterlockedExchangeAdd( \
+ (atomic_int_fast32_t *)obj, \
+ arg))))
+
+#ifdef _WIN64
+#define atomic_fetch_add_explicit64(obj, arg, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedExchangeAddNoFence64((atomic_int_fast64_t *)obj, \
+ arg) \
+ : (order == memory_order_acquire \
+ ? InterlockedExchangeAddAcquire64( \
+ (atomic_int_fast64_t *)obj, arg) \
+ : (order == memory_order_release \
+ ? InterlockedExchangeAddRelease64( \
+ (atomic_int_fast64_t *)obj, \
+ arg) \
+ : InterlockedExchangeAdd64( \
+ (atomic_int_fast64_t *)obj, \
+ arg))))
+#else /* ifdef _WIN64 */
+#define atomic_fetch_add_explicit64(obj, arg, order) \
+ InterlockedExchangeAdd64((atomic_int_fast64_t *)obj, arg)
+#endif /* ifdef _WIN64 */
+
+static inline int8_t
+atomic_add_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ (sizeof(*(obj)) == 8 \
+ ? atomic_fetch_add_explicit64(obj, arg, order) \
+ : (sizeof(*(obj)) == 4 \
+ ? atomic_fetch_add_explicit32(obj, arg, order) \
+ : (sizeof(*(obj)) == 2 \
+ ? atomic_fetch_add_explicit16(obj, arg, \
+ order) \
+ : (sizeof(*(obj)) == 1 \
+ ? atomic_fetch_add_explicit8( \
+ obj, arg, order) \
+ : atomic_add_abort()))))
+
+#define atomic_fetch_add(obj, arg) \
+ atomic_fetch_add_explicit(obj, arg, memory_order_seq_cst)
+
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ atomic_fetch_add_explicit(obj, -arg, order)
+
+#define atomic_fetch_sub(obj, arg) \
+ atomic_fetch_sub_explicit(obj, arg, memory_order_seq_cst)
+
+#define atomic_fetch_and_explicit8(obj, arg, order) \
+ InterlockedAnd8((atomic_int_fast8_t *)obj, arg)
+
+#define atomic_fetch_and_explicit16(obj, arg, order) \
+ InterlockedAnd16((atomic_short *)obj, arg)
+
+#define atomic_fetch_and_explicit32(obj, arg, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedAndNoFence((atomic_int_fast32_t *)obj, arg) \
+ : (order == memory_order_acquire \
+ ? InterlockedAndAcquire( \
+ (atomic_int_fast32_t *)obj, arg) \
+ : (order == memory_order_release \
+ ? InterlockedAndRelease( \
+ (atomic_int_fast32_t *)obj, \
+ arg) \
+ : InterlockedAnd( \
+ (atomic_int_fast32_t *)obj, \
+ arg))))
+
+#ifdef _WIN64
+#define atomic_fetch_and_explicit64(obj, arg, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedAnd64NoFence((atomic_int_fast64_t *)obj, arg) \
+ : (order == memory_order_acquire \
+ ? InterlockedAnd64Acquire( \
+ (atomic_int_fast64_t *)obj, arg) \
+ : (order == memory_order_release \
+ ? InterlockedAnd64Release( \
+ (atomic_int_fast64_t *)obj, \
+ arg) \
+ : InterlockedAnd64( \
+ (atomic_int_fast64_t *)obj, \
+ arg))))
+#else /* ifdef _WIN64 */
+#define atomic_fetch_and_explicit64(obj, arg, order) \
+ InterlockedAnd64((atomic_int_fast64_t *)obj, arg)
+#endif /* ifdef _WIN64 */
+
+static inline int8_t
+atomic_and_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_fetch_and_explicit(obj, arg, order) \
+ (sizeof(*(obj)) == 8 \
+ ? atomic_fetch_and_explicit64(obj, arg, order) \
+ : (sizeof(*(obj)) == 4 \
+ ? atomic_fetch_and_explicit32(obj, arg, order) \
+ : (sizeof(*(obj)) == 2 \
+ ? atomic_fetch_and_explicit16(obj, arg, \
+ order) \
+ : (sizeof(*(obj)) == 1 \
+ ? atomic_fetch_and_explicit8( \
+ obj, arg, order) \
+ : atomic_and_abort()))))
+
+#define atomic_fetch_and(obj, arg) \
+ atomic_fetch_and_explicit(obj, arg, memory_order_seq_cst)
+
+#define atomic_fetch_or_explicit8(obj, arg, order) \
+ InterlockedOr8((atomic_int_fast8_t *)obj, arg)
+
+#define atomic_fetch_or_explicit16(obj, arg, order) \
+ InterlockedOr16((atomic_short *)obj, arg)
+
+#define atomic_fetch_or_explicit32(obj, arg, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedOrNoFence((atomic_int_fast32_t *)obj, arg) \
+ : (order == memory_order_acquire \
+ ? InterlockedOrAcquire((atomic_int_fast32_t *)obj, \
+ arg) \
+ : (order == memory_order_release \
+ ? InterlockedOrRelease( \
+ (atomic_int_fast32_t *)obj, \
+ arg) \
+ : InterlockedOr( \
+ (atomic_int_fast32_t *)obj, \
+ arg))))
+
+#ifdef _WIN64
+#define atomic_fetch_or_explicit64(obj, arg, order) \
+ (order == memory_order_relaxed \
+ ? InterlockedOr64NoFence((atomic_int_fast64_t *)obj, arg) \
+ : (order == memory_order_acquire \
+ ? InterlockedOr64Acquire( \
+ (atomic_int_fast64_t *)obj, arg) \
+ : (order == memory_order_release \
+ ? InterlockedOr64Release( \
+ (atomic_int_fast64_t *)obj, \
+ arg) \
+ : InterlockedOr64( \
+ (atomic_int_fast64_t *)obj, \
+ arg))))
+#else /* ifdef _WIN64 */
+#define atomic_fetch_or_explicit64(obj, arg, order) \
+ InterlockedOr64((atomic_int_fast64_t *)obj, arg)
+#endif /* ifdef _WIN64 */
+
+static inline int8_t
+atomic_or_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_fetch_or_explicit(obj, arg, order) \
+ (sizeof(*(obj)) == 8 \
+ ? atomic_fetch_or_explicit64(obj, arg, order) \
+ : (sizeof(*(obj)) == 4 \
+ ? atomic_fetch_or_explicit32(obj, arg, order) \
+ : (sizeof(*(obj)) == 2 \
+ ? atomic_fetch_or_explicit16(obj, arg, \
+ order) \
+ : (sizeof(*(obj)) == 1 \
+ ? atomic_fetch_or_explicit8( \
+ obj, arg, order) \
+ : atomic_or_abort()))))
+
+#define atomic_fetch_or(obj, arg) \
+ atomic_fetch_or_explicit(obj, arg, memory_order_seq_cst)
+
+static inline bool
+atomic_compare_exchange_strong_explicit8(atomic_int_fast8_t *obj,
+ int8_t *expected, int8_t desired,
+ memory_order succ, memory_order fail) {
+ bool __r;
+ int8_t __v;
+
+ UNUSED(succ);
+ UNUSED(fail);
+
+ __v = InterlockedCompareExchange8((atomic_int_fast8_t *)obj, desired,
+ *expected);
+ __r = (*(expected) == __v);
+ if (!__r) {
+ *(expected) = __v;
+ }
+ return (__r);
+}
+
+static inline bool
+atomic_compare_exchange_strong_explicit16(atomic_short *obj, short *expected,
+ short desired, memory_order succ,
+ memory_order fail) {
+ bool __r;
+ short __v;
+
+ UNUSED(succ);
+ UNUSED(fail);
+
+ __v = InterlockedCompareExchange16((atomic_short *)obj, desired,
+ *expected);
+ __r = (*(expected) == __v);
+ if (!__r) {
+ *(expected) = __v;
+ }
+ return (__r);
+}
+
+static inline bool
+atomic_compare_exchange_strong_explicit32(atomic_int_fast32_t *obj,
+ int32_t *expected, int32_t desired,
+ memory_order succ,
+ memory_order fail) {
+ bool __r;
+ int32_t __v;
+
+ UNUSED(succ);
+ UNUSED(fail);
+
+ switch (succ) {
+ case memory_order_relaxed:
+ __v = InterlockedCompareExchangeNoFence(
+ (atomic_int_fast32_t *)obj, desired, *expected);
+ break;
+ case memory_order_acquire:
+ __v = InterlockedCompareExchangeAcquire(
+ (atomic_int_fast32_t *)obj, desired, *expected);
+ break;
+ case memory_order_release:
+ __v = InterlockedCompareExchangeRelease(
+ (atomic_int_fast32_t *)obj, desired, *expected);
+ break;
+ default:
+ __v = InterlockedCompareExchange((atomic_int_fast32_t *)obj,
+ desired, *expected);
+ break;
+ }
+ __r = (*(expected) == __v);
+ if (!__r) {
+ *(expected) = __v;
+ }
+ return (__r);
+}
+
+static inline bool
+atomic_compare_exchange_strong_explicit64(atomic_int_fast64_t *obj,
+ int64_t *expected, int64_t desired,
+ memory_order succ,
+ memory_order fail) {
+ bool __r;
+ int64_t __v;
+
+ UNUSED(succ);
+ UNUSED(fail);
+
+#ifdef _WIN64
+ switch (succ) {
+ case memory_order_relaxed:
+ __v = InterlockedCompareExchangeNoFence64(
+ (atomic_int_fast64_t *)obj, desired, *expected);
+ break;
+ case memory_order_acquire:
+ __v = InterlockedCompareExchangeAcquire64(
+ (atomic_int_fast64_t *)obj, desired, *expected);
+ break;
+ case memory_order_release:
+ __v = InterlockedCompareExchangeRelease64(
+ (atomic_int_fast64_t *)obj, desired, *expected);
+ break;
+ default:
+ __v = InterlockedCompareExchange64((atomic_int_fast64_t *)obj,
+ desired, *expected);
+ break;
+ }
+#else /* ifdef _WIN64 */
+ __v = InterlockedCompareExchange64((atomic_int_fast64_t *)obj, desired,
+ *expected);
+#endif /* ifdef _WIN64 */
+ __r = (*(expected) == __v);
+ if (!__r) {
+ *(expected) = __v;
+ }
+ return (__r);
+}
+
+static inline bool
+atomic_compare_exchange_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, \
+ fail) \
+ (sizeof(*(obj)) == 8 \
+ ? atomic_compare_exchange_strong_explicit64( \
+ obj, expected, desired, succ, fail) \
+ : (sizeof(*(obj)) == 4 \
+ ? atomic_compare_exchange_strong_explicit32( \
+ obj, expected, desired, succ, fail) \
+ : (sizeof(*(obj)) == 2 \
+ ? atomic_compare_exchange_strong_explicit16( \
+ obj, expected, desired, succ, \
+ fail) \
+ : (sizeof(*(obj)) == 1 \
+ ? atomic_compare_exchange_strong_explicit8( \
+ obj, expected, \
+ desired, succ, \
+ fail) \
+ : atomic_compare_exchange_abort()))))
+
+#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_explicit(obj, expected, desired, succ, \
+ fail) \
+ atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, \
+ fail)
+
+#define atomic_compare_exchange_weak(obj, expected, desired) \
+ atomic_compare_exchange_weak_explicit(obj, expected, desired, \
+ memory_order_seq_cst, \
+ memory_order_seq_cst)
+
+static inline bool
+atomic_exchange_abort() {
+ UNREACHABLE();
+}
+
+#define atomic_exchange_explicit(obj, desired, order) \
+ (sizeof(*(obj)) == 8 \
+ ? InterlockedExchange64(obj, desired) \
+ : (sizeof(*(obj)) == 4 \
+ ? InterlockedExchange(obj, desired) \
+ : (sizeof(*(obj)) == 2 \
+ ? InterlockedExchange16(obj, desired) \
+ : (sizeof(*(obj)) == 1 \
+ ? InterlockedExchange8( \
+ obj, desired) \
+ : atomic_exchange_abort()))))
+
+#define atomic_exchange(obj, desired) \
+ atomic_exchange_explicit(obj, desired, memory_order_seq_cst)
diff --git a/lib/isc/win32/include/isc/stdtime.h b/lib/isc/win32/include/isc/stdtime.h
new file mode 100644
index 0000000..12e990c
--- /dev/null
+++ b/lib/isc/win32/include/isc/stdtime.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_STDTIME_H
+#define ISC_STDTIME_H 1
+
+#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:
+ *
+ * '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
+
+#endif /* ISC_STDTIME_H */
diff --git a/lib/isc/win32/include/isc/syslog.h b/lib/isc/win32/include/isc/syslog.h
new file mode 100644
index 0000000..2638ad2
--- /dev/null
+++ b/lib/isc/win32/include/isc/syslog.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.
+ */
+
+#ifndef ISC_SYSLOG_H
+#define ISC_SYSLOG_H 1
+
+#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:
+ *
+ * 'str' is not NULL
+ * 'facilityp' is not NULL
+ *
+ * Returns:
+ * ISC_R_SUCCESS
+ * ISC_R_NOTFOUND
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SYSLOG_H */
diff --git a/lib/isc/win32/include/isc/thread.h b/lib/isc/win32/include/isc/thread.h
new file mode 100644
index 0000000..5e30c63
--- /dev/null
+++ b/lib/isc/win32/include/isc/thread.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.
+ */
+
+#ifndef ISC_THREAD_H
+#define ISC_THREAD_H 1
+
+#include <inttypes.h>
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/result.h>
+
+extern __declspec(thread) size_t isc_tid_v;
+
+/*
+ * Inlines to help with wait return checking
+ */
+
+/* check handle for NULL and INVALID_HANDLE */
+inline BOOL
+IsValidHandle(HANDLE hHandle) {
+ return ((hHandle != NULL) && (hHandle != INVALID_HANDLE_VALUE));
+}
+
+/* validate wait return codes... */
+inline BOOL
+WaitSucceeded(DWORD dwWaitResult, DWORD dwHandleCount) {
+ return ((dwWaitResult >= WAIT_OBJECT_0) &&
+ (dwWaitResult < WAIT_OBJECT_0 + dwHandleCount));
+}
+
+inline BOOL
+WaitAbandoned(DWORD dwWaitResult, DWORD dwHandleCount) {
+ return ((dwWaitResult >= WAIT_ABANDONED_0) &&
+ (dwWaitResult < WAIT_ABANDONED_0 + dwHandleCount));
+}
+
+inline BOOL
+WaitTimeout(DWORD dwWaitResult) {
+ return (dwWaitResult == WAIT_TIMEOUT);
+}
+
+inline BOOL
+WaitFailed(DWORD dwWaitResult) {
+ return (dwWaitResult == WAIT_FAILED);
+}
+
+/* compute object indices for waits... */
+inline DWORD
+WaitSucceededIndex(DWORD dwWaitResult) {
+ return (dwWaitResult - WAIT_OBJECT_0);
+}
+
+inline DWORD
+WaitAbandonedIndex(DWORD dwWaitResult) {
+ return (dwWaitResult - WAIT_ABANDONED_0);
+}
+
+typedef HANDLE isc_thread_t;
+typedef DWORD isc_threadresult_t;
+typedef void *isc_threadarg_t;
+typedef isc_threadresult_t(WINAPI *isc_threadfunc_t)(isc_threadarg_t);
+
+#define isc_thread_self (uintptr_t) GetCurrentThreadId
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *);
+
+void
+isc_thread_join(isc_thread_t, isc_threadresult_t *);
+
+void
+isc_thread_setconcurrency(unsigned int level);
+
+void
+isc_thread_setname(isc_thread_t, const char *);
+
+isc_result_t
+isc_thread_setaffinity(int cpu);
+
+#define isc_thread_yield() Sleep(0)
+
+#if HAVE___DECLSPEC_THREAD
+#define ISC_THREAD_LOCAL static __declspec(thread)
+#else /* if HAVE___DECLSPEC_THREAD */
+#error "Thread-local storage support is required!"
+#endif /* if HAVE___DECLSPEC_THREAD */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_THREAD_H */
diff --git a/lib/isc/win32/include/isc/time.h b/lib/isc/win32/include/isc/time.h
new file mode 100644
index 0000000..baed464
--- /dev/null
+++ b/lib/isc/win32/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.
+ */
+
+#ifndef ISC_TIME_H
+#define ISC_TIME_H 1
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <time.h>
+#include <windows.h>
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+/***
+ *** POSIX Shims
+ ***/
+
+struct tm *
+gmtime_r(const time_t *clock, struct tm *result);
+
+struct tm *
+localtime_r(const time_t *clock, struct tm *result);
+
+int
+nanosleep(const struct timespec *req, struct timespec *rem);
+
+typedef uint32_t useconds_t;
+
+int
+usleep(useconds_t usec);
+
+/***
+ *** Intervals
+ ***/
+
+/*
+ * 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 {
+ int64_t interval;
+};
+
+LIBISC_EXTERNAL_DATA 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:
+ *
+ * 't' is a valid pointer.
+ * nanoseconds < 1000000000.
+ */
+
+bool
+isc_interval_iszero(const isc_interval_t *i);
+/*
+ * Returns true iff. 'i' is the zero interval.
+ *
+ * Requires:
+ *
+ * '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 {
+ FILETIME absolute;
+};
+
+LIBISC_EXTERNAL_DATA 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.
+ *
+ * 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:
+ * The date of the epoch is platform-dependent.
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ */
+
+bool
+isc_time_isepoch(const isc_time_t *t);
+/*
+ * Returns true iff. 't' is the epoch ("time zero").
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ */
+
+isc_result_t
+isc_time_now(isc_time_t *t);
+/*
+ * Set 't' to the current absolute time.
+ *
+ * Requires:
+ *
+ * 't' is a valid pointer.
+ *
+ * Returns:
+ *
+ * Success
+ * Unexpected error
+ * Getting the time from the system failed.
+ * 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:
+ * This call is equivalent to:
+ *
+ * isc_time_now(t);
+ * isc_time_add(t, i, t);
+ *
+ * Requires:
+ *
+ * 't' and 'i' are valid pointers.
+ *
+ * Returns:
+ *
+ * Success
+ * Unexpected error
+ * Getting the time from the system failed.
+ * 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:
+ *
+ * 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ *
+ * -1 t1 < t2 (comparing times, not pointers)
+ * 0 t1 = t2
+ * 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:
+ *
+ * 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ * Success
+ * 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:
+ *
+ * 't', 'i', and 'result' are valid pointers.
+ *
+ * Returns:
+ * Success
+ * 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 milliseconds between time t1 and time t2.
+ * t2 is the subtrahend of t1; ie, difference = t1 - t2.
+ *
+ * Requires:
+ *
+ * 't1' and 't2' are valid pointers.
+ *
+ * Returns:
+ * The difference of t1 - t2, or 0 if t1 <= t2.
+ */
+
+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.
+ */
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t);
+/*
+ * Return the number of nanoseconds stored in a time structure.
+ *
+ * Notes:
+ * 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:
+ * 't' is a valid pointer.
+ *
+ * Ensures:
+ * 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:
+ * 'len' > 0
+ * '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:
+ * 'len' > 0
+ * '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
+ *
+ */
+
+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
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_TIME_H */
diff --git a/lib/isc/win32/include/isc/win32os.h b/lib/isc/win32/include/isc/win32os.h
new file mode 100644
index 0000000..22def42
--- /dev/null
+++ b/lib/isc/win32/include/isc/win32os.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef ISC_WIN32OS_H
+#define ISC_WIN32OS_H 1
+
+#include <isc/lang.h>
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * Return the number of CPUs available on the system, or 1 if this cannot
+ * be determined.
+ */
+
+int
+isc_win32os_versioncheck(unsigned int major, unsigned int minor,
+ unsigned int updatemajor, unsigned int updateminor);
+
+/*
+ * Checks the current version of the operating system with the
+ * supplied version information.
+ * Returns:
+ * -1 if less than the version information supplied
+ * 0 if equal to all of the version information supplied
+ * +1 if greater than the version information supplied
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_WIN32OS_H */
diff --git a/lib/isc/win32/interfaceiter.c b/lib/isc/win32/interfaceiter.c
new file mode 100644
index 0000000..db82e20
--- /dev/null
+++ b/lib/isc/win32/interfaceiter.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Note that this code will need to be revisited to support IPv6 Interfaces.
+ * For now we just iterate through IPv4 interfaces.
+ */
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <isc/interfaceiter.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/strerr.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+void
+InitSockets(void);
+
+/* Common utility functions */
+
+/*
+ * Extract the network address part from a "struct sockaddr".
+ *
+ * The address family is given explicitly
+ * instead of using src->sa_family, because the latter does not work
+ * for copying a network mask obtained by SIOCGIFNETMASK (it does
+ * not have a valid address family).
+ */
+
+#define IFITER_MAGIC 0x49464954U /* IFIT. */
+#define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC)
+
+struct isc_interfaceiter {
+ unsigned int magic; /* Magic number. */
+ isc_mem_t *mctx;
+ SOCKET socket;
+ INTERFACE_INFO IFData; /* Current Interface Info. */
+ int numIF; /* Current Interface count. */
+ int v4IF; /* Number of IPv4 Interfaces */
+ INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */
+ unsigned int buf4size; /* Bytes allocated. */
+ INTERFACE_INFO *pos4; /* Current offset in IF List */
+ SOCKET_ADDRESS_LIST *buf6; /* Buffer for WSAIoctl data. */
+ unsigned int buf6size; /* Bytes allocated. */
+ unsigned int pos6; /* Which entry to process. */
+ bool v6loop; /* See IPv6 loop address. */
+ bool pos6zero; /* Done pos6 == 0. */
+ isc_interface_t current; /* Current interface data. */
+ isc_result_t result; /* Last result code. */
+};
+
+/*
+ * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
+ * We assume no sane system will have more than than 1K of IP addresses on
+ * all of its adapters.
+ */
+#define IFCONF_SIZE_INITIAL 16
+#define IFCONF_SIZE_INCREMENT 64
+#define IFCONF_SIZE_MAX 1040
+
+static void
+get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
+ dst->family = family;
+ switch (family) {
+ case AF_INET:
+ memmove(&dst->type.in, &((struct sockaddr_in *)src)->sin_addr,
+ sizeof(struct in_addr));
+ break;
+ case AF_INET6:
+ memmove(&dst->type.in6,
+ &((struct sockaddr_in6 *)src)->sin6_addr,
+ sizeof(struct in6_addr));
+ dst->zone = ((struct sockaddr_in6 *)src)->sin6_scope_id;
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+isc_result_t
+isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_interfaceiter_t *iter;
+ isc_result_t result;
+ int error;
+ unsigned long bytesReturned = 0;
+
+ REQUIRE(mctx != NULL);
+ REQUIRE(iterp != NULL);
+ REQUIRE(*iterp == NULL);
+
+ iter = isc_mem_get(mctx, sizeof(*iter));
+
+ InitSockets();
+
+ iter->mctx = mctx;
+ iter->buf4 = NULL;
+ iter->buf6 = NULL;
+ iter->pos4 = NULL;
+ iter->pos6 = 0;
+ iter->v6loop = true;
+ iter->pos6zero = true;
+ iter->buf6size = 0;
+ iter->buf4size = 0;
+ iter->result = ISC_R_FAILURE;
+ iter->numIF = 0;
+ iter->v4IF = 0;
+
+ /*
+ * Create an unbound datagram socket to do the
+ * SIO_GET_INTERFACE_LIST WSAIoctl on.
+ */
+ iter->socket = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iter->socket == INVALID_SOCKET) {
+ error = WSAGetLastError();
+ if (error == WSAEAFNOSUPPORT) {
+ goto inet6_only;
+ }
+ strerror_r(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "making interface scan socket: %s", strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto socket_failure;
+ }
+
+ /*
+ * Get the interface configuration, allocating more memory if
+ * necessary.
+ */
+ iter->buf4size = IFCONF_SIZE_INITIAL * sizeof(INTERFACE_INFO);
+
+ for (;;) {
+ iter->buf4 = isc_mem_get(mctx, iter->buf4size);
+
+ if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST, 0, 0,
+ iter->buf4, iter->buf4size, &bytesReturned, 0,
+ 0) == SOCKET_ERROR)
+ {
+ error = WSAGetLastError();
+ if (error != WSAEFAULT && error != WSAENOBUFS) {
+ errno = error;
+ strerror_r(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "get interface configuration: "
+ "%s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto ioctl_failure;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ /*
+ * The WSAIoctl succeeded.
+ * If the number of the returned bytes is the same
+ * as the buffer size, we will grow it just in
+ * case and retry.
+ */
+ if (bytesReturned > 0 &&
+ (bytesReturned < iter->buf4size))
+ {
+ break;
+ }
+ }
+ if (iter->buf4size >= IFCONF_SIZE_MAX * sizeof(INTERFACE_INFO))
+ {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "get interface configuration: "
+ "maximum buffer size exceeded");
+ result = ISC_R_UNEXPECTED;
+ goto ioctl_failure;
+ }
+ isc_mem_put(mctx, iter->buf4, iter->buf4size);
+
+ iter->buf4size += IFCONF_SIZE_INCREMENT *
+ sizeof(INTERFACE_INFO);
+ }
+
+ /*
+ * A newly created iterator has an undefined position
+ * until isc_interfaceiter_first() is called.
+ */
+ iter->v4IF = bytesReturned / sizeof(INTERFACE_INFO);
+
+ /* We don't need the socket any more, so close it */
+ closesocket(iter->socket);
+
+inet6_only:
+ /*
+ * Create an unbound datagram socket to do the
+ * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
+ */
+ iter->socket = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (iter->socket == INVALID_SOCKET) {
+ error = WSAGetLastError();
+ if (error == WSAEAFNOSUPPORT) {
+ goto inet_only;
+ }
+ strerror_r(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "making interface scan socket: %s", strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto ioctl_failure;
+ }
+
+ /*
+ * Get the interface configuration, allocating more memory if
+ * necessary.
+ */
+ iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
+ IFCONF_SIZE_INITIAL * sizeof(SOCKET_ADDRESS);
+
+ for (;;) {
+ iter->buf6 = isc_mem_get(mctx, iter->buf6size);
+
+ if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY, 0, 0,
+ iter->buf6, iter->buf6size, &bytesReturned, 0,
+ 0) == SOCKET_ERROR)
+ {
+ error = WSAGetLastError();
+ if (error != WSAEFAULT && error != WSAENOBUFS) {
+ errno = error;
+ strerror_r(error, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "sio address list query: %s",
+ strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto ioctl6_failure;
+ }
+ /*
+ * EINVAL. Retry with a bigger buffer.
+ */
+ } else {
+ break;
+ }
+
+ if (iter->buf6size >= IFCONF_SIZE_MAX * sizeof(SOCKET_ADDRESS))
+ {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "get interface configuration: "
+ "maximum buffer size exceeded");
+ result = ISC_R_UNEXPECTED;
+ goto ioctl6_failure;
+ }
+ isc_mem_put(mctx, iter->buf6, iter->buf6size);
+
+ iter->buf6size += IFCONF_SIZE_INCREMENT *
+ sizeof(SOCKET_ADDRESS);
+ }
+
+ closesocket(iter->socket);
+
+inet_only:
+ iter->magic = IFITER_MAGIC;
+ *iterp = iter;
+ return (ISC_R_SUCCESS);
+
+ioctl6_failure:
+ isc_mem_put(mctx, iter->buf6, iter->buf6size);
+
+ioctl_failure:
+ if (iter->buf4 != NULL) {
+ isc_mem_put(mctx, iter->buf4, iter->buf4size);
+ }
+ if (iter->socket != INVALID_SOCKET) {
+ (void)closesocket(iter->socket);
+ }
+
+socket_failure:
+ isc_mem_put(mctx, iter, sizeof(*iter));
+ return (result);
+}
+
+/*
+ * Get information about the current interface to iter->current.
+ * If successful, return ISC_R_SUCCESS.
+ * If the interface has an unsupported address family, or if
+ * some operation on it fails, return ISC_R_IGNORE to make
+ * the higher-level iterator code ignore it.
+ */
+
+static isc_result_t
+internal_current(isc_interfaceiter_t *iter) {
+ BOOL ifNamed = FALSE;
+ unsigned long flags;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->numIF >= 0);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = AF_INET;
+
+ get_addr(AF_INET, &iter->current.address,
+ (struct sockaddr *)&(iter->IFData.iiAddress));
+
+ /*
+ * Get interface flags.
+ */
+
+ iter->current.flags = 0;
+ flags = iter->IFData.iiFlags;
+
+ if ((flags & IFF_UP) != 0) {
+ iter->current.flags |= INTERFACE_F_UP;
+ }
+
+ if ((flags & IFF_POINTTOPOINT) != 0) {
+ iter->current.flags |= INTERFACE_F_POINTTOPOINT;
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "PPP Interface %d", iter->numIF);
+ ifNamed = TRUE;
+ }
+
+ if ((flags & IFF_LOOPBACK) != 0) {
+ iter->current.flags |= INTERFACE_F_LOOPBACK;
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "Loopback Interface %d", iter->numIF);
+ ifNamed = TRUE;
+ }
+
+ /*
+ * If the interface is point-to-point, get the destination address.
+ */
+ if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
+ get_addr(AF_INET, &iter->current.dstaddress,
+ (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
+ }
+
+ if (ifNamed == FALSE) {
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "TCP/IP Interface %d", iter->numIF);
+ }
+
+ /*
+ * Get the network mask.
+ */
+ get_addr(AF_INET, &iter->current.netmask,
+ (struct sockaddr *)&(iter->IFData.iiNetmask));
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+internal_current6(isc_interfaceiter_t *iter) {
+ SOCKET fd;
+ int i;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->buf6 != NULL);
+
+ memset(&iter->current, 0, sizeof(iter->current));
+ iter->current.af = AF_INET6;
+
+ if (!iter->pos6zero) {
+ if (iter->pos6 == 0U) {
+ iter->pos6zero = true;
+ }
+ get_addr(AF_INET6, &iter->current.address,
+ iter->buf6->Address[iter->pos6].lpSockaddr);
+
+ /*
+ * Set interface flags.
+ */
+
+ iter->current.flags = INTERFACE_F_UP;
+
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "TCP/IPv6 Interface %u", iter->pos6 + 1);
+
+ for (i = 0; i < 16; i++) {
+ iter->current.netmask.type.in6.s6_addr[i] = 0xff;
+ }
+ iter->current.netmask.family = AF_INET6;
+ if (IN6_IS_ADDR_LOOPBACK(&iter->current.address.type.in6)) {
+ iter->v6loop = true;
+ }
+ } else {
+ /*
+ * See if we can bind to the ::1 and if so return ::1.
+ */
+ struct sockaddr_in6 sin6;
+
+ iter->v6loop = true; /* So we don't loop forever. */
+
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd == INVALID_SOCKET) {
+ return (ISC_R_IGNORE);
+ }
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr.s6_addr[15] = 1;
+ if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
+ closesocket(fd);
+ return (ISC_R_IGNORE);
+ }
+ closesocket(fd);
+
+ iter->current.flags = INTERFACE_F_UP | INTERFACE_F_LOOPBACK;
+ snprintf(iter->current.name, sizeof(iter->current.name),
+ "TCP/IPv6 Loopback Interface");
+ for (i = 0; i < 16; i++) {
+ if (i != 15) {
+ iter->current.address.type.in6.s6_addr[i] = 0;
+ } else {
+ iter->current.address.type.in6.s6_addr[i] = 1;
+ }
+ iter->current.netmask.type.in6.s6_addr[i] = 0xff;
+ }
+ iter->current.address.family = AF_INET6;
+ iter->current.netmask.family = AF_INET6;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Step the iterator to the next interface. Unlike
+ * isc_interfaceiter_next(), this may leave the iterator
+ * positioned on an interface that will ultimately
+ * be ignored. Return ISC_R_NOMORE if there are no more
+ * interfaces, otherwise ISC_R_SUCCESS.
+ */
+static isc_result_t
+internal_next(isc_interfaceiter_t *iter) {
+ if (iter->numIF >= iter->v4IF) {
+ return (ISC_R_NOMORE);
+ }
+
+ /*
+ * The first one needs to be set up to point to the last
+ * Element of the array. Go to the end and back up
+ * Microsoft's implementation is peculiar for returning
+ * the list in reverse order
+ */
+
+ if (iter->numIF == 0) {
+ iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
+ }
+
+ iter->pos4--;
+ if (&(iter->pos4) < &(iter->buf4)) {
+ return (ISC_R_NOMORE);
+ }
+
+ memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
+ memmove(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
+ iter->numIF++;
+
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+internal_next6(isc_interfaceiter_t *iter) {
+ if (iter->pos6 == 0U && iter->v6loop) {
+ return (ISC_R_NOMORE);
+ }
+ if (iter->pos6 != 0U) {
+ iter->pos6--;
+ }
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_interfaceiter_current(isc_interfaceiter_t *iter, isc_interface_t *ifdata) {
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+ memmove(ifdata, &iter->current, sizeof(*ifdata));
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_interfaceiter_first(isc_interfaceiter_t *iter) {
+ REQUIRE(VALID_IFITER(iter));
+
+ if (iter->buf6 != NULL) {
+ iter->pos6 = iter->buf6->iAddressCount;
+ iter->v6loop = false;
+ iter->pos6zero = (iter->pos6 == 0U);
+ }
+ iter->result = ISC_R_SUCCESS;
+ return (isc_interfaceiter_next(iter));
+}
+
+isc_result_t
+isc_interfaceiter_next(isc_interfaceiter_t *iter) {
+ isc_result_t result;
+
+ REQUIRE(VALID_IFITER(iter));
+ REQUIRE(iter->result == ISC_R_SUCCESS);
+
+ for (;;) {
+ result = internal_next(iter);
+ if (result == ISC_R_NOMORE) {
+ result = internal_next6(iter);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+ result = internal_current6(iter);
+ if (result == ISC_R_IGNORE) {
+ continue;
+ }
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ break;
+ }
+ result = internal_current(iter);
+ if (result != ISC_R_IGNORE) {
+ break;
+ }
+ }
+ iter->result = result;
+ return (result);
+}
+
+void
+isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
+ isc_interfaceiter_t *iter;
+ REQUIRE(iterp != NULL);
+ iter = *iterp;
+ *iterp = NULL;
+ REQUIRE(VALID_IFITER(iter));
+
+ if (iter->buf4 != NULL) {
+ isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
+ }
+ if (iter->buf6 != NULL) {
+ isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
+ }
+
+ iter->magic = 0;
+ isc_mem_put(iter->mctx, iter, sizeof(*iter));
+}
diff --git a/lib/isc/win32/ipv6.c b/lib/isc/win32/ipv6.c
new file mode 100644
index 0000000..fecec98
--- /dev/null
+++ b/lib/isc/win32/ipv6.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <isc/net.h>
+#include <isc/platform.h>
+
+LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_loopback =
+ IN6ADDR_LOOPBACK_INIT;
diff --git a/lib/isc/win32/libgen.h b/lib/isc/win32/libgen.h
new file mode 100644
index 0000000..b04ac37
--- /dev/null
+++ b/lib/isc/win32/libgen.h
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+#ifndef LIBGEN_H
+#define LIBGEN_H 1
+
+char *
+basename(const char *);
+char *
+dirname(const char *);
+
+#endif /* ifndef LIBGEN_H */
diff --git a/lib/isc/win32/libisc.def.exclude b/lib/isc/win32/libisc.def.exclude
new file mode 100644
index 0000000..d2fe4ec
--- /dev/null
+++ b/lib/isc/win32/libisc.def.exclude
@@ -0,0 +1,42 @@
+; These symbols are not needed by the WIN32 build, but build-tarballs
+; will complain if they aren't present here.
+isc_socket_accept
+isc_socket_attach
+isc_socket_bind
+isc_socket_cancel
+isc_socket_cleanunix
+isc_socket_close
+isc_socket_connect
+isc_socket_create
+isc_socket_detach
+isc_socket_dscp
+isc_socket_dup
+isc_socket_fdwatchcreate
+isc_socket_fdwatchpoke
+isc_socket_filter
+isc_socket_getpeername
+isc_socket_getsockname
+isc_socket_gettype
+isc_socket_ipv6only
+isc_socket_listen
+isc_socket_open
+isc_socket_permunix
+isc_socket_recv
+isc_socket_recv2
+isc_socket_recvv
+isc_socket_register
+isc_socket_send
+isc_socket_sendto
+isc_socket_sendto2
+isc_socket_sendtov
+isc_socket_sendtov2
+isc_socket_sendv
+isc_socketmgr_create
+isc_socketmgr_create2
+isc_socketmgr_destroy
+isc_socketmgr_setstats
+isc_print_fprintf
+isc_print_printf
+isc_print_snprintf
+isc_print_sprintf
+isc_print_vsnprintf
diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in
new file mode 100644
index 0000000..0ee055d
--- /dev/null
+++ b/lib/isc/win32/libisc.def.in
@@ -0,0 +1,805 @@
+LIBRARY libisc
+
+; Exported Functions
+EXPORTS
+
+NTReportError
+closelog
+@IF PKCS11
+getpassphrase
+@END PKCS11
+isc_app_block
+isc_app_ctxfinish
+isc_app_ctxonrun
+isc_app_ctxrun
+isc_app_ctxshutdown
+isc_app_ctxstart
+isc_app_ctxsuspend
+isc_app_finish
+isc_app_onrun
+isc_app_reload
+isc_app_run
+isc_app_shutdown
+isc_app_start
+isc_app_unblock
+isc_appctx_create
+isc_appctx_destroy
+isc_astack_destroy
+isc_astack_new
+isc_astack_pop
+isc_astack_trypush
+isc__buffer_activeregion
+isc__buffer_add
+isc__buffer_availableregion
+isc__buffer_back
+isc__buffer_clear
+isc__buffer_consumedregion
+isc__buffer_first
+isc__buffer_forward
+isc__buffer_init
+isc__buffer_initnull
+isc__buffer_invalidate
+isc__buffer_putmem
+isc__buffer_putstr
+isc__buffer_putuint16
+isc__buffer_putuint24
+isc__buffer_putuint32
+isc__buffer_putuint48
+isc__buffer_putuint8
+isc__buffer_region
+isc__buffer_remainingregion
+isc__buffer_setactive
+isc__buffer_subtract
+isc__buffer_usedregion
+isc__mem_allocate
+isc__mem_free
+isc__mem_get
+isc__mem_printactive
+isc__mem_put
+isc__mem_putanddetach
+isc__mem_reallocate
+isc__mem_strdup
+isc__mem_strndup
+isc__mempool_get
+isc__mempool_put
+isc__md_md5
+isc__md_sha1
+isc__md_sha224
+isc__md_sha256
+isc__md_sha384
+isc__md_sha512
+isc_socket_accept
+isc_socket_attach
+isc_socket_bind
+isc_socket_cancel
+isc_socket_cleanunix
+isc_socket_close
+isc_socket_connect
+isc_socket_create
+isc_socket_detach
+isc_socket_dscp
+isc_socket_dup
+isc_socket_filter
+isc_socket_getfd
+isc_socket_getname
+isc_socket_getpeername
+isc_socket_getsockname
+isc_socket_gettag
+isc_socket_gettype
+isc_socket_hasreuseport
+isc_socket_ipv6only
+isc_socket_listen
+isc_socket_open
+isc_socket_permunix
+isc_socket_recv
+isc_socket_recv2
+isc_socket_send
+isc_socket_sendto
+isc_socket_sendto2
+isc_socket_setname
+isc_socketmgr_create
+isc_socketmgr_create2
+isc_socketmgr_destroy
+isc_socketmgr_getmaxsockets
+isc_socketmgr_setreserved
+isc_socketmgr_setstats
+isc_aes128_crypt
+isc_aes192_crypt
+isc_aes256_crypt
+isc_app_block
+isc_app_ctxfinish
+isc_app_ctxonrun
+isc_app_ctxrun
+isc_app_ctxshutdown
+isc_app_ctxstart
+isc_app_ctxsuspend
+isc_app_finish
+isc_app_isrunning
+isc_app_onrun
+isc_app_reload
+isc_app_run
+isc_app_shutdown
+isc_app_start
+isc_app_unblock
+isc_appctx_create
+isc_appctx_destroy
+isc_assertion_failed
+isc_assertion_setcallback
+isc_assertion_typetotext
+isc_backtrace_getsymbol
+isc_backtrace_getsymbolfromindex
+isc_backtrace_gettrace
+isc_base32_decoderegion
+isc_base32_decodestring
+isc_base32_tobuffer
+isc_base32_totext
+isc_base32hex_decoderegion
+isc_base32hex_decodestring
+isc_base32hex_tobuffer
+isc_base32hex_totext
+isc_base32hexnp_decoderegion
+isc_base32hexnp_decodestring
+isc_base32hexnp_tobuffer
+isc_base32hexnp_totext
+isc_base64_decodestring
+isc_base64_tobuffer
+isc_base64_totext
+isc_buffer_allocate
+isc_buffer_compact
+isc_buffer_copyregion
+isc_buffer_dup
+isc_buffer_free
+isc_buffer_getuint16
+isc_buffer_getuint32
+isc_buffer_getuint48
+isc_buffer_getuint8
+isc_buffer_printf
+isc_buffer_putdecint
+isc_buffer_reinit
+isc_buffer_reserve
+isc_buffer_setautorealloc
+isc_bufferlist_availablecount
+isc_bufferlist_usedcount
+isc_commandline_parse
+isc_commandline_strtoargv
+isc_condition_broadcast
+isc_condition_destroy
+isc_condition_init
+isc_condition_signal
+isc_condition_wait
+isc_condition_waituntil
+isc_counter_attach
+isc_counter_create
+isc_counter_detach
+isc_counter_increment
+isc_counter_setlimit
+isc_counter_used
+isc_crc64_final
+isc_crc64_init
+isc_crc64_update
+isc_dir_chdir
+isc_dir_chroot
+isc_dir_close
+isc_dir_createunique
+isc_dir_init
+isc_dir_open
+isc_dir_read
+isc_dir_reset
+isc_enable_constructors
+isc_entropy_get
+isc_errno_toresult
+isc_error_fatal
+isc_error_runtimecheck
+isc_error_setfatal
+isc_error_setunexpected
+isc_error_unexpected
+isc_event_allocate
+isc_event_constallocate
+isc_event_free
+isc_file_absolutepath
+isc_file_basename
+isc_file_bopenunique
+isc_file_bopenuniquemode
+isc_file_bopenuniqueprivate
+isc_file_exists
+isc_file_getmodtime
+isc_file_getsize
+isc_file_getsizefd
+isc_file_isabsolute
+isc_file_ischdiridempotent
+isc_file_iscurrentdir
+isc_file_isdirectory
+isc_file_isdirwritable
+isc_file_isplainfile
+isc_file_isplainfilefd
+isc_file_mktemplate
+isc_file_mmap
+isc_file_mode
+isc_file_munmap
+isc_file_openunique
+isc_file_openuniquemode
+isc_file_openuniqueprivate
+isc_file_progname
+isc_file_remove
+isc_file_rename
+isc_file_renameunique
+isc_file_safecreate
+isc_file_safemovefile
+isc_file_sanitize
+isc_file_settime
+isc_file_splitpath
+isc_file_template
+isc_file_truncate
+isc_fsaccess_add
+isc_fsaccess_changeowner
+isc_fsaccess_remove
+isc_fsaccess_set
+isc_hash32
+isc_hash64
+isc_hash_get_initializer
+isc_hash_set_initializer
+isc_heap_create
+isc_heap_decreased
+isc_heap_delete
+isc_heap_destroy
+isc_heap_foreach
+isc_heap_element
+isc_heap_increased
+isc_heap_insert
+isc_hex_decodestring
+isc_hex_tobuffer
+isc_hex_totext
+isc_hmac
+isc_hmac_new
+isc_hmac_free
+isc_hmac_init
+isc_hmac_reset
+isc_hmac_update
+isc_hmac_final
+isc_hmac_get_md_type
+isc_hmac_get_size
+isc_hmac_get_block_size
+isc_ht_add
+isc_ht_count
+isc_ht_delete
+isc_ht_destroy
+isc_ht_find
+isc_ht_init
+isc_ht_iter_create
+isc_ht_iter_current
+isc_ht_iter_currentkey
+isc_ht_iter_delcurrent_next
+isc_ht_iter_destroy
+isc_ht_iter_first
+isc_ht_iter_next
+isc_httpd_addheader
+isc_httpd_addheaderuint
+isc_httpd_endheaders
+isc_httpd_response
+isc_httpd_setfinishhook
+isc_httpdmgr_addurl
+isc_httpdmgr_addurl2
+isc_httpdmgr_create
+isc_httpdmgr_shutdown
+isc_interfaceiter_create
+isc_interfaceiter_current
+isc_interfaceiter_destroy
+isc_interfaceiter_first
+isc_interfaceiter_next
+isc_interval_iszero
+isc_interval_set
+isc_iterated_hash
+isc_lex_close
+isc_lex_create
+isc_lex_destroy
+isc_lex_getcomments
+isc_lex_getlasttokentext
+isc_lex_getmastertoken
+isc_lex_getoctaltoken
+isc_lex_getsourceline
+isc_lex_getsourcename
+isc_lex_getspecials
+isc_lex_gettoken
+isc_lex_isfile
+isc_lex_openbuffer
+isc_lex_openfile
+isc_lex_openstream
+isc_lex_setcomments
+isc_lex_setsourceline
+isc_lex_setsourcename
+isc_lex_setspecials
+isc_lex_ungettoken
+isc_lfsr_generate
+isc_lfsr_generate32
+isc_lfsr_init
+isc_lfsr_skip
+isc_lib_ntservice
+isc_lib_register
+isc_log_categorybyname
+isc_log_closefilelogs
+isc_log_create
+isc_log_createchannel
+isc_log_destroy
+isc_log_getdebuglevel
+isc_log_getduplicateinterval
+isc_log_gettag
+isc_log_modulebyname
+isc_log_opensyslog
+isc_log_registercategories
+isc_log_registermodules
+isc_log_setcontext
+isc_log_setdebuglevel
+isc_log_setduplicateinterval
+isc_log_settag
+isc_log_usechannel
+isc_log_vwrite
+isc_log_vwrite1
+isc_log_wouldlog
+isc_log_write
+isc_log_write1
+isc_logconfig_create
+isc_logconfig_destroy
+isc_logconfig_use
+isc_logfile_roll
+isc_managers_create
+isc_managers_destroy
+isc_md_new
+isc_md_init
+isc_md_reset
+isc_md_update
+isc_md_final
+isc_md_free
+isc_md_get_md_type
+isc_md_get_size
+isc_md_get_block_size
+isc_md_type_get_size
+isc_md_type_get_block_size
+isc_md
+isc__mem_checkdestroyed
+isc__mem_initialize
+isc__mem_shutdown
+isc_mem_attach
+isc_mem_checkdestroyed
+isc_mem_create
+isc_mem_destroy
+isc_mem_detach
+isc_mem_getname
+isc_mem_gettag
+isc_mem_inuse
+isc_mem_isovermem
+isc_mem_maxinuse
+isc_mem_references
+@IF NOTYET
+isc_mem_renderjson
+@END NOTYET
+@IF LIBXML2
+isc_mem_renderxml
+@END LIBXML2
+isc_mem_setdestroycheck
+isc_mem_setname
+isc_mem_setwater
+isc_mem_stats
+isc_mem_total
+isc_mem_waterack
+isc_meminfo_totalphys
+isc_mempool_create
+isc_mempool_destroy
+isc_mempool_getallocated
+isc_mempool_getfillcount
+isc_mempool_getfreecount
+isc_mempool_getfreemax
+isc_mempool_getmaxalloc
+isc_mempool_setfillcount
+isc_mempool_setfreemax
+isc_mempool_setmaxalloc
+isc_mempool_setname
+isc_mutexblock_destroy
+isc_mutexblock_init
+isc_net_disableipv4
+isc_net_disableipv6
+isc_net_enableipv4
+isc_net_enableipv6
+isc_net_getudpportrange
+isc_net_probe_ipv6only
+isc_net_probe_ipv6pktinfo
+isc_net_probedscp
+isc_net_probeipv4
+isc_net_probeipv6
+isc_net_probeunix
+isc_netaddr_any
+isc_netaddr_any6
+isc_netaddr_eqprefix
+isc_netaddr_equal
+isc_netaddr_format
+isc_netaddr_fromin
+isc_netaddr_fromin6
+isc_netaddr_frompath
+isc_netaddr_fromsockaddr
+isc_netaddr_fromv4mapped
+isc_netaddr_getzone
+isc_netaddr_isexperimental
+isc_netaddr_islinklocal
+isc_netaddr_isloopback
+isc_netaddr_ismulticast
+isc_netaddr_isnetzero
+isc_netaddr_issitelocal
+isc_netaddr_masktoprefixlen
+isc_netaddr_prefixok
+isc_netaddr_setzone
+isc_netaddr_totext
+isc_netaddr_unspec
+isc_netscope_pton
+isc__nmhandle_attach
+isc__nmhandle_detach
+isc_nmhandle_cleartimeout
+isc_nmhandle_getdata
+isc_nmhandle_getextra
+isc_nmhandle_is_stream
+isc_nmhandle_keepalive
+isc_nmhandle_netmgr
+isc_nmhandle_localaddr
+isc_nmhandle_peeraddr
+isc_nmhandle_setdata
+isc_nmhandle_settimeout
+isc_nmhandle_setwritetimeout
+isc_nm_attach
+isc_nm_cancelread
+isc_nm_detach
+isc_nm_getloadbalancesockets
+isc_nm_gettimeouts
+isc_nm_listentcp
+isc_nm_listentcpdns
+isc_nm_listenudp
+isc_nm_maxudp
+isc_nm_pause
+isc_nm_pauseread
+isc_nm_read
+isc_nm_resume
+isc_nm_resumeread
+isc_nm_send
+isc_nm_setloadbalancesockets
+isc_nm_setstats
+isc_nm_settimeouts
+isc_nm_stoplistening
+isc_nm_task_enqueue
+isc_nm_tcpconnect
+isc_nm_tcpdnsconnect
+isc_nm_tcpdns_sequential
+isc_nm_tid
+isc_nm_timer_create
+isc_nm_timer_attach
+isc_nm_timer_detach
+isc_nm_timer_start
+isc_nm_timer_stop
+isc_nm_udpconnect
+isc_nm_work_offload
+isc_nmsocket_close
+isc__nm_acquire_interlocked
+isc__nm_drop_interlocked
+isc__nm_acquire_interlocked_force
+isc_nonce_buf
+isc_ntpaths_get
+isc_ntpaths_init
+isc_once_do
+isc_os_ncpus
+isc_parse_uint16
+isc_parse_uint32
+isc_parse_uint8
+isc_pool_count
+isc_pool_create
+isc_pool_destroy
+isc_pool_expand
+isc_pool_get
+isc_portset_add
+isc_portset_addrange
+isc_portset_create
+isc_portset_destroy
+isc_portset_isset
+isc_portset_nports
+isc_portset_remove
+isc_portset_removerange
+isc_quota_attach
+isc_quota_attach_cb
+isc_quota_cb_init
+isc_quota_destroy
+isc_quota_detach
+isc_quota_getmax
+isc_quota_getsoft
+isc_quota_getused
+isc_quota_init
+isc_quota_max
+isc_quota_soft
+isc_radix_create
+isc_radix_destroy
+isc_radix_insert
+isc_radix_process
+isc_radix_remove
+isc_radix_search
+isc_random8
+isc_random16
+isc_random32
+isc_random_buf
+isc_random_uniform
+isc_ratelimiter_attach
+isc_ratelimiter_create
+isc_ratelimiter_dequeue
+isc_ratelimiter_detach
+isc_ratelimiter_enqueue
+isc_ratelimiter_release
+isc_ratelimiter_setinterval
+isc_ratelimiter_setpertic
+isc_ratelimiter_setpushpop
+isc_ratelimiter_shutdown
+isc_ratelimiter_stall
+isc_regex_validate
+isc_region_compare
+isc_resource_getcurlimit
+isc_resource_getlimit
+isc_resource_setlimit
+isc_result_register
+isc_result_registerids
+isc_result_toid
+isc_result_totext
+isc_rwlock_destroy
+isc_rwlock_downgrade
+isc_rwlock_init
+isc_rwlock_lock
+isc_rwlock_trylock
+isc_rwlock_tryupgrade
+isc_rwlock_unlock
+isc_safe_memequal
+isc_safe_memwipe
+isc_serial_eq
+isc_serial_ge
+isc_serial_gt
+isc_serial_le
+isc_serial_lt
+isc_serial_ne
+isc_halfsiphash24
+isc_siphash24
+isc_sockaddr_any
+isc_sockaddr_any6
+isc_sockaddr_anyofpf
+isc_sockaddr_compare
+isc_sockaddr_eqaddr
+isc_sockaddr_eqaddrprefix
+isc_sockaddr_equal
+isc_sockaddr_format
+isc_sockaddr_fromin
+isc_sockaddr_fromin6
+isc_sockaddr_fromnetaddr
+isc_sockaddr_frompath
+isc_sockaddr_fromsockaddr
+isc_sockaddr_getport
+isc_sockaddr_hash
+isc_sockaddr_isexperimental
+isc_sockaddr_islinklocal
+isc_sockaddr_ismulticast
+isc_sockaddr_isnetzero
+isc_sockaddr_issitelocal
+isc_sockaddr_pf
+isc_sockaddr_setport
+isc_sockaddr_totext
+isc_sockaddr_v6fromin
+isc_socket_socketevent
+isc_socketmgr_maxudp
+@IF NOTYET
+isc_socketmgr_renderjson
+@END NOTYET
+@IF LIBXML2
+isc_socketmgr_renderxml
+@END LIBXML2
+isc_stats_attach
+isc_stats_create
+isc_stats_decrement
+isc_stats_detach
+isc_stats_dump
+isc_stats_get_counter
+isc_stats_increment
+isc_stats_ncounters
+isc_stats_resize
+isc_stats_set
+isc_stats_update_if_greater
+isc_stdio_close
+isc_stdio_flush
+isc_stdio_open
+isc_stdio_read
+isc_stdio_seek
+isc_stdio_sync
+isc_stdio_tell
+isc_stdio_write
+isc_stdtime_get
+isc_stdtime_tostring
+isc_string_strerror_r
+isc_symtab_count
+isc_symtab_create
+isc_symtab_define
+isc_symtab_destroy
+isc_symtab_lookup
+isc_symtab_undefine
+isc_syslog_facilityfromstring
+isc_task_attach
+isc_task_beginexclusive
+isc_task_create
+isc_task_create_bound
+isc_task_destroy
+isc_task_detach
+isc_task_endexclusive
+isc_task_exiting
+isc_task_getname
+isc_task_unsendrange
+isc_task_getcurrenttime
+isc_task_getcurrenttimex
+isc_task_getnetmgr
+isc_task_getprivilege
+isc_task_gettag
+isc_task_onshutdown
+isc_task_pause
+isc_task_privileged
+isc_task_purge
+isc_task_purgeevent
+isc_task_purgerange
+isc_task_ready
+isc_task_run
+isc_task_send
+isc_task_sendanddetach
+isc_task_sendto
+isc_task_sendtoanddetach
+isc_task_setname
+isc_task_setprivilege
+isc_task_setquantum
+isc_task_shutdown
+isc_task_unpause
+isc_task_unsend
+isc_taskmgr_attach
+isc_taskmgr_detach
+isc_taskmgr_excltask
+isc_taskmgr_mode
+@IF NOTYET
+isc_taskmgr_renderjson
+@END NOTYET
+@IF LIBXML2
+isc_taskmgr_renderxml
+@END LIBXML2
+isc_taskmgr_setexcltask
+isc_taskmgr_setmode
+isc_taskpool_create
+isc_taskpool_destroy
+isc_taskpool_expand
+isc_taskpool_gettask
+isc_taskpool_size
+isc_thread_create
+isc_thread_join
+isc_thread_setaffinity
+isc_thread_setconcurrency
+isc_thread_setname
+gmtime_r
+localtime_r
+nanosleep
+usleep
+isc_time_add
+isc_time_compare
+isc_time_formatISO8601
+isc_time_formatISO8601L
+isc_time_formatISO8601Lms
+isc_time_formatISO8601Lus
+isc_time_formatISO8601ms
+isc_time_formatISO8601us
+isc_time_formathttptimestamp
+isc_time_formatshorttimestamp
+isc_time_formattimestamp
+isc_time_isepoch
+isc_time_microdiff
+isc_time_nanoseconds
+isc_time_now
+isc_time_now_hires
+isc_time_nowplusinterval
+isc_time_parsehttptimestamp
+isc_time_secondsastimet
+isc_time_seconds
+isc_time_set
+isc_time_settoepoch
+isc_time_subtract
+isc_timer_create
+isc_timer_destroy
+isc_timer_gettype
+isc_timer_reset
+isc_timer_touch
+isc_timermgr_create
+isc_timermgr_destroy
+isc_timermgr_poke
+isc__tls_initialize
+isc__tls_shutdown
+isc__trampoline_initialize
+isc__trampoline_shutdown
+isc__trampoline_get
+isc__trampoline_run
+isc_tm_timegm
+isc_tm_strptime
+isc_url_parse
+isc_utf8_bom
+isc_utf8_valid
+isc_win32os_versioncheck
+openlog
+@IF PKCS11
+pk11_attribute_bytype
+pk11_attribute_first
+pk11_attribute_next
+pk11_dump_tokens
+pk11_error_fatalcheck
+pk11_finalize
+pk11_get_best_token
+pk11_get_lib_name
+pk11_get_load_error_message
+pk11_get_session
+pk11_initialize
+pk11_mem_get
+pk11_mem_put
+pk11_numbits
+pk11_parse_uri
+pk11_result_register
+pk11_result_totext
+pk11_return_session
+pk11_set_lib_name
+pkcs_C_CloseSession
+pkcs_C_CreateObject
+pkcs_C_DeriveKey
+pkcs_C_DestroyObject
+pkcs_C_DigestFinal
+pkcs_C_DigestInit
+pkcs_C_DigestUpdate
+pkcs_C_Encrypt
+pkcs_C_EncryptInit
+pkcs_C_Finalize
+pkcs_C_FindObjects
+pkcs_C_FindObjectsFinal
+pkcs_C_FindObjectsInit
+pkcs_C_GenerateKey
+pkcs_C_GenerateKeyPair
+pkcs_C_GenerateRandom
+pkcs_C_GetAttributeValue
+pkcs_C_GetMechanismInfo
+pkcs_C_GetSlotList
+pkcs_C_GetTokenInfo
+pkcs_C_Initialize
+pkcs_C_Login
+pkcs_C_Logout
+pkcs_C_OpenSession
+pkcs_C_SeedRandom
+pkcs_C_SetAttributeValue
+pkcs_C_Sign
+pkcs_C_SignFinal
+pkcs_C_SignInit
+pkcs_C_SignUpdate
+pkcs_C_Verify
+pkcs_C_VerifyFinal
+pkcs_C_VerifyInit
+pkcs_C_VerifyUpdate
+@END PKCS11
+strlcat
+strlcpy
+strnstr
+syslog
+
+@IF NOLONGER
+; Exported Data
+
+EXPORTS
+
+isc__backtrace_nsymbols DATA
+isc__backtrace_symtable DATA
+isc_bind9 DATA
+isc_commandline_argument DATA
+isc_commandline_errprint DATA
+isc_commandline_index DATA
+isc_commandline_option DATA
+isc_commandline_progname DATA
+isc_commandline_reset DATA
+isc_dscp_check_value DATA
+isc_hashctx DATA
+isc_mem_debugging DATA
+isc_tid_v DATA
+@IF PKCS11
+pk11_verbose_init DATA
+@END PKCS11
+@END NOLONGER
diff --git a/lib/isc/win32/libisc.vcxproj.filters.in b/lib/isc/win32/libisc.vcxproj.filters.in
new file mode 100644
index 0000000..75a4c80
--- /dev/null
+++ b/lib/isc/win32/libisc.vcxproj.filters.in
@@ -0,0 +1,671 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Library Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Win32 Source Files">
+ <UniqueIdentifier>{289562c2-1bdd-4582-b6bd-3f598ee23cbd}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Win32 Header Files">
+ <UniqueIdentifier>{d03c3e6a-e78e-4a01-bd77-64c839b1adfe}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Library Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libisc.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\isc\aes.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\app.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\assertions.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\astack.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\atomic.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\backtrace.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\barrier.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\base32.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\base64.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\bind9.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\boolean.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\buffer.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\bufferlist.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\commandline.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\counter.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\crc64.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\endian.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\errno.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\error.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\event.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\eventclass.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\file.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\formatcheck.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\fsaccess.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hash.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\heap.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hex.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\hmac.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\ht.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\httpd.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\interfaceiter.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\iterated_hash.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\json.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lang.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lex.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lfsr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\lib.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\list.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\log.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\magic.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\managers.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\mem.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\meminfo.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\mutexblock.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\netaddr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\netscope.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\nonce.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\os.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\parseint.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\pool.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\portset.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\print.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\quota.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\radix.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\random.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\ratelimiter.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\refcount.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\regex.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\region.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\resource.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\result.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\resultclass.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\rwlock.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\safe.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\serial.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\siphash.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\sockaddr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\socket.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\stats.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\stdio.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\stdlib.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\strerr.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\string.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\symtab.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\task.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\taskpool.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\timer.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\tm.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\types.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\url.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\utf8.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\util.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\isc\version.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+@IF PKCS11
+ <ClInclude Include="..\include\pk11\constants.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pk11\internal.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pk11\pk11.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pk11\result.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\pkcs11\pkcs11.h">
+ <Filter>Pkcs11 Header Files</Filter>
+ </ClInclude>
+@END PKCS11
+ <ClInclude Include="include\isc\bind_registry.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\bindevt.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\condition.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\dir.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\ipv6.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\mutex.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\net.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\netdb.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\ntgroups.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\ntpaths.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\offset.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\once.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\platform.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\stat.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\stdatomic.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\stdtime.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\strerror.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\syslog.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\thread.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\time.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="include\isc\win32os.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\entropy_private.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\netmgr_p.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\openssl_shim.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\trampoline_p.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="errno2result.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="syslog.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="unistd.h">
+ <Filter>Win32 Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\config.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\versions.h">
+ <Filter>Library Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="condition.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dir.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DLLMain.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="errno.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="errno2result.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="file.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="fsaccess.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="interfaceiter.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ipv6.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="meminfo.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="net.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ntpaths.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="once.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="os.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="resource.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="socket.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdio.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdtime.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="syslog.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="thread.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="time.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="version.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="win32os.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+@IF PKCS11
+ <ClCompile Include="pk11_api.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+@END PKCS11
+ <ClCompile Include="..\aes.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\app.c">
+ <Filter>Win32 Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\assertions.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\astack.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\backtrace.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\backtrace-emptytbl.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\base32.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\base64.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\bind9.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\buffer.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\bufferlist.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\commandline.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\counter.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\crc64.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\error.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\event.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\entropy.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hash.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\heap.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hex.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\hmac.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ht.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\httpd.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\iterated_hash.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lex.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lfsr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\lib.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\log.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\managers.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mem.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\mutexblock.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netaddr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netmgr\netmgr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netmgr\tcp.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netmgr\udp.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netmgr\uverr2result.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netmgr\uv-compat.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netmgr\tcpdns.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\netscope.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nonce.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\openssl_shim.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\parseint.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\pool.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\portset.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\quota.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\radix.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\random.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\ratelimiter.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\regex.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\region.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\result.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\rwlock.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\safe.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\serial.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\siphash.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\sockaddr.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\stats.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\string.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\symtab.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\task.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\taskpool.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\timer.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\tls.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\trampoline.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\tm.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\url.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\utf8.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+@IF PKCS11
+ <ClCompile Include="..\pk11.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\pk11_result.c">
+ <Filter>Library Source Files</Filter>
+ </ClCompile>
+@END PKCS11
+ </ItemGroup>
+</Project>
diff --git a/lib/isc/win32/libisc.vcxproj.in b/lib/isc/win32/libisc.vcxproj.in
new file mode 100644
index 0000000..8fd9381
--- /dev/null
+++ b/lib/isc/win32/libisc.vcxproj.in
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="@TOOLS_VERSION@" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|@PLATFORM@">
+ <Configuration>Debug</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|@PLATFORM@">
+ <Configuration>Release</Configuration>
+ <Platform>@PLATFORM@</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3840E563-D180-4761-AA9C-E6155F02EAFF}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libisc</RootNamespace>
+ @WINDOWS_TARGET_PLATFORM_VERSION@
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>MultiByte</CharacterSet>
+ @PLATFORM_TOOLSET@
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ @PLATFORM_TOOLSET@
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ <IntDirSharingDetected>None</IntDirSharingDetected>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>..\..\..\Build\$(Configuration)\</OutDir>
+ <IntDir>.\$(Configuration)\</IntDir>
+ <IntDirSharingDetected>None</IntDirSharingDetected>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|@PLATFORM@'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>false</TreatWarningAsError>
+ <Optimization>Disabled</Optimization>
+@IF PKCS11
+ <PreprocessorDefinitions>BIND9;@PK11_LIB_LOCATION@WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@ELSE PKCS11
+ <PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@END PKCS11
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ </Link>
+ <PreBuildEvent>
+ <Command>cd ..\..\..\win32utils
+
+if NOT Exist ..\Build mkdir ..\Build
+if NOT Exist ..\Build\Debug mkdir ..\Build\Debug
+
+echo Copying documentation.
+
+copy ..\*.md ..\Build\Debug
+copy ..\CHANGES* ..\Build\Debug
+copy ..\COPYRIGHT ..\Build\Debug
+copy ..\LICENSE ..\Build\Debug
+
+echo Copying COPYRIGHT notice.
+
+copy ..\COPYRIGHT ..\Build\Debug
+
+echo Copying the OpenSSL DLL and LICENSE.
+
+copy @OPENSSL_DLLCRYPTO@ ..\Build\Debug\
+copy @OPENSSL_DLLSSL@ ..\Build\Debug\
+copy @OPENSSL_PATH@\LICENSE ..\Build\Debug\OpenSSL-LICENSE
+
+echo Copying libuv DLL.
+copy @LIBUV_DLL@ ..\Build\Debug\
+
+@IF LIBXML2
+echo Copying the libxml DLL.
+
+copy @LIBXML2_DLL@ ..\Build\Debug\
+@END LIBXML2
+
+@IF GSSAPI
+echo Copying the GSSAPI and KRB5 DLLs.
+
+copy @GSSAPI_DLL@ ..\Build\Debug\
+copy @KRB5_DLL@ ..\Build\Debug\
+copy @COMERR_DLL@ ..\Build\Debug\
+copy @K5SPRT_DLL@ ..\Build\Debug\
+copy @WSHELP_DLL@ ..\Build\Debug\
+@END GSSAPI
+
+@IF IDNKIT
+echo Copying the IDN kit DLL.
+
+copy @IDN_DLL@ ..\Build\Debug\
+copy @ICONV_DLL@ ..\Build\Debug\
+@END IDNKIT
+
+@IF ZLIB
+echo Copying the zlib DLL.
+
+copy @ZLIB_DLL@ ..\Build\Debug\
+@END ZLIB
+
+echo Copying Visual C x86 Redistributable Installer.
+
+copy /Y @VCREDIST_PATH@ ..\Build\Debug\
+
+echo Copying install files (flags and file list).
+
+copy InstallFlags ..\Build\Debug\
+copy InstallFiles ..\Build\Debug\
+
+</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|@PLATFORM@'">
+ <ClCompile>
+ <WarningLevel>Level1</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>@INTRINSIC@</IntrinsicFunctions>
+@IF PKCS11
+ <PreprocessorDefinitions>BIND9;@PK11_LIB_LOCATION@WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@ELSE PKCS11
+ <PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
+ <AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+@END PKCS11
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <StringPooling>true</StringPooling>
+ <PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\$(Configuration)\</AssemblerListingLocation>
+ <ObjectFileName>.\$(Configuration)\</ObjectFileName>
+ <ProgramDataBaseFileName>$(OutDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
+ <ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
+ <LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
+ </Link>
+ <PreBuildEvent>
+ <Command>cd ..\..\..\win32utils
+
+if NOT Exist ..\Build mkdir ..\Build
+if NOT Exist ..\Build\Release mkdir ..\Build\Release
+
+echo Copying documentation.
+
+copy ..\*.md ..\Build\Release
+copy ..\CHANGES* ..\Build\Release
+copy ..\COPYRIGHT ..\Build\Release
+copy ..\LICENSE ..\Build\Release
+
+echo Copying the OpenSSL DLL and LICENSE.
+
+copy @OPENSSL_DLLCRYPTO@ ..\Build\Release\
+copy @OPENSSL_DLLSSL@ ..\Build\Release\
+copy @OPENSSL_PATH@\LICENSE ..\Build\Release\OpenSSL-LICENSE
+
+echo Copying libuv DLL.
+copy @LIBUV_DLL@ ..\Build\Release\
+
+@IF LIBXML2
+echo Copying the libxml DLL.
+
+copy @LIBXML2_DLL@ ..\Build\Release\
+@END LIBXML2
+
+@IF GSSAPI
+echo Copying the GSSAPI and KRB5 DLLs.
+
+copy @GSSAPI_DLL@ ..\Build\Release\
+copy @KRB5_DLL@ ..\Build\Release\
+copy @COMERR_DLL@ ..\Build\Release\
+copy @K5SPRT_DLL@ ..\Build\Release\
+copy @WSHELP_DLL@ ..\Build\Release\
+@END GSSAPI
+
+@IF IDNKIT
+echo Copying the IDN kit DLL.
+
+copy @IDN_DLL@ ..\Build\Release\
+copy @ICONV_DLL@ ..\Build\Release\
+@END IDNKIT
+
+@IF ZLIB
+echo Copying the zlib DLL.
+
+copy @ZLIB_DLL@ ..\Build\Release\
+@END ZLIB
+
+echo Copying Visual C x86 Redistributable Installer.
+
+copy /Y @VCREDIST_PATH@ ..\Build\Release\
+
+echo Copying install files (flags and file list).
+
+copy InstallFlags ..\Build\Release\
+copy InstallFiles ..\Build\Release\
+
+</Command>
+ </PreBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="libisc.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\config.h" />
+ <ClInclude Include="..\include\isc\aes.h" />
+ <ClInclude Include="..\include\isc\app.h" />
+ <ClInclude Include="..\include\isc\assertions.h" />
+ <ClInclude Include="..\include\isc\astack.h" />
+ <ClInclude Include="..\include\isc\atomic.h" />
+ <ClInclude Include="..\include\isc\backtrace.h" />
+ <ClInclude Include="..\include\isc\barrier.h" />
+ <ClInclude Include="..\include\isc\base32.h" />
+ <ClInclude Include="..\include\isc\base64.h" />
+ <ClInclude Include="..\include\isc\bind9.h" />
+ <ClInclude Include="..\include\isc\boolean.h" />
+ <ClInclude Include="..\include\isc\buffer.h" />
+ <ClInclude Include="..\include\isc\bufferlist.h" />
+ <ClInclude Include="..\include\isc\commandline.h" />
+ <ClInclude Include="..\include\isc\counter.h" />
+ <ClInclude Include="..\include\isc\crc64.h" />
+ <ClInclude Include="..\include\isc\endian.h" />
+ <ClInclude Include="..\include\isc\errno.h" />
+ <ClInclude Include="..\include\isc\error.h" />
+ <ClInclude Include="..\include\isc\event.h" />
+ <ClInclude Include="..\include\isc\eventclass.h" />
+ <ClInclude Include="..\include\isc\file.h" />
+ <ClInclude Include="..\include\isc\formatcheck.h" />
+ <ClInclude Include="..\include\isc\fsaccess.h" />
+ <ClInclude Include="..\include\isc\hash.h" />
+ <ClInclude Include="..\include\isc\heap.h" />
+ <ClInclude Include="..\include\isc\hex.h" />
+ <ClInclude Include="..\include\isc\hmac.h" />
+ <ClInclude Include="..\include\isc\ht.h" />
+ <ClInclude Include="..\include\isc\httpd.h" />
+ <ClInclude Include="..\include\isc\interfaceiter.h" />
+ <ClInclude Include="..\include\isc\iterated_hash.h" />
+ <ClInclude Include="..\include\isc\json.h" />
+ <ClInclude Include="..\include\isc\lang.h" />
+ <ClInclude Include="..\include\isc\lex.h" />
+ <ClInclude Include="..\include\isc\lfsr.h" />
+ <ClInclude Include="..\include\isc\lib.h" />
+ <ClInclude Include="..\include\isc\list.h" />
+ <ClInclude Include="..\include\isc\log.h" />
+ <ClInclude Include="..\include\isc\magic.h" />
+ <ClInclude Include="..\include\isc\managers.h" />
+ <ClInclude Include="..\include\isc\md.h" />
+ <ClInclude Include="..\include\isc\mem.h" />
+ <ClInclude Include="..\include\isc\meminfo.h" />
+ <ClInclude Include="..\include\isc\mutexblock.h" />
+ <ClInclude Include="..\include\isc\netaddr.h" />
+ <ClInclude Include="..\include\isc\netscope.h" />
+ <ClInclude Include="..\include\isc\nonce.h" />
+ <ClInclude Include="..\include\isc\os.h" />
+ <ClInclude Include="..\include\isc\parseint.h" />
+ <ClInclude Include="..\include\isc\pool.h" />
+ <ClInclude Include="..\include\isc\portset.h" />
+ <ClInclude Include="..\include\isc\print.h" />
+ <ClInclude Include="..\include\isc\quota.h" />
+ <ClInclude Include="..\include\isc\radix.h" />
+ <ClInclude Include="..\include\isc\random.h" />
+ <ClInclude Include="..\include\isc\ratelimiter.h" />
+ <ClInclude Include="..\include\isc\refcount.h" />
+ <ClInclude Include="..\include\isc\regex.h" />
+ <ClInclude Include="..\include\isc\region.h" />
+ <ClInclude Include="..\include\isc\resource.h" />
+ <ClInclude Include="..\include\isc\result.h" />
+ <ClInclude Include="..\include\isc\resultclass.h" />
+ <ClInclude Include="..\include\isc\rwlock.h" />
+ <ClInclude Include="..\include\isc\safe.h" />
+ <ClInclude Include="..\include\isc\serial.h" />
+ <ClInclude Include="..\include\isc\siphash.h" />
+ <ClInclude Include="..\include\isc\sockaddr.h" />
+ <ClInclude Include="..\include\isc\socket.h" />
+ <ClInclude Include="..\include\isc\stats.h" />
+ <ClInclude Include="..\include\isc\stdio.h" />
+ <ClInclude Include="..\include\isc\stdlib.h" />
+ <ClInclude Include="..\include\isc\strerr.h" />
+ <ClInclude Include="..\include\isc\string.h" />
+ <ClInclude Include="..\include\isc\symtab.h" />
+ <ClInclude Include="..\include\isc\task.h" />
+ <ClInclude Include="..\include\isc\taskpool.h" />
+ <ClInclude Include="..\include\isc\timer.h" />
+ <ClInclude Include="..\include\isc\tm.h" />
+ <ClInclude Include="..\include\isc\types.h" />
+ <ClInclude Include="..\include\isc\utf8.h" />
+ <ClInclude Include="..\include\isc\util.h" />
+ <ClInclude Include="..\include\isc\version.h" />
+@IF PKCS11
+ <ClInclude Include="..\include\pk11\constants.h" />
+ <ClInclude Include="..\include\pk11\internal.h" />
+ <ClInclude Include="..\include\pk11\pk11.h" />
+ <ClInclude Include="..\include\pk11\result.h" />
+ <ClInclude Include="..\include\pkcs11\pkcs11.h" />
+@END PKCS11
+ <ClInclude Include="errno2result.h" />
+ <ClInclude Include="include\isc\bindevt.h" />
+ <ClInclude Include="include\isc\bind_registry.h" />
+ <ClInclude Include="include\isc\condition.h" />
+ <ClInclude Include="include\isc\dir.h" />
+ <ClInclude Include="include\isc\ipv6.h" />
+ <ClInclude Include="include\isc\mutex.h" />
+ <ClInclude Include="include\isc\net.h" />
+ <ClInclude Include="include\isc\netdb.h" />
+ <ClInclude Include="include\isc\ntgroups.h" />
+ <ClInclude Include="include\isc\ntpaths.h" />
+ <ClInclude Include="include\isc\offset.h" />
+ <ClInclude Include="include\isc\once.h" />
+ <ClInclude Include="include\isc\platform.h" />
+ <ClInclude Include="include\isc\stat.h" />
+ <ClInclude Include="include\isc\stdatomic.h" />
+ <ClInclude Include="include\isc\stdtime.h" />
+ <ClInclude Include="include\isc\strerror.h" />
+ <ClInclude Include="include\isc\syslog.h" />
+ <ClInclude Include="include\isc\thread.h" />
+ <ClInclude Include="include\isc\time.h" />
+ <ClInclude Include="include\isc\win32os.h" />
+ <ClInclude Include="..\entropy_private.h" />
+ <ClInclude Include="..\netmgr_p.h" />
+ <ClInclude Include="..\openssl_shim.h" />
+ <ClInclude Include="..\trampoline_p.h" />
+ <ClInclude Include="syslog.h" />
+ <ClInclude Include="unistd.h" />
+ <ClInclude Include="..\..\versions.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\aes.c" />
+ <ClCompile Include="..\app.c" />
+ <ClCompile Include="..\assertions.c" />
+ <ClCompile Include="..\astack.c" />
+ <ClCompile Include="..\backtrace-emptytbl.c" />
+ <ClCompile Include="..\backtrace.c" />
+ <ClCompile Include="..\base32.c" />
+ <ClCompile Include="..\base64.c" />
+ <ClCompile Include="..\bind9.c" />
+ <ClCompile Include="..\buffer.c" />
+ <ClCompile Include="..\bufferlist.c" />
+ <ClCompile Include="..\commandline.c" />
+ <ClCompile Include="..\counter.c" />
+ <ClCompile Include="..\crc64.c" />
+ <ClCompile Include="..\entropy.c" />
+ <ClCompile Include="..\error.c" />
+ <ClCompile Include="..\event.c" />
+ <ClCompile Include="..\hash.c" />
+ <ClCompile Include="..\heap.c" />
+ <ClCompile Include="..\hex.c" />
+ <ClCompile Include="..\hmac.c" />
+ <ClCompile Include="..\ht.c" />
+ <ClCompile Include="..\httpd.c" />
+ <ClCompile Include="..\iterated_hash.c" />
+ <ClCompile Include="..\lex.c" />
+ <ClCompile Include="..\lfsr.c" />
+ <ClCompile Include="..\lib.c" />
+ <ClCompile Include="..\log.c" />
+ <ClCompile Include="..\managers.c" />
+ <ClCompile Include="..\md.c" />
+ <ClCompile Include="..\mem.c" />
+ <ClCompile Include="..\mutexblock.c" />
+ <ClCompile Include="..\netaddr.c" />
+ <ClCompile Include="..\netmgr\netmgr.c" />
+ <ClCompile Include="..\netmgr\tcp.c" />
+ <ClCompile Include="..\netmgr\udp.c" />
+ <ClCompile Include="..\netmgr\uverr2result.c" />
+ <ClCompile Include="..\netmgr\uv-compat.c" />
+ <ClCompile Include="..\netmgr\tcpdns.c" />
+ <ClCompile Include="..\netscope.c" />
+ <ClCompile Include="..\nonce.c" />
+ <ClCompile Include="..\openssl_shim.c" />
+ <ClCompile Include="..\parseint.c" />
+ <ClCompile Include="..\pool.c" />
+ <ClCompile Include="..\portset.c" />
+ <ClCompile Include="..\quota.c" />
+ <ClCompile Include="..\radix.c" />
+ <ClCompile Include="..\random.c" />
+ <ClCompile Include="..\ratelimiter.c" />
+ <ClCompile Include="..\regex.c" />
+ <ClCompile Include="..\region.c" />
+ <ClCompile Include="..\result.c" />
+ <ClCompile Include="..\rwlock.c" />
+ <ClCompile Include="..\safe.c" />
+ <ClCompile Include="..\serial.c" />
+ <ClCompile Include="..\siphash.c" />
+ <ClCompile Include="..\sockaddr.c" />
+ <ClCompile Include="..\stats.c" />
+ <ClCompile Include="..\string.c" />
+ <ClCompile Include="..\symtab.c" />
+ <ClCompile Include="..\task.c" />
+ <ClCompile Include="..\taskpool.c" />
+ <ClCompile Include="..\timer.c" />
+ <ClCompile Include="..\trampoline.c" />
+ <ClCompile Include="..\tls.c" />
+ <ClCompile Include="..\tm.c" />
+ <ClCompile Include="..\url.c" />
+ <ClCompile Include="..\utf8.c" />
+@IF PKCS11
+ <ClCompile Include="..\pk11.c" />
+ <ClCompile Include="..\pk11_result.c" />
+@END PKCS11
+ <ClCompile Include="condition.c" />
+ <ClCompile Include="dir.c" />
+ <ClCompile Include="DLLMain.c" />
+ <ClCompile Include="errno.c" />
+ <ClCompile Include="errno2result.c" />
+ <ClCompile Include="file.c" />
+ <ClCompile Include="fsaccess.c" />
+ <ClCompile Include="interfaceiter.c" />
+ <ClCompile Include="ipv6.c" />
+ <ClCompile Include="meminfo.c" />
+ <ClCompile Include="net.c" />
+ <ClCompile Include="ntpaths.c" />
+ <ClCompile Include="once.c" />
+ <ClCompile Include="os.c" />
+ <ClCompile Include="resource.c" />
+ <ClCompile Include="socket.c" />
+ <ClCompile Include="stdio.c" />
+ <ClCompile Include="stdtime.c" />
+ <ClCompile Include="syslog.c" />
+ <ClCompile Include="thread.c" />
+ <ClCompile Include="time.c" />
+ <ClCompile Include="version.c" />
+ <ClCompile Include="win32os.c" />
+@IF PKCS11
+ <ClCompile Include="pk11_api.c" />
+@END PKCS11
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/lib/isc/win32/libisc.vcxproj.user b/lib/isc/win32/libisc.vcxproj.user
new file mode 100644
index 0000000..ace9a86
--- /dev/null
+++ b/lib/isc/win32/libisc.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/lib/isc/win32/meminfo.c b/lib/isc/win32/meminfo.c
new file mode 100644
index 0000000..ab10b89
--- /dev/null
+++ b/lib/isc/win32/meminfo.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <inttypes.h>
+#include <windows.h>
+
+#include <isc/meminfo.h>
+
+uint64_t
+isc_meminfo_totalphys(void) {
+ MEMORYSTATUSEX statex;
+
+ statex.dwLength = sizeof(statex);
+ GlobalMemoryStatusEx(&statex);
+ return ((uint64_t)statex.ullTotalPhys);
+}
diff --git a/lib/isc/win32/net.c b/lib/isc/win32/net.c
new file mode 100644
index 0000000..ea4656d
--- /dev/null
+++ b/lib/isc/win32/net.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <isc/log.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/strerr.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/*%
+ * Definitions about UDP port range specification. This is a total mess of
+ * portability variants: some use sysctl (but the sysctl names vary), some use
+ * system-specific interfaces, some have the same interface for IPv4 and IPv6,
+ * some separate them, etc...
+ */
+
+/*%
+ * The last resort defaults: use all non well known port space
+ */
+#ifndef ISC_NET_PORTRANGELOW
+#define ISC_NET_PORTRANGELOW 32768
+#endif /* ISC_NET_PORTRANGELOW */
+#ifndef ISC_NET_PORTRANGEHIGH
+#define ISC_NET_PORTRANGEHIGH 65535
+#endif /* ISC_NET_PORTRANGEHIGH */
+
+static isc_once_t once = ISC_ONCE_INIT;
+static isc_once_t once_ipv6only = ISC_ONCE_INIT;
+static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
+static isc_result_t ipv4_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
+static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
+
+void
+InitSockets(void);
+
+static isc_result_t
+try_proto(int domain) {
+ SOCKET s;
+ char strbuf[ISC_STRERRORSIZE];
+ int errval;
+
+ s = socket(domain, SOCK_STREAM, IPPROTO_TCP);
+ if (s == INVALID_SOCKET) {
+ errval = WSAGetLastError();
+ switch (errval) {
+ case WSAEAFNOSUPPORT:
+ case WSAEPROTONOSUPPORT:
+ case WSAEINVAL:
+ return (ISC_R_NOTFOUND);
+ default:
+ strerror_r(errval, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() failed: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ closesocket(s);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+initialize_action(void) {
+ InitSockets();
+ ipv4_result = try_proto(PF_INET);
+ ipv6_result = try_proto(PF_INET6);
+}
+
+static void
+initialize(void) {
+ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_net_probeipv4(void) {
+ initialize();
+ return (ipv4_result);
+}
+
+isc_result_t
+isc_net_probeipv6(void) {
+ initialize();
+ return (ipv6_result);
+}
+
+isc_result_t
+isc_net_probeunix(void) {
+ return (ISC_R_NOTFOUND);
+}
+
+static void
+try_ipv6only(void) {
+#ifdef IPV6_V6ONLY
+ SOCKET s;
+ int on;
+ char strbuf[ISC_STRERRORSIZE];
+#endif /* ifdef IPV6_V6ONLY */
+ isc_result_t result;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6only_result = result;
+ return;
+ }
+
+#ifndef IPV6_V6ONLY
+ ipv6only_result = ISC_R_NOTFOUND;
+ return;
+#else /* ifndef IPV6_V6ONLY */
+ /* check for TCP sockets */
+ s = socket(PF_INET6, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET) {
+ strerror_r(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "socket() failed: %s",
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on,
+ sizeof(on)) < 0)
+ {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ closesocket(s);
+
+ /* check for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == INVALID_SOCKET) {
+ strerror_r(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "socket() failed: %s",
+ strbuf);
+ ipv6only_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on,
+ sizeof(on)) < 0)
+ {
+ ipv6only_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ ipv6only_result = ISC_R_SUCCESS;
+
+close:
+ closesocket(s);
+ return;
+#endif /* IPV6_V6ONLY */
+}
+
+static void
+initialize_ipv6only(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6only, try_ipv6only) ==
+ ISC_R_SUCCESS);
+}
+
+#ifdef __notyet__
+/*
+ * XXXMPA requires win32/socket.c to be updated to support
+ * WSASendMsg and WSARecvMsg which are themselves Winsock
+ * and compiler version dependent.
+ */
+static void
+try_ipv6pktinfo(void) {
+ SOCKET s;
+ int on;
+ char strbuf[ISC_STRERRORSIZE];
+ isc_result_t result;
+ int optname;
+
+ result = isc_net_probeipv6();
+ if (result != ISC_R_SUCCESS) {
+ ipv6pktinfo_result = result;
+ return;
+ }
+
+ /* we only use this for UDP sockets */
+ s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == INVALID_SOCKET) {
+ strerror_r(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "socket() failed: %s",
+ strbuf);
+ ipv6pktinfo_result = ISC_R_UNEXPECTED;
+ return;
+ }
+
+#ifdef IPV6_RECVPKTINFO
+ optname = IPV6_RECVPKTINFO;
+#else /* ifdef IPV6_RECVPKTINFO */
+ optname = IPV6_PKTINFO;
+#endif /* ifdef IPV6_RECVPKTINFO */
+ on = 1;
+ if (setsockopt(s, IPPROTO_IPV6, optname, (const char *)&on,
+ sizeof(on)) < 0)
+ {
+ ipv6pktinfo_result = ISC_R_NOTFOUND;
+ goto close;
+ }
+
+ ipv6pktinfo_result = ISC_R_SUCCESS;
+
+close:
+ closesocket(s);
+ return;
+}
+
+static void
+initialize_ipv6pktinfo(void) {
+ RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo, try_ipv6pktinfo) ==
+ ISC_R_SUCCESS);
+}
+#endif /* __notyet__ */
+
+isc_result_t
+isc_net_probe_ipv6only(void) {
+ initialize_ipv6only();
+ return (ipv6only_result);
+}
+
+isc_result_t
+isc_net_probe_ipv6pktinfo(void) {
+#ifdef __notyet__
+ initialize_ipv6pktinfo();
+#endif /* __notyet__ */
+ return (ipv6pktinfo_result);
+}
+
+isc_result_t
+isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
+ int result = ISC_R_FAILURE;
+
+ REQUIRE(low != NULL && high != NULL);
+
+ UNUSED(af);
+
+ if (result != ISC_R_SUCCESS) {
+ *low = ISC_NET_PORTRANGELOW;
+ *high = ISC_NET_PORTRANGEHIGH;
+ }
+
+ return (ISC_R_SUCCESS); /* we currently never fail in this function */
+}
+
+void
+isc_net_disableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_SUCCESS) {
+ ipv4_result = ISC_R_DISABLED;
+ }
+}
+
+void
+isc_net_disableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_SUCCESS) {
+ ipv6_result = ISC_R_DISABLED;
+ }
+}
+
+void
+isc_net_enableipv4(void) {
+ initialize();
+ if (ipv4_result == ISC_R_DISABLED) {
+ ipv4_result = ISC_R_SUCCESS;
+ }
+}
+
+void
+isc_net_enableipv6(void) {
+ initialize();
+ if (ipv6_result == ISC_R_DISABLED) {
+ ipv6_result = ISC_R_SUCCESS;
+ }
+}
+
+unsigned int
+isc_net_probedscp(void) {
+ return (0);
+}
diff --git a/lib/isc/win32/netdb.h b/lib/isc/win32/netdb.h
new file mode 100644
index 0000000..5a5c122
--- /dev/null
+++ b/lib/isc/win32/netdb.h
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+#ifndef NETDB_H
+#define NETDB_H 1
+
+#include <stddef.h>
+#include <winsock2.h>
+
+/*
+ * Define if <netdb.h> does not declare struct addrinfo.
+ */
+
+#if _MSC_VER < 1600
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and
+ * IPv6 */
+ size_t ai_addrlen; /* Length of ai_addr */
+ char *ai_canonname; /* Canonical name for hostname */
+ struct sockaddr *ai_addr; /* Binary address */
+ struct addrinfo *ai_next; /* Next structure in linked list */
+};
+#endif /* if _MSC_VER < 1600 */
+
+/*
+ * Undefine all \#defines we are interested in as <netdb.h> may or may not have
+ * defined them.
+ */
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#undef NETDB_INTERNAL
+#undef NETDB_SUCCESS
+#undef HOST_NOT_FOUND
+#undef TRY_AGAIN
+#undef NO_RECOVERY
+#undef NO_DATA
+#undef NO_ADDRESS
+
+#define NETDB_INTERNAL -1 /* see errno */
+#define NETDB_SUCCESS 0 /* no problem */
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#undef EAI_ADDRFAMILY
+#undef EAI_AGAIN
+#undef EAI_BADFLAGS
+#undef EAI_FAIL
+#undef EAI_FAMILY
+#undef EAI_MEMORY
+#undef EAI_NODATA
+#undef EAI_NONAME
+#undef EAI_SERVICE
+#undef EAI_SOCKTYPE
+#undef EAI_SYSTEM
+#undef EAI_BADHINTS
+#undef EAI_PROTOCOL
+#undef EAI_MAX
+
+#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
+#define EAI_AGAIN 2 /* temporary failure in name resolution */
+#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
+#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_MEMORY 6 /* memory allocation failure */
+#define EAI_NODATA 7 /* no address associated with hostname */
+#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
+#define EAI_SYSTEM 11 /* system error returned in errno */
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+#define EAI_MAX 14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#undef AI_PASSIVE
+#undef AI_CANONNAME
+#undef AI_NUMERICHOST
+
+#define AI_PASSIVE 0x00000001
+#define AI_CANONNAME 0x00000002
+#define AI_NUMERICHOST 0x00000004
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#undef AI_V4MAPPED
+#undef AI_ALL
+#undef AI_ADDRCONFIG
+#undef AI_DEFAULT
+
+#define AI_V4MAPPED 0x00000008
+#define AI_ALL 0x00000010
+#define AI_ADDRCONFIG 0x00000020
+#define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
+
+/*
+ * Constants for getnameinfo()
+ */
+#undef NI_MAXHOST
+#undef NI_MAXSERV
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+/*
+ * Flag values for getnameinfo()
+ */
+#undef NI_NOFQDN
+#undef NI_NUMERICHOST
+#undef NI_NAMEREQD
+#undef NI_NUMERICSERV
+#undef NI_DGRAM
+#undef NI_NUMERICSCOPE
+
+#define NI_NOFQDN 0x00000001
+#define NI_NUMERICHOST 0x00000002
+#define NI_NAMEREQD 0x00000004
+#define NI_NUMERICSERV 0x00000008
+#define NI_DGRAM 0x00000010
+#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/
+
+/*
+ * Structures for getrrsetbyname()
+ */
+struct rdatainfo {
+ unsigned int rdi_length;
+ unsigned char *rdi_data;
+};
+
+struct rrsetinfo {
+ unsigned int rri_flags;
+ int rri_rdclass;
+ int rri_rdtype;
+ unsigned int rri_ttl;
+ unsigned int rri_nrdatas;
+ unsigned int rri_nsigs;
+ char *rri_name;
+ struct rdatainfo *rri_rdatas;
+ struct rdatainfo *rri_sigs;
+};
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#define RRSET_VALIDATED 0x00000001
+/* Set was dnssec validated */
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#define ERRSET_SUCCESS 0
+#define ERRSET_NOMEMORY 1
+#define ERRSET_FAIL 2
+#define ERRSET_INVAL 3
+
+#endif /* NETDB_H */
diff --git a/lib/isc/win32/ntgroups.c b/lib/isc/win32/ntgroups.c
new file mode 100644
index 0000000..0584d48
--- /dev/null
+++ b/lib/isc/win32/ntgroups.c
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+/*
+ * The NT Groups have two groups that are not well documented and are
+ * not normally seen: None and Everyone. A user account belongs to
+ * any number of groups, but if it is not a member of any group then
+ * it is a member of the None Group. The None group is not listed
+ * anywhere. You cannot remove an account from the none group except
+ * by making it a member of some other group, The second group is the
+ * Everyone group. All accounts, no matter how many groups that they
+ * belong to, also belong to the Everyone group. You cannot remove an
+ * account from the Everyone group.
+ */
+
+#ifndef UNICODE
+#define UNICODE
+#endif /* UNICODE */
+
+/*
+ * Silence warnings.
+ */
+#define _CRT_SECURE_NO_DEPRECATE 1
+
+/* clang-format off */
+#include <assert.h>
+#include <windows.h>
+#include <lm.h>
+/* clang-format on */
+
+#include <isc/ntgroups.h>
+#include <isc/result.h>
+
+#define MAX_NAME_LENGTH 256
+
+#define CHECK(op) \
+ do { \
+ result = (op); \
+ if (result != ISC_R_SUCCESS) { \
+ goto cleanup; \
+ } \
+ } while (0)
+
+isc_result_t
+isc_ntsecurity_getaccountgroups(char *username, char **GroupList,
+ unsigned int maxgroups,
+ unsigned int *totalGroups) {
+ LPGROUP_USERS_INFO_0 pTmpBuf;
+ LPLOCALGROUP_USERS_INFO_0 pTmpLBuf;
+ DWORD i;
+ LPLOCALGROUP_USERS_INFO_0 pBuf = NULL;
+ LPGROUP_USERS_INFO_0 pgrpBuf = NULL;
+ DWORD dwLevel = 0;
+ DWORD dwFlags = LG_INCLUDE_INDIRECT;
+ DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
+ DWORD dwEntriesRead = 0;
+ DWORD dwTotalEntries = 0;
+ NET_API_STATUS nStatus;
+ size_t retlen;
+ wchar_t user[MAX_NAME_LENGTH];
+ isc_result_t result;
+
+ *totalGroups = 0;
+
+ retlen = mbstowcs(user, username, MAX_NAME_LENGTH);
+ if (retlen == (size_t)(-1)) {
+ return (ISC_R_FAILURE);
+ }
+
+ /*
+ * Call the NetUserGetLocalGroups function
+ * specifying information level 0.
+ *
+ * The LG_INCLUDE_INDIRECT flag specifies that the
+ * function should also return the names of the local
+ * groups in which the user is indirectly a member.
+ */
+ nStatus = NetUserGetLocalGroups(NULL, user, dwLevel, dwFlags,
+ (LPBYTE *)&pBuf, dwPrefMaxLen,
+ &dwEntriesRead, &dwTotalEntries);
+ /*
+ * See if the call succeeds,
+ */
+ if (nStatus != NERR_Success) {
+ if (nStatus == ERROR_ACCESS_DENIED) {
+ return (ISC_R_NOPERM);
+ }
+ if (nStatus == ERROR_MORE_DATA) {
+ return (ISC_R_NOSPACE);
+ }
+ if (nStatus == NERR_UserNotFound) {
+ dwEntriesRead = 0;
+ }
+ }
+
+ if (pBuf != NULL) {
+ pTmpLBuf = pBuf;
+ /*
+ * Loop through the entries
+ */
+ for (i = 0; (i < dwEntriesRead && *totalGroups < maxgroups);
+ i++)
+ {
+ assert(pTmpLBuf != NULL);
+ if (pTmpLBuf == NULL) {
+ break;
+ }
+ retlen = wcslen(pTmpLBuf->lgrui0_name);
+ GroupList[*totalGroups] = (char *)malloc(retlen + 1);
+ if (GroupList[*totalGroups] == NULL) {
+ CHECK(ISC_R_NOMEMORY);
+ }
+
+ retlen = wcstombs(GroupList[*totalGroups],
+ pTmpLBuf->lgrui0_name, retlen);
+ if (retlen == (size_t)(-1)) {
+ free(GroupList[*totalGroups]);
+ CHECK(ISC_R_FAILURE);
+ }
+ GroupList[*totalGroups][retlen] = '\0';
+ if (strcmp(GroupList[*totalGroups], "None") == 0) {
+ free(GroupList[*totalGroups]);
+ } else {
+ (*totalGroups)++;
+ }
+ pTmpLBuf++;
+ }
+ }
+ /* Free the allocated memory. */
+ /* cppcheck-suppress duplicateCondition */
+ if (pBuf != NULL) {
+ NetApiBufferFree(pBuf);
+ }
+
+ /*
+ * Call the NetUserGetGroups function, specifying level 0.
+ */
+ nStatus = NetUserGetGroups(NULL, user, dwLevel, (LPBYTE *)&pgrpBuf,
+ dwPrefMaxLen, &dwEntriesRead,
+ &dwTotalEntries);
+ /*
+ * See if the call succeeds,
+ */
+ if (nStatus != NERR_Success) {
+ if (nStatus == ERROR_ACCESS_DENIED) {
+ return (ISC_R_NOPERM);
+ }
+ if (nStatus == ERROR_MORE_DATA) {
+ return (ISC_R_NOSPACE);
+ }
+ if (nStatus == NERR_UserNotFound) {
+ dwEntriesRead = 0;
+ }
+ }
+
+ if (pgrpBuf != NULL) {
+ pTmpBuf = pgrpBuf;
+ /*
+ * Loop through the entries
+ */
+ for (i = 0; (i < dwEntriesRead && *totalGroups < maxgroups);
+ i++)
+ {
+ assert(pTmpBuf != NULL);
+
+ if (pTmpBuf == NULL) {
+ break;
+ }
+ retlen = wcslen(pTmpBuf->grui0_name);
+ GroupList[*totalGroups] = (char *)malloc(retlen + 1);
+ if (GroupList[*totalGroups] == NULL) {
+ CHECK(ISC_R_NOMEMORY);
+ }
+
+ retlen = wcstombs(GroupList[*totalGroups],
+ pTmpBuf->grui0_name, retlen);
+ if (retlen == (size_t)(-1)) {
+ free(GroupList[*totalGroups]);
+ CHECK(ISC_R_FAILURE);
+ }
+ GroupList[*totalGroups][retlen] = '\0';
+ if (strcmp(GroupList[*totalGroups], "None") == 0) {
+ free(GroupList[*totalGroups]);
+ } else {
+ (*totalGroups)++;
+ }
+ pTmpBuf++;
+ }
+ }
+ /*
+ * Free the allocated memory.
+ */
+ /* cppcheck-suppress duplicateCondition */
+ if (pgrpBuf != NULL) {
+ NetApiBufferFree(pgrpBuf);
+ }
+
+ return (ISC_R_SUCCESS);
+
+cleanup:
+ while (--(*totalGroups) > 0) {
+ free(GroupList[*totalGroups]);
+ }
+ return (result);
+}
diff --git a/lib/isc/win32/ntpaths.c b/lib/isc/win32/ntpaths.c
new file mode 100644
index 0000000..793b72a
--- /dev/null
+++ b/lib/isc/win32/ntpaths.c
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+/*
+ * This module fetches the required path information that is specific
+ * to NT systems which can have its configuration and system files
+ * almost anywhere. It can be used to override whatever the application
+ * had previously assigned to the pointer. Basic information about the
+ * file locations are stored in the registry.
+ */
+
+#include <isc/bind_registry.h>
+#include <isc/ntpaths.h>
+#include <isc/string.h>
+
+/*
+ * Module Variables
+ */
+
+static char systemDir[MAX_PATH];
+static char namedBase[MAX_PATH];
+static char ns_confFile[MAX_PATH];
+static char rndc_confFile[MAX_PATH];
+static char ns_defaultpidfile[MAX_PATH];
+static char ns_lockfile[MAX_PATH];
+static char local_state_dir[MAX_PATH];
+static char sys_conf_dir[MAX_PATH];
+static char rndc_keyFile[MAX_PATH];
+static char session_keyFile[MAX_PATH];
+static char resolv_confFile[MAX_PATH];
+static char bind_keysFile[MAX_PATH];
+
+static DWORD baseLen = MAX_PATH;
+static BOOL Initialized = FALSE;
+
+void
+isc_ntpaths_init(void) {
+ HKEY hKey;
+ BOOL keyFound = TRUE;
+
+ memset(namedBase, 0, sizeof(namedBase));
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey) !=
+ ERROR_SUCCESS)
+ {
+ keyFound = FALSE;
+ }
+
+ if (keyFound == TRUE) {
+ /* Get the named directory */
+ if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL,
+ (LPBYTE)namedBase,
+ &baseLen) != ERROR_SUCCESS)
+ {
+ keyFound = FALSE;
+ }
+ RegCloseKey(hKey);
+ }
+
+ GetSystemDirectory(systemDir, MAX_PATH);
+
+ if (keyFound == FALSE) {
+ /* Use the System Directory as a default */
+ strlcpy(namedBase, systemDir, sizeof(namedBase));
+ }
+
+ strlcpy(ns_confFile, namedBase, sizeof(ns_confFile));
+ strlcat(ns_confFile, "\\etc\\named.conf", sizeof(ns_confFile));
+
+ strlcpy(rndc_keyFile, namedBase, sizeof(rndc_keyFile));
+ strlcat(rndc_keyFile, "\\etc\\rndc.key", sizeof(rndc_keyFile));
+
+ strlcpy(session_keyFile, namedBase, sizeof(session_keyFile));
+ strlcat(session_keyFile, "\\etc\\session.key", sizeof(session_keyFile));
+
+ strlcpy(rndc_confFile, namedBase, sizeof(rndc_confFile));
+ strlcat(rndc_confFile, "\\etc\\rndc.conf", sizeof(rndc_confFile));
+
+ strlcpy(ns_defaultpidfile, namedBase, sizeof(ns_defaultpidfile));
+ strlcat(ns_defaultpidfile, "\\etc\\named.pid",
+ sizeof(ns_defaultpidfile));
+
+ strlcpy(ns_lockfile, namedBase, sizeof(ns_lockfile));
+ strlcat(ns_lockfile, "\\etc\\named.lock", sizeof(ns_lockfile));
+
+ strlcpy(local_state_dir, namedBase, sizeof(local_state_dir));
+ strlcat(local_state_dir, "\\bin", sizeof(local_state_dir));
+
+ strlcpy(sys_conf_dir, namedBase, sizeof(sys_conf_dir));
+ strlcat(sys_conf_dir, "\\etc", sizeof(sys_conf_dir));
+
+ /* Added to avoid an assert on NULL value */
+ strlcpy(resolv_confFile, namedBase, sizeof(resolv_confFile));
+ strlcat(resolv_confFile, "\\etc\\resolv.conf", sizeof(resolv_confFile));
+
+ strlcpy(bind_keysFile, namedBase, sizeof(bind_keysFile));
+ strlcat(bind_keysFile, "\\etc\\bind.keys", sizeof(bind_keysFile));
+
+ Initialized = TRUE;
+}
+
+char *
+isc_ntpaths_get(int ind) {
+ if (!Initialized) {
+ isc_ntpaths_init();
+ }
+
+ switch (ind) {
+ case NAMED_CONF_PATH:
+ return (ns_confFile);
+ break;
+ case RESOLV_CONF_PATH:
+ return (resolv_confFile);
+ break;
+ case RNDC_CONF_PATH:
+ return (rndc_confFile);
+ break;
+ case NAMED_PID_PATH:
+ return (ns_defaultpidfile);
+ break;
+ case NAMED_LOCK_PATH:
+ return (ns_lockfile);
+ break;
+ case LOCAL_STATE_DIR:
+ return (local_state_dir);
+ break;
+ case SYS_CONF_DIR:
+ return (sys_conf_dir);
+ break;
+ case RNDC_KEY_PATH:
+ return (rndc_keyFile);
+ break;
+ case SESSION_KEY_PATH:
+ return (session_keyFile);
+ break;
+ case BIND_KEYS_PATH:
+ return (bind_keysFile);
+ break;
+ default:
+ return (NULL);
+ }
+}
diff --git a/lib/isc/win32/once.c b/lib/isc/win32/once.c
new file mode 100644
index 0000000..23966cb
--- /dev/null
+++ b/lib/isc/win32/once.c
@@ -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.
+ */
+
+#include <windows.h>
+
+#include <isc/assertions.h>
+#include <isc/once.h>
+#include <isc/util.h>
+
+isc_result_t
+isc_once_do(isc_once_t *controller, void (*function)(void)) {
+ REQUIRE(controller != NULL && function != NULL);
+
+ if (controller->status == ISC_ONCE_INIT_NEEDED) {
+ if (InterlockedDecrement(&controller->counter) == 0) {
+ if (controller->status == ISC_ONCE_INIT_NEEDED) {
+ function();
+ controller->status = ISC_ONCE_INIT_DONE;
+ }
+ } else {
+ while (controller->status == ISC_ONCE_INIT_NEEDED) {
+ /*
+ * Sleep(0) indicates that this thread
+ * should be suspended to allow other
+ * waiting threads to execute.
+ */
+ Sleep(0);
+ }
+ }
+ }
+
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/os.c b/lib/isc/win32/os.c
new file mode 100644
index 0000000..19a992e
--- /dev/null
+++ b/lib/isc/win32/os.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <windows.h>
+
+#include <isc/os.h>
+
+static BOOL bInit = FALSE;
+static SYSTEM_INFO SystemInfo;
+
+static void
+initialize_action(void) {
+ if (bInit) {
+ return;
+ }
+
+ GetSystemInfo(&SystemInfo);
+ bInit = TRUE;
+}
+
+unsigned int
+isc_os_ncpus(void) {
+ long ncpus;
+ initialize_action();
+ ncpus = SystemInfo.dwNumberOfProcessors;
+ if (ncpus <= 0) {
+ ncpus = 1;
+ }
+
+ return ((unsigned int)ncpus);
+}
diff --git a/lib/isc/win32/pk11_api.c b/lib/isc/win32/pk11_api.c
new file mode 100644
index 0000000..5ee8e0d
--- /dev/null
+++ b/lib/isc/win32/pk11_api.c
@@ -0,0 +1,706 @@
+/*
+ * 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 */
+
+/* missing code for WIN32 */
+
+#include <string.h>
+#include <windows.h>
+
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/print.h>
+#include <isc/stdio.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include <pk11/internal.h>
+#include <pk11/pk11.h>
+
+char *
+getpass(const char *prompt) {
+ static char buf[128];
+ HANDLE h;
+ DWORD cc, mode;
+ int cnt;
+
+ h = GetStdHandle(STD_INPUT_HANDLE);
+ fputs(prompt, stderr);
+ fflush(stderr);
+ fflush(stdout);
+ FlushConsoleInputBuffer(h);
+ GetConsoleMode(h, &mode);
+ SetConsoleMode(h, ENABLE_PROCESSED_INPUT);
+
+ for (cnt = 0; cnt < sizeof(buf) - 1; cnt++) {
+ ReadFile(h, buf + cnt, 1, &cc, NULL);
+ if (buf[cnt] == '\r') {
+ break;
+ }
+ fputc('*', stdout);
+ fflush(stderr);
+ fflush(stdout);
+ }
+
+ SetConsoleMode(h, mode);
+ buf[cnt] = '\0';
+ fputs("\n", stderr);
+ return (buf);
+}
+
+/* load PKCS11 DLL */
+
+static HINSTANCE hPK11 = NULL;
+static char loaderrmsg[1024];
+
+CK_RV
+pkcs_C_Initialize(CK_VOID_PTR pReserved) {
+ CK_C_Initialize sym;
+ const char *lib_name = pk11_get_lib_name();
+
+ if (hPK11 != NULL) {
+ return (CKR_LIBRARY_ALREADY_INITIALIZED);
+ }
+
+ if (lib_name == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ /* Visual Studio conversion issue... */
+ if (*lib_name == ' ') {
+ lib_name++;
+ }
+
+ hPK11 = LoadLibraryA(lib_name);
+
+ if (hPK11 == NULL) {
+ const DWORD err = GetLastError();
+ snprintf(loaderrmsg, sizeof(loaderrmsg),
+ "LoadLibraryA(\"%s\") failed with 0x%X\n", lib_name,
+ err);
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ sym = (CK_C_Initialize)GetProcAddress(hPK11, "C_Initialize");
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(pReserved));
+}
+
+char *
+pk11_get_load_error_message(void) {
+ return (loaderrmsg);
+}
+
+CK_RV
+pkcs_C_Finalize(CK_VOID_PTR pReserved) {
+ CK_C_Finalize sym;
+ CK_RV rv;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ sym = (CK_C_Finalize)GetProcAddress(hPK11, "C_Finalize");
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ rv = (*sym)(pReserved);
+ if ((rv == CKR_OK) && (FreeLibrary(hPK11) == 0)) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ hPK11 = NULL;
+ return (rv);
+}
+
+CK_RV
+pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount) {
+ static CK_C_GetSlotList sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GetSlotList)GetProcAddress(hPK11, "C_GetSlotList");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(tokenPresent, pSlotList, pulCount));
+}
+
+CK_RV
+pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) {
+ static CK_C_GetTokenInfo sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GetTokenInfo)GetProcAddress(hPK11, "C_"
+ "GetTokenInfo");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(slotID, pInfo));
+}
+
+CK_RV
+pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR pInfo) {
+ static CK_C_GetMechanismInfo sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GetMechanismInfo)GetProcAddress(hPK11, "C_"
+ "GetMechanis"
+ "mInfo");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(slotID, type, pInfo));
+}
+
+CK_RV
+pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
+ CK_RV (*Notify)(CK_SESSION_HANDLE hSession,
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication),
+ CK_SESSION_HANDLE_PTR phSession) {
+ static CK_C_OpenSession sym = NULL;
+
+ if (hPK11 == NULL) {
+ hPK11 = LoadLibraryA(pk11_get_lib_name());
+ }
+ if (hPK11 == NULL) {
+ const DWORD err = GetLastError();
+ snprintf(loaderrmsg, sizeof(loaderrmsg),
+ "LoadLibraryA(\"%s\") failed with 0x%X\n",
+ pk11_get_lib_name(), err);
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_OpenSession)GetProcAddress(hPK11, "C_OpenSession");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(slotID, flags, pApplication, Notify, phSession));
+}
+
+CK_RV
+pkcs_C_CloseSession(CK_SESSION_HANDLE hSession) {
+ static CK_C_CloseSession sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_CloseSession)GetProcAddress(hPK11, "C_"
+ "CloseSession");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession));
+}
+
+CK_RV
+pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
+ CK_CHAR_PTR pPin, CK_ULONG usPinLen) {
+ static CK_C_Login sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_Login)GetProcAddress(hPK11, "C_Login");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, userType, pPin, usPinLen));
+}
+
+CK_RV
+pkcs_C_Logout(CK_SESSION_HANDLE hSession) {
+ static CK_C_Logout sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_Logout)GetProcAddress(hPK11, "C_Logout");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession));
+}
+
+CK_RV
+pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject) {
+ static CK_C_CreateObject sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_CreateObject)GetProcAddress(hPK11, "C_"
+ "CreateObject");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pTemplate, usCount, phObject));
+}
+
+CK_RV
+pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) {
+ static CK_C_DestroyObject sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_DestroyObject)GetProcAddress(hPK11, "C_"
+ "DestroyObjec"
+ "t");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, hObject));
+}
+
+CK_RV
+pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount) {
+ static CK_C_GetAttributeValue sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GetAttributeValue)GetProcAddress(hPK11, "C_"
+ "GetAttribu"
+ "teValue");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, hObject, pTemplate, usCount));
+}
+
+CK_RV
+pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount) {
+ static CK_C_SetAttributeValue sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_SetAttributeValue)GetProcAddress(hPK11, "C_"
+ "SetAttribu"
+ "teValue");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, hObject, pTemplate, usCount));
+}
+
+CK_RV
+pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG usCount) {
+ static CK_C_FindObjectsInit sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_FindObjectsInit)GetProcAddress(hPK11, "C_"
+ "FindObjectsI"
+ "nit");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pTemplate, usCount));
+}
+
+CK_RV
+pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
+ CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount) {
+ static CK_C_FindObjects sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_FindObjects)GetProcAddress(hPK11, "C_FindObjects");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, phObject, usMaxObjectCount, pusObjectCount));
+}
+
+CK_RV
+pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession) {
+ static CK_C_FindObjectsFinal sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_FindObjectsFinal)GetProcAddress(hPK11, "C_"
+ "FindObjects"
+ "Final");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession));
+}
+
+CK_RV
+pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey) {
+ static CK_C_EncryptInit sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_EncryptInit)GetProcAddress(hPK11, "C_EncryptInit");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism, hKey));
+}
+
+CK_RV
+pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen) {
+ static CK_C_Encrypt sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_Encrypt)GetProcAddress(hPK11, "C_Encrypt");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pData, ulDataLen, pEncryptedData,
+ pulEncryptedDataLen));
+}
+
+CK_RV
+pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) {
+ static CK_C_DigestInit sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_DigestInit)GetProcAddress(hPK11, "C_DigestInit");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism));
+}
+
+CK_RV
+pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen) {
+ static CK_C_DigestUpdate sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_DigestUpdate)GetProcAddress(hPK11, "C_"
+ "DigestUpdate");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pPart, ulPartLen));
+}
+
+CK_RV
+pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
+ CK_ULONG_PTR pulDigestLen) {
+ static CK_C_DigestFinal sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_DigestFinal)GetProcAddress(hPK11, "C_DigestFinal");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pDigest, pulDigestLen));
+}
+
+CK_RV
+pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey) {
+ static CK_C_SignInit sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_SignInit)GetProcAddress(hPK11, "C_SignInit");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism, hKey));
+}
+
+CK_RV
+pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) {
+ static CK_C_Sign sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_Sign)GetProcAddress(hPK11, "C_Sign");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pData, ulDataLen, pSignature,
+ pulSignatureLen));
+}
+
+CK_RV
+pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen) {
+ static CK_C_SignUpdate sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_SignUpdate)GetProcAddress(hPK11, "C_SignUpdate");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pPart, ulPartLen));
+}
+
+CK_RV
+pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen) {
+ static CK_C_SignFinal sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_SignFinal)GetProcAddress(hPK11, "C_SignFinal");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pSignature, pulSignatureLen));
+}
+
+CK_RV
+pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey) {
+ static CK_C_VerifyInit sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_VerifyInit)GetProcAddress(hPK11, "C_VerifyInit");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism, hKey));
+}
+
+CK_RV
+pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) {
+ static CK_C_Verify sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_Verify)GetProcAddress(hPK11, "C_Verify");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pData, ulDataLen, pSignature, ulSignatureLen));
+}
+
+CK_RV
+pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen) {
+ static CK_C_VerifyUpdate sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_VerifyUpdate)GetProcAddress(hPK11, "C_"
+ "VerifyUpdate");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pPart, ulPartLen));
+}
+
+CK_RV
+pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen) {
+ static CK_C_VerifyFinal sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_VerifyFinal)GetProcAddress(hPK11, "C_VerifyFinal");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pSignature, ulSignatureLen));
+}
+
+CK_RV
+pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phKey) {
+ static CK_C_GenerateKey sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GenerateKey)GetProcAddress(hPK11, "C_GenerateKey");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism, pTemplate, ulCount, phKey));
+}
+
+CK_RV
+pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ CK_ULONG usPublicKeyAttributeCount,
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ CK_ULONG usPrivateKeyAttributeCount,
+ CK_OBJECT_HANDLE_PTR phPrivateKey,
+ CK_OBJECT_HANDLE_PTR phPublicKey) {
+ static CK_C_GenerateKeyPair sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GenerateKeyPair)GetProcAddress(hPK11, "C_"
+ "GenerateKeyP"
+ "air");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism, pPublicKeyTemplate,
+ usPublicKeyAttributeCount, pPrivateKeyTemplate,
+ usPrivateKeyAttributeCount, phPrivateKey, phPublicKey));
+}
+
+CK_RV
+pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) {
+ static CK_C_DeriveKey sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_DeriveKey)GetProcAddress(hPK11, "C_DeriveKey");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pMechanism, hBaseKey, pTemplate,
+ ulAttributeCount, phKey));
+}
+
+CK_RV
+pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
+ CK_ULONG ulSeedLen) {
+ static CK_C_SeedRandom sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_SeedRandom)GetProcAddress(hPK11, "C_SeedRandom");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, pSeed, ulSeedLen));
+}
+
+CK_RV
+pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData,
+ CK_ULONG ulRandomLen) {
+ static CK_C_GenerateRandom sym = NULL;
+
+ if (hPK11 == NULL) {
+ return (CKR_LIBRARY_FAILED_TO_LOAD);
+ }
+ if (sym == NULL) {
+ sym = (CK_C_GenerateRandom)GetProcAddress(hPK11, "C_"
+ "GenerateRando"
+ "m");
+ }
+ if (sym == NULL) {
+ return (CKR_SYMBOL_RESOLUTION_FAILED);
+ }
+ return ((*sym)(hSession, RandomData, ulRandomLen));
+}
diff --git a/lib/isc/win32/resource.c b/lib/isc/win32/resource.c
new file mode 100644
index 0000000..b44b322
--- /dev/null
+++ b/lib/isc/win32/resource.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdio.h>
+
+#include <isc/platform.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+/*
+ * Windows limits the maximum number of open files to 2048
+ */
+
+#define WIN32_MAX_OPEN_FILES 2048
+
+isc_result_t
+isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
+ isc_resourcevalue_t rlim_value;
+ int wresult;
+
+ if (resource != isc_resource_openfiles) {
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+
+ if (value == ISC_RESOURCE_UNLIMITED) {
+ rlim_value = WIN32_MAX_OPEN_FILES;
+ } else {
+ rlim_value = min(value, WIN32_MAX_OPEN_FILES);
+ }
+
+ wresult = _setmaxstdio((int)rlim_value);
+
+ if (wresult > 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+isc_result_t
+isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+ if (resource != isc_resource_openfiles) {
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+
+ *value = WIN32_MAX_OPEN_FILES;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
+ return (isc_resource_getlimit(resource, value));
+}
diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c
new file mode 100644
index 0000000..c154175
--- /dev/null
+++ b/lib/isc/win32/socket.c
@@ -0,0 +1,3965 @@
+/*
+ * 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.
+ */
+
+/* This code uses functions which are only available on Server 2003 and
+ * higher, and Windows XP and higher.
+ *
+ * This code is by nature multithreaded and takes advantage of various
+ * features to pass on information through the completion port for
+ * when I/O is completed. All sends, receives, accepts, and connects are
+ * completed through the completion port.
+ *
+ * The number of Completion Port Worker threads used is the total number
+ * of CPU's + 1. This increases the likelihood that a Worker Thread is
+ * available for processing a completed request.
+ *
+ * XXXPDM 5 August, 2002
+ */
+
+#define MAKE_EXTERNAL 1
+
+#include <sys/types.h>
+
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
+#endif /* ifndef _WINSOCKAPI_ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <io.h>
+#include <process.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/buffer.h>
+#include <isc/condition.h>
+#include <isc/list.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/mutex.h>
+#include <isc/net.h>
+#include <isc/once.h>
+#include <isc/os.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/refcount.h>
+#include <isc/region.h>
+#include <isc/socket.h>
+#include <isc/stats.h>
+#include <isc/strerr.h>
+#include <isc/string.h>
+#include <isc/syslog.h>
+#include <isc/task.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+#include <isc/win32os.h>
+
+/* clang-format off */
+/* U Can't Touch This */
+#include <mswsock.h>
+/* clang-format on */
+
+#ifdef HAVE_JSON_C
+#include <json_object.h>
+#endif /* HAVE_JSON_C */
+
+#ifdef HAVE_LIBXML2
+#include <libxml/xmlwriter.h>
+#define ISC_XMLCHAR (const xmlChar *)
+#endif /* HAVE_LIBXML2 */
+
+#include "errno2result.h"
+
+/*
+ * Set by the -T dscp option on the command line. If set to a value
+ * other than -1, we check to make sure DSCP values match it, and
+ * assert if not.
+ */
+LIBISC_EXTERNAL_DATA int isc_dscp_check_value = -1;
+
+/*
+ * How in the world can Microsoft exist with APIs like this?
+ * We can't actually call this directly, because it turns out
+ * no library exports this function. Instead, we need to
+ * issue a runtime call to get the address.
+ */
+LPFN_CONNECTEX ISCConnectEx;
+LPFN_ACCEPTEX ISCAcceptEx;
+LPFN_GETACCEPTEXSOCKADDRS ISCGetAcceptExSockaddrs;
+
+/*
+ * Run expensive internal consistency checks.
+ */
+#ifdef ISC_SOCKET_CONSISTENCY_CHECKS
+#define CONSISTENT(sock) consistent(sock)
+#else /* ifdef ISC_SOCKET_CONSISTENCY_CHECKS */
+#define CONSISTENT(sock) \
+ do { \
+ } while (0)
+#endif /* ifdef ISC_SOCKET_CONSISTENCY_CHECKS */
+static void
+consistent(isc_socket_t *sock);
+
+/*
+ * Define this macro to control the behavior of connection
+ * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823
+ * for details.
+ * NOTE: This requires that Windows 2000 systems install Service Pack 2
+ * or later.
+ */
+#ifndef SIO_UDP_CONNRESET
+#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
+#endif /* ifndef SIO_UDP_CONNRESET */
+
+/*
+ * Define what the possible "soft" errors can be. These are non-fatal returns
+ * of various network related functions, like recv() and so on.
+ */
+#define SOFT_ERROR(e) \
+ ((e) == WSAEINTR || (e) == WSAEWOULDBLOCK || (e) == EWOULDBLOCK || \
+ (e) == EINTR || (e) == EAGAIN || (e) == 0)
+
+/*
+ * Pending errors are not really errors and should be
+ * kept separate
+ */
+#define PENDING_ERROR(e) ((e) == WSA_IO_PENDING || (e) == 0)
+
+#define DOIO_SUCCESS 0 /* i/o ok, event sent */
+#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */
+#define DOIO_HARD 2 /* i/o error, event sent */
+#define DOIO_EOF 3 /* EOF, no event sent */
+#define DOIO_PENDING 4 /* status when i/o is in process */
+#define DOIO_NEEDMORE \
+ 5 /* IO was processed, but we need more due to minimum \
+ */
+
+#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
+
+/*
+ * DLVL(90) -- Function entry/exit and other tracing.
+ * DLVL(70) -- Socket "correctness" -- including returning of events, etc.
+ * DLVL(60) -- Socket data send/receive
+ * DLVL(50) -- Event tracing, including receiving/sending completion events.
+ * DLVL(20) -- Socket creation/destruction.
+ */
+#define TRACE_LEVEL 90
+#define CORRECTNESS_LEVEL 70
+#define IOEVENT_LEVEL 60
+#define EVENT_LEVEL 50
+#define CREATION_LEVEL 20
+
+#define TRACE DLVL(TRACE_LEVEL)
+#define CORRECTNESS DLVL(CORRECTNESS_LEVEL)
+#define IOEVENT DLVL(IOEVENT_LEVEL)
+#define EVENT DLVL(EVENT_LEVEL)
+#define CREATION DLVL(CREATION_LEVEL)
+
+typedef isc_event_t intev_t;
+
+/*
+ * Socket State
+ */
+enum {
+ SOCK_INITIALIZED, /* Socket Initialized */
+ SOCK_OPEN, /* Socket opened but nothing yet to do */
+ SOCK_DATA, /* Socket sending or receiving data */
+ SOCK_LISTEN, /* TCP Socket listening for connects */
+ SOCK_ACCEPT, /* TCP socket is waiting to accept */
+ SOCK_CONNECT, /* TCP Socket connecting */
+ SOCK_CLOSED, /* Socket has been closed */
+};
+
+#define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o')
+#define VALID_SOCKET(t) ISC_MAGIC_VALID(t, SOCKET_MAGIC)
+
+/*
+ * IPv6 control information. If the socket is an IPv6 socket we want
+ * to collect the destination address and interface so the client can
+ * set them on outgoing packets.
+ */
+#ifndef USE_CMSG
+#define USE_CMSG 1
+#endif /* ifndef USE_CMSG */
+
+/*
+ * We really don't want to try and use these control messages. Win32
+ * doesn't have this mechanism before XP.
+ */
+#undef USE_CMSG
+
+/*
+ * Message header for recvmsg and sendmsg calls.
+ * Used value-result for recvmsg, value only for sendmsg.
+ */
+struct msghdr {
+ SOCKADDR_STORAGE to_addr; /* UDP send/recv address */
+ int to_addr_len; /* length of the address */
+ WSABUF *msg_iov; /* scatter/gather array */
+ u_int msg_iovlen; /* # elements in msg_iov */
+ void *msg_control; /* ancillary data, see below */
+ u_int msg_controllen; /* ancillary data buffer len */
+ u_int msg_totallen; /* total length of this message */
+} msghdr;
+
+/*
+ * The size to raise the receive buffer to.
+ */
+#define RCVBUFSIZE (32 * 1024)
+
+/*
+ * The number of times a send operation is repeated if the result
+ * is WSAEINTR.
+ */
+#define NRETRIES 10
+
+struct isc_socket {
+ /* Not locked. */
+ unsigned int magic;
+ isc_socketmgr_t *manager;
+ isc_mutex_t lock;
+ isc_sockettype_t type;
+
+ /* Pointers to scatter/gather buffers */
+ WSABUF iov[ISC_SOCKET_MAXSCATTERGATHER];
+
+ /* Locked by socket lock. */
+ ISC_LINK(isc_socket_t) link;
+ isc_refcount_t references; /* EXTERNAL references */
+ SOCKET fd; /* file handle */
+ int pf; /* protocol family */
+ char name[16];
+ void *tag;
+
+ /*
+ * Each recv() call uses this buffer. It is a per-socket receive
+ * buffer that allows us to decouple the system recv() from the
+ * recv_list done events. This means the items on the recv_list
+ * can be removed without having to cancel pending system recv()
+ * calls. It also allows us to read-ahead in some cases.
+ */
+ struct {
+ SOCKADDR_STORAGE from_addr; /* UDP send/recv address */
+ int from_addr_len; /* length of the address */
+ char *base; /* the base of the buffer */
+ char *consume_position; /* where to start
+ * copying data from
+ * next */
+ unsigned int len; /* the actual size of this buffer */
+ unsigned int remaining; /* the number of bytes
+ * remaining */
+ } recvbuf;
+
+ ISC_LIST(isc_socketevent_t) send_list;
+ ISC_LIST(isc_socketevent_t) recv_list;
+ ISC_LIST(isc_socket_newconnev_t) accept_list;
+ ISC_LIST(isc_socket_connev_t) connect_list;
+
+ isc_sockaddr_t address; /* remote address */
+
+ unsigned int listener : 1, /* listener socket */
+ connected : 1, pending_connect : 1, /* connect
+ * pending */
+ bound : 1, /* bound to local addr */
+ dupped : 1; /* created by isc_socket_dup() */
+ unsigned int pending_iocp; /* Should equal the counters below.
+ * Debug. */
+ unsigned int pending_recv; /* Number of outstanding recv() calls.
+ * */
+ unsigned int pending_send; /* Number of outstanding send() calls.
+ * */
+ unsigned int pending_accept; /* Number of outstanding accept()
+ * calls. */
+ unsigned int state; /* Socket state. Debugging and consistency
+ * checking.
+ */
+ int state_lineno; /* line which last touched state */
+};
+
+#define _set_state(sock, _state) \
+ do { \
+ (sock)->state = (_state); \
+ (sock)->state_lineno = __LINE__; \
+ } while (0)
+
+/*
+ * I/O Completion ports Info structures
+ */
+
+static HANDLE hHeapHandle = NULL;
+typedef struct IoCompletionInfo {
+ OVERLAPPED overlapped;
+ isc_socketevent_t *dev; /* send()/recv() done event */
+ isc_socket_connev_t *cdev; /* connect() done event */
+ isc_socket_newconnev_t *adev; /* accept() done event */
+ void *acceptbuffer;
+ DWORD received_bytes;
+ int request_type;
+ struct msghdr messagehdr;
+ void *buf;
+ unsigned int buflen;
+} IoCompletionInfo;
+
+/*
+ * Define a maximum number of I/O Completion Port worker threads
+ * to handle the load on the Completion Port. The actual number
+ * used is the number of CPU's + 1.
+ */
+#define MAX_IOCPTHREADS 20
+
+#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
+#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
+
+struct isc_socketmgr {
+ /* Not locked. */
+ unsigned int magic;
+ isc_mem_t *mctx;
+ isc_mutex_t lock;
+ isc_stats_t *stats;
+
+ /* Locked by manager lock. */
+ ISC_LIST(isc_socket_t) socklist;
+ bool bShutdown;
+ isc_condition_t shutdown_ok;
+ HANDLE hIoCompletionPort;
+ int maxIOCPThreads;
+ HANDLE hIOCPThreads[MAX_IOCPTHREADS];
+ size_t maxudp;
+
+ /*
+ * Debugging.
+ * Modified by InterlockedIncrement() and InterlockedDecrement()
+ */
+ LONG totalSockets;
+ LONG iocp_total;
+};
+
+enum { SOCKET_RECV, SOCKET_SEND, SOCKET_ACCEPT, SOCKET_CONNECT };
+
+/*
+ * send() and recv() iovec counts
+ */
+#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER)
+#define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
+
+static isc_result_t
+socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp, isc_socket_t *dup_socket);
+static isc_threadresult_t WINAPI
+SocketIoThread(LPVOID ThreadContext);
+static void
+maybe_free_socket(isc_socket_t **, int);
+static void
+free_socket(isc_socket_t **, int);
+static bool
+senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev);
+static bool
+acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev);
+static bool
+connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev);
+static void
+send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev);
+static void
+send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev);
+static void
+send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev);
+static void
+send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev);
+static void
+send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
+static void
+send_connectdone_abort(isc_socket_t *sock, isc_result_t result);
+static void
+queue_receive_event(isc_socket_t *sock, isc_task_t *task,
+ isc_socketevent_t *dev);
+static void
+queue_receive_request(isc_socket_t *sock);
+
+/*
+ * This is used to dump the contents of the sock structure
+ * You should make sure that the sock is locked before
+ * dumping it. Since the code uses simple printf() statements
+ * it should only be used interactively.
+ */
+void
+sock_dump(isc_socket_t *sock) {
+ isc_socketevent_t *ldev;
+ isc_socket_newconnev_t *ndev;
+ isc_socket_connev_t *cdev;
+
+#if 0
+ isc_sockaddr_t addr;
+ char socktext[ISC_SOCKADDR_FORMATSIZE];
+ isc_result_t result;
+
+ result = isc_socket_getpeername(sock,&addr);
+ if (result == ISC_R_SUCCESS) {
+ isc_sockaddr_format(&addr,socktext,sizeof(socktext));
+ printf("Remote Socket: %s\n",socktext);
+ }
+ result = isc_socket_getsockname(sock,&addr);
+ if (result == ISC_R_SUCCESS) {
+ isc_sockaddr_format(&addr,socktext,sizeof(socktext));
+ printf("This Socket: %s\n",socktext);
+ }
+#endif /* if 0 */
+
+ printf("\n\t\tSock Dump\n");
+ printf("\t\tfd: %Iu\n", sock->fd);
+ printf("\t\treferences: %" PRIuFAST32 "\n",
+ isc_refcount_current(&sock->references));
+ printf("\t\tpending_accept: %u\n", sock->pending_accept);
+ printf("\t\tconnecting: %u\n", sock->pending_connect);
+ printf("\t\tconnected: %u\n", sock->connected);
+ printf("\t\tbound: %u\n", sock->bound);
+ printf("\t\tpending_iocp: %u\n", sock->pending_iocp);
+ printf("\t\tsocket type: %d\n", sock->type);
+
+ printf("\n\t\tSock Recv List\n");
+ ldev = ISC_LIST_HEAD(sock->recv_list);
+ while (ldev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+
+ printf("\n\t\tSock Send List\n");
+ ldev = ISC_LIST_HEAD(sock->send_list);
+ while (ldev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+
+ printf("\n\t\tSock Accept List\n");
+ ndev = ISC_LIST_HEAD(sock->accept_list);
+ while (ndev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ndev = ISC_LIST_NEXT(ndev, ev_link);
+ }
+
+ printf("\n\t\tSock Connect List\n");
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ while (cdev != NULL) {
+ printf("\t\tdev: %p\n", cdev);
+ cdev = ISC_LIST_NEXT(cdev, ev_link);
+ }
+}
+
+static void
+socket_log(int lineno, isc_socket_t *sock, const isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ const char *fmt, ...) ISC_FORMAT_PRINTF(10, 11);
+
+/* This function will add an entry to the I/O completion port
+ * that will signal the I/O thread to exit (gracefully)
+ */
+static void
+signal_iocompletionport_exit(isc_socketmgr_t *manager) {
+ int i;
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_MANAGER(manager));
+ for (i = 0; i < manager->maxIOCPThreads; i++) {
+ if (!PostQueuedCompletionStatus(manager->hIoCompletionPort, 0,
+ 0, 0))
+ {
+ errval = GetLastError();
+ strerror_r(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ "Can't request service thread to exit: %s",
+ strbuf);
+ }
+ }
+}
+
+/*
+ * Create the worker threads for the I/O Completion Port
+ */
+void
+iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ int i;
+
+ INSIST(total_threads > 0);
+ REQUIRE(VALID_MANAGER(manager));
+ /*
+ * We need at least one
+ */
+ for (i = 0; i < total_threads; i++) {
+ isc_thread_create(SocketIoThread, manager,
+ &manager->hIOCPThreads[i]);
+ }
+}
+
+/*
+ * Create/initialise the I/O completion port
+ */
+void
+iocompletionport_init(isc_socketmgr_t *manager) {
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_MANAGER(manager));
+ /*
+ * Create a private heap to handle the socket overlapped structure
+ * The minimum number of structures is 10, there is no maximum
+ */
+ hHeapHandle = HeapCreate(0, 10 * sizeof(IoCompletionInfo), 0);
+ if (hHeapHandle == NULL) {
+ errval = GetLastError();
+ strerror_r(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ "HeapCreate() failed during initialization: %s",
+ strbuf);
+ }
+
+ /* Now Create the Completion Port */
+ manager->hIoCompletionPort = CreateIoCompletionPort(
+ INVALID_HANDLE_VALUE, NULL, 0, manager->maxIOCPThreads);
+ if (manager->hIoCompletionPort == NULL) {
+ errval = GetLastError();
+ strerror_r(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ "CreateIoCompletionPort() failed during "
+ "initialization: %s",
+ strbuf);
+ }
+
+ /*
+ * Worker threads for servicing the I/O
+ */
+ iocompletionport_createthreads(manager->maxIOCPThreads, manager);
+}
+
+/*
+ * Associate a socket with an IO Completion Port. This allows us to queue
+ * events for it and have our worker pool of threads process them.
+ */
+void
+iocompletionport_update(isc_socket_t *sock) {
+ HANDLE hiocp;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ hiocp = CreateIoCompletionPort((HANDLE)sock->fd,
+ sock->manager->hIoCompletionPort,
+ (ULONG_PTR)sock, 0);
+
+ if (hiocp == NULL) {
+ DWORD errval = GetLastError();
+ strerror_r(errval, strbuf, sizeof(strbuf));
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
+ ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
+ "iocompletionport_update: failed to open io "
+ "completion port: %s",
+ strbuf);
+
+ /* XXXMLG temporary hack to make failures detected.
+ * This function should return errors to the caller, not
+ * exit here.
+ */
+ FATAL_ERROR(__FILE__, __LINE__,
+ "CreateIoCompletionPort() failed during "
+ "initialization: %s",
+ strbuf);
+ }
+
+ InterlockedIncrement(&sock->manager->iocp_total);
+}
+
+/*
+ * Routine to cleanup and then close the socket.
+ * Only close the socket here if it is NOT associated
+ * with an event, otherwise the WSAWaitForMultipleEvents
+ * may fail due to the fact that the Wait should not
+ * be running while closing an event or a socket.
+ * The socket is locked before calling this function
+ */
+void
+socket_close(isc_socket_t *sock) {
+ REQUIRE(sock != NULL);
+
+ if (sock->fd != INVALID_SOCKET) {
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ InterlockedDecrement(&sock->manager->totalSockets);
+ }
+}
+
+static isc_once_t initialise_once = ISC_ONCE_INIT;
+static bool initialised = false;
+
+static void
+initialise(void) {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ SOCKET sock;
+ GUID GUIDConnectEx = WSAID_CONNECTEX;
+ GUID GUIDAcceptEx = WSAID_ACCEPTEX;
+ GUID GUIDGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
+ DWORD dwBytes;
+
+ /* Need Winsock 2.2 or better */
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ char strbuf[ISC_STRERRORSIZE];
+ strerror_r(err, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__, "WSAStartup() failed: %s",
+ strbuf);
+ }
+ /*
+ * The following APIs do not exist as functions in a library, but
+ * we must ask winsock for them. They are "extensions" -- but why
+ * they cannot be actual functions is beyond me. So, ask winsock
+ * for the pointers to the functions we need.
+ */
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ INSIST(sock != INVALID_SOCKET);
+ err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GUIDConnectEx,
+ sizeof(GUIDConnectEx), &ISCConnectEx,
+ sizeof(ISCConnectEx), &dwBytes, NULL, NULL);
+ INSIST(err == 0);
+
+ err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GUIDAcceptEx,
+ sizeof(GUIDAcceptEx), &ISCAcceptEx, sizeof(ISCAcceptEx),
+ &dwBytes, NULL, NULL);
+ INSIST(err == 0);
+
+ err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &GUIDGetAcceptExSockaddrs,
+ sizeof(GUIDGetAcceptExSockaddrs),
+ &ISCGetAcceptExSockaddrs,
+ sizeof(ISCGetAcceptExSockaddrs), &dwBytes, NULL, NULL);
+ INSIST(err == 0);
+
+ closesocket(sock);
+
+ initialised = true;
+}
+
+/*
+ * Initialize socket services
+ */
+void
+InitSockets(void) {
+ RUNTIME_CHECK(isc_once_do(&initialise_once, initialise) ==
+ ISC_R_SUCCESS);
+ if (!initialised) {
+ exit(1);
+ }
+}
+
+int
+internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
+ struct msghdr *messagehdr, int flags, int *Error) {
+ int Result;
+ DWORD BytesSent;
+ DWORD Flags = flags;
+ int total_sent;
+
+ *Error = 0;
+ Result = WSASendTo(sock->fd, messagehdr->msg_iov,
+ messagehdr->msg_iovlen, &BytesSent, Flags,
+ (SOCKADDR *)&messagehdr->to_addr,
+ messagehdr->to_addr_len, (LPWSAOVERLAPPED)lpo, NULL);
+
+ total_sent = (int)BytesSent;
+
+ /* Check for errors.*/
+ if (Result == SOCKET_ERROR) {
+ *Error = WSAGetLastError();
+
+ switch (*Error) {
+ case WSA_IO_INCOMPLETE:
+ case WSA_WAIT_IO_COMPLETION:
+ case WSA_IO_PENDING:
+ case NO_ERROR: /* Strange, but okay */
+ sock->pending_iocp++;
+ sock->pending_send++;
+ break;
+
+ default:
+ return (-1);
+ break;
+ }
+ } else {
+ sock->pending_iocp++;
+ sock->pending_send++;
+ }
+
+ if (lpo != NULL) {
+ return (0);
+ } else {
+ return (total_sent);
+ }
+}
+
+static void
+queue_receive_request(isc_socket_t *sock) {
+ DWORD Flags = 0;
+ DWORD NumBytes = 0;
+ int Result;
+ int Error;
+ int need_retry;
+ WSABUF iov[1];
+ IoCompletionInfo *lpo = NULL;
+ isc_result_t isc_result;
+
+retry:
+ need_retry = false;
+
+ /*
+ * If we already have a receive pending, do nothing.
+ */
+ if (sock->pending_recv > 0) {
+ if (lpo != NULL) {
+ HeapFree(hHeapHandle, 0, lpo);
+ }
+ return;
+ }
+
+ /*
+ * If no one is waiting, do nothing.
+ */
+ if (ISC_LIST_EMPTY(sock->recv_list)) {
+ if (lpo != NULL) {
+ HeapFree(hHeapHandle, 0, lpo);
+ }
+ return;
+ }
+
+ INSIST(sock->recvbuf.remaining == 0);
+ INSIST(sock->fd != INVALID_SOCKET);
+
+ iov[0].len = sock->recvbuf.len;
+ iov[0].buf = sock->recvbuf.base;
+
+ if (lpo == NULL) {
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ RUNTIME_CHECK(lpo != NULL);
+ } else {
+ ZeroMemory(lpo, sizeof(IoCompletionInfo));
+ }
+ lpo->request_type = SOCKET_RECV;
+
+ sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr);
+
+ Error = 0;
+ Result = WSARecvFrom((SOCKET)sock->fd, iov, 1, &NumBytes, &Flags,
+ (SOCKADDR *)&sock->recvbuf.from_addr,
+ &sock->recvbuf.from_addr_len, (LPWSAOVERLAPPED)lpo,
+ NULL);
+
+ /* Check for errors. */
+ if (Result == SOCKET_ERROR) {
+ Error = WSAGetLastError();
+
+ switch (Error) {
+ case WSA_IO_PENDING:
+ sock->pending_iocp++;
+ sock->pending_recv++;
+ break;
+
+ /* direct error: no completion event */
+ case ERROR_HOST_UNREACHABLE:
+ case WSAENETRESET:
+ case WSAECONNRESET:
+ if (!sock->connected) {
+ /* soft error */
+ need_retry = true;
+ break;
+ }
+ FALLTHROUGH;
+
+ default:
+ isc_result = isc__errno2result(Error);
+ if (isc_result == ISC_R_UNEXPECTED) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "WSARecvFrom: Windows error "
+ "code: %d, isc result %d",
+ Error, isc_result);
+ }
+ send_recvdone_abort(sock, isc_result);
+ HeapFree(hHeapHandle, 0, lpo);
+ lpo = NULL;
+ break;
+ }
+ } else {
+ /*
+ * The recv() finished immediately, but we will still get
+ * a completion event. Rather than duplicate code, let
+ * that thread handle sending the data along its way.
+ */
+ sock->pending_iocp++;
+ sock->pending_recv++;
+ }
+
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ "queue_io_request: fd %d result %d error %d", sock->fd,
+ Result, Error);
+
+ CONSISTENT(sock);
+
+ if (need_retry) {
+ goto retry;
+ }
+}
+
+static void
+manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *fmt, ...) {
+ char msgbuf[2048];
+ va_list ap;
+
+ if (!isc_log_wouldlog(isc_lctx, level)) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ isc_log_write(isc_lctx, category, module, level, "sockmgr %p: %s",
+ sockmgr, msgbuf);
+}
+
+static void
+socket_log(int lineno, isc_socket_t *sock, const isc_sockaddr_t *address,
+ isc_logcategory_t *category, isc_logmodule_t *module, int level,
+ const char *fmt, ...) {
+ char msgbuf[2048];
+ char peerbuf[256];
+ va_list ap;
+
+ if (!isc_log_wouldlog(isc_lctx, level)) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ va_end(ap);
+
+ if (address == NULL) {
+ isc_log_write(isc_lctx, category, module, level,
+ "socket %p line %d: %s", sock, lineno, msgbuf);
+ } else {
+ isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
+ isc_log_write(isc_lctx, category, module, level,
+ "socket %p line %d %s: %s", sock, lineno, peerbuf,
+ msgbuf);
+ }
+}
+
+/*
+ * Make an fd SOCKET non-blocking.
+ */
+static isc_result_t
+make_nonblock(SOCKET fd) {
+ int ret;
+ unsigned long flags = 1;
+ char strbuf[ISC_STRERRORSIZE];
+
+ /* Set the socket to non-blocking */
+ ret = ioctlsocket(fd, FIONBIO, &flags);
+
+ if (ret == -1) {
+ strerror_r(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "ioctlsocket(%d, FIOBIO, %d): %s", fd, flags,
+ strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Windows 2000 systems incorrectly cause UDP sockets using WSARecvFrom
+ * to not work correctly, returning a WSACONNRESET error when a WSASendTo
+ * fails with an "ICMP port unreachable" response and preventing the
+ * socket from using the WSARecvFrom in subsequent operations.
+ * The function below fixes this, but requires that Windows 2000
+ * Service Pack 2 or later be installed on the system. NT 4.0
+ * systems are not affected by this and work correctly.
+ * See Microsoft Knowledge Base Article Q263823 for details of this.
+ */
+isc_result_t
+connection_reset_fix(SOCKET fd) {
+ DWORD dwBytesReturned = 0;
+ BOOL bNewBehavior = FALSE;
+ DWORD status;
+
+ if (isc_win32os_versioncheck(5, 0, 0, 0) < 0) {
+ return (ISC_R_SUCCESS); /* NT 4.0 has no problem */
+ }
+ /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */
+ status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
+ sizeof(bNewBehavior), NULL, 0, &dwBytesReturned, NULL,
+ NULL);
+ if (status != SOCKET_ERROR) {
+ return (ISC_R_SUCCESS);
+ } else {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "WSAIoctl(SIO_UDP_CONNRESET, oldBehaviour) "
+ "failed");
+ return (ISC_R_UNEXPECTED);
+ }
+}
+
+/*
+ * Construct an iov array and attach it to the msghdr passed in. This is
+ * the SEND constructor, which will use the used region of the buffer
+ * (if using a buffer list) or will use the internal region (if a single
+ * buffer I/O is requested).
+ *
+ * Nothing can be NULL, and the done event must list at least one buffer
+ * on the buffer linked list for this function to be meaningful.
+ */
+static void
+build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *msg, char *cmsg, WSABUF *iov,
+ IoCompletionInfo *lpo) {
+ unsigned int iovcount;
+ size_t write_count;
+
+ memset(msg, 0, sizeof(*msg));
+
+ memmove(&msg->to_addr, &dev->address.type, dev->address.length);
+ msg->to_addr_len = dev->address.length;
+
+ write_count = 0;
+ iovcount = 0;
+
+ /*
+ * Single buffer I/O? Skip what we've done so far in this region.
+ */
+ write_count = dev->region.length - dev->n;
+ lpo->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, write_count);
+ RUNTIME_CHECK(lpo->buf != NULL);
+
+ socket_log(__LINE__, sock, NULL, TRACE, "alloc_buffer %p %d", lpo->buf,
+ write_count);
+
+ memmove(lpo->buf, (dev->region.base + dev->n), write_count);
+ lpo->buflen = (unsigned int)write_count;
+ iov[0].buf = lpo->buf;
+ iov[0].len = (u_long)write_count;
+ iovcount = 1;
+
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iovcount;
+ msg->msg_totallen = (u_int)write_count;
+}
+
+static void
+set_dev_address(const isc_sockaddr_t *address, isc_socket_t *sock,
+ isc_socketevent_t *dev) {
+ if (sock->type == isc_sockettype_udp) {
+ if (address != NULL) {
+ dev->address = *address;
+ } else {
+ dev->address = sock->address;
+ }
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(address == NULL);
+ dev->address = sock->address;
+ }
+}
+
+static void
+destroy_socketevent(isc_event_t *event) {
+ isc_socketevent_t *ev = (isc_socketevent_t *)event;
+
+ (ev->destroy)(event);
+}
+
+static isc_socketevent_t *
+allocate_socketevent(isc_mem_t *mctx, isc_socket_t *sock,
+ isc_eventtype_t eventtype, isc_taskaction_t action,
+ void *arg) {
+ isc_socketevent_t *ev;
+
+ ev = (isc_socketevent_t *)isc_event_allocate(mctx, sock, eventtype,
+ action, arg, sizeof(*ev));
+
+ ev->result = ISC_R_IOERROR; /* XXXMLG temporary change to detect failure
+ */
+ /* to set */
+ ISC_LINK_INIT(ev, ev_link);
+ ev->region.base = NULL;
+ ev->n = 0;
+ ev->offset = 0;
+ ev->attributes = 0;
+ ev->destroy = ev->ev_destroy;
+ ev->ev_destroy = destroy_socketevent;
+ ev->dscp = 0;
+
+ return (ev);
+}
+
+#if defined(ISC_SOCKET_DEBUG)
+static void
+dump_msg(struct msghdr *msg, isc_socket_t *sock) {
+ unsigned int i;
+
+ printf("MSGHDR %p, Socket #: %Iu\n", msg, sock->fd);
+ printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
+ printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
+ for (i = 0; i < (unsigned int)msg->msg_iovlen; i++) {
+ printf("\t\t%u\tbase %p, len %u\n", i, msg->msg_iov[i].buf,
+ msg->msg_iov[i].len);
+ }
+}
+#endif /* if defined(ISC_SOCKET_DEBUG) */
+
+/*
+ * map the error code
+ */
+int
+map_socket_error(isc_socket_t *sock, int windows_errno, int *isc_errno,
+ char *errorstring, size_t bufsize) {
+ int doreturn;
+ switch (windows_errno) {
+ case WSAECONNREFUSED:
+ *isc_errno = ISC_R_CONNREFUSED;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case WSAENETUNREACH:
+ case ERROR_NETWORK_UNREACHABLE:
+ *isc_errno = ISC_R_NETUNREACH;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case ERROR_PORT_UNREACHABLE:
+ case ERROR_HOST_UNREACHABLE:
+ case WSAEHOSTUNREACH:
+ *isc_errno = ISC_R_HOSTUNREACH;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case WSAENETDOWN:
+ *isc_errno = ISC_R_NETDOWN;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case WSAEHOSTDOWN:
+ *isc_errno = ISC_R_HOSTDOWN;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case WSAEACCES:
+ *isc_errno = ISC_R_NOPERM;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case WSAECONNRESET:
+ case WSAENETRESET:
+ case WSAECONNABORTED:
+ case WSAEDISCON:
+ *isc_errno = ISC_R_CONNECTIONRESET;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case WSAENOTCONN:
+ *isc_errno = ISC_R_NOTCONNECTED;
+ if (sock->connected) {
+ doreturn = DOIO_HARD;
+ } else {
+ doreturn = DOIO_SOFT;
+ }
+ break;
+ case ERROR_OPERATION_ABORTED:
+ case ERROR_CONNECTION_ABORTED:
+ case ERROR_REQUEST_ABORTED:
+ *isc_errno = ISC_R_CONNECTIONRESET;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAENOBUFS:
+ *isc_errno = ISC_R_NORESOURCES;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAEAFNOSUPPORT:
+ *isc_errno = ISC_R_FAMILYNOSUPPORT;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAEADDRNOTAVAIL:
+ *isc_errno = ISC_R_ADDRNOTAVAIL;
+ doreturn = DOIO_HARD;
+ break;
+ case WSAEDESTADDRREQ:
+ *isc_errno = ISC_R_BADADDRESSFORM;
+ doreturn = DOIO_HARD;
+ break;
+ case ERROR_NETNAME_DELETED:
+ *isc_errno = ISC_R_NETDOWN;
+ doreturn = DOIO_HARD;
+ break;
+ default:
+ *isc_errno = ISC_R_IOERROR;
+ doreturn = DOIO_HARD;
+ break;
+ }
+ if (doreturn == DOIO_HARD) {
+ strerror_r(windows_errno, errorstring, bufsize);
+ }
+ return (doreturn);
+}
+
+static void
+fill_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
+ int copylen;
+
+ INSIST(dev->n < dev->minimum);
+ INSIST(sock->recvbuf.remaining > 0);
+ INSIST(sock->pending_recv == 0);
+
+ if (sock->type == isc_sockettype_udp) {
+ dev->address.length = sock->recvbuf.from_addr_len;
+ memmove(&dev->address.type, &sock->recvbuf.from_addr,
+ sock->recvbuf.from_addr_len);
+ if (isc_sockaddr_getport(&dev->address) == 0) {
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ socket_log(__LINE__, sock, &dev->address,
+ IOEVENT,
+ "dropping source port zero packet");
+ }
+ sock->recvbuf.remaining = 0;
+ return;
+ }
+ /*
+ * Simulate a firewall blocking UDP responses bigger than
+ * 'maxudp' bytes.
+ */
+ if (sock->manager->maxudp != 0 &&
+ sock->recvbuf.remaining > sock->manager->maxudp)
+ {
+ sock->recvbuf.remaining = 0;
+ return;
+ }
+ } else if (sock->type == isc_sockettype_tcp) {
+ dev->address = sock->address;
+ }
+
+ copylen = min(dev->region.length - dev->n, sock->recvbuf.remaining);
+ memmove(dev->region.base + dev->n, sock->recvbuf.consume_position,
+ copylen);
+ sock->recvbuf.consume_position += copylen;
+ sock->recvbuf.remaining -= copylen;
+ dev->n += copylen;
+
+ /*
+ * UDP receives are all-consuming. That is, if we have 4k worth of
+ * data in our receive buffer, and the caller only gave us
+ * 1k of space, we will toss the remaining 3k of data. TCP
+ * will keep the extra data around and use it for later requests.
+ */
+ if (sock->type == isc_sockettype_udp) {
+ sock->recvbuf.remaining = 0;
+ }
+}
+
+/*
+ * Copy out as much data from the internal buffer to done events.
+ * As each done event is filled, send it along its way.
+ */
+static void
+completeio_recv(isc_socket_t *sock) {
+ isc_socketevent_t *dev;
+
+ /*
+ * If we are in the process of filling our buffer, we cannot
+ * touch it yet, so don't.
+ */
+ if (sock->pending_recv > 0) {
+ return;
+ }
+
+ while (sock->recvbuf.remaining > 0 && !ISC_LIST_EMPTY(sock->recv_list))
+ {
+ dev = ISC_LIST_HEAD(sock->recv_list);
+
+ /*
+ * See if we have sufficient data in our receive buffer
+ * to handle this. If we do, copy out the data.
+ */
+ fill_recv(sock, dev);
+
+ /*
+ * Did we satisfy it?
+ */
+ if (dev->n >= dev->minimum) {
+ dev->result = ISC_R_SUCCESS;
+ send_recvdone_event(sock, &dev);
+ }
+ }
+}
+
+/*
+ * Returns:
+ * DOIO_SUCCESS The operation succeeded. dev->result contains
+ * ISC_R_SUCCESS.
+ *
+ * DOIO_HARD A hard or unexpected I/O error was encountered.
+ * dev->result contains the appropriate error.
+ *
+ * DOIO_SOFT A soft I/O error was encountered. No senddone
+ * event was sent. The operation should be retried.
+ *
+ * No other return values are possible.
+ */
+static int
+completeio_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *messagehdr, int cc, int send_errno) {
+ char strbuf[ISC_STRERRORSIZE];
+
+ if (send_errno != 0) {
+ if (SOFT_ERROR(send_errno)) {
+ return (DOIO_SOFT);
+ }
+
+ return (map_socket_error(sock, send_errno, &dev->result, strbuf,
+ sizeof(strbuf)));
+ }
+
+ /*
+ * If we write less than we expected, update counters, poke.
+ */
+ dev->n += cc;
+ if (cc != messagehdr->msg_totallen) {
+ return (DOIO_SOFT);
+ }
+
+ /*
+ * Exactly what we wanted to write. We're done with this
+ * entry. Post its completion event.
+ */
+ dev->result = ISC_R_SUCCESS;
+ return (DOIO_SUCCESS);
+}
+
+static int
+startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
+ int *send_errno) {
+ char *cmsg = NULL;
+ char strbuf[ISC_STRERRORSIZE];
+ IoCompletionInfo *lpo;
+ int status;
+ struct msghdr *mh;
+
+ /*
+ * Simulate a firewall blocking UDP responses bigger than
+ * 'maxudp' bytes.
+ */
+ if (sock->type == isc_sockettype_udp && sock->manager->maxudp != 0 &&
+ dev->region.length - dev->n > sock->manager->maxudp)
+ {
+ *nbytes = dev->region.length - dev->n;
+ return (DOIO_SUCCESS);
+ }
+
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ RUNTIME_CHECK(lpo != NULL);
+ lpo->request_type = SOCKET_SEND;
+ lpo->dev = dev;
+ mh = &lpo->messagehdr;
+ memset(mh, 0, sizeof(struct msghdr));
+
+ build_msghdr_send(sock, dev, mh, cmsg, sock->iov, lpo);
+
+ *nbytes = internal_sendmsg(sock, lpo, mh, 0, send_errno);
+
+ if (*nbytes <= 0) {
+ /*
+ * I/O has been initiated
+ * completion will be through the completion port
+ */
+ if (PENDING_ERROR(*send_errno)) {
+ status = DOIO_PENDING;
+ goto done;
+ }
+
+ if (SOFT_ERROR(*send_errno)) {
+ status = DOIO_SOFT;
+ goto done;
+ }
+
+ /*
+ * If we got this far then something is wrong
+ */
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ strerror_r(*send_errno, strbuf, sizeof(strbuf));
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ "startio_send: internal_sendmsg(%d) %d "
+ "bytes, err %d/%s",
+ sock->fd, *nbytes, *send_errno, strbuf);
+ }
+ status = DOIO_HARD;
+ goto done;
+ }
+ dev->result = ISC_R_SUCCESS;
+ status = DOIO_SOFT;
+done:
+ _set_state(sock, SOCK_DATA);
+ return (status);
+}
+
+static void
+use_min_mtu(isc_socket_t *sock) {
+#ifdef IPV6_USE_MIN_MTU
+ /* use minimum MTU */
+ if (sock->pf == AF_INET6) {
+ int on = 1;
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+ (void *)&on, sizeof(on));
+ }
+#else /* ifdef IPV6_USE_MIN_MTU */
+ UNUSED(sock);
+#endif /* ifdef IPV6_USE_MIN_MTU */
+}
+
+static isc_result_t
+allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
+ isc_socket_t **socketp) {
+ isc_socket_t *sock;
+
+ sock = isc_mem_get(manager->mctx, sizeof(*sock));
+
+ sock->magic = 0;
+ isc_refcount_init(&sock->references, 0);
+
+ sock->manager = manager;
+ sock->type = type;
+ sock->fd = INVALID_SOCKET;
+
+ ISC_LINK_INIT(sock, link);
+
+ /*
+ * Set up list of readers and writers to be initially empty.
+ */
+ ISC_LIST_INIT(sock->recv_list);
+ ISC_LIST_INIT(sock->send_list);
+ ISC_LIST_INIT(sock->accept_list);
+ ISC_LIST_INIT(sock->connect_list);
+ sock->pending_accept = 0;
+ sock->pending_recv = 0;
+ sock->pending_send = 0;
+ sock->pending_iocp = 0;
+ sock->listener = 0;
+ sock->connected = 0;
+ sock->pending_connect = 0;
+ sock->bound = 0;
+ sock->dupped = 0;
+ memset(sock->name, 0, sizeof(sock->name)); /* zero the name field */
+ _set_state(sock, SOCK_INITIALIZED);
+
+ sock->recvbuf.len = 65536;
+ sock->recvbuf.consume_position = sock->recvbuf.base;
+ sock->recvbuf.remaining = 0;
+ sock->recvbuf.base = isc_mem_get(manager->mctx,
+ sock->recvbuf.len); /* max buffer */
+ /* size */
+
+ /*
+ * Initialize the lock.
+ */
+ isc_mutex_init(&sock->lock);
+
+ socket_log(__LINE__, sock, NULL, EVENT, "allocated");
+
+ sock->magic = SOCKET_MAGIC;
+ *socketp = sock;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Verify that the socket state is consistent.
+ */
+static void
+consistent(isc_socket_t *sock) {
+ isc_socketevent_t *dev;
+ isc_socket_newconnev_t *nev;
+ unsigned int count;
+ char *crash_reason;
+ bool crash = false;
+
+ REQUIRE(sock->pending_iocp == sock->pending_recv + sock->pending_send +
+ sock->pending_accept +
+ sock->pending_connect);
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+ count = 0;
+ while (dev != NULL) {
+ count++;
+ dev = ISC_LIST_NEXT(dev, ev_link);
+ }
+ if (count > sock->pending_send) {
+ crash = true;
+ crash_reason = "send_list > sock->pending_send";
+ }
+
+ nev = ISC_LIST_HEAD(sock->accept_list);
+ count = 0;
+ while (nev != NULL) {
+ count++;
+ nev = ISC_LIST_NEXT(nev, ev_link);
+ }
+ if (count > sock->pending_accept) {
+ crash = true;
+ crash_reason = "accept_list > sock->pending_accept";
+ }
+
+ if (crash) {
+ socket_log(__LINE__, sock, NULL, CREATION,
+ "SOCKET INCONSISTENT: %s", crash_reason);
+ sock_dump(sock);
+ INSIST(!crash);
+ }
+}
+
+/*
+ * Maybe free the socket.
+ *
+ * This function will verify that the socket is no longer in use in any way,
+ * either internally or externally. This is the only place where this
+ * check is to be made; if some bit of code believes that IT is done with
+ * the socket (e.g., some reference counter reaches zero), it should call
+ * this function.
+ *
+ * When calling this function, the socket must be locked, and the manager
+ * must be unlocked.
+ *
+ * When this function returns, *socketp will be NULL. No tricks to try
+ * to hold on to this pointer are allowed.
+ */
+static void
+maybe_free_socket(isc_socket_t **socketp, int lineno) {
+ isc_socket_t *sock = *socketp;
+ *socketp = NULL;
+
+ INSIST(VALID_SOCKET(sock));
+ CONSISTENT(sock);
+
+ if (sock->pending_iocp > 0 || sock->pending_recv > 0 ||
+ sock->pending_send > 0 || sock->pending_accept > 0 ||
+ isc_refcount_current(&sock->references) > 0 ||
+ sock->pending_connect == 1 || !ISC_LIST_EMPTY(sock->recv_list) ||
+ !ISC_LIST_EMPTY(sock->send_list) ||
+ !ISC_LIST_EMPTY(sock->accept_list) ||
+ !ISC_LIST_EMPTY(sock->connect_list) || sock->fd != INVALID_SOCKET)
+ {
+ UNLOCK(&sock->lock);
+ return;
+ }
+ UNLOCK(&sock->lock);
+
+ free_socket(&sock, lineno);
+}
+
+void
+free_socket(isc_socket_t **sockp, int lineno) {
+ isc_socketmgr_t *manager;
+ isc_socket_t *sock = *sockp;
+ *sockp = NULL;
+
+ /*
+ * Seems we can free the socket after all.
+ */
+ manager = sock->manager;
+ socket_log(__LINE__, sock, NULL, CREATION,
+ "freeing socket line %d fd %d lock %p semaphore %p", lineno,
+ sock->fd, &sock->lock, sock->lock.LockSemaphore);
+
+ sock->magic = 0;
+ isc_mutex_destroy(&sock->lock);
+
+ if (sock->recvbuf.base != NULL) {
+ isc_mem_put(manager->mctx, sock->recvbuf.base,
+ sock->recvbuf.len);
+ }
+
+ LOCK(&manager->lock);
+ if (ISC_LINK_LINKED(sock, link)) {
+ ISC_LIST_UNLINK(manager->socklist, sock, link);
+ }
+ isc_mem_put(manager->mctx, sock, sizeof(*sock));
+
+ if (ISC_LIST_EMPTY(manager->socklist)) {
+ SIGNAL(&manager->shutdown_ok);
+ }
+ UNLOCK(&manager->lock);
+}
+
+/*
+ * Create a new 'type' socket managed by 'manager'. Events
+ * will be posted to 'task' and when dispatched 'action' will be
+ * called with 'arg' as the arg value. The new socket is returned
+ * in 'socketp'.
+ */
+static isc_result_t
+socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp, isc_socket_t *dup_socket) {
+ isc_socket_t *sock = NULL;
+ isc_result_t result;
+#if defined(USE_CMSG)
+ int on = 1;
+#endif /* if defined(USE_CMSG) */
+#if defined(SO_RCVBUF)
+ socklen_t optlen;
+ int size;
+#endif /* if defined(SO_RCVBUF) */
+ int socket_errno;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+#ifndef SOCK_RAW
+ if (type == isc_sockettype_raw) {
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+#endif /* ifndef SOCK_RAW */
+
+ result = allocate_socket(manager, type, &sock);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ sock->pf = pf;
+ switch (type) {
+ case isc_sockettype_udp:
+ sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock->fd != INVALID_SOCKET) {
+ result = connection_reset_fix(sock->fd);
+ if (result != ISC_R_SUCCESS) {
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "closed %d %d %" PRIuFAST32 " "
+ "con_reset_fix_failed",
+ sock->pending_recv,
+ sock->pending_send,
+ isc_refcount_current(
+ &sock->references));
+ closesocket(sock->fd);
+ _set_state(sock, SOCK_CLOSED);
+ sock->fd = INVALID_SOCKET;
+ free_socket(&sock, __LINE__);
+ return (result);
+ }
+ }
+ break;
+ case isc_sockettype_tcp:
+ sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
+ break;
+#ifdef SOCK_RAW
+ case isc_sockettype_raw:
+ sock->fd = socket(pf, SOCK_RAW, 0);
+#ifdef PF_ROUTE
+ if (pf == PF_ROUTE) {
+ sock->bound = 1;
+ }
+#endif /* ifdef PF_ROUTE */
+ break;
+#endif /* ifdef SOCK_RAW */
+ }
+
+ if (sock->fd == INVALID_SOCKET) {
+ socket_errno = WSAGetLastError();
+ free_socket(&sock, __LINE__);
+
+ switch (socket_errno) {
+ case WSAEMFILE:
+ case WSAENOBUFS:
+ return (ISC_R_NORESOURCES);
+
+ case WSAEPROTONOSUPPORT:
+ case WSAEPFNOSUPPORT:
+ case WSAEAFNOSUPPORT:
+ return (ISC_R_FAMILYNOSUPPORT);
+
+ default:
+ strerror_r(socket_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() failed: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ result = make_nonblock(sock->fd);
+ if (result != ISC_R_SUCCESS) {
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "closed %d %d %" PRIuFAST32 " make_nonblock_failed",
+ sock->pending_recv, sock->pending_send,
+ isc_refcount_current(&sock->references));
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ free_socket(&sock, __LINE__);
+ return (result);
+ }
+
+ /*
+ * Use minimum mtu if possible.
+ */
+ use_min_mtu(sock);
+
+#if defined(USE_CMSG) || defined(SO_RCVBUF)
+ if (type == isc_sockettype_udp) {
+#if defined(USE_CMSG)
+#ifdef IPV6_RECVPKTINFO
+ /* 2292bis */
+ if ((pf == AF_INET6) &&
+ (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (char *)&on, sizeof(on)) < 0))
+ {
+ strerror_r(WSAGetLastError(), strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_RECVPKTINFO) "
+ "failed: %s",
+ sock->fd, strbuf);
+ }
+#else /* ifdef IPV6_RECVPKTINFO */
+ /* 2292 */
+ if ((pf == AF_INET6) &&
+ (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (char *)&on, sizeof(on)) < 0))
+ {
+ strerror_r(WSAGetLastError(), strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, IPV6_PKTINFO) %s: %s",
+ sock->fd, strbuf);
+ }
+#endif /* IPV6_RECVPKTINFO */
+#endif /* defined(USE_CMSG) */
+
+#if defined(SO_RCVBUF)
+ optlen = sizeof(size);
+ if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, (char *)&size,
+ &optlen) >= 0 &&
+ size < RCVBUFSIZE)
+ {
+ size = RCVBUFSIZE;
+ (void)setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&size, sizeof(size));
+ }
+#endif /* if defined(SO_RCVBUF) */
+ }
+#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
+
+ _set_state(sock, SOCK_OPEN);
+ isc_refcount_init(&sock->references, 1);
+ *socketp = sock;
+
+ iocompletionport_update(sock);
+
+ if (dup_socket) {
+#ifndef ISC_ALLOW_MAPPED
+ isc_socket_ipv6only(sock, true);
+#endif /* ifndef ISC_ALLOW_MAPPED */
+
+ if (dup_socket->bound) {
+ isc_sockaddr_t local;
+
+ result = isc_socket_getsockname(dup_socket, &local);
+ if (result != ISC_R_SUCCESS) {
+ isc_socket_close(sock);
+ return (result);
+ }
+ result = isc_socket_bind(sock, &local,
+ ISC_SOCKET_REUSEADDRESS);
+ if (result != ISC_R_SUCCESS) {
+ isc_socket_close(sock);
+ return (result);
+ }
+ }
+ sock->dupped = 1;
+ }
+
+ /*
+ * Note we don't have to lock the socket like we normally would because
+ * there are no external references to it yet.
+ */
+ LOCK(&manager->lock);
+ ISC_LIST_APPEND(manager->socklist, sock, link);
+ InterlockedIncrement(&manager->totalSockets);
+ UNLOCK(&manager->lock);
+
+ socket_log(__LINE__, sock, NULL, CREATION, "created %u type %u",
+ sock->fd, type);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
+ isc_socket_t **socketp) {
+ return (socket_create(manager, pf, type, socketp, NULL));
+}
+
+isc_result_t
+isc_socket_dup(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ return (socket_create(sock->manager, sock->pf, sock->type, socketp,
+ sock));
+}
+
+isc_result_t
+isc_socket_open(isc_socket_t *sock) {
+ REQUIRE(VALID_SOCKET(sock));
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Attach to a socket. Caller must explicitly detach when it is done.
+ */
+void
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+
+ isc_refcount_increment0(&sock->references);
+
+ *socketp = sock;
+}
+
+/*
+ * Dereference a socket. If this is the last reference to it, clean things
+ * up by destroying the socket.
+ */
+void
+isc_socket_detach(isc_socket_t **socketp) {
+ isc_socket_t *sock;
+ uint32_t references;
+
+ REQUIRE(socketp != NULL);
+ sock = *socketp;
+ *socketp = NULL;
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ references = isc_refcount_decrement(&sock->references);
+
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "detach_socket %d %d %" PRIuFAST32, sock->pending_recv,
+ sock->pending_send, isc_refcount_current(&sock->references));
+
+ if (references == 1 && sock->fd != INVALID_SOCKET) {
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ }
+
+ maybe_free_socket(&sock, __LINE__); /* Also unlocks the socket lock */
+}
+
+isc_result_t
+isc_socket_close(isc_socket_t *sock) {
+ REQUIRE(VALID_SOCKET(sock));
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Dequeue an item off the given socket's read queue, set the result code
+ * in the done event to the one provided, and send it to the task it was
+ * destined for.
+ *
+ * If the event to be sent is on a list, remove it before sending. If
+ * asked to, send and detach from the task as well.
+ *
+ * Caller must have the socket locked if the event is attached to the socket.
+ */
+static void
+send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link)) {
+ ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+ }
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED) != 0) {
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ } else {
+ isc_task_send(task, (isc_event_t **)dev);
+ }
+
+ CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
+ isc_task_t *task;
+
+ INSIST(dev != NULL && *dev != NULL);
+
+ task = (*dev)->ev_sender;
+ (*dev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*dev, ev_link)) {
+ ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+ }
+
+ if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED) != 0) {
+ isc_task_sendanddetach(&task, (isc_event_t **)dev);
+ } else {
+ isc_task_send(task, (isc_event_t **)dev);
+ }
+
+ CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev) {
+ isc_task_t *task;
+
+ INSIST(adev != NULL && *adev != NULL);
+
+ task = (*adev)->ev_sender;
+ (*adev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*adev, ev_link)) {
+ ISC_LIST_DEQUEUE(sock->accept_list, *adev, ev_link);
+ }
+
+ isc_task_sendanddetach(&task, (isc_event_t **)adev);
+
+ CONSISTENT(sock);
+}
+
+/*
+ * See comments for send_recvdone_event() above.
+ */
+static void
+send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) {
+ isc_task_t *task;
+
+ INSIST(cdev != NULL && *cdev != NULL);
+
+ task = (*cdev)->ev_sender;
+ (*cdev)->ev_sender = sock;
+
+ if (ISC_LINK_LINKED(*cdev, ev_link)) {
+ ISC_LIST_DEQUEUE(sock->connect_list, *cdev, ev_link);
+ }
+
+ isc_task_sendanddetach(&task, (isc_event_t **)cdev);
+
+ CONSISTENT(sock);
+}
+
+/*
+ * On entry to this function, the event delivered is the internal
+ * readable event, and the first item on the accept_list should be
+ * the done event we want to send. If the list is empty, this is a no-op,
+ * so just close the new connection, unlock, and return.
+ *
+ * Note the socket is locked before entering here
+ */
+static void
+internal_accept(isc_socket_t *sock, IoCompletionInfo *lpo, int accept_errno) {
+ isc_socket_newconnev_t *adev;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_socket_t *nsock;
+ struct sockaddr *localaddr;
+ int localaddr_len = sizeof(*localaddr);
+ struct sockaddr *remoteaddr;
+ int remoteaddr_len = sizeof(*remoteaddr);
+
+ INSIST(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ socket_log(__LINE__, sock, NULL, TRACE, "internal_accept called");
+
+ INSIST(sock->listener);
+
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_accept > 0);
+ sock->pending_accept--;
+
+ adev = lpo->adev;
+
+ /*
+ * If the event is no longer in the list we can just return.
+ */
+ if (!acceptdone_is_active(sock, adev)) {
+ goto done;
+ }
+
+ nsock = adev->newsocket;
+
+ /*
+ * Pull off the done event.
+ */
+ ISC_LIST_UNLINK(sock->accept_list, adev, ev_link);
+
+ /*
+ * Extract the addresses from the socket, copy them into the structure,
+ * and return the new socket.
+ */
+ ISCGetAcceptExSockaddrs(
+ lpo->acceptbuffer, 0, sizeof(SOCKADDR_STORAGE) + 16,
+ sizeof(SOCKADDR_STORAGE) + 16, (LPSOCKADDR *)&localaddr,
+ &localaddr_len, (LPSOCKADDR *)&remoteaddr, &remoteaddr_len);
+ memmove(&adev->address.type, remoteaddr, remoteaddr_len);
+ adev->address.length = remoteaddr_len;
+ nsock->address = adev->address;
+ nsock->pf = adev->address.type.sa.sa_family;
+
+ socket_log(__LINE__, nsock, &nsock->address, TRACE,
+ "internal_accept parent %p", sock);
+
+ result = make_nonblock(adev->newsocket->fd);
+ INSIST(result == ISC_R_SUCCESS);
+
+ /*
+ * Use minimum mtu if possible.
+ */
+ use_min_mtu(adev->newsocket);
+
+ INSIST(setsockopt(nsock->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&sock->fd, sizeof(sock->fd)) == 0);
+
+ /*
+ * Hook it up into the manager.
+ */
+ nsock->bound = 1;
+ nsock->connected = 1;
+ _set_state(nsock, SOCK_OPEN);
+
+ LOCK(&nsock->manager->lock);
+ ISC_LIST_APPEND(nsock->manager->socklist, nsock, link);
+ InterlockedIncrement(&nsock->manager->totalSockets);
+ UNLOCK(&nsock->manager->lock);
+
+ socket_log(__LINE__, sock, &nsock->address, CREATION,
+ "accepted_connection new_socket %p fd %d", nsock, nsock->fd);
+
+ adev->result = result;
+ send_acceptdone_event(sock, &adev);
+
+done:
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+
+ HeapFree(hHeapHandle, 0, lpo->acceptbuffer);
+ lpo->acceptbuffer = NULL;
+}
+
+/*
+ * Called when a socket with a pending connect() finishes.
+ * Note that the socket is locked before entering.
+ */
+static void
+internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) {
+ isc_socket_connev_t *cdev;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_connect == 1);
+ sock->pending_connect = 0;
+
+ /*
+ * If the event is no longer in the list we can just close and return.
+ */
+ cdev = lpo->cdev;
+ if (!connectdone_is_active(sock, cdev)) {
+ sock->pending_connect = 0;
+ if (sock->fd != INVALID_SOCKET) {
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ }
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * Check possible Windows network event error status here.
+ */
+ if (connect_errno != 0) {
+ /*
+ * If the error is SOFT, just try again on this
+ * fd and pretend nothing strange happened.
+ */
+ if (SOFT_ERROR(connect_errno) ||
+ connect_errno == WSAEINPROGRESS)
+ {
+ sock->pending_connect = 1;
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * Translate other errors into ISC_R_* flavors.
+ */
+ switch (connect_errno) {
+#define ERROR_MATCH(a, b) \
+ case a: \
+ result = b; \
+ break;
+ ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);
+ ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
+ ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED);
+ ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
+ ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTDOWN);
+ ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH);
+ ERROR_MATCH(WSAENETDOWN, ISC_R_NETDOWN);
+ ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);
+ ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
+ ERROR_MATCH(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
+ ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
+#undef ERROR_MATCH
+ default:
+ result = ISC_R_UNEXPECTED;
+ strerror_r(connect_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "internal_connect: connect() %s",
+ strbuf);
+ }
+ } else {
+ INSIST(setsockopt(sock->fd, SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0);
+ result = ISC_R_SUCCESS;
+ sock->connected = 1;
+ socket_log(__LINE__, sock, &sock->address, IOEVENT,
+ "internal_connect: success");
+ }
+
+ do {
+ cdev->result = result;
+ send_connectdone_event(sock, &cdev);
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ } while (cdev != NULL);
+
+ UNLOCK(&sock->lock);
+}
+
+/*
+ * Loop through the socket, returning ISC_R_EOF for each done event pending.
+ */
+static void
+send_recvdone_abort(isc_socket_t *sock, isc_result_t result) {
+ isc_socketevent_t *dev;
+
+ while (!ISC_LIST_EMPTY(sock->recv_list)) {
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ dev->result = result;
+ send_recvdone_event(sock, &dev);
+ }
+}
+
+/*
+ * Loop through the socket, returning result for each done event pending.
+ */
+static void
+send_connectdone_abort(isc_socket_t *sock, isc_result_t result) {
+ isc_socket_connev_t *dev;
+
+ while (!ISC_LIST_EMPTY(sock->connect_list)) {
+ dev = ISC_LIST_HEAD(sock->connect_list);
+ dev->result = result;
+ send_connectdone_event(sock, &dev);
+ }
+}
+
+/*
+ * Take the data we received in our private buffer, and if any recv() calls on
+ * our list are satisfied, send the corresponding done event.
+ *
+ * If we need more data (there are still items on the recv_list after we consume
+ * all our data) then arrange for another system recv() call to fill our
+ * buffers.
+ */
+static void
+internal_recv(isc_socket_t *sock, int nbytes) {
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ "internal_recv: %d bytes received", nbytes);
+
+ /*
+ * If we got here, the I/O operation succeeded. However, we might
+ * still have removed this event from our notification list (or never
+ * placed it on it due to immediate completion.)
+ * Handle the reference counting here, and handle the cancellation
+ * event just after.
+ */
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_recv > 0);
+ sock->pending_recv--;
+
+ /*
+ * The only way we could have gotten here is that our I/O has
+ * successfully completed. Update our pointers, and move on.
+ * The only odd case here is that we might not have received
+ * enough data on a TCP stream to satisfy the minimum requirements.
+ * If this is the case, we will re-issue the recv() call for what
+ * we need.
+ *
+ * We do check for a recv() of 0 bytes on a TCP stream. This
+ * means the remote end has closed.
+ */
+ if (nbytes == 0 && sock->type == isc_sockettype_tcp) {
+ send_recvdone_abort(sock, ISC_R_EOF);
+ maybe_free_socket(&sock, __LINE__);
+ return;
+ }
+ sock->recvbuf.remaining = nbytes;
+ sock->recvbuf.consume_position = sock->recvbuf.base;
+ completeio_recv(sock);
+
+ /*
+ * If there are more receivers waiting for data, queue another receive
+ * here.
+ */
+ queue_receive_request(sock);
+
+ /*
+ * Unlock and/or destroy if we are the last thing this socket has left
+ * to do.
+ */
+ maybe_free_socket(&sock, __LINE__);
+}
+
+static void
+internal_send(isc_socket_t *sock, isc_socketevent_t *dev,
+ struct msghdr *messagehdr, int nbytes, int send_errno,
+ IoCompletionInfo *lpo) {
+ /*
+ * Find out what socket this is and lock it.
+ */
+ INSIST(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ socket_log(__LINE__, sock, NULL, IOEVENT,
+ "internal_send: task got socket event %p", dev);
+
+ if (lpo->buf != NULL) {
+ socket_log(__LINE__, sock, NULL, TRACE, "free_buffer %p",
+ lpo->buf);
+
+ HeapFree(hHeapHandle, 0, lpo->buf);
+ lpo->buf = NULL;
+ lpo->buflen = 0;
+ }
+
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_send > 0);
+ sock->pending_send--;
+
+ /* If the event is no longer in the list we can just return */
+ if (!senddone_is_active(sock, dev)) {
+ goto done;
+ }
+
+ /*
+ * Set the error code and send things on its way.
+ */
+ switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) {
+ case DOIO_SOFT:
+ break;
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ send_senddone_event(sock, &dev);
+ break;
+ }
+
+done:
+ maybe_free_socket(&sock, __LINE__);
+}
+
+/*
+ * These return if the done event passed in is on the list.
+ * Using these ensures we will not double-send an event.
+ */
+static bool
+senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev) {
+ isc_socketevent_t *ldev;
+
+ ldev = ISC_LIST_HEAD(sock->send_list);
+ while (ldev != NULL && ldev != dev) {
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+
+ return (ldev == NULL ? false : true);
+}
+
+static bool
+acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev) {
+ isc_socket_newconnev_t *ldev;
+
+ ldev = ISC_LIST_HEAD(sock->accept_list);
+ while (ldev != NULL && ldev != dev) {
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+
+ return (ldev == NULL ? false : true);
+}
+
+static bool
+connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev) {
+ isc_socket_connev_t *cdev;
+
+ cdev = ISC_LIST_HEAD(sock->connect_list);
+ while (cdev != NULL && cdev != dev) {
+ cdev = ISC_LIST_NEXT(cdev, ev_link);
+ }
+
+ return (cdev == NULL ? false : true);
+}
+
+/* */
+/* The Windows network stack seems to have two very distinct paths depending */
+/* on what is installed. Specifically, if something is looking at network */
+/* connections (like an anti-virus or anti-malware application, such as */
+/* McAfee products) Windows may return additional error conditions which */
+/* were not previously returned. */
+/* */
+/* One specific one is when a TCP SYN scan is used. In this situation, */
+/* Windows responds with the SYN-ACK, but the scanner never responds with */
+/* the 3rd packet, the ACK. Windows considers this a partially open connection.
+ */
+/* Most Unix networking stacks, and Windows without McAfee installed, will */
+/* not return this to the caller. However, with this product installed, */
+/* Windows returns this as a failed status on the Accept() call. Here, we */
+/* will just re-issue the ISCAcceptEx() call as if nothing had happened. */
+/* */
+/* This code should only be called when the listening socket has received */
+/* such an error. Additionally, the "parent" socket must be locked. */
+/* Additionally, the lpo argument is re-used here, and must not be freed */
+/* by the caller. */
+/* */
+static isc_result_t
+restart_accept(isc_socket_t *parent, IoCompletionInfo *lpo) {
+ isc_socket_t *nsock = lpo->adev->newsocket;
+ SOCKET new_fd;
+
+ /*
+ * AcceptEx() requires we pass in a socket. Note that we carefully
+ * do not close the previous socket in case of an error message returned
+ * by our new socket() call. If we return an error here, our caller
+ * will clean up.
+ */
+ new_fd = socket(parent->pf, SOCK_STREAM, IPPROTO_TCP);
+ if (nsock->fd == INVALID_SOCKET) {
+ return (ISC_R_FAILURE); /* parent will ask windows for error */
+ /* message */
+ }
+ closesocket(nsock->fd);
+ nsock->fd = new_fd;
+
+ memset(&lpo->overlapped, 0, sizeof(lpo->overlapped));
+
+ ISCAcceptEx(parent->fd, nsock->fd, /* Accepted Socket */
+ lpo->acceptbuffer, /* Buffer for initial Recv */
+ 0, /* Length of Buffer */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16
+ */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Remote address length + 16
+ */
+ (LPDWORD)&lpo->received_bytes, /* Bytes Recved */
+ (LPOVERLAPPED)lpo /* Overlapped structure */
+ );
+
+ InterlockedDecrement(&nsock->manager->iocp_total);
+ iocompletionport_update(nsock);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This is the I/O Completion Port Worker Function. It loops forever
+ * waiting for I/O to complete and then forwards them for further
+ * processing. There are a number of these in separate threads.
+ */
+static isc_threadresult_t WINAPI
+SocketIoThread(LPVOID ThreadContext) {
+ isc_socketmgr_t *manager = ThreadContext;
+ DWORD nbytes;
+ IoCompletionInfo *lpo = NULL;
+ isc_socket_t *sock = NULL;
+ int request;
+ struct msghdr *messagehdr = NULL;
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ int errstatus;
+
+ REQUIRE(VALID_MANAGER(manager));
+
+ /*
+ * Set the thread priority high enough so I/O will
+ * preempt normal recv packet processing, but not
+ * higher than the timer sync thread.
+ */
+ if (!SetThreadPriority(GetCurrentThread(),
+ THREAD_PRIORITY_ABOVE_NORMAL))
+ {
+ errval = GetLastError();
+ strerror_r(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__, "Can't set thread priority: %s",
+ strbuf);
+ }
+
+ /*
+ * Loop forever waiting on I/O Completions and then processing them
+ */
+ while (TRUE) {
+ BOOL bSuccess;
+
+ wait_again:
+ bSuccess = GetQueuedCompletionStatus(
+ manager->hIoCompletionPort, &nbytes, (PULONG_PTR)&sock,
+ (LPWSAOVERLAPPED *)&lpo, INFINITE);
+ if (lpo == NULL) { /* Received request to exit */
+ break;
+ }
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ request = lpo->request_type;
+
+ if (!bSuccess) {
+ errstatus = GetLastError();
+ } else {
+ errstatus = 0;
+ }
+ if (!bSuccess && errstatus != ERROR_MORE_DATA) {
+ isc_result_t isc_result;
+
+ /*
+ * Did the I/O operation complete?
+ */
+ isc_result = isc__errno2result(errstatus);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+ switch (request) {
+ case SOCKET_RECV:
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_recv > 0);
+ sock->pending_recv--;
+ if (!sock->connected &&
+ ((errstatus == ERROR_HOST_UNREACHABLE) ||
+ (errstatus == WSAENETRESET) ||
+ (errstatus == WSAECONNRESET)))
+ {
+ /* ignore soft errors */
+ queue_receive_request(sock);
+ break;
+ }
+ send_recvdone_abort(sock, isc_result);
+ if (isc_result == ISC_R_UNEXPECTED) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "SOCKET_RECV: Windows "
+ "error code: %d, "
+ "returning ISC error "
+ "%d",
+ errstatus, isc_result);
+ }
+ break;
+
+ case SOCKET_SEND:
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_send > 0);
+ sock->pending_send--;
+ if (senddone_is_active(sock, lpo->dev)) {
+ lpo->dev->result = isc_result;
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "canceled_send");
+ send_senddone_event(sock, &lpo->dev);
+ }
+ break;
+
+ case SOCKET_ACCEPT:
+ INSIST(sock->pending_iocp > 0);
+ INSIST(sock->pending_accept > 0);
+
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "Accept: errstatus=%d isc_result=%d",
+ errstatus, isc_result);
+
+ if (acceptdone_is_active(sock, lpo->adev)) {
+ if (restart_accept(sock, lpo) ==
+ ISC_R_SUCCESS)
+ {
+ UNLOCK(&sock->lock);
+ goto wait_again;
+ } else {
+ errstatus = GetLastError();
+ isc_result = isc__errno2result(
+ errstatus);
+ socket_log(__LINE__, sock, NULL,
+ EVENT,
+ "restart_accept() "
+ "failed: "
+ "errstatus=%d "
+ "isc_result=%d",
+ errstatus,
+ isc_result);
+ }
+ }
+
+ sock->pending_iocp--;
+ sock->pending_accept--;
+ if (acceptdone_is_active(sock, lpo->adev)) {
+ closesocket(lpo->adev->newsocket->fd);
+ lpo->adev->newsocket->fd =
+ INVALID_SOCKET;
+ isc_refcount_decrementz(
+ &lpo->adev->newsocket
+ ->references);
+ free_socket(&lpo->adev->newsocket,
+ __LINE__);
+ lpo->adev->result = isc_result;
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "canceled_accept");
+ send_acceptdone_event(sock, &lpo->adev);
+ }
+ break;
+
+ case SOCKET_CONNECT:
+ INSIST(sock->pending_iocp > 0);
+ sock->pending_iocp--;
+ INSIST(sock->pending_connect == 1);
+ sock->pending_connect = 0;
+ if (connectdone_is_active(sock, lpo->cdev)) {
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "canceled_connect");
+ send_connectdone_abort(sock,
+ isc_result);
+ }
+ break;
+ }
+ maybe_free_socket(&sock, __LINE__);
+
+ if (lpo != NULL) {
+ HeapFree(hHeapHandle, 0, lpo);
+ }
+ continue;
+ }
+
+ messagehdr = &lpo->messagehdr;
+
+ switch (request) {
+ case SOCKET_RECV:
+ internal_recv(sock, nbytes);
+ break;
+ case SOCKET_SEND:
+ internal_send(sock, lpo->dev, messagehdr, nbytes,
+ errstatus, lpo);
+ break;
+ case SOCKET_ACCEPT:
+ internal_accept(sock, lpo, errstatus);
+ break;
+ case SOCKET_CONNECT:
+ internal_connect(sock, lpo, errstatus);
+ break;
+ }
+
+ if (lpo != NULL) {
+ HeapFree(hHeapHandle, 0, lpo);
+ }
+ }
+
+ /*
+ * Exit Completion Port Thread
+ */
+ manager_log(manager, TRACE, "SocketIoThread exiting");
+ return ((isc_threadresult_t)0);
+}
+
+/*
+ * Create a new socket manager.
+ */
+isc_result_t
+isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
+ return (isc_socketmgr_create2(mctx, managerp, 0, 1));
+}
+
+isc_result_t
+isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
+ unsigned int maxsocks, int nthreads) {
+ isc_socketmgr_t *manager;
+
+ REQUIRE(managerp != NULL && *managerp == NULL);
+
+ if (maxsocks != 0) {
+ return (ISC_R_NOTIMPLEMENTED);
+ }
+
+ manager = isc_mem_get(mctx, sizeof(*manager));
+
+ InitSockets();
+
+ manager->magic = SOCKET_MANAGER_MAGIC;
+ manager->mctx = NULL;
+ manager->stats = NULL;
+ ISC_LIST_INIT(manager->socklist);
+ isc_mutex_init(&manager->lock);
+ isc_condition_init(&manager->shutdown_ok);
+
+ isc_mem_attach(mctx, &manager->mctx);
+ if (nthreads == 0) {
+ nthreads = isc_os_ncpus() + 1;
+ }
+ manager->maxIOCPThreads = min(nthreads, MAX_IOCPTHREADS);
+
+ iocompletionport_init(manager); /* Create the Completion Ports */
+
+ manager->bShutdown = false;
+ manager->totalSockets = 0;
+ manager->iocp_total = 0;
+ manager->maxudp = 0;
+
+ *managerp = manager;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(nsockp != NULL);
+
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(ISC_LIST_EMPTY(manager->socklist));
+ REQUIRE(manager->stats == NULL);
+ REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
+
+ isc_stats_attach(stats, &manager->stats);
+}
+
+void
+isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
+ isc_socketmgr_t *manager;
+
+ /*
+ * Destroy a socket manager.
+ */
+
+ REQUIRE(managerp != NULL);
+ manager = *managerp;
+ *managerp = NULL;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&manager->lock);
+
+ /*
+ * Wait for all sockets to be destroyed.
+ */
+ while (!ISC_LIST_EMPTY(manager->socklist)) {
+ manager_log(manager, CREATION, "sockets exist");
+ WAIT(&manager->shutdown_ok, &manager->lock);
+ }
+
+ UNLOCK(&manager->lock);
+
+ /*
+ * Here, we need to had some wait code for the completion port
+ * thread.
+ */
+ signal_iocompletionport_exit(manager);
+ manager->bShutdown = true;
+
+ /*
+ * Wait for threads to exit.
+ */
+ for (int i = 0; i < manager->maxIOCPThreads; i++) {
+ isc_thread_join((isc_thread_t)manager->hIOCPThreads[i], NULL);
+ }
+ /*
+ * Clean up.
+ */
+
+ CloseHandle(manager->hIoCompletionPort);
+
+ (void)isc_condition_destroy(&manager->shutdown_ok);
+
+ isc_mutex_destroy(&manager->lock);
+ if (manager->stats != NULL) {
+ isc_stats_detach(&manager->stats);
+ }
+ manager->magic = 0;
+ isc_mem_putanddetach(&manager->mctx, manager, sizeof(*manager));
+}
+
+static void
+queue_receive_event(isc_socket_t *sock, isc_task_t *task,
+ isc_socketevent_t *dev) {
+ isc_task_t *ntask = NULL;
+
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ /*
+ * Enqueue the request.
+ */
+ INSIST(!ISC_LINK_LINKED(dev, ev_link));
+ ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
+
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "queue_receive_event: event %p -> task %p", dev, ntask);
+}
+
+/*
+ * Check the pending receive queue, and if we have data pending, give it to this
+ * caller. If we have none, queue an I/O request. If this caller is not the
+ * first on the list, then we will just queue this event and return.
+ *
+ * Caller must have the socket locked.
+ */
+static isc_result_t
+socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ unsigned int flags) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ if (sock->fd == INVALID_SOCKET) {
+ return (ISC_R_EOF);
+ }
+
+ /*
+ * Queue our event on the list of things to do. Call our function to
+ * attempt to fill buffers as much as possible, and return done events.
+ * We are going to lie about our handling of the ISC_SOCKFLAG_IMMEDIATE
+ * here and tell our caller that we could not satisfy it immediately.
+ */
+ queue_receive_event(sock, task, dev);
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) {
+ result = ISC_R_INPROGRESS;
+ }
+
+ completeio_recv(sock);
+
+ /*
+ * If there are more receivers waiting for data, queue another receive
+ * here. If the
+ */
+ queue_receive_request(sock);
+
+ return (result);
+}
+
+isc_result_t
+isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
+ isc_task_t *task, isc_taskaction_t action, void *arg) {
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock, ISC_SOCKEVENT_RECVDONE,
+ action, arg);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+
+ ret = isc_socket_recv2(sock, region, minimum, task, dev, 0);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
+ isc_task_t *task, isc_socketevent_t *event,
+ unsigned int flags) {
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ event->result = ISC_R_UNEXPECTED;
+ event->ev_sender = sock;
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ /*
+ * UDP sockets are always partial read.
+ */
+ if (sock->type == isc_sockettype_udp) {
+ event->minimum = 1;
+ } else {
+ if (minimum == 0) {
+ event->minimum = region->length;
+ } else {
+ event->minimum = minimum;
+ }
+ }
+
+ ret = socket_recv(sock, event, task, flags);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+/*
+ * Caller must have the socket locked.
+ */
+static isc_result_t
+socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
+ const isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ unsigned int flags) {
+ int io_state;
+ int send_errno = 0;
+ int cc = 0;
+ isc_task_t *ntask = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ dev->ev_sender = task;
+
+ set_dev_address(address, sock, dev);
+ if (pktinfo != NULL) {
+ socket_log(__LINE__, sock, NULL, TRACE,
+ "pktinfo structure provided, ifindex %u (set to 0)",
+ pktinfo->ipi6_ifindex);
+
+ dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
+ dev->pktinfo = *pktinfo;
+ /*
+ * Set the pktinfo index to 0 here, to let the kernel decide
+ * what interface it should send on.
+ */
+ dev->pktinfo.ipi6_ifindex = 0;
+ }
+
+ io_state = startio_send(sock, dev, &cc, &send_errno);
+ switch (io_state) {
+ case DOIO_PENDING: /* I/O started. Enqueue completion event. */
+ case DOIO_SOFT:
+ /*
+ * We couldn't send all or part of the request right now, so
+ * queue it unless ISC_SOCKFLAG_NORETRY is set.
+ */
+ if ((flags & ISC_SOCKFLAG_NORETRY) == 0 ||
+ io_state == DOIO_PENDING)
+ {
+ isc_task_attach(task, &ntask);
+ dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
+
+ /*
+ * Enqueue the request.
+ */
+ INSIST(!ISC_LINK_LINKED(dev, ev_link));
+ ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
+
+ socket_log(__LINE__, sock, NULL, EVENT,
+ "socket_send: event %p -> task %p", dev,
+ ntask);
+
+ if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) {
+ result = ISC_R_INPROGRESS;
+ }
+ break;
+ }
+
+ case DOIO_SUCCESS:
+ break;
+ }
+
+ return (result);
+}
+
+isc_result_t
+isc_socket_send(isc_socket_t *sock, isc_region_t *region, isc_task_t *task,
+ isc_taskaction_t action, void *arg) {
+ /*
+ * REQUIRE() checking is performed in isc_socket_sendto().
+ */
+ return (isc_socket_sendto(sock, region, task, action, arg, NULL, NULL));
+}
+
+isc_result_t
+isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ const isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) {
+ isc_socketevent_t *dev;
+ isc_socketmgr_t *manager;
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ REQUIRE(region != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ INSIST(sock->bound);
+
+ dev = allocate_socketevent(manager->mctx, sock, ISC_SOCKEVENT_SENDDONE,
+ action, arg);
+ if (dev == NULL) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_NOMEMORY);
+ }
+ dev->region = *region;
+
+ ret = socket_send(sock, dev, task, address, pktinfo, 0);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, isc_task_t *task,
+ const isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
+ isc_socketevent_t *event, unsigned int flags) {
+ isc_result_t ret;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE | ISC_SOCKFLAG_NORETRY)) ==
+ 0);
+ if ((flags & ISC_SOCKFLAG_NORETRY) != 0) {
+ REQUIRE(sock->type == isc_sockettype_udp);
+ }
+ event->ev_sender = sock;
+ event->result = ISC_R_UNEXPECTED;
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+ event->region = *region;
+ event->n = 0;
+ event->offset = 0;
+ event->attributes = 0;
+
+ ret = socket_send(sock, event, task, address, pktinfo, flags);
+ UNLOCK(&sock->lock);
+ return (ret);
+}
+
+isc_result_t
+isc_socket_bind(isc_socket_t *sock, const isc_sockaddr_t *sockaddr,
+ isc_socket_options_t options) {
+ int bind_errno;
+ char strbuf[ISC_STRERRORSIZE];
+ int on = 1;
+
+ REQUIRE(VALID_SOCKET(sock));
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ INSIST(!sock->bound);
+ INSIST(!sock->dupped);
+
+ if (sock->pf != sockaddr->type.sa.sa_family) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_FAMILYMISMATCH);
+ }
+ /*
+ * Only set SO_REUSEADDR when we want a specific port.
+ */
+ if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
+ isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
+ setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) < 0)
+ {
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d) failed",
+ sock->fd);
+ /* Press on... */
+ }
+ if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
+ bind_errno = WSAGetLastError();
+ UNLOCK(&sock->lock);
+ switch (bind_errno) {
+ case WSAEACCES:
+ return (ISC_R_NOPERM);
+ case WSAEADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case WSAEADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+ case WSAEINVAL:
+ return (ISC_R_BOUND);
+ default:
+ strerror_r(bind_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+
+ socket_log(__LINE__, sock, sockaddr, TRACE, "bound");
+ sock->bound = 1;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_filter(isc_socket_t *sock, const char *filter) {
+ UNUSED(sock);
+ UNUSED(filter);
+
+ REQUIRE(VALID_SOCKET(sock));
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+/*
+ * Set up to listen on a given socket. We do this by creating an internal
+ * event that will be dispatched when the socket has read activity. The
+ * watcher will send the internal event to the task when there is a new
+ * connection.
+ *
+ * Unlike in read, we don't preallocate a done event here. Every time there
+ * is a new connection we'll have to allocate a new one anyway, so we might
+ * as well keep things simple rather than having to track them.
+ */
+isc_result_t
+isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
+ char strbuf[ISC_STRERRORSIZE];
+#if defined(ENABLE_TCP_FASTOPEN) && defined(TCP_FASTOPEN)
+ char on = 1;
+#endif /* if defined(ENABLE_TCP_FASTOPEN) && defined(TCP_FASTOPEN) */
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ REQUIRE(!sock->listener);
+ REQUIRE(sock->bound);
+ REQUIRE(sock->type == isc_sockettype_tcp);
+
+ if (backlog == 0) {
+ backlog = SOMAXCONN;
+ }
+
+ if (listen(sock->fd, (int)backlog) < 0) {
+ UNLOCK(&sock->lock);
+ strerror_r(WSAGetLastError(), strbuf, sizeof(strbuf));
+
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
+
+ return (ISC_R_UNEXPECTED);
+ }
+
+#if defined(ENABLE_TCP_FASTOPEN) && defined(TCP_FASTOPEN)
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on)) <
+ 0)
+ {
+ strerror_r(errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "setsockopt(%d, TCP_FASTOPEN) failed with %s",
+ sock->fd, strbuf);
+ /* TCP_FASTOPEN is experimental so ignore failures */
+ }
+#endif /* if defined(ENABLE_TCP_FASTOPEN) && defined(TCP_FASTOPEN) */
+
+ socket_log(__LINE__, sock, NULL, TRACE, "listening");
+ sock->listener = 1;
+ _set_state(sock, SOCK_LISTEN);
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * This should try to do aggressive accept() XXXMLG
+ */
+isc_result_t
+isc_socket_accept(isc_socket_t *sock, isc_task_t *task, isc_taskaction_t action,
+ void *arg) {
+ isc_socket_newconnev_t *adev;
+ isc_socketmgr_t *manager;
+ isc_task_t *ntask = NULL;
+ isc_socket_t *nsock;
+ isc_result_t result;
+ IoCompletionInfo *lpo;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ REQUIRE(sock->listener);
+
+ /*
+ * Sender field is overloaded here with the task we will be sending
+ * this event to. Just before the actual event is delivered the
+ * actual ev_sender will be touched up to be the socket.
+ */
+ adev = (isc_socket_newconnev_t *)isc_event_allocate(
+ manager->mctx, task, ISC_SOCKEVENT_NEWCONN, action, arg,
+ sizeof(*adev));
+ ISC_LINK_INIT(adev, ev_link);
+
+ result = allocate_socket(manager, sock->type, &nsock);
+ if (result != ISC_R_SUCCESS) {
+ isc_event_free((isc_event_t **)&adev);
+ UNLOCK(&sock->lock);
+ return (result);
+ }
+
+ /*
+ * AcceptEx() requires we pass in a socket.
+ */
+ nsock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
+ if (nsock->fd == INVALID_SOCKET) {
+ free_socket(&nsock, __LINE__);
+ isc_event_free((isc_event_t **)&adev);
+ UNLOCK(&sock->lock);
+ return (ISC_R_FAILURE); /* XXXMLG need real error message */
+ }
+
+ /*
+ * Attach to socket and to task.
+ */
+ isc_task_attach(task, &ntask);
+ if (isc_task_exiting(ntask)) {
+ free_socket(&nsock, __LINE__);
+ isc_task_detach(&ntask);
+ isc_event_free(ISC_EVENT_PTR(&adev));
+ UNLOCK(&sock->lock);
+ return (ISC_R_SHUTTINGDOWN);
+ }
+ isc_refcount_increment0(&nsock->references);
+
+ adev->ev_sender = ntask;
+ adev->newsocket = nsock;
+ _set_state(nsock, SOCK_ACCEPT);
+
+ /*
+ * Queue io completion for an accept().
+ */
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ RUNTIME_CHECK(lpo != NULL);
+ lpo->acceptbuffer =
+ (void *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
+ (sizeof(SOCKADDR_STORAGE) + 16) * 2);
+ RUNTIME_CHECK(lpo->acceptbuffer != NULL);
+
+ lpo->adev = adev;
+ lpo->request_type = SOCKET_ACCEPT;
+
+ ISCAcceptEx(sock->fd, nsock->fd, /* Accepted Socket */
+ lpo->acceptbuffer, /* Buffer for initial Recv */
+ 0, /* Length of Buffer */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16
+ */
+ sizeof(SOCKADDR_STORAGE) + 16, /* Remote address length + 16
+ */
+ (LPDWORD)&lpo->received_bytes, /* Bytes Recved */
+ (LPOVERLAPPED)lpo /* Overlapped structure */
+ );
+ iocompletionport_update(nsock);
+
+ socket_log(__LINE__, sock, NULL, TRACE, "accepting for nsock %p fd %d",
+ nsock, nsock->fd);
+
+ /*
+ * Enqueue the event
+ */
+ ISC_LIST_ENQUEUE(sock->accept_list, adev, ev_link);
+ sock->pending_accept++;
+ sock->pending_iocp++;
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_connect(isc_socket_t *sock, const isc_sockaddr_t *addr,
+ isc_task_t *task, isc_taskaction_t action, void *arg) {
+ char strbuf[ISC_STRERRORSIZE];
+ isc_socket_connev_t *cdev;
+ isc_task_t *ntask = NULL;
+ isc_socketmgr_t *manager;
+ IoCompletionInfo *lpo;
+ int bind_errno;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addr != NULL);
+ REQUIRE(task != NULL);
+ REQUIRE(action != NULL);
+
+ manager = sock->manager;
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(addr != NULL);
+
+ if (isc_sockaddr_ismulticast(addr)) {
+ return (ISC_R_MULTICAST);
+ }
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ /*
+ * Windows sockets won't connect unless the socket is bound.
+ */
+ if (!sock->bound) {
+ isc_sockaddr_t any;
+
+ isc_sockaddr_anyofpf(&any, isc_sockaddr_pf(addr));
+ if (bind(sock->fd, &any.type.sa, any.length) < 0) {
+ bind_errno = WSAGetLastError();
+ UNLOCK(&sock->lock);
+ switch (bind_errno) {
+ case WSAEACCES:
+ return (ISC_R_NOPERM);
+ case WSAEADDRNOTAVAIL:
+ return (ISC_R_ADDRNOTAVAIL);
+ case WSAEADDRINUSE:
+ return (ISC_R_ADDRINUSE);
+ case WSAEINVAL:
+ return (ISC_R_BOUND);
+ default:
+ strerror_r(bind_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
+ strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+ sock->bound = 1;
+ }
+
+ cdev = (isc_socket_connev_t *)isc_event_allocate(
+ manager->mctx, sock, ISC_SOCKEVENT_CONNECT, action, arg,
+ sizeof(*cdev));
+ ISC_LINK_INIT(cdev, ev_link);
+
+ if (sock->connected) {
+ INSIST(isc_sockaddr_equal(&sock->address, addr));
+ cdev->result = ISC_R_SUCCESS;
+ isc_task_send(task, ISC_EVENT_PTR(&cdev));
+
+ UNLOCK(&sock->lock);
+ return (ISC_R_SUCCESS);
+ }
+
+ if ((sock->type == isc_sockettype_tcp) && !sock->pending_connect) {
+ /*
+ * Queue io completion for an accept().
+ */
+ lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY,
+ sizeof(IoCompletionInfo));
+ lpo->cdev = cdev;
+ lpo->request_type = SOCKET_CONNECT;
+
+ sock->address = *addr;
+ ISCConnectEx(sock->fd, &addr->type.sa, addr->length, NULL, 0,
+ NULL, (LPOVERLAPPED)lpo);
+
+ /*
+ * Attach to task.
+ */
+ isc_task_attach(task, &ntask);
+ cdev->ev_sender = ntask;
+
+ sock->pending_connect = 1;
+ _set_state(sock, SOCK_CONNECT);
+
+ /*
+ * Enqueue the request.
+ */
+ INSIST(!ISC_LINK_LINKED(cdev, ev_link));
+ ISC_LIST_ENQUEUE(sock->connect_list, cdev, ev_link);
+ sock->pending_iocp++;
+ } else if (sock->type == isc_sockettype_tcp) {
+ INSIST(sock->pending_connect);
+ INSIST(isc_sockaddr_equal(&sock->address, addr));
+ isc_task_attach(task, &ntask);
+ cdev->ev_sender = ntask;
+ INSIST(!ISC_LINK_LINKED(cdev, ev_link));
+ ISC_LIST_ENQUEUE(sock->connect_list, cdev, ev_link);
+ } else {
+ REQUIRE(!sock->pending_connect);
+ WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL,
+ NULL, NULL);
+ cdev->result = ISC_R_SUCCESS;
+ isc_task_send(task, (isc_event_t **)&cdev);
+ }
+ CONSISTENT(sock);
+ UNLOCK(&sock->lock);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ isc_result_t result;
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ if (sock->connected) {
+ *addressp = sock->address;
+ result = ISC_R_SUCCESS;
+ } else {
+ result = ISC_R_NOTCONNECTED;
+ }
+
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+isc_result_t
+isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
+ socklen_t len;
+ isc_result_t result;
+ char strbuf[ISC_STRERRORSIZE];
+
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(addressp != NULL);
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ if (!sock->bound) {
+ result = ISC_R_NOTBOUND;
+ goto out;
+ }
+
+ result = ISC_R_SUCCESS;
+
+ len = sizeof(addressp->type);
+ if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
+ strerror_r(WSAGetLastError(), strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s", strbuf);
+ result = ISC_R_UNEXPECTED;
+ goto out;
+ }
+ addressp->length = (unsigned int)len;
+
+out:
+ UNLOCK(&sock->lock);
+
+ return (result);
+}
+
+/*
+ * Run through the list of events on this socket, and cancel the ones
+ * queued for task "task" of type "how". "how" is a bitmask.
+ */
+void
+isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+ REQUIRE(VALID_SOCKET(sock));
+
+ /*
+ * Quick exit if there is nothing to do. Don't even bother locking
+ * in this case.
+ */
+ if (how == 0) {
+ return;
+ }
+
+ LOCK(&sock->lock);
+ CONSISTENT(sock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return;
+ }
+
+ /*
+ * All of these do the same thing, more or less.
+ * Each will:
+ * o If the internal event is marked as "posted" try to
+ * remove it from the task's queue. If this fails, mark it
+ * as canceled instead, and let the task clean it up later.
+ * o For each I/O request for that task of that type, post
+ * its done event with status of "ISC_R_CANCELED".
+ * o Reset any state needed.
+ */
+
+ if ((how & ISC_SOCKCANCEL_RECV) != 0) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->recv_list);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_recvdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+ how &= ~ISC_SOCKCANCEL_RECV;
+
+ if ((how & ISC_SOCKCANCEL_SEND) != 0) {
+ isc_socketevent_t *dev;
+ isc_socketevent_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->send_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_senddone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ }
+ how &= ~ISC_SOCKCANCEL_SEND;
+
+ if (((how & ISC_SOCKCANCEL_ACCEPT) != 0) &&
+ !ISC_LIST_EMPTY(sock->accept_list))
+ {
+ isc_socket_newconnev_t *dev;
+ isc_socket_newconnev_t *next;
+ isc_task_t *current_task;
+
+ dev = ISC_LIST_HEAD(sock->accept_list);
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+
+ if ((task == NULL) || (task == current_task)) {
+ isc_refcount_decrementz(
+ &dev->newsocket->references);
+ closesocket(dev->newsocket->fd);
+ dev->newsocket->fd = INVALID_SOCKET;
+ free_socket(&dev->newsocket, __LINE__);
+
+ dev->result = ISC_R_CANCELED;
+ send_acceptdone_event(sock, &dev);
+ }
+
+ dev = next;
+ }
+ }
+ how &= ~ISC_SOCKCANCEL_ACCEPT;
+
+ if (((how & ISC_SOCKCANCEL_CONNECT) != 0) &&
+ !ISC_LIST_EMPTY(sock->connect_list))
+ {
+ isc_socket_connev_t *dev;
+ isc_socket_connev_t *next;
+ isc_task_t *current_task;
+
+ INSIST(sock->pending_connect);
+
+ dev = ISC_LIST_HEAD(sock->connect_list);
+
+ while (dev != NULL) {
+ current_task = dev->ev_sender;
+ next = ISC_LIST_NEXT(dev, ev_link);
+ if ((task == NULL) || (task == current_task)) {
+ dev->result = ISC_R_CANCELED;
+ send_connectdone_event(sock, &dev);
+ }
+ dev = next;
+ }
+ closesocket(sock->fd);
+ sock->fd = INVALID_SOCKET;
+ _set_state(sock, SOCK_CLOSED);
+ }
+ how &= ~ISC_SOCKCANCEL_CONNECT;
+ UNUSED(how);
+
+ maybe_free_socket(&sock, __LINE__);
+}
+
+isc_sockettype_t
+isc_socket_gettype(isc_socket_t *sock) {
+ isc_sockettype_t type;
+
+ REQUIRE(VALID_SOCKET(sock));
+
+ LOCK(&sock->lock);
+
+ /*
+ * make sure that the socket's not closed
+ */
+ if (sock->fd == INVALID_SOCKET) {
+ UNLOCK(&sock->lock);
+ return (ISC_R_CONNREFUSED);
+ }
+
+ type = sock->type;
+ UNLOCK(&sock->lock);
+ return (type);
+}
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, bool yes) {
+#if defined(IPV6_V6ONLY)
+ int onoff = yes ? 1 : 0;
+#else /* if defined(IPV6_V6ONLY) */
+ UNUSED(yes);
+#endif /* if defined(IPV6_V6ONLY) */
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IPV6_V6ONLY
+ if (sock->pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&onoff, sizeof(onoff));
+ }
+#endif /* ifdef IPV6_V6ONLY */
+}
+
+void
+isc_socket_dscp(isc_socket_t *sock, isc_dscp_t dscp) {
+#if !defined(IP_TOS) && !defined(IPV6_TCLASS)
+ UNUSED(dscp);
+#else /* if !defined(IP_TOS) && !defined(IPV6_TCLASS) */
+ if (dscp < 0) {
+ return;
+ }
+
+ dscp <<= 2;
+ dscp &= 0xff;
+#endif /* if !defined(IP_TOS) && !defined(IPV6_TCLASS) */
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IP_TOS
+ if (sock->pf == AF_INET) {
+ (void)setsockopt(sock->fd, IPPROTO_IP, IP_TOS, (char *)&dscp,
+ sizeof(dscp));
+ }
+#endif /* ifdef IP_TOS */
+#ifdef IPV6_TCLASS
+ if (sock->pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS,
+ (char *)&dscp, sizeof(dscp));
+ }
+#endif /* ifdef IPV6_TCLASS */
+}
+
+void
+isc_socket_cleanunix(const isc_sockaddr_t *addr, bool active) {
+ UNUSED(addr);
+ UNUSED(active);
+}
+
+isc_result_t
+isc_socket_permunix(const isc_sockaddr_t *addr, uint32_t perm, uint32_t owner,
+ uint32_t group) {
+ UNUSED(addr);
+ UNUSED(perm);
+ UNUSED(owner);
+ UNUSED(group);
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+void
+isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) {
+ /*
+ * Name 'socket'.
+ */
+
+ REQUIRE(VALID_SOCKET(socket));
+
+ LOCK(&socket->lock);
+ strlcpy(socket->name, name, sizeof(socket->name));
+ socket->tag = tag;
+ UNLOCK(&socket->lock);
+}
+
+const char *
+isc_socket_getname(isc_socket_t *socket) {
+ return (socket->name);
+}
+
+void *
+isc_socket_gettag(isc_socket_t *socket) {
+ return (socket->tag);
+}
+
+int
+isc_socket_getfd(isc_socket_t *socket) {
+ return ((short)socket->fd);
+}
+
+void
+isc_socketmgr_setreserved(isc_socketmgr_t *manager, uint32_t reserved) {
+ UNUSED(manager);
+ UNUSED(reserved);
+}
+
+isc_socketevent_t *
+isc_socket_socketevent(isc_mem_t *mctx, void *sender, isc_eventtype_t eventtype,
+ isc_taskaction_t action, void *arg) {
+ return (allocate_socketevent(mctx, sender, eventtype, action, arg));
+}
+
+bool
+isc_socket_hasreuseport() {
+ return (false);
+}
+
+#ifdef HAVE_LIBXML2
+
+static const char *
+_socktype(isc_sockettype_t type) {
+ switch (type) {
+ case isc_sockettype_udp:
+ return ("udp");
+ case isc_sockettype_tcp:
+ return ("tcp");
+ case isc_sockettype_unix:
+ return ("unix");
+ default:
+ return ("not-initialized");
+ }
+}
+
+#define TRY0(a) \
+ do { \
+ xmlrc = (a); \
+ if (xmlrc < 0) \
+ goto error; \
+ } while (0)
+int
+isc_socketmgr_renderxml(isc_socketmgr_t *mgr, void *writer0) {
+ isc_socket_t *sock = NULL;
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t addr;
+ socklen_t len;
+ int xmlrc;
+ xmlTextWriterPtr writer = (xmlTextWriterPtr)writer0;
+
+ LOCK(&mgr->lock);
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"));
+ sock = ISC_LIST_HEAD(mgr->socklist);
+ while (sock != NULL) {
+ LOCK(&sock->lock);
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket"));
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%p", sock));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ if (sock->name[0] != 0) {
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "name"));
+ TRY0(xmlTextWriterWriteFormatString(writer, "%s",
+ sock->name));
+ TRY0(xmlTextWriterEndElement(writer)); /* name */
+ }
+
+ TRY0(xmlTextWriterStartElement(writer,
+ ISC_XMLCHAR "references"));
+ TRY0(xmlTextWriterWriteFormatString(
+ writer, "%" PRIuFAST32,
+ isc_refcount_current(&sock->references)));
+ TRY0(xmlTextWriterEndElement(writer));
+
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "type",
+ ISC_XMLCHAR _socktype(sock->type)));
+
+ if (sock->connected) {
+ isc_sockaddr_format(&sock->address, peerbuf,
+ sizeof(peerbuf));
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "peer-address",
+ ISC_XMLCHAR peerbuf));
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+ isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "local-address",
+ ISC_XMLCHAR peerbuf));
+ }
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "states"));
+ if (sock->pending_recv) {
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending-receive"));
+ }
+ if (sock->pending_send) {
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending-send"));
+ }
+ if (sock->pending_accept) {
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "state",
+ ISC_XMLCHAR "pending_accept"));
+ }
+ if (sock->listener) {
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "listener"));
+ }
+ if (sock->connected) {
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "state",
+ ISC_XMLCHAR "connected"));
+ }
+ if (sock->pending_connect) {
+ TRY0(xmlTextWriterWriteElement(
+ writer, ISC_XMLCHAR "state",
+ ISC_XMLCHAR "connecting"));
+ }
+ if (sock->bound) {
+ TRY0(xmlTextWriterWriteElement(writer,
+ ISC_XMLCHAR "state",
+ ISC_XMLCHAR "bound"));
+ }
+
+ TRY0(xmlTextWriterEndElement(writer)); /* states */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* socket */
+
+ UNLOCK(&sock->lock);
+ sock = ISC_LIST_NEXT(sock, link);
+ }
+ TRY0(xmlTextWriterEndElement(writer)); /* sockets */
+
+error:
+ if (sock != NULL) {
+ UNLOCK(&sock->lock);
+ }
+
+ UNLOCK(&mgr->lock);
+
+ return (xmlrc);
+}
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_JSON_C
+#define CHECKMEM(m) \
+ do { \
+ if (m == NULL) { \
+ result = ISC_R_NOMEMORY; \
+ goto error; \
+ } \
+ } while (0)
+isc_result_t
+isc_socketmgr_renderjson(isc_socketmgr_t *mgr, void *stats0) {
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_socket_t *sock = NULL;
+ char peerbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t addr;
+ socklen_t len;
+ json_object *obj, *array = json_object_new_array();
+ json_object *stats = (json_object *)stats;
+
+ CHECKMEM(array);
+
+ LOCK(&mgr->lock);
+
+#ifdef USE_SHARED_MANAGER
+ obj = json_object_new_int(mgr->refs);
+ CHECKMEM(obj);
+ json_object_object_add(stats, "references", obj);
+#endif /* USE_SHARED_MANAGER */
+
+ sock = ISC_LIST_HEAD(mgr->socklist);
+ while (sock != NULL) {
+ json_object *states, *entry = json_object_new_object();
+ char buf[255];
+
+ CHECKMEM(entry);
+ json_object_array_add(array, entry);
+
+ LOCK(&sock->lock);
+
+ snprintf(buf, sizeof(buf), "%p", sock);
+ obj = json_object_new_string(buf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "id", obj);
+
+ if (sock->name[0] != 0) {
+ obj = json_object_new_string(sock->name);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "name", obj);
+ }
+
+ obj = json_object_new_int(
+ isc_refcount_current(&sock->references));
+ CHECKMEM(obj);
+ json_object_object_add(entry, "references", obj);
+
+ obj = json_object_new_string(_socktype(sock->type));
+ CHECKMEM(obj);
+ json_object_object_add(entry, "type", obj);
+
+ if (sock->connected) {
+ isc_sockaddr_format(&sock->address, peerbuf,
+ sizeof(peerbuf));
+ obj = json_object_new_string(peerbuf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "peer-address", obj);
+ }
+
+ len = sizeof(addr);
+ if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
+ isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
+ obj = json_object_new_string(peerbuf);
+ CHECKMEM(obj);
+ json_object_object_add(entry, "local-address", obj);
+ }
+
+ states = json_object_new_array();
+ CHECKMEM(states);
+ json_object_object_add(entry, "states", states);
+
+ if (sock->pending_recv) {
+ obj = json_object_new_string("pending-receive");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_send) {
+ obj = json_object_new_string("pending-send");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_accept) {
+ obj = json_object_new_string("pending-accept");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->listener) {
+ obj = json_object_new_string("listener");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->connected) {
+ obj = json_object_new_string("connected");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->pending_connect) {
+ obj = json_object_new_string("connecting");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ if (sock->bound) {
+ obj = json_object_new_string("bound");
+ CHECKMEM(obj);
+ json_object_array_add(states, obj);
+ }
+
+ UNLOCK(&sock->lock);
+ sock = ISC_LIST_NEXT(sock, link);
+ }
+
+ json_object_object_add(stats, "sockets", array);
+ array = NULL;
+ result = ISC_R_SUCCESS;
+
+error:
+ if (array != NULL) {
+ json_object_put(array);
+ }
+
+ if (sock != NULL) {
+ UNLOCK(&sock->lock);
+ }
+
+ UNLOCK(&mgr->lock);
+
+ return (result);
+}
+#endif /* HAVE_JSON_C */
+
+void
+isc_socketmgr_maxudp(isc_socketmgr_t *manager, unsigned int maxudp) {
+ REQUIRE(VALID_MANAGER(manager));
+
+ manager->maxudp = maxudp;
+}
diff --git a/lib/isc/win32/stdio.c b/lib/isc/win32/stdio.c
new file mode 100644
index 0000000..1e55c30
--- /dev/null
+++ b/lib/isc/win32/stdio.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <errno.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <isc/stdio.h>
+#include <isc/util.h>
+
+#include "errno2result.h"
+
+isc_result_t
+isc_stdio_open(const char *filename, const char *mode, FILE **fp) {
+ FILE *f;
+
+ f = fopen(filename, mode);
+ if (f == NULL) {
+ return (isc__errno2result(errno));
+ }
+ *fp = f;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_stdio_close(FILE *f) {
+ int r;
+
+ r = fclose(f);
+ if (r == 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+isc_result_t
+isc_stdio_seek(FILE *f, off_t offset, int whence) {
+ int r;
+
+#ifndef _WIN64
+ r = fseek(f, offset, whence);
+#else /* ifndef _WIN64 */
+ r = _fseeki64(f, offset, whence);
+#endif /* ifndef _WIN64 */
+ if (r == 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+isc_result_t
+isc_stdio_tell(FILE *f, off_t *offsetp) {
+#ifndef _WIN64
+ long r;
+#else /* ifndef _WIN64 */
+ __int64 r;
+#endif /* ifndef _WIN64 */
+
+ REQUIRE(offsetp != NULL);
+
+#ifndef _WIN64
+ r = ftell(f);
+#else /* ifndef _WIN64 */
+ r = _ftelli64(f);
+#endif /* ifndef _WIN64 */
+ if (r >= 0) {
+ *offsetp = r;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+isc_result_t
+isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) {
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fread(ptr, size, nmemb, f);
+ if (r != nmemb) {
+ if (feof(f)) {
+ result = ISC_R_EOF;
+ } else {
+ result = isc__errno2result(errno);
+ }
+ }
+ if (nret != NULL) {
+ *nret = r;
+ }
+ return (result);
+}
+
+isc_result_t
+isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f,
+ size_t *nret) {
+ isc_result_t result = ISC_R_SUCCESS;
+ size_t r;
+
+ clearerr(f);
+ r = fwrite(ptr, size, nmemb, f);
+ if (r != nmemb) {
+ result = isc__errno2result(errno);
+ }
+ if (nret != NULL) {
+ *nret = r;
+ }
+ return (result);
+}
+
+isc_result_t
+isc_stdio_flush(FILE *f) {
+ int r;
+
+ r = fflush(f);
+ if (r == 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
+
+isc_result_t
+isc_stdio_sync(FILE *f) {
+ struct _stat buf;
+ int r;
+
+ if (_fstat(_fileno(f), &buf) != 0) {
+ return (isc__errno2result(errno));
+ }
+
+ /*
+ * Only call _commit() on regular files.
+ */
+ if ((buf.st_mode & S_IFMT) != S_IFREG) {
+ return (ISC_R_SUCCESS);
+ }
+
+ r = _commit(_fileno(f));
+ if (r == 0) {
+ return (ISC_R_SUCCESS);
+ } else {
+ return (isc__errno2result(errno));
+ }
+}
diff --git a/lib/isc/win32/stdtime.c b/lib/isc/win32/stdtime.c
new file mode 100644
index 0000000..93fcd66
--- /dev/null
+++ b/lib/isc/win32/stdtime.c
@@ -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.
+ */
+
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/stdtime.h>
+#include <isc/util.h>
+
+void
+isc_stdtime_get(isc_stdtime_t *t) {
+ /*
+ * Set 't' to the number of seconds past 00:00:00 UTC, January 1, 1970.
+ */
+
+ REQUIRE(t != NULL);
+
+ (void)_time32(t);
+}
+
+void
+isc_stdtime_tostring(isc_stdtime_t t, char *out, size_t outlen) {
+ time_t when;
+
+ REQUIRE(out != NULL);
+ /* Minimum buffer as per ctime_r() specification. */
+ REQUIRE(outlen >= 26);
+
+ /* time_t and isc_stdtime_t might be different sizes */
+ when = t;
+ INSIST((ctime_s(out, outlen, &when) == 0));
+ *(out + strlen(out) - 1) = '\0';
+}
diff --git a/lib/isc/win32/syslog.c b/lib/isc/win32/syslog.c
new file mode 100644
index 0000000..ad23a0f
--- /dev/null
+++ b/lib/isc/win32/syslog.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <windows.h>
+
+#include <isc/bindevt.h>
+#include <isc/result.h>
+#include <isc/syslog.h>
+#include <isc/util.h>
+
+static HANDLE hAppLog = NULL;
+static FILE *log_stream;
+static int debug_level = 0;
+
+static struct dsn_c_pvt_sfnt {
+ int val;
+ const char *strval;
+} facilities[] = { { LOG_KERN, "kern" },
+ { LOG_USER, "user" },
+ { LOG_MAIL, "mail" },
+ { LOG_DAEMON, "daemon" },
+ { LOG_AUTH, "auth" },
+ { LOG_SYSLOG, "syslog" },
+ { LOG_LPR, "lpr" },
+#ifdef LOG_NEWS
+ { LOG_NEWS, "news" },
+#endif /* ifdef LOG_NEWS */
+#ifdef LOG_UUCP
+ { LOG_UUCP, "uucp" },
+#endif /* ifdef LOG_UUCP */
+#ifdef LOG_CRON
+ { LOG_CRON, "cron" },
+#endif /* ifdef LOG_CRON */
+#ifdef LOG_AUTHPRIV
+ { LOG_AUTHPRIV, "authpriv" },
+#endif /* ifdef LOG_AUTHPRIV */
+#ifdef LOG_FTP
+ { LOG_FTP, "ftp" },
+#endif /* ifdef LOG_FTP */
+ { LOG_LOCAL0, "local0" },
+ { LOG_LOCAL1, "local1" },
+ { LOG_LOCAL2, "local2" },
+ { LOG_LOCAL3, "local3" },
+ { LOG_LOCAL4, "local4" },
+ { LOG_LOCAL5, "local5" },
+ { LOG_LOCAL6, "local6" },
+ { LOG_LOCAL7, "local7" },
+ { 0, NULL } };
+
+isc_result_t
+isc_syslog_facilityfromstring(const char *str, int *facilityp) {
+ int i;
+
+ REQUIRE(str != NULL);
+ REQUIRE(facilityp != NULL);
+
+ for (i = 0; facilities[i].strval != NULL; i++) {
+ if (strcasecmp(facilities[i].strval, str) == 0) {
+ *facilityp = facilities[i].val;
+ return (ISC_R_SUCCESS);
+ }
+ }
+ return (ISC_R_NOTFOUND);
+}
+
+/*
+ * Log to the NT Event Log
+ */
+void
+syslog(int level, const char *fmt, ...) {
+ va_list ap;
+ char buf[1024];
+ char *str[1];
+
+ str[0] = buf;
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ /* Make sure that the channel is open to write the event */
+ if (hAppLog != NULL) {
+ switch (level) {
+ case LOG_INFO:
+ case LOG_NOTICE:
+ case LOG_DEBUG:
+ ReportEvent(hAppLog, EVENTLOG_INFORMATION_TYPE, 0,
+ BIND_INFO_MSG, NULL, 1, 0, str, NULL);
+ break;
+ case LOG_WARNING:
+ ReportEvent(hAppLog, EVENTLOG_WARNING_TYPE, 0,
+ BIND_WARN_MSG, NULL, 1, 0, str, NULL);
+ break;
+ default:
+ ReportEvent(hAppLog, EVENTLOG_ERROR_TYPE, 0,
+ BIND_ERR_MSG, NULL, 1, 0, str, NULL);
+ break;
+ }
+ }
+}
+
+/*
+ * Initialize event logging
+ */
+void
+openlog(const char *name, int flags, ...) {
+ /* Get a handle to the Application event log */
+ hAppLog = RegisterEventSource(NULL, name);
+}
+
+/*
+ * Close the Handle to the application Event Log
+ * We don't care whether or not we succeeded so ignore return values
+ * In fact if we failed then we would have nowhere to put the message
+ */
+void
+closelog(void) {
+ DeregisterEventSource(hAppLog);
+}
+
+/*
+ * Keep event logging synced with the current debug level
+ */
+void
+ModifyLogLevel(int level) {
+ debug_level = level;
+}
+
+/*
+ * Initialize logging for the port section of libbind.
+ * Piggyback onto stream given.
+ */
+void
+InitNTLogging(FILE *stream, int debug) {
+ log_stream = stream;
+ ModifyLogLevel(debug);
+}
+/*
+ * This function is for reporting errors to the application
+ * event log in case the regular syslog is not available
+ * mainly during startup. It should not be used under normal
+ * circumstances.
+ */
+void
+NTReportError(const char *name, const char *str) {
+ HANDLE hNTAppLog = NULL;
+ const char *buf[1];
+
+ buf[0] = str;
+
+ hNTAppLog = RegisterEventSource(NULL, name);
+
+ ReportEvent(hNTAppLog, EVENTLOG_ERROR_TYPE, 0, BIND_ERR_MSG, NULL, 1, 0,
+ buf, NULL);
+
+ DeregisterEventSource(hNTAppLog);
+}
diff --git a/lib/isc/win32/syslog.h b/lib/isc/win32/syslog.h
new file mode 100644
index 0000000..e785144
--- /dev/null
+++ b/lib/isc/win32/syslog.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+#include <stdio.h>
+
+/* Constant definitions for openlog() */
+#define LOG_PID 1
+#define LOG_CONS 2
+/* NT event log does not support facility level */
+#define LOG_KERN 0
+#define LOG_USER 0
+#define LOG_MAIL 0
+#define LOG_DAEMON 0
+#define LOG_AUTH 0
+#define LOG_SYSLOG 0
+#define LOG_LPR 0
+#define LOG_LOCAL0 0
+#define LOG_LOCAL1 0
+#define LOG_LOCAL2 0
+#define LOG_LOCAL3 0
+#define LOG_LOCAL4 0
+#define LOG_LOCAL5 0
+#define LOG_LOCAL6 0
+#define LOG_LOCAL7 0
+
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but signification condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+void
+syslog(int level, const char *fmt, ...);
+
+void
+openlog(const char *, int, ...);
+
+void
+closelog(void);
+
+void
+ModifyLogLevel(int level);
+
+void
+InitNTLogging(FILE *, int);
+
+void
+NTReportError(const char *, const char *);
+/*
+ * Include the event codes required for logging.
+ */
+#include <isc/bindevt.h>
+
+#endif /* ifndef _SYSLOG_H */
diff --git a/lib/isc/win32/thread.c b/lib/isc/win32/thread.c
new file mode 100644
index 0000000..e373e75
--- /dev/null
+++ b/lib/isc/win32/thread.c
@@ -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.
+ */
+
+#include <process.h>
+
+#include <isc/mutex.h>
+#include <isc/once.h>
+#include <isc/strerr.h>
+#include <isc/thread.h>
+#include <isc/util.h>
+
+#include "trampoline_p.h"
+
+void
+isc_thread_create(isc_threadfunc_t start, isc_threadarg_t arg,
+ isc_thread_t *threadp) {
+ isc_thread_t thread;
+ unsigned int id;
+ isc__trampoline_t *trampoline_arg;
+
+ trampoline_arg = isc__trampoline_get(start, arg);
+
+ thread = (isc_thread_t)_beginthreadex(NULL, 0, isc__trampoline_run,
+ trampoline_arg, 0, &id);
+ if (thread == NULL) {
+ char strbuf[ISC_STRERRORSIZE];
+ strerror_r(errno, strbuf, sizeof(strbuf));
+ isc_error_fatal(__FILE__, __LINE__, "_beginthreadex failed: %s",
+ strbuf);
+ }
+
+ *threadp = thread;
+
+ return;
+}
+
+void
+isc_thread_join(isc_thread_t thread, isc_threadresult_t *rp) {
+ DWORD result;
+
+ result = WaitForSingleObject(thread, INFINITE);
+ if (result != WAIT_OBJECT_0) {
+ isc_error_fatal(__FILE__, __LINE__,
+ "WaitForSingleObject() != WAIT_OBJECT_0");
+ }
+ if (rp != NULL && !GetExitCodeThread(thread, rp)) {
+ isc_error_fatal(__FILE__, __LINE__,
+ "GetExitCodeThread() failed: %d",
+ GetLastError());
+ }
+ (void)CloseHandle(thread);
+}
+
+void
+isc_thread_setconcurrency(unsigned int level) {
+ /*
+ * This is unnecessary on Win32 systems, but is here so that the
+ * call exists
+ */
+}
+
+void
+isc_thread_setname(isc_thread_t thread, const char *name) {
+ UNUSED(thread);
+ UNUSED(name);
+}
+
+isc_result_t
+isc_thread_setaffinity(int cpu) {
+ /* no-op on Windows for now */
+ return (ISC_R_SUCCESS);
+}
diff --git a/lib/isc/win32/time.c b/lib/isc/win32/time.c
new file mode 100644
index 0000000..c29edd3
--- /dev/null
+++ b/lib/isc/win32/time.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <windows.h>
+
+#include <isc/assertions.h>
+#include <isc/once.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/tm.h>
+#include <isc/util.h>
+
+/*
+ * struct FILETIME uses "100-nanoseconds intervals".
+ * NS / S = 1000000000 (10^9).
+ * While it is reasonably obvious that this makes the needed
+ * conversion factor 10^7, it is coded this way for additional clarity.
+ */
+#define NS_PER_S 1000000000
+#define NS_INTERVAL 100
+#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL)
+
+/***
+ *** Absolute Times
+ ***/
+
+static const isc_time_t epoch = { { 0, 0 } };
+LIBISC_EXTERNAL_DATA const isc_time_t *const isc_time_epoch = &epoch;
+
+/***
+ *** Intervals
+ ***/
+
+static const isc_interval_t zero_interval = { 0 };
+LIBISC_EXTERNAL_DATA const isc_interval_t *const isc_interval_zero =
+ &zero_interval;
+
+void
+isc_interval_set(isc_interval_t *i, unsigned int seconds,
+ unsigned int nanoseconds) {
+ REQUIRE(i != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ /*
+ * This rounds nanoseconds up not down.
+ */
+ i->interval = (LONGLONG)seconds * INTERVALS_PER_S +
+ (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL;
+}
+
+bool
+isc_interval_iszero(const isc_interval_t *i) {
+ REQUIRE(i != NULL);
+ if (i->interval == 0) {
+ return (true);
+ }
+
+ return (false);
+}
+
+void
+isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
+ SYSTEMTIME epoch1970 = { 1970, 1, 4, 1, 0, 0, 0, 0 };
+ FILETIME temp;
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL);
+ REQUIRE(nanoseconds < NS_PER_S);
+
+ SystemTimeToFileTime(&epoch1970, &temp);
+
+ i1.LowPart = temp.dwLowDateTime;
+ i1.HighPart = temp.dwHighDateTime;
+
+ /* cppcheck-suppress unreadVariable */
+ i1.QuadPart += (unsigned __int64)nanoseconds / 100;
+ /* cppcheck-suppress unreadVariable */
+ i1.QuadPart += (unsigned __int64)seconds * 10000000;
+
+ t->absolute.dwLowDateTime = i1.LowPart;
+ t->absolute.dwHighDateTime = i1.HighPart;
+}
+
+void
+isc_time_settoepoch(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ t->absolute.dwLowDateTime = 0;
+ t->absolute.dwHighDateTime = 0;
+}
+
+bool
+isc_time_isepoch(const isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ if (t->absolute.dwLowDateTime == 0 && t->absolute.dwHighDateTime == 0) {
+ return (true);
+ }
+
+ return (false);
+}
+
+isc_result_t
+isc_time_now(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ GetSystemTimeAsFileTime(&t->absolute);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_now_hires(isc_time_t *t) {
+ REQUIRE(t != NULL);
+
+ GetSystemTimePreciseAsFileTime(&t->absolute);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL);
+ REQUIRE(i != NULL);
+
+ GetSystemTimeAsFileTime(&t->absolute);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+
+ if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) {
+ return (ISC_R_RANGE);
+ }
+
+ /* cppcheck-suppress unreadVariable */
+ i1.QuadPart += i->interval;
+
+ t->absolute.dwLowDateTime = i1.LowPart;
+ t->absolute.dwHighDateTime = i1.HighPart;
+
+ return (ISC_R_SUCCESS);
+}
+
+int
+isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
+ REQUIRE(t1 != NULL && t2 != NULL);
+
+ return ((int)CompareFileTime(&t1->absolute, &t2->absolute));
+}
+
+isc_result_t
+isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) {
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+
+ if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) {
+ return (ISC_R_RANGE);
+ }
+
+ /* cppcheck-suppress unreadVariable */
+ i1.QuadPart += i->interval;
+
+ result->absolute.dwLowDateTime = i1.LowPart;
+ result->absolute.dwHighDateTime = i1.HighPart;
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
+ isc_time_t *result) {
+ ULARGE_INTEGER i1;
+
+ REQUIRE(t != NULL && i != NULL && result != NULL);
+
+ i1.LowPart = t->absolute.dwLowDateTime;
+ i1.HighPart = t->absolute.dwHighDateTime;
+
+ if (i1.QuadPart < (unsigned __int64)i->interval) {
+ return (ISC_R_RANGE);
+ }
+
+ /* cppcheck-suppress unreadVariable */
+ i1.QuadPart -= i->interval;
+
+ result->absolute.dwLowDateTime = i1.LowPart;
+ result->absolute.dwHighDateTime = i1.HighPart;
+
+ return (ISC_R_SUCCESS);
+}
+
+uint64_t
+isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
+ ULARGE_INTEGER i1, i2;
+ LONGLONG i3;
+
+ REQUIRE(t1 != NULL && t2 != NULL);
+
+ /* cppcheck-suppress unreadVariable */
+ i1.LowPart = t1->absolute.dwLowDateTime;
+ /* cppcheck-suppress unreadVariable */
+ i1.HighPart = t1->absolute.dwHighDateTime;
+ /* cppcheck-suppress unreadVariable */
+ i2.LowPart = t2->absolute.dwLowDateTime;
+ /* cppcheck-suppress unreadVariable */
+ i2.HighPart = t2->absolute.dwHighDateTime;
+
+ if (i1.QuadPart <= i2.QuadPart) {
+ return (0);
+ }
+
+ /*
+ * Convert to microseconds.
+ */
+ i3 = (i1.QuadPart - i2.QuadPart) / 10;
+
+ return (i3);
+}
+
+uint32_t
+isc_time_seconds(const isc_time_t *t) {
+ SYSTEMTIME epoch1970 = { 1970, 1, 4, 1, 0, 0, 0, 0 };
+ FILETIME temp;
+ ULARGE_INTEGER i1, i2;
+ LONGLONG i3;
+
+ SystemTimeToFileTime(&epoch1970, &temp);
+
+ /* cppcheck-suppress unreadVariable */
+ i1.LowPart = t->absolute.dwLowDateTime;
+ /* cppcheck-suppress unreadVariable */
+ i1.HighPart = t->absolute.dwHighDateTime;
+ /* cppcheck-suppress unreadVariable */
+ i2.LowPart = temp.dwLowDateTime;
+ /* cppcheck-suppress unreadVariable */
+ i2.HighPart = temp.dwHighDateTime;
+
+ i3 = (i1.QuadPart - i2.QuadPart) / 10000000;
+
+ return ((uint32_t)i3);
+}
+
+isc_result_t
+isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
+ time_t seconds;
+
+ REQUIRE(t != NULL);
+
+ seconds = (time_t)isc_time_seconds(t);
+
+ INSIST(sizeof(unsigned int) == sizeof(uint32_t));
+ INSIST(sizeof(time_t) >= sizeof(uint32_t));
+
+ if (isc_time_seconds(t) > (~0U >> 1) && seconds <= (time_t)(~0U >> 1)) {
+ return (ISC_R_RANGE);
+ }
+
+ *secondsp = seconds;
+
+ return (ISC_R_SUCCESS);
+}
+
+uint32_t
+isc_time_nanoseconds(const isc_time_t *t) {
+ ULARGE_INTEGER i;
+
+ i.LowPart = t->absolute.dwLowDateTime;
+ i.HighPart = t->absolute.dwHighDateTime;
+ return ((uint32_t)(i.QuadPart % 10000000) * 100);
+}
+
+void
+isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ FILETIME localft;
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToLocalFileTime(&t->absolute, &localft) &&
+ FileTimeToSystemTime(&localft, &st))
+ {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ NULL, TimeBuf, 50);
+
+ snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf,
+ st.wMilliseconds);
+ } else {
+ strlcpy(buf, "99-Bad-9999 99:99:99.999", len);
+ }
+}
+
+void
+isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "ddd',' dd MMM yyyy",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+
+ snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+isc_result_t
+isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
+ struct tm t_tm;
+ time_t when;
+ char *p;
+
+ REQUIRE(buf != NULL);
+ REQUIRE(t != NULL);
+
+ p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
+ if (p == NULL) {
+ return (ISC_R_UNEXPECTED);
+ }
+ when = isc_tm_timegm(&t_tm);
+ if (when == -1) {
+ return (ISC_R_UNEXPECTED);
+ }
+ isc_time_set(t, (unsigned int)when, 0);
+ return (ISC_R_SUCCESS);
+}
+
+void
+isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%s", DateBuf, TimeBuf);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSS" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%s.%03u", DateBuf, TimeBuf,
+ st.wMilliseconds);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601Lus(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSSSSS" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ ULARGE_INTEGER i;
+
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "yyyy-MM-dd",
+ DateBuf, 50);
+ GetTimeFormat(LOCALE_USER_DEFAULT,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+ i.LowPart = t->absolute.dwLowDateTime;
+ i.HighPart = t->absolute.dwHighDateTime;
+ snprintf(buf, len, "%sT%s.%06u", DateBuf, TimeBuf,
+ (uint32_t)(i.QuadPart % 10000000) / 10);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", DateBuf,
+ 50);
+ GetTimeFormat(LOCALE_NEUTRAL,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%sZ", DateBuf, TimeBuf);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSSZ" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", DateBuf,
+ 50);
+ GetTimeFormat(LOCALE_NEUTRAL,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+ snprintf(buf, len, "%sT%s.%03uZ", DateBuf, TimeBuf,
+ st.wMilliseconds);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y-%m-%dT%H:%M:%S.SSSSSSZ" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ ULARGE_INTEGER i;
+
+ GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", DateBuf,
+ 50);
+ GetTimeFormat(LOCALE_NEUTRAL,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hh':'mm':'ss", TimeBuf, 50);
+ i.LowPart = t->absolute.dwLowDateTime;
+ i.HighPart = t->absolute.dwHighDateTime;
+ snprintf(buf, len, "%sT%s.%06uZ", DateBuf, TimeBuf,
+ (uint32_t)(i.QuadPart % 10000000) / 10);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+void
+isc_time_formatshorttimestamp(const isc_time_t *t, char *buf,
+ unsigned int len) {
+ SYSTEMTIME st;
+ char DateBuf[50];
+ char TimeBuf[50];
+
+ /* strtime() format: "%Y%m%d%H%M%SSSS" */
+
+ REQUIRE(t != NULL);
+ REQUIRE(buf != NULL);
+ REQUIRE(len > 0);
+
+ if (FileTimeToSystemTime(&t->absolute, &st)) {
+ GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyyMMdd", DateBuf, 50);
+ GetTimeFormat(LOCALE_NEUTRAL,
+ TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, &st,
+ "hhmmss", TimeBuf, 50);
+ snprintf(buf, len, "%s%s%03u", DateBuf, TimeBuf,
+ st.wMilliseconds);
+ } else {
+ buf[0] = 0;
+ }
+}
+
+/*
+ * POSIX Shims
+ */
+
+struct tm *
+gmtime_r(const time_t *clock, struct tm *result) {
+ errno_t ret = gmtime_s(result, clock);
+ if (ret != 0) {
+ errno = ret;
+ return (NULL);
+ }
+ return (result);
+}
+
+struct tm *
+localtime_r(const time_t *clock, struct tm *result) {
+ errno_t ret = localtime_s(result, clock);
+ if (ret != 0) {
+ errno = ret;
+ return (NULL);
+ }
+ return (result);
+}
+
+#define BILLION 1000000000
+
+static isc_once_t nsec_ticks_once = ISC_ONCE_INIT;
+static double nsec_ticks = 0;
+
+static void
+nsec_ticks_init(void) {
+ LARGE_INTEGER ticks;
+ RUNTIME_CHECK(QueryPerformanceFrequency(&ticks) != 0);
+ nsec_ticks = (double)ticks.QuadPart / 1000000000.0;
+ RUNTIME_CHECK(nsec_ticks != 0.0);
+}
+
+int
+nanosleep(const struct timespec *req, struct timespec *rem) {
+ int_fast64_t sleep_msec;
+ uint_fast64_t ticks, until;
+ LARGE_INTEGER before, after;
+
+ RUNTIME_CHECK(isc_once_do(&nsec_ticks_once, nsec_ticks_init) ==
+ ISC_R_SUCCESS);
+
+ if (req->tv_nsec < 0 || BILLION <= req->tv_nsec) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* Sleep() is not interruptible; there is no remaining delay ever */
+ if (rem != NULL) {
+ rem->tv_sec = 0;
+ rem->tv_nsec = 0;
+ }
+
+ if (req->tv_sec >= 0) {
+ /*
+ * For requested delays of one second or more, 15ms resolution
+ * granularity is sufficient.
+ */
+ Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000);
+
+ return (0);
+ }
+
+ /* Sleep has <-8,8> ms precision, so substract 10 milliseconds */
+ sleep_msec = (int64_t)req->tv_nsec / 1000000 - 10;
+ ticks = req->tv_nsec * nsec_ticks;
+
+ RUNTIME_CHECK(QueryPerformanceCounter(&before) != 0);
+
+ until = before.QuadPart + ticks;
+
+ if (sleep_msec > 0) {
+ Sleep(sleep_msec);
+ }
+
+ while (true) {
+ LARGE_INTEGER after;
+ RUNTIME_CHECK(QueryPerformanceCounter(&after) != 0);
+ if (after.QuadPart >= until) {
+ break;
+ }
+ }
+
+done:
+ return (0);
+}
+
+int
+usleep(useconds_t useconds) {
+ struct timespec req;
+
+ req.tv_sec = useconds / 1000000;
+ req.tv_nsec = (useconds * 1000) % 1000000000;
+
+ nanosleep(&req, NULL);
+
+ return (0);
+}
diff --git a/lib/isc/win32/unistd.h b/lib/isc/win32/unistd.h
new file mode 100644
index 0000000..e1aff40
--- /dev/null
+++ b/lib/isc/win32/unistd.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.
+ */
+
+/* None of these are defined in NT, so define them for our use */
+#define O_NONBLOCK 1
+#define PORT_NONBLOCK O_NONBLOCK
+
+/*
+ * fcntl() commands
+ */
+#define F_SETFL 0
+#define F_GETFL 1
+#define F_SETFD 2
+#define F_GETFD 3
+/*
+ * Enough problems not having full fcntl() without worrying about this!
+ */
+#undef F_DUPFD
+
+int
+fcntl(int, int, ...);
+
+/*
+ * access() related definitions for winXP
+ */
+#include <io.h>
+#ifndef F_OK
+#define F_OK 0
+#endif /* ifndef F_OK */
+
+#ifndef X_OK
+#define X_OK 1
+#endif /* ifndef X_OK */
+
+#ifndef W_OK
+#define W_OK 2
+#endif /* ifndef W_OK */
+
+#ifndef R_OK
+#define R_OK 4
+#endif /* ifndef R_OK */
+
+#define access _access
+
+#include <process.h>
diff --git a/lib/isc/win32/version.c b/lib/isc/win32/version.c
new file mode 100644
index 0000000..b49347f
--- /dev/null
+++ b/lib/isc/win32/version.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <versions.h>
+
+#include <isc/version.h>
+
+LIBISC_EXTERNAL_DATA const char isc_version[] = VERSION;
diff --git a/lib/isc/win32/win32os.c b/lib/isc/win32/win32os.c
new file mode 100644
index 0000000..4f86d38
--- /dev/null
+++ b/lib/isc/win32/win32os.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <windows.h>
+
+#ifndef TESTVERSION
+#include <isc/win32os.h>
+#else /* ifndef TESTVERSION */
+#include <stdio.h>
+
+#include <isc/util.h>
+#endif /* ifndef TESTVERSION */
+#include <isc/print.h>
+
+int
+isc_win32os_versioncheck(unsigned int major, unsigned int minor,
+ unsigned int spmajor, unsigned int spminor) {
+ OSVERSIONINFOEX osVer;
+ DWORD typeMask;
+ ULONGLONG conditionMask;
+
+ memset(&osVer, 0, sizeof(OSVERSIONINFOEX));
+ osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ typeMask = 0;
+ conditionMask = 0;
+
+ /* Optimistic: likely greater */
+ osVer.dwMajorVersion = major;
+ typeMask |= VER_MAJORVERSION;
+ conditionMask = VerSetConditionMask(conditionMask, VER_MAJORVERSION,
+ VER_GREATER);
+ osVer.dwMinorVersion = minor;
+ typeMask |= VER_MINORVERSION;
+ conditionMask = VerSetConditionMask(conditionMask, VER_MINORVERSION,
+ VER_GREATER);
+ osVer.wServicePackMajor = spmajor;
+ typeMask |= VER_SERVICEPACKMAJOR;
+ conditionMask = VerSetConditionMask(conditionMask, VER_SERVICEPACKMAJOR,
+ VER_GREATER);
+ osVer.wServicePackMinor = spminor;
+ typeMask |= VER_SERVICEPACKMINOR;
+ conditionMask = VerSetConditionMask(conditionMask, VER_SERVICEPACKMINOR,
+ VER_GREATER);
+ if (VerifyVersionInfo(&osVer, typeMask, conditionMask)) {
+ return (1);
+ }
+
+ /* Failed: retry with equal */
+ conditionMask = 0;
+ conditionMask = VerSetConditionMask(conditionMask, VER_MAJORVERSION,
+ VER_EQUAL);
+ conditionMask = VerSetConditionMask(conditionMask, VER_MINORVERSION,
+ VER_EQUAL);
+ conditionMask = VerSetConditionMask(conditionMask, VER_SERVICEPACKMAJOR,
+ VER_EQUAL);
+ conditionMask = VerSetConditionMask(conditionMask, VER_SERVICEPACKMINOR,
+ VER_EQUAL);
+ if (VerifyVersionInfo(&osVer, typeMask, conditionMask)) {
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+#ifdef TESTVERSION
+int
+main(int argc, char **argv) {
+ unsigned int major = 0;
+ unsigned int minor = 0;
+ unsigned int spmajor = 0;
+ unsigned int spminor = 0;
+ int ret;
+
+ if (argc > 1) {
+ --argc;
+ ++argv;
+ major = (unsigned int)atoi(argv[0]);
+ }
+ if (argc > 1) {
+ --argc;
+ ++argv;
+ minor = (unsigned int)atoi(argv[0]);
+ }
+ if (argc > 1) {
+ --argc;
+ ++argv;
+ spmajor = (unsigned int)atoi(argv[0]);
+ }
+ if (argc > 1) {
+ --argc;
+ POST(argc);
+ ++argv;
+ spminor = (unsigned int)atoi(argv[0]);
+ }
+
+ ret = isc_win32os_versioncheck(major, minor, spmajor, spminor);
+
+ printf("%s major %u minor %u SP major %u SP minor %u\n",
+ ret > 0 ? "greater" : (ret == 0 ? "equal" : "less"), major,
+ minor, spmajor, spminor);
+ return (ret);
+}
+#endif /* ifdef TESTVERSION */