xref: /netbsd-src/external/mpl/bind/dist/lib/isc/include/isc/netmgr.h (revision a45db23f655e22f0c2354600d3b3c2cb98abf2dc)
1 /*	$NetBSD: netmgr.h,v 1.7 2022/09/23 12:15:33 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 #pragma once
17 
18 #include <unistd.h>
19 
20 #include <isc/mem.h>
21 #include <isc/region.h>
22 #include <isc/result.h>
23 #include <isc/types.h>
24 
25 #ifndef _WIN32
26 #include <sys/socket.h>
27 #include <sys/types.h>
28 #endif
29 
30 #if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
31 #define HAVE_SO_REUSEPORT_LB 1
32 #endif
33 
34 /*
35  * Replacement for isc_sockettype_t provided by socket.h.
36  */
37 typedef enum {
38 	isc_socktype_tcp = 1,
39 	isc_socktype_udp = 2,
40 	isc_socktype_unix = 3,
41 	isc_socktype_raw = 4
42 } isc_socktype_t;
43 
44 typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
45 				 isc_region_t *region, void *cbarg);
46 /*%<
47  * Callback function to be used when receiving a packet.
48  *
49  * 'handle' the handle that can be used to send back the answer.
50  * 'eresult' the result of the event.
51  * 'region' contains the received data, if any. It will be freed
52  *          after return by caller.
53  * 'cbarg'  the callback argument passed to isc_nm_listenudp(),
54  *          isc_nm_listentcpdns(), or isc_nm_read().
55  */
56 typedef isc_result_t (*isc_nm_accept_cb_t)(isc_nmhandle_t *handle,
57 					   isc_result_t result, void *cbarg);
58 /*%<
59  * Callback function to be used when accepting a connection. (This differs
60  * from isc_nm_cb_t below in that it returns a result code.)
61  *
62  * 'handle' the handle that can be used to send back the answer.
63  * 'eresult' the result of the event.
64  * 'cbarg'  the callback argument passed to isc_nm_listentcp() or
65  * isc_nm_listentcpdns().
66  */
67 
68 typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
69 			    void *cbarg);
70 /*%<
71  * Callback function for other network completion events (send, connect).
72  *
73  * 'handle' the handle on which the event took place.
74  * 'eresult' the result of the event.
75  * 'cbarg'  the callback argument passed to isc_nm_send(),
76  *          isc_nm_tcp_connect(), or isc_nm_listentcp()
77  */
78 
79 typedef void (*isc_nm_opaquecb_t)(void *arg);
80 /*%<
81  * Opaque callback function, used for isc_nmhandle 'reset' and 'free'
82  * callbacks.
83  */
84 
85 typedef void (*isc_nm_workcb_t)(void *arg);
86 typedef void (*isc_nm_after_workcb_t)(void *arg, isc_result_t result);
87 /*%<
88  * Callback functions for libuv threadpool work (see uv_work_t)
89  */
90 
91 void
92 isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst);
93 void
94 isc_nm_detach(isc_nm_t **mgr0);
95 /*%<
96  * Attach/detach a network manager. When all references have been
97  * released, the network manager is shut down, freeing all resources.
98  * Destroy is working the same way as detach, but it actively waits
99  * for all other references to be gone.
100  */
101 
102 /* Return thread ID of current thread, or ISC_NETMGR_TID_UNKNOWN */
103 int
104 isc_nm_tid(void);
105 
106 void
107 isc_nmsocket_close(isc_nmsocket_t **sockp);
108 /*%<
109  * isc_nmsocket_close() detaches a listening socket that was
110  * created by isc_nm_listenudp(), isc_nm_listentcp(), or
111  * isc_nm_listentcpdns(). Once there are no remaining child
112  * sockets with active handles, the socket will be closed.
113  */
114 
115 #ifdef NETMGR_TRACE
116 #define isc_nmhandle_attach(handle, dest) \
117 	isc__nmhandle_attach(handle, dest, __FILE__, __LINE__, __func__)
118 #define isc_nmhandle_detach(handlep) \
119 	isc__nmhandle_detach(handlep, __FILE__, __LINE__, __func__)
120 #define FLARG , const char *file, unsigned int line, const char *func
121 #else
122 #define isc_nmhandle_attach(handle, dest) isc__nmhandle_attach(handle, dest)
123 #define isc_nmhandle_detach(handlep)	  isc__nmhandle_detach(handlep)
124 #define FLARG
125 #endif
126 
127 void
128 isc__nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **dest FLARG);
129 void
130 isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG);
131 /*%<
132  * Increment/decrement the reference counter in a netmgr handle,
133  * but (unlike the attach/detach functions) do not change the pointer
134  * value. If reference counters drop to zero, the handle can be
135  * marked inactive, possibly triggering deletion of its associated
136  * socket.
137  *
138  * (This will be used to prevent a client from being cleaned up when
139  * it's passed to an isc_task event handler. The libuv code would not
140  * otherwise know that the handle was in use and might free it, along
141  * with the client.)
142  */
143 #undef FLARG
144 
145 int
146 isc_nmhandle_getfd(isc_nmhandle_t *handle);
147 
148 void *
149 isc_nmhandle_getdata(isc_nmhandle_t *handle);
150 
151 void *
152 isc_nmhandle_getextra(isc_nmhandle_t *handle);
153 
154 bool
155 isc_nmhandle_is_stream(isc_nmhandle_t *handle);
156 
157 void
158 isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg,
159 		     isc_nm_opaquecb_t doreset, isc_nm_opaquecb_t dofree);
160 /*%<
161  * isc_nmhandle_t has a void* opaque field (for example, ns_client_t).
162  * We reuse handle and `opaque` can also be reused between calls.
163  * This function sets this field and two callbacks:
164  * - doreset resets the `opaque` to initial state
165  * - dofree frees everything associated with `opaque`
166  */
167 
168 void
169 isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
170 void
171 isc_nmhandle_cleartimeout(isc_nmhandle_t *handle);
172 /*%<
173  * Set/clear the read/recv timeout for the socket connected to 'handle'
174  * to 'timeout' (in milliseconds), and reset the timer.
175  *
176  * When this is called on a 'wrapper' socket handle (for example,
177  * a TCPDNS socket wrapping a TCP connection), the timer is set for
178  * both socket layers.
179  */
180 
181 void
182 isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value);
183 /*%<
184  * Enable/disable keepalive on this connection by setting it to 'value'.
185  *
186  * When keepalive is active, we switch to using the keepalive timeout
187  * to determine when to close a connection, rather than the idle timeout.
188  *
189  * This applies only to TCP-based DNS connections (i.e., TCPDNS).
190  * On other types of connection it has no effect.
191  */
192 
193 isc_sockaddr_t
194 isc_nmhandle_peeraddr(isc_nmhandle_t *handle);
195 /*%<
196  * Return the peer address for the given handle.
197  */
198 isc_sockaddr_t
199 isc_nmhandle_localaddr(isc_nmhandle_t *handle);
200 /*%<
201  * Return the local address for the given handle.
202  */
203 
204 isc_nm_t *
205 isc_nmhandle_netmgr(isc_nmhandle_t *handle);
206 /*%<
207  * Return a pointer to the netmgr object for the given handle.
208  */
209 
210 isc_result_t
211 isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
212 		 void *cbarg, size_t extrasize, isc_nmsocket_t **sockp);
213 /*%<
214  * Start listening for UDP packets on interface 'iface' using net manager
215  * 'mgr'.
216  *
217  * On success, 'sockp' will be updated to contain a new listening UDP socket.
218  *
219  * When a packet is received on the socket, 'cb' will be called with 'cbarg'
220  * as its argument.
221  *
222  * When handles are allocated for the socket, 'extrasize' additional bytes
223  * can be allocated along with the handle for an associated object, which
224  * can then be freed automatically when the handle is destroyed.
225  */
226 
227 void
228 isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
229 		  isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
230 		  size_t extrahandlesize);
231 /*%<
232  * Open a UDP socket, bind to 'local' and connect to 'peer', and
233  * immediately call 'cb' with a handle so that the caller can begin
234  * sending packets over UDP.
235  *
236  * When handles are allocated for the socket, 'extrasize' additional bytes
237  * can be allocated along with the handle for an associated object, which
238  * can then be freed automatically when the handle is destroyed.
239  *
240  * 'timeout' specifies the timeout interval in milliseconds.
241  *
242  * The connected socket can only be accessed via the handle passed to
243  * 'cb'.
244  */
245 
246 void
247 isc_nm_stoplistening(isc_nmsocket_t *sock);
248 /*%<
249  * Stop listening on socket 'sock'.
250  */
251 
252 void
253 isc_nm_pause(isc_nm_t *mgr);
254 /*%<
255  * Pause all processing, equivalent to taskmgr exclusive tasks.
256  * It won't return until all workers have been paused.
257  */
258 
259 void
260 isc_nm_resume(isc_nm_t *mgr);
261 /*%<
262  * Resume paused processing. It will return immediately after signalling
263  * workers to resume.
264  */
265 
266 void
267 isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
268 /*
269  * Begin (or continue) reading on the socket associated with 'handle', and
270  * update its recv callback to 'cb', which will be called as soon as there
271  * is data to process.
272  */
273 
274 void
275 isc_nm_pauseread(isc_nmhandle_t *handle);
276 /*%<
277  * Pause reading on this handle's socket, but remember the callback.
278  *
279  * Requires:
280  * \li	'handle' is a valid netmgr handle.
281  */
282 
283 void
284 isc_nm_cancelread(isc_nmhandle_t *handle);
285 /*%<
286  * Cancel reading on a connected socket. Calls the read/recv callback on
287  * active handles with a result code of ISC_R_CANCELED.
288  *
289  * Requires:
290  * \li	'sock' is a valid netmgr socket
291  * \li	...for which a read/recv callback has been defined.
292  */
293 
294 void
295 isc_nm_resumeread(isc_nmhandle_t *handle);
296 /*%<
297  * Resume reading on the handle's socket.
298  *
299  * Requires:
300  * \li	'handle' is a valid netmgr handle.
301  * \li	...for a socket with a defined read/recv callback.
302  */
303 
304 void
305 isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
306 	    void *cbarg);
307 /*%<
308  * Send the data in 'region' via 'handle'. Afterward, the callback 'cb' is
309  * called with the argument 'cbarg'.
310  *
311  * 'region' is not copied; it has to be allocated beforehand and freed
312  * in 'cb'.
313  */
314 
315 isc_result_t
316 isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface,
317 		 isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
318 		 size_t extrahandlesize, int backlog, isc_quota_t *quota,
319 		 isc_nmsocket_t **sockp);
320 /*%<
321  * Start listening for raw messages over the TCP interface 'iface', using
322  * net manager 'mgr'.
323  *
324  * On success, 'sockp' will be updated to contain a new listening TCP
325  * socket.
326  *
327  * When connection is accepted on the socket, 'accept_cb' will be called with
328  * 'accept_cbarg' as its argument. The callback is expected to start a read.
329  *
330  * When handles are allocated for the socket, 'extrasize' additional bytes
331  * will be allocated along with the handle for an associated object.
332  *
333  * If 'quota' is not NULL, then the socket is attached to the specified
334  * quota. This allows us to enforce TCP client quota limits.
335  *
336  */
337 
338 void
339 isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
340 		  isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
341 		  size_t extrahandlesize);
342 /*%<
343  * Create a socket using netmgr 'mgr', bind it to the address 'local',
344  * and connect it to the address 'peer'.
345  *
346  * When the connection is complete or has timed out, call 'cb' with
347  * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
348  * with the handle to use for an associated object.
349  *
350  * 'timeout' specifies the timeout interval in milliseconds.
351  *
352  * The connected socket can only be accessed via the handle passed to
353  * 'cb'.
354  */
355 
356 isc_result_t
357 isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
358 		    isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
359 		    isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
360 		    size_t extrahandlesize, int backlog, isc_quota_t *quota,
361 		    isc_nmsocket_t **sockp);
362 /*%<
363  * Start listening for DNS messages over the TCP interface 'iface', using
364  * net manager 'mgr'.
365  *
366  * On success, 'sockp' will be updated to contain a new listening TCPDNS
367  * socket. This is a wrapper around a raw TCP socket, which sends and
368  * receives DNS messages via that socket. It handles message buffering
369  * and pipelining, and automatically prepends messages with a two-byte
370  * length field.
371  *
372  * When a complete DNS message is received on the socket, 'cb' will be
373  * called with 'cbarg' as its argument.
374  *
375  * When a new TCPDNS connection is accepted, 'accept_cb' will be called
376  * with 'accept_cbarg' as its argument.
377  *
378  * When handles are allocated for the socket, 'extrasize' additional bytes
379  * will be allocated along with the handle for an associated object
380  * (typically ns_client).
381  *
382  * 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
383  */
384 
385 void
386 isc_nm_tcpdns_sequential(isc_nmhandle_t *handle);
387 /*%<
388  * Disable pipelining on this connection. Each DNS packet will be only
389  * processed after the previous completes.
390  *
391  * The socket must be unpaused after the query is processed.  This is done
392  * the response is sent, or if we're dropping the query, it will be done
393  * when a handle is fully dereferenced by calling the socket's
394  * closehandle_cb callback.
395  *
396  * Note: This can only be run while a message is being processed; if it is
397  * run before any messages are read, no messages will be read.
398  *
399  * Also note: once this has been set, it cannot be reversed for a given
400  * connection.
401  */
402 
403 void
404 isc_nm_tcpdns_keepalive(isc_nmhandle_t *handle, bool value);
405 /*%<
406  * Enable/disable keepalive on this connection by setting it to 'value'.
407  *
408  * When keepalive is active, we switch to using the keepalive timeout
409  * to determine when to close a connection, rather than the idle timeout.
410  */
411 
412 void
413 isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
414 		   uint32_t keepalive, uint32_t advertised);
415 /*%<
416  * Sets the initial, idle, and keepalive timeout values (in milliseconds) to use
417  * for TCP connections, and the timeout value to advertise in responses using
418  * the EDNS TCP Keepalive option (which should ordinarily be the same
419  * as 'keepalive'), in milliseconds.
420  *
421  * Requires:
422  * \li	'mgr' is a valid netmgr.
423  */
424 
425 bool
426 isc_nm_getloadbalancesockets(isc_nm_t *mgr);
427 void
428 isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled);
429 /*%<
430  * Get and set value of load balancing of the sockets.
431  *
432  * Requires:
433  * \li	'mgr' is a valid netmgr.
434  */
435 
436 void
437 isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
438 		   uint32_t *keepalive, uint32_t *advertised);
439 /*%<
440  * Gets the initial, idle, keepalive, or advertised timeout values,
441  * in milliseconds.
442  *
443  * Any integer pointer parameter not set to NULL will be updated to
444  * contain the corresponding timeout value.
445  *
446  * Requires:
447  * \li	'mgr' is a valid netmgr.
448  */
449 
450 void
451 isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
452 /*%<
453  * Simulate a broken firewall that blocks UDP messages larger than a given
454  * size.
455  */
456 
457 void
458 isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
459 /*%<
460  * Set a socket statistics counter set 'stats' for 'mgr'.
461  *
462  * Requires:
463  *\li	'mgr' is valid and doesn't have stats already set.
464  *
465  *\li	stats is a valid set of statistics counters supporting the
466  *	full range of socket-related stats counter numbers.
467  */
468 
469 void
470 isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
471 		     isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
472 		     size_t extrahandlesize);
473 /*%<
474  * Establish a DNS client connection via a TCP connection, bound to
475  * the address 'local' and connected to the address 'peer'.
476  *
477  * When the connection is complete or has timed out, call 'cb' with
478  * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
479  * with the handle to use for an associated object.
480  *
481  * 'timeout' specifies the timeout interval in milliseconds.
482  *
483  * The connected socket can only be accessed via the handle passed to
484  * 'cb'.
485  */
486 
487 void
488 isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid);
489 /*%<
490  * Enqueue the 'task' onto the netmgr ievents queue.
491  *
492  * Requires:
493  * \li 'mgr' is a valid netmgr object
494  * \li 'task' is a valid task
495  * \li 'threadid' is either the preferred netmgr tid or -1, in which case
496  *     tid will be picked randomly. The threadid is capped (by modulo) to
497  *     maximum number of 'workers' as specifed in isc_nm_start()
498  */
499 
500 void
501 isc_nm_work_offload(isc_nm_t *mgr, isc_nm_workcb_t work_cb,
502 		    isc_nm_after_workcb_t after_work_cb, void *data);
503 /*%<
504  * Schedules a job to be handled by the libuv thread pool (see uv_work_t).
505  * The function specified in `work_cb` will be run by a thread in the
506  * thread pool; when complete, the `after_work_cb` function will run.
507  *
508  * Requires:
509  * \li 'mgr' is a valid netmgr object.
510  * \li We are currently running in a network manager thread.
511  */
512 
513 void
514 isc__nm_force_tid(int tid);
515 /*%<
516  * Force the thread ID to 'tid'. This is STRICTLY for use in unit
517  * tests and should not be used in any production code.
518  */
519 
520 void
521 isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout);
522 
523 /*
524  * Timer related functions
525  */
526 
527 typedef struct isc_nm_timer isc_nm_timer_t;
528 
529 typedef void (*isc_nm_timer_cb)(void *, isc_result_t);
530 
531 void
532 isc_nm_timer_create(isc_nmhandle_t *, isc_nm_timer_cb, void *,
533 		    isc_nm_timer_t **);
534 
535 void
536 isc_nm_timer_attach(isc_nm_timer_t *, isc_nm_timer_t **);
537 
538 void
539 isc_nm_timer_detach(isc_nm_timer_t **);
540 
541 void
542 isc_nm_timer_start(isc_nm_timer_t *, uint64_t);
543 
544 void
545 isc_nm_timer_stop(isc_nm_timer_t *);
546