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