Annotation of src/external/mpl/bind/dist/lib/isc/netmgr/netmgr-int.h, Revision 1.1.1.3
1.1 christos 1: /* $NetBSD$ */
2:
3: /*
4: * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
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
1.1.1.3 ! christos 8: * file, you can obtain one at https://mozilla.org/MPL/2.0/.
1.1 christos 9: *
10: * See the COPYRIGHT file distributed with this work for additional
11: * information regarding copyright ownership.
12: */
13:
14: #pragma once
15:
16: #include <unistd.h>
17: #include <uv.h>
18:
1.1.1.3 ! christos 19: #include <openssl/err.h>
! 20: #include <openssl/ssl.h>
! 21:
1.1 christos 22: #include <isc/astack.h>
23: #include <isc/atomic.h>
24: #include <isc/buffer.h>
25: #include <isc/condition.h>
26: #include <isc/magic.h>
27: #include <isc/mem.h>
28: #include <isc/netmgr.h>
29: #include <isc/queue.h>
1.1.1.2 christos 30: #include <isc/quota.h>
1.1 christos 31: #include <isc/random.h>
32: #include <isc/refcount.h>
33: #include <isc/region.h>
34: #include <isc/result.h>
35: #include <isc/sockaddr.h>
36: #include <isc/stats.h>
37: #include <isc/thread.h>
38: #include <isc/util.h>
39:
40: #include "uv-compat.h"
41:
42: #define ISC_NETMGR_TID_UNKNOWN -1
43:
44: #if !defined(WIN32)
45: /*
46: * New versions of libuv support recvmmsg on unices.
47: * Since recvbuf is only allocated per worker allocating a bigger one is not
48: * that wasteful.
49: * 20 here is UV__MMSG_MAXWIDTH taken from the current libuv source, nothing
50: * will break if the original value changes.
51: */
52: #define ISC_NETMGR_RECVBUF_SIZE (20 * 65536)
53: #else
54: #define ISC_NETMGR_RECVBUF_SIZE (65536)
55: #endif
56:
1.1.1.3 ! christos 57: #if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
! 58: #define HAVE_SO_REUSEPORT_LB 1
! 59: #endif
! 60:
! 61: /*
! 62: * Define NETMGR_TRACE to activate tracing of handles and sockets.
! 63: * This will impair performance but enables us to quickly determine,
! 64: * if netmgr resources haven't been cleaned up on shutdown, which ones
! 65: * are still in use.
! 66: */
! 67: #ifdef NETMGR_TRACE
! 68: #define TRACE_SIZE 8
! 69:
! 70: void
! 71: isc__nm_dump_active(isc_nm_t *nm);
! 72:
! 73: #if defined(__linux__)
! 74: #include <syscall.h>
! 75: #define gettid() (uint32_t) syscall(SYS_gettid)
! 76: #elif defined(_WIN32)
! 77: #define gettid() (uint32_t) GetCurrentThreadId()
! 78: #else
! 79: #define gettid() (uint32_t) pthread_self()
! 80: #endif
! 81:
! 82: #ifdef NETMGR_TRACE_VERBOSE
! 83: #define NETMGR_TRACE_LOG(format, ...) \
! 84: fprintf(stderr, "%" PRIu32 ":%d:%s:%u:%s:" format, gettid(), \
! 85: isc_nm_tid(), file, line, func, __VA_ARGS__)
! 86: #else
! 87: #define NETMGR_TRACE_LOG(format, ...) \
! 88: (void)file; \
! 89: (void)line; \
! 90: (void)func;
! 91: #endif
! 92:
! 93: #define FLARG_PASS , file, line, func
! 94: #define FLARG \
! 95: , const char *file __attribute__((unused)), \
! 96: unsigned int line __attribute__((unused)), \
! 97: const char *func __attribute__((unused))
! 98: #define FLARG_IEVENT(ievent) \
! 99: const char *file = ievent->file; \
! 100: unsigned int line = ievent->line; \
! 101: const char *func = ievent->func;
! 102: #define FLARG_IEVENT_PASS(ievent) \
! 103: ievent->file = file; \
! 104: ievent->line = line; \
! 105: ievent->func = func;
! 106: #define isc__nm_uvreq_get(req, sock) \
! 107: isc___nm_uvreq_get(req, sock, __FILE__, __LINE__, __func__)
! 108: #define isc__nm_uvreq_put(req, sock) \
! 109: isc___nm_uvreq_put(req, sock, __FILE__, __LINE__, __func__)
! 110: #define isc__nmsocket_init(sock, mgr, type, iface) \
! 111: isc___nmsocket_init(sock, mgr, type, iface, __FILE__, __LINE__, \
! 112: __func__)
! 113: #define isc__nmsocket_put(sockp) \
! 114: isc___nmsocket_put(sockp, __FILE__, __LINE__, __func__)
! 115: #define isc__nmsocket_attach(sock, target) \
! 116: isc___nmsocket_attach(sock, target, __FILE__, __LINE__, __func__)
! 117: #define isc__nmsocket_detach(socketp) \
! 118: isc___nmsocket_detach(socketp, __FILE__, __LINE__, __func__)
! 119: #define isc__nmsocket_close(socketp) \
! 120: isc___nmsocket_close(socketp, __FILE__, __LINE__, __func__)
! 121: #define isc__nmhandle_get(sock, peer, local) \
! 122: isc___nmhandle_get(sock, peer, local, __FILE__, __LINE__, __func__)
! 123: #define isc__nmsocket_prep_destroy(sock) \
! 124: isc___nmsocket_prep_destroy(sock, __FILE__, __LINE__, __func__)
! 125: #else
! 126: #define NETMGR_TRACE_LOG(format, ...)
! 127:
! 128: #define FLARG_PASS
! 129: #define FLARG
! 130: #define FLARG_IEVENT(ievent)
! 131: #define FLARG_IEVENT_PASS(ievent)
! 132: #define isc__nm_uvreq_get(req, sock) isc___nm_uvreq_get(req, sock)
! 133: #define isc__nm_uvreq_put(req, sock) isc___nm_uvreq_put(req, sock)
! 134: #define isc__nmsocket_init(sock, mgr, type, iface) \
! 135: isc___nmsocket_init(sock, mgr, type, iface)
! 136: #define isc__nmsocket_put(sockp) isc___nmsocket_put(sockp)
! 137: #define isc__nmsocket_attach(sock, target) isc___nmsocket_attach(sock, target)
! 138: #define isc__nmsocket_detach(socketp) isc___nmsocket_detach(socketp)
! 139: #define isc__nmsocket_close(socketp) isc___nmsocket_close(socketp)
! 140: #define isc__nmhandle_get(sock, peer, local) \
! 141: isc___nmhandle_get(sock, peer, local)
! 142: #define isc__nmsocket_prep_destroy(sock) isc___nmsocket_prep_destroy(sock)
! 143: #endif
! 144:
1.1 christos 145: /*
146: * Single network event loop worker.
147: */
148: typedef struct isc__networker {
149: isc_nm_t *mgr;
150: int id; /* thread id */
151: uv_loop_t loop; /* libuv loop structure */
152: uv_async_t async; /* async channel to send
153: * data to this networker */
154: isc_mutex_t lock;
155: isc_condition_t cond;
156: bool paused;
157: bool finished;
158: isc_thread_t thread;
159: isc_queue_t *ievents; /* incoming async events */
160: isc_queue_t *ievents_prio; /* priority async events
161: * used for listening etc.
162: * can be processed while
163: * worker is paused */
164: isc_refcount_t references;
165: atomic_int_fast64_t pktcount;
166: char *recvbuf;
167: bool recvbuf_inuse;
168: } isc__networker_t;
169:
170: /*
171: * A general handle for a connection bound to a networker. For UDP
172: * connections we have peer address here, so both TCP and UDP can be
173: * handled with a simple send-like function
174: */
1.1.1.3 ! christos 175: #define NMHANDLE_MAGIC ISC_MAGIC('N', 'M', 'H', 'D')
! 176: #define VALID_NMHANDLE(t) \
! 177: (ISC_MAGIC_VALID(t, NMHANDLE_MAGIC) && \
! 178: atomic_load(&(t)->references) > 0)
1.1 christos 179:
180: typedef void (*isc__nm_closecb)(isc_nmhandle_t *);
181:
182: struct isc_nmhandle {
183: int magic;
184: isc_refcount_t references;
185:
186: /*
187: * The socket is not 'attached' in the traditional
188: * reference-counting sense. Instead, we keep all handles in an
189: * array in the socket object. This way, we don't have circular
190: * dependencies and we can close all handles when we're destroying
191: * the socket.
192: */
193: isc_nmsocket_t *sock;
1.1.1.3 ! christos 194: size_t ah_pos; /* Position in the socket's 'active handles' array */
1.1 christos 195:
196: isc_sockaddr_t peer;
197: isc_sockaddr_t local;
198: isc_nm_opaquecb_t doreset; /* reset extra callback, external */
199: isc_nm_opaquecb_t dofree; /* free extra callback, external */
1.1.1.3 ! christos 200: #ifdef NETMGR_TRACE
! 201: void *backtrace[TRACE_SIZE];
! 202: int backtrace_size;
! 203: LINK(isc_nmhandle_t) active_link;
! 204: #endif
1.1 christos 205: void *opaque;
206: char extra[];
207: };
208:
209: /*
210: * An interface - an address we can listen on.
211: */
212: struct isc_nmiface {
213: isc_sockaddr_t addr;
214: };
215:
216: typedef enum isc__netievent_type {
1.1.1.3 ! christos 217: netievent_udpconnect,
1.1 christos 218: netievent_udpsend,
1.1.1.3 ! christos 219: netievent_udpread,
1.1 christos 220: netievent_udpstop,
1.1.1.3 ! christos 221: netievent_udpcancel,
! 222: netievent_udpclose,
1.1 christos 223:
224: netievent_tcpconnect,
225: netievent_tcpsend,
226: netievent_tcpstartread,
227: netievent_tcppauseread,
1.1.1.2 christos 228: netievent_tcpaccept,
1.1 christos 229: netievent_tcpstop,
1.1.1.3 ! christos 230: netievent_tcpcancel,
1.1 christos 231: netievent_tcpclose,
1.1.1.2 christos 232:
1.1.1.3 ! christos 233: netievent_tcpdnsaccept,
! 234: netievent_tcpdnsconnect,
1.1.1.2 christos 235: netievent_tcpdnssend,
1.1.1.3 ! christos 236: netievent_tcpdnsread,
! 237: netievent_tcpdnscancel,
! 238: netievent_tcpdnsclose,
! 239: netievent_tcpdnsstop,
! 240:
! 241: netievent_tlsclose,
! 242: netievent_tlssend,
! 243: netievent_tlsstartread,
! 244: netievent_tlsconnect,
! 245: netievent_tlsdobio,
! 246:
! 247: netievent_tlsdnsaccept,
! 248: netievent_tlsdnsconnect,
! 249: netievent_tlsdnssend,
! 250: netievent_tlsdnsread,
! 251: netievent_tlsdnscancel,
! 252: netievent_tlsdnsclose,
! 253: netievent_tlsdnsstop,
1.1 christos 254:
1.1.1.3 ! christos 255: netievent_close,
1.1 christos 256: netievent_shutdown,
257: netievent_stop,
1.1.1.3 ! christos 258: netievent_pause,
! 259:
! 260: netievent_connectcb,
! 261: netievent_readcb,
! 262: netievent_sendcb,
! 263:
1.1 christos 264: netievent_prio = 0xff, /* event type values higher than this
265: * will be treated as high-priority
266: * events, which can be processed
267: * while the netmgr is paused.
268: */
269: netievent_udplisten,
270: netievent_tcplisten,
1.1.1.3 ! christos 271: netievent_tcpdnslisten,
! 272: netievent_resume,
! 273: netievent_detach,
1.1 christos 274: } isc__netievent_type;
275:
276: typedef union {
277: isc_nm_recv_cb_t recv;
278: isc_nm_cb_t send;
279: isc_nm_cb_t connect;
1.1.1.2 christos 280: isc_nm_accept_cb_t accept;
1.1 christos 281: } isc__nm_cb_t;
282:
283: /*
284: * Wrapper around uv_req_t with 'our' fields in it. req->data should
285: * always point to its parent. Note that we always allocate more than
286: * sizeof(struct) because we make room for different req types;
287: */
288: #define UVREQ_MAGIC ISC_MAGIC('N', 'M', 'U', 'R')
289: #define VALID_UVREQ(t) ISC_MAGIC_VALID(t, UVREQ_MAGIC)
290:
1.1.1.3 ! christos 291: typedef struct isc__nm_uvreq isc__nm_uvreq_t;
! 292: struct isc__nm_uvreq {
1.1 christos 293: int magic;
294: isc_nmsocket_t *sock;
295: isc_nmhandle_t *handle;
1.1.1.3 ! christos 296: char tcplen[2]; /* The TCP DNS message length */
1.1 christos 297: uv_buf_t uvbuf; /* translated isc_region_t, to be
298: * sent or received */
299: isc_sockaddr_t local; /* local address */
300: isc_sockaddr_t peer; /* peer address */
301: isc__nm_cb_t cb; /* callback */
302: void *cbarg; /* callback argument */
303: uv_pipe_t ipc; /* used for sending socket
304: * uv_handles to other threads */
305: union {
1.1.1.3 ! christos 306: uv_handle_t handle;
1.1 christos 307: uv_req_t req;
308: uv_getaddrinfo_t getaddrinfo;
309: uv_getnameinfo_t getnameinfo;
310: uv_shutdown_t shutdown;
311: uv_write_t write;
312: uv_connect_t connect;
313: uv_udp_send_t udp_send;
314: uv_fs_t fs;
315: uv_work_t work;
316: } uv_req;
1.1.1.3 ! christos 317: ISC_LINK(isc__nm_uvreq_t) link;
! 318: };
! 319:
! 320: void *
! 321: isc__nm_get_netievent(isc_nm_t *mgr, isc__netievent_type type);
! 322: /*%<
! 323: * Allocate an ievent and set the type.
! 324: */
! 325: void
! 326: isc__nm_put_netievent(isc_nm_t *mgr, void *ievent);
! 327:
! 328: /*
! 329: * The macros here are used to simulate the "inheritance" in C, there's the base
! 330: * netievent structure that contains just its own type and socket, and there are
! 331: * extended netievent types that also have handles or requests or other data.
! 332: *
! 333: * The macros here ensure that:
! 334: *
! 335: * 1. every netievent type has matching definition, declaration and
! 336: * implementation
! 337: *
! 338: * 2. we handle all the netievent types of same subclass the same, e.g. if the
! 339: * extended netievent contains handle, we always attach to the handle in
! 340: * the ctor and detach from the handle in dtor.
! 341: *
! 342: * There are three macros here for each netievent subclass:
! 343: *
! 344: * 1. NETIEVENT_*_TYPE(type) creates the typedef for each type; used below in
! 345: * this header
! 346: *
! 347: * 2. NETIEVENT_*_DECL(type) generates the declaration of the get and put
! 348: * functions (isc__nm_get_netievent_* and isc__nm_put_netievent_*); used
! 349: * below in this header
! 350: *
! 351: * 3. NETIEVENT_*_DEF(type) generates the definition of the functions; used
! 352: * either in netmgr.c or matching protocol file (e.g. udp.c, tcp.c, etc.)
! 353: */
! 354:
! 355: #define NETIEVENT__SOCKET \
! 356: isc__netievent_type type; \
! 357: isc_nmsocket_t *sock; \
! 358: const char *file; \
! 359: unsigned int line; \
! 360: const char *func
1.1 christos 361:
362: typedef struct isc__netievent__socket {
1.1.1.3 ! christos 363: NETIEVENT__SOCKET;
1.1 christos 364: } isc__netievent__socket_t;
365:
1.1.1.3 ! christos 366: #define NETIEVENT_SOCKET_TYPE(type) \
! 367: typedef isc__netievent__socket_t isc__netievent_##type##_t;
! 368:
! 369: #define NETIEVENT_SOCKET_DECL(type) \
! 370: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 371: isc_nm_t *nm, isc_nmsocket_t *sock); \
! 372: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 373: isc__netievent_##type##_t *ievent);
! 374:
! 375: #define NETIEVENT_SOCKET_DEF(type) \
! 376: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 377: isc_nm_t *nm, isc_nmsocket_t *sock) { \
! 378: isc__netievent_##type##_t *ievent = \
! 379: isc__nm_get_netievent(nm, netievent_##type); \
! 380: isc__nmsocket_attach(sock, &ievent->sock); \
! 381: \
! 382: return (ievent); \
! 383: } \
! 384: \
! 385: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 386: isc__netievent_##type##_t *ievent) { \
! 387: isc__nmsocket_detach(&ievent->sock); \
! 388: isc__nm_put_netievent(nm, ievent); \
! 389: }
1.1 christos 390:
391: typedef struct isc__netievent__socket_req {
1.1.1.3 ! christos 392: NETIEVENT__SOCKET;
1.1 christos 393: isc__nm_uvreq_t *req;
394: } isc__netievent__socket_req_t;
395:
1.1.1.3 ! christos 396: #define NETIEVENT_SOCKET_REQ_TYPE(type) \
! 397: typedef isc__netievent__socket_req_t isc__netievent_##type##_t;
1.1 christos 398:
1.1.1.3 ! christos 399: #define NETIEVENT_SOCKET_REQ_DECL(type) \
! 400: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 401: isc_nm_t *nm, isc_nmsocket_t *sock, isc__nm_uvreq_t *req); \
! 402: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 403: isc__netievent_##type##_t *ievent);
! 404:
! 405: #define NETIEVENT_SOCKET_REQ_DEF(type) \
! 406: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 407: isc_nm_t *nm, isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { \
! 408: isc__netievent_##type##_t *ievent = \
! 409: isc__nm_get_netievent(nm, netievent_##type); \
! 410: isc__nmsocket_attach(sock, &ievent->sock); \
! 411: ievent->req = req; \
! 412: \
! 413: return (ievent); \
! 414: } \
! 415: \
! 416: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 417: isc__netievent_##type##_t *ievent) { \
! 418: isc__nmsocket_detach(&ievent->sock); \
! 419: isc__nm_put_netievent(nm, ievent); \
! 420: }
! 421:
! 422: typedef struct isc__netievent__socket_req_result {
1.1 christos 423: isc__netievent_type type;
424: isc_nmsocket_t *sock;
1.1.1.3 ! christos 425: isc__nm_uvreq_t *req;
! 426: isc_result_t result;
! 427: } isc__netievent__socket_req_result_t;
! 428:
! 429: #define NETIEVENT_SOCKET_REQ_RESULT_TYPE(type) \
! 430: typedef isc__netievent__socket_req_result_t isc__netievent_##type##_t;
1.1 christos 431:
1.1.1.3 ! christos 432: #define NETIEVENT_SOCKET_REQ_RESULT_DECL(type) \
! 433: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 434: isc_nm_t *nm, isc_nmsocket_t *sock, isc__nm_uvreq_t *req, \
! 435: isc_result_t result); \
! 436: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 437: isc__netievent_##type##_t *ievent);
! 438:
! 439: #define NETIEVENT_SOCKET_REQ_RESULT_DEF(type) \
! 440: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 441: isc_nm_t *nm, isc_nmsocket_t *sock, isc__nm_uvreq_t *req, \
! 442: isc_result_t result) { \
! 443: isc__netievent_##type##_t *ievent = \
! 444: isc__nm_get_netievent(nm, netievent_##type); \
! 445: isc__nmsocket_attach(sock, &ievent->sock); \
! 446: ievent->req = req; \
! 447: ievent->result = result; \
! 448: \
! 449: return (ievent); \
! 450: } \
! 451: \
! 452: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 453: isc__netievent_##type##_t *ievent) { \
! 454: isc__nmsocket_detach(&ievent->sock); \
! 455: isc__nm_put_netievent(nm, ievent); \
! 456: }
1.1 christos 457:
458: typedef struct isc__netievent__socket_handle {
1.1.1.3 ! christos 459: NETIEVENT__SOCKET;
1.1 christos 460: isc_nmhandle_t *handle;
461: } isc__netievent__socket_handle_t;
462:
1.1.1.3 ! christos 463: #define NETIEVENT_SOCKET_HANDLE_TYPE(type) \
! 464: typedef isc__netievent__socket_handle_t isc__netievent_##type##_t;
! 465:
! 466: #define NETIEVENT_SOCKET_HANDLE_DECL(type) \
! 467: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 468: isc_nm_t *nm, isc_nmsocket_t *sock, isc_nmhandle_t *handle); \
! 469: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 470: isc__netievent_##type##_t *ievent);
! 471:
! 472: #define NETIEVENT_SOCKET_HANDLE_DEF(type) \
! 473: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 474: isc_nm_t *nm, isc_nmsocket_t *sock, isc_nmhandle_t *handle) { \
! 475: isc__netievent_##type##_t *ievent = \
! 476: isc__nm_get_netievent(nm, netievent_##type); \
! 477: isc__nmsocket_attach(sock, &ievent->sock); \
! 478: isc_nmhandle_attach(handle, &ievent->handle); \
! 479: \
! 480: return (ievent); \
! 481: } \
! 482: \
! 483: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 484: isc__netievent_##type##_t *ievent) { \
! 485: isc__nmsocket_detach(&ievent->sock); \
! 486: isc_nmhandle_detach(&ievent->handle); \
! 487: isc__nm_put_netievent(nm, ievent); \
! 488: }
! 489:
1.1.1.2 christos 490: typedef struct isc__netievent__socket_quota {
1.1.1.3 ! christos 491: NETIEVENT__SOCKET;
1.1.1.2 christos 492: isc_quota_t *quota;
493: } isc__netievent__socket_quota_t;
494:
1.1.1.3 ! christos 495: #define NETIEVENT_SOCKET_QUOTA_TYPE(type) \
! 496: typedef isc__netievent__socket_quota_t isc__netievent_##type##_t;
! 497:
! 498: #define NETIEVENT_SOCKET_QUOTA_DECL(type) \
! 499: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 500: isc_nm_t *nm, isc_nmsocket_t *sock, isc_quota_t *quota); \
! 501: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 502: isc__netievent_##type##_t *ievent);
! 503:
! 504: #define NETIEVENT_SOCKET_QUOTA_DEF(type) \
! 505: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 506: isc_nm_t *nm, isc_nmsocket_t *sock, isc_quota_t *quota) { \
! 507: isc__netievent_##type##_t *ievent = \
! 508: isc__nm_get_netievent(nm, netievent_##type); \
! 509: isc__nmsocket_attach(sock, &ievent->sock); \
! 510: ievent->quota = quota; \
! 511: \
! 512: return (ievent); \
! 513: } \
! 514: \
! 515: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 516: isc__netievent_##type##_t *ievent) { \
! 517: isc__nmsocket_detach(&ievent->sock); \
! 518: isc__nm_put_netievent(nm, ievent); \
! 519: }
1.1.1.2 christos 520:
1.1 christos 521: typedef struct isc__netievent_udpsend {
1.1.1.3 ! christos 522: NETIEVENT__SOCKET;
1.1 christos 523: isc_sockaddr_t peer;
524: isc__nm_uvreq_t *req;
525: } isc__netievent_udpsend_t;
526:
1.1.1.3 ! christos 527: typedef struct isc__netievent_tlsconnect {
! 528: isc__netievent_type type;
! 529: isc_nmsocket_t *sock;
! 530: SSL_CTX *ctx;
! 531: isc_sockaddr_t local; /* local address */
! 532: isc_sockaddr_t peer; /* peer address */
! 533: } isc__netievent_tlsconnect_t;
! 534:
1.1 christos 535: typedef struct isc__netievent {
536: isc__netievent_type type;
537: } isc__netievent_t;
538:
1.1.1.3 ! christos 539: #define NETIEVENT_TYPE(type) typedef isc__netievent_t isc__netievent_##type##_t;
! 540:
! 541: #define NETIEVENT_DECL(type) \
! 542: isc__netievent_##type##_t *isc__nm_get_netievent_##type(isc_nm_t *nm); \
! 543: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 544: isc__netievent_##type##_t *ievent);
! 545:
! 546: #define NETIEVENT_DEF(type) \
! 547: isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
! 548: isc_nm_t *nm) { \
! 549: isc__netievent_##type##_t *ievent = \
! 550: isc__nm_get_netievent(nm, netievent_##type); \
! 551: \
! 552: return (ievent); \
! 553: } \
! 554: \
! 555: void isc__nm_put_netievent_##type(isc_nm_t *nm, \
! 556: isc__netievent_##type##_t *ievent) { \
! 557: isc__nm_put_netievent(nm, ievent); \
! 558: }
1.1 christos 559:
560: typedef union {
561: isc__netievent_t ni;
562: isc__netievent__socket_t nis;
563: isc__netievent__socket_req_t nisr;
564: isc__netievent_udpsend_t nius;
1.1.1.2 christos 565: isc__netievent__socket_quota_t nisq;
1.1.1.3 ! christos 566: isc__netievent_tlsconnect_t nitc;
1.1 christos 567: } isc__netievent_storage_t;
568:
569: /*
570: * Network manager
571: */
572: #define NM_MAGIC ISC_MAGIC('N', 'E', 'T', 'M')
573: #define VALID_NM(t) ISC_MAGIC_VALID(t, NM_MAGIC)
574:
575: struct isc_nm {
576: int magic;
577: isc_refcount_t references;
578: isc_mem_t *mctx;
579: uint32_t nworkers;
580: isc_mutex_t lock;
581: isc_condition_t wkstatecond;
582: isc__networker_t *workers;
583:
584: isc_stats_t *stats;
585:
586: isc_mempool_t *reqpool;
587: isc_mutex_t reqlock;
588:
589: isc_mempool_t *evpool;
590: isc_mutex_t evlock;
591:
1.1.1.3 ! christos 592: uint_fast32_t workers_running;
! 593: uint_fast32_t workers_paused;
1.1 christos 594: atomic_uint_fast32_t maxudp;
595:
596: /*
597: * Active connections are being closed and new connections are
598: * no longer allowed.
599: */
600: atomic_bool closing;
601:
602: /*
603: * A worker is actively waiting for other workers, for example to
604: * stop listening; that means no other thread can do the same thing
605: * or pause, or we'll deadlock. We have to either re-enqueue our
606: * event or wait for the other one to finish if we want to pause.
607: */
608: atomic_bool interlocked;
609:
610: /*
611: * Timeout values for TCP connections, corresponding to
612: * tcp-intiial-timeout, tcp-idle-timeout, tcp-keepalive-timeout,
613: * and tcp-advertised-timeout. Note that these are stored in
614: * milliseconds so they can be used directly with the libuv timer,
615: * but they are configured in tenths of seconds.
616: */
1.1.1.3 ! christos 617: atomic_uint_fast32_t init;
! 618: atomic_uint_fast32_t idle;
! 619: atomic_uint_fast32_t keepalive;
! 620: atomic_uint_fast32_t advertised;
! 621:
! 622: #ifdef NETMGR_TRACE
! 623: ISC_LIST(isc_nmsocket_t) active_sockets;
! 624: #endif
1.1 christos 625: };
626:
627: typedef enum isc_nmsocket_type {
628: isc_nm_udpsocket,
629: isc_nm_udplistener, /* Aggregate of nm_udpsocks */
630: isc_nm_tcpsocket,
631: isc_nm_tcplistener,
632: isc_nm_tcpdnslistener,
1.1.1.3 ! christos 633: isc_nm_tcpdnssocket,
! 634: isc_nm_tlslistener,
! 635: isc_nm_tlssocket,
! 636: isc_nm_tlsdnslistener,
! 637: isc_nm_tlsdnssocket
1.1 christos 638: } isc_nmsocket_type;
639:
640: /*%
641: * A universal structure for either a single socket or a group of
642: * dup'd/SO_REUSE_PORT-using sockets listening on the same interface.
643: */
644: #define NMSOCK_MAGIC ISC_MAGIC('N', 'M', 'S', 'K')
645: #define VALID_NMSOCK(t) ISC_MAGIC_VALID(t, NMSOCK_MAGIC)
646:
647: /*%
648: * Index into socket stat counter arrays.
649: */
1.1.1.3 ! christos 650: enum {
! 651: STATID_OPEN = 0,
! 652: STATID_OPENFAIL = 1,
! 653: STATID_CLOSE = 2,
! 654: STATID_BINDFAIL = 3,
! 655: STATID_CONNECTFAIL = 4,
! 656: STATID_CONNECT = 5,
! 657: STATID_ACCEPTFAIL = 6,
! 658: STATID_ACCEPT = 7,
! 659: STATID_SENDFAIL = 8,
! 660: STATID_RECVFAIL = 9,
! 661: STATID_ACTIVE = 10
! 662: };
1.1 christos 663:
664: struct isc_nmsocket {
665: /*% Unlocked, RO */
666: int magic;
667: int tid;
668: isc_nmsocket_type type;
669: isc_nm_t *mgr;
670: /*% Parent socket for multithreaded listeners */
671: isc_nmsocket_t *parent;
672: /*% Listener socket this connection was accepted on */
673: isc_nmsocket_t *listener;
1.1.1.3 ! christos 674: /*% Self socket */
! 675: isc_nmsocket_t *self;
! 676:
! 677: /*% TLS stuff */
! 678: struct tls {
! 679: bool server;
! 680: BIO *app_bio;
! 681: SSL *ssl;
! 682: SSL_CTX *ctx;
! 683: BIO *ssl_bio;
! 684: enum {
! 685: TLS_INIT,
! 686: TLS_HANDSHAKE,
! 687: TLS_IO,
! 688: TLS_ERROR,
! 689: TLS_CLOSING
! 690: } state;
! 691: isc_region_t senddata;
! 692: bool sending;
! 693: /* List of active send requests. */
! 694: ISC_LIST(isc__nm_uvreq_t) sends;
! 695: } tls;
1.1 christos 696:
697: /*%
698: * quota is the TCP client, attached when a TCP connection
699: * is established. pquota is a non-attached pointer to the
700: * TCP client quota, stored in listening sockets but only
701: * attached in connected sockets.
702: */
703: isc_quota_t *quota;
704: isc_quota_t *pquota;
1.1.1.2 christos 705: isc_quota_cb_t quotacb;
1.1 christos 706:
707: /*%
708: * Socket statistics
709: */
710: const isc_statscounter_t *statsindex;
711:
712: /*%
1.1.1.3 ! christos 713: * TCP read/connect timeout timers.
1.1 christos 714: */
715: uv_timer_t timer;
716: bool timer_initialized;
1.1.1.3 ! christos 717: bool timer_running;
1.1 christos 718: uint64_t read_timeout;
1.1.1.3 ! christos 719: uint64_t connect_timeout;
1.1 christos 720:
721: /*% outer socket is for 'wrapped' sockets - e.g. tcpdns in tcp */
722: isc_nmsocket_t *outer;
723:
724: /*% server socket for connections */
725: isc_nmsocket_t *server;
726:
727: /*% Child sockets for multi-socket setups */
728: isc_nmsocket_t *children;
1.1.1.3 ! christos 729: uint_fast32_t nchildren;
1.1 christos 730: isc_nmiface_t *iface;
1.1.1.3 ! christos 731: isc_nmhandle_t *statichandle;
! 732: isc_nmhandle_t *outerhandle;
1.1 christos 733:
734: /*% Extra data allocated at the end of each isc_nmhandle_t */
735: size_t extrahandlesize;
736:
737: /*% TCP backlog */
738: int backlog;
739:
740: /*% libuv data */
741: uv_os_sock_t fd;
742: union uv_any_handle uv_handle;
743:
744: /*% Peer address */
745: isc_sockaddr_t peer;
746:
747: /* Atomic */
748: /*% Number of running (e.g. listening) child sockets */
1.1.1.3 ! christos 749: uint_fast32_t rchildren;
1.1 christos 750:
751: /*%
752: * Socket is active if it's listening, working, etc. If it's
753: * closing, then it doesn't make a sense, for example, to
754: * push handles or reqs for reuse.
755: */
756: atomic_bool active;
757: atomic_bool destroying;
758:
759: /*%
760: * Socket is closed if it's not active and all the possible
761: * callbacks were fired, there are no active handles, etc.
762: * If active==false but closed==false, that means the socket
763: * is closing.
764: */
1.1.1.3 ! christos 765: atomic_bool closing;
1.1 christos 766: atomic_bool closed;
767: atomic_bool listening;
1.1.1.3 ! christos 768: atomic_bool connecting;
! 769: atomic_bool connected;
! 770: bool accepting;
! 771: bool reading;
1.1 christos 772: isc_refcount_t references;
773:
774: /*%
1.1.1.3 ! christos 775: * Established an outgoing connection, as client not server.
1.1 christos 776: */
1.1.1.3 ! christos 777: atomic_bool client;
1.1 christos 778:
779: /*%
1.1.1.3 ! christos 780: * TCPDNS socket has been set not to pipeline.
1.1 christos 781: */
1.1.1.3 ! christos 782: atomic_bool sequential;
1.1 christos 783:
784: /*%
1.1.1.3 ! christos 785: * The socket is processing read callback, this is guard to not read
! 786: * data before the readcb is back.
1.1 christos 787: */
1.1.1.3 ! christos 788: bool processing;
1.1 christos 789:
790: /*%
791: * A TCP socket has had isc_nm_pauseread() called.
792: */
793: atomic_bool readpaused;
794:
795: /*%
796: * A TCP or TCPDNS socket has been set to use the keepalive
797: * timeout instead of the default idle timeout.
798: */
799: atomic_bool keepalive;
800:
801: /*%
802: * 'spare' handles for that can be reused to avoid allocations,
803: * for UDP.
804: */
805: isc_astack_t *inactivehandles;
806: isc_astack_t *inactivereqs;
807:
808: /*%
809: * Used to wait for TCP listening events to complete, and
810: * for the number of running children to reach zero during
811: * shutdown.
1.1.1.3 ! christos 812: *
! 813: * We use two condition variables to prevent the race where the netmgr
! 814: * threads would be able to finish and destroy the socket before it's
! 815: * unlocked by the isc_nm_listen<proto>() function. So, the flow is as
! 816: * follows:
! 817: *
! 818: * 1. parent thread creates all children sockets and passes then to
! 819: * netthreads, looks at the signaling variable and WAIT(cond) until
! 820: * the childrens are done initializing
! 821: *
! 822: * 2. the events get picked by netthreads, calls the libuv API (and
! 823: * either succeeds or fails) and WAIT(scond) until all other
! 824: * children sockets in netthreads are initialized and the listening
! 825: * socket lock is unlocked
! 826: *
! 827: * 3. the control is given back to the parent thread which now either
! 828: * returns success or shutdowns the listener if an error has
! 829: * occured in the children netthread
! 830: *
! 831: * NOTE: The other approach would be doing an extra attach to the parent
! 832: * listening socket, and then detach it in the parent thread, but that
! 833: * breaks the promise that once the libuv socket is initialized on the
! 834: * nmsocket, the nmsocket needs to be handled only by matching
! 835: * netthread, so in fact that would add a complexity in a way that
! 836: * isc__nmsocket_detach would have to be converted to use an
! 837: * asynchrounous netievent.
1.1 christos 838: */
839: isc_mutex_t lock;
840: isc_condition_t cond;
1.1.1.3 ! christos 841: isc_condition_t scond;
1.1 christos 842:
843: /*%
1.1.1.3 ! christos 844: * Used to pass a result back from listen or connect events.
1.1 christos 845: */
846: isc_result_t result;
847:
848: /*%
849: * List of active handles.
850: * ah - current position in 'ah_frees'; this represents the
851: * current number of active handles;
852: * ah_size - size of the 'ah_frees' and 'ah_handles' arrays
853: * ah_handles - array pointers to active handles
854: *
855: * Adding a handle
856: * - if ah == ah_size, reallocate
857: * - x = ah_frees[ah]
858: * - ah_frees[ah++] = 0;
859: * - ah_handles[x] = handle
860: * - x must be stored with the handle!
861: * Removing a handle:
862: * - ah_frees[--ah] = x
863: * - ah_handles[x] = NULL;
864: *
865: * XXX: for now this is locked with socket->lock, but we
866: * might want to change it to something lockless in the
867: * future.
868: */
869: atomic_int_fast32_t ah;
870: size_t ah_size;
871: size_t *ah_frees;
872: isc_nmhandle_t **ah_handles;
873:
874: /*% Buffer for TCPDNS processing */
875: size_t buf_size;
876: size_t buf_len;
877: unsigned char *buf;
878:
879: /*%
880: * This function will be called with handle->sock
881: * as the argument whenever a handle's references drop
882: * to zero, after its reset callback has been called.
883: */
884: isc_nm_opaquecb_t closehandle_cb;
885:
1.1.1.3 ! christos 886: isc_nmhandle_t *recv_handle;
! 887: isc_nm_recv_cb_t recv_cb;
! 888: void *recv_cbarg;
! 889: bool recv_read;
! 890:
! 891: isc_nm_cb_t connect_cb;
! 892: void *connect_cbarg;
1.1 christos 893:
1.1.1.3 ! christos 894: isc_nm_accept_cb_t accept_cb;
1.1 christos 895: void *accept_cbarg;
1.1.1.3 ! christos 896:
! 897: atomic_int_fast32_t active_child_connections;
! 898: #ifdef NETMGR_TRACE
! 899: void *backtrace[TRACE_SIZE];
! 900: int backtrace_size;
! 901: LINK(isc_nmsocket_t) active_link;
! 902: ISC_LIST(isc_nmhandle_t) active_handles;
! 903: #endif
1.1 christos 904: };
905:
906: bool
907: isc__nm_in_netthread(void);
908: /*%
909: * Returns 'true' if we're in the network thread.
910: */
911:
1.1.1.3 ! christos 912: void
! 913: isc__nm_maybe_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event);
1.1 christos 914: /*%<
1.1.1.3 ! christos 915: * If the caller is already in the matching nmthread, process the netievent
! 916: * directly, if not enqueue using isc__nm_enqueue_ievent().
1.1 christos 917: */
918:
919: void
920: isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event);
921: /*%<
922: * Enqueue an ievent onto a specific worker queue. (This the only safe
923: * way to use an isc__networker_t from another thread.)
924: */
925:
926: void
927: isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf);
928: /*%<
929: * Free a buffer allocated for a receive operation.
930: *
931: * Note that as currently implemented, this doesn't actually
932: * free anything, marks the isc__networker's UDP receive buffer
933: * as "not in use".
934: */
935:
936: isc_nmhandle_t *
1.1.1.3 ! christos 937: isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
! 938: isc_sockaddr_t *local FLARG);
1.1 christos 939: /*%<
940: * Get a handle for the socket 'sock', allocating a new one
941: * if there isn't one available in 'sock->inactivehandles'.
942: *
943: * If 'peer' is not NULL, set the handle's peer address to 'peer',
944: * otherwise set it to 'sock->peer'.
945: *
946: * If 'local' is not NULL, set the handle's local address to 'local',
947: * otherwise set it to 'sock->iface->addr'.
1.1.1.3 ! christos 948: *
! 949: * 'sock' will be attached to 'handle->sock'. The caller may need
! 950: * to detach the socket afterward.
1.1 christos 951: */
952:
953: isc__nm_uvreq_t *
1.1.1.3 ! christos 954: isc___nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock FLARG);
1.1 christos 955: /*%<
956: * Get a UV request structure for the socket 'sock', allocating a
957: * new one if there isn't one available in 'sock->inactivereqs'.
958: */
959:
960: void
1.1.1.3 ! christos 961: isc___nm_uvreq_put(isc__nm_uvreq_t **req, isc_nmsocket_t *sock FLARG);
1.1 christos 962: /*%<
963: * Completes the use of a UV request structure, setting '*req' to NULL.
964: *
965: * The UV request is pushed onto the 'sock->inactivereqs' stack or,
966: * if that doesn't work, freed.
967: */
968:
969: void
1.1.1.3 ! christos 970: isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
! 971: isc_nmiface_t *iface FLARG);
1.1 christos 972: /*%<
973: * Initialize socket 'sock', attach it to 'mgr', and set it to type 'type'
974: * and its interface to 'iface'.
975: */
976:
977: void
1.1.1.3 ! christos 978: isc___nmsocket_attach(isc_nmsocket_t *sock, isc_nmsocket_t **target FLARG);
! 979: /*%<
! 980: * Attach to a socket, increasing refcount
! 981: */
! 982:
! 983: void
! 984: isc___nmsocket_detach(isc_nmsocket_t **socketp FLARG);
! 985: /*%<
! 986: * Detach from socket, decreasing refcount and possibly destroying the
! 987: * socket if it's no longer referenced.
! 988: */
! 989:
! 990: void
! 991: isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG);
1.1 christos 992: /*%<
993: * Market 'sock' as inactive, close it if necessary, and destroy it
994: * if there are no remaining references or active handles.
995: */
996:
997: bool
998: isc__nmsocket_active(isc_nmsocket_t *sock);
999: /*%<
1000: * Determine whether 'sock' is active by checking 'sock->active'
1001: * or, for child sockets, 'sock->parent->active'.
1002: */
1003:
1.1.1.3 ! christos 1004: bool
! 1005: isc__nmsocket_deactivate(isc_nmsocket_t *sock);
! 1006: /*%<
! 1007: * @brief Deactivate active socket
! 1008: *
! 1009: * Atomically deactive the socket by setting @p sock->active or, for child
! 1010: * sockets, @p sock->parent->active to @c false
! 1011: *
! 1012: * @param[in] sock - valid nmsocket
! 1013: * @return @c false if the socket was already inactive, @c true otherwise
! 1014: */
! 1015:
1.1 christos 1016: void
1.1.1.3 ! christos 1017: isc__nmsocket_clearcb(isc_nmsocket_t *sock);
1.1 christos 1018: /*%<
1.1.1.3 ! christos 1019: * Clear the recv and accept callbacks in 'sock'.
! 1020: */
! 1021:
! 1022: void
! 1023: isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
! 1024: isc_result_t eresult);
! 1025: void
! 1026: isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0);
! 1027: /*%<
! 1028: * Issue a connect callback on the socket, used to call the callback
! 1029:
! 1030: */
! 1031:
! 1032: isc_result_t
! 1033: isc__nm_acceptcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
! 1034: isc_result_t eresult);
! 1035: /*%<
! 1036: * Issue a synchronous accept callback on the socket.
! 1037: */
! 1038:
! 1039: void
! 1040: isc__nm_readcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
! 1041: isc_result_t eresult);
! 1042: void
! 1043: isc__nm_async_readcb(isc__networker_t *worker, isc__netievent_t *ev0);
! 1044:
! 1045: /*%<
! 1046: * Issue a read callback on the socket, used to call the callback
! 1047: * on failed conditions when the event can't be scheduled on the uv loop.
! 1048: *
! 1049: */
! 1050:
! 1051: void
! 1052: isc__nm_sendcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
! 1053: isc_result_t eresult);
! 1054: void
! 1055: isc__nm_async_sendcb(isc__networker_t *worker, isc__netievent_t *ev0);
! 1056: /*%<
! 1057: * Issue a write callback on the socket, used to call the callback
! 1058: * on failed conditions when the event can't be scheduled on the uv loop.
1.1 christos 1059: */
1060:
1061: void
1062: isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0);
1063: /*%<
1064: * Walk through all uv handles, get the underlying sockets and issue
1065: * close on them.
1066: */
1067:
1.1.1.3 ! christos 1068: void
1.1 christos 1069: isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
1070: void *cbarg);
1071: /*%<
1072: * Back-end implementation of isc_nm_send() for UDP handles.
1073: */
1074:
1075: void
1.1.1.3 ! christos 1076: isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
! 1077: /*
! 1078: * Back-end implementation of isc_nm_read() for UDP handles.
! 1079: */
! 1080:
! 1081: void
! 1082: isc__nm_udp_close(isc_nmsocket_t *sock);
! 1083: /*%<
! 1084: * Close a UDP socket.
! 1085: */
! 1086:
! 1087: void
! 1088: isc__nm_udp_cancelread(isc_nmhandle_t *handle);
! 1089: /*%<
! 1090: * Stop reading on a connected UDP handle.
! 1091: */
! 1092:
! 1093: void
! 1094: isc__nm_udp_shutdown(isc_nmsocket_t *sock);
! 1095: /*%<
! 1096: * Called during the shutdown process to close and clean up connected
! 1097: * sockets.
! 1098: */
! 1099:
! 1100: void
1.1 christos 1101: isc__nm_udp_stoplistening(isc_nmsocket_t *sock);
1.1.1.3 ! christos 1102: /*%<
! 1103: * Stop listening on 'sock'.
! 1104: */
1.1 christos 1105:
1106: void
1.1.1.3 ! christos 1107: isc__nm_udp_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
! 1108: /*%<
! 1109: * Set the recv timeout for the UDP socket associated with 'handle'.
! 1110: */
1.1 christos 1111:
1112: void
1.1.1.3 ! christos 1113: isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0);
! 1114: void
! 1115: isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0);
! 1116: void
1.1 christos 1117: isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0);
1118: void
1119: isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0);
1.1.1.3 ! christos 1120: void
! 1121: isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0);
! 1122: void
! 1123: isc__nm_async_udpcancel(isc__networker_t *worker, isc__netievent_t *ev0);
! 1124: void
! 1125: isc__nm_async_udpclose(isc__networker_t *worker, isc__netievent_t *ev0);
1.1 christos 1126: /*%<
1127: * Callback handlers for asynchronous UDP events (listen, stoplisten, send).
1128: */
1129:
1.1.1.3 ! christos 1130: void
1.1 christos 1131: isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
1132: void *cbarg);
1133: /*%<
1134: * Back-end implementation of isc_nm_send() for TCP handles.
1135: */
1136:
1.1.1.3 ! christos 1137: void
1.1 christos 1138: isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
1.1.1.3 ! christos 1139: /*
! 1140: * Back-end implementation of isc_nm_read() for TCP handles.
! 1141: */
1.1 christos 1142:
1143: void
1144: isc__nm_tcp_close(isc_nmsocket_t *sock);
1145: /*%<
1146: * Close a TCP socket.
1147: */
1.1.1.3 ! christos 1148: void
! 1149: isc__nm_tcp_pauseread(isc_nmhandle_t *handle);
1.1 christos 1150: /*%<
1.1.1.3 ! christos 1151: * Pause reading on this handle, while still remembering the callback.
1.1 christos 1152: */
1153:
1.1.1.3 ! christos 1154: void
! 1155: isc__nm_tcp_resumeread(isc_nmhandle_t *handle);
1.1 christos 1156: /*%<
1157: * Resume reading from socket.
1158: *
1159: */
1160:
1161: void
1162: isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
1163: /*%<
1.1.1.3 ! christos 1164: * Called during the shutdown process to close and clean up connected
! 1165: * sockets.
! 1166: */
! 1167:
! 1168: void
! 1169: isc__nm_tcp_cancelread(isc_nmhandle_t *handle);
! 1170: /*%<
! 1171: * Stop reading on a connected TCP handle.
1.1 christos 1172: */
1173:
1174: void
1175: isc__nm_tcp_stoplistening(isc_nmsocket_t *sock);
1.1.1.3 ! christos 1176: /*%<
! 1177: * Stop listening on 'sock'.
! 1178: */
! 1179:
! 1180: int_fast32_t
! 1181: isc__nm_tcp_listener_nactive(isc_nmsocket_t *sock);
! 1182: /*%<
! 1183: * Returns the number of active connections for the TCP listener socket.
! 1184: */
! 1185:
! 1186: void
! 1187: isc__nm_tcp_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
! 1188: /*%<
! 1189: * Set the read timeout for the TCP socket associated with 'handle'.
! 1190: */
1.1 christos 1191:
1192: void
1193: isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0);
1194: void
1195: isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0);
1196: void
1.1.1.2 christos 1197: isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0);
1.1 christos 1198: void
1.1.1.2 christos 1199: isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0);
1.1 christos 1200: void
1201: isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0);
1202: void
1203: isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0);
1204: void
1205: isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0);
1206: void
1.1.1.3 ! christos 1207: isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0);
1.1 christos 1208: void
1.1.1.3 ! christos 1209: isc__nm_async_tcppauseread(isc__networker_t *worker, isc__netievent_t *ev0);
! 1210: void
! 1211: isc__nm_async_tcpcancel(isc__networker_t *worker, isc__netievent_t *ev0);
1.1 christos 1212: void
1213: isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
1214: /*%<
1215: * Callback handlers for asynchronous TCP events (connect, listen,
1216: * stoplisten, send, read, pause, close).
1217: */
1218:
1.1.1.3 ! christos 1219: void
! 1220: isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0);
! 1221:
! 1222: void
! 1223: isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0);
! 1224:
! 1225: void
! 1226: isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0);
! 1227:
! 1228: void
! 1229: isc__nm_async_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0);
! 1230:
! 1231: void
! 1232: isc__nm_async_tlsdobio(isc__networker_t *worker, isc__netievent_t *ev0);
! 1233:
! 1234: /*%<
! 1235: * Callback handlers for asynchronouse TLS events.
! 1236: */
! 1237:
! 1238: void
! 1239: isc__nm_async_tcpdnsaccept(isc__networker_t *worker, isc__netievent_t *ev0);
! 1240: void
! 1241: isc__nm_async_tcpdnsconnect(isc__networker_t *worker, isc__netievent_t *ev0);
! 1242: void
! 1243: isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0);
! 1244: void
1.1 christos 1245: isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
1246: isc_nm_cb_t cb, void *cbarg);
1247: /*%<
1248: * Back-end implementation of isc_nm_send() for TCPDNS handles.
1249: */
1250:
1251: void
1.1.1.3 ! christos 1252: isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock);
! 1253:
! 1254: void
1.1 christos 1255: isc__nm_tcpdns_close(isc_nmsocket_t *sock);
1256: /*%<
1257: * Close a TCPDNS socket.
1258: */
1259:
1260: void
1261: isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
1.1.1.3 ! christos 1262: /*%<
! 1263: * Stop listening on 'sock'.
! 1264: */
1.1 christos 1265:
1266: void
1.1.1.3 ! christos 1267: isc__nm_tcpdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
! 1268: /*%<
! 1269: * Set the read timeout and reset the timer for the TCPDNS socket
! 1270: * associated with 'handle', and the TCP socket it wraps around.
! 1271: */
1.1 christos 1272:
1.1.1.2 christos 1273: void
1.1.1.3 ! christos 1274: isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0);
! 1275: void
! 1276: isc__nm_async_tcpdnsaccept(isc__networker_t *worker, isc__netievent_t *ev0);
! 1277: void
! 1278: isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0);
! 1279: void
! 1280: isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
! 1281: void
1.1.1.2 christos 1282: isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
1.1.1.3 ! christos 1283: void
! 1284: isc__nm_async_tcpdnsstop(isc__networker_t *worker, isc__netievent_t *ev0);
! 1285:
! 1286: void
! 1287: isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0);
! 1288:
! 1289: void
! 1290: isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
! 1291:
! 1292: void
! 1293: isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle);
! 1294: /*%<
! 1295: * Stop reading on a connected TCPDNS handle.
! 1296: */
! 1297:
! 1298: void
! 1299: isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region,
! 1300: isc_nm_cb_t cb, void *cbarg);
! 1301: /*%<
! 1302: * Back-end implementation of isc_nm_send() for TLSDNS handles.
! 1303: */
! 1304:
! 1305: void
! 1306: isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock);
! 1307:
! 1308: void
! 1309: isc__nm_tlsdns_close(isc_nmsocket_t *sock);
! 1310: /*%<
! 1311: * Close a TLSDNS socket.
! 1312: */
! 1313:
! 1314: void
! 1315: isc__nm_tlsdns_stoplistening(isc_nmsocket_t *sock);
! 1316: /*%<
! 1317: * Stop listening on 'sock'.
! 1318: */
! 1319:
! 1320: void
! 1321: isc__nm_tlsdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
! 1322: /*%<
! 1323: * Set the read timeout and reset the timer for the TLSDNS socket
! 1324: * associated with 'handle', and the TCP socket it wraps around.
! 1325: */
! 1326:
! 1327: void
! 1328: isc__nm_async_tlsdnscancel(isc__networker_t *worker, isc__netievent_t *ev0);
! 1329: void
! 1330: isc__nm_async_tlsdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
! 1331: void
! 1332: isc__nm_async_tlsdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
! 1333: void
! 1334: isc__nm_async_tlsdnsstop(isc__networker_t *worker, isc__netievent_t *ev0);
! 1335:
! 1336: void
! 1337: isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0);
! 1338:
! 1339: void
! 1340: isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
! 1341:
! 1342: void
! 1343: isc__nm_tlsdns_cancelread(isc_nmhandle_t *handle);
! 1344: /*%<
! 1345: * Stop reading on a connected TLSDNS handle.
! 1346: */
! 1347:
! 1348: void
! 1349: isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
! 1350: void *cbarg);
! 1351:
! 1352: void
! 1353: isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
! 1354:
! 1355: void
! 1356: isc__nm_tls_close(isc_nmsocket_t *sock);
! 1357: /*%<
! 1358: * Close a TLS socket.
! 1359: */
! 1360:
! 1361: void
! 1362: isc__nm_tls_pauseread(isc_nmhandle_t *handle);
! 1363: /*%<
! 1364: * Pause reading on this handle, while still remembering the callback.
! 1365: */
! 1366:
! 1367: void
! 1368: isc__nm_tls_resumeread(isc_nmhandle_t *handle);
! 1369: /*%<
! 1370: * Resume reading from the handle.
! 1371: *
! 1372: */
! 1373:
! 1374: void
! 1375: isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
1.1.1.2 christos 1376:
1.1 christos 1377: #define isc__nm_uverr2result(x) \
1.1.1.3 ! christos 1378: isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
1.1 christos 1379: isc_result_t
1380: isc___nm_uverr2result(int uverr, bool dolog, const char *file,
1.1.1.3 ! christos 1381: unsigned int line, const char *func);
1.1 christos 1382: /*%<
1383: * Convert a libuv error value into an isc_result_t. The
1384: * list of supported error values is not complete; new users
1385: * of this function should add any expected errors that are
1386: * not already there.
1387: */
1388:
1389: bool
1390: isc__nm_acquire_interlocked(isc_nm_t *mgr);
1391: /*%<
1392: * Try to acquire interlocked state; return true if successful.
1393: */
1394:
1395: void
1396: isc__nm_drop_interlocked(isc_nm_t *mgr);
1397: /*%<
1398: * Drop interlocked state; signal waiters.
1399: */
1400:
1401: void
1402: isc__nm_acquire_interlocked_force(isc_nm_t *mgr);
1403: /*%<
1404: * Actively wait for interlocked state.
1405: */
1406:
1407: void
1408: isc__nm_incstats(isc_nm_t *mgr, isc_statscounter_t counterid);
1409: /*%<
1410: * Increment socket-related statistics counters.
1411: */
1412:
1413: void
1414: isc__nm_decstats(isc_nm_t *mgr, isc_statscounter_t counterid);
1415: /*%<
1416: * Decrement socket-related statistics counters.
1417: */
1.1.1.3 ! christos 1418:
! 1419: isc_result_t
! 1420: isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp);
! 1421: /*%<
! 1422: * Platform independent socket() version
! 1423: */
! 1424:
! 1425: void
! 1426: isc__nm_closesocket(uv_os_sock_t sock);
! 1427: /*%<
! 1428: * Platform independent closesocket() version
! 1429: */
! 1430:
! 1431: isc_result_t
! 1432: isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family);
! 1433: /*%<
! 1434: * Set the IP_FREEBIND (or equivalent) socket option on the uv_handle
! 1435: */
! 1436:
! 1437: isc_result_t
! 1438: isc__nm_socket_reuse(uv_os_sock_t fd);
! 1439: /*%<
! 1440: * Set the SO_REUSEADDR or SO_REUSEPORT (or equivalent) socket option on the fd
! 1441: */
! 1442:
! 1443: isc_result_t
! 1444: isc__nm_socket_reuse_lb(uv_os_sock_t fd);
! 1445: /*%<
! 1446: * Set the SO_REUSEPORT_LB (or equivalent) socket option on the fd
! 1447: */
! 1448:
! 1449: isc_result_t
! 1450: isc__nm_socket_incoming_cpu(uv_os_sock_t fd);
! 1451: /*%<
! 1452: * Set the SO_INCOMING_CPU socket option on the fd if available
! 1453: */
! 1454:
! 1455: isc_result_t
! 1456: isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family);
! 1457: /*%<
! 1458: * Set the SO_IP_DONTFRAG (or equivalent) socket option of the fd if available
! 1459: */
! 1460:
! 1461: isc_result_t
! 1462: isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms);
! 1463: /*%<
! 1464: * Set the connection timeout in miliseconds, on non-Linux platforms,
! 1465: * the minimum value must be at least 1000 (1 second).
! 1466: */
! 1467:
! 1468: void
! 1469: isc__nm_tls_initialize(void);
! 1470: /*%<
! 1471: * Initialize OpenSSL library, idempotent.
! 1472: */
! 1473:
! 1474: /*
! 1475: * typedef all the netievent types
! 1476: */
! 1477:
! 1478: NETIEVENT_SOCKET_TYPE(close);
! 1479: NETIEVENT_SOCKET_TYPE(tcpclose);
! 1480: NETIEVENT_SOCKET_TYPE(tcplisten);
! 1481: NETIEVENT_SOCKET_TYPE(tcppauseread);
! 1482: NETIEVENT_SOCKET_TYPE(tcpstop);
! 1483: NETIEVENT_SOCKET_TYPE(tlsclose);
! 1484: /* NETIEVENT_SOCKET_TYPE(tlsconnect); */ /* unique type, defined independently
! 1485: */
! 1486: NETIEVENT_SOCKET_TYPE(tlsdobio);
! 1487: NETIEVENT_SOCKET_TYPE(tlsstartread);
! 1488: NETIEVENT_SOCKET_TYPE(udpclose);
! 1489: NETIEVENT_SOCKET_TYPE(udplisten);
! 1490: NETIEVENT_SOCKET_TYPE(udpread);
! 1491: /* NETIEVENT_SOCKET_TYPE(udpsend); */ /* unique type, defined independently */
! 1492: NETIEVENT_SOCKET_TYPE(udpstop);
! 1493:
! 1494: NETIEVENT_SOCKET_TYPE(tcpdnsclose);
! 1495: NETIEVENT_SOCKET_TYPE(tcpdnsread);
! 1496: NETIEVENT_SOCKET_TYPE(tcpdnsstop);
! 1497: NETIEVENT_SOCKET_TYPE(tcpdnslisten);
! 1498: NETIEVENT_SOCKET_REQ_TYPE(tcpdnsconnect);
! 1499: NETIEVENT_SOCKET_REQ_TYPE(tcpdnssend);
! 1500: NETIEVENT_SOCKET_HANDLE_TYPE(tcpdnscancel);
! 1501: NETIEVENT_SOCKET_QUOTA_TYPE(tcpdnsaccept);
! 1502:
! 1503: NETIEVENT_SOCKET_TYPE(tlsdnsclose);
! 1504: NETIEVENT_SOCKET_TYPE(tlsdnsread);
! 1505: NETIEVENT_SOCKET_TYPE(tlsdnsstop);
! 1506: NETIEVENT_SOCKET_REQ_TYPE(tlsdnssend);
! 1507: NETIEVENT_SOCKET_HANDLE_TYPE(tlsdnscancel);
! 1508:
! 1509: NETIEVENT_SOCKET_REQ_TYPE(tcpconnect);
! 1510: NETIEVENT_SOCKET_REQ_TYPE(tcpsend);
! 1511: NETIEVENT_SOCKET_TYPE(tcpstartread);
! 1512: NETIEVENT_SOCKET_REQ_TYPE(tlssend);
! 1513: NETIEVENT_SOCKET_REQ_TYPE(udpconnect);
! 1514:
! 1515: NETIEVENT_SOCKET_REQ_RESULT_TYPE(connectcb);
! 1516: NETIEVENT_SOCKET_REQ_RESULT_TYPE(readcb);
! 1517: NETIEVENT_SOCKET_REQ_RESULT_TYPE(sendcb);
! 1518:
! 1519: NETIEVENT_SOCKET_HANDLE_TYPE(detach);
! 1520: NETIEVENT_SOCKET_HANDLE_TYPE(tcpcancel);
! 1521: NETIEVENT_SOCKET_HANDLE_TYPE(udpcancel);
! 1522:
! 1523: NETIEVENT_SOCKET_QUOTA_TYPE(tcpaccept);
! 1524:
! 1525: NETIEVENT_TYPE(pause);
! 1526: NETIEVENT_TYPE(resume);
! 1527: NETIEVENT_TYPE(shutdown);
! 1528: NETIEVENT_TYPE(stop);
! 1529:
! 1530: /* Now declared the helper functions */
! 1531:
! 1532: NETIEVENT_SOCKET_DECL(close);
! 1533: NETIEVENT_SOCKET_DECL(tcpclose);
! 1534: NETIEVENT_SOCKET_DECL(tcplisten);
! 1535: NETIEVENT_SOCKET_DECL(tcppauseread);
! 1536: NETIEVENT_SOCKET_DECL(tcpstartread);
! 1537: NETIEVENT_SOCKET_DECL(tcpstop);
! 1538: NETIEVENT_SOCKET_DECL(tlsclose);
! 1539: NETIEVENT_SOCKET_DECL(tlsconnect);
! 1540: NETIEVENT_SOCKET_DECL(tlsdobio);
! 1541: NETIEVENT_SOCKET_DECL(tlsstartread);
! 1542: NETIEVENT_SOCKET_DECL(udpclose);
! 1543: NETIEVENT_SOCKET_DECL(udplisten);
! 1544: NETIEVENT_SOCKET_DECL(udpread);
! 1545: NETIEVENT_SOCKET_DECL(udpsend);
! 1546: NETIEVENT_SOCKET_DECL(udpstop);
! 1547:
! 1548: NETIEVENT_SOCKET_DECL(tcpdnsclose);
! 1549: NETIEVENT_SOCKET_DECL(tcpdnsread);
! 1550: NETIEVENT_SOCKET_DECL(tcpdnsstop);
! 1551: NETIEVENT_SOCKET_DECL(tcpdnslisten);
! 1552: NETIEVENT_SOCKET_REQ_DECL(tcpdnsconnect);
! 1553: NETIEVENT_SOCKET_REQ_DECL(tcpdnssend);
! 1554: NETIEVENT_SOCKET_HANDLE_DECL(tcpdnscancel);
! 1555: NETIEVENT_SOCKET_QUOTA_DECL(tcpdnsaccept);
! 1556:
! 1557: NETIEVENT_SOCKET_DECL(tlsdnsclose);
! 1558: NETIEVENT_SOCKET_DECL(tlsdnsread);
! 1559: NETIEVENT_SOCKET_DECL(tlsdnsstop);
! 1560: NETIEVENT_SOCKET_REQ_DECL(tlsdnssend);
! 1561: NETIEVENT_SOCKET_HANDLE_DECL(tlsdnscancel);
! 1562:
! 1563: NETIEVENT_SOCKET_REQ_DECL(tcpconnect);
! 1564: NETIEVENT_SOCKET_REQ_DECL(tcpsend);
! 1565: NETIEVENT_SOCKET_REQ_DECL(tlssend);
! 1566: NETIEVENT_SOCKET_REQ_DECL(udpconnect);
! 1567:
! 1568: NETIEVENT_SOCKET_REQ_RESULT_DECL(connectcb);
! 1569: NETIEVENT_SOCKET_REQ_RESULT_DECL(readcb);
! 1570: NETIEVENT_SOCKET_REQ_RESULT_DECL(sendcb);
! 1571:
! 1572: NETIEVENT_SOCKET_HANDLE_DECL(udpcancel);
! 1573: NETIEVENT_SOCKET_HANDLE_DECL(tcpcancel);
! 1574: NETIEVENT_SOCKET_DECL(detach);
! 1575:
! 1576: NETIEVENT_SOCKET_QUOTA_DECL(tcpaccept);
! 1577:
! 1578: NETIEVENT_DECL(pause);
! 1579: NETIEVENT_DECL(resume);
! 1580: NETIEVENT_DECL(shutdown);
! 1581: NETIEVENT_DECL(stop);
CVSweb <webmaster@jp.NetBSD.org>