lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md.@O@ mem.@O@ mutexblock.@O@ \
netmgr/netmgr.@O@ netmgr/tcp.@O@ netmgr/udp.@O@ \
- netmgr/tcpdns.@O@ netmgr/uverr2result.@O@ \
+ netmgr/tcpdns.@O@ netmgr/uverr2result.@O@ netmgr/uv-compat.@O@ \
netaddr.@O@ netscope.@O@ nonce.@O@ openssl_shim.@O@ pool.@O@ \
parseint.@O@ portset.@O@ queue.@O@ quota.@O@ \
radix.@O@ random.@O@ ratelimiter.@O@ \
CWARNINGS =
# Alphabetically
-OBJS = netmgr.@O@ tcp.@O@ udp.@O@ tcpdns.@O@ uverr2result.@O@
+OBJS = netmgr.@O@ tcp.@O@ udp.@O@ tcpdns.@O@ uverr2result.@O@ uv-compat.@O@
# Alphabetically
-SRCS = netmgr.c tcp.c udp.c tcpdns.c uverr2result.c
+SRCS = netmgr.c tcp.c udp.c tcpdns.c uverr2result.c uv-compat.c
TARGETS = ${OBJS}
--- /dev/null
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <unistd.h>
+#include "uv-compat.h"
+
+/*
+ * XXXWPK: This code goes into libuv internals and it's platform dependent.
+ * It's ugly, we shouldn't do it, but the alternative with passing sockets
+ * over IPC sockets is even worse, and causes all kind of different
+ * problems. We should try to push these things upstream.
+ */
+
+#ifdef WIN32
+/* This code is adapted from libuv/src/win/internal.h */
+typedef enum {
+ UV__IPC_SOCKET_XFER_NONE = 0,
+ UV__IPC_SOCKET_XFER_TCP_CONNECTION,
+ UV__IPC_SOCKET_XFER_TCP_SERVER
+} uv__ipc_socket_xfer_type_t;
+
+typedef struct {
+ WSAPROTOCOL_INFOW socket_info;
+ uint32_t delayed_error;
+} uv__ipc_socket_xfer_info_t;
+
+int
+uv__tcp_xfer_import(uv_tcp_t *tcp, uv__ipc_socket_xfer_type_t xfer_type,
+ uv__ipc_socket_xfer_info_t *xfer_info);
+int
+uv__tcp_xfer_export(uv_tcp_t *handle, int pid,
+ uv__ipc_socket_xfer_info_t *xfer_info);
+
+int
+isc_uv_export(uv_stream_t *stream, isc_uv_stream_info_t *info) {
+ if (stream->type != UV_TCP) {
+ return (-1);
+ }
+ if (uv__tcp_xfer_export((uv_tcp_t *) stream, GetCurrentProcessId(),
+ &info->socket_info) == -1) {
+ return (-1);
+ }
+
+ info->type = UV_TCP;
+}
+
+int
+isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info) {
+ uv__ipc_socket_xfer_info_t xfer_info;
+
+ if (stream->type != UV_TCP || info->type != UV_TCP) {
+ return (-1);
+ }
+ xfer_info.socket_info = info->socket_info;
+
+ return (uv__tcp_xfer_import((uv_tcp_t *) stream,
+ UV__IPC_SOCKET_XFER_TCP_SERVER,
+ &xfer_info));
+}
+#else /* WIN32 */
+/* Adapted from libuv/src/unix/internal.h */
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+static int
+isc_uv__cloexec(int fd, int set) {
+ int r;
+
+ /*
+ * This #ifdef is taken directly from the libuv sources.
+ * We use FIOCLEX and FIONCLEX ioctl() calls when possible,
+ * but on some platforms are not implemented, or defined but
+ * not implemented correctly. On those, we use the FD_CLOEXEC
+ * fcntl() call, which adds extra system call overhead, but
+ * works.
+ */
+#if defined(_AIX) || \
+ defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__) || \
+ defined(__linux__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+ do {
+ r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
+ } while (r == -1 && errno == EINTR);
+#else /* FIOCLEX/FIONCLEX unsupported */
+ int flags;
+
+ do {
+ r = fcntl(fd, F_GETFD);
+ } while (r == -1 && errno == EINTR);
+
+ if (r == -1) {
+ return (-1);
+ }
+
+ if (!!(r & FD_CLOEXEC) == !!set) {
+ return (0);
+ }
+
+ if (set) {
+ flags = r | FD_CLOEXEC;
+ } else {
+ flags = r & ~FD_CLOEXEC;
+ }
+
+ do {
+ r = fcntl(fd, F_SETFD, flags);
+ } while (r == -1 && errno == EINTR);
+#endif /* FIOCLEX/FIONCLEX unsupported */
+
+ if (r != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+isc_uv_export(uv_stream_t *stream, isc_uv_stream_info_t *info) {
+ int oldfd, fd;
+ int err;
+
+ if (stream->type != UV_TCP) {
+ return (-1);
+ }
+ err = uv_fileno((uv_handle_t *) stream, (uv_os_fd_t *) &oldfd);
+
+ if (err != 0) {
+ return (err);
+ }
+
+ fd = dup(oldfd);
+ if (fd == -1) {
+ return (-1);
+ }
+
+ err = isc_uv__cloexec(fd, 1);
+ if (err != 0) {
+ close(fd);
+ return (err);
+ }
+
+ info->type = stream->type;
+ info->fd = fd;
+ return (0);
+}
+
+int
+isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info) {
+ if (info->type != UV_TCP) {
+ return (-1);
+ }
+
+ uv_tcp_t *tcp = (uv_tcp_t *) stream;
+ return (uv_tcp_open(tcp, info->fd));
+}
+#endif
#include <uv.h>
/*
- * Those functions were introduced in newer libuv, we still
+ * These functions were introduced in newer libuv, but we still
* want BIND9 compile on older ones so we emulate them.
* They're inline to avoid conflicts when running with a newer
* library version.
*/
#ifndef HAVE_UV_HANDLE_GET_DATA
-static inline void*
-uv_handle_get_data(const uv_handle_t* handle) {
- return (handle->data);
+static inline void *
+uv_handle_get_data(const uv_handle_t *handle) {
+ return (handle->data);
}
#endif
#ifndef HAVE_UV_HANDLE_SET_DATA
static inline void
-uv_handle_set_data(uv_handle_t* handle, void* data) {
- handle->data = data;
+uv_handle_set_data(uv_handle_t *handle, void *data) {
+ handle->data = data;
};
#endif
+
+/*
+ * These functions are not available in libuv, but they're very internal
+ * to libuv. We should try to get them merged upstream.
+ */
+
+/*
+ * A sane way to pass listening TCP socket to child threads, without using
+ * IPC (as the libuv example shows) but a version of the uv_export() and
+ * uv_import() functions that were unfortunately removed from libuv.
+ * This is based on the original libuv code.
+ */
+
+typedef struct isc_uv_stream_info_s isc_uv_stream_info_t;
+
+struct isc_uv_stream_info_s {
+ uv_handle_type type;
+#ifdef WIN32
+ WSAPROTOCOL_INFOW socket_info;
+#else
+ int fd;
+#endif
+};
+
+int
+isc_uv_export(uv_stream_t *stream, isc_uv_stream_info_t *info);
+/*%<
+ * Exports uv_stream_t as isc_uv_stream_info_t value, which could
+ * be used to initialize shared streams within the same process.
+ */
+
+int
+isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info);
+/*%<
+ * Imports uv_stream_info_t value into uv_stream_t to initialize a
+ * shared stream.
+ */
isc_timermgr_poke
isc_tm_timegm
isc_tm_strptime
+isc_uv_export
+isc_uv_import
isc_win32os_versioncheck
openlog
@IF PKCS11
<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" />
./lib/isc/netmgr/tcp.c C 2019,2020
./lib/isc/netmgr/tcpdns.c C 2019,2020
./lib/isc/netmgr/udp.c C 2019,2020
+./lib/isc/netmgr/uv-compat.c C 2020
./lib/isc/netmgr/uv-compat.h C 2019,2020
./lib/isc/netmgr/uverr2result.c C 2019,2020
./lib/isc/netscope.c C 2002,2004,2005,2006,2007,2016,2018,2019,2020
./win32utils/GeoIP.diff X 2013,2018,2019,2020
./win32utils/bind9.sln.in X 2013,2014,2015,2016,2017,2018,2019,2020
./win32utils/index.html HTML 2006,2007,2008,2012,2013,2014,2015,2016,2018,2019,2020
+./win32utils/libuv.diff X 2020
--- /dev/null
+To make TCP listening properly multithreaded, we need to have the
+uv_export() and uv_import() functions that were removed from libuv.
+The alternative is passing sockets over IPC, which is complicated and
+error prone.
+
+To make it simple, we export two internal functions from libuv; they will
+be used in lib/isc/netmgr/uv-compat.c by our versions of the uv_export()
+and uv_import() functions.
+
+diff --git a/src/win/internal.h b/src/win/internal.h
+index 058ddb8e..a9dc4168 100644
+--- a/src/win/internal.h
++++ b/src/win/internal.h
+@@ -92,11 +92,11 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
+ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
+
+-int uv__tcp_xfer_export(uv_tcp_t* handle,
++UV_EXTERN int uv__tcp_xfer_export(uv_tcp_t* handle,
+ int pid,
+ uv__ipc_socket_xfer_type_t* xfer_type,
+ uv__ipc_socket_xfer_info_t* xfer_info);
+-int uv__tcp_xfer_import(uv_tcp_t* tcp,
++UV_EXTERN int uv__tcp_xfer_import(uv_tcp_t* tcp,
+ uv__ipc_socket_xfer_type_t xfer_type,
+ uv__ipc_socket_xfer_info_t* xfer_info);
+