1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #if HAVE_CMOCKA
15 #include <inttypes.h>
16 #include <sched.h> /* IWYU pragma: keep */
17 #include <setjmp.h>
18 #include <stdarg.h>
19 #include <stdbool.h>
20 #include <stddef.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <uv.h>
25 
26 #include <isc/atomic.h>
27 
28 #define UNIT_TESTING
29 #include <cmocka.h>
30 
31 #include "../netmgr/uv-compat.h"
32 
33 /* uv_udp_t */
34 
35 int
36 __wrap_uv_udp_open(uv_udp_t *handle, uv_os_sock_t sock);
37 int
38 __wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
39 		   unsigned int flags);
40 #if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
41 int
42 __wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
43 int
44 __wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
45 			  int *namelen);
46 #endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
47 int
48 __wrap_uv_udp_getsockname(const uv_udp_t *handle, struct sockaddr *name,
49 			  int *namelen);
50 int
51 __wrap_uv_udp_send(uv_udp_send_t *req, uv_udp_t *handle, const uv_buf_t bufs[],
52 		   unsigned int nbufs, const struct sockaddr *addr,
53 		   uv_udp_send_cb send_cb);
54 int
55 __wrap_uv_udp_recv_start(uv_udp_t *handle, uv_alloc_cb alloc_cb,
56 			 uv_udp_recv_cb recv_cb);
57 int
58 __wrap_uv_udp_recv_stop(uv_udp_t *handle);
59 
60 /* uv_tcp_t */
61 int
62 __wrap_uv_tcp_open(uv_tcp_t *handle, uv_os_sock_t sock);
63 int
64 __wrap_uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr,
65 		   unsigned int flags);
66 int
67 __wrap_uv_tcp_getsockname(const uv_tcp_t *handle, struct sockaddr *name,
68 			  int *namelen);
69 int
70 __wrap_uv_tcp_getpeername(const uv_tcp_t *handle, struct sockaddr *name,
71 			  int *namelen);
72 int
73 __wrap_uv_tcp_connect(uv_connect_t *req, uv_tcp_t *handle,
74 		      const struct sockaddr *addr, uv_connect_cb cb);
75 
76 /* uv_stream_t */
77 int
78 __wrap_uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb);
79 int
80 __wrap_uv_accept(uv_stream_t *server, uv_stream_t *client);
81 
82 /* uv_handle_t */
83 int
84 __wrap_uv_send_buffer_size(uv_handle_t *handle, int *value);
85 int
86 __wrap_uv_recv_buffer_size(uv_handle_t *handle, int *value);
87 int
88 __wrap_uv_fileno(const uv_handle_t *handle, uv_os_fd_t *fd);
89 
90 /* uv_timer_t */
91 /* FIXME */
92 /*
93  * uv_timer_init
94  * uv_timer_start
95  */
96 
97 static atomic_int __state_uv_udp_open = ATOMIC_VAR_INIT(0);
98 
99 int
__wrap_uv_udp_open(uv_udp_t * handle,uv_os_sock_t sock)100 __wrap_uv_udp_open(uv_udp_t *handle, uv_os_sock_t sock) {
101 	if (atomic_load(&__state_uv_udp_open) == 0) {
102 		return (uv_udp_open(handle, sock));
103 	}
104 	return (atomic_load(&__state_uv_udp_open));
105 }
106 
107 static atomic_int __state_uv_udp_bind = ATOMIC_VAR_INIT(0);
108 
109 int
__wrap_uv_udp_bind(uv_udp_t * handle,const struct sockaddr * addr,unsigned int flags)110 __wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
111 		   unsigned int flags) {
112 	if (atomic_load(&__state_uv_udp_bind) == 0) {
113 		return (uv_udp_bind(handle, addr, flags));
114 	}
115 	return (atomic_load(&__state_uv_udp_bind));
116 }
117 
118 static atomic_int __state_uv_udp_connect = ATOMIC_VAR_INIT(0);
119 #if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
120 int
__wrap_uv_udp_connect(uv_udp_t * handle,const struct sockaddr * addr)121 __wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
122 	if (atomic_load(&__state_uv_udp_connect) == 0) {
123 		return (uv_udp_connect(handle, addr));
124 	}
125 	return (atomic_load(&__state_uv_udp_connect));
126 }
127 #endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
128 
129 static atomic_int __state_uv_udp_getpeername = ATOMIC_VAR_INIT(0);
130 #if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
131 int
__wrap_uv_udp_getpeername(const uv_udp_t * handle,struct sockaddr * name,int * namelen)132 __wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
133 			  int *namelen) {
134 	if (atomic_load(&__state_uv_udp_getpeername) == 0) {
135 		return (uv_udp_getpeername(handle, name, namelen));
136 	}
137 	return (atomic_load(&__state_uv_udp_getpeername));
138 }
139 #endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
140 
141 static atomic_int __state_uv_udp_getsockname = ATOMIC_VAR_INIT(0);
142 int
__wrap_uv_udp_getsockname(const uv_udp_t * handle,struct sockaddr * name,int * namelen)143 __wrap_uv_udp_getsockname(const uv_udp_t *handle, struct sockaddr *name,
144 			  int *namelen) {
145 	if (atomic_load(&__state_uv_udp_getsockname) == 0) {
146 		return (uv_udp_getsockname(handle, name, namelen));
147 	}
148 	return (atomic_load(&__state_uv_udp_getsockname));
149 }
150 
151 static atomic_int __state_uv_udp_send = ATOMIC_VAR_INIT(0);
152 int
__wrap_uv_udp_send(uv_udp_send_t * req,uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,uv_udp_send_cb send_cb)153 __wrap_uv_udp_send(uv_udp_send_t *req, uv_udp_t *handle, const uv_buf_t bufs[],
154 		   unsigned int nbufs, const struct sockaddr *addr,
155 		   uv_udp_send_cb send_cb) {
156 	if (atomic_load(&__state_uv_udp_send) == 0) {
157 		return (uv_udp_send(req, handle, bufs, nbufs, addr, send_cb));
158 	}
159 	return (atomic_load(&__state_uv_udp_send));
160 }
161 
162 static atomic_int __state_uv_udp_recv_start = ATOMIC_VAR_INIT(0);
163 int
__wrap_uv_udp_recv_start(uv_udp_t * handle,uv_alloc_cb alloc_cb,uv_udp_recv_cb recv_cb)164 __wrap_uv_udp_recv_start(uv_udp_t *handle, uv_alloc_cb alloc_cb,
165 			 uv_udp_recv_cb recv_cb) {
166 	if (atomic_load(&__state_uv_udp_recv_start) == 0) {
167 		return (uv_udp_recv_start(handle, alloc_cb, recv_cb));
168 	}
169 	return (atomic_load(&__state_uv_udp_recv_start));
170 }
171 
172 static atomic_int __state_uv_udp_recv_stop = ATOMIC_VAR_INIT(0);
173 int
__wrap_uv_udp_recv_stop(uv_udp_t * handle)174 __wrap_uv_udp_recv_stop(uv_udp_t *handle) {
175 	if (atomic_load(&__state_uv_udp_recv_stop) == 0) {
176 		return (uv_udp_recv_stop(handle));
177 	}
178 	return (atomic_load(&__state_uv_udp_recv_stop));
179 }
180 
181 static atomic_int __state_uv_tcp_open = ATOMIC_VAR_INIT(0);
182 int
__wrap_uv_tcp_open(uv_tcp_t * handle,uv_os_sock_t sock)183 __wrap_uv_tcp_open(uv_tcp_t *handle, uv_os_sock_t sock) {
184 	if (atomic_load(&__state_uv_tcp_open) == 0) {
185 		return (uv_tcp_open(handle, sock));
186 	}
187 	return (atomic_load(&__state_uv_tcp_open));
188 }
189 
190 static atomic_int __state_uv_tcp_bind = ATOMIC_VAR_INIT(0);
191 int
__wrap_uv_tcp_bind(uv_tcp_t * handle,const struct sockaddr * addr,unsigned int flags)192 __wrap_uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr,
193 		   unsigned int flags) {
194 	if (atomic_load(&__state_uv_tcp_bind) == 0) {
195 		return (uv_tcp_bind(handle, addr, flags));
196 	}
197 	return (atomic_load(&__state_uv_tcp_bind));
198 }
199 
200 static atomic_int __state_uv_tcp_getsockname = ATOMIC_VAR_INIT(0);
201 int
__wrap_uv_tcp_getsockname(const uv_tcp_t * handle,struct sockaddr * name,int * namelen)202 __wrap_uv_tcp_getsockname(const uv_tcp_t *handle, struct sockaddr *name,
203 			  int *namelen) {
204 	if (atomic_load(&__state_uv_tcp_getsockname) == 0) {
205 		return (uv_tcp_getsockname(handle, name, namelen));
206 	}
207 	return (atomic_load(&__state_uv_tcp_getsockname));
208 }
209 
210 static atomic_int __state_uv_tcp_getpeername = ATOMIC_VAR_INIT(0);
211 int
__wrap_uv_tcp_getpeername(const uv_tcp_t * handle,struct sockaddr * name,int * namelen)212 __wrap_uv_tcp_getpeername(const uv_tcp_t *handle, struct sockaddr *name,
213 			  int *namelen) {
214 	if (atomic_load(&__state_uv_tcp_getpeername) == 0) {
215 		return (uv_tcp_getpeername(handle, name, namelen));
216 	}
217 	return (atomic_load(&__state_uv_tcp_getpeername));
218 }
219 
220 static atomic_int __state_uv_tcp_connect = ATOMIC_VAR_INIT(0);
221 int
__wrap_uv_tcp_connect(uv_connect_t * req,uv_tcp_t * handle,const struct sockaddr * addr,uv_connect_cb cb)222 __wrap_uv_tcp_connect(uv_connect_t *req, uv_tcp_t *handle,
223 		      const struct sockaddr *addr, uv_connect_cb cb) {
224 	if (atomic_load(&__state_uv_tcp_connect) == 0) {
225 		return (uv_tcp_connect(req, handle, addr, cb));
226 	}
227 	return (atomic_load(&__state_uv_tcp_connect));
228 }
229 
230 static atomic_int __state_uv_listen = ATOMIC_VAR_INIT(0);
231 int
__wrap_uv_listen(uv_stream_t * stream,int backlog,uv_connection_cb cb)232 __wrap_uv_listen(uv_stream_t *stream, int backlog, uv_connection_cb cb) {
233 	if (atomic_load(&__state_uv_listen) == 0) {
234 		return (uv_listen(stream, backlog, cb));
235 	}
236 	return (atomic_load(&__state_uv_listen));
237 }
238 
239 static atomic_int __state_uv_accept = ATOMIC_VAR_INIT(0);
240 int
__wrap_uv_accept(uv_stream_t * server,uv_stream_t * client)241 __wrap_uv_accept(uv_stream_t *server, uv_stream_t *client) {
242 	if (atomic_load(&__state_uv_accept) == 0) {
243 		return (uv_accept(server, client));
244 	}
245 	return (atomic_load(&__state_uv_accept));
246 }
247 
248 static atomic_int __state_uv_send_buffer_size = ATOMIC_VAR_INIT(0);
249 int
__wrap_uv_send_buffer_size(uv_handle_t * handle,int * value)250 __wrap_uv_send_buffer_size(uv_handle_t *handle, int *value) {
251 	if (atomic_load(&__state_uv_send_buffer_size) == 0) {
252 		return (uv_send_buffer_size(handle, value));
253 	}
254 	return (atomic_load(&__state_uv_send_buffer_size));
255 }
256 
257 static atomic_int __state_uv_recv_buffer_size = ATOMIC_VAR_INIT(0);
258 int
__wrap_uv_recv_buffer_size(uv_handle_t * handle,int * value)259 __wrap_uv_recv_buffer_size(uv_handle_t *handle, int *value) {
260 	if (atomic_load(&__state_uv_recv_buffer_size) == 0) {
261 		return (uv_recv_buffer_size(handle, value));
262 	}
263 	return (atomic_load(&__state_uv_recv_buffer_size));
264 }
265 
266 static atomic_int __state_uv_fileno = ATOMIC_VAR_INIT(0);
267 int
__wrap_uv_fileno(const uv_handle_t * handle,uv_os_fd_t * fd)268 __wrap_uv_fileno(const uv_handle_t *handle, uv_os_fd_t *fd) {
269 	if (atomic_load(&__state_uv_fileno) == 0) {
270 		return (uv_fileno(handle, fd));
271 	}
272 	return (atomic_load(&__state_uv_fileno));
273 }
274 
275 #define uv_udp_open(...) __wrap_uv_udp_open(__VA_ARGS__)
276 #define uv_udp_bind(...) __wrap_uv_udp_bind(__VA_ARGS__)
277 #if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
278 #define uv_udp_connect(...)	__wrap_uv_udp_connect(__VA_ARGS__)
279 #define uv_udp_getpeername(...) __wrap_uv_udp_getpeername(__VA_ARGS__)
280 #endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
281 #define uv_udp_getsockname(...) __wrap_uv_udp_getsockname(__VA_ARGS__)
282 #define uv_udp_send(...)	__wrap_uv_udp_send(__VA_ARGS__)
283 #define uv_udp_recv_start(...)	__wrap_uv_udp_recv_start(__VA_ARGS__)
284 #define uv_udp_recv_stop(...)	__wrap_uv_udp_recv_stop(__VA_ARGS__)
285 
286 #define uv_tcp_open(...)	__wrap_uv_tcp_open(__VA_ARGS__)
287 #define uv_tcp_bind(...)	__wrap_uv_tcp_bind(__VA_ARGS__)
288 #define uv_tcp_getsockname(...) __wrap_uv_tcp_getsockname(__VA_ARGS__)
289 #define uv_tcp_getpeername(...) __wrap_uv_tcp_getpeername(__VA_ARGS__)
290 #define uv_tcp_connect(...)	__wrap_uv_tcp_connect(__VA_ARGS__)
291 
292 #define uv_listen(...) __wrap_uv_listen(__VA_ARGS__)
293 #define uv_accept(...) __wrap_uv_accept(__VA_ARGS__)
294 
295 #define uv_send_buffer_size(...) __wrap_uv_send_buffer_size(__VA_ARGS__)
296 #define uv_recv_buffer_size(...) __wrap_uv_recv_buffer_size(__VA_ARGS__)
297 #define uv_fileno(...)		 __wrap_uv_fileno(__VA_ARGS__)
298 
299 #define RESET_RETURN                                           \
300 	{                                                      \
301 		atomic_store(&__state_uv_udp_open, 0);         \
302 		atomic_store(&__state_uv_udp_bind, 0);         \
303 		atomic_store(&__state_uv_udp_connect, 0);      \
304 		atomic_store(&__state_uv_udp_getpeername, 0);  \
305 		atomic_store(&__state_uv_udp_getsockname, 0);  \
306 		atomic_store(&__state_uv_udp_send, 0);         \
307 		atomic_store(&__state_uv_udp_recv_start, 0);   \
308 		atomic_store(&__state_uv_udp_recv_stop, 0);    \
309 		atomic_store(&__state_uv_tcp_open, 0);         \
310 		atomic_store(&__state_uv_tcp_bind, 0);         \
311 		atomic_store(&__state_uv_tcp_getpeername, 0);  \
312 		atomic_store(&__state_uv_tcp_getsockname, 0);  \
313 		atomic_store(&__state_uv_tcp_connect, 0);      \
314 		atomic_store(&__state_uv_listen, 0);           \
315 		atomic_store(&__state_uv_accept, 0);           \
316 		atomic_store(&__state_uv_send_buffer_size, 0); \
317 		atomic_store(&__state_uv_recv_buffer_size, 0); \
318 		atomic_store(&__state_uv_fileno, 0);           \
319 	}
320 
321 #define WILL_RETURN(func, value) atomic_store(&__state_##func, value)
322 
323 #endif /* HAVE_CMOCKA */
324