summaryrefslogtreecommitdiffstats
path: root/lib/isc/include/isc/netmgr.h
blob: eff33f6acb7ca71237d7bb2578f60974554ba556 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
/*
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 *
 * SPDX-License-Identifier: MPL-2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
 */

#pragma once

#include <unistd.h>

#include <isc/mem.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/tls.h>
#include <isc/types.h>

#include <sys/socket.h>
#include <sys/types.h>

#if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
#define HAVE_SO_REUSEPORT_LB 1
#endif

/*
 * Replacement for isc_sockettype_t provided by socket.h.
 */
typedef enum {
	isc_socktype_tcp = 1,
	isc_socktype_udp = 2,
	isc_socktype_unix = 3,
	isc_socktype_raw = 4
} isc_socktype_t;

typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
				 isc_region_t *region, void *cbarg);
/*%<
 * Callback function to be used when receiving a packet.
 *
 * 'handle' the handle that can be used to send back the answer.
 * 'eresult' the result of the event.
 * 'region' contains the received data, if any. It will be freed
 *          after return by caller.
 * 'cbarg'  the callback argument passed to isc_nm_listenudp(),
 *          isc_nm_listentcpdns(), or isc_nm_read().
 */
typedef isc_result_t (*isc_nm_accept_cb_t)(isc_nmhandle_t *handle,
					   isc_result_t result, void *cbarg);
/*%<
 * Callback function to be used when accepting a connection. (This differs
 * from isc_nm_cb_t below in that it returns a result code.)
 *
 * 'handle' the handle that can be used to send back the answer.
 * 'eresult' the result of the event.
 * 'cbarg'  the callback argument passed to isc_nm_listentcp() or
 * isc_nm_listentcpdns().
 */

typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
			    void *cbarg);
/*%<
 * Callback function for other network completion events (send, connect).
 *
 * 'handle' the handle on which the event took place.
 * 'eresult' the result of the event.
 * 'cbarg'  the callback argument passed to isc_nm_send(),
 *          isc_nm_tcp_connect(), or isc_nm_listentcp()
 */

typedef void (*isc_nm_opaquecb_t)(void *arg);
/*%<
 * Opaque callback function, used for isc_nmhandle 'reset' and 'free'
 * callbacks.
 */

typedef void (*isc_nm_workcb_t)(void *arg);
typedef void (*isc_nm_after_workcb_t)(void *arg, isc_result_t result);
/*%<
 * Callback functions for libuv threadpool work (see uv_work_t)
 */

void
isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst);
void
isc_nm_detach(isc_nm_t **mgr0);
/*%<
 * Attach/detach a network manager. When all references have been
 * released, the network manager is shut down, freeing all resources.
 * Destroy is working the same way as detach, but it actively waits
 * for all other references to be gone.
 */

/* Return thread ID of current thread, or ISC_NETMGR_TID_UNKNOWN */
int
isc_nm_tid(void);

void
isc_nmsocket_close(isc_nmsocket_t **sockp);
/*%<
 * isc_nmsocket_close() detaches a listening socket that was
 * created by isc_nm_listenudp(), isc_nm_listentcp(), or
 * isc_nm_listentcpdns(). Once there are no remaining child
 * sockets with active handles, the socket will be closed.
 */

void
isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
/*%<
 * Asynchronously replace the TLS context within the listener socket object.
 * The function is intended to be used during reconfiguration.
 *
 * Requires:
 * \li	'listener' is a pointer to a valid network manager listener socket
 object with TLS support;
 * \li	'tlsctx' is a valid pointer to a TLS context object.
 */

void
isc_nmsocket_set_max_streams(isc_nmsocket_t *listener,
			     const uint32_t  max_streams);
/*%<
 * Set the maximum allowed number of concurrent streams for accepted
 * client connections. The implementation might be asynchronous
 * depending on the listener socket type.
 *
 * The call is a no-op for any listener socket type that does not
 * support concept of multiple sessions per a client
 * connection. Currently, it works only for HTTP/2 listeners.
 *
 * Setting 'max_streams' to '0' instructs the listener that there is
 * no limit for concurrent streams.
 *
 * Requires:
 * \li	'listener' is a pointer to a valid network manager listener socket.
 */

