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