Files
bind9/lib/isc/netmgr/uv-compat.c
Witold Kręcicki 091117b7ae isc_uv_import must pass UV__IPC_SOCKET_XFER_TCP_CONNECTION, not SERVER.
As a leftover from old TCP accept code isc_uv_import passed TCP_SERVER
flag when importing a socket on Windows.
Since now we're importing/exporting accepted connections it needs to
pass TCP_CONNECTION flag.

(cherry picked from commit 801f7af6e9)
2020-06-03 23:27:24 +02:00

190 lines
4.3 KiB
C

/*
* 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 "uv-compat.h"
#include <unistd.h>
#include <isc/util.h>
#ifndef HAVE_UV_IMPORT
/*
* 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;
/*
* Needed to make sure that the internal structure that we pulled out of
* libuv hasn't changed.
*/
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 target_pid,
uv__ipc_socket_xfer_type_t *xfer_type,
uv__ipc_socket_xfer_info_t *xfer_info);
int
isc_uv_export(uv_stream_t *stream, isc_uv_stream_info_t *info) {
uv__ipc_socket_xfer_info_t xfer_info;
uv__ipc_socket_xfer_type_t xfer_type = UV__IPC_SOCKET_XFER_NONE;
/*
* Needed to make sure that the internal structure that we pulled
* out of libuv hasn't changed.
*/
RUNTIME_CHECK(sizeof(uv__ipc_socket_xfer_info_t) == 632);
if (stream->type != UV_TCP) {
return (-1);
}
int r = uv__tcp_xfer_export((uv_tcp_t *)stream, GetCurrentProcessId(),
&xfer_type, &xfer_info);
if (r != 0) {
return (r);
}
if (xfer_info.delayed_error != 0) {
return (xfer_info.delayed_error);
}
INSIST(xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION);
info->type = UV_TCP;
info->socket_info = xfer_info.socket_info;
return (0);
}
int
isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info) {
if (stream->type != UV_TCP || info->type != UV_TCP) {
return (-1);
}
return (uv__tcp_xfer_import(
(uv_tcp_t *)stream, UV__IPC_SOCKET_XFER_TCP_CONNECTION,
&(uv__ipc_socket_xfer_info_t){
.socket_info = info->socket_info }));
}
#else /* WIN32 */
/* Adapted from libuv/src/unix/internal.h */
#include <fcntl.h>
#include <sys/ioctl.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 /* ifdef WIN32 */
#endif /* ifndef HAVE_UV_IMPORT */