#ifdef NETMGR_TRACE
#define isc_nmhandle_attach(handle, dest) \
	isc__nmhandle_attach(handle, dest, __FILE__, __LINE__, __func__)
#define isc_nmhandle_detach(handlep) \
	isc__nmhandle_detach(handlep, __FILE__, __LINE__, __func__)
#define FLARG , const char *file, unsigned int line, const char *func
#else
#define isc_nmhandle_attach(handle, dest) isc__nmhandle_attach(handle, dest)
#define isc_nmhandle_detach(handlep)	  isc__nmhandle_detach(handlep)
#define FLARG
#endif

void
isc__nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **dest FLARG);
void
isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG);
/*%<
 * Increment/decrement the reference counter in a netmgr handle,
 * but (unlike the attach/detach functions) do not change the pointer
 * value. If reference counters drop to zero, the handle can be
 * marked inactive, possibly triggering deletion of its associated
 * socket.
 *
 * (This will be used to prevent a client from being cleaned up when
 * it's passed to an isc_task event handler. The libuv code would not
 * otherwise know that the handle was in use and might free it, along
 * with the client.)
 */
#undef FLARG

void *
isc_nmhandle_getdata(isc_nmhandle_t *handle);

void *
isc_nmhandle_getextra(isc_nmhandle_t *handle);

bool
isc_nmhandle_is_stream(isc_nmhandle_t *handle);

void
isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg,
		     isc_nm_opaquecb_t doreset, isc_nm_opaquecb_t dofree);
/*%<
 * isc_nmhandle_t has a void* opaque field (for example, ns_client_t).
 * We reuse handle and `opaque` can also be reused between calls.
 * This function sets this field and two callbacks:
 * - doreset resets the `opaque` to initial state
 * - dofree frees everything associated with `opaque`
 */

void
isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc_nmhandle_cleartimeout(isc_nmhandle_t *handle);
/*%<
 * Set/clear the read/recv timeout for the socket connected to 'handle'
 * to 'timeout' (in milliseconds), and reset the timer.
 *
 * When this is called on a 'wrapper' socket handle (for example,
 * a TCPDNS socket wrapping a TCP connection), the timer is set for
 * both socket layers.
 */
bool
isc_nmhandle_timer_running(isc_nmhandle_t *handle);
/*%<
 * Return true if the timer for the socket connected to 'handle'
 * is running.
 */

void
isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value);
/*%<
 * Enable/disable keepalive on this connection by setting it to 'value'.
 *
 * When keepalive is active, we switch to using the keepalive timeout
 * to determine when to close a connection, rather than the idle timeout.
 *
 * This applies only to TCP-based DNS connections (i.e., TCPDNS or
 * TLSDNS). On other types of connection it has no effect.
 */

isc_sockaddr_t
isc_nmhandle_peeraddr(isc_nmhandle_t *handle);
/*%<
 * Return the peer address for the given handle.
 */
isc_sockaddr_t
isc_nmhandle_localaddr(isc_nmhandle_t *handle);
/*%<
 * Return the local address for the given handle.
 */

isc_nm_t *
isc_nmhandle_netmgr(isc_nmhandle_t *handle);
/*%<
 * Return a pointer to the netmgr object for the given handle.
 */

isc_result_t
isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
		 void *cbarg, size_t extrasize, isc_nmsocket_t **sockp);
/*%<
 * Start listening for UDP packets on interface 'iface' using net manager
 * 'mgr'.
 *
 * On success, 'sockp' will be updated to contain a new listening UDP socket.
 *
 * When a packet is received on the socket, 'cb' will be called with 'cbarg'
 * as its argument.
 *
 * When handles are allocated for the socket, 'extrasize' additional bytes
 * can be allocated along with the handle for an associated object, which
 * can then be freed automatically when the handle is destroyed.
 */

void
isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
		  isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
		  size_t extrahandlesize);
