9b2743294cb710a1af88d13a87dabe91d4fb6c1cTinderbox User * Copyright (C) 1999-2009, 2011-2017 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrewstypedef ISC_LIST(dns_dispentry_t) dns_displist_t;
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉typedef ISC_LIST(dispsocket_t) dispsocketlist_t;
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrewstypedef ISC_LIST(dispportentry_t) dispportlist_t;
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein unsigned int qid_nbuckets; /*%< hash table size */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein unsigned int qid_increment; /*%< id increment on collision */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein dns_displist_t *qid_table; /*%< the table itself */
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 dispsocketlist_t *sock_table; /*%< socket table */
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff /* Unlocked. */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_entropy_t *entropy; /*%< entropy source */
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff /* Locked by "lock". */
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman /* Locked by rng_lock. */
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman isc_rng_t *rngctx; /*%< RNG context for QID */
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman /* locked by buffer_lock */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein unsigned int buffersize; /*%< size of each buffer */
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff /* Locked internally. */
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_t *depool; /*%< pool for dispatch events */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein isc_mempool_t *dpool; /*%< dispatch allocations */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Locked by qid->lock if qid exists; otherwise, can be used without
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * being locked.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Memory footprint considerations: this is a simple implementation of
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * available ports, i.e., an ordered array of the actual port numbers.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * This will require about 256KB of memory in the worst case (128KB for
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * each of IPv4 and IPv6). We could reduce it by representing it as a
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * more sophisticated way such as a list (or array) of ranges that are
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * searched to identify a specific port. Our decision here is the saved
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * memory isn't worth the implementation complexity, considering the
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * fact that the whole BIND9 process (which is mainly named) already
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * requires a pretty large memory footprint. We may, however, have to
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * revisit the decision when we want to use it as a separate module for
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * an environment where memory requirement is severer.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 in_port_t *v4ports; /*%< available ports for IPv4 */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int nv4ports; /*%< # of available ports for IPv4 */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 in_port_t *v6ports; /*%< available ports for IPv4 */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int nv6ports; /*%< # of available ports for IPv4 */
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0)
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Maximum number of dispatch sockets that can be pooled for reuse. The
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * appropriate value may vary, but experiments have shown a busy caching server
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * may need more than 1000 sockets concurrently opened. The maximum allowable
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * number of dispatch sockets (per manager) will be set to the double of this
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Quota to control the number of dispatch sockets. If a dispatch has more
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * than the quota of sockets, new queries will purge oldest ones, so that
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * a massive number of outstanding queries won't prevent subsequent queries
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * (especially if the older ones take longer time and result in timeout).
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews in_port_t localport; /* XXX: should be removed later */
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews * A port table entry. We remember every port we first open in a table with a
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews * reference counter so that we can 'reuse' the same port (with different
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews * destination addresses) using the SO_REUSEADDR socket option.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Number of tasks for each dispatch that use separate sockets for different
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * transactions. This must be a power of 2 as it will divide 32 bit numbers
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * to get an uniformly random tasks selection. See get_dispsocket().
83f8c56f43852bf9a9c6964eae285284b23f9d8dMichael Graff /* Unlocked. */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein dns_dispatchmgr_t *mgr; /*%< dispatch manager */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * internal task buckets. We use multiple tasks to distribute various
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * socket events well when using separate dispatch sockets. We use the
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * 1st task (task[0]) for internal control events.
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein isc_socket_t *socket; /*%< isc socket attached to */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 in_port_t localport; /*%< local UDP port */
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews isc_sockaddr_t peer; /*%< peer address (TCP) */
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_t *sepool; /*%< pool for socket events */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein /*% Locked by mgr->lock. */
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff /* Locked by "lock". */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein unsigned int requests; /*%< how many requests we have */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein unsigned int tcpbuffers; /*%< allocated buffers */
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman isc_rng_t *rngctx; /*%< for QID/UDP port num */
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews dispportlist_t *port_table; /*%< hold ports 'owned' by us */
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews isc_mempool_t *portpool; /*%< port table entries */
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrews#define VALID_QID(e) ISC_MAGIC_VALID((e), QID_MAGIC)
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p')
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉#define DISPSOCK_MAGIC ISC_MAGIC('D', 's', 'o', 'c')
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉#define VALID_DISPSOCK(e) ISC_MAGIC_VALID((e), DISPSOCK_MAGIC)
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p')
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrews#define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman#define DISP_RNGCTX(disp) ((disp)->socktype == isc_sockettype_udp) ? \
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Locking a query port buffer is a bit tricky. We access the buffer without
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * locking until qid is created. Technically, there is a possibility of race
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * between the creation of qid and access to the port buffer; in practice,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * however, this should be safe because qid isn't created until the first
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * dispatch is created and there should be no contending situation until then.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉#define PORTBUFLOCK(mgr) if ((mgr)->qid != NULL) LOCK(&((mgr)->qid->lock))
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉#define PORTBUFUNLOCK(mgr) if ((mgr)->qid != NULL) UNLOCK((&(mgr)->qid->lock))
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉static dns_dispentry_t *entry_search(dns_qid_t *, isc_sockaddr_t *,
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 dns_messageid_t, in_port_t, unsigned int);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffstatic isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellingtonstatic void destroy_disp(isc_task_t *task, isc_event_t *event);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static void destroy_dispsocket(dns_dispatch_t *, dispsocket_t **);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static void udp_exrecv(isc_task_t *, isc_event_t *);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static void udp_shrecv(isc_task_t *, isc_event_t *);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static void udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *);
0a9fedafec59fd3ec2eeadc3f123db163e71c0fbMichael Graffstatic void tcp_recv(isc_task_t *, isc_event_t *);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static isc_result_t startrecv(dns_dispatch_t *, dispsocket_t *);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t,
0a9fedafec59fd3ec2eeadc3f123db163e71c0fbMichael Graffstatic void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
8470db5b12c18cfb32a757e265ce4e7789052c92Michael Graffstatic void *allocate_udp_buffer(dns_dispatch_t *disp);
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Huntstatic inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Huntstatic inline dns_dispatchevent_t *allocate_devent(dns_dispatch_t *disp);
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrewsstatic dns_dispentry_t *linear_first(dns_qid_t *disp);
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrewsstatic dns_dispentry_t *linear_next(dns_qid_t *disp,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffstatic void dispatch_free(dns_dispatch_t **dispp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffstatic isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffstatic isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffstatic void destroy_mgr(dns_dispatchmgr_t **mgrp);
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrewsstatic isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int increment, dns_qid_t **qidp,
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrewsstatic void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉static isc_boolean_t portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafssonmgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffmgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
f19e6ef1eb7d5abf547fc1af24e561bdc5d75b22Mark Andrewsstatic inline void
870a748bae74b9c4b264da96cfbcb4e90d7a2c1dMark Andrewsinc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
dd2a0a6d2dec1c23787351e51b434a838dec5603Evan Huntstatic inline void
dd2a0a6d2dec1c23787351e51b434a838dec5603Evan Huntdec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafssondispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffdispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafssonrequest_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graffrequest_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
ec46482ef3c0c3e9747f0074cb9263adb8aef961Andreas Gustafsson "dispatch %p response %p %s: %s", disp, resp,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
0941f35ad9b4f48a5324af405a730c3cb3e0aad8Michael Graff * Return a hash of the destination and message id.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
3530e10080e5a7d95c7d13abdc02c1d8bd12ec18Andreas Gustafsson * Find the first entry in 'qid'. Returns NULL if there are no entries.
3530e10080e5a7d95c7d13abdc02c1d8bd12ec18Andreas Gustafsson * Find the next entry after 'resp' in 'qid'. Return NULL if there are
3530e10080e5a7d95c7d13abdc02c1d8bd12ec18Andreas Gustafsson * no more entries.
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrewslinear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * The dispatch must be locked.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (!ISC_LIST_EMPTY(disp->activesockets))
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff * Called when refcount reaches 0 (and safe to destroy).
2b258a1f5b02488c6a36ac1b0a7535b42ea6fd34Evan Hunt * The dispatcher must be locked.
2b258a1f5b02488c6a36ac1b0a7535b42ea6fd34Evan Hunt * The manager must not be locked.
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellingtondestroy_disp(isc_task_t *task, isc_event_t *event) {
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellington INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff "shutting down; detaching from sock %p, task %p",
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link);
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews * Manipulate port table per dispatch: find an entry for a given port number,
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews * create a new entry, and decrement a given entry with possible clean-up.
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrewsport_search(dns_dispatch_t *disp, in_port_t port) {
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews portentry = ISC_LIST_HEAD(disp->port_table[port %
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrewsnew_portentry(dns_dispatch_t *disp, in_port_t port) {
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE],
cfc22e53a89ccac4eb04b4f41a93f73e629e80edEvan Hunt * The caller must not hold the qid->lock.
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrewsderef_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews REQUIRE(portentry != NULL && portentry->refs > 0);
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews ISC_LIST_UNLINK(disp->port_table[portentry->port %
38c3ed154a2e014dad359e852b08722defa118ebEvan Hunt * Set '*portentryp' to NULL inside the lock so that
38c3ed154a2e014dad359e852b08722defa118ebEvan Hunt * dispsock->portentry does not change in socket_search.
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 * Find a dispsocket for socket address 'dest', and port number 'port'.
38c3ed154a2e014dad359e852b08722defa118ebEvan Hunt * Return NULL if no such entry exists. Requires qid->lock to be held.
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port,
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]);
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 dispsock = ISC_LIST_NEXT(dispsock, blink);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Make a new socket for a single dispatch with a random port number.
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt * The caller must hold the disp->lock
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (isc_sockaddr_pf(&disp->local) == AF_INET) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispsock = ISC_LIST_HEAD(disp->inactivesockets);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_attach(disp->task[r % disp->ntasks], &dispsock->task);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Pick up a random UDP port and open a new socket with it. Avoid
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * choosing ports that share the same destination because it will be
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * very likely to fail in bind(2) or connect(2).
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 for (i = 0; i < 64; i++) {
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman port = ports[isc_rng_uniformrandom(DISP_RNGCTX(disp), nports)];
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt if (socket_search(qid, dest, port, bucket) != NULL) {
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
9cf04a12ec5ea0ee64338feef76e885980a524dfMark Andrews isc_sockaddr_format(&localaddr, buf, sizeof(buf));
9cf04a12ec5ea0ee64338feef76e885980a524dfMark Andrews "open_socket(%s) -> %s: continuing",
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * We could keep it in the inactive list, but since this should
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * be an exceptional case and might be resource shortage, we'd
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * rather destroy it.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Destroy a dedicated dispatch socket.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * The dispatch must be locked.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 REQUIRE(dispsockp != NULL && *dispsockp != NULL);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 REQUIRE(!ISC_LINK_LINKED(dispsock, link));
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_mempool_put(disp->mgr->spool, dispsock);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Deactivate a dedicated dispatch socket. Move it to the inactive list for
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * future reuse unless the total number of sockets are exceeding the maximum.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * The dispatch must be locked.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(disp->activesockets, dispsock, link);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 INSIST(dispsock->resp->dispsocket == dispsock);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (disp->nsockets > DNS_DISPATCH_POOLSOCKS)
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
34350037a886e7a16728335821da2bbff95683a9Evan Hunt ISC_LIST_APPEND(disp->inactivesockets, dispsock, link);
34350037a886e7a16728335821da2bbff95683a9Evan Hunt * If the underlying system does not allow this
34350037a886e7a16728335821da2bbff95683a9Evan Hunt * optimization, destroy this temporary structure (and
34350037a886e7a16728335821da2bbff95683a9Evan Hunt * create a new one for a new transaction).
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Find an entry for query ID 'id', socket address 'dest', and port number
3530e10080e5a7d95c7d13abdc02c1d8bd12ec18Andreas Gustafsson * Return NULL if no such entry exists.
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 res = ISC_LIST_HEAD(qid->qid_table[bucket]);
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 if (res->id == id && isc_sockaddr_equal(dest, &res->host) &&
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencefree_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graffstatic inline void
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_socketevent_t *sev = (isc_socketevent_t *) ev;
af669cb4fd7ecfb67ed145b176e5e764b249573bMark Andrewsallocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock,
ee980d3fc4c23b7f87fed96d3ba5e928937c9ed4Tinderbox User isc_eventtype_t type, isc_taskaction_t action, const void *arg)
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Huntstatic inline void
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Huntfree_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉udp_exrecv(isc_task_t *task, isc_event_t *ev) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉udp_shrecv(isc_task_t *task, isc_event_t *ev) {
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff * General flow:
135b1206c96d03353ac59fde7be0053dacc6568eAndreas Gustafsson * If I/O result == CANCELED or error, free the buffer.
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * If query, free the buffer, restart.
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff * If response:
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff * Allocate event, fill in details.
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff * If cannot allocate, free buffer, restart.
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff * find target. If not found, free buffer, restart.
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff * if event queue is not empty, queue. else, send.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
8d1943e8ffa991d54c5406342e44d7134762e7eaMichael Graff isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
8ed2c82a73a6c0a9c04ad26a4ef39b5a738099f6Andreas Gustafsson "got packet: requests %d, buffers %d, recvs %d",
f98d6edb191348477c9c5a156003df627d9bc42cBrian Wellington disp->requests, disp->mgr->buffers, disp->recv_pending);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * Unless the receive event was imported from a listening
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * interface, in which case the event type is
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * dispsock->resp can be NULL if this transaction was canceled
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * just after receiving a response. Since this socket is
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * exclusively used and there should be at most one receive
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * event the canceled event should have been no effect. So
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * we can (and should) deactivate the socket right now.
6da50be4364a17cdcd14095c0110aaa6a0566178Bob Halley * This dispatcher is shutting down.
6da50be4364a17cdcd14095c0110aaa6a0566178Bob Halley free_buffer(disp, ev->region.base, ev->region.length);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_send(disp->task[0], &disp->ctlevent);
2f76108082f11d4979048f1c22602391c5733c88Tatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
2f76108082f11d4979048f1c22602391c5733c88Tatuya JINMEI 神明達哉 * This is most likely a network error on a
2f76108082f11d4979048f1c22602391c5733c88Tatuya JINMEI 神明達哉 * connected socket. It makes no sense to
2f76108082f11d4979048f1c22602391c5733c88Tatuya JINMEI 神明達哉 * check the address or parse the packet, but it
2f76108082f11d4979048f1c22602391c5733c88Tatuya JINMEI 神明達哉 * will help to return the error to the caller.
61facaae4eb15535e1b0cebf007500551874f133Mark Andrews free_buffer(disp, ev->region.base, ev->region.length);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 } else if (ev->result != ISC_R_SUCCESS) {
6da50be4364a17cdcd14095c0110aaa6a0566178Bob Halley free_buffer(disp, ev->region.base, ev->region.length);
135b1206c96d03353ac59fde7be0053dacc6568eAndreas Gustafsson "odd socket result in udp_recv(): %s",
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellington * If this is from a blackholed address, drop it.
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellington isc_netaddr_fromsockaddr(&netaddr, &ev->address);
8ed67113ec802546179294a682581faa75e890c9Andreas Gustafsson dns_acl_match(&netaddr, NULL, disp->mgr->blackhole,
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellington "blackholed packet from %s",
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellington free_buffer(disp, ev->region.base, ev->region.length);
8d1943e8ffa991d54c5406342e44d7134762e7eaMichael Graff * Peek into the buffer to see what we can see.
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence isc_buffer_init(&source, ev->region.base, ev->region.length);
8d1943e8ffa991d54c5406342e44d7134762e7eaMichael Graff dres = dns_message_peekheader(&source, &id, &flags);
1ec39fc7a8b6ad92de3363d4c50b75e24fcd6accMichael Graff free_buffer(disp, ev->region.base, ev->region.length);
8ed2c82a73a6c0a9c04ad26a4ef39b5a738099f6Andreas Gustafsson dispatch_log(disp, LVL(10), "got garbage packet");
8ed2c82a73a6c0a9c04ad26a4ef39b5a738099f6Andreas Gustafsson "got valid DNS message header, /QR %c, id %u",
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
e618d503ba1a38fc407b071c43ded97ac59f0106Brian Wellington * Look at flags. If query, drop it. If response,
e618d503ba1a38fc407b071c43ded97ac59f0106Brian Wellington * look to see where it goes.
e618d503ba1a38fc407b071c43ded97ac59f0106Brian Wellington free_buffer(disp, ev->region.base, ev->region.length);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Search for the corresponding response. If we are using an exclusive
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * socket, we've already identified it and we can skip the search; but
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * the ID and the address must match the expected ones.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 bucket = dns_hash(qid, &ev->address, id, disp->localport);
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 resp = entry_search(qid, &ev->address, id, disp->localport,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 "search for response in bucket %d: %s",
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 bucket, (resp == NULL ? "not found" : "found"));
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 free_buffer(disp, ev->region.base, ev->region.length);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 } else if (resp->id != id || !isc_sockaddr_equal(&ev->address,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 "response to an exclusive socket doesn't match");
d8c2b1787119de43dd6b7e3927ff193ed5df682fMark Andrews free_buffer(disp, ev->region.base, ev->region.length);
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * Now that we have the original dispatch the query was sent
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * from check that the address and port the response was
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * sent to make sense.
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * Check that the socket types and ports match.
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews free_buffer(disp, ev->region.base, ev->region.length);
0606c47750ad362909f010db2ef1ff8dcc96f9cbEvan Hunt * If each dispatch is bound to a different address
0606c47750ad362909f010db2ef1ff8dcc96f9cbEvan Hunt * then fail.
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * Note under Linux a packet can be sent out via IPv4 socket
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * and the response be received via a IPv6 socket.
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews * Requests sent out via IPv6 should always come back in
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 &&
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews free_buffer(disp, ev->region.base, ev->region.length);
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local));
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local));
0606c47750ad362909f010db2ef1ff8dcc96f9cbEvan Hunt if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) &&
a295fbb55cfed38bcf2853c60410cce52ab6cebbMark Andrews free_buffer(disp, ev->region.base, ev->region.length);
d8c2b1787119de43dd6b7e3927ff193ed5df682fMark Andrews free_buffer(disp, ev->region.base, ev->region.length);
0b14ebe3132846e91bea02992493e3d506233e76Michael Graff * At this point, rev contains the event we want to fill in, and
0b14ebe3132846e91bea02992493e3d506233e76Michael Graff * resp contains the information on the place to send it to.
0b14ebe3132846e91bea02992493e3d506233e76Michael Graff * Send the event off.
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff "[a] Sent event %p buffer %p len %d to task %p",
42b48d11ca7b296324d7a8a98cdbf0070b0deb1dMark Andrews isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
ab0e5066083abcbec62513a3cc041d1f1eb9098aMichael Graff * Restart recv() to get the next packet.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (result != ISC_R_SUCCESS && dispsock != NULL) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * XXX: wired. There seems to be no recovery process other than
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * deactivate this socket anyway (since we cannot start
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * receiving, we won't be able to receive a cancel event
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * from the user).
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * General flow:
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * If I/O result == CANCELED, EOF, or error, notify everyone as the
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * various queues drain.
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * If query, restart.
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * If response:
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * Allocate event, fill in details.
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * If cannot allocate, restart.
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 * find target. If not found, restart.
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * if event queue is not empty, queue. else, send.
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencetcp_recv(isc_task_t *task, isc_event_t *ev_in) {
8ed2c82a73a6c0a9c04ad26a4ef39b5a738099f6Andreas Gustafsson "got TCP packet: requests %d, buffers %d, recvs %d",
f98d6edb191348477c9c5a156003df627d9bc42cBrian Wellington disp->requests, disp->tcpbuffers, disp->recv_pending);
6da50be4364a17cdcd14095c0110aaa6a0566178Bob Halley * This dispatcher is shutting down. Force cancelation.
00010dc6a4c9591891bf565f15af17a7e06eaca2Andreas Gustafsson dispatch_log(disp, LVL(90), "shutting down on EOF");
3733c24efa7eaa65455153702c3fb71c9233eafbMark Andrews isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf));
0fa218cc7cf0e5aef35bb4f5228dfccc04444d90Mark Andrews dispatch_log(disp, level, "shutting down due to TCP "
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * The event is statically allocated in the tcpmsg
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff * structure, and destroy_disp() frees the tcpmsg, so we must
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff * free the event *before* calling destroy_disp().
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * If the recv() was canceled pass the word on.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_send(disp->task[0], &disp->ctlevent);
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p",
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * Peek into the buffer to see what we can see.
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
8ed2c82a73a6c0a9c04ad26a4ef39b5a738099f6Andreas Gustafsson dispatch_log(disp, LVL(10), "got garbage packet");
8ed2c82a73a6c0a9c04ad26a4ef39b5a738099f6Andreas Gustafsson "got valid DNS message header, /QR %c, id %u",
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * Allocate an event to send to the query or response client, and
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * allocate a new buffer for our use.
e618d503ba1a38fc407b071c43ded97ac59f0106Brian Wellington * Look at flags. If query, drop it. If response,
e618d503ba1a38fc407b071c43ded97ac59f0106Brian Wellington * look to see where it goes.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket);
d8c2b1787119de43dd6b7e3927ff193ed5df682fMark Andrews "search for response in bucket %d: %s",
d8c2b1787119de43dd6b7e3927ff193ed5df682fMark Andrews bucket, (resp == NULL ? "not found" : "found"));
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * At this point, rev contains the event we want to fill in, and
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * resp contains the information on the place to send it to.
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * Send the event off.
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff "[b] Sent event %p buffer %p len %d to task %p",
42b48d11ca7b296324d7a8a98cdbf0070b0deb1dMark Andrews isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
c6066a8e67f40c7c12925c5634485f55713c06d6Michael Graff * Restart recv() to get the next packet.
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * disp must be locked.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellington if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (disp->recv_pending != 0 && dispsock == NULL)
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews if (disp->mgr->buffers >= disp->mgr->maxbuffers)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
f98d6edb191348477c9c5a156003df627d9bc42cBrian Wellington * UDP reads are always maximal.
af669cb4fd7ecfb67ed145b176e5e764b249573bMark Andrews res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 free_buffer(disp, region.base, region.length);
af669cb4fd7ecfb67ed145b176e5e764b249573bMark Andrews res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 free_buffer(disp, region.base, region.length);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 return (ISC_R_SUCCESS); /* recover by cancel */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0],
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 return (ISC_R_SUCCESS); /* recover by cancel */
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff * Mgr must be locked when calling this function.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt "depool=%d, rpool=%d, dpool=%d",
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff if (isc_mempool_getallocated(mgr->rpool) != 0)
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff if (isc_mempool_getallocated(mgr->dpool) != 0)
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff * Mgr must be unlocked when calling this function.
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
240e53b13217af266abb3dae8ba103614daf2bf7Mark Andrewsopen_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt result = isc_socket_create(mgr, isc_sockaddr_pf(local),
240e53b13217af266abb3dae8ba103614daf2bf7Mark Andrews result = isc_socket_bind(sock, local, options);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Create a temporary port list to set the initial default set of dispatch
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * ports: [1024, 65535]. This is almost meaningless as the application will
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * normally set the ports explicitly, but is provided to fill some minor corner
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = isc_portset_create(mctx, portsetp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_portset_addrange(*portsetp, 1024, 65535);
80617c8faa03b2c425e320597eb768073fd0b987Michael Graffdns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = isc_mutex_init(&mgr->buffer_lock);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatch_t),
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_setname(mgr->depool, "dispmgr_depool");
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_associatelock(mgr->depool, &mgr->depool_lock);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_associatelock(mgr->rpool, &mgr->rpool_lock);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = create_default_portset(mctx, &v4portset);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = create_default_portset(mctx, &v6portset);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = dns_dispatchmgr_setavailports(mgr,
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman result = isc_rng_create(mctx, mgr->entropy, &mgr->rngctx);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellingtondns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellington dns_acl_attach(blackhole, &mgr->blackhole);
97f26b88f62b10a9c26a91ebe8387d2e498c2d00Andreas Gustafssondns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 /* This function is deprecated: use dns_dispatchmgr_setavailports(). */
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 return (NULL); /* this function is deprecated */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 nv4ports = isc_portset_nports(v4portset);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 nv6ports = isc_portset_nports(v6portset);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 } while (p++ < 65535);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 INSIST(i4 == nv4ports && i6 == nv6ports);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int buffersize, unsigned int maxbuffers,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int maxrequests, unsigned int buckets,
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * Keep some number of items around. This should be a config
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * option. For now, keep 8, but later keep at least two even
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * if the caller wants less. This allows us to ensure certain
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * things, like an event can be "freed" and the next allocation
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * will always succeed.
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * Note that if limits are placed on anything here, we use one
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * event internally, so the actual limit should be "wanted + 1."
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 /* Create or adjust buffer pool */
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews * We only increase the maxbuffers to avoid accidental buffer
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews * shortage. Ideally we'd separate the manager-wide maximum
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews * from per-dispatch limits and respect the latter within the
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews * global limit. But at this moment that's deemed to be
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews * overkilling and isn't worth additional implementation
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews * complexity.
2a0d4c4d6ba5addb33cd1bccecc55ca4a095f191Mark Andrews isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = isc_mempool_create(mgr->mctx, buffersize, &mgr->bpool);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_associatelock(mgr->bpool, &mgr->bpool_lock);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 /* Create or adjust socket pool */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = isc_mempool_create(mgr->mctx, sizeof(dispsocket_t),
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_mempool_setname(mgr->spool, "dispmgr_spool");
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_mempool_setmaxalloc(mgr->spool, maxrequests);
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_associatelock(mgr->spool, &mgr->spool_lock);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE);
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencedns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff mgr_log(mgr, LVL(90), "destroy: killit=%d", killit);
d9059b0c38bd630c367d81424d72b1308cd74b04Tatuya JINMEI 神明達哉dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉port_cmp(const void *key, const void *ent) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
281bab0f36eaedc56f859721fbdf45568b71cd60Mark Andrews result = isc_socket_getsockname(sock, sockaddrp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (isc_sockaddr_pf(sockaddrp) == AF_INET) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL)
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencelocal_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Don't match wildcard ports unless the port is available in the
2a03c0af765860308edb715be012d4bc743c47f1Tatuya JINMEI 神明達哉 * current configuration.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 !portavailable(disp->mgr, disp->socket, NULL)) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews * Check if we match the binding <address,port>.
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews * Wildcard ports match/fail here.
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews * Check if we match a bound wildcard port <address,port>.
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews result = isc_socket_getsockname(disp->socket, &sockaddr);
455bb19b5dbf5dce6e625349acf5018fc4823adbTatuya JINMEI 神明達哉 return (isc_sockaddr_equal(&sockaddr, addr));
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Requires mgr be locked.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * No dispatcher can be locked by this thread when calling this function.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * If a matching dispatcher is found, it is locked after this function
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * returns, and must be unlocked by the caller.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffdispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
2a03c0af765860308edb715be012d4bc743c47f1Tatuya JINMEI 神明達哉 * Make certain that we will not match a private or exclusive dispatch.
2a03c0af765860308edb715be012d4bc743c47f1Tatuya JINMEI 神明達哉 attributes &= ~(DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
2a03c0af765860308edb715be012d4bc743c47f1Tatuya JINMEI 神明達哉 mask |= (DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
b9c8f4378ae98056ca4244b6d454baff85f4bc2aMichael Graff && ATTRMATCH(disp->attributes, attributes, mask)
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrewsqid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int increment, dns_qid_t **qidp,
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrews unsigned int i;
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 qid->sock_table = isc_mem_get(mgr->mctx, buckets *
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 for (i = 0; i < buckets; i++) {
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrewsqid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
b55dc7da2e2d1b92e92fdb5da8991d73dcfc6819Tatuya JINMEI 神明達哉 qid->qid_nbuckets * sizeof(dispsocketlist_t));
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Allocate and set important limits.
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrewsdispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Set up the dispatcher, mostly. Don't bother setting some of
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * the options that are controlled by tcp vs. udp, etc.
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson memset(&disp->local, 0, sizeof(disp->local));
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman isc_rng_attach(mgr->rngctx, &disp->rngctx);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * error returns
584848087f7463c1f659ce4712dc047d8e7f2b07Francis Dupont * MUST be unlocked, and not used by anything.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 INSIST(ISC_LIST_EMPTY(disp->activesockets));
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++)
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffdns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_taskmgr_t *taskmgr, unsigned int buffersize,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff unsigned int maxbuffers, unsigned int maxrequests,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff unsigned int attributes, dns_dispatch_t **dispp)
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews return (dns_dispatch_createtcp2(mgr, sock, taskmgr, NULL, NULL,
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrewsdns_dispatch_createtcp2(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
948c80ffa8f4efbade049f49d9751675f6937cf4Tinderbox User isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews isc_sockaddr_t *destaddr, unsigned int buffersize,
948c80ffa8f4efbade049f49d9751675f6937cf4Tinderbox User unsigned int maxbuffers, unsigned int maxrequests,
948c80ffa8f4efbade049f49d9751675f6937cf4Tinderbox User unsigned int buckets, unsigned int increment,
948c80ffa8f4efbade049f49d9751675f6937cf4Tinderbox User unsigned int attributes, dns_dispatch_t **dispp)
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
24675e8e132e068cbb5c6e13dc147dcba52919c4David Lawrence REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * dispatch_allocate() checks mgr for us.
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * qid_allocate() checks buckets and increment for us.
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews result = dispatch_allocate(mgr, maxrequests, &disp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = qid_allocate(mgr, buckets, increment, &disp->qid, ISC_FALSE);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = isc_task_create(taskmgr, 0, &disp->task[0]);
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellington disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_setname(disp->task[0], "tcpdispatch", disp);
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graff * Append it to the dispatcher list.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispatch_log(disp, LVL(90), "created task %p", disp->task[0]);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Error returns.
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrewsdns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews isc_sockaddr_t *localaddr, dns_dispatch_t **dispp)
761d135ed686601f36fe3d0d4aaa6bf41287bb0fEvan Hunt attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
761d135ed686601f36fe3d0d4aaa6bf41287bb0fEvan Hunt DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews ATTRMATCH(disp->attributes, attributes, mask) &&
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews isc_sockaddr_eqaddr(localaddr, &disp->local))) {
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews /* attach */
74717eef53ba5d6aefc80eb262bbb090ff4bb3b5Mark Andrews return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
ff62d4458acda2110a3763ec576a4f728450662cEvan Huntdns_dispatch_gettcp2(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt isc_sockaddr_t *localaddr, isc_boolean_t *connected,
1059bc2e42e8214f8b73d3b4cd181d8394a94a6aFrancis Dupont /* First pass (same as dns_dispatch_gettcp()) */
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt /* attach */
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt /* Second pass */
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt /* attach */
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Huntdns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff unsigned int maxbuffers, unsigned int maxrequests,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt dns_dispatch_t **dispp, dns_dispatch_t *dup_dispatch)
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
281bab0f36eaedc56f859721fbdf45568b71cd60Mark Andrews * See if we have a dispatcher that matches.
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Nope, create one.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Huntdns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt unsigned int buffersize,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt unsigned int maxbuffers, unsigned int maxrequests,
41bbb34bc20f189af62e7047ce42822615417f15Evan Hunt return (dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * mgr should be locked.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 unsigned int i, j;
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 anyport = ISC_TF(isc_sockaddr_getport(localaddr) == 0);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * If no port is specified, we first try to pick up a random
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * port by ourselves.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 for (i = 0; i < 1024; i++) {
84dc4b3e7eea3e9c8fafa5f4fd632a51ee8b356fMukund Sivaraman prt = ports[isc_rng_uniformrandom(DISP_RNGCTX(disp),
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_sockaddr_setport(&localaddr_bound, prt);
9de0f9b0aed432ee357dbba8d1d807525f4b6d4aMark Andrews result = open_socket(sockmgr, &localaddr_bound,
99394e9807411cbbeb9814b603c7dfa3b569388eMark Andrews * Continue if the port choosen is already in use
99394e9807411cbbeb9814b603c7dfa3b569388eMark Andrews * or the OS has reserved it.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * If this fails 1024 times, we then ask the kernel for
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * choosing one.
92241b04f16e1095a53f2c75e7987381dd0773afMark Andrews /* Allow to reuse address for non-random ports. */
a4037b279b13cc3f5b73d2f42e9c893cea2a6734Tatuya JINMEI 神明達哉 for (j = 0; j < 0xffffU; j++) {
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
a4037b279b13cc3f5b73d2f42e9c893cea2a6734Tatuya JINMEI 神明達哉 if (j == 0xffffU) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 "avoid-v%s-udp-ports: unable to allocate "
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 "an available port",
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6");
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 for (i = 0; i < DNS_DISPATCH_HELD; i++) {
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffdispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews * dispatch_allocate() checks mgr for us.
8affb49a70de247206cb04aae87730f2b4c90dd0Mark Andrews result = dispatch_allocate(mgr, maxrequests, &disp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) {
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock,
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt mgr_log(mgr, LVL(90), "dns_dispatch_createudp: Created"
4e9a1ad22618a46dab82eeb2d030190cec0afbc6Mukund Sivaraman " UDP dispatch for %s with socket fd %d",
ebacb7908afe3d62fe341f7ef9efed63d0c651a2Tatuya JINMEI 神明達哉 * For dispatches using exclusive sockets with a specific
ebacb7908afe3d62fe341f7ef9efed63d0c651a2Tatuya JINMEI 神明達哉 * source address, we only check if the specified address is
ebacb7908afe3d62fe341f7ef9efed63d0c651a2Tatuya JINMEI 神明達哉 * available on the system. Query sockets will be created later
ebacb7908afe3d62fe341f7ef9efed63d0c651a2Tatuya JINMEI 神明達哉 isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
ebacb7908afe3d62fe341f7ef9efed63d0c651a2Tatuya JINMEI 神明達哉 if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
f07b2fccaf6be13d9440d323e9e79ee84fe345e2Evan Hunt result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++)
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews result = isc_mempool_create(mgr->mctx, sizeof(dispportentry_t),
96b3cb85d3b06d99323a6ea7ae04f4eb3d74e8bcMark Andrews isc_mempool_setname(disp->portpool, "disp_portpool");
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 result = isc_task_create(taskmgr, 0, &disp->task[i]);
307d2084502eddc7ce921e5ce439aec3531d90e0Tatuya JINMEI 神明達哉 while (--i >= 0) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_setname(disp->task[i], "udpdispatch", disp);
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellington disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt if (isc_mempool_create(mgr->mctx, sizeof(isc_socketevent_t),
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt isc_mempool_associatelock(disp->sepool, &disp->sepool_lock);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Append it to the dispatcher list.
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * Error returns.
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencedns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * It is important to lock the manager while we are deleting the dispatch,
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * since dns_dispatch_getudp will call dispatch_find, which returns to
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * the caller a dispatch but does not attach to it until later. _getudp
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * locks the manager, however, so locking it here will keep us from attaching
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff * to a dispatcher that is in the process of going away.
54a64ec428cb9f783d62a044cbec3a72724a937cMichael Graff REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socket_cancel(disp->socket, disp->task[0],
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 for (dispsock = ISC_LIST_HEAD(disp->activesockets);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispsock = ISC_LIST_NEXT(dispsock, link)) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socket_cancel(dispsock->socket, dispsock->task,
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_send(disp->task[0], &disp->ctlevent);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_t *task, isc_taskaction_t action, void *arg,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dns_messageid_t *idp, dns_dispentry_t **resp,
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrews return (dns_dispatch_addresponse3(disp, 0, dest, task, action, arg,
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrewsdns_dispatch_addresponse3(dns_dispatch_t *disp, unsigned int options,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Kill oldest outstanding query if the number of sockets
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * exceeds the quota to keep the room for new queries.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 oldestsocket = ISC_LIST_HEAD(disp->activesockets);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if (oldestresp != NULL && !oldestresp->item_out) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Move this entry to the tail so that it won't (easily) be
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * examined before actually being canceled.
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_APPEND(disp->activesockets, oldestsocket, link);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Get a separate UDP socket with a random port number.
54489ba1672458382e8dfb5490fcfc7230f8ea85Evan Hunt result = get_dispsocket(disp, dest, sockmgr, &dispsocket,
f19e6ef1eb7d5abf547fc1af24e561bdc5d75b22Mark Andrews inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrews * Try somewhat hard to find an unique ID unless FIXEDID is set
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrews * in which case we use the id passed in via *idp.
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrews id = (dns_messageid_t)isc_rng_random(DISP_RNGCTX(disp));
e2fe1fda755f24f593406dc26fed87e8ea1bb502Tatuya JINMEI 神明達哉 if (entry_search(qid, dest, id, localport, bucket) == NULL) {
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrews if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0)
109f477ed7b0ea20217f0b1d5560f376c6d2cd92Mark Andrews } while (i++ < 64);
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrews ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
3c671ac666de8a7dcd7bd02afa20968da0b85bbdMark Andrews if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 ISC_LIST_APPEND(disp->activesockets, dispsocket, link);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_t *task, isc_taskaction_t action, void *arg,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dns_messageid_t *idp, dns_dispentry_t **resp)
2cf81a3d8a8a12e81a762a0bc3d46e0b117733bfAutomatic Updater REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
ffeaac1d826b541af39d7b20b9b68ff19ff01832Mark Andrews return (dns_dispatch_addresponse3(disp, 0, dest, task, action, arg,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]);
ff62d4458acda2110a3763ec576a4f728450662cEvan Hunt if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsdns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews REQUIRE(sockevent != NULL && *sockevent != NULL);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews free_buffer(disp, ev->buffer.base, ev->buffer.length);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews "[c] Sent event %p buffer %p len %d to task %p",
46993e1d9d18410a5852b7d990338b70b158855cMichael Graffdns_dispatch_removeresponse(dns_dispentry_t **resp,
6d58c9b95ec40eb38533061eefab6cb256e870e6Bob Halley unsigned int n;
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socket_cancel(disp->socket, disp->task[0],
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 for (dispsock = ISC_LIST_HEAD(disp->activesockets);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 dispsock = ISC_LIST_NEXT(dispsock, link)) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socket_cancel(dispsock->socket, dispsock->task,
a7c76f1924d5fc914c579fd3b0276ffbddd2f65aMark Andrews ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
6d58c9b95ec40eb38533061eefab6cb256e870e6Bob Halley * We've posted our event, but the caller hasn't gotten it
6d58c9b95ec40eb38533061eefab6cb256e870e6Bob Halley * yet. Take it back.
6d58c9b95ec40eb38533061eefab6cb256e870e6Bob Halley n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH,
6d58c9b95ec40eb38533061eefab6cb256e870e6Bob Halley * We had better have gotten it back.
6d58c9b95ec40eb38533061eefab6cb256e870e6Bob Halley ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events);
6f1422b81ed2c5142092e2ced8e3faf0e61f3ba0Michael Graff free_buffer(disp, ev->buffer.base, ev->buffer.length);
20c266cbc999c724e03e6edd437fb4181b92f095Michael Graff request_log(disp, res, LVL(90), "detaching from task %p", res->task);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socket_cancel(res->dispsocket->socket,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 res->dispsocket->task, ISC_SOCKCANCEL_RECV);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * Free any buffered responses as well
6f1422b81ed2c5142092e2ced8e3faf0e61f3ba0Michael Graff free_buffer(disp, ev->buffer.base, ev->buffer.length);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_send(disp->task[0], &disp->ctlevent);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * Search for the first response handler without packets outstanding
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * unless a specific hander is given.
d8c2b1787119de43dd6b7e3927ff193ed5df682fMark Andrews /* Empty. */)
6f1422b81ed2c5142092e2ced8e3faf0e61f3ba0Michael Graff * No one to send the cancel event to, so nothing to do.
d1ba6e9180c7d7458656a6e53e52fde056fd244cMichael Graff * Send the shutdown failsafe event to this resp.
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
97a195d7ff64f78b32dbfde0edb8109fc800ee02Andreas Gustafsson "cancel: failsafe event %p -> task %p",
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencedns_dispatch_getsocket(dns_dispatch_t *disp) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉dns_dispatch_getentrysocket(dns_dispentry_t *resp) {
a674e7ececfd787f0c3e7a6dc36f7f79ba1ddab9Mark Andrewsdns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉dns_dispatch_getattributes(dns_dispatch_t *disp) {
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * We don't bother locking disp here; it's the caller's responsibility
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 * to use only non volatile flags.
ca9739800f045cd4d39014f98b920d4354b5bd14Michael Graffdns_dispatch_changeattributes(dns_dispatch_t *disp,
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 /* Exclusive attribute can only be set on creation */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 /* Also, a dispatch with randomport specified cannot start listening */
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 ||
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0);
ca0db0cdc8ad7c771c4922b8220ebafde953904eMichael Graff * Should check for valid attributes here!
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN)
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
e992af4209b737f511b6f2fad3ddb7bdfc17b9aeTatuya JINMEI 神明達哉 disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_socket_cancel(disp->socket, disp->task[0],
319d2971f1f10ded49e2325e2f8e7f24ea37a708Brian Wellingtondns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
527163f0e5e8639bcceb7fe52387285042f5b24cEvan Hunt if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0)
35f06ab0e6d5ad26176b7584de7b4d405272ba68Brian Wellington INSIST(sevent->n <= disp->mgr->buffersize);
319d2971f1f10ded49e2325e2f8e7f24ea37a708Brian Wellington newsevent->region.length = disp->mgr->buffersize;
319d2971f1f10ded49e2325e2f8e7f24ea37a708Brian Wellington newsevent->attributes = sevent->attributes;
386d3a99c190bad55edf44d076e6bd087e230ab8Tatuya JINMEI 神明達哉 isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent));
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt /* check that dispatch set is configured */
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntdns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr,
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t));
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dns_dispatch_attach(source, &dset->dispatches[0]);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt for (i = 1; i < n; i++) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt result = dispatch_createudp(mgr, sockmgr, taskmgr,
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt for (j = 0; j < i; j++)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t));
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntdns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt sock = dns_dispatch_getsocket(dset->dispatches[i]);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntdns_dispatchset_destroy(dns_dispatchset_t **dsetp) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
67adc03ef81fb610f8df093b17f55275ee816754Evan Huntdns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) {
3d181bc9f12154a56bfbb536198a6c481cbcd525David Lawrencedns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafsson isc_sockaddr_format(&disp->local, foo, sizeof(foo));
46993e1d9d18410a5852b7d990338b70b158855cMichael Graff printf("\tdispatch %p, addr %s\n", disp, foo);