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