/*%<
 * Open a UDP socket, bind to 'local' and connect to 'peer', and
 * immediately call 'cb' with a handle so that the caller can begin
 * sending packets over UDP.
 *
 * When handles are allocated for the socket, 'extrasize' additional bytes
 * can be allocated along with the handle for an associated object, which
 * can then be freed automatically when the handle is destroyed.
 *
 * 'timeout' specifies the timeout interval in milliseconds.
 *
 * The connected socket can only be accessed via the handle passed to
 * 'cb'.
 */

isc_result_t
isc_nm_routeconnect(isc_nm_t *mgr, isc_nm_cb_t cb, void *cbarg,
		    size_t extrahandlesize);
/*%<
 * Open a route/netlink socket and call 'cb', so the caller can be
 * begin listening for interface changes.  This behaves similarly to
 * isc_nm_udpconnect().
 *
 * Returns ISC_R_NOTIMPLEMENTED on systems where route/netlink sockets
 * are not supported.
 */

void
isc_nm_stoplistening(isc_nmsocket_t *sock);
/*%<
 * Stop listening on socket 'sock'.
 */

void
isc_nm_pause(isc_nm_t *mgr);
/*%<
 * Pause all processing, equivalent to taskmgr exclusive tasks.
 * It won't return until all workers have been paused.
 */

void
isc_nm_resume(isc_nm_t *mgr);
/*%<
 * Resume paused processing. It will return immediately after signalling
 * workers to resume.
 */

void
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
 * Begin (or continue) reading on the socket associated with 'handle', and
 * update its recv callback to 'cb', which will be called as soon as there
 * is data to process.
 */

void
isc_nm_pauseread(isc_nmhandle_t *handle);
/*%<
 * Pause reading on this handle's socket, but remember the callback.
 *
 * Requires:
 * \li	'handle' is a valid netmgr handle.
 */

void
isc_nm_cancelread(isc_nmhandle_t *handle);
/*%<
 * Cancel reading on a connected socket. Calls the read/recv callback on
 * active handles with a result code of ISC_R_CANCELED.
 *
 * Requires:
 * \li	'sock' is a valid netmgr socket
 * \li	...for which a read/recv callback has been defined.
 */

void
isc_nm_resumeread(isc_nmhandle_t *handle);
/*%<
 * Resume reading on the handle's socket.
 *
 * Requires:
 * \li	'handle' is a valid netmgr handle.
 * \li	...for a socket with a defined read/recv callback.
 */

void
isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
	    void *cbarg);
/*%<
 * Send the data in 'region' via 'handle'. Afterward, the callback 'cb' is
 * called with the argument 'cbarg'.
 *
 * 'region' is not copied; it has to be allocated beforehand and freed
 * in 'cb'.
 */

isc_result_t
isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface,
		 isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
		 size_t extrahandlesize, int backlog, isc_quota_t *quota,
		 isc_nmsocket_t **sockp);
/*%<
 * Start listening for raw messages over the TCP interface 'iface', using
 * net manager 'mgr'.
 *
 * On success, 'sockp' will be updated to contain a new listening TCP
 * socket.
 *
 * When connection is accepted on the socket, 'accept_cb' will be called with
 * 'accept_cbarg' as its argument. The callback is expected to start a read.
 *
 * When handles are allocated for the socket, 'extrasize' additional bytes
 * will be allocated along with the handle for an associated object.
 *
 * If 'quota' is not NULL, then the socket is attached to the specified
 * quota. This allows us to enforce TCP client quota limits.
 *
 */

void
isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
		  isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
		  size_t extrahandlesize);
/*%<
 * Create a socket using netmgr 'mgr', bind it to the address 'local',
 * and connect it to the address 'peer'.
 *
 * When the connection is complete or has timed out, call 'cb' with
 * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
 * with the handle to use for an associated object.
 *
 * 'timeout' specifies the timeout interval in milliseconds.
 *
 * The connected socket can only be accessed via the handle passed to
 * 'cb'.
 */

isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
		    isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
		    isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
		    size_t extrahandlesize, int backlog, isc_quota_t *quota,
		    isc_nmsocket_t **sockp);
