Home | History | Annotate | Line # | Download | only in netmgr
      1  1.1  christos /*	$NetBSD: uv-compat.c,v 1.1 2024/02/18 20:57:55 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  1.1  christos  *
      6  1.1  christos  * SPDX-License-Identifier: MPL-2.0
      7  1.1  christos  *
      8  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  1.1  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  1.1  christos  *
     12  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13  1.1  christos  * information regarding copyright ownership.
     14  1.1  christos  */
     15  1.1  christos 
     16  1.1  christos #include "uv-compat.h"
     17  1.1  christos #include <unistd.h>
     18  1.1  christos 
     19  1.1  christos #include <isc/util.h>
     20  1.1  christos 
     21  1.1  christos #include "netmgr-int.h"
     22  1.1  christos 
     23  1.1  christos #if UV_VERSION_HEX < UV_VERSION(1, 27, 0)
     24  1.1  christos int
     25  1.1  christos isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
     26  1.1  christos 	int err = 0;
     27  1.1  christos 
     28  1.1  christos 	do {
     29  1.1  christos 		int addrlen = (addr->sa_family == AF_INET)
     30  1.1  christos 				      ? sizeof(struct sockaddr_in)
     31  1.1  christos 				      : sizeof(struct sockaddr_in6);
     32  1.1  christos #ifdef WIN32
     33  1.1  christos 		err = connect(handle->socket, addr, addrlen);
     34  1.1  christos #else  /* WIN32 */
     35  1.1  christos 		err = connect(handle->io_watcher.fd, addr, addrlen);
     36  1.1  christos #endif /* WIN32 */
     37  1.1  christos 	} while (err == -1 && errno == EINTR);
     38  1.1  christos 
     39  1.1  christos 	if (err) {
     40  1.1  christos #ifdef WIN32
     41  1.1  christos 		return (uv_translate_sys_error(err));
     42  1.1  christos #else /* WIN32 */
     43  1.1  christos #if UV_VERSION_HEX >= UV_VERSION(1, 10, 0)
     44  1.1  christos 		return (uv_translate_sys_error(errno));
     45  1.1  christos #else
     46  1.1  christos 		return (-errno);
     47  1.1  christos #endif /* UV_VERSION_HEX >= UV_VERSION(1, 10, 0) */
     48  1.1  christos #endif /* WIN32 */
     49  1.1  christos 	}
     50  1.1  christos 
     51  1.1  christos 	return (0);
     52  1.1  christos }
     53  1.1  christos #endif /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
     54  1.1  christos 
     55  1.1  christos #if UV_VERSION_HEX < UV_VERSION(1, 32, 0)
     56  1.1  christos int
     57  1.1  christos uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb) {
     58  1.1  christos 	if (setsockopt(handle->io_watcher.fd, SOL_SOCKET, SO_LINGER,
     59  1.1  christos 		       &(struct linger){ 1, 0 }, sizeof(struct linger)) == -1)
     60  1.1  christos 	{
     61  1.1  christos #if UV_VERSION_HEX >= UV_VERSION(1, 10, 0)
     62  1.1  christos 		return (uv_translate_sys_error(errno));
     63  1.1  christos #else
     64  1.1  christos 		return (-errno);
     65  1.1  christos #endif /* UV_VERSION_HEX >= UV_VERSION(1, 10, 0) */
     66  1.1  christos 	}
     67  1.1  christos 
     68  1.1  christos 	uv_close((uv_handle_t *)handle, close_cb);
     69  1.1  christos 	return (0);
     70  1.1  christos }
     71  1.1  christos #endif /* UV_VERSION_HEX < UV_VERSION(1, 32, 0) */
     72  1.1  christos 
     73  1.1  christos int
     74  1.1  christos isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
     75  1.1  christos 		    unsigned int flags) {
     76  1.1  christos 	int r;
     77  1.1  christos 	uv_os_sock_t fd;
     78  1.1  christos 
     79  1.1  christos 	r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
     80  1.1  christos 	if (r < 0) {
     81  1.1  christos 		return (r);
     82  1.1  christos 	}
     83  1.1  christos 
     84  1.1  christos #if defined(WIN32)
     85  1.1  christos 	REQUIRE(fd != INVALID_SOCKET);
     86  1.1  christos #endif
     87  1.1  christos 
     88  1.1  christos 	r = uv_udp_bind(handle, addr, flags);
     89  1.1  christos 	if (r == UV_EADDRNOTAVAIL &&
     90  1.1  christos 	    isc__nm_socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
     91  1.1  christos 	{
     92  1.1  christos 		/*
     93  1.1  christos 		 * Retry binding with IP_FREEBIND (or equivalent option) if the
     94  1.1  christos 		 * address is not available. This helps with IPv6 tentative
     95  1.1  christos 		 * addresses which are reported by the route socket, although
     96  1.1  christos 		 * named is not yet able to properly bind to them.
     97  1.1  christos 		 */
     98  1.1  christos 		r = uv_udp_bind(handle, addr, flags);
     99  1.1  christos 	}
    100  1.1  christos 
    101  1.1  christos 	return (r);
    102  1.1  christos }
    103  1.1  christos 
    104  1.1  christos static int
    105  1.1  christos isc__uv_tcp_bind_now(uv_tcp_t *handle, const struct sockaddr *addr,
    106  1.1  christos 		     unsigned int flags) {
    107  1.1  christos 	int r;
    108  1.1  christos 	struct sockaddr_storage sname;
    109  1.1  christos 	int snamelen = sizeof(sname);
    110  1.1  christos 
    111  1.1  christos 	r = uv_tcp_bind(handle, addr, flags);
    112  1.1  christos 	if (r < 0) {
    113  1.1  christos 		return (r);
    114  1.1  christos 	}
    115  1.1  christos 
    116  1.1  christos 	/*
    117  1.1  christos 	 * uv_tcp_bind() uses a delayed error, initially returning
    118  1.1  christos 	 * success even if bind() fails. By calling uv_tcp_getsockname()
    119  1.1  christos 	 * here we can find out whether the bind() call was successful.
    120  1.1  christos 	 */
    121  1.1  christos 	r = uv_tcp_getsockname(handle, (struct sockaddr *)&sname, &snamelen);
    122  1.1  christos 	if (r < 0) {
    123  1.1  christos 		return (r);
    124  1.1  christos 	}
    125  1.1  christos 
    126  1.1  christos 	return (0);
    127  1.1  christos }
    128  1.1  christos 
    129  1.1  christos int
    130  1.1  christos isc_uv_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
    131  1.1  christos 		    unsigned int flags) {
    132  1.1  christos 	int r;
    133  1.1  christos 	uv_os_sock_t fd;
    134  1.1  christos 
    135  1.1  christos 	r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
    136  1.1  christos 	if (r < 0) {
    137  1.1  christos 		return (r);
    138  1.1  christos 	}
    139  1.1  christos 
    140  1.1  christos 	r = isc__uv_tcp_bind_now(handle, addr, flags);
    141  1.1  christos 	if (r == UV_EADDRNOTAVAIL &&
    142  1.1  christos 	    isc__nm_socket_freebind(fd, addr->sa_family) == ISC_R_SUCCESS)
    143  1.1  christos 	{
    144  1.1  christos 		/*
    145  1.1  christos 		 * Retry binding with IP_FREEBIND (or equivalent option) if the
    146  1.1  christos 		 * address is not available. This helps with IPv6 tentative
    147  1.1  christos 		 * addresses which are reported by the route socket, although
    148  1.1  christos 		 * named is not yet able to properly bind to them.
    149  1.1  christos 		 */
    150  1.1  christos 		r = isc__uv_tcp_bind_now(handle, addr, flags);
    151  1.1  christos 	}
    152  1.1  christos 
    153  1.1  christos 	return (r);
    154  1.1  christos }
    155