mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-04 08:35:31 +00:00
Move socket related functions to netmgr/socket.c
Move the netmgr socket related functions from netmgr/netmgr.c and netmgr/uv-compat.c to netmgr/socket.c, so they are all present all in the same place. Adjust the names of couple interal functions accordingly.
This commit is contained in:
@@ -103,6 +103,7 @@ libisc_la_SOURCES = \
|
||||
$(libisc_la_HEADERS) \
|
||||
netmgr/netmgr-int.h \
|
||||
netmgr/netmgr.c \
|
||||
netmgr/socket.c \
|
||||
netmgr/tcp.c \
|
||||
netmgr/tcpdns.c \
|
||||
netmgr/timer.c \
|
||||
|
@@ -1875,12 +1875,6 @@ isc__nm_closesocket(uv_os_sock_t sock);
|
||||
* Platform independent closesocket() version
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family);
|
||||
/*%<
|
||||
* Set the IP_FREEBIND (or equivalent) socket option on the uv_handle
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_reuse(uv_os_sock_t fd);
|
||||
/*%<
|
||||
@@ -2160,3 +2154,15 @@ isc__nmsocket_writetimeout_cb(void *data, isc_result_t eresult);
|
||||
isc_error_fatal(__FILE__, __LINE__, "%s failed: %s", #func, \
|
||||
uv_strerror(ret)); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind to the socket, but allow binding to IPv6 tentative addresses reported by
|
||||
* the route socket by setting IP_FREEBIND (or equivalent).
|
||||
*/
|
||||
int
|
||||
isc__nm_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags);
|
||||
|
||||
int
|
||||
isc__nm_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags);
|
||||
|
@@ -2978,213 +2978,6 @@ isc__nm_decstats(isc_nmsocket_t *sock, isc__nm_statid_t id) {
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp) {
|
||||
int sock = socket(domain, type, protocol);
|
||||
if (sock < 0) {
|
||||
return (isc_errno_toresult(errno));
|
||||
}
|
||||
|
||||
*sockp = (uv_os_sock_t)sock;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_closesocket(uv_os_sock_t sock) {
|
||||
close(sock);
|
||||
}
|
||||
|
||||
#define setsockopt_on(socket, level, name) \
|
||||
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
|
||||
|
||||
#define setsockopt_off(socket, level, name) \
|
||||
setsockopt(socket, level, name, &(int){ 0 }, sizeof(int))
|
||||
|
||||
isc_result_t
|
||||
isc__nm_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
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_reuse(uv_os_sock_t fd) {
|
||||
/*
|
||||
* Generally, the SO_REUSEADDR socket option allows reuse of
|
||||
* local addresses.
|
||||
*
|
||||
* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some
|
||||
* additional refinements for programs that use multicast.
|
||||
*
|
||||
* On Linux, SO_REUSEPORT has different semantics: it _shares_ the port
|
||||
* rather than steal it from the current listener, so we don't use it
|
||||
* here, but rather in isc__nm_socket_reuse_lb().
|
||||
*
|
||||
* On Windows, it also allows a socket to forcibly bind to a port in use
|
||||
* by another socket.
|
||||
*/
|
||||
|
||||
#if defined(SO_REUSEPORT) && !defined(__linux__)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#elif defined(SO_REUSEADDR)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEADDR) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#else
|
||||
UNUSED(fd);
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_reuse_lb(uv_os_sock_t fd) {
|
||||
/*
|
||||
* On FreeBSD 12+, SO_REUSEPORT_LB socket option allows sockets to be
|
||||
* bound to an identical socket address. For UDP sockets, the use of
|
||||
* this option can provide better distribution of incoming datagrams to
|
||||
* multiple processes (or threads) as compared to the traditional
|
||||
* technique of having multiple processes compete to receive datagrams
|
||||
* on the same socket.
|
||||
*
|
||||
* On Linux, the same thing is achieved simply with SO_REUSEPORT.
|
||||
*/
|
||||
#if defined(SO_REUSEPORT_LB)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT_LB) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && defined(__linux__)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_incoming_cpu(uv_os_sock_t fd) {
|
||||
#ifdef SO_INCOMING_CPU
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_INCOMING_CPU) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
/*
|
||||
* Disable the Path MTU Discovery on IP packets
|
||||
*/
|
||||
if (sa_family == AF_INET6) {
|
||||
#if defined(IPV6_DONTFRAG)
|
||||
if (setsockopt_off(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#elif defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
|
||||
&(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
} else if (sa_family == AF_INET) {
|
||||
#if defined(IP_DONTFRAG)
|
||||
if (setsockopt_off(fd, IPPROTO_IP, IP_DONTFRAG) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER,
|
||||
&(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
} else {
|
||||
return (ISC_R_FAMILYNOSUPPORT);
|
||||
}
|
||||
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_v6only(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
/*
|
||||
* Enable the IPv6-only option on IPv6 sockets
|
||||
*/
|
||||
if (sa_family == AF_INET6) {
|
||||
#if defined(IPV6_V6ONLY)
|
||||
if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_V6ONLY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
}
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type) {
|
||||
int proto, pf, addrlen, fd, r;
|
||||
@@ -3242,81 +3035,6 @@ isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type) {
|
||||
#define TIMEOUT_OPTNAME TCP_KEEPINIT
|
||||
#endif
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms) {
|
||||
#if defined(TIMEOUT_OPTNAME)
|
||||
TIMEOUT_TYPE timeout = timeout_ms / TIMEOUT_DIV;
|
||||
|
||||
if (timeout == 0) {
|
||||
timeout = 1;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, IPPROTO_TCP, TIMEOUT_OPTNAME, &timeout,
|
||||
sizeof(timeout)) == -1)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
#else
|
||||
UNUSED(fd);
|
||||
UNUSED(timeout_ms);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) {
|
||||
#ifdef TCP_NODELAY
|
||||
if (setsockopt_on(fd, IPPROTO_TCP, TCP_NODELAY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_tcp_maxseg(uv_os_sock_t fd, int size) {
|
||||
#ifdef TCP_MAXSEG
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (void *)&size,
|
||||
sizeof(size))) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
UNUSED(size);
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
if (sa_family != AF_INET6) {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#ifdef IPV6_USE_MIN_MTU
|
||||
if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#elif defined(IPV6_MTU)
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &(int){ 1280 },
|
||||
sizeof(int)) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle) {
|
||||
int32_t recv_buffer_size = 0;
|
||||
|
378
lib/isc/netmgr/socket.c
Normal file
378
lib/isc/netmgr/socket.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* 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/errno.h>
|
||||
|
||||
#include "netmgr-int.h"
|
||||
#include "uv-compat.h"
|
||||
|
||||
#define setsockopt_on(socket, level, name) \
|
||||
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
|
||||
|
||||
#define setsockopt_off(socket, level, name) \
|
||||
setsockopt(socket, level, name, &(int){ 0 }, sizeof(int))
|
||||
|
||||
static isc_result_t
|
||||
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__nm_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
uv_os_sock_t fd;
|
||||
|
||||
r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
r = uv_udp_bind(handle, addr, flags);
|
||||
if (r == UV_EADDRNOTAVAIL &&
|
||||
socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Retry binding with IP_FREEBIND (or equivalent option) if the
|
||||
* address is not available. This helps with IPv6 tentative
|
||||
* addresses which are reported by the route socket, although
|
||||
* named is not yet able to properly bind to them.
|
||||
*/
|
||||
r = uv_udp_bind(handle, addr, flags);
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_bind_now(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
struct sockaddr_storage sname;
|
||||
int snamelen = sizeof(sname);
|
||||
|
||||
r = uv_tcp_bind(handle, addr, flags);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
* uv_tcp_bind() uses a delayed error, initially returning
|
||||
* success even if bind() fails. By calling uv_tcp_getsockname()
|
||||
* here we can find out whether the bind() call was successful.
|
||||
*/
|
||||
r = uv_tcp_getsockname(handle, (struct sockaddr *)&sname, &snamelen);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
isc__nm_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
uv_os_sock_t fd;
|
||||
|
||||
r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
r = tcp_bind_now(handle, addr, flags);
|
||||
if (r == UV_EADDRNOTAVAIL &&
|
||||
socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Retry binding with IP_FREEBIND (or equivalent option) if the
|
||||
* address is not available. This helps with IPv6 tentative
|
||||
* addresses which are reported by the route socket, although
|
||||
* named is not yet able to properly bind to them.
|
||||
*/
|
||||
r = tcp_bind_now(handle, addr, flags);
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp) {
|
||||
int sock = socket(domain, type, protocol);
|
||||
if (sock < 0) {
|
||||
return (isc_errno_toresult(errno));
|
||||
}
|
||||
|
||||
*sockp = (uv_os_sock_t)sock;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_closesocket(uv_os_sock_t sock) {
|
||||
close(sock);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_reuse(uv_os_sock_t fd) {
|
||||
/*
|
||||
* Generally, the SO_REUSEADDR socket option allows reuse of
|
||||
* local addresses.
|
||||
*
|
||||
* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some
|
||||
* additional refinements for programs that use multicast.
|
||||
*
|
||||
* On Linux, SO_REUSEPORT has different semantics: it _shares_ the port
|
||||
* rather than steal it from the current listener, so we don't use it
|
||||
* here, but rather in isc__nm_socket_reuse_lb().
|
||||
*
|
||||
* On Windows, it also allows a socket to forcibly bind to a port in use
|
||||
* by another socket.
|
||||
*/
|
||||
|
||||
#if defined(SO_REUSEPORT) && !defined(__linux__)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#elif defined(SO_REUSEADDR)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEADDR) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
#else
|
||||
UNUSED(fd);
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_reuse_lb(uv_os_sock_t fd) {
|
||||
/*
|
||||
* On FreeBSD 12+, SO_REUSEPORT_LB socket option allows sockets to be
|
||||
* bound to an identical socket address. For UDP sockets, the use of
|
||||
* this option can provide better distribution of incoming datagrams to
|
||||
* multiple processes (or threads) as compared to the traditional
|
||||
* technique of having multiple processes compete to receive datagrams
|
||||
* on the same socket.
|
||||
*
|
||||
* On Linux, the same thing is achieved simply with SO_REUSEPORT.
|
||||
*/
|
||||
#if defined(SO_REUSEPORT_LB)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT_LB) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && defined(__linux__)
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_incoming_cpu(uv_os_sock_t fd) {
|
||||
#ifdef SO_INCOMING_CPU
|
||||
if (setsockopt_on(fd, SOL_SOCKET, SO_INCOMING_CPU) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
/*
|
||||
* Disable the Path MTU Discovery on IP packets
|
||||
*/
|
||||
if (sa_family == AF_INET6) {
|
||||
#if defined(IPV6_DONTFRAG)
|
||||
if (setsockopt_off(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#elif defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
|
||||
&(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
} else if (sa_family == AF_INET) {
|
||||
#if defined(IP_DONTFRAG)
|
||||
if (setsockopt_off(fd, IPPROTO_IP, IP_DONTFRAG) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER,
|
||||
&(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
} else {
|
||||
return (ISC_R_FAMILYNOSUPPORT);
|
||||
}
|
||||
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_v6only(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
/*
|
||||
* Enable the IPv6-only option on IPv6 sockets
|
||||
*/
|
||||
if (sa_family == AF_INET6) {
|
||||
#if defined(IPV6_V6ONLY)
|
||||
if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_V6ONLY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
}
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms) {
|
||||
#if defined(TIMEOUT_OPTNAME)
|
||||
TIMEOUT_TYPE timeout = timeout_ms / TIMEOUT_DIV;
|
||||
|
||||
if (timeout == 0) {
|
||||
timeout = 1;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, IPPROTO_TCP, TIMEOUT_OPTNAME, &timeout,
|
||||
sizeof(timeout)) == -1)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
#else
|
||||
UNUSED(fd);
|
||||
UNUSED(timeout_ms);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) {
|
||||
#ifdef TCP_NODELAY
|
||||
if (setsockopt_on(fd, IPPROTO_TCP, TCP_NODELAY) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_tcp_maxseg(uv_os_sock_t fd, int size) {
|
||||
#ifdef TCP_MAXSEG
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (void *)&size,
|
||||
sizeof(size))) {
|
||||
return (ISC_R_FAILURE);
|
||||
} else {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
UNUSED(size);
|
||||
return (ISC_R_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family) {
|
||||
if (sa_family != AF_INET6) {
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
#ifdef IPV6_USE_MIN_MTU
|
||||
if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#elif defined(IPV6_MTU)
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &(int){ 1280 },
|
||||
sizeof(int)) == -1) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#else
|
||||
UNUSED(fd);
|
||||
#endif
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
@@ -550,7 +550,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
if (mgr->load_balance_sockets) {
|
||||
r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
|
||||
r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
|
||||
&sock->iface.type.sa, flags);
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
@@ -558,7 +558,7 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
} else {
|
||||
if (sock->parent->fd == -1) {
|
||||
r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
|
||||
r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
|
||||
&sock->iface.type.sa, flags);
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
|
@@ -516,7 +516,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
if (mgr->load_balance_sockets) {
|
||||
r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
|
||||
r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
|
||||
&sock->iface.type.sa, flags);
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
@@ -524,7 +524,7 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
} else {
|
||||
if (sock->parent->fd == -1) {
|
||||
r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
|
||||
r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
|
||||
&sock->iface.type.sa, flags);
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
|
@@ -603,7 +603,7 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
if (mgr->load_balance_sockets) {
|
||||
r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
|
||||
r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
|
||||
&sock->iface.type.sa, flags);
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
@@ -611,7 +611,7 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
} else {
|
||||
if (sock->parent->fd == -1) {
|
||||
r = isc_uv_tcp_freebind(&sock->uv_handle.tcp,
|
||||
r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
|
||||
&sock->iface.type.sa, flags);
|
||||
if (r < 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
|
@@ -463,7 +463,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
}
|
||||
|
||||
if (mgr->load_balance_sockets) {
|
||||
r = isc_uv_udp_freebind(&sock->uv_handle.udp,
|
||||
r = isc__nm_udp_freebind(&sock->uv_handle.udp,
|
||||
&sock->parent->iface.type.sa,
|
||||
uv_bind_flags);
|
||||
if (r < 0) {
|
||||
@@ -473,7 +473,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
} else {
|
||||
if (sock->parent->fd == -1) {
|
||||
/* This thread is first, bind the socket */
|
||||
r = isc_uv_udp_freebind(&sock->uv_handle.udp,
|
||||
r = isc__nm_udp_freebind(&sock->uv_handle.udp,
|
||||
&sock->parent->iface.type.sa,
|
||||
uv_bind_flags);
|
||||
if (r < 0) {
|
||||
|
@@ -59,82 +59,3 @@ uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb) {
|
||||
return (0);
|
||||
}
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 32, 0) */
|
||||
|
||||
int
|
||||
isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
uv_os_sock_t fd;
|
||||
|
||||
r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
r = uv_udp_bind(handle, addr, flags);
|
||||
if (r == UV_EADDRNOTAVAIL &&
|
||||
isc__nm_socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Retry binding with IP_FREEBIND (or equivalent option) if the
|
||||
* address is not available. This helps with IPv6 tentative
|
||||
* addresses which are reported by the route socket, although
|
||||
* named is not yet able to properly bind to them.
|
||||
*/
|
||||
r = uv_udp_bind(handle, addr, flags);
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
isc__uv_tcp_bind_now(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
struct sockaddr_storage sname;
|
||||
int snamelen = sizeof(sname);
|
||||
|
||||
r = uv_tcp_bind(handle, addr, flags);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
* uv_tcp_bind() uses a delayed error, initially returning
|
||||
* success even if bind() fails. By calling uv_tcp_getsockname()
|
||||
* here we can find out whether the bind() call was successful.
|
||||
*/
|
||||
r = uv_tcp_getsockname(handle, (struct sockaddr *)&sname, &snamelen);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
isc_uv_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
|
||||
unsigned int flags) {
|
||||
int r;
|
||||
uv_os_sock_t fd;
|
||||
|
||||
r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
|
||||
if (r < 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
r = isc__uv_tcp_bind_now(handle, addr, flags);
|
||||
if (r == UV_EADDRNOTAVAIL &&
|
||||
isc__nm_socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
|
||||
{
|
||||
/*
|
||||
* Retry binding with IP_FREEBIND (or equivalent option) if the
|
||||
* address is not available. This helps with IPv6 tentative
|
||||
* addresses which are reported by the route socket, although
|
||||
* named is not yet able to properly bind to them.
|
||||
*/
|
||||
r = isc__uv_tcp_bind_now(handle, addr, flags);
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
@@ -116,11 +116,3 @@ uv_os_getenv(const char *name, char *buffer, size_t *size) {
|
||||
|
||||
#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);
|
||||
|
@@ -43,6 +43,7 @@
|
||||
|
||||
#include "../netmgr/http.c"
|
||||
#include "../netmgr/netmgr-int.h"
|
||||
#include "../netmgr/socket.c"
|
||||
#include "../netmgr/uv-compat.c"
|
||||
#include "../netmgr/uv-compat.h"
|
||||
#include "../netmgr_p.h"
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#define KEEP_BEFORE
|
||||
|
||||
#include "../netmgr/netmgr-int.h"
|
||||
#include "../netmgr/socket.c"
|
||||
#include "../netmgr/udp.c"
|
||||
#include "../netmgr/uv-compat.c"
|
||||
#include "../netmgr/uv-compat.h"
|
||||
|
Reference in New Issue
Block a user