/*%<
 * Start listening for DNS messages over the TCP interface 'iface', using
 * net manager 'mgr'.
 *
 * On success, 'sockp' will be updated to contain a new listening TCPDNS
 * socket. This is a wrapper around a raw TCP socket, which sends and
 * receives DNS messages via that socket. It handles message buffering
 * and pipelining, and automatically prepends messages with a two-byte
 * length field.
 *
 * When a complete DNS message is received on the socket, 'cb' will be
 * called with 'cbarg' as its argument.
 *
 * When a new TCPDNS connection is accepted, 'accept_cb' will be called
 * with 'accept_cbarg' as its argument.
 *
 * When handles are allocated for the socket, 'extrasize' additional bytes
 * will be allocated along with the handle for an associated object
 * (typically ns_client).
 *
 * 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
 */

isc_result_t
isc_nm_listentlsdns(isc_nm_t *mgr, isc_sockaddr_t *iface,
		    isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
		    isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
		    size_t extrahandlesize, int backlog, isc_quota_t *quota,
		    isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);
/*%<
 * Same as isc_nm_listentcpdns but for an SSL (DoT) socket.
 */

void
isc_nm_sequential(isc_nmhandle_t *handle);
/*%<
 * Disable pipelining on this connection. Each DNS packet will be only
 * processed after the previous completes.
 *
 * The socket must be unpaused after the query is processed.  This is done
 * the response is sent, or if we're dropping the query, it will be done
 * when a handle is fully dereferenced by calling the socket's
 * closehandle_cb callback.
 *
 * Note: This can only be run while a message is being processed; if it is
 * run before any messages are read, no messages will be read.
 *
 * Also note: once this has been set, it cannot be reversed for a given
 * connection.
 */

void
isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
		   uint32_t keepalive, uint32_t advertised);
/*%<
 * Sets the initial, idle, and keepalive timeout values (in milliseconds) to use
 * for TCP connections, and the timeout value to advertise in responses using
 * the EDNS TCP Keepalive option (which should ordinarily be the same
 * as 'keepalive'), in milliseconds.
 *
 * Requires:
 * \li	'mgr' is a valid netmgr.
 */

void
isc_nm_setnetbuffers(isc_nm_t *mgr, int32_t recv_tcp, int32_t send_tcp,
		     int32_t recv_udp, int32_t send_udp);
/*%<
 * If not 0, sets the SO_RCVBUF and SO_SNDBUF socket options for TCP and UDP
 * respectively.
 *
 * Requires:
 * \li	'mgr' is a valid netmgr.
 */

bool
isc_nm_getloadbalancesockets(isc_nm_t *mgr);
void
isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled);
/*%<
 * Get and set value of load balancing of the sockets.
 *
 * Requires:
 * \li	'mgr' is a valid netmgr.
 */

void
isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
		   uint32_t *keepalive, uint32_t *advertised);
/*%<
 * Gets the initial, idle, keepalive, or advertised timeout values,
 * in milliseconds.
 *
 * Any integer pointer parameter not set to NULL will be updated to
 * contain the corresponding timeout value.
 *
 * Requires:
 * \li	'mgr' is a valid netmgr.
 */

void
isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp);
/*%<
 * Simulate a broken firewall that blocks UDP messages larger than a given
 * size.
 */

void
isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
/*%<
 * Set a socket statistics counter set 'stats' for 'mgr'.
 *
 * Requires:
 *\li	'mgr' is valid and doesn't have stats already set.
 *
 *\li	stats is a valid set of statistics counters supporting the
 *	full range of socket-related stats counter numbers.
 */

isc_result_t
isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type);
/*%<
 * Check whether the specified address is available on the local system
 * by opening a socket and immediately closing it.
 *
 * Requires:
 *\li	'addr' is not NULL.
 */

void
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
		     isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
		     size_t extrahandlesize);
void
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
		     isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
		     size_t extrahandlesize, isc_tlsctx_t *sslctx,
		     isc_tlsctx_client_session_cache_t *client_sess_cache);
