adb.c revision d4d2a13916a114879763562db6a19b70b1444ec1
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Copyright (C) 1999 Internet Software Consortium.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Permission to use, copy, modify, and distribute this software for any
5347c0fcb04eaea19d9f39795646239f487c6207Tinderbox User * purpose with or without fee is hereby granted, provided that the above
5347c0fcb04eaea19d9f39795646239f487c6207Tinderbox User * copyright notice and this permission notice appear in all copies.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
d6fa26d0adaec6c910115be34fe7a5a5f402c14fMark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Implementation notes
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * --------------------
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * In handles, if task == NULL, no events will be generated, and no events
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * have been sent. If task != NULL but taskaction == NULL, an event has been
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * posted but not yet freed. If neigher are NULL, no event was posted.
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User#define DNS_ADBNAME_MAGIC 0x6164624e /* adbN. */
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User#define DNS_ADBNAME_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define DNS_ADBNAMEHOOK_MAGIC 0x61644e48 /* adNH. */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define DNS_ADBNAMEHOOK_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define DNS_ADBZONEINFO_MAGIC 0x6164625a /* adbZ. */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#define DNS_ADBZONEINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBZONEINFO_MAGIC)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define DNS_ADBENTRY_MAGIC 0x61646245 /* adbE. */
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User#define DNS_ADBENTRY_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User#define DNS_ADBFETCH_MAGIC 0x61646246 /* adbF. */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define DNS_ADBFETCH_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Lengths of lists needs to be powers of two.
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User#define DNS_ADBNAMELIST_LENGTH 32 /* how many buckets for names */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define DNS_ADBENTRYLIST_LENGTH 32 /* how many buckets for addresses */
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein#define CLEAN_SECONDS 20 /* clean this many seconds initially */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#define FREE_ITEMS 16 /* free count for memory pools */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#define FILL_COUNT 8 /* fill count for memory pools */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#define DNS_ADB_INVALIDBUCKET (-1) /* invalid bucket address */
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox Usertypedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeintypedef struct dns_adbzoneinfo dns_adbzoneinfo_t;
2b4d1b54f6ca406b8233d9e6fea9593df6dad035Tinderbox Usertypedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
2b4d1b54f6ca406b8233d9e6fea9593df6dad035Tinderbox User unsigned int magic;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * Bucketized locks and lists for names.
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User dns_adbnamelist_t names[DNS_ADBNAMELIST_LENGTH];
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User isc_mutex_t namelocks[DNS_ADBNAMELIST_LENGTH];
bbbf2e27d3a981163dab139497d6b2dc85449db0Tinderbox User isc_boolean_t name_sd[DNS_ADBNAMELIST_LENGTH];
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * Bucketized locks for entries.
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User dns_adbentrylist_t entries[DNS_ADBENTRYLIST_LENGTH];
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User isc_mutex_t entrylocks[DNS_ADBENTRYLIST_LENGTH];
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * XXX: This has a pointer to the adb it came from. It shouldn't need
44d0f0256fbdce130a18655023c3b06bacacbd61Automatic Updater * this, but I can't think of how to get rid of it. In particular, since
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * events have but one "arg" value, and that is currently used for the name
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * pointer in fetches, we need a way to get to the fetch contexts as well
bcf15a19ae0efa72a22cdfb50666a3c6ce39eb9fTinderbox User * as the adb itself.
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User unsigned int magic;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein unsigned int magic;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * dns_adbnamehook_t
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * This is a small widget that dangles off a dns_adbname_t. It contains a
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * pointer to the address information about this host, and a link to the next
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * namehook that will contain the next address this host has.
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt unsigned int magic;
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * dns_adbzoneinfo_t
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * This is a small widget that holds zone-specific information about an
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * address. Currently limited to lameness, but could just as easily be
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * extended to other types of information about zones.
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User unsigned int magic;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * An address entry. It holds quite a bit of information about addresses,
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * including edns state, rtt, and of course the address of the host.
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User unsigned int magic;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt unsigned int refcnt;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt unsigned int flags;
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein unsigned int srtt;
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox User * Internal functions (and prototypes).
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox Userstatic inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline void free_adbname(dns_adb_t *, dns_adbname_t **);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline dns_adbzoneinfo_t *new_adbzoneinfo(dns_adb_t *, dns_name_t *);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline void free_adbzoneinfo(dns_adb_t *, dns_adbzoneinfo_t **);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic inline dns_adbentry_t *new_adbentry(dns_adb_t *);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
71c66a876ecca77923638d3f94cc0783152b2f03Mark Andrewsstatic inline dns_adbhandle_t *new_adbhandle(dns_adb_t *);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic inline void free_adbhandle(dns_adb_t *, dns_adbhandle_t **);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *,
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox Userstatic inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic void print_dns_name(FILE *, dns_name_t *);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic void print_namehook_list(FILE *, dns_adbname_t *);
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox Userstatic void print_handle_list(FILE *, dns_adbname_t *);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox Userstatic void print_fetch_list(FILE *, dns_adbname_t *);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox Userstatic inline void inc_adb_irefcnt(dns_adb_t *, isc_boolean_t);
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox Userstatic inline void dec_adb_irefcnt(dns_adb_t *, isc_boolean_t);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinstatic inline void inc_adb_erefcnt(dns_adb_t *, isc_boolean_t);
cd32f419a8a5432fbb139f56ee73cbf68b9350ccTinderbox Userstatic inline void dec_adb_erefcnt(dns_adb_t *, isc_boolean_t);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline void dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
33c9436ef1a43d3c0fc3d9be9b4b0509daa83223Tinderbox Userstatic void clean_namehooks_at_name(dns_adb_t *, dns_adbname_t *);
a1ff871f78b7d907d6fc3a382beea2a640fe8423Tinderbox Userstatic void clean_handles_at_name(dns_adbname_t *, isc_eventtype_t);
3ca1a32241189d1e02e59f6b56399eb9b40f2aafTinderbox Userstatic void cancel_fetches_at_name(dns_adb_t *, dns_adbname_t *);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic isc_result_t construct_name(dns_adb_t *, dns_adbhandle_t *,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic isc_result_t fetch_name(dns_adb_t *, dns_adbname_t *,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntstatic void timer_cleanup(isc_task_t *, isc_event_t *);
cd32f419a8a5432fbb139f56ee73cbf68b9350ccTinderbox Userstatic inline void link_name(dns_adb_t *, int, dns_adbname_t *);
cd32f419a8a5432fbb139f56ee73cbf68b9350ccTinderbox Userstatic inline void unlink_name(dns_adb_t *, dns_adbname_t *);
cd32f419a8a5432fbb139f56ee73cbf68b9350ccTinderbox Userstatic void kill_name(dns_adb_t *, dns_adbname_t **, isc_eventtype_t ev);
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Requires the adbname bucket be locked and that no entry buckets be locked.
af40ebed6257e4ac1996144530b3de317cf4da11Tinderbox Userimport_rdataset(dns_adb_t *adb, dns_adbname_t *adbname,
44d0f0256fbdce130a18655023c3b06bacacbd61Automatic Updater dns_rdataset_t *rdataset, isc_stdtime_t now)
811ccf37deef5ad425a6bfb3a71f6730d4d3ebc4Tinderbox User dns_adbentry_t *foundentry; /* NO CLEAN UP! */
7e71f05d8643aca84914437c900cb716444507e4Tinderbox User foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
28b3569d6248168e6c00caab951521cc8141a49dAutomatic Updater ISC_LIST_APPEND(adb->entries[addr_bucket],
2cbb4ab75757fbb656997a82c14ca07db37d481aAutomatic Updater ISC_LIST_APPEND(adbname->namehooks, nh, link);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (now + rdataset->ttl < adbname->expire_time)
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * Requires the name's bucket be locked.
e2e4d321999340802f77adaacd19c797d04b4b95Automatic Updaterkill_name(dns_adb_t *adb, dns_adbname_t **n, isc_eventtype_t ev)
0c6ada0a814f3c5417daa1654129bc2af56ed504Automatic Updater * If we're dead already, just check to see if we should go
0c6ada0a814f3c5417daa1654129bc2af56ed504Automatic Updater * away now or not.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (name->dead && ISC_LIST_EMPTY(name->fetches)) {
9b469e3c59015b1a4899c9d8395168126fe094fdAutomatic Updater * Clean up the name's various lists. These two are destructive
9b469e3c59015b1a4899c9d8395168126fe094fdAutomatic Updater * in that they will always empty the list.
10b865e9187fc77cae02f106ddcc9e03eecdfe06Tinderbox User * If fetches are running, cancel them. If none are running, we can
10b865e9187fc77cae02f106ddcc9e03eecdfe06Tinderbox User * just kill the name here.
1e9517ea2156b990be21f44676d3370318eacf17Tinderbox User * Requires the name's bucket be locked.
1e9517ea2156b990be21f44676d3370318eacf17Tinderbox Userstatic inline void
1e9517ea2156b990be21f44676d3370318eacf17Tinderbox Userlink_name(dns_adb_t *adb, int bucket, dns_adbname_t *name)
1e9517ea2156b990be21f44676d3370318eacf17Tinderbox User INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
1e9517ea2156b990be21f44676d3370318eacf17Tinderbox User ISC_LIST_PREPEND(adb->names[bucket], name, link);
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox User * Requires the name's bucket be locked.
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox Userstatic inline void
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox Userunlink_name(dns_adb_t *adb, dns_adbname_t *name)
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox User ISC_LIST_UNLINK(adb->names[bucket], name, link);
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox Userstatic inline void
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox Userviolate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want)
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox User if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
7911e6f9de303bca5a3d8b34f4330c8f7cecffaeTinderbox User * The ADB _MUST_ be locked before calling. Also, exit conditions must be
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * checked after calling this function.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein for (bucket = 0 ; bucket < DNS_ADBNAMELIST_LENGTH ; bucket++) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * Run through the list. For each name, clean up handles
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein * found there, and cancel any fetches running. When
0b89eee6167201843c9a46b7e7c63cb1e4e09ba3Tinderbox User * all the fetches are canceled, the name will destroy
int addr_bucket;
if (lock)
if (lock)
if (lock)
if (lock)
if (lock)
if (lock)
if (lock)
if (lock)
int bucket;
if (lock)
if (lock)
int bucket;
if (lock)
if (lock)
if (!destroy_entry)
static inline dns_adbname_t *
return (NULL);
return (NULL);
return (name);
dns_adbname_t *n;
n = *name;
n->magic = 0;
static inline dns_adbnamehook_t *
return (NULL);
return (nh);
static inline dns_adbzoneinfo_t *
return (NULL);
return (NULL);
return (zi);
static inline dns_adbentry_t *
dns_adbentry_t *e;
isc_uint32_t r;
if (e == NULL)
return (NULL);
e->refcnt = 0;
e->flags = 0;
e->goodness = 0;
dns_adbentry_t *e;
e = *entry;
e->magic = 0;
static inline dns_adbhandle_t *
dns_adbhandle_t *h;
if (h == NULL)
return (NULL);
h->magic = 0;
return (NULL);
static inline dns_adbfetch_t *
dns_adbfetch_t *f;
if (f == NULL)
return (NULL);
f->magic = 0;
goto err;
goto err;
err:
return (NULL);
dns_adbfetch_t *f;
f = *fetch;
f->magic = 0;
static inline dns_adbaddrinfo_t *
return (NULL);
return (ai);
static inline dns_adbname_t *
int bucket;
return (adbname);
return (NULL);
static inline dns_adbentry_t *
int bucket;
return (entry);
return (NULL);
static isc_boolean_t
return (ISC_FALSE);
return (is_bad);
int bucket;
goto next;
goto out;
next:
out:
return (ISC_R_NOMEMORY);
goto fail0a;
goto fail0b;
goto fail0c;
goto fail1;
for (i = 0 ; i < DNS_ADBNAMELIST_LENGTH ; i++) {
for (i = 0 ; i < DNS_ADBENTRYLIST_LENGTH ; i++)
goto fail2;
#define MPINIT(t, p, l, n) do { \
goto fail3; \
isc_mempool_setname((p), n); \
goto fail3;
goto fail3;
return (ISC_R_SUCCESS);
return (result);
int bucket;
if (now == 0) {
return (result);
goto success;
goto fail;
goto fail;
goto found;
goto found;
goto fail;
goto fail;
goto success;
fail:
if (attach_to_task) {
return (result);
int name_bucket;
return (ISC_R_NOTFOUND);
if (decr_adbrefcnt)
return (DNS_R_SUCCESS);
if (now == 0) {
return (result);
goto out;
goto out;
goto out;
goto out;
return (ISC_R_SUCCESS);
out:
if (free_name)
if (free_entry)
if (free_namehook)
return (result);
int bucket;
goto cleanup;
const char *tmpp;
for (i = 0 ; i < DNS_ADBNAMELIST_LENGTH ; i++)
for (i = 0 ; i < DNS_ADBENTRYLIST_LENGTH ; i++)
for (i = 0 ; i < DNS_ADBNAMELIST_LENGTH ; i++) {
for (i = 0 ; i < DNS_ADBENTRYLIST_LENGTH ; i++) {
case AF_INET:
case AF_INET6:
for (i = 0 ; i < DNS_ADBENTRYLIST_LENGTH ; i++)
for (i = 0 ; i < DNS_ADBNAMELIST_LENGTH ; i++)
const char *tmpp;
case AF_INET:
case AF_INET6:
isc_buffer_t b;
static isc_result_t
return (ISC_R_NOTIMPLEMENTED);
switch (result) {
case DNS_R_GLUE:
case DNS_R_HINT:
case DNS_R_SUCCESS:
return (result);
int bucket;
(void)task;
if (decr_adbrefcnt)
goto out;
out:
static isc_result_t
goto cleanup;
goto cleanup;
goto cleanup;
return (result);
int bucket;
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
int goodness_adjustment)
int bucket;
if (goodness_adjustment == 0)
if (goodness_adjustment > 0) {
int bucket;
unsigned int new_srtt;
if (factor == 0)