2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 18:19:42 +00:00
bind/lib/isc/netmgr/netmgr-int.h
Aram Sargsyan 70ad94257d Implement tcp-primaries-timeout
The new 'tcp-primaries-timeout' configuration option works the same way
as the existing 'tcp-initial-timeout' option, but applies only to the
TCP connections made to the primary servers, so that the timeout value
can be set separately for them. The default is 15 seconds.

Also, while accommodating zone.c's code to support the new option, make
a light refactoring with the way UDP timeouts are calculated by using
definitions instead of hardcoded values.
2025-04-23 17:03:05 +00:00

1516 lines
38 KiB
C

/*
* 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 <openssl/err.h>
#include <openssl/ssl.h>
#include <isc/atomic.h>
#include <isc/barrier.h>
#include <isc/buffer.h>
#include <isc/dnsstream.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/proxy2.h>
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/stats.h>
#include <isc/thread.h>
#include <isc/tid.h>
#include <isc/time.h>
#include <isc/tls.h>
#include <isc/util.h>
#include <isc/uv.h>
#include "../loop_p.h"
#define ISC_NETMGR_TID_UNKNOWN -1
/*
* Receive buffers
*/
#if HAVE_DECL_UV_UDP_MMSG_CHUNK
/*
* The value 20 here is UV__MMSG_MAXWIDTH taken from the current libuv source,
* libuv will not receive more that 20 datagrams in a single recvmmsg call.
*/
#define ISC_NETMGR_UDP_RECVBUF_SIZE (20 * UINT16_MAX)
#else
/*
* A single DNS message size
*/
#define ISC_NETMGR_UDP_RECVBUF_SIZE UINT16_MAX
#endif
#define ISC_NETMGR_UDP_SENDBUF_SIZE UINT16_MAX
/*
* The TCP send and receive buffers can fit one maximum sized DNS message plus
* its size, the receive buffer here affects TCP, DoT and DoH.
*/
#define ISC_NETMGR_TCP_SENDBUF_SIZE (sizeof(uint16_t) + UINT16_MAX)
#define ISC_NETMGR_TCP_RECVBUF_SIZE (sizeof(uint16_t) + UINT16_MAX)
/* Pick the larger buffer */
#define ISC_NETMGR_RECVBUF_SIZE \
(ISC_NETMGR_UDP_RECVBUF_SIZE >= ISC_NETMGR_TCP_RECVBUF_SIZE \
? ISC_NETMGR_UDP_RECVBUF_SIZE \
: ISC_NETMGR_TCP_RECVBUF_SIZE)
/*
* Make sure our RECVBUF size is large enough
*/
STATIC_ASSERT(ISC_NETMGR_UDP_RECVBUF_SIZE <= ISC_NETMGR_RECVBUF_SIZE,
"UDP receive buffer size must be smaller or equal than worker "
"receive buffer size");
STATIC_ASSERT(ISC_NETMGR_TCP_RECVBUF_SIZE <= ISC_NETMGR_RECVBUF_SIZE,
"TCP receive buffer size must be smaller or equal than worker "
"receive buffer size");
/*%
* Maximum outstanding DNS message that we process in a single TCP read.
*/
#define ISC_NETMGR_MAX_STREAM_CLIENTS_PER_CONN 23
/*%
* Regular TCP buffer size.
*/
#define NM_REG_BUF 4096
/*%
* Larger buffer for when the regular one isn't enough; this will
* hold two full DNS packets with lengths. netmgr receives 64k at
* most in TCPDNS or TLSDNS connections, so there's no risk of overrun
* when using a buffer this size.
*/
#define NM_BIG_BUF ISC_NETMGR_TCP_RECVBUF_SIZE * 2
/*%
* Maximum segment size (MSS) of TCP socket on which the server responds to
* queries. Value lower than common MSS on Ethernet (1220, that is 1280 (IPv6
* minimum link MTU) - 40 (IPv6 fixed header) - 20 (TCP fixed header)) will
* address path MTU problem.
*/
#define NM_MAXSEG (1280 - 20 - 40)
/*%
* How many isc_nmhandles and isc_nm_uvreqs will we be
* caching for reuse in a socket.
*/
#define ISC_NM_NMSOCKET_MAX 64
#define ISC_NM_NMHANDLES_MAX 64
#define ISC_NM_UVREQS_MAX 64
/*% ISC_PROXY2_MIN_AF_UNIX_SIZE is the largest type when TLVs are not used */
#define ISC_NM_PROXY2_DEFAULT_BUFFER_SIZE (ISC_PROXY2_MIN_AF_UNIX_SIZE)
/*
* Define ISC_NETMGR_TRACE to activate tracing of handles and sockets.
* This will impair performance but enables us to quickly determine,
* if netmgr resources haven't been cleaned up on shutdown, which ones
* are still in use.
*/
#if ISC_NETMGR_TRACE
#define TRACE_SIZE 8
#if defined(__linux__)
#include <syscall.h>
#define gettid() (uint64_t)syscall(SYS_gettid)
#elif defined(__FreeBSD__)
#include <pthread_np.h>
#define gettid() (uint64_t)(pthread_getthreadid_np())
#elif defined(__OpenBSD__)
#include <unistd.h>
#define gettid() (uint64_t)(getthrid())
#elif defined(__NetBSD__)
#include <lwp.h>
#define gettid() (uint64_t)(_lwp_self())
#elif defined(__DragonFly__)
#include <unistd.h>
#define gettid() (uint64_t)(lwp_gettid())
#else
#define gettid() (uint64_t)(pthread_self())
#endif
#define NETMGR_TRACE_LOG(format, ...) \
fprintf(stderr, "%" PRIu64 ":%d:%s:%u:%s:" format, gettid(), \
isc_tid(), file, line, func, __VA_ARGS__)
#define FLARG \
, const char *func ISC_ATTR_UNUSED, const char *file ISC_ATTR_UNUSED, \
unsigned int line ISC_ATTR_UNUSED
#define FLARG_PASS , func, file, line
#define isc__nm_uvreq_get(sock) \
isc___nm_uvreq_get(sock, __func__, __FILE__, __LINE__)
#define isc__nm_uvreq_put(req) \
isc___nm_uvreq_put(req, __func__, __FILE__, __LINE__)
#define isc__nmsocket_init(sock, mgr, type, iface, parent) \
isc___nmsocket_init(sock, mgr, type, iface, parent, __func__, \
__FILE__, __LINE__)
#define isc__nmsocket_put(sockp) \
isc___nmsocket_put(sockp, __func__, __FILE__, __LINE__)
#define isc__nmsocket_attach(sock, target) \
isc___nmsocket_attach(sock, target, __func__, __FILE__, __LINE__)
#define isc__nmsocket_detach(socketp) \
isc___nmsocket_detach(socketp, __func__, __FILE__, __LINE__)
#define isc__nmsocket_close(socketp) \
isc___nmsocket_close(socketp, __func__, __FILE__, __LINE__)
#define isc__nmhandle_get(sock, peer, local) \
isc___nmhandle_get(sock, peer, local, __func__, __FILE__, __LINE__)
#define isc__nmsocket_prep_destroy(sock) \
isc___nmsocket_prep_destroy(sock, __func__, __FILE__, __LINE__)
#define isc__nm_get_read_req(sock, sockaddr) \
isc___nm_get_read_req(sock, sockaddr, __func__, __FILE__, __LINE__)
#else
#define NETMGR_TRACE_LOG(format, ...)
#define FLARG
#define FLARG_PASS
#define isc__nm_uvreq_get(sock) isc___nm_uvreq_get(sock)
#define isc__nm_uvreq_put(req) isc___nm_uvreq_put(req)
#define isc__nmsocket_init(sock, mgr, type, iface, parent) \
isc___nmsocket_init(sock, mgr, type, iface, parent)
#define isc__nmsocket_put(sockp) isc___nmsocket_put(sockp)
#define isc__nmsocket_attach(sock, target) isc___nmsocket_attach(sock, target)
#define isc__nmsocket_detach(socketp) isc___nmsocket_detach(socketp)
#define isc__nmsocket_close(socketp) isc___nmsocket_close(socketp)
#define isc__nmhandle_get(sock, peer, local) \
isc___nmhandle_get(sock, peer, local)
#define isc__nmsocket_prep_destroy(sock) isc___nmsocket_prep_destroy(sock)
#define isc__nm_get_read_req(sock, sockaddr) \
isc___nm_get_read_req(sock, sockaddr)
#endif
typedef struct isc__nm_uvreq isc__nm_uvreq_t;
/*
* Single network event loop worker.
*/
typedef struct isc__networker {
isc_mem_t *mctx;
isc_refcount_t references;
isc_loop_t *loop;
isc_nm_t *netmgr;
bool shuttingdown;
char *recvbuf;
bool recvbuf_inuse;
ISC_LIST(isc_nmsocket_t) active_sockets;
isc_mempool_t *nmsocket_pool;
isc_mempool_t *uvreq_pool;
} isc__networker_t;
ISC_REFCOUNT_DECL(isc__networker);
#ifdef ISC_NETMGR_TRACE
void
isc__nm_dump_active(isc__networker_t *worker);
void
isc__nm_dump_active_manager(isc_nm_t *netmgr);
#endif /* ISC_NETMGR_TRACE */
/*
* A general handle for a connection bound to a networker. For UDP
* connections we have peer address here, so both TCP and UDP can be
* handled with a simple send-like function
*/
#define NMHANDLE_MAGIC ISC_MAGIC('N', 'M', 'H', 'D')
#define VALID_NMHANDLE(t) \
(ISC_MAGIC_VALID(t, NMHANDLE_MAGIC) && \
atomic_load(&(t)->references) > 0)
typedef void (*isc__nm_closecb)(isc_nmhandle_t *);
typedef struct isc_nm_http_session isc_nm_http_session_t;
struct isc_nmhandle {
int magic;
isc_refcount_t references;
/*
* The socket is not 'attached' in the traditional
* reference-counting sense. Instead, we keep all handles in an
* array in the socket object. This way, we don't have circular
* dependencies and we can close all handles when we're destroying
* the socket.
*/
isc_nmsocket_t *sock;
isc_nm_http_session_t *httpsession;
isc_sockaddr_t peer;
isc_sockaddr_t local;
bool proxy_is_unspec;
struct isc_nmhandle *proxy_udphandle;
isc_nm_opaquecb_t doreset; /* reset extra callback, external */
isc_nm_opaquecb_t dofree; /* free extra callback, external */
#if ISC_NETMGR_TRACE
void *backtrace[TRACE_SIZE];
int backtrace_size;
#endif
ISC_LINK(isc_nmhandle_t) active_link;
ISC_LINK(isc_nmhandle_t) inactive_link;
void *opaque;
isc_job_t job;
};
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_cb_t send;
isc_nm_cb_t connect;
} isc__nm_cb_t;
/*
* Wrapper around uv_req_t with 'our' fields in it. req->data should
* always point to its parent. Note that we always allocate more than
* sizeof(struct) because we make room for different req types;
*/
#define UVREQ_MAGIC ISC_MAGIC('N', 'M', 'U', 'R')
#define VALID_UVREQ(t) ISC_MAGIC_VALID(t, UVREQ_MAGIC)
typedef struct isc__nm_uvreq isc__nm_uvreq_t;
struct isc__nm_uvreq {
int magic;
isc_nmsocket_t *sock;
isc_nmhandle_t *handle;
char tcplen[2]; /* The TCP DNS message length */
uv_buf_t uvbuf; /* translated isc_region_t, to be
* sent or received */
isc_sockaddr_t local; /* local address */
isc_sockaddr_t peer; /* peer address */
isc__nm_cb_t cb; /* callback */
void *cbarg; /* callback argument */
isc_nm_timer_t *timer; /* TCP write timer */
int connect_tries; /* connect retries */
isc_result_t result;
union {
uv_handle_t handle;
uv_write_t write;
uv_connect_t connect;
uv_udp_send_t udp_send;
} uv_req;
ISC_LINK(isc__nm_uvreq_t) link;
ISC_LINK(isc__nm_uvreq_t) active_link;
isc_job_t job;
};
/*
* Network manager
*/
#define NM_MAGIC ISC_MAGIC('N', 'E', 'T', 'M')
#define VALID_NM(t) ISC_MAGIC_VALID(t, NM_MAGIC)
struct isc_nm {
int magic;
isc_refcount_t references;
isc_mem_t *mctx;
isc_loopmgr_t *loopmgr;
uint32_t nloops;
isc__networker_t *workers;
isc_stats_t *stats;
atomic_uint_fast32_t maxudp;
bool load_balance_sockets;
/*
* Active connections are being closed and new connections are
* no longer allowed.
*/
atomic_bool shuttingdown;
/*
* Timeout values for TCP connections, corresponding to
* tcp-intiial-timeout, tcp-idle-timeout, tcp-keepalive-timeout,
* tcp-advertised-timeout, and tcp-primaries-timeout. Note that these
* are stored in milliseconds so they can be used directly with the
* libuv timer, but they are configured in tenths of seconds.
*/
atomic_uint_fast32_t init;
atomic_uint_fast32_t idle;
atomic_uint_fast32_t keepalive;
atomic_uint_fast32_t advertised;
atomic_uint_fast32_t primaries;
/*
* Socket SO_RCVBUF and SO_SNDBUF values
*/
atomic_int_fast32_t recv_udp_buffer_size;
atomic_int_fast32_t send_udp_buffer_size;
atomic_int_fast32_t recv_tcp_buffer_size;
atomic_int_fast32_t send_tcp_buffer_size;
};
/*%
* A universal structure for either a single socket or a group of
* dup'd/SO_REUSE_PORT-using sockets listening on the same interface.
*/
#define NMSOCK_MAGIC ISC_MAGIC('N', 'M', 'S', 'K')
#define VALID_NMSOCK(t) ISC_MAGIC_VALID(t, NMSOCK_MAGIC)
/*%
* Index into socket stat counter arrays.
*/
typedef enum {
STATID_OPEN = 0,
STATID_OPENFAIL = 1,
STATID_CLOSE = 2,
STATID_BINDFAIL = 3,
STATID_CONNECTFAIL = 4,
STATID_CONNECT = 5,
STATID_ACCEPTFAIL = 6,
STATID_ACCEPT = 7,
STATID_SENDFAIL = 8,
STATID_RECVFAIL = 9,
STATID_ACTIVE = 10,
STATID_CLIENTS = 11,
STATID_MAX = 12,
} isc__nm_statid_t;
typedef struct isc_nmsocket_tls_send_req {
isc_nmsocket_t *tlssock;
isc_buffer_t data;
isc_nm_cb_t cb;
void *cbarg;
isc_nmhandle_t *handle;
bool finish;
uint8_t smallbuf[512];
} isc_nmsocket_tls_send_req_t;
#if HAVE_LIBNGHTTP2
typedef enum isc_http_request_type {
ISC_HTTP_REQ_GET,
ISC_HTTP_REQ_POST,
ISC_HTTP_REQ_UNSUPPORTED
} isc_http_request_type_t;
typedef enum isc_http_scheme_type {
ISC_HTTP_SCHEME_HTTP,
ISC_HTTP_SCHEME_HTTP_SECURE,
ISC_HTTP_SCHEME_UNSUPPORTED
} isc_http_scheme_type_t;
typedef struct isc_nm_httphandler {
int magic;
char *path;
isc_nm_recv_cb_t cb;
void *cbarg;
ISC_LINK(struct isc_nm_httphandler) link;
} isc_nm_httphandler_t;
struct isc_nm_http_endpoints {
uint32_t magic;
isc_mem_t *mctx;
ISC_LIST(isc_nm_httphandler_t) handlers;
isc_refcount_t references;
atomic_bool in_use;
};
typedef struct isc_nmsocket_h2 {
isc_nmsocket_t *psock; /* owner of the structure */
char *request_path;
char *query_data;
size_t query_data_len;
bool query_too_large;
isc_buffer_t rbuf;
isc_buffer_t wbuf;
int32_t stream_id;
isc_nm_http_session_t *session;
/* maximum concurrent streams (server-side) */
atomic_uint_fast32_t max_concurrent_streams;
uint32_t min_ttl; /* used to set "max-age" in responses */
isc_http_request_type_t request_type;
isc_http_scheme_type_t request_scheme;
size_t content_length;
char clenbuf[128];
char cache_control_buf[128];
int headers_error_code;
size_t headers_data_processed;
isc_nm_recv_cb_t cb;
void *cbarg;
ISC_LINK(struct isc_nmsocket_h2) link;
isc_nm_http_endpoints_t **listener_endpoints;
size_t n_listener_endpoints;
isc_nm_http_endpoints_t *peer_endpoints;
bool request_received;
bool response_submitted;
struct {
char *uri;
bool post;
isc_tlsctx_t *tlsctx;
isc_sockaddr_t local_interface;
void *cstream;
const char *tls_peer_verify_string;
} connect;
} isc_nmsocket_h2_t;
#endif /* HAVE_LIBNGHTTP2 */
typedef void (*isc_nm_closehandlecb_t)(void *arg);
/*%<
* Opaque callback function, used for isc_nmhandle 'reset' and 'free'
* callbacks.
*/
struct isc_nmsocket {
/*% Unlocked, RO */
int magic;
uint32_t tid;
isc_refcount_t references;
isc_nmsocket_type type;
isc__networker_t *worker;
isc_barrier_t listen_barrier;
isc_barrier_t stop_barrier;
/*% Parent socket for multithreaded listeners */
isc_nmsocket_t *parent;
/*% TLS stuff */
struct tlsstream {
bool server;
BIO *bio_in;
BIO *bio_out;
isc_tls_t *tls;
isc_tlsctx_t *ctx;
isc_tlsctx_t **listener_tls_ctx; /*%< A context reference per
worker */
size_t n_listener_tls_ctx;
char *sni_hostname;
isc_tlsctx_client_session_cache_t *client_sess_cache;
bool client_session_saved;
isc_nmsocket_t *tlslistener;
isc_nmsocket_t *tlssocket;
atomic_bool result_updated;
enum {
TLS_INIT,
TLS_HANDSHAKE,
TLS_IO,
TLS_CLOSED
} state; /*%< The order of these is significant */
size_t nsending;
bool tcp_nodelay_value;
isc_nmsocket_tls_send_req_t *send_req; /*%< Send req to reuse */
bool reading;
} tlsstream;
#if HAVE_LIBNGHTTP2
isc_nmsocket_h2_t *h2;
#endif /* HAVE_LIBNGHTTP2 */
struct {
isc_dnsstream_assembler_t *input;
bool reading;
isc_nmsocket_t *listener;
isc_nmsocket_t *sock;
size_t nsending;
void *send_req;
bool dot_alpn_negotiated;
const char *tls_verify_error;
} streamdns;
struct {
isc_nmsocket_t *sock;
bool reading;
size_t nsending;
void *send_req;
union {
isc_proxy2_handler_t *handler; /* server */
isc_buffer_t *outbuf; /* client */
} proxy2;
bool header_processed;
bool extra_processed; /* data arrived past header processed */
isc_nmsocket_t **udp_server_socks; /* UDP sockets */
size_t udp_server_socks_num;
} proxy;
/*%
* pquota is a non-attached pointer to the TCP client quota, stored in
* listening sockets.
*/
isc_quota_t *pquota;
isc_job_t quotacb;
/*%
* Socket statistics
*/
const isc_statscounter_t *statsindex;
/*%
* TCP read/connect timeout timers.
*/
uv_timer_t read_timer;
uint64_t read_timeout;
uint64_t connect_timeout;
/*%
* TCP write timeout timer.
*/
uint64_t write_timeout;
/*
* Reading was throttled over TCP as the peer does not read the
* data we are sending back.
*/
bool reading_throttled;
/*% outer socket is for 'wrapped' sockets - e.g. tcpdns in tcp */
isc_nmsocket_t *outer;
/*% server socket for connections */
isc_nmsocket_t *server;
/*% client socket for connections */
isc_nmsocket_t *listener;
/*% Child sockets for multi-socket setups */
isc_nmsocket_t *children;
uint_fast32_t nchildren;
isc_sockaddr_t iface;
isc_nmhandle_t *statichandle;
isc_nmhandle_t *outerhandle;
/*% TCP backlog */
int backlog;
/*% libuv data */
uv_os_sock_t fd;
union uv_any_handle uv_handle;
/*% Peer address */
isc_sockaddr_t peer;
/*%
* Socket is active if it's listening, working, etc. If it's
* closing, then it doesn't make a sense, for example, to
* push handles or reqs for reuse.
*/
bool active;
bool destroying;
bool route_sock;
/*%
* Socket is closed if it's not active and all the possible
* callbacks were fired, there are no active handles, etc.
* If active==false but closed==false, that means the socket
* is closing.
*/
bool closing;
bool closed;
bool connecting;
bool connected;
bool accepting;
bool reading;
bool timedout;
/*%
* A timestamp of when the connection acceptance was delayed due
* to quota.
*/
isc_nanosecs_t quota_accept_ts;
/*%
* Established an outgoing connection, as client not server.
*/
bool client;
/*%
* The socket is processing read callback, this is guard to not read
* data before the readcb is back.
*/
bool processing;
/*%
* A TCP or TCPDNS socket has been set to use the keepalive
* timeout instead of the default idle timeout.
*/
bool keepalive;
/*%
* 'spare' handles for that can be reused to avoid allocations, for UDP.
*/
ISC_LIST(isc_nmhandle_t) inactive_handles;
size_t inactive_handles_cur;
size_t inactive_handles_max;
/*%
* 'active' handles and uvreqs, mostly for debugging purposes.
*/
ISC_LIST(isc_nmhandle_t) active_handles;
ISC_LIST(isc__nm_uvreq_t) active_uvreqs;
size_t active_handles_cur;
size_t active_handles_max;
/*%
* Used to pass a result back from listen or connect events.
*/
isc_result_t result;
/*%
* This function will be called with handle->sock
* as the argument whenever a handle's references drop
* to zero, after its reset callback has been called.
*/
isc_nm_closehandlecb_t closehandle_cb;
isc_nmhandle_t *recv_handle;
isc_nm_recv_cb_t recv_cb;
void *recv_cbarg;
isc_nm_cb_t connect_cb;
void *connect_cbarg;
isc_nm_accept_cb_t accept_cb;
void *accept_cbarg;
bool barriers_initialised;
bool manual_read_timer;
#if ISC_NETMGR_TRACE
void *backtrace[TRACE_SIZE];
int backtrace_size;
#endif
ISC_LINK(isc_nmsocket_t) active_link;
isc_job_t job;
};
void
isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf);
/*%<
* Free a buffer allocated for a receive operation.
*
* Note that as currently implemented, this doesn't actually
* free anything, marks the isc__networker's UDP receive buffer
* as "not in use".
*/
isc_nmhandle_t *
isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t const *peer,
isc_sockaddr_t const *local FLARG);
/*%<
* Get a handle for the socket 'sock', allocating a new one
* if there isn't one available in 'sock->inactivehandles'.
*
* If 'peer' is not NULL, set the handle's peer address to 'peer',
* otherwise set it to 'sock->peer'.
*
* If 'local' is not NULL, set the handle's local address to 'local',
* otherwise set it to 'sock->iface->addr'.
*
* 'sock' will be attached to 'handle->sock'. The caller may need
* to detach the socket afterward.
*/
isc__nm_uvreq_t *
isc___nm_uvreq_get(isc_nmsocket_t *sock FLARG);
/*%<
* Get a UV request structure for the socket 'sock', allocating a
* new one if there isn't one available in 'sock->inactivereqs'.
*/
void
isc___nm_uvreq_put(isc__nm_uvreq_t **req FLARG);
/*%<
* Completes the use of a UV request structure, setting '*req' to NULL.
*
* The UV request is pushed onto the 'sock->inactivereqs' stack or,
* if that doesn't work, freed.
*/
void
isc___nmsocket_init(isc_nmsocket_t *sock, isc__networker_t *worker,
isc_nmsocket_type type, isc_sockaddr_t *iface,
isc_nmsocket_t *parent FLARG);
/*%<
* Initialize socket 'sock', attach it to 'mgr', and set it to type 'type'
* and its interface to 'iface'.
*/
void
isc___nmsocket_attach(isc_nmsocket_t *sock, isc_nmsocket_t **target FLARG);
/*%<
* Attach to a socket, increasing refcount
*/
void
isc___nmsocket_detach(isc_nmsocket_t **socketp FLARG);
/*%<
* Detach from socket, decreasing refcount and possibly destroying the
* socket if it's no longer referenced.
*/
void
isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG);
/*%<
* Market 'sock' as inactive, close it if necessary, and destroy it
* if there are no remaining references or active handles.
*/
void
isc__nmsocket_shutdown(isc_nmsocket_t *sock);
/*%<
* Initiate the socket shutdown which actively calls the active
* callbacks.
*/
void
isc__nmsocket_reset(isc_nmsocket_t *sock);
/*%<
* Reset and close the socket.
*/
bool
isc__nmsocket_active(isc_nmsocket_t *sock);
/*%<
* Determine whether 'sock' is active by checking 'sock->active'
* or, for child sockets, 'sock->parent->active'.
*/
void
isc__nmsocket_clearcb(isc_nmsocket_t *sock);
/*%<
* Clear the recv and accept callbacks in 'sock'.
*/
void
isc__nmsocket_timer_stop(isc_nmsocket_t *sock);
void
isc__nmsocket_timer_start(isc_nmsocket_t *sock);
void
isc__nmsocket_timer_restart(isc_nmsocket_t *sock);
bool
isc__nmsocket_timer_running(isc_nmsocket_t *sock);
/*%<
* Start/stop/restart/check the timeout on the socket
*/
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult, bool async);
void
isc__nm_readcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult, bool async);
/*%<
* Issue a read callback on the socket, used to call the callback
* on failed conditions when the event can't be scheduled on the uv loop.
*
*/
void
isc__nm_sendcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult, bool async);
/*%<
* Issue a write callback on the socket, used to call the callback
* on failed conditions when the event can't be scheduled on the uv loop.
*/
void
isc__nm_udp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* Back-end implementation of isc_nm_send() for UDP handles.
*/
void
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
* Back-end implementation of isc_nm_read() for UDP handles.
*/
void
isc__nm_udp_close(isc_nmsocket_t *sock);
/*%<
* Close a UDP socket.
*/
void
isc__nm_udp_shutdown(isc_nmsocket_t *sock);
/*%<
* Called during the shutdown process to close and clean up connected
* sockets.
*/
void
isc__nm_udp_stoplistening(isc_nmsocket_t *sock);
/*%<
* Stop listening on 'sock'.
*/
void
isc__nm_udp_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
/*%<
* Set or clear the recv timeout for the UDP socket associated with 'handle'.
*/
void
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* Back-end implementation of isc_nm_send() for TCP handles.
*/
void
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*
* Start reading on this handle.
*/
void
isc__nm_tcp_close(isc_nmsocket_t *sock);
/*%<
* Close a TCP socket.
*/
void
isc__nm_tcp_read_stop(isc_nmhandle_t *handle);
/*%<
* Stop reading on this handle.
*/
void
isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
/*%<
* Called during the shutdown process to close and clean up connected
* sockets.
*/
void
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock);
/*%<
* Stop listening on 'sock'.
*/
void
isc__nm_tcp_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
/*%<
* Set the read timeout for the TCP socket associated with 'handle'.
*/
void
isc__nmhandle_tcp_set_manual_timer(isc_nmhandle_t *handle, const bool manual);
void
isc__nm_tcp_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* The same as 'isc__nm_tcp_send()', but with data length sent
* ahead of data (two bytes (16 bit) in big-endian format).
*/
void
isc__nm_tls_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* Back-end implementation of isc_nm_send() for TLSDNS handles.
*/
void
isc__nm_tls_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
/*%<
* The same as 'isc__nm_tls_send()', but with data length sent
* ahead of data (two bytes (16 bit) in big-endian format).
*/
void
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
/*%<
* Start reading on the TLS handle.
*/
void
isc__nm_tls_close(isc_nmsocket_t *sock);
/*%<
* Close a TLS socket.
*/
void
isc__nm_tls_read_stop(isc_nmhandle_t *handle);
/*%<
* Stop reading on the TLS handle.
*/
void
isc__nm_tls_cleanup_data(isc_nmsocket_t *sock);
void
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_tls_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nm_tls_cleartimeout(isc_nmhandle_t *handle);
/*%<
* Set the read timeout and reset the timer for the socket
* associated with 'handle', and the TCP socket it wraps
* around.
*/
void
isc__nmsocket_tls_reset(isc_nmsocket_t *sock);
void
isc__nmhandle_tls_set_manual_timer(isc_nmhandle_t *handle, const bool manual);
const char *
isc__nm_tls_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
void
isc__nmhandle_tls_keepalive(isc_nmhandle_t *handle, bool value);
/*%<
* Set the keepalive value on the underlying TCP handle.
*/
void
isc__nm_async_tls_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx,
const int tid);
void
isc__nmhandle_tls_setwritetimeout(isc_nmhandle_t *handle,
uint64_t write_timeout);
bool
isc__nmsocket_tls_timer_running(isc_nmsocket_t *sock);
void
isc__nmsocket_tls_timer_restart(isc_nmsocket_t *sock);
void
isc__nmsocket_tls_timer_stop(isc_nmsocket_t *sock);
void
isc__nm_tls_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
void
isc__nmhandle_tls_get_selected_alpn(isc_nmhandle_t *handle,
const unsigned char **alpn,
unsigned int *alpnlen);
isc_result_t
isc__nmhandle_tls_set_tcp_nodelay(isc_nmhandle_t *handle, const bool value);
#if HAVE_LIBNGHTTP2
void
isc__nm_http_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nm_http_cleartimeout(isc_nmhandle_t *handle);
/*%<
* Set the read timeout and reset the timer for the socket
* associated with 'handle', and the TLS/TCP socket it wraps
* around.
*/
void
isc__nmhandle_http_keepalive(isc_nmhandle_t *handle, bool value);
/*%<
* Set the keepalive value on the underlying session handle
*/
void
isc__nm_http_cleanup_data(isc_nmsocket_t *sock);
isc_result_t
isc__nm_http_request(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_recv_cb_t reply_cb, void *cbarg);
void
isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_http_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_http_close(isc_nmsocket_t *sock);
void
isc__nm_http_bad_request(isc_nmhandle_t *handle);
/*%<
* Respond to the request with 400 "Bad Request" status.
*
* Requires:
* \li 'handle' is a valid HTTP netmgr handle object, referencing a server-side
* socket
*/
bool
isc__nm_http_has_encryption(const isc_nmhandle_t *handle);
void
isc__nm_http_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl);
const char *
isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
bool
isc__nm_parse_httpquery(const char *query_string, const char **start,
size_t *len);
char *
isc__nm_base64url_to_base64(isc_mem_t *mem, const char *base64url,
const size_t base64url_len, size_t *res_len);
char *
isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64,
const size_t base64_len, size_t *res_len);
void
isc__nm_httpsession_attach(isc_nm_http_session_t *source,
isc_nm_http_session_t **targetp);
void
isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp);
isc_nmhandle_t *
isc__nm_httpsession_handle(isc_nm_http_session_t *session);
void
isc__nm_http_set_tlsctx(isc_nmsocket_t *sock, isc_tlsctx_t *tlsctx);
void
isc__nm_http_set_max_streams(isc_nmsocket_t *listener,
const uint32_t max_concurrent_streams);
#endif
void
isc__nm_streamdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb,
void *cbarg);
void
isc__nm_streamdns_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_streamdns_close(isc_nmsocket_t *sock);
void
isc__nm_streamdns_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_streamdns_cleanup_data(isc_nmsocket_t *sock);
void
isc__nmhandle_streamdns_cleartimeout(isc_nmhandle_t *handle);
void
isc__nmhandle_streamdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nmhandle_streamdns_keepalive(isc_nmhandle_t *handle, bool value);
void
isc__nmhandle_streamdns_setwritetimeout(isc_nmhandle_t *handle,
uint32_t timeout);
bool
isc__nm_streamdns_has_encryption(const isc_nmhandle_t *handle);
const char *
isc__nm_streamdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
void
isc__nm_streamdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
isc_result_t
isc__nm_streamdns_xfr_checkperm(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_reset(isc_nmsocket_t *sock);
bool
isc__nmsocket_streamdns_timer_running(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_timer_stop(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_timer_restart(isc_nmsocket_t *sock);
void
isc__nm_streamdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
bool
isc__nm_valid_proxy_addresses(const isc_sockaddr_t *src,
const isc_sockaddr_t *dst);
void
isc__nm_proxystream_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
void
isc__nm_proxystream_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_proxystream_cleanup_data(isc_nmsocket_t *sock);
void
isc__nmhandle_proxystream_cleartimeout(isc_nmhandle_t *handle);
void
isc__nmhandle_proxystream_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nmhandle_proxystream_keepalive(isc_nmhandle_t *handle, bool value);
void
isc__nmhandle_proxystream_setwritetimeout(isc_nmhandle_t *handle,
uint64_t write_timeout);
void
isc__nmsocket_proxystream_reset(isc_nmsocket_t *sock);
bool
isc__nmsocket_proxystream_timer_running(isc_nmsocket_t *sock);
void
isc__nmsocket_proxystream_timer_restart(isc_nmsocket_t *sock);
void
isc__nmsocket_proxystream_timer_stop(isc_nmsocket_t *sock);
void
isc__nmhandle_proxystream_set_manual_timer(isc_nmhandle_t *handle,
const bool manual);
isc_result_t
isc__nmhandle_proxystream_set_tcp_nodelay(isc_nmhandle_t *handle,
const bool value);
void
isc__nm_proxystream_read_stop(isc_nmhandle_t *handle);
void
isc__nm_proxystream_close(isc_nmsocket_t *sock);
void
isc__nm_proxystream_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb,
void *cbarg);
void
isc__nm_proxystream_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_proxystream_senddns(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_proxystream_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
bool
isc__nm_proxystream_has_encryption(const isc_nmhandle_t *handle);
const char *
isc__nm_proxystream_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
void
isc__nmhandle_proxystream_get_selected_alpn(isc_nmhandle_t *handle,
const unsigned char **alpn,
unsigned int *alpnlen);
void
isc__nm_proxyudp_failed_read_cb(isc_nmsocket_t *sock, const isc_result_t result,
const bool async);
void
isc__nm_proxyudp_stoplistening(isc_nmsocket_t *listener);
void
isc__nm_proxyudp_cleanup_data(isc_nmsocket_t *sock);
void
isc__nmhandle_proxyudp_cleartimeout(isc_nmhandle_t *handle);
void
isc__nmhandle_proxyudp_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nmhandle_proxyudp_setwritetimeout(isc_nmhandle_t *handle,
uint64_t write_timeout);
bool
isc__nmsocket_proxyudp_timer_running(isc_nmsocket_t *sock);
void
isc__nmsocket_proxyudp_timer_restart(isc_nmsocket_t *sock);
void
isc__nmsocket_proxyudp_timer_stop(isc_nmsocket_t *sock);
void
isc__nm_proxyudp_close(isc_nmsocket_t *sock);
void
isc__nm_proxyudp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_proxyudp_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_incstats(isc_nmsocket_t *sock, isc__nm_statid_t id);
/*%<
* Increment socket-related statistics counters.
*/
void
isc__nm_decstats(isc_nmsocket_t *sock, isc__nm_statid_t id);
/*%<
* Decrement socket-related statistics counters.
*/
isc_result_t
isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp);
/*%<
* Platform independent socket() version
*/
void
isc__nm_closesocket(uv_os_sock_t sock);
/*%<
* Platform independent closesocket() version
*/
isc_result_t
isc__nm_socket_reuse(uv_os_sock_t fd, int val);
/*%<
* Set the SO_REUSEADDR or SO_REUSEPORT (or equivalent) socket option on the fd
*/
isc_result_t
isc__nm_socket_reuse_lb(uv_os_sock_t fd);
/*%<
* Set the SO_REUSEPORT_LB (or equivalent) socket option on the fd
*/
isc_result_t
isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family);
/*%<
* Disable the Path MTU Discovery, either by disabling IP(V6)_DONTFRAG socket
* option, or setting the IP(V6)_MTU_DISCOVER socket option to IP_PMTUDISC_OMIT
*/
isc_result_t
isc__nm_socket_v6only(uv_os_sock_t fd, sa_family_t sa_family);
/*%<
* Restrict the socket to sending and receiving IPv6 packets only
*/
isc_result_t
isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms);
/*%<
* Set the connection timeout in milliseconds, on non-Linux platforms,
* the minimum value must be at least 1000 (1 second).
*/
isc_result_t
isc__nm_socket_tcp_nodelay(const uv_os_sock_t fd, bool value);
/*%<
* Disables/Enables Nagle's algorithm on a TCP socket (sets TCP_NODELAY if
* 'value' equals 'true' or vice versa).
*/
isc_result_t
isc__nm_socket_tcp_maxseg(uv_os_sock_t fd, int size);
/*%<
* Set the TCP maximum segment size
*/
isc_result_t
isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family);
/*%<
* Use minimum MTU on IPv6 sockets
*/
void
isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle);
/*%>
* Sets the pre-configured network buffers size on the handle.
*/
void
isc__nmsocket_barrier_init(isc_nmsocket_t *listener);
/*%>
* Initialise the socket synchronisation barrier according to the
* number of children.
*/
void
isc__nmsocket_stop(isc_nmsocket_t *listener);
/*%>
* Broadcast "stop" event for a listener socket across all workers and
* wait its processing completion - then, stop and close the underlying
* transport listener socket.
*
* The primitive is used in multi-layer transport listener sockets to
* implement shutdown properly: after the broadcasted events has been
* processed it is safe to destroy the shared data within the listener
* socket (including shutting down the underlying transport listener
* socket).
*/
void
isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
void
isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
isc__nm_uvreq_t *
isc___nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr FLARG);
void
isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf);
void
isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
const struct sockaddr *addr, unsigned int flags);
void
isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
isc_result_t
isc__nm_start_reading(isc_nmsocket_t *sock);
void
isc__nm_stop_reading(isc_nmsocket_t *sock);
bool
isc__nmsocket_closing(isc_nmsocket_t *sock);
bool
isc__nm_closing(isc__networker_t *worker);
void
isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
isc_result_t eresult, bool async);
void
isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
isc_result_t eresult, bool async);
void
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async);
void
isc__nm_accept_connection_log(isc_nmsocket_t *sock, isc_result_t result,
bool can_log_quota);
/*
* Timeout callbacks
*/
void
isc__nmsocket_connecttimeout_cb(uv_timer_t *timer);
void
isc__nmsocket_readtimeout_cb(uv_timer_t *timer);
void
isc__nmsocket_writetimeout_cb(void *data, isc_result_t eresult);
/*
* Bind to the socket, but allow binding to IPv6 tentative addresses reported by
* the route socket by setting IP_FREEBIND (or equivalent).
*/
int
isc__nm_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
unsigned int flags);
int
isc__nm_tcp_freebind(uv_tcp_t *handle, const struct sockaddr *addr,
unsigned int flags);
void
isc__nmsocket_log_tls_session_reuse(isc_nmsocket_t *sock, isc_tls_t *tls);
/*
* Logging helpers
*/
void
isc__netmgr_log(const isc_nm_t *netmgr, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
void
isc__nmsocket_log(const isc_nmsocket_t *sock, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
void
isc__nmhandle_log(const isc_nmhandle_t *handle, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
void
isc__nm_received_proxy_header_log(isc_nmhandle_t *handle,
const isc_proxy2_command_t cmd,
const int socktype,
const isc_sockaddr_t *restrict src_addr,
const isc_sockaddr_t *restrict dst_addr,
const isc_region_t *restrict tlvs);
void
isc__nmhandle_set_manual_timer(isc_nmhandle_t *handle, const bool manual);
/*
* Set manual read timer control mode - so that it will not get reset
* automatically on read nor get started when read is initiated.
*/
void
isc__nmhandle_get_selected_alpn(isc_nmhandle_t *handle,
const unsigned char **alpn,
unsigned int *alpnlen);
/*
* Returns a non zero terminated ALPN identifier via 'alpn'. The
* length of the identifier is returned via 'alpnlen'. If after the
* call either 'alpn == NULL' or 'alpnlen == 0', then identifier was
* not negotiated of the underlying protocol of the connection
* represented via the given handle does not support ALPN.
*/
void
isc__nm_senddns(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg);
/*%<
* The same as 'isc_nm_send()', but with data length sent
* ahead of data (two bytes (16 bit) in big-endian format).
*/