/*%<
 * Establish a DNS client connection via a TCP or TLS connection, bound to
 * the address 'local' and connected to the address 'peer'.
 *
 * When the connection is complete or has timed out, call 'cb' with
 * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along
 * with the handle to use for an associated object.
 *
 * 'timeout' specifies the timeout interval in milliseconds.
 *
 * The connected socket can only be accessed via the handle passed to
 * 'cb'.
 */

/*%<
 * Returns 'true' iff 'handle' is associated with a socket of type
 * 'isc_nm_tlsdnssocket'.
 */

bool
isc_nm_is_http_handle(isc_nmhandle_t *handle);
/*%<
 * Returns 'true' iff 'handle' is associated with a socket of type
 * 'isc_nm_httpsocket'.
 */

#if HAVE_LIBNGHTTP2

#define ISC_NM_HTTP_DEFAULT_PATH "/dns-query"

isc_result_t
isc_nm_listentls(isc_nm_t *mgr, isc_sockaddr_t *iface,
		 isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
		 size_t extrahandlesize, int backlog, isc_quota_t *quota,
		 isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);

void
isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
		  isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx,
		  isc_tlsctx_client_session_cache_t *client_sess_cache,
		  unsigned int timeout, size_t extrahandlesize);

void
isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
		   const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
		   isc_tlsctx_t			     *ctx,
		   isc_tlsctx_client_session_cache_t *client_sess_cache,
		   unsigned int timeout, size_t extrahandlesize);

isc_result_t
isc_nm_listenhttp(isc_nm_t *mgr, isc_sockaddr_t *iface, int backlog,
		  isc_quota_t *quota, isc_tlsctx_t *ctx,
		  isc_nm_http_endpoints_t *eps, uint32_t max_concurrent_streams,
		  isc_nmsocket_t **sockp);

isc_nm_http_endpoints_t *
isc_nm_http_endpoints_new(isc_mem_t *mctx);
/*%<
 * Create a new, empty HTTP endpoints set object.
 *
 * Requires:
 * \li 'mctx' a valid memory context object.
 */

isc_result_t
isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps,
			  const char *uri, const isc_nm_recv_cb_t cb,
			  void *cbarg, const size_t extrahandlesize);
/*%< Adds a new endpoint to the given HTTP endpoints set object.
 *
 * NOTE: adding an endpoint is allowed only if the endpoint object has
 * not been passed to isc_nm_listenhttp() yet.
 *
 * Requires:
 * \li 'eps' is a valid pointer to a valid isc_nm_http_endpoints_t
 * object;
 * \li 'uri' is a valid pointer to a string of length > 0;
 * \li 'cb' is a valid pointer to a read callback function.
 */

void
isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t  *source,
			     isc_nm_http_endpoints_t **targetp);
/*%<
 * Attaches to an HTTP endpoints set object.
 *
 * Requires:
 * \li 'source' is a non-NULL pointer to a valid
 * isc_nm_http_endpoints_t object;
 * \li 'target' is a pointer to a pointer, containing NULL.
 */

void
isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp);
/*%<
 * Detaches from an HTTP endpoints set object. When reference count
 * reaches 0, the object get deleted.
 *
 * Requires:
 * \li 'epsp' is a pointer to a pointer to a valid
 * isc_nm_http_endpoints_t object.
 */

bool
isc_nm_http_path_isvalid(const char *path);
/*%<
 * Returns 'true' if 'path' matches the format requirements for
 * the path component of a URI as defined in RFC 3986 section 3.3.
 */

void
isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa,
		    const char *hostname, const uint16_t http_port,
		    const char *abs_path, char *outbuf,
		    const size_t outbuf_len);
/*%<
 * Makes a URI connection string out of na isc_sockaddr_t object 'sa'
 * or the specified 'hostname' and 'http_port'.
 *
 * Requires:
 * \li 'abs_path' is a valid absolute HTTP path string;
 * \li 'outbuf' is a valid pointer to a buffer which will get the result;
 * \li 'outbuf_len' is a size of the result buffer and is greater than zero.
 */

void
isc_nm_http_set_endpoints(isc_nmsocket_t	  *listener,
			  isc_nm_http_endpoints_t *eps);
