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
isc_uv_udp_connect(uv_udp_t * handle,const struct sockaddr * addr)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
uv_tcp_close_reset(uv_tcp_t * handle,uv_close_cb close_cb)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
isc_uv_udp_freebind(uv_udp_t * handle,const struct sockaddr * addr,unsigned int flags)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
isc__uv_tcp_bind_now(uv_tcp_t * handle,const struct sockaddr * addr,unsigned int flags)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
isc_uv_tcp_freebind(uv_tcp_t * handle,const struct sockaddr * addr,unsigned int flags)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