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)
190 lines
4.3 KiB
C
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 */
|