/*%<
 * Asynchronously replace the set of HTTP endpoints (paths) within
 * the listener socket object.  The function is intended to be used
 * during reconfiguration.
 *
 * Requires:
 * \li	'listener' is a pointer to a valid network manager HTTP listener socket;
 * \li	'eps' is a valid pointer to an HTTP endpoints set.
 */

#endif /* HAVE_LIBNGHTTP2 */

void
isc_nm_bad_request(isc_nmhandle_t *handle);
/*%<
 * Perform a transport protocol specific action on the handle in case of a
 * bad/malformed incoming DNS message.
 *
 * NOTE: The function currently is no-op for any protocol except HTTP/2.
 *
 * Requires:
 *  \li 'handle' is a valid netmgr handle object.
 */

isc_result_t
isc_nm_xfr_checkperm(isc_nmhandle_t *handle);
/*%<
 * Check if it is permitted to do a zone transfer over the given handle.
 *
 * Returns:
 * \li	#ISC_R_SUCCESS		Success, permission check passed successfully
 * \li	#ISC_R_DOTALPNERROR	No permission because of ALPN tag mismatch
 * \li	#ISC_R_NOPERM		No permission because of other restrictions
 * \li  any other result indicates failure (i.e. no permission)
 *
 * Requires:
 * \li	'handle' is a valid connection handle.
 */

void
isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl);
/*%<
 * Set the minimal time to live from the server's response Answer
 * section as a hint to the underlying transport.
 *
 * NOTE: The function currently is no-op for any protocol except HTTP/2.
 *
 * Requires:
 *
 * \li 'handle' is a valid netmgr handle object associated with an accepted
 * connection.
 */

isc_nmsocket_type
isc_nm_socket_type(const isc_nmhandle_t *handle);
/*%<
 * Returns the handle's underlying socket type.
 *
 * Requires:
 *  \li 'handle' is a valid netmgr handle object.
 */

bool
isc_nm_has_encryption(const isc_nmhandle_t *handle);
/*%<
 * Returns 'true' iff the handle's underlying transport does encryption.
 *
 * Requires:
 *  \li 'handle' is a valid netmgr handle object.
 */

const char *
isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
/*%<
 * Returns user-readable message describing TLS peer's certificate
 * validation result. Returns 'NULL' for the transport handles for
 * which peer verification was not performed.
 *
 * Requires:
 *  \li 'handle' is a valid netmgr handle object.
 */

void
isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid);
/*%<
 * Enqueue the 'task' onto the netmgr ievents queue.
 *
 * Requires:
 * \li 'mgr' is a valid netmgr object
 * \li 'task' is a valid task
 * \li 'threadid' is either the preferred netmgr tid or -1, in which case
 *     tid will be picked randomly. The threadid is capped (by modulo) to
 *     maximum number of 'workers' as specifed in isc_nm_start()
 */

void
isc_nm_work_offload(isc_nm_t *mgr, isc_nm_workcb_t work_cb,
		    isc_nm_after_workcb_t after_work_cb, void *data);
/*%<
 * Schedules a job to be handled by the libuv thread pool (see uv_work_t).
 * The function specified in `work_cb` will be run by a thread in the
 * thread pool; when complete, the `after_work_cb` function will run.
 *
 * Requires:
 * \li 'mgr' is a valid netmgr object.
 * \li We are currently running in a network manager thread.
 */

void
isc__nm_force_tid(int tid);
/*%<
 * Force the thread ID to 'tid'. This is STRICTLY for use in unit
 * tests and should not be used in any production code.
 */

void
isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout);

/*
 * Timer related functions
 */

typedef struct isc_nm_timer isc_nm_timer_t;

typedef void (*isc_nm_timer_cb)(void *, isc_result_t);

void
isc_nm_timer_create(isc_nmhandle_t *, isc_nm_timer_cb, void *,
		    isc_nm_timer_t **);

void
isc_nm_timer_attach(isc_nm_timer_t *, isc_nm_timer_t **);

void
isc_nm_timer_detach(isc_nm_timer_t **);

void
isc_nm_timer_start(isc_nm_timer_t *, uint64_t);

void
isc_nm_timer_stop(isc_nm_timer_t *);