WIP: Add isc_work_queue() to replace isc_nm_offload_work() - but don't use it yet
This commit is contained in:
124
lib/isc/include/isc/uv.h
Normal file
124
lib/isc/include/isc/uv.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 <stdbool.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include <isc/result.h>
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
||||
|
||||
#if !defined(UV__ERR)
|
||||
#define UV__ERR(x) (-(x))
|
||||
#endif
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 19, 0)
|
||||
static inline void *
|
||||
uv_handle_get_data(const uv_handle_t *handle) {
|
||||
return (handle->data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uv_handle_set_data(uv_handle_t *handle, void *data) {
|
||||
handle->data = data;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
uv_req_get_data(const uv_req_t *req) {
|
||||
return (req->data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uv_req_set_data(uv_req_t *req, void *data) {
|
||||
req->data = data;
|
||||
}
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 19, 0) */
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 32, 0)
|
||||
int
|
||||
uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb);
|
||||
#endif
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 34, 0)
|
||||
#define uv_sleep(msec) usleep(msec * 1000)
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 34, 0) */
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 27, 0)
|
||||
int
|
||||
isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
|
||||
/*%<
|
||||
* Associate the UDP handle to a remote address and port, so every message sent
|
||||
* by this handle is automatically sent to that destination.
|
||||
*
|
||||
* NOTE: This is just a limited shim for uv_udp_connect() as it requires the
|
||||
* handle to be bound.
|
||||
*/
|
||||
#else /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
|
||||
#define isc_uv_udp_connect uv_udp_connect
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 12, 0)
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline int
|
||||
uv_os_getenv(const char *name, char *buffer, size_t *size) {
|
||||
size_t len;
|
||||
char *buf = getenv(name);
|
||||
|
||||
if (buf == NULL) {
|
||||
return (UV_ENOENT);
|
||||
}
|
||||
|
||||
len = strlen(buf) + 1;
|
||||
if (len > *size) {
|
||||
*size = len;
|
||||
return (UV_ENOBUFS);
|
||||
}
|
||||
|
||||
*size = len;
|
||||
memmove(buffer, buf, len);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define uv_os_setenv(name, value) setenv(name, value, 0)
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 12, 0) */
|
||||
|
||||
int
|
||||
isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags);
|
||||
|
||||
int
|
||||
isc_uv_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags);
|
||||
|
||||
#define isc__nm_uverr2result(x) \
|
||||
isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
|
||||
isc_result_t
|
||||
isc___nm_uverr2result(int uverr, bool dolog, const char *file,
|
||||
unsigned int line, const char *func);
|
||||
|
||||
/* FIXME: Deduplicate with netmgr-int.h */
|
||||
#define UV_RUNTIME_CHECK(func, ret) \
|
||||
if (ret != 0) { \
|
||||
isc_error_fatal(__FILE__, __LINE__, "%s failed: %s\n", #func, \
|
||||
uv_strerror(ret)); \
|
||||
}
|
||||
21
lib/isc/include/isc/work.h
Normal file
21
lib/isc/include/isc/work.h
Normal file
@@ -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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <isc/lang.h>
|
||||
#include <isc/loop.h>
|
||||
|
||||
void
|
||||
isc_queue_work(isc_loop_t *loop, isc_work_cb work_cb,
|
||||
isc_after_work_cb after_work_cb, void *cbarg);
|
||||
@@ -11,12 +11,10 @@
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include "uv-compat.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#include <isc/util.h>
|
||||
|
||||
#include "netmgr-int.h"
|
||||
#include <isc/uv.h>
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 27, 0)
|
||||
int
|
||||
@@ -60,6 +58,50 @@ uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb) {
|
||||
}
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 32, 0) */
|
||||
|
||||
#define setsockopt_on(socket, level, name) \
|
||||
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
|
||||
|
||||
static isc_result_t
|
||||
isc__socket_freebind(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
/*
|
||||
* Set the IP_FREEBIND (or equivalent option) on the uv_handle.
|
||||
*/
|
||||
#ifdef IP_FREEBIND
|
||||
UNUSED(sa_family);
|
||||
if (setsockopt_on(fd, IPPROTO_IP, IP_FREEBIND) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#elif defined(IP_BINDANY) || defined(IPV6_BINDANY)
|
||||
if (sa_family == AF_INET) {
|
||||
#if defined(IP_BINDANY)
|
||||
if (setsockopt_on(fd, IPPROTO_IP, IP_BINDANY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
} else if (sa_family == AF_INET6) {
|
||||
#if defined(IPV6_BINDANY)
|
||||
if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_BINDANY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
#elif defined(SO_BINDANY)
|
||||
UNUSED(sa_family);
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_BINDANY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#else
|
||||
UNUSED(fd);
|
||||
UNUSED(sa_family);
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
@@ -73,7 +115,7 @@ isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
|
||||
r = uv_udp_bind(handle, addr, flags);
|
||||
if (r == UV_EADDRNOTAVAIL &&
|
||||
isc__nm_socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
isc__socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Retry binding with IP_FREEBIND (or equivalent option) if the
|
||||
@@ -125,7 +167,7 @@ isc_uv_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
|
||||
r = isc__uv_tcp_bind_now(handle, addr, flags);
|
||||
if (r == UV_EADDRNOTAVAIL &&
|
||||
isc__nm_socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
isc__socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Retry binding with IP_FREEBIND (or equivalent option) if the
|
||||
@@ -138,3 +180,85 @@ isc_uv_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Convert a libuv error value into an isc_result_t. The
|
||||
* list of supported error values is not complete; new users
|
||||
* of this function should add any expected errors that are
|
||||
* not already there.
|
||||
*/
|
||||
isc_result_t
|
||||
isc___nm_uverr2result(int uverr, bool dolog, const char *file,
|
||||
unsigned int line, const char *func) {
|
||||
switch (uverr) {
|
||||
case 0:
|
||||
return (ISC_R_SUCCESS);
|
||||
case UV_ENOTDIR:
|
||||
case UV_ELOOP:
|
||||
case UV_EINVAL: /* XXX sometimes this is not for files */
|
||||
case UV_ENAMETOOLONG:
|
||||
case UV_EBADF:
|
||||
return (ISC_R_INVALIDFILE);
|
||||
case UV_ENOENT:
|
||||
return (ISC_R_FILENOTFOUND);
|
||||
case UV_EAGAIN:
|
||||
return (ISC_R_NOCONN);
|
||||
case UV_EACCES:
|
||||
case UV_EPERM:
|
||||
return (ISC_R_NOPERM);
|
||||
case UV_EEXIST:
|
||||
return (ISC_R_FILEEXISTS);
|
||||
case UV_EIO:
|
||||
return (ISC_R_IOERROR);
|
||||
case UV_ENOMEM:
|
||||
return (ISC_R_NOMEMORY);
|
||||
case UV_ENFILE:
|
||||
case UV_EMFILE:
|
||||
return (ISC_R_TOOMANYOPENFILES);
|
||||
case UV_ENOSPC:
|
||||
return (ISC_R_DISCFULL);
|
||||
case UV_EPIPE:
|
||||
case UV_ECONNRESET:
|
||||
case UV_ECONNABORTED:
|
||||
return (ISC_R_CONNECTIONRESET);
|
||||
case UV_ENOTCONN:
|
||||
return (ISC_R_NOTCONNECTED);
|
||||
case UV_ETIMEDOUT:
|
||||
return (ISC_R_TIMEDOUT);
|
||||
case UV_ENOBUFS:
|
||||
return (ISC_R_NORESOURCES);
|
||||
case UV_EAFNOSUPPORT:
|
||||
return (ISC_R_FAMILYNOSUPPORT);
|
||||
case UV_ENETDOWN:
|
||||
return (ISC_R_NETDOWN);
|
||||
case UV_EHOSTDOWN:
|
||||
return (ISC_R_HOSTDOWN);
|
||||
case UV_ENETUNREACH:
|
||||
return (ISC_R_NETUNREACH);
|
||||
case UV_EHOSTUNREACH:
|
||||
return (ISC_R_HOSTUNREACH);
|
||||
case UV_EADDRINUSE:
|
||||
return (ISC_R_ADDRINUSE);
|
||||
case UV_EADDRNOTAVAIL:
|
||||
return (ISC_R_ADDRNOTAVAIL);
|
||||
case UV_ECONNREFUSED:
|
||||
return (ISC_R_CONNREFUSED);
|
||||
case UV_ECANCELED:
|
||||
return (ISC_R_CANCELED);
|
||||
case UV_EOF:
|
||||
return (ISC_R_EOF);
|
||||
case UV_EMSGSIZE:
|
||||
return (ISC_R_MAXSIZE);
|
||||
case UV_ENOTSUP:
|
||||
return (ISC_R_FAMILYNOSUPPORT);
|
||||
default:
|
||||
if (dolog) {
|
||||
UNEXPECTED_ERROR(
|
||||
file, line,
|
||||
"unable to convert libuv "
|
||||
"error code in %s to isc_result: %d: %s",
|
||||
func, uverr, uv_strerror(uverr));
|
||||
}
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
67
lib/isc/work.c
Normal file
67
lib/isc/work.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include <isc/loop.h>
|
||||
#include <isc/uv.h>
|
||||
#include <isc/work.h>
|
||||
|
||||
#include "loop_p.h"
|
||||
|
||||
static void
|
||||
isc__work_cb(uv_work_t *req) {
|
||||
isc_work_t *work = uv_req_get_data((uv_req_t *)req);
|
||||
|
||||
work->work_cb(work->cbarg);
|
||||
}
|
||||
|
||||
static void
|
||||
isc__after_work_cb(uv_work_t *req, int status) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc_work_t *work = uv_req_get_data((uv_req_t *)req);
|
||||
|
||||
if (status != 0) {
|
||||
result = isc__nm_uverr2result(status);
|
||||
}
|
||||
|
||||
work->after_work_cb(work->cbarg, result);
|
||||
|
||||
isc_mem_put(work->mctx, work, sizeof(*work));
|
||||
}
|
||||
|
||||
void
|
||||
isc_queue_work(isc_loop_t *loop, isc_work_cb work_cb,
|
||||
isc_after_work_cb after_work_cb, void *cbarg) {
|
||||
isc_work_t *work = NULL;
|
||||
int r;
|
||||
|
||||
REQUIRE(VALID_LOOP(loop));
|
||||
REQUIRE(work_cb != NULL);
|
||||
REQUIRE(after_work_cb != NULL);
|
||||
|
||||
work = isc_mem_get(loop->mctx, sizeof(*work));
|
||||
*work = (isc_work_t){
|
||||
.work_cb = work_cb,
|
||||
.after_work_cb = after_work_cb,
|
||||
.cbarg = cbarg,
|
||||
};
|
||||
isc_mem_attach(loop->mctx, &work->mctx);
|
||||
|
||||
uv_req_set_data((uv_req_t *)&work->work, work);
|
||||
|
||||
r = uv_queue_work(&loop->loop, &work->work, isc__work_cb,
|
||||
isc__after_work_cb);
|
||||
UV_RUNTIME_CHECK(uv_queue_work, r);
|
||||
}
|
||||
Reference in New Issue
Block a user