Merge from vendor branch NTPD:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / adb.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: adb.c,v 1.181.2.17 2004/03/09 06:10:59 marka Exp $ */
19
20 /*
21  * Implementation notes
22  * --------------------
23  *
24  * In finds, if task == NULL, no events will be generated, and no events
25  * have been sent.  If task != NULL but taskaction == NULL, an event has been
26  * posted but not yet freed.  If neither are NULL, no event was posted.
27  *
28  */
29
30 /*
31  * After we have cleaned all buckets, dump the database contents.
32  */
33 #if 0
34 #define DUMP_ADB_AFTER_CLEANING
35 #endif
36
37 #include <config.h>
38
39 #include <limits.h>
40
41 #include <isc/mutexblock.h>
42 #include <isc/netaddr.h>
43 #include <isc/random.h>
44 #include <isc/string.h>         /* Required for HP/UX (and others?) */
45 #include <isc/task.h>
46 #include <isc/timer.h>
47 #include <isc/util.h>
48
49 #include <dns/a6.h>
50 #include <dns/adb.h>
51 #include <dns/db.h>
52 #include <dns/events.h>
53 #include <dns/log.h>
54 #include <dns/rdata.h>
55 #include <dns/rdataset.h>
56 #include <dns/rdatastruct.h>
57 #include <dns/resolver.h>
58 #include <dns/result.h>
59
60 #define DNS_ADB_MAGIC             ISC_MAGIC('D', 'a', 'd', 'b')
61 #define DNS_ADB_VALID(x)          ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
62 #define DNS_ADBNAME_MAGIC         ISC_MAGIC('a', 'd', 'b', 'N')
63 #define DNS_ADBNAME_VALID(x)      ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
64 #define DNS_ADBNAMEHOOK_MAGIC     ISC_MAGIC('a', 'd', 'N', 'H')
65 #define DNS_ADBNAMEHOOK_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
66 #define DNS_ADBZONEINFO_MAGIC     ISC_MAGIC('a', 'd', 'b', 'Z')
67 #define DNS_ADBZONEINFO_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBZONEINFO_MAGIC)
68 #define DNS_ADBENTRY_MAGIC        ISC_MAGIC('a', 'd', 'b', 'E')
69 #define DNS_ADBENTRY_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
70 #define DNS_ADBFETCH_MAGIC        ISC_MAGIC('a', 'd', 'F', '4')
71 #define DNS_ADBFETCH_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
72 #define DNS_ADBFETCH6_MAGIC       ISC_MAGIC('a', 'd', 'F', '6')
73 #define DNS_ADBFETCH6_VALID(x)    ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
74
75 /*
76  * The number of buckets needs to be a prime (for good hashing).
77  *
78  * XXXRTH  How many buckets do we need?
79  */
80 #define NBUCKETS               1009     /* how many buckets for names/addrs */
81
82 /*
83  * For type 3 negative cache entries, we will remember that the address is
84  * broken for this long.  XXXMLG This is also used for actual addresses, too.
85  * The intent is to keep us from constantly asking about A/A6/AAAA records
86  * if the zone has extremely low TTLs.
87  */
88 #define ADB_CACHE_MINIMUM       10      /* seconds */
89 #define ADB_CACHE_MAXIMUM       86400   /* seconds (86400 = 24 hours) */
90 #define ADB_ENTRY_WINDOW        1800    /* seconds  */
91
92 /*
93  * Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all
94  * buckets are cleaned in CLEAN_PERIOD seconds.
95  */
96 #define CLEAN_PERIOD            3600
97 #define CLEAN_SECONDS           30
98 #define CLEAN_BUCKETS           ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
99
100 #define FREE_ITEMS              64      /* free count for memory pools */
101 #define FILL_COUNT              16      /* fill count for memory pools */
102
103 #define DNS_ADB_INVALIDBUCKET (-1)      /* invalid bucket address */
104
105 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
106 typedef struct dns_adbnamehook dns_adbnamehook_t;
107 typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
108 typedef struct dns_adbzoneinfo dns_adbzoneinfo_t;
109 typedef ISC_LIST(dns_adbentry_t) dns_adbentrylist_t;
110 typedef struct dns_adbfetch dns_adbfetch_t;
111 typedef struct dns_adbfetch6 dns_adbfetch6_t;
112
113 struct dns_adb {
114         unsigned int                    magic;
115
116         isc_mutex_t                     lock;
117         isc_mutex_t                     reflock; /* Covers irefcnt, erefcnt */
118         isc_mem_t                      *mctx;
119         dns_view_t                     *view;
120         isc_timermgr_t                 *timermgr;
121         isc_timer_t                    *timer;
122         isc_taskmgr_t                  *taskmgr;
123         isc_task_t                     *task;
124
125         isc_interval_t                  tick_interval;
126         int                             next_cleanbucket;
127
128         unsigned int                    irefcnt;
129         unsigned int                    erefcnt;
130
131         isc_mutex_t                     mplock;
132         isc_mempool_t                  *nmp;    /* dns_adbname_t */
133         isc_mempool_t                  *nhmp;   /* dns_adbnamehook_t */
134         isc_mempool_t                  *zimp;   /* dns_adbzoneinfo_t */
135         isc_mempool_t                  *emp;    /* dns_adbentry_t */
136         isc_mempool_t                  *ahmp;   /* dns_adbfind_t */
137         isc_mempool_t                  *aimp;   /* dns_adbaddrinfo_t */
138         isc_mempool_t                  *afmp;   /* dns_adbfetch_t */
139         isc_mempool_t                  *af6mp;  /* dns_adbfetch6_t */
140
141         /*
142          * Bucketized locks and lists for names.
143          *
144          * XXXRTH  Have a per-bucket structure that contains all of these?
145          */
146         dns_adbnamelist_t               names[NBUCKETS];
147         isc_mutex_t                     namelocks[NBUCKETS];
148         isc_boolean_t                   name_sd[NBUCKETS];
149         unsigned int                    name_refcnt[NBUCKETS];
150
151         /*
152          * Bucketized locks for entries.
153          *
154          * XXXRTH  Have a per-bucket structure that contains all of these?
155          */
156         dns_adbentrylist_t              entries[NBUCKETS];
157         isc_mutex_t                     entrylocks[NBUCKETS];
158         isc_boolean_t                   entry_sd[NBUCKETS]; /* shutting down */
159         unsigned int                    entry_refcnt[NBUCKETS];
160
161         isc_event_t                     cevent;
162         isc_boolean_t                   cevent_sent;
163         isc_boolean_t                   shutting_down;
164         isc_eventlist_t                 whenshutdown;
165 };
166
167 /*
168  * XXXMLG  Document these structures.
169  */
170
171 struct dns_adbname {
172         unsigned int                    magic;
173         dns_name_t                      name;
174         dns_adb_t                      *adb;
175         unsigned int                    partial_result;
176         unsigned int                    flags;
177         int                             lock_bucket;
178         dns_name_t                      target;
179         isc_stdtime_t                   expire_target;
180         isc_stdtime_t                   expire_v4;
181         isc_stdtime_t                   expire_v6;
182         unsigned int                    chains;
183         dns_adbnamehooklist_t           v4;
184         dns_adbnamehooklist_t           v6;
185         dns_adbfetch_t                 *fetch_a;
186         dns_adbfetch_t                 *fetch_aaaa;
187         ISC_LIST(dns_adbfetch6_t)       fetches_a6;
188         unsigned int                    fetch_err;
189         unsigned int                    fetch6_err;
190         dns_adbfindlist_t               finds;
191         ISC_LINK(dns_adbname_t)         plink;
192 };
193
194 struct dns_adbfetch {
195         unsigned int                    magic;
196         dns_adbnamehook_t              *namehook;
197         dns_adbentry_t                 *entry;
198         dns_fetch_t                    *fetch;
199         dns_rdataset_t                  rdataset;
200 };
201
202 struct dns_adbfetch6 {
203         unsigned int                    magic;
204         unsigned int                    flags;
205         dns_adbnamehook_t              *namehook;
206         dns_adbentry_t                 *entry;
207         dns_fetch_t                    *fetch;
208         dns_rdataset_t                  rdataset;
209         dns_a6context_t                 a6ctx;
210         ISC_LINK(dns_adbfetch6_t)       plink;
211 };
212
213 /*
214  * dns_adbnamehook_t
215  *
216  * This is a small widget that dangles off a dns_adbname_t.  It contains a
217  * pointer to the address information about this host, and a link to the next
218  * namehook that will contain the next address this host has.
219  */
220 struct dns_adbnamehook {
221         unsigned int                    magic;
222         dns_adbentry_t                 *entry;
223         ISC_LINK(dns_adbnamehook_t)     plink;
224 };
225
226 /*
227  * dns_adbzoneinfo_t
228  *
229  * This is a small widget that holds zone-specific information about an
230  * address.  Currently limited to lameness, but could just as easily be
231  * extended to other types of information about zones.
232  */
233 struct dns_adbzoneinfo {
234         unsigned int                    magic;
235
236         dns_name_t                      zone;
237         isc_stdtime_t                   lame_timer;
238
239         ISC_LINK(dns_adbzoneinfo_t)     plink;
240 };
241
242 /*
243  * An address entry.  It holds quite a bit of information about addresses,
244  * including edns state (in "flags"), rtt, and of course the address of
245  * the host.
246  */
247 struct dns_adbentry {
248         unsigned int                    magic;
249
250         int                             lock_bucket;
251         unsigned int                    refcnt;
252
253         unsigned int                    flags;
254         unsigned int                    srtt;
255         isc_sockaddr_t                  sockaddr;
256         
257         isc_stdtime_t                   expires;
258         /*
259          * A nonzero 'expires' field indicates that the entry should
260          * persist until that time.  This allows entries found
261          * using dns_adb_findaddrinfo() to persist for a limited time
262          * even though they are not necessarily associated with a
263          * name.
264          */
265
266         ISC_LIST(dns_adbzoneinfo_t)     zoneinfo;
267         ISC_LINK(dns_adbentry_t)        plink;
268 };
269
270 /*
271  * Internal functions (and prototypes).
272  */
273 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
274 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
275 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
276                                                  dns_adbentry_t *);
277 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
278 static inline dns_adbzoneinfo_t *new_adbzoneinfo(dns_adb_t *, dns_name_t *);
279 static inline void free_adbzoneinfo(dns_adb_t *, dns_adbzoneinfo_t **);
280 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
281 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
282 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
283 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
284 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
285                                                  in_port_t);
286 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
287 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
288 static inline dns_adbfetch6_t *new_adbfetch6(dns_adb_t *, dns_adbname_t *,
289                                              dns_a6context_t *);
290 static inline void free_adbfetch6(dns_adb_t *, dns_adbfetch6_t **);
291 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
292                                                 unsigned int, int *);
293 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
294                                                   isc_sockaddr_t *, int *);
295 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug);
296 static void print_dns_name(FILE *, dns_name_t *);
297 static void print_namehook_list(FILE *, const char *legend,
298                                 dns_adbnamehooklist_t *list,
299                                 isc_boolean_t debug);
300 static void print_find_list(FILE *, dns_adbname_t *);
301 static void print_fetch_list(FILE *, dns_adbname_t *);
302 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
303 static inline void inc_adb_erefcnt(dns_adb_t *);
304 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
305                                     isc_boolean_t);
306 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
307                                     isc_boolean_t);
308 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
309 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
310 static void clean_target(dns_adb_t *, dns_name_t *);
311 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
312                                 unsigned int);
313 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
314 static void cancel_fetches_at_name(dns_adbname_t *);
315 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
316                                 dns_rdatatype_t);
317 static isc_result_t fetch_name_v4(dns_adbname_t *, isc_boolean_t);
318 static isc_result_t fetch_name_aaaa(dns_adbname_t *);
319 static isc_result_t fetch_name_a6(dns_adbname_t *, isc_boolean_t);
320 static inline void check_exit(dns_adb_t *);
321 static void timer_cleanup(isc_task_t *, isc_event_t *);
322 static void destroy(dns_adb_t *);
323 static isc_boolean_t shutdown_names(dns_adb_t *);
324 static isc_boolean_t shutdown_entries(dns_adb_t *);
325 static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
326 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
327 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
328 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
329 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
330 static void fetch_callback_a6(isc_task_t *, isc_event_t *);
331 static isc_result_t dbfind_a6(dns_adbname_t *, isc_stdtime_t);
332
333 /*
334  * MUST NOT overlap DNS_ADBFIND_* flags!
335  */
336 #define FIND_EVENT_SENT         0x40000000
337 #define FIND_EVENT_FREED        0x80000000
338 #define FIND_EVENTSENT(h)       (((h)->flags & FIND_EVENT_SENT) != 0)
339 #define FIND_EVENTFREED(h)      (((h)->flags & FIND_EVENT_FREED) != 0)
340
341 #define NAME_NEEDS_POKE         0x80000000
342 #define NAME_IS_DEAD            0x40000000
343 #define NAME_HINT_OK            DNS_ADBFIND_HINTOK
344 #define NAME_GLUE_OK            DNS_ADBFIND_GLUEOK
345 #define NAME_STARTATZONE        DNS_ADBFIND_STARTATZONE
346 #define NAME_DEAD(n)            (((n)->flags & NAME_IS_DEAD) != 0)
347 #define NAME_NEEDSPOKE(n)       (((n)->flags & NAME_NEEDS_POKE) != 0)
348 #define NAME_GLUEOK(n)          (((n)->flags & NAME_GLUE_OK) != 0)
349 #define NAME_HINTOK(n)          (((n)->flags & NAME_HINT_OK) != 0)
350
351 /*
352  * To the name, address classes are all that really exist.  If it has a
353  * V6 address it doesn't care if it came from an A6 chain or an AAAA query.
354  */
355 #define NAME_HAS_V4(n)          (!ISC_LIST_EMPTY((n)->v4))
356 #define NAME_HAS_V6(n)          (!ISC_LIST_EMPTY((n)->v6))
357 #define NAME_HAS_ADDRS(n)       (NAME_HAS_V4(n) || NAME_HAS_V6(n))
358
359 /*
360  * Fetches are broken out into A, AAAA, and A6 types.  In some cases,
361  * however, it makes more sense to test for a particular class of fetches,
362  * like V4 or V6 above.
363  */
364 #define NAME_FETCH_A(n)         ((n)->fetch_a != NULL)
365 #define NAME_FETCH_AAAA(n)      ((n)->fetch_aaaa != NULL)
366 #define NAME_FETCH_A6(n)        (!ISC_LIST_EMPTY((n)->fetches_a6))
367 #define NAME_FETCH_V4(n)        (NAME_FETCH_A(n))
368 #define NAME_FETCH_V6(n)        (NAME_FETCH_AAAA(n) || NAME_FETCH_A6(n))
369 #define NAME_FETCH(n)           (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
370
371 /*
372  * Was this fetch started using the hints database?
373  * Was this the initial fetch for the A6 record?  If so, we might want to
374  * start AAAA queries if it fails.
375  */
376 #define FETCH_FIRST_A6          0x80000000
377 #define FETCH_FIRSTA6(f)        (((f)->flags & FETCH_FIRST_A6) != 0)
378
379 /*
380  * Find options and tests to see if there are addresses on the list.
381  */
382 #define FIND_WANTEVENT(fn)      (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
383 #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
384 #define FIND_AVOIDFETCHES(fn)   (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
385                                  != 0)
386 #define FIND_STARTATZONE(fn)    (((fn)->options & DNS_ADBFIND_STARTATZONE) \
387                                  != 0)
388 #define FIND_HINTOK(fn)         (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
389 #define FIND_GLUEOK(fn)         (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
390 #define FIND_HAS_ADDRS(fn)      (!ISC_LIST_EMPTY((fn)->list))
391 #define FIND_RETURNLAME(fn)     (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
392
393 /*
394  * These are currently used on simple unsigned ints, so they are
395  * not really associated with any particular type.
396  */
397 #define WANT_INET(x)            (((x) & DNS_ADBFIND_INET) != 0)
398 #define WANT_INET6(x)           (((x) & DNS_ADBFIND_INET6) != 0)
399
400 #define EXPIRE_OK(exp, now)     ((exp == INT_MAX) || (exp < now))
401
402 /*
403  * Find out if the flags on a name (nf) indicate if it is a hint or
404  * glue, and compare this to the appropriate bits set in o, to see if
405  * this is ok.
406  */
407 #define GLUE_OK(nf, o) (!NAME_GLUEOK(nf) || (((o) & DNS_ADBFIND_GLUEOK) != 0))
408 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
409 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
410 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
411                                     ((o) & DNS_ADBFIND_STARTATZONE))
412
413 #define ENTER_LEVEL             50
414 #define EXIT_LEVEL              ENTER_LEVEL
415 #define CLEAN_LEVEL             100
416 #define DEF_LEVEL               5
417 #define NCACHE_LEVEL            20
418
419 #define NCACHE_RESULT(r)        ((r) == DNS_R_NCACHENXDOMAIN || \
420                                  (r) == DNS_R_NCACHENXRRSET)
421 #define AUTH_NX(r)              ((r) == DNS_R_NXDOMAIN || \
422                                  (r) == DNS_R_NXRRSET)
423 #define NXDOMAIN_RESULT(r)      ((r) == DNS_R_NXDOMAIN || \
424                                  (r) == DNS_R_NCACHENXDOMAIN)
425 #define NXRRSET_RESULT(r)       ((r) == DNS_R_NCACHENXRRSET || \
426                                  (r) == DNS_R_NXRRSET || \
427                                  (r) == DNS_R_HINTNXRRSET)
428
429 /*
430  * Error state rankings.
431  */
432
433 #define FIND_ERR_SUCCESS                0  /* highest rank */
434 #define FIND_ERR_CANCELED               1
435 #define FIND_ERR_FAILURE                2
436 #define FIND_ERR_NXDOMAIN               3
437 #define FIND_ERR_NXRRSET                4
438 #define FIND_ERR_UNEXPECTED             5
439 #define FIND_ERR_NOTFOUND               6
440 #define FIND_ERR_MAX                    7
441
442 static const char *errnames[] = {
443         "success",
444         "canceled",
445         "failure",
446         "nxdomain",
447         "nxrrset",
448         "unexpected",
449         "not_found"
450 };
451
452 #define NEWERR(old, new)        (ISC_MIN((old), (new)))
453
454 static isc_result_t find_err_map[FIND_ERR_MAX] = {
455         ISC_R_SUCCESS,
456         ISC_R_CANCELED,
457         ISC_R_FAILURE,
458         DNS_R_NXDOMAIN,
459         DNS_R_NXRRSET,
460         ISC_R_UNEXPECTED,
461         ISC_R_NOTFOUND          /* not YET found */
462 };
463
464 static void
465 DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
466
467 static void
468 DP(int level, const char *format, ...) {
469         va_list args;
470
471         va_start(args, format);
472         isc_log_vwrite(dns_lctx,
473                        DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
474                        ISC_LOG_DEBUG(level), format, args);
475         va_end(args);
476 }
477
478 static inline dns_ttl_t
479 ttlclamp(dns_ttl_t ttl) {
480         if (ttl < ADB_CACHE_MINIMUM)
481                 ttl = ADB_CACHE_MINIMUM;
482         if (ttl > ADB_CACHE_MAXIMUM)
483                 ttl = ADB_CACHE_MAXIMUM;
484
485         return (ttl);
486 }
487
488 /*
489  * Requires the adbname bucket be locked and that no entry buckets be locked.
490  *
491  * This code handles A and AAAA rdatasets only.
492  */
493 static isc_result_t
494 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
495                 isc_stdtime_t now)
496 {
497         isc_result_t result;
498         dns_adb_t *adb;
499         dns_adbnamehook_t *nh;
500         dns_adbnamehook_t *anh;
501         dns_rdata_t rdata = DNS_RDATA_INIT;
502         struct in_addr ina;
503         struct in6_addr in6a;
504         isc_sockaddr_t sockaddr;
505         dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
506         int addr_bucket;
507         isc_boolean_t new_addresses_added;
508         dns_rdatatype_t rdtype;
509         unsigned int findoptions;
510
511         INSIST(DNS_ADBNAME_VALID(adbname));
512         adb = adbname->adb;
513         INSIST(DNS_ADB_VALID(adb));
514
515         rdtype = rdataset->type;
516         INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
517         if (rdtype == dns_rdatatype_a)
518                 findoptions = DNS_ADBFIND_INET;
519         else
520                 findoptions = DNS_ADBFIND_INET6;
521
522         addr_bucket = DNS_ADB_INVALIDBUCKET;
523         new_addresses_added = ISC_FALSE;
524
525         nh = NULL;
526         result = dns_rdataset_first(rdataset);
527         while (result == ISC_R_SUCCESS) {
528                 dns_rdata_reset(&rdata);
529                 dns_rdataset_current(rdataset, &rdata);
530                 if (rdtype == dns_rdatatype_a) {
531                         INSIST(rdata.length == 4);
532                         memcpy(&ina.s_addr, rdata.data, 4);
533                         isc_sockaddr_fromin(&sockaddr, &ina, 0);
534                 } else {
535                         INSIST(rdata.length == 16);
536                         memcpy(in6a.s6_addr, rdata.data, 16);
537                         isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
538                 }
539
540                 INSIST(nh == NULL);
541                 nh = new_adbnamehook(adb, NULL);
542                 if (nh == NULL) {
543                         adbname->partial_result |= findoptions;
544                         result = ISC_R_NOMEMORY;
545                         goto fail;
546                 }
547
548                 foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
549                 if (foundentry == NULL) {
550                         dns_adbentry_t *entry;
551
552                         entry = new_adbentry(adb);
553                         if (entry == NULL) {
554                                 adbname->partial_result |= findoptions;
555                                 result = ISC_R_NOMEMORY;
556                                 goto fail;
557                         }
558
559                         entry->sockaddr = sockaddr;
560                         entry->refcnt = 1;
561
562                         nh->entry = entry;
563
564                         link_entry(adb, addr_bucket, entry);
565                 } else {
566                         for (anh = ISC_LIST_HEAD(adbname->v4);
567                              anh != NULL;
568                              anh = ISC_LIST_NEXT(anh, plink))
569                                 if (anh->entry == foundentry)
570                                         break;
571                         if (anh == NULL) {
572                                 foundentry->refcnt++;
573                                 nh->entry = foundentry;
574                         } else
575                                 free_adbnamehook(adb, &nh);
576                 }
577
578                 new_addresses_added = ISC_TRUE;
579                 if (nh != NULL) {
580                         if (rdtype == dns_rdatatype_a)
581                                 ISC_LIST_APPEND(adbname->v4, nh, plink);
582                         else
583                                 ISC_LIST_APPEND(adbname->v6, nh, plink);
584                 }
585                 nh = NULL;
586                 result = dns_rdataset_next(rdataset);
587         }
588
589  fail:
590         if (nh != NULL)
591                 free_adbnamehook(adb, &nh);
592
593         if (addr_bucket != DNS_ADB_INVALIDBUCKET)
594                 UNLOCK(&adb->entrylocks[addr_bucket]);
595
596         if (rdataset->trust == dns_trust_glue ||
597             rdataset->trust == dns_trust_additional)
598                 rdataset->ttl = ADB_CACHE_MINIMUM;
599         else
600                 rdataset->ttl = ttlclamp(rdataset->ttl);
601
602         if (rdtype == dns_rdatatype_a) {
603                 DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
604                    adbname->expire_v4, now + rdataset->ttl);
605                 adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
606                                              now + rdataset->ttl);
607         } else {
608                 DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
609                    adbname->expire_v6, now + rdataset->ttl);
610                 adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
611                                              now + rdataset->ttl);
612         }
613
614         if (new_addresses_added) {
615                 /*
616                  * Lie a little here.  This is more or less so code that cares
617                  * can find out if any new information was added or not.
618                  */
619                 return (ISC_R_SUCCESS);
620         }
621
622         return (result);
623 }
624
625 static void
626 import_a6(dns_a6context_t *a6ctx) {
627         dns_adbname_t *name;
628         dns_adb_t *adb;
629         dns_adbnamehook_t *nh;
630         dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
631         int addr_bucket;
632         isc_sockaddr_t sockaddr;
633
634         name = a6ctx->arg;
635         INSIST(DNS_ADBNAME_VALID(name));
636         adb = name->adb;
637         INSIST(DNS_ADB_VALID(adb));
638
639         addr_bucket = DNS_ADB_INVALIDBUCKET;
640
641         DP(ENTER_LEVEL, "ENTER: import_a6() name %p", name);
642
643         nh = new_adbnamehook(adb, NULL);
644         if (nh == NULL) {
645                 name->partial_result |= DNS_ADBFIND_INET6; /* clear for AAAA */
646                 goto fail;
647         }
648
649         isc_sockaddr_fromin6(&sockaddr, &a6ctx->in6addr, 0);
650
651         foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
652         if (foundentry == NULL) {
653                 dns_adbentry_t *entry;
654                 entry = new_adbentry(adb);
655                 if (entry == NULL) {
656                         name->partial_result |= DNS_ADBFIND_INET6;
657                         goto fail;
658                 }
659
660                 entry->sockaddr = sockaddr;
661                 entry->refcnt = 1;
662                 nh->entry = entry;
663                 link_entry(adb, addr_bucket, entry);
664         } else {
665                 foundentry->refcnt++;
666                 nh->entry = foundentry;
667         }
668
669         ISC_LIST_APPEND(name->v6, nh, plink);
670         nh = NULL;
671
672  fail:
673         DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) in import_v6",
674            name->expire_v6, a6ctx->expiration);
675         name->expire_v6 = ISC_MIN(name->expire_v6, a6ctx->expiration);
676
677         name->flags |= NAME_NEEDS_POKE;
678
679         if (nh != NULL)
680                 free_adbnamehook(adb, &nh);
681
682         if (addr_bucket != DNS_ADB_INVALIDBUCKET)
683                 UNLOCK(&adb->entrylocks[addr_bucket]);
684 }
685
686 /*
687  * Requires the name's bucket be locked.
688  */
689 static isc_boolean_t
690 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
691         dns_adbname_t *name;
692         isc_boolean_t result = ISC_FALSE;
693         isc_boolean_t result4, result6;
694         dns_adb_t *adb;
695
696         INSIST(n != NULL);
697         name = *n;
698         *n = NULL;
699         INSIST(DNS_ADBNAME_VALID(name));
700         adb = name->adb;
701         INSIST(DNS_ADB_VALID(adb));
702
703         DP(DEF_LEVEL, "killing name %p", name);
704
705         /*
706          * If we're dead already, just check to see if we should go
707          * away now or not.
708          */
709         if (NAME_DEAD(name) && !NAME_FETCH(name)) {
710                 result = unlink_name(adb, name);
711                 free_adbname(adb, &name);
712                 if (result)
713                         result = dec_adb_irefcnt(adb);
714                 return (result);
715         }
716
717         /*
718          * Clean up the name's various lists.  These two are destructive
719          * in that they will always empty the list.
720          */
721         clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
722         result4 = clean_namehooks(adb, &name->v4);
723         result6 = clean_namehooks(adb, &name->v6);
724         clean_target(adb, &name->target);
725         result = ISC_TF(result4 || result6);
726
727         /*
728          * If fetches are running, cancel them.  If none are running, we can
729          * just kill the name here.
730          */
731         if (!NAME_FETCH(name)) {
732                 INSIST(result == ISC_FALSE);
733                 result = unlink_name(adb, name);
734                 free_adbname(adb, &name);
735                 if (result)
736                         result = dec_adb_irefcnt(adb);
737         } else {
738                 name->flags |= NAME_IS_DEAD;
739                 cancel_fetches_at_name(name);
740         }
741         return (result);
742 }
743
744 /*
745  * Requires the name's bucket be locked and no entry buckets be locked.
746  */
747 static isc_boolean_t
748 check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
749         dns_adb_t *adb;
750         isc_boolean_t result4 = ISC_FALSE;
751         isc_boolean_t result6 = ISC_FALSE;
752
753         INSIST(DNS_ADBNAME_VALID(name));
754         adb = name->adb;
755         INSIST(DNS_ADB_VALID(adb));
756
757         /*
758          * Check to see if we need to remove the v4 addresses
759          */
760         if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
761                 if (NAME_HAS_V4(name)) {
762                         DP(DEF_LEVEL, "expiring v4 for name %p", name);
763                         result4 = clean_namehooks(adb, &name->v4);
764                         name->partial_result &= ~DNS_ADBFIND_INET;
765                 }
766                 name->expire_v4 = INT_MAX;
767                 name->fetch_err = FIND_ERR_UNEXPECTED;
768         }
769
770         /*
771          * Check to see if we need to remove the v6 addresses
772          */
773         if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
774                 if (NAME_HAS_V6(name)) {
775                         DP(DEF_LEVEL, "expiring v6 for name %p", name);
776                         result6 = clean_namehooks(adb, &name->v6);
777                         name->partial_result &= ~DNS_ADBFIND_INET6;
778                 }
779                 name->expire_v6 = INT_MAX;
780                 name->fetch6_err = FIND_ERR_UNEXPECTED;
781         }
782
783         /*
784          * Check to see if we need to remove the alias target.
785          */
786         if (EXPIRE_OK(name->expire_target, now)) {
787                 clean_target(adb, &name->target);
788                 name->expire_target = INT_MAX;
789         }
790         return (ISC_TF(result4 || result6));
791 }
792
793 /*
794  * Requires the name's bucket be locked.
795  */
796 static inline void
797 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
798         INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
799
800         ISC_LIST_PREPEND(adb->names[bucket], name, plink);
801         name->lock_bucket = bucket;
802         adb->name_refcnt[bucket]++;
803 }
804
805 /*
806  * Requires the name's bucket be locked.
807  */
808 static inline isc_boolean_t
809 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
810         int bucket;
811         isc_boolean_t result = ISC_FALSE;
812
813         bucket = name->lock_bucket;
814         INSIST(bucket != DNS_ADB_INVALIDBUCKET);
815
816         ISC_LIST_UNLINK(adb->names[bucket], name, plink);
817         name->lock_bucket = DNS_ADB_INVALIDBUCKET;
818         INSIST(adb->name_refcnt[bucket] > 0);
819         adb->name_refcnt[bucket]--;
820         if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
821                 result = ISC_TRUE;
822         return (result);
823 }
824
825 /*
826  * Requires the entry's bucket be locked.
827  */
828 static inline void
829 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
830         ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
831         entry->lock_bucket = bucket;
832         adb->entry_refcnt[bucket]++;
833 }
834
835 /*
836  * Requires the entry's bucket be locked.
837  */
838 static inline isc_boolean_t
839 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
840         int bucket;
841         isc_boolean_t result = ISC_FALSE;
842
843         bucket = entry->lock_bucket;
844         INSIST(bucket != DNS_ADB_INVALIDBUCKET);
845
846         ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
847         entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
848         INSIST(adb->entry_refcnt[bucket] > 0);
849         adb->entry_refcnt[bucket]--;
850         if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
851                 result = ISC_TRUE;
852         return (result);
853 }
854
855 static inline void
856 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
857         if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
858                 UNLOCK(have);
859                 LOCK(want);
860                 LOCK(have);
861         }
862 }
863
864 /*
865  * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
866  * checked after calling this function.
867  */
868 static isc_boolean_t
869 shutdown_names(dns_adb_t *adb) {
870         int bucket;
871         isc_boolean_t result = ISC_FALSE;
872         dns_adbname_t *name;
873         dns_adbname_t *next_name;
874
875         for (bucket = 0 ; bucket < NBUCKETS ; bucket++) {
876                 LOCK(&adb->namelocks[bucket]);
877                 adb->name_sd[bucket] = ISC_TRUE;
878
879                 name = ISC_LIST_HEAD(adb->names[bucket]);
880                 if (name == NULL) {
881                         /*
882                          * This bucket has no names.  We must decrement the
883                          * irefcnt ourselves, since it will not be
884                          * automatically triggered by a name being unlinked.
885                          */
886                         INSIST(result == ISC_FALSE);
887                         result = dec_adb_irefcnt(adb);
888                 } else {
889                         /*
890                          * Run through the list.  For each name, clean up finds
891                          * found there, and cancel any fetches running.  When
892                          * all the fetches are canceled, the name will destroy
893                          * itself.
894                          */
895                         while (name != NULL) {
896                                 next_name = ISC_LIST_NEXT(name, plink);
897                                 INSIST(result == ISC_FALSE);
898                                 result = kill_name(&name,
899                                                    DNS_EVENT_ADBSHUTDOWN);
900                                 name = next_name;
901                         }
902                 }
903
904                 UNLOCK(&adb->namelocks[bucket]);
905         }
906         return (result);
907 }
908
909 /*
910  * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
911  * checked after calling this function.
912  */
913 static isc_boolean_t
914 shutdown_entries(dns_adb_t *adb) {
915         int bucket;
916         isc_boolean_t result = ISC_FALSE;
917         dns_adbentry_t *entry;
918         dns_adbentry_t *next_entry;
919
920         for (bucket = 0 ; bucket < NBUCKETS ; bucket++) {
921                 LOCK(&adb->entrylocks[bucket]);
922                 adb->entry_sd[bucket] = ISC_TRUE;
923
924                 entry = ISC_LIST_HEAD(adb->entries[bucket]);
925                 if (entry == NULL) {
926                         /*
927                          * This bucket has no entries.  We must decrement the
928                          * irefcnt ourselves, since it will not be
929                          * automatically triggered by an entry being unlinked.
930                          */
931                         result = dec_adb_irefcnt(adb);
932                 } else {
933                         /*
934                          * Run through the list.  Cleanup any entries not
935                          * associated with names, and which are not in use.
936                          */
937                         while (entry != NULL) {
938                                 next_entry = ISC_LIST_NEXT(entry, plink);
939                                 if (entry->refcnt == 0 &&
940                                     entry->expires != 0) {
941                                         result = unlink_entry(adb, entry);
942                                         free_adbentry(adb, &entry);
943                                         if (result)
944                                                 result = dec_adb_irefcnt(adb);
945                                 }
946                                 entry = next_entry;
947                         }
948                 }
949
950                 UNLOCK(&adb->entrylocks[bucket]);
951         }
952         return (result);
953 }
954
955 /*
956  * Name bucket must be locked
957  */
958 static void
959 cancel_fetches_at_name(dns_adbname_t *name) {
960         dns_adbfetch6_t *fetch6;
961
962         if (NAME_FETCH_A(name))
963             dns_resolver_cancelfetch(name->fetch_a->fetch);
964
965
966         if (NAME_FETCH_AAAA(name))
967             dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
968
969
970         fetch6 = ISC_LIST_HEAD(name->fetches_a6);
971         while (fetch6 != NULL) {
972                 dns_resolver_cancelfetch(fetch6->fetch);
973                 fetch6 = ISC_LIST_NEXT(fetch6, plink);
974         }
975 }
976
977 /*
978  * Assumes the name bucket is locked.
979  */
980 static isc_boolean_t
981 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
982         dns_adbentry_t *entry;
983         dns_adbnamehook_t *namehook;
984         int addr_bucket;
985         isc_boolean_t result = ISC_FALSE;
986
987         addr_bucket = DNS_ADB_INVALIDBUCKET;
988         namehook = ISC_LIST_HEAD(*namehooks);
989         while (namehook != NULL) {
990                 INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
991
992                 /*
993                  * Clean up the entry if needed.
994                  */
995                 entry = namehook->entry;
996                 if (entry != NULL) {
997                         INSIST(DNS_ADBENTRY_VALID(entry));
998
999                         if (addr_bucket != entry->lock_bucket) {
1000                                 if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1001                                         UNLOCK(&adb->entrylocks[addr_bucket]);
1002                                 addr_bucket = entry->lock_bucket;
1003                                 LOCK(&adb->entrylocks[addr_bucket]);
1004                         }
1005
1006                         result = dec_entry_refcnt(adb, entry, ISC_FALSE);
1007                 }
1008
1009                 /*
1010                  * Free the namehook
1011                  */
1012                 namehook->entry = NULL;
1013                 ISC_LIST_UNLINK(*namehooks, namehook, plink);
1014                 free_adbnamehook(adb, &namehook);
1015
1016                 namehook = ISC_LIST_HEAD(*namehooks);
1017         }
1018
1019         if (addr_bucket != DNS_ADB_INVALIDBUCKET)
1020                 UNLOCK(&adb->entrylocks[addr_bucket]);
1021         return (result);
1022 }
1023
1024 static void
1025 clean_target(dns_adb_t *adb, dns_name_t *target) {
1026         if (dns_name_countlabels(target) > 0) {
1027                 dns_name_free(target, adb->mctx);
1028                 dns_name_init(target, NULL);
1029         }
1030 }
1031
1032 static isc_result_t
1033 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
1034            dns_rdataset_t *rdataset, dns_name_t *target)
1035 {
1036         isc_result_t result;
1037         dns_namereln_t namereln;
1038         unsigned int nlabels, nbits;
1039         int order;
1040         dns_rdata_t rdata = DNS_RDATA_INIT;
1041         dns_fixedname_t fixed1, fixed2;
1042         dns_name_t *prefix, *new_target;
1043
1044         REQUIRE(dns_name_countlabels(target) == 0);
1045
1046         if (rdataset->type == dns_rdatatype_cname) {
1047                 dns_rdata_cname_t cname;
1048
1049                 /*
1050                  * Copy the CNAME's target into the target name.
1051                  */
1052                 result = dns_rdataset_first(rdataset);
1053                 if (result != ISC_R_SUCCESS)
1054                         return (result);
1055                 dns_rdataset_current(rdataset, &rdata);
1056                 result = dns_rdata_tostruct(&rdata, &cname, NULL);
1057                 if (result != ISC_R_SUCCESS)
1058                         return (result);
1059                 result = dns_name_dup(&cname.cname, adb->mctx, target);
1060                 dns_rdata_freestruct(&cname);
1061                 if (result != ISC_R_SUCCESS)
1062                         return (result);
1063         } else {
1064                 dns_rdata_dname_t dname;
1065
1066                 INSIST(rdataset->type == dns_rdatatype_dname);
1067                 namereln = dns_name_fullcompare(name, fname, &order,
1068                                                 &nlabels, &nbits);
1069                 INSIST(namereln == dns_namereln_subdomain);
1070                 /*
1071                  * Get the target name of the DNAME.
1072                  */
1073                 result = dns_rdataset_first(rdataset);
1074                 if (result != ISC_R_SUCCESS)
1075                         return (result);
1076                 dns_rdataset_current(rdataset, &rdata);
1077                 result = dns_rdata_tostruct(&rdata, &dname, NULL);
1078                 if (result != ISC_R_SUCCESS)
1079                         return (result);
1080                 /*
1081                  * Construct the new target name.
1082                  */
1083                 dns_fixedname_init(&fixed1);
1084                 prefix = dns_fixedname_name(&fixed1);
1085                 dns_fixedname_init(&fixed2);
1086                 new_target = dns_fixedname_name(&fixed2);
1087                 result = dns_name_split(name, nlabels, nbits, prefix, NULL);
1088                 if (result != ISC_R_SUCCESS) {
1089                         dns_rdata_freestruct(&dname);
1090                         return (result);
1091                 }
1092                 result = dns_name_concatenate(prefix, &dname.dname, new_target,
1093                                               NULL);
1094                 dns_rdata_freestruct(&dname);
1095                 if (result != ISC_R_SUCCESS)
1096                         return (result);
1097                 result = dns_name_dup(new_target, adb->mctx, target);
1098                 if (result != ISC_R_SUCCESS)
1099                         return (result);
1100         }
1101
1102         return (ISC_R_SUCCESS);
1103 }
1104
1105 /*
1106  * Assumes nothing is locked, since this is called by the client.
1107  */
1108 static void
1109 event_free(isc_event_t *event) {
1110         dns_adbfind_t *find;
1111
1112         INSIST(event != NULL);
1113         find = event->ev_destroy_arg;
1114         INSIST(DNS_ADBFIND_VALID(find));
1115
1116         LOCK(&find->lock);
1117         find->flags |= FIND_EVENT_FREED;
1118         event->ev_destroy_arg = NULL;
1119         UNLOCK(&find->lock);
1120 }
1121
1122 /*
1123  * Assumes the name bucket is locked.
1124  */
1125 static void
1126 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
1127                     unsigned int addrs)
1128 {
1129         isc_event_t *ev;
1130         isc_task_t *task;
1131         dns_adbfind_t *find;
1132         dns_adbfind_t *next_find;
1133         isc_boolean_t process;
1134         unsigned int wanted, notify;
1135
1136         DP(ENTER_LEVEL,
1137            "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
1138            name, evtype, addrs);
1139
1140         find = ISC_LIST_HEAD(name->finds);
1141         while (find != NULL) {
1142                 LOCK(&find->lock);
1143                 next_find = ISC_LIST_NEXT(find, plink);
1144
1145                 process = ISC_FALSE;
1146                 wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1147                 notify = wanted & addrs;
1148
1149                 switch (evtype) {
1150                 case DNS_EVENT_ADBMOREADDRESSES:
1151                         DP(3, "DNS_EVENT_ADBMOREADDRESSES");
1152                         if ((notify) != 0) {
1153                                 find->flags &= ~addrs;
1154                                 process = ISC_TRUE;
1155                         }
1156                         break;
1157                 case DNS_EVENT_ADBNOMOREADDRESSES:
1158                         DP(3, "DNS_EVENT_ADBNOMOREADDRESSES");
1159                         find->flags &= ~addrs;
1160                         wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
1161                         if (wanted == 0)
1162                                 process = ISC_TRUE;
1163                         break;
1164                 default:
1165                         find->flags &= ~addrs;
1166                         process = ISC_TRUE;
1167                 }
1168
1169                 if (process) {
1170                         DP(DEF_LEVEL, "cfan: processing find %p", find);
1171                         /*
1172                          * Unlink the find from the name, letting the caller
1173                          * call dns_adb_destroyfind() on it to clean it up
1174                          * later.
1175                          */
1176                         ISC_LIST_UNLINK(name->finds, find, plink);
1177                         find->adbname = NULL;
1178                         find->name_bucket = DNS_ADB_INVALIDBUCKET;
1179
1180                         INSIST(!FIND_EVENTSENT(find));
1181
1182                         ev = &find->event;
1183                         task = ev->ev_sender;
1184                         ev->ev_sender = find;
1185                         find->result_v4 = find_err_map[name->fetch_err];
1186                         find->result_v6 = find_err_map[name->fetch6_err];
1187                         ev->ev_type = evtype;
1188                         ev->ev_destroy = event_free;
1189                         ev->ev_destroy_arg = find;
1190
1191                         DP(DEF_LEVEL,
1192                            "Sending event %p to task %p for find %p",
1193                            ev, task, find);
1194
1195                         isc_task_sendanddetach(&task, (isc_event_t **)&ev);
1196                 } else {
1197                         DP(DEF_LEVEL, "cfan: skipping find %p", find);
1198                 }
1199
1200                 UNLOCK(&find->lock);
1201                 find = next_find;
1202         }
1203
1204         DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
1205 }
1206
1207 static inline void
1208 check_exit(dns_adb_t *adb) {
1209         isc_event_t *event;
1210         /*
1211          * The caller must be holding the adb lock.
1212          */
1213         if (adb->shutting_down) {
1214                 /*
1215                  * If there aren't any external references either, we're
1216                  * done.  Send the control event to initiate shutdown.
1217                  */
1218                 INSIST(!adb->cevent_sent);      /* Sanity check. */
1219                 event = &adb->cevent;
1220                 isc_task_send(adb->task, &event);
1221                 adb->cevent_sent = ISC_TRUE;
1222         }
1223 }
1224
1225 static inline isc_boolean_t
1226 dec_adb_irefcnt(dns_adb_t *adb) {
1227         isc_event_t *event;
1228         isc_task_t *etask;
1229         isc_boolean_t result = ISC_FALSE;
1230
1231         LOCK(&adb->reflock);
1232
1233         INSIST(adb->irefcnt > 0);
1234         adb->irefcnt--;
1235
1236         if (adb->irefcnt == 0) {
1237                 event = ISC_LIST_HEAD(adb->whenshutdown);
1238                 while (event != NULL) {
1239                         ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
1240                         etask = event->ev_sender;
1241                         event->ev_sender = adb;
1242                         isc_task_sendanddetach(&etask, &event);
1243                         event = ISC_LIST_HEAD(adb->whenshutdown);
1244                 }
1245         }
1246
1247         if (adb->irefcnt == 0 && adb->erefcnt == 0)
1248                 result = ISC_TRUE;
1249         UNLOCK(&adb->reflock);
1250         return (result);
1251 }
1252
1253 static inline void
1254 inc_adb_irefcnt(dns_adb_t *adb) {
1255         LOCK(&adb->reflock);
1256         adb->irefcnt++;
1257         UNLOCK(&adb->reflock);
1258 }
1259
1260 static inline void
1261 inc_adb_erefcnt(dns_adb_t *adb) {
1262         LOCK(&adb->reflock);
1263         adb->erefcnt++;
1264         UNLOCK(&adb->reflock);
1265 }
1266
1267 static inline void
1268 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1269         int bucket;
1270
1271         bucket = entry->lock_bucket;
1272
1273         if (lock)
1274                 LOCK(&adb->entrylocks[bucket]);
1275
1276         entry->refcnt++;
1277
1278         if (lock)
1279                 UNLOCK(&adb->entrylocks[bucket]);
1280 }
1281
1282 static inline isc_boolean_t
1283 dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
1284         int bucket;
1285         isc_boolean_t destroy_entry;
1286         isc_boolean_t result = ISC_FALSE;
1287
1288         bucket = entry->lock_bucket;
1289
1290         if (lock)
1291                 LOCK(&adb->entrylocks[bucket]);
1292
1293         INSIST(entry->refcnt > 0);
1294         entry->refcnt--;
1295
1296         destroy_entry = ISC_FALSE;
1297         if (entry->refcnt == 0 &&
1298             (adb->entry_sd[bucket] || entry->expires == 0)) {
1299                 destroy_entry = ISC_TRUE;
1300                 result = unlink_entry(adb, entry);
1301         }
1302
1303         if (lock)
1304                 UNLOCK(&adb->entrylocks[bucket]);
1305
1306         if (!destroy_entry)
1307                 return (result);
1308
1309         entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
1310
1311         free_adbentry(adb, &entry);
1312         if (result)
1313                 result =dec_adb_irefcnt(adb);
1314         
1315         return (result);
1316 }
1317
1318 static inline dns_adbname_t *
1319 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
1320         dns_adbname_t *name;
1321
1322         name = isc_mempool_get(adb->nmp);
1323         if (name == NULL)
1324                 return (NULL);
1325
1326         dns_name_init(&name->name, NULL);
1327         if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
1328                 isc_mempool_put(adb->nmp, name);
1329                 return (NULL);
1330         }
1331         dns_name_init(&name->target, NULL);
1332         name->magic = DNS_ADBNAME_MAGIC;
1333         name->adb = adb;
1334         name->partial_result = 0;
1335         name->flags = 0;
1336         name->expire_v4 = INT_MAX;
1337         name->expire_v6 = INT_MAX;
1338         name->expire_target = INT_MAX;
1339         name->chains = 0;
1340         name->lock_bucket = DNS_ADB_INVALIDBUCKET;
1341         ISC_LIST_INIT(name->v4);
1342         ISC_LIST_INIT(name->v6);
1343         name->fetch_a = NULL;
1344         name->fetch_aaaa = NULL;
1345         ISC_LIST_INIT(name->fetches_a6);
1346         name->fetch_err = FIND_ERR_UNEXPECTED;
1347         name->fetch6_err = FIND_ERR_UNEXPECTED;
1348         ISC_LIST_INIT(name->finds);
1349         ISC_LINK_INIT(name, plink);
1350
1351         return (name);
1352 }
1353
1354 static inline void
1355 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
1356         dns_adbname_t *n;
1357
1358         INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
1359         n = *name;
1360         *name = NULL;
1361
1362         INSIST(!NAME_HAS_V4(n));
1363         INSIST(!NAME_HAS_V6(n));
1364         INSIST(!NAME_FETCH(n));
1365         INSIST(ISC_LIST_EMPTY(n->finds));
1366         INSIST(!ISC_LINK_LINKED(n, plink));
1367         INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
1368         INSIST(n->adb == adb);
1369
1370         n->magic = 0;
1371         dns_name_free(&n->name, adb->mctx);
1372
1373         isc_mempool_put(adb->nmp, n);
1374 }
1375
1376 static inline dns_adbnamehook_t *
1377 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
1378         dns_adbnamehook_t *nh;
1379
1380         nh = isc_mempool_get(adb->nhmp);
1381         if (nh == NULL)
1382                 return (NULL);
1383
1384         nh->magic = DNS_ADBNAMEHOOK_MAGIC;
1385         nh->entry = entry;
1386         ISC_LINK_INIT(nh, plink);
1387
1388         return (nh);
1389 }
1390
1391 static inline void
1392 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
1393         dns_adbnamehook_t *nh;
1394
1395         INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
1396         nh = *namehook;
1397         *namehook = NULL;
1398
1399         INSIST(nh->entry == NULL);
1400         INSIST(!ISC_LINK_LINKED(nh, plink));
1401
1402         nh->magic = 0;
1403         isc_mempool_put(adb->nhmp, nh);
1404 }
1405
1406 static inline dns_adbzoneinfo_t *
1407 new_adbzoneinfo(dns_adb_t *adb, dns_name_t *zone) {
1408         dns_adbzoneinfo_t *zi;
1409
1410         zi = isc_mempool_get(adb->zimp);
1411         if (zi == NULL)
1412                 return (NULL);
1413
1414         dns_name_init(&zi->zone, NULL);
1415         if (dns_name_dup(zone, adb->mctx, &zi->zone) != ISC_R_SUCCESS) {
1416                 isc_mempool_put(adb->zimp, zi);
1417                 return (NULL);
1418         }
1419
1420         zi->magic = DNS_ADBZONEINFO_MAGIC;
1421         zi->lame_timer = 0;
1422         ISC_LINK_INIT(zi, plink);
1423
1424         return (zi);
1425 }
1426
1427 static inline void
1428 free_adbzoneinfo(dns_adb_t *adb, dns_adbzoneinfo_t **zoneinfo) {
1429         dns_adbzoneinfo_t *zi;
1430
1431         INSIST(zoneinfo != NULL && DNS_ADBZONEINFO_VALID(*zoneinfo));
1432         zi = *zoneinfo;
1433         *zoneinfo = NULL;
1434
1435         INSIST(!ISC_LINK_LINKED(zi, plink));
1436
1437         dns_name_free(&zi->zone, adb->mctx);
1438
1439         zi->magic = 0;
1440
1441         isc_mempool_put(adb->zimp, zi);
1442 }
1443
1444 static inline dns_adbentry_t *
1445 new_adbentry(dns_adb_t *adb) {
1446         dns_adbentry_t *e;
1447         isc_uint32_t r;
1448
1449         e = isc_mempool_get(adb->emp);
1450         if (e == NULL)
1451                 return (NULL);
1452
1453         e->magic = DNS_ADBENTRY_MAGIC;
1454         e->lock_bucket = DNS_ADB_INVALIDBUCKET;
1455         e->refcnt = 0;
1456         e->flags = 0;
1457         isc_random_get(&r);
1458         e->srtt = (r & 0x1f) + 1;
1459         e->expires = 0;
1460         ISC_LIST_INIT(e->zoneinfo);
1461         ISC_LINK_INIT(e, plink);
1462
1463         return (e);
1464 }
1465
1466 static inline void
1467 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
1468         dns_adbentry_t *e;
1469         dns_adbzoneinfo_t *zi;
1470
1471         INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
1472         e = *entry;
1473         *entry = NULL;
1474
1475         INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
1476         INSIST(e->refcnt == 0);
1477         INSIST(!ISC_LINK_LINKED(e, plink));
1478
1479         e->magic = 0;
1480
1481         zi = ISC_LIST_HEAD(e->zoneinfo);
1482         while (zi != NULL) {
1483                 ISC_LIST_UNLINK(e->zoneinfo, zi, plink);
1484                 free_adbzoneinfo(adb, &zi);
1485                 zi = ISC_LIST_HEAD(e->zoneinfo);
1486         }
1487
1488         isc_mempool_put(adb->emp, e);
1489 }
1490
1491 static inline dns_adbfind_t *
1492 new_adbfind(dns_adb_t *adb) {
1493         dns_adbfind_t *h;
1494         isc_result_t result;
1495
1496         h = isc_mempool_get(adb->ahmp);
1497         if (h == NULL)
1498                 return (NULL);
1499
1500         /*
1501          * Public members.
1502          */
1503         h->magic = 0;
1504         h->adb = adb;
1505         h->partial_result = 0;
1506         h->options = 0;
1507         h->flags = 0;
1508         h->result_v4 = ISC_R_UNEXPECTED;
1509         h->result_v6 = ISC_R_UNEXPECTED;
1510         ISC_LINK_INIT(h, publink);
1511         ISC_LINK_INIT(h, plink);
1512         ISC_LIST_INIT(h->list);
1513         h->adbname = NULL;
1514         h->name_bucket = DNS_ADB_INVALIDBUCKET;
1515
1516         /*
1517          * private members
1518          */
1519         result = isc_mutex_init(&h->lock);
1520         if (result != ISC_R_SUCCESS) {
1521                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1522                                  "isc_mutex_init failed in new_adbfind()");
1523                 isc_mempool_put(adb->ahmp, h);
1524                 return (NULL);
1525         }
1526
1527         ISC_EVENT_INIT(&h->event, sizeof (isc_event_t), 0, 0, 0, NULL, NULL,
1528                        NULL, NULL, h);
1529
1530         inc_adb_irefcnt(adb);
1531         h->magic = DNS_ADBFIND_MAGIC;
1532         return (h);
1533 }
1534
1535 static inline dns_adbfetch_t *
1536 new_adbfetch(dns_adb_t *adb) {
1537         dns_adbfetch_t *f;
1538
1539         f = isc_mempool_get(adb->afmp);
1540         if (f == NULL)
1541                 return (NULL);
1542
1543         f->magic = 0;
1544         f->namehook = NULL;
1545         f->entry = NULL;
1546         f->fetch = NULL;
1547
1548         f->namehook = new_adbnamehook(adb, NULL);
1549         if (f->namehook == NULL)
1550                 goto err;
1551
1552         f->entry = new_adbentry(adb);
1553         if (f->entry == NULL)
1554                 goto err;
1555
1556         dns_rdataset_init(&f->rdataset);
1557
1558         f->magic = DNS_ADBFETCH_MAGIC;
1559
1560         return (f);
1561
1562  err:
1563         if (f->namehook != NULL)
1564                 free_adbnamehook(adb, &f->namehook);
1565         if (f->entry != NULL)
1566                 free_adbentry(adb, &f->entry);
1567         isc_mempool_put(adb->afmp, f);
1568         return (NULL);
1569 }
1570
1571 static inline void
1572 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
1573         dns_adbfetch_t *f;
1574
1575         INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
1576         f = *fetch;
1577         *fetch = NULL;
1578
1579         f->magic = 0;
1580
1581         if (f->namehook != NULL)
1582                 free_adbnamehook(adb, &f->namehook);
1583         if (f->entry != NULL)
1584                 free_adbentry(adb, &f->entry);
1585
1586         if (dns_rdataset_isassociated(&f->rdataset))
1587                 dns_rdataset_disassociate(&f->rdataset);
1588
1589         isc_mempool_put(adb->afmp, f);
1590 }
1591
1592 /*
1593  * Caller must be holding the name lock.
1594  */
1595 static isc_result_t
1596 a6find(void *arg, dns_name_t *a6name, dns_rdatatype_t type, isc_stdtime_t now,
1597        dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
1598 {
1599         dns_adbname_t *name;
1600         dns_adb_t *adb;
1601         isc_result_t result;
1602
1603         name = arg;
1604         INSIST(DNS_ADBNAME_VALID(name));
1605         adb = name->adb;
1606         INSIST(DNS_ADB_VALID(adb));
1607
1608         result = dns_view_simplefind(adb->view, a6name, type, now,
1609                                      DNS_DBFIND_GLUEOK, ISC_FALSE,
1610                                      rdataset, sigrdataset);
1611         if (result == DNS_R_GLUE)
1612                 result = ISC_R_SUCCESS;
1613         return (result);
1614 }
1615
1616 /*
1617  * Caller must be holding the name lock.
1618  */
1619 static void
1620 a6missing(dns_a6context_t *a6ctx, dns_name_t *a6name) {
1621         dns_adbname_t *name;
1622         dns_adb_t *adb;
1623         dns_adbfetch6_t *fetch;
1624         isc_result_t result;
1625
1626         name = a6ctx->arg;
1627         INSIST(DNS_ADBNAME_VALID(name));
1628         adb = name->adb;
1629         INSIST(DNS_ADB_VALID(adb));
1630
1631         fetch = new_adbfetch6(adb, name, a6ctx);
1632         if (fetch == NULL) {
1633                 name->partial_result |= DNS_ADBFIND_INET6;
1634                 return;
1635         }
1636
1637         result = dns_resolver_createfetch(adb->view->resolver, a6name,
1638                                           dns_rdatatype_a6,
1639                                           NULL, NULL, NULL, 0,
1640                                           adb->task, fetch_callback_a6,
1641                                           name, &fetch->rdataset, NULL,
1642                                           &fetch->fetch);
1643         if (result != ISC_R_SUCCESS)
1644                 goto cleanup;
1645
1646         name->chains = a6ctx->chains;
1647         ISC_LIST_APPEND(name->fetches_a6, fetch, plink);
1648
1649  cleanup:
1650         if (result != ISC_R_SUCCESS) {
1651                 free_adbfetch6(adb, &fetch);
1652                 name->partial_result |= DNS_ADBFIND_INET6;
1653         }
1654 }
1655
1656 static inline dns_adbfetch6_t *
1657 new_adbfetch6(dns_adb_t *adb, dns_adbname_t *name, dns_a6context_t *a6ctx) {
1658         dns_adbfetch6_t *f;
1659
1660         f = isc_mempool_get(adb->af6mp);
1661         if (f == NULL)
1662                 return (NULL);
1663
1664         f->magic = 0;
1665         f->namehook = NULL;
1666         f->entry = NULL;
1667         f->fetch = NULL;
1668         f->flags = 0;
1669
1670         f->namehook = new_adbnamehook(adb, NULL);
1671         if (f->namehook == NULL)
1672                 goto err;
1673
1674         f->entry = new_adbentry(adb);
1675         if (f->entry == NULL)
1676                 goto err;
1677
1678         dns_rdataset_init(&f->rdataset);
1679
1680         dns_a6_init(&f->a6ctx, a6find, NULL, import_a6,
1681                     a6missing, name);
1682         if (a6ctx != NULL)
1683                 dns_a6_copy(a6ctx, &f->a6ctx);
1684
1685         ISC_LINK_INIT(f, plink);
1686         f->magic = DNS_ADBFETCH6_MAGIC;
1687
1688         return (f);
1689
1690  err:
1691         if (f->namehook != NULL)
1692                 free_adbnamehook(adb, &f->namehook);
1693         if (f->entry != NULL)
1694                 free_adbentry(adb, &f->entry);
1695         isc_mempool_put(adb->af6mp, f);
1696         return (NULL);
1697 }
1698
1699 static inline void
1700 free_adbfetch6(dns_adb_t *adb, dns_adbfetch6_t **fetch) {
1701         dns_adbfetch6_t *f;
1702
1703         INSIST(fetch != NULL && DNS_ADBFETCH6_VALID(*fetch));
1704         f = *fetch;
1705         *fetch = NULL;
1706
1707         f->magic = 0;
1708
1709         if (f->namehook != NULL)
1710                 free_adbnamehook(adb, &f->namehook);
1711         if (f->entry != NULL)
1712                 free_adbentry(adb, &f->entry);
1713
1714         if (dns_rdataset_isassociated(&f->rdataset))
1715                 dns_rdataset_disassociate(&f->rdataset);
1716
1717         isc_mempool_put(adb->af6mp, f);
1718 }
1719
1720 static inline isc_boolean_t
1721 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
1722         dns_adbfind_t *find;
1723
1724         INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
1725         find = *findp;
1726         *findp = NULL;
1727
1728         INSIST(!FIND_HAS_ADDRS(find));
1729         INSIST(!ISC_LINK_LINKED(find, publink));
1730         INSIST(!ISC_LINK_LINKED(find, plink));
1731         INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
1732         INSIST(find->adbname == NULL);
1733
1734         find->magic = 0;
1735
1736         DESTROYLOCK(&find->lock);
1737         isc_mempool_put(adb->ahmp, find);
1738         return (dec_adb_irefcnt(adb));
1739 }
1740
1741 /*
1742  * Copy bits from the entry into the newly allocated addrinfo.  The entry
1743  * must be locked, and the reference count must be bumped up by one
1744  * if this function returns a valid pointer.
1745  */
1746 static inline dns_adbaddrinfo_t *
1747 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
1748         dns_adbaddrinfo_t *ai;
1749
1750         ai = isc_mempool_get(adb->aimp);
1751         if (ai == NULL)
1752                 return (NULL);
1753
1754         ai->magic = DNS_ADBADDRINFO_MAGIC;
1755         ai->sockaddr = entry->sockaddr;
1756         isc_sockaddr_setport(&ai->sockaddr, port);
1757         ai->srtt = entry->srtt;
1758         ai->flags = entry->flags;
1759         ai->entry = entry;
1760         ISC_LINK_INIT(ai, publink);
1761
1762         return (ai);
1763 }
1764
1765 static inline void
1766 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
1767         dns_adbaddrinfo_t *ai;
1768
1769         INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
1770         ai = *ainfo;
1771         *ainfo = NULL;
1772
1773         INSIST(ai->entry == NULL);
1774         INSIST(!ISC_LINK_LINKED(ai, publink));
1775
1776         ai->magic = 0;
1777
1778         isc_mempool_put(adb->aimp, ai);
1779 }
1780
1781 /*
1782  * Search for the name.  NOTE:  The bucket is kept locked on both
1783  * success and failure, so it must always be unlocked by the caller!
1784  *
1785  * On the first call to this function, *bucketp must be set to
1786  * DNS_ADB_INVALIDBUCKET.
1787  */
1788 static inline dns_adbname_t *
1789 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
1790                    unsigned int options, int *bucketp)
1791 {
1792         dns_adbname_t *adbname;
1793         int bucket;
1794
1795         bucket = dns_fullname_hash(name, ISC_FALSE) % NBUCKETS;
1796
1797         if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1798                 LOCK(&adb->namelocks[bucket]);
1799                 *bucketp = bucket;
1800         } else if (*bucketp != bucket) {
1801                 UNLOCK(&adb->namelocks[*bucketp]);
1802                 LOCK(&adb->namelocks[bucket]);
1803                 *bucketp = bucket;
1804         }
1805
1806         adbname = ISC_LIST_HEAD(adb->names[bucket]);
1807         while (adbname != NULL) {
1808                 if (!NAME_DEAD(adbname)) {
1809                         if (dns_name_equal(name, &adbname->name)
1810                             && GLUEHINT_OK(adbname, options)
1811                             && STARTATZONE_MATCHES(adbname, options))
1812                                 return (adbname);
1813                 }
1814                 adbname = ISC_LIST_NEXT(adbname, plink);
1815         }
1816
1817         return (NULL);
1818 }
1819
1820 /*
1821  * Search for the address.  NOTE:  The bucket is kept locked on both
1822  * success and failure, so it must always be unlocked by the caller.
1823  *
1824  * On the first call to this function, *bucketp must be set to
1825  * DNS_ADB_INVALIDBUCKET.  This will cause a lock to occur.  On
1826  * later calls (within the same "lock path") it can be left alone, so
1827  * if this function is called multiple times locking is only done if
1828  * the bucket changes.
1829  */
1830 static inline dns_adbentry_t *
1831 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) {
1832         dns_adbentry_t *entry;
1833         int bucket;
1834
1835         bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
1836
1837         if (*bucketp == DNS_ADB_INVALIDBUCKET) {
1838                 LOCK(&adb->entrylocks[bucket]);
1839                 *bucketp = bucket;
1840         } else if (*bucketp != bucket) {
1841                 UNLOCK(&adb->entrylocks[*bucketp]);
1842                 LOCK(&adb->entrylocks[bucket]);
1843                 *bucketp = bucket;
1844         }
1845
1846         entry = ISC_LIST_HEAD(adb->entries[bucket]);
1847         while (entry != NULL) {
1848                 if (isc_sockaddr_equal(addr, &entry->sockaddr))
1849                         return (entry);
1850                 entry = ISC_LIST_NEXT(entry, plink);
1851         }
1852
1853         return (NULL);
1854 }
1855
1856 /*
1857  * Entry bucket MUST be locked!
1858  */
1859 static isc_boolean_t
1860 entry_is_bad_for_zone(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *zone,
1861                       isc_stdtime_t now)
1862 {
1863         dns_adbzoneinfo_t *zi, *next_zi;
1864         isc_boolean_t is_bad;
1865
1866         is_bad = ISC_FALSE;
1867
1868         zi = ISC_LIST_HEAD(entry->zoneinfo);
1869         if (zi == NULL)
1870                 return (ISC_FALSE);
1871         while (zi != NULL) {
1872                 next_zi = ISC_LIST_NEXT(zi, plink);
1873
1874                 /*
1875                  * Has the entry expired?
1876                  */
1877                 if (zi->lame_timer < now) {
1878                         ISC_LIST_UNLINK(entry->zoneinfo, zi, plink);
1879                         free_adbzoneinfo(adb, &zi);
1880                 }
1881
1882                 /*
1883                  * Order tests from least to most expensive.
1884                  */
1885                 if (zi != NULL && !is_bad) {
1886                         if (dns_name_equal(zone, &zi->zone))
1887                                 is_bad = ISC_TRUE;
1888                 }
1889
1890                 zi = next_zi;
1891         }
1892
1893         return (is_bad);
1894 }
1895
1896 static void
1897 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *zone,
1898                     dns_adbname_t *name, isc_stdtime_t now)
1899 {
1900         dns_adbnamehook_t *namehook;
1901         dns_adbaddrinfo_t *addrinfo;
1902         dns_adbentry_t *entry;
1903         int bucket;
1904
1905         bucket = DNS_ADB_INVALIDBUCKET;
1906
1907         if (find->options & DNS_ADBFIND_INET) {
1908                 namehook = ISC_LIST_HEAD(name->v4);
1909                 while (namehook != NULL) {
1910                         entry = namehook->entry;
1911                         bucket = entry->lock_bucket;
1912                         LOCK(&adb->entrylocks[bucket]);
1913
1914                         if (!FIND_RETURNLAME(find)
1915                             && entry_is_bad_for_zone(adb, entry, zone, now)) {
1916                                 find->options |= DNS_ADBFIND_LAMEPRUNED;
1917                                 goto nextv4;
1918                         }
1919                         addrinfo = new_adbaddrinfo(adb, entry, find->port);
1920                         if (addrinfo == NULL) {
1921                                 find->partial_result |= DNS_ADBFIND_INET;
1922                                 goto out;
1923                         }
1924                         /*
1925                          * Found a valid entry.  Add it to the find's list.
1926                          */
1927                         inc_entry_refcnt(adb, entry, ISC_FALSE);
1928                         ISC_LIST_APPEND(find->list, addrinfo, publink);
1929                         addrinfo = NULL;
1930                 nextv4:
1931                         UNLOCK(&adb->entrylocks[bucket]);
1932                         bucket = DNS_ADB_INVALIDBUCKET;
1933                         namehook = ISC_LIST_NEXT(namehook, plink);
1934                 }
1935         }
1936
1937         if (find->options & DNS_ADBFIND_INET6) {
1938                 namehook = ISC_LIST_HEAD(name->v6);
1939                 while (namehook != NULL) {
1940                         entry = namehook->entry;
1941                         bucket = entry->lock_bucket;
1942                         LOCK(&adb->entrylocks[bucket]);
1943
1944                         if (entry_is_bad_for_zone(adb, entry, zone, now))
1945                                 goto nextv6;
1946                         addrinfo = new_adbaddrinfo(adb, entry, find->port);
1947                         if (addrinfo == NULL) {
1948                                 find->partial_result |= DNS_ADBFIND_INET6;
1949                                 goto out;
1950                         }
1951                         /*
1952                          * Found a valid entry.  Add it to the find's list.
1953                          */
1954                         inc_entry_refcnt(adb, entry, ISC_FALSE);
1955                         ISC_LIST_APPEND(find->list, addrinfo, publink);
1956                         addrinfo = NULL;
1957                 nextv6:
1958                         UNLOCK(&adb->entrylocks[bucket]);
1959                         bucket = DNS_ADB_INVALIDBUCKET;
1960                         namehook = ISC_LIST_NEXT(namehook, plink);
1961                 }
1962         }
1963
1964  out:
1965         if (bucket != DNS_ADB_INVALIDBUCKET)
1966                 UNLOCK(&adb->entrylocks[bucket]);
1967 }
1968
1969 static void
1970 shutdown_task(isc_task_t *task, isc_event_t *ev) {
1971         dns_adb_t *adb;
1972
1973         UNUSED(task);
1974
1975         adb = ev->ev_arg;
1976         INSIST(DNS_ADB_VALID(adb));
1977
1978         /*
1979          * Kill the timer, and then the ADB itself.  Note that this implies
1980          * that this task was the one scheduled to get timer events.  If
1981          * this is not true (and it is unfortunate there is no way to INSIST()
1982          * this) badness will occur.
1983          */
1984         LOCK(&adb->lock);
1985         isc_timer_detach(&adb->timer);
1986         UNLOCK(&adb->lock);
1987         isc_event_free(&ev);
1988         destroy(adb);
1989 }
1990
1991 /*
1992  * name bucket must be locked; adb may be locked; no other locks held.
1993  */
1994 static isc_boolean_t
1995 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
1996         dns_adbname_t *name;
1997         isc_result_t result = ISC_FALSE;
1998
1999         INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
2000         name = *namep;
2001
2002         if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
2003                 return (result);
2004         if (NAME_FETCH(name))
2005                 return (result);
2006         if (!EXPIRE_OK(name->expire_v4, now))
2007                 return (result);
2008         if (!EXPIRE_OK(name->expire_v6, now))
2009                 return (result);
2010         if (!EXPIRE_OK(name->expire_target, now))
2011                 return (result);
2012
2013         /*
2014          * The name is empty.  Delete it.
2015          */
2016         result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
2017         *namep = NULL;
2018
2019         /*
2020          * Our caller, or one of its callers, will be calling check_exit() at
2021          * some point, so we don't need to do it here.
2022          */
2023         return (result);
2024 }
2025
2026 /*
2027  * entry bucket must be locked; adb may be locked; no other locks held.
2028  */
2029 static isc_boolean_t
2030 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
2031 {
2032         dns_adbentry_t *entry;
2033         isc_boolean_t result = ISC_FALSE;
2034
2035         INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
2036         entry = *entryp;
2037
2038         if (entry->refcnt != 0)
2039                 return (result);
2040         if (entry->expires == 0 || entry->expires > now)
2041                 return (result);
2042
2043         /*
2044          * The entry is not in use.  Delete it.
2045          */
2046         DP(DEF_LEVEL, "killing entry %p", entry);
2047         INSIST(ISC_LINK_LINKED(entry, plink));
2048         result = unlink_entry(adb, entry);
2049         free_adbentry(adb, &entry);
2050         if (result)
2051                 dec_adb_irefcnt(adb);
2052         *entryp = NULL;
2053         return (result);
2054 }
2055
2056 /*
2057  * ADB must be locked, and no other locks held.
2058  */
2059 static isc_boolean_t
2060 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2061         dns_adbname_t *name;
2062         dns_adbname_t *next_name;
2063         isc_result_t result = ISC_FALSE;
2064
2065         DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
2066
2067         LOCK(&adb->namelocks[bucket]);
2068         if (adb->name_sd[bucket]) {
2069                 UNLOCK(&adb->namelocks[bucket]);
2070                 return (result);
2071         }
2072
2073         name = ISC_LIST_HEAD(adb->names[bucket]);
2074         while (name != NULL) {
2075                 next_name = ISC_LIST_NEXT(name, plink);
2076                 INSIST(result == ISC_FALSE);
2077                 result = check_expire_namehooks(name, now);
2078                 if (!result)
2079                         result = check_expire_name(&name, now);
2080                 name = next_name;
2081         }
2082         UNLOCK(&adb->namelocks[bucket]);
2083         return (result);
2084 }
2085
2086 /*
2087  * ADB must be locked, and no other locks held.
2088  */
2089 static isc_boolean_t
2090 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
2091         dns_adbentry_t *entry, *next_entry;
2092         isc_boolean_t result = ISC_FALSE;
2093
2094         DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
2095
2096         LOCK(&adb->entrylocks[bucket]);
2097         entry = ISC_LIST_HEAD(adb->entries[bucket]);
2098         while (entry != NULL) {
2099                 next_entry = ISC_LIST_NEXT(entry, plink);
2100                 INSIST(result == ISC_FALSE);
2101                 result = check_expire_entry(adb, &entry, now);
2102                 entry = next_entry;
2103         }
2104         UNLOCK(&adb->entrylocks[bucket]);
2105         return (result);
2106 }
2107
2108 static void
2109 timer_cleanup(isc_task_t *task, isc_event_t *ev) {
2110         dns_adb_t *adb;
2111         isc_stdtime_t now;
2112         unsigned int i;
2113
2114         UNUSED(task);
2115
2116         adb = ev->ev_arg;
2117         INSIST(DNS_ADB_VALID(adb));
2118
2119         LOCK(&adb->lock);
2120
2121         isc_stdtime_get(&now);
2122
2123         for (i = 0 ; i < CLEAN_BUCKETS ; i++) {
2124                 /*
2125                  * Call our cleanup routines.
2126                  */
2127                 RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) ==
2128                               ISC_FALSE);
2129                 RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now)
2130                               == ISC_FALSE);
2131
2132                 /*
2133                  * Set the next bucket to be cleaned.
2134                  */
2135                 adb->next_cleanbucket++;
2136                 if (adb->next_cleanbucket >= NBUCKETS) {
2137                         adb->next_cleanbucket = 0;
2138 #ifdef DUMP_ADB_AFTER_CLEANING
2139                         dump_adb(adb, stdout, ISC_TRUE);
2140 #endif
2141                 }
2142         }
2143
2144         /*
2145          * Reset the timer.
2146          * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
2147          * ISC_R_NOMEMORY, but it isn't clear what could be done here
2148          * if either one of those things happened.
2149          */
2150         (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
2151                               &adb->tick_interval, ISC_FALSE);
2152
2153         UNLOCK(&adb->lock);
2154
2155         isc_event_free(&ev);
2156 }
2157
2158 static void
2159 destroy(dns_adb_t *adb) {
2160         adb->magic = 0;
2161
2162         /*
2163          * The timer is already dead, from the task's shutdown callback.
2164          */
2165         isc_task_detach(&adb->task);
2166
2167         isc_mempool_destroy(&adb->nmp);
2168         isc_mempool_destroy(&adb->nhmp);
2169         isc_mempool_destroy(&adb->zimp);
2170         isc_mempool_destroy(&adb->emp);
2171         isc_mempool_destroy(&adb->ahmp);
2172         isc_mempool_destroy(&adb->aimp);
2173         isc_mempool_destroy(&adb->afmp);
2174         isc_mempool_destroy(&adb->af6mp);
2175
2176         isc_mutexblock_destroy(adb->entrylocks, NBUCKETS);
2177         isc_mutexblock_destroy(adb->namelocks, NBUCKETS);
2178
2179         DESTROYLOCK(&adb->reflock);
2180         DESTROYLOCK(&adb->lock);
2181         DESTROYLOCK(&adb->mplock);
2182
2183         isc_mem_put(adb->mctx, adb, sizeof (dns_adb_t));
2184 }
2185
2186
2187 /*
2188  * Public functions.
2189  */
2190
2191 isc_result_t
2192 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
2193                isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
2194 {
2195         dns_adb_t *adb;
2196         isc_result_t result;
2197         int i;
2198
2199         REQUIRE(mem != NULL);
2200         REQUIRE(view != NULL);
2201         REQUIRE(timermgr != NULL);
2202         REQUIRE(taskmgr != NULL);
2203         REQUIRE(newadb != NULL && *newadb == NULL);
2204
2205         adb = isc_mem_get(mem, sizeof (dns_adb_t));
2206         if (adb == NULL)
2207                 return (ISC_R_NOMEMORY);
2208
2209         /*
2210          * Initialize things here that cannot fail, and especially things
2211          * that must be NULL for the error return to work properly.
2212          */
2213         adb->magic = 0;
2214         adb->erefcnt = 1;
2215         adb->irefcnt = 0;
2216         adb->nmp = NULL;
2217         adb->nhmp = NULL;
2218         adb->zimp = NULL;
2219         adb->emp = NULL;
2220         adb->ahmp = NULL;
2221         adb->aimp = NULL;
2222         adb->afmp = NULL;
2223         adb->af6mp = NULL;
2224         adb->task = NULL;
2225         adb->timer = NULL;
2226         adb->mctx = mem;
2227         adb->view = view;
2228         adb->timermgr = timermgr;
2229         adb->taskmgr = taskmgr;
2230         adb->next_cleanbucket = 0;
2231         ISC_EVENT_INIT(&adb->cevent, sizeof adb->cevent, 0, NULL,
2232                        DNS_EVENT_ADBCONTROL, shutdown_task, adb,
2233                        adb, NULL, NULL);
2234         adb->cevent_sent = ISC_FALSE;
2235         adb->shutting_down = ISC_FALSE;
2236         ISC_LIST_INIT(adb->whenshutdown);
2237
2238         result = isc_mutex_init(&adb->lock);
2239         if (result != ISC_R_SUCCESS)
2240                 goto fail0b;
2241
2242         result = isc_mutex_init(&adb->mplock);
2243         if (result != ISC_R_SUCCESS)
2244                 goto fail0c;
2245
2246         result = isc_mutex_init(&adb->reflock);
2247         if (result != ISC_R_SUCCESS)
2248                 goto fail0d;
2249
2250         /*
2251          * Initialize the bucket locks for names and elements.
2252          * May as well initialize the list heads, too.
2253          */
2254         result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
2255         if (result != ISC_R_SUCCESS)
2256                 goto fail1;
2257         for (i = 0 ; i < NBUCKETS ; i++) {
2258                 ISC_LIST_INIT(adb->names[i]);
2259                 adb->name_sd[i] = ISC_FALSE;
2260                 adb->name_refcnt[i] = 0;
2261                 adb->irefcnt++;
2262         }
2263         for (i = 0 ; i < NBUCKETS ; i++) {
2264                 ISC_LIST_INIT(adb->entries[i]);
2265                 adb->entry_sd[i] = ISC_FALSE;
2266                 adb->entry_refcnt[i] = 0;
2267                 adb->irefcnt++;
2268         }
2269         result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
2270         if (result != ISC_R_SUCCESS)
2271                 goto fail2;
2272
2273         /*
2274          * Memory pools
2275          */
2276 #define MPINIT(t, p, n) do { \
2277         result = isc_mempool_create(mem, sizeof (t), &(p)); \
2278         if (result != ISC_R_SUCCESS) \
2279                 goto fail3; \
2280         isc_mempool_setfreemax((p), FREE_ITEMS); \
2281         isc_mempool_setfillcount((p), FILL_COUNT); \
2282         isc_mempool_setname((p), n); \
2283         isc_mempool_associatelock((p), &adb->mplock); \
2284 } while (0)
2285
2286         MPINIT(dns_adbname_t, adb->nmp, "adbname");
2287         MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
2288         MPINIT(dns_adbzoneinfo_t, adb->zimp, "adbzoneinfo");
2289         MPINIT(dns_adbentry_t, adb->emp, "adbentry");
2290         MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
2291         MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
2292         MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
2293         MPINIT(dns_adbfetch6_t, adb->af6mp, "adbfetch6");
2294
2295 #undef MPINIT
2296
2297         /*
2298          * Allocate a timer and a task for our periodic cleanup.
2299          */
2300         result = isc_task_create(adb->taskmgr, 0, &adb->task);
2301         if (result != ISC_R_SUCCESS)
2302                 goto fail3;
2303         isc_task_setname(adb->task, "ADB", adb);
2304         /*
2305          * XXXMLG When this is changed to be a config file option,
2306          */
2307         isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
2308         result = isc_timer_create(adb->timermgr, isc_timertype_once,
2309                                   NULL, &adb->tick_interval, adb->task,
2310                                   timer_cleanup, adb, &adb->timer);
2311         if (result != ISC_R_SUCCESS)
2312                 goto fail3;
2313
2314         DP(5,
2315            "Cleaning interval for adb:  "
2316            "%u buckets every %u seconds, %u buckets in system, %u cl.interval",
2317            CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
2318
2319         /*
2320          * Normal return.
2321          */
2322         adb->magic = DNS_ADB_MAGIC;
2323         *newadb = adb;
2324         return (ISC_R_SUCCESS);
2325
2326  fail3:
2327         if (adb->task != NULL)
2328                 isc_task_detach(&adb->task);
2329         if (adb->timer != NULL)
2330                 isc_timer_detach(&adb->timer);
2331
2332         /* clean up entrylocks */
2333         isc_mutexblock_destroy(adb->entrylocks, NBUCKETS);
2334
2335  fail2: /* clean up namelocks */
2336         isc_mutexblock_destroy(adb->namelocks, NBUCKETS);
2337
2338  fail1: /* clean up only allocated memory */
2339         if (adb->nmp != NULL)
2340                 isc_mempool_destroy(&adb->nmp);
2341         if (adb->nhmp != NULL)
2342                 isc_mempool_destroy(&adb->nhmp);
2343         if (adb->zimp != NULL)
2344                 isc_mempool_destroy(&adb->zimp);
2345         if (adb->emp != NULL)
2346                 isc_mempool_destroy(&adb->emp);
2347         if (adb->ahmp != NULL)
2348                 isc_mempool_destroy(&adb->ahmp);
2349         if (adb->aimp != NULL)
2350                 isc_mempool_destroy(&adb->aimp);
2351         if (adb->afmp != NULL)
2352                 isc_mempool_destroy(&adb->afmp);
2353         if (adb->af6mp != NULL)
2354                 isc_mempool_destroy(&adb->af6mp);
2355
2356         DESTROYLOCK(&adb->reflock);
2357  fail0d:
2358         DESTROYLOCK(&adb->mplock);
2359  fail0c:
2360         DESTROYLOCK(&adb->lock);
2361  fail0b:
2362         isc_mem_put(mem, adb, sizeof (dns_adb_t));
2363
2364         return (result);
2365 }
2366
2367 void
2368 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
2369
2370         REQUIRE(DNS_ADB_VALID(adb));
2371         REQUIRE(adbx != NULL && *adbx == NULL);
2372
2373         inc_adb_erefcnt(adb);
2374         *adbx = adb;
2375 }
2376
2377 void
2378 dns_adb_detach(dns_adb_t **adbx) {
2379         dns_adb_t *adb;
2380         isc_boolean_t need_exit_check;
2381
2382         REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
2383
2384         adb = *adbx;
2385         *adbx = NULL;
2386
2387         INSIST(adb->erefcnt > 0);
2388
2389         LOCK(&adb->reflock);
2390         adb->erefcnt--;
2391         need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
2392         UNLOCK(&adb->reflock);
2393
2394         if (need_exit_check) {
2395                 LOCK(&adb->lock);
2396                 INSIST(adb->shutting_down);
2397                 check_exit(adb);
2398                 UNLOCK(&adb->lock);
2399         }
2400 }
2401
2402 void
2403 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
2404         isc_task_t *clone;
2405         isc_event_t *event;
2406         isc_boolean_t zeroirefcnt = ISC_FALSE;
2407
2408         /*
2409          * Send '*eventp' to 'task' when 'adb' has shutdown.
2410          */
2411
2412         REQUIRE(DNS_ADB_VALID(adb));
2413         REQUIRE(eventp != NULL);
2414
2415         event = *eventp;
2416         *eventp = NULL;
2417
2418         LOCK(&adb->lock);
2419
2420         LOCK(&adb->reflock);
2421         zeroirefcnt = ISC_TF(adb->irefcnt == 0);
2422
2423         if (adb->shutting_down && zeroirefcnt &&
2424             isc_mempool_getallocated(adb->ahmp) == 0) {
2425                 /*
2426                  * We're already shutdown.  Send the event.
2427                  */
2428                 event->ev_sender = adb;
2429                 isc_task_send(task, &event);
2430         } else {
2431                 clone = NULL;
2432                 isc_task_attach(task, &clone);
2433                 event->ev_sender = clone;
2434                 ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
2435         }
2436
2437         UNLOCK(&adb->reflock);
2438         UNLOCK(&adb->lock);
2439 }
2440
2441 void
2442 dns_adb_shutdown(dns_adb_t *adb) {
2443         isc_boolean_t need_check_exit;
2444
2445         /*
2446          * Shutdown 'adb'.
2447          */
2448
2449         LOCK(&adb->lock);
2450
2451         if (!adb->shutting_down) {
2452                 adb->shutting_down = ISC_TRUE;
2453                 need_check_exit = shutdown_names(adb);
2454                 if (!need_check_exit)
2455                         need_check_exit = shutdown_entries(adb);
2456                 if (need_check_exit)
2457                         check_exit(adb);
2458         }
2459
2460         UNLOCK(&adb->lock);
2461 }
2462
2463 isc_result_t
2464 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
2465                    void *arg, dns_name_t *name, dns_name_t *zone,
2466                    unsigned int options, isc_stdtime_t now, dns_name_t *target,
2467                    in_port_t port, dns_adbfind_t **findp)
2468 {
2469         dns_adbfind_t *find;
2470         dns_adbname_t *adbname;
2471         int bucket;
2472         isc_boolean_t want_event, start_at_zone, alias, have_address;
2473         isc_result_t result;
2474         unsigned int wanted_addresses;
2475         unsigned int wanted_fetches;
2476         unsigned int query_pending;
2477
2478         REQUIRE(DNS_ADB_VALID(adb));
2479         if (task != NULL) {
2480                 REQUIRE(action != NULL);
2481         }
2482         REQUIRE(name != NULL);
2483         REQUIRE(zone != NULL);
2484         REQUIRE(findp != NULL && *findp == NULL);
2485         REQUIRE(target == NULL || dns_name_hasbuffer(target));
2486
2487         REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
2488
2489         result = ISC_R_UNEXPECTED;
2490         wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
2491         wanted_fetches = 0;
2492         query_pending = 0;
2493         want_event = ISC_FALSE;
2494         start_at_zone = ISC_FALSE;
2495         alias = ISC_FALSE;
2496
2497         if (now == 0)
2498                 isc_stdtime_get(&now);
2499
2500         /*
2501          * XXXMLG  Move this comment somewhere else!
2502          *
2503          * Look up the name in our internal database.
2504          *
2505          * Possibilities:  Note that these are not always exclusive.
2506          *
2507          *      No name found.  In this case, allocate a new name header and
2508          *      an initial namehook or two.  If any of these allocations
2509          *      fail, clean up and return ISC_R_NOMEMORY.
2510          *
2511          *      Name found, valid addresses present.  Allocate one addrinfo
2512          *      structure for each found and append it to the linked list
2513          *      of addresses for this header.
2514          *
2515          *      Name found, queries pending.  In this case, if a task was
2516          *      passed in, allocate a job id, attach it to the name's job
2517          *      list and remember to tell the caller that there will be
2518          *      more info coming later.
2519          */
2520
2521         find = new_adbfind(adb);
2522         if (find == NULL)
2523                 return (ISC_R_NOMEMORY);
2524
2525         find->port = port;
2526
2527         /*
2528          * Remember what types of addresses we are interested in.
2529          */
2530         find->options = options;
2531         find->flags |= wanted_addresses;
2532         if (FIND_WANTEVENT(find)) {
2533                 REQUIRE(task != NULL);
2534         }
2535
2536         /*
2537          * Try to see if we know anything about this name at all.
2538          */
2539         bucket = DNS_ADB_INVALIDBUCKET;
2540         adbname = find_name_and_lock(adb, name, find->options, &bucket);
2541         if (adb->name_sd[bucket]) {
2542                 DP(DEF_LEVEL,
2543                    "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
2544                 RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2545                 result = ISC_R_SHUTTINGDOWN;
2546                 goto out;
2547         }
2548
2549         /*
2550          * Nothing found.  Allocate a new adbname structure for this name.
2551          */
2552         if (adbname == NULL) {
2553                 adbname = new_adbname(adb, name);
2554                 if (adbname == NULL) {
2555                         RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
2556                         result = ISC_R_NOMEMORY;
2557                         goto out;
2558                 }
2559                 link_name(adb, bucket, adbname);
2560                 if (FIND_HINTOK(find))
2561                         adbname->flags |= NAME_HINT_OK;
2562                 if (FIND_GLUEOK(find))
2563                         adbname->flags |= NAME_GLUE_OK;
2564                 if (FIND_STARTATZONE(find))
2565                         adbname->flags |= NAME_STARTATZONE;
2566         }
2567
2568         /*
2569          * Expire old entries, etc.
2570          */
2571         RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
2572
2573         /*
2574          * Do we know that the name is an alias?
2575          */
2576         if (!EXPIRE_OK(adbname->expire_target, now)) {
2577                 /*
2578                  * Yes, it is.
2579                  */
2580                 DP(DEF_LEVEL,
2581                    "dns_adb_createfind: name %p is an alias (cached)",
2582                    adbname);
2583                 alias = ISC_TRUE;
2584                 goto post_copy;
2585         }
2586
2587         /*
2588          * Try to populate the name from the database and/or
2589          * start fetches.  First try looking for an A record
2590          * in the database.
2591          */
2592         if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
2593             && WANT_INET(wanted_addresses)) {
2594                 result = dbfind_name(adbname, now, dns_rdatatype_a);
2595                 if (result == ISC_R_SUCCESS) {
2596                         DP(DEF_LEVEL,
2597                            "dns_adb_createfind: found A for name %p in db",
2598                            adbname);
2599                         goto v6;
2600                 }
2601
2602                 /*
2603                  * Did we get a CNAME or DNAME?
2604                  */
2605                 if (result == DNS_R_ALIAS) {
2606                         DP(DEF_LEVEL,
2607                            "dns_adb_createfind: name %p is an alias",
2608                            adbname);
2609                         alias = ISC_TRUE;
2610                         goto post_copy;
2611                 }
2612
2613                 /*
2614                  * If the name doesn't exist at all, don't bother with
2615                  * v6 queries; they won't work.
2616                  *
2617                  * If the name does exist but we didn't get our data, go
2618                  * ahead and try a6.
2619                  *
2620                  * If the result is neither of these, try a fetch for A.
2621                  */
2622                 if (NXDOMAIN_RESULT(result))
2623                         goto fetch;
2624                 else if (NXRRSET_RESULT(result))
2625                         goto v6;
2626
2627                 if (!NAME_FETCH_V4(adbname))
2628                         wanted_fetches |= DNS_ADBFIND_INET;
2629         }
2630
2631  v6:
2632         if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
2633             && WANT_INET6(wanted_addresses)) {
2634                 result = dbfind_a6(adbname, now);
2635                 if (result == ISC_R_SUCCESS) {
2636                         DP(DEF_LEVEL,
2637                            "dns_adb_createfind: found A6 for name %p",
2638                            adbname);
2639                         goto fetch;
2640                 }
2641
2642                 /*
2643                  * Did we get a CNAME or DNAME?
2644                  */
2645                 if (result == DNS_R_ALIAS) {
2646                         DP(DEF_LEVEL,
2647                            "dns_adb_createfind: name %p is an alias",
2648                            adbname);
2649                         alias = ISC_TRUE;
2650                         goto post_copy;
2651                 }
2652
2653                 /*
2654                  * If the name doesn't exist at all, jump to the fetch
2655                  * code.  Otherwise, we'll try AAAA.
2656                  */
2657                 if (NXDOMAIN_RESULT(result))
2658                         goto fetch;
2659
2660                 result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
2661                 if (result == ISC_R_SUCCESS) {
2662                         DP(DEF_LEVEL,
2663                            "dns_adb_createfind: found AAAA for name %p",
2664                            adbname);
2665                         goto fetch;
2666                 }
2667
2668                 /*
2669                  * Did we get a CNAME or DNAME?  This should have hit
2670                  * during the A6 query, but we'll reproduce it here Just
2671                  * In Case.
2672                  */
2673                 if (result == DNS_R_ALIAS) {
2674                         DP(DEF_LEVEL,
2675                            "dns_adb_createfind: name %p is an alias",
2676                            adbname);
2677                         alias = ISC_TRUE;
2678                         goto post_copy;
2679                 }
2680
2681                 /*
2682                  * Listen to negative cache hints, and don't start
2683                  * another query.
2684                  */
2685                 if (NCACHE_RESULT(result) || AUTH_NX(result))
2686                         goto fetch;
2687
2688                 if (!NAME_FETCH_V6(adbname))
2689                         wanted_fetches |= DNS_ADBFIND_INET6;
2690         }
2691
2692  fetch:
2693         if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
2694             (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
2695                 have_address = ISC_TRUE;
2696         else
2697                 have_address = ISC_FALSE;
2698         if (wanted_fetches != 0 &&
2699             ! (FIND_AVOIDFETCHES(find) && have_address)) {
2700                 /*
2701                  * We're missing at least one address family.  Either the
2702                  * caller hasn't instructed us to avoid fetches, or we don't
2703                  * know anything about any of the address families that would
2704                  * be acceptable so we have to launch fetches.
2705                  */
2706
2707                 if (FIND_STARTATZONE(find))
2708                         start_at_zone = ISC_TRUE;
2709
2710                 /*
2711                  * Start V4.
2712                  */
2713                 if (WANT_INET(wanted_fetches) &&
2714                     fetch_name_v4(adbname, start_at_zone) == ISC_R_SUCCESS) {
2715                         DP(DEF_LEVEL,
2716                            "dns_adb_createfind: started A fetch for name %p",
2717                            adbname);
2718                 }
2719
2720                 /*
2721                  * Start V6.
2722                  */
2723                 if (WANT_INET6(wanted_fetches) &&
2724                     fetch_name_a6(adbname, start_at_zone) == ISC_R_SUCCESS) {
2725                         DP(DEF_LEVEL,
2726                            "dns_adb_createfind: started A6 fetch for name %p",
2727                            adbname);
2728                 }
2729         }
2730
2731         /*
2732          * Run through the name and copy out the bits we are
2733          * interested in.
2734          */
2735         copy_namehook_lists(adb, find, zone, adbname, now);
2736
2737  post_copy:
2738         if (NAME_FETCH_V4(adbname))
2739                 query_pending |= DNS_ADBFIND_INET;
2740         if (NAME_FETCH_V6(adbname))
2741                 query_pending |= DNS_ADBFIND_INET6;
2742
2743         /*
2744          * Attach to the name's query list if there are queries
2745          * already running, and we have been asked to.
2746          */
2747         want_event = ISC_TRUE;
2748         if (!FIND_WANTEVENT(find))
2749                 want_event = ISC_FALSE;
2750         if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
2751                 want_event = ISC_FALSE;
2752         if ((wanted_addresses & query_pending) == 0)
2753                 want_event = ISC_FALSE;
2754         if (alias)
2755                 want_event = ISC_FALSE;
2756         if (want_event) {
2757                 find->adbname = adbname;
2758                 find->name_bucket = bucket;
2759                 ISC_LIST_APPEND(adbname->finds, find, plink);
2760                 find->query_pending = (query_pending & wanted_addresses);
2761                 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
2762                 find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
2763                 DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
2764                    find, adbname);
2765         } else {
2766                 /*
2767                  * Remove the flag so the caller knows there will never
2768                  * be an event, and set internal flags to fake that
2769                  * the event was sent and freed, so dns_adb_destroyfind() will
2770                  * do the right thing.
2771                  */
2772                 find->query_pending = (query_pending & wanted_addresses);
2773                 find->options &= ~DNS_ADBFIND_WANTEVENT;
2774                 find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
2775                 find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
2776         }
2777
2778         find->partial_result |= (adbname->partial_result & wanted_addresses);
2779         if (alias) {
2780                 if (target != NULL) {
2781                         result = dns_name_copy(&adbname->target, target, NULL);
2782                         if (result != ISC_R_SUCCESS)
2783                                 goto out;
2784                 }
2785                 result = DNS_R_ALIAS;
2786         } else
2787                 result = ISC_R_SUCCESS;
2788
2789         /*
2790          * Copy out error flags from the name structure into the find.
2791          */
2792         find->result_v4 = find_err_map[adbname->fetch_err];
2793         find->result_v6 = find_err_map[adbname->fetch6_err];
2794
2795  out:
2796         if (find != NULL) {
2797                 *findp = find;
2798
2799                 if (want_event) {
2800                         isc_task_t *taskp;
2801
2802                         INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
2803                         taskp = NULL;
2804                         isc_task_attach(task, &taskp);
2805                         find->event.ev_sender = taskp;
2806                         find->event.ev_action = action;
2807                         find->event.ev_arg = arg;
2808                 }
2809         }
2810
2811         if (bucket != DNS_ADB_INVALIDBUCKET)
2812                 UNLOCK(&adb->namelocks[bucket]);
2813
2814         return (result);
2815 }
2816
2817 void
2818 dns_adb_destroyfind(dns_adbfind_t **findp) {
2819         dns_adbfind_t *find;
2820         dns_adbentry_t *entry;
2821         dns_adbaddrinfo_t *ai;
2822         int bucket;
2823         dns_adb_t *adb;
2824
2825         REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
2826         find = *findp;
2827         *findp = NULL;
2828
2829         LOCK(&find->lock);
2830
2831         DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
2832
2833         adb = find->adb;
2834         REQUIRE(DNS_ADB_VALID(adb));
2835
2836         REQUIRE(FIND_EVENTFREED(find));
2837
2838         bucket = find->name_bucket;
2839         INSIST(bucket == DNS_ADB_INVALIDBUCKET);
2840
2841         UNLOCK(&find->lock);
2842
2843         /*
2844          * The find doesn't exist on any list, and nothing is locked.
2845          * Return the find to the memory pool, and decrement the adb's
2846          * reference count.
2847          */
2848         ai = ISC_LIST_HEAD(find->list);
2849         while (ai != NULL) {
2850                 ISC_LIST_UNLINK(find->list, ai, publink);
2851                 entry = ai->entry;
2852                 ai->entry = NULL;
2853                 INSIST(DNS_ADBENTRY_VALID(entry));
2854                 RUNTIME_CHECK(dec_entry_refcnt(adb, entry, ISC_TRUE) ==
2855                               ISC_FALSE);
2856                 free_adbaddrinfo(adb, &ai);
2857                 ai = ISC_LIST_HEAD(find->list);
2858         }
2859
2860         /*
2861          * WARNING:  The find is freed with the adb locked.  This is done
2862          * to avoid a race condition where we free the find, some other
2863          * thread tests to see if it should be destroyed, detects it should
2864          * be, destroys it, and then we try to lock it for our check, but the
2865          * lock is destroyed.
2866          */
2867         LOCK(&adb->lock);
2868         if (free_adbfind(adb, &find))
2869                 check_exit(adb);
2870         UNLOCK(&adb->lock);
2871 }
2872
2873 void
2874 dns_adb_cancelfind(dns_adbfind_t *find) {
2875         isc_event_t *ev;
2876         isc_task_t *task;
2877         dns_adb_t *adb;
2878         int bucket;
2879         int unlock_bucket;
2880
2881         LOCK(&find->lock);
2882
2883         DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
2884
2885         adb = find->adb;
2886         REQUIRE(DNS_ADB_VALID(adb));
2887
2888         REQUIRE(!FIND_EVENTFREED(find));
2889         REQUIRE(FIND_WANTEVENT(find));
2890
2891         bucket = find->name_bucket;
2892         if (bucket == DNS_ADB_INVALIDBUCKET)
2893                 goto cleanup;
2894
2895         /*
2896          * We need to get the adbname's lock to unlink the find.
2897          */
2898         unlock_bucket = bucket;
2899         violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
2900         bucket = find->name_bucket;
2901         if (bucket != DNS_ADB_INVALIDBUCKET) {
2902                 ISC_LIST_UNLINK(find->adbname->finds, find, plink);
2903                 find->adbname = NULL;
2904                 find->name_bucket = DNS_ADB_INVALIDBUCKET;
2905         }
2906         UNLOCK(&adb->namelocks[unlock_bucket]);
2907         bucket = DNS_ADB_INVALIDBUCKET;
2908
2909  cleanup:
2910
2911         if (!FIND_EVENTSENT(find)) {
2912                 ev = &find->event;
2913                 task = ev->ev_sender;
2914                 ev->ev_sender = find;
2915                 ev->ev_type = DNS_EVENT_ADBCANCELED;
2916                 ev->ev_destroy = event_free;
2917                 ev->ev_destroy_arg = find;
2918                 find->result_v4 = ISC_R_CANCELED;
2919                 find->result_v6 = ISC_R_CANCELED;
2920
2921                 DP(DEF_LEVEL, "Sending event %p to task %p for find %p",
2922                    ev, task, find);
2923
2924                 isc_task_sendanddetach(&task, (isc_event_t **)&ev);
2925         }
2926
2927         UNLOCK(&find->lock);
2928 }
2929
2930 void
2931 dns_adb_dump(dns_adb_t *adb, FILE *f) {
2932         REQUIRE(DNS_ADB_VALID(adb));
2933         REQUIRE(f != NULL);
2934
2935         /*
2936          * Lock the adb itself, lock all the name buckets, then lock all
2937          * the entry buckets.  This should put the adb into a state where
2938          * nothing can change, so we can iterate through everything and
2939          * print at our leisure.
2940          */
2941
2942         LOCK(&adb->lock);
2943         dump_adb(adb, f, ISC_FALSE);
2944         UNLOCK(&adb->lock);
2945 }
2946
2947 static void
2948 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
2949         if (value == INT_MAX)
2950                 return;
2951         fprintf(f, " [%s TTL %d]", legend, value - now);
2952 }
2953
2954 static void
2955 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug) {
2956         int i;
2957         dns_adbname_t *name;
2958         isc_stdtime_t now;
2959
2960         isc_stdtime_get(&now);
2961
2962         fprintf(f, ";\n; Address database dump\n;\n");
2963         if (debug)
2964                 fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
2965                         adb, adb->erefcnt, adb->irefcnt,
2966                         isc_mempool_getallocated(adb->nhmp));
2967
2968         for (i = 0 ; i < NBUCKETS ; i++)
2969                 LOCK(&adb->namelocks[i]);
2970         for (i = 0 ; i < NBUCKETS ; i++)
2971                 LOCK(&adb->entrylocks[i]);
2972
2973         /*
2974          * Dump the names
2975          */
2976         for (i = 0 ; i < NBUCKETS ; i++) {
2977                 name = ISC_LIST_HEAD(adb->names[i]);
2978                 if (name == NULL)
2979                         continue;
2980                 if (debug)
2981                         fprintf(f, "; bucket %d\n", i);
2982                 for (;
2983                      name != NULL;
2984                      name = ISC_LIST_NEXT(name, plink))
2985                 {
2986                         if (debug)
2987                                 fprintf(f, "; name %p (flags %08x)\n",
2988                                         name, name->flags);
2989
2990                         fprintf(f, "; ");
2991                         print_dns_name(f, &name->name);
2992                         if (dns_name_countlabels(&name->target) > 0) {
2993                                 fprintf(f, " alias ");
2994                                 print_dns_name(f, &name->target);
2995                         }
2996
2997                         dump_ttl(f, "v4", name->expire_v4, now);
2998                         dump_ttl(f, "v6", name->expire_v6, now);
2999                         dump_ttl(f, "target", name->expire_target, now);
3000
3001                         fprintf(f, " [v4 %s] [v6 %s]",
3002                                 errnames[name->fetch_err],
3003                                 errnames[name->fetch6_err]);
3004
3005                         fprintf(f, "\n");
3006
3007                         print_namehook_list(f, "v4", &name->v4, debug);
3008                         print_namehook_list(f, "v6", &name->v6, debug);
3009
3010                         if (debug)
3011                                 print_fetch_list(f, name);
3012                         if (debug)
3013                                 print_find_list(f, name);
3014
3015                 }
3016         }
3017
3018         /*
3019          * Unlock everything
3020          */
3021         for (i = 0; i < NBUCKETS; i++)
3022                 UNLOCK(&adb->entrylocks[i]);
3023         for (i = 0; i < NBUCKETS; i++)
3024                 UNLOCK(&adb->namelocks[i]);
3025 }
3026
3027 static void
3028 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug)
3029 {
3030         char addrbuf[ISC_NETADDR_FORMATSIZE];
3031         isc_netaddr_t netaddr;
3032
3033         isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
3034         isc_netaddr_format(&netaddr, addrbuf, sizeof addrbuf);
3035
3036         if (debug)
3037                 fprintf(f, ";\t%p: refcnt %u flags %08x \n",
3038                         entry, entry->refcnt, entry->flags);
3039                         
3040         fprintf(f, ";\t%s [srtt %u]", addrbuf, entry->srtt);
3041         fprintf(f, "\n");
3042 }
3043
3044 void
3045 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
3046         char tmp[512];
3047         const char *tmpp;
3048         dns_adbaddrinfo_t *ai;
3049         isc_sockaddr_t *sa;
3050
3051         /*
3052          * Not used currently, in the API Just In Case we
3053          * want to dump out the name and/or entries too.
3054          */
3055
3056         LOCK(&find->lock);
3057
3058         fprintf(f, ";Find %p\n", find);
3059         fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
3060                 find->query_pending, find->partial_result,
3061                 find->options, find->flags);
3062         fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
3063                 find->name_bucket, find->adbname, find->event.ev_sender);
3064
3065         ai = ISC_LIST_HEAD(find->list);
3066         if (ai != NULL)
3067                 fprintf(f, "\tAddresses:\n");
3068         while (ai != NULL) {
3069                 sa = &ai->sockaddr;
3070                 switch (sa->type.sa.sa_family) {
3071                 case AF_INET:
3072                         tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
3073                                          tmp, sizeof tmp);
3074                         break;
3075                 case AF_INET6:
3076                         tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
3077                                          tmp, sizeof tmp);
3078                         break;
3079                 default:
3080                         tmpp = "UnkFamily";
3081                 }
3082
3083                 if (tmpp == NULL)
3084                         tmpp = "BadAddress";
3085
3086                 fprintf(f, "\t\tentry %p, flags %08x"
3087                         " srtt %u addr %s\n",
3088                         ai->entry, ai->flags, ai->srtt, tmpp);
3089
3090                 ai = ISC_LIST_NEXT(ai, publink);
3091         }
3092
3093         UNLOCK(&find->lock);
3094 }
3095
3096 static void
3097 print_dns_name(FILE *f, dns_name_t *name) {
3098         char buf[DNS_NAME_FORMATSIZE];
3099
3100         INSIST(f != NULL);
3101
3102         dns_name_format(name, buf, sizeof(buf));
3103         fprintf(f, "%s", buf);
3104 }
3105
3106 static void
3107 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
3108                     isc_boolean_t debug)
3109 {
3110         dns_adbnamehook_t *nh;
3111
3112         for (nh = ISC_LIST_HEAD(*list);
3113              nh != NULL;
3114              nh = ISC_LIST_NEXT(nh, plink))
3115         {
3116                 if (debug)
3117                         fprintf(f, ";\tHook(%s) %p\n", legend, nh);
3118                 dump_entry(f, nh->entry, debug);
3119         }
3120 }
3121
3122 static inline void
3123 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
3124         fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n",
3125                 type, ft, ft->namehook, ft->entry, ft->fetch);
3126 }
3127
3128 static inline void
3129 print_fetch6(FILE *f, dns_adbfetch6_t *ft) {
3130         fprintf(f, "\t\tFetch(A6): %p -> { nh %p, entry %p, fetch %p }\n",
3131                 ft, ft->namehook, ft->entry, ft->fetch);
3132 }
3133
3134 static void
3135 print_fetch_list(FILE *f, dns_adbname_t *n) {
3136         dns_adbfetch6_t *fetch6;
3137
3138         if (NAME_FETCH_A(n))
3139                 print_fetch(f, n->fetch_a, "A");
3140         if (NAME_FETCH_AAAA(n))
3141                 print_fetch(f, n->fetch_aaaa, "AAAA");
3142
3143         fetch6 = ISC_LIST_HEAD(n->fetches_a6);
3144         while (fetch6 != NULL) {
3145                 print_fetch6(f, fetch6);
3146                 fetch6 = ISC_LIST_NEXT(fetch6, plink);
3147         }
3148 }
3149
3150 static void
3151 print_find_list(FILE *f, dns_adbname_t *name) {
3152         dns_adbfind_t *find;
3153
3154         find = ISC_LIST_HEAD(name->finds);
3155         while (find != NULL) {
3156                 dns_adb_dumpfind(find, f);
3157                 find = ISC_LIST_NEXT(find, plink);
3158         }
3159 }
3160
3161 static isc_result_t
3162 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
3163 {
3164         isc_result_t result;
3165         dns_rdataset_t rdataset;
3166         dns_adb_t *adb;
3167         dns_fixedname_t foundname;
3168         dns_name_t *fname;
3169
3170         INSIST(DNS_ADBNAME_VALID(adbname));
3171         adb = adbname->adb;
3172         INSIST(DNS_ADB_VALID(adb));
3173         INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
3174
3175         dns_fixedname_init(&foundname);
3176         fname = dns_fixedname_name(&foundname);
3177         dns_rdataset_init(&rdataset);
3178
3179         if (rdtype == dns_rdatatype_a)
3180                 adbname->fetch_err = FIND_ERR_UNEXPECTED;
3181         else
3182                 adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3183
3184         result = dns_view_find(adb->view, &adbname->name, rdtype, now,
3185                                NAME_GLUEOK(adbname),
3186                                ISC_TF(NAME_HINTOK(adbname)),
3187                                NULL, NULL, fname, &rdataset, NULL);
3188
3189         /* XXXVIX this switch statement is too sparse to gen a jump table. */
3190         switch (result) {
3191         case DNS_R_GLUE:
3192         case DNS_R_HINT:
3193         case ISC_R_SUCCESS:
3194                 /*
3195                  * Found in the database.  Even if we can't copy out
3196                  * any information, return success, or else a fetch
3197                  * will be made, which will only make things worse.
3198                  */
3199                 if (rdtype == dns_rdatatype_a)
3200                         adbname->fetch_err = FIND_ERR_SUCCESS;
3201                 else
3202                         adbname->fetch6_err = FIND_ERR_SUCCESS;
3203                 result = import_rdataset(adbname, &rdataset, now);
3204                 break;
3205         case DNS_R_NXDOMAIN:
3206         case DNS_R_NXRRSET:
3207                 /*
3208                  * We're authoritative and the data doesn't exist.
3209                  * Make up a negative cache entry so we don't ask again
3210                  * for a while.
3211                  *
3212                  * XXXRTH  What time should we use?  I'm putting in 30 seconds
3213                  * for now.
3214                  */
3215                 if (rdtype == dns_rdatatype_a) {
3216                         adbname->expire_v4 = now + 30;
3217                         DP(NCACHE_LEVEL,
3218                            "adb name %p: Caching auth negative entry for A",
3219                            adbname);
3220                         if (result == DNS_R_NXDOMAIN)
3221                                 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3222                         else
3223                                 adbname->fetch_err = FIND_ERR_NXRRSET;
3224                 } else {
3225                         DP(NCACHE_LEVEL,
3226                            "adb name %p: Caching auth negative entry for AAAA",
3227                            adbname);
3228                         adbname->expire_v6 = now + 30;
3229                         if (result == DNS_R_NXDOMAIN)
3230                                 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3231                         else
3232                                 adbname->fetch6_err = FIND_ERR_NXRRSET;
3233                 }
3234                 break;
3235         case DNS_R_NCACHENXDOMAIN:
3236         case DNS_R_NCACHENXRRSET:
3237                 /*
3238                  * We found a negative cache entry.  Pull the TTL from it
3239                  * so we won't ask again for a while.
3240                  */
3241                 rdataset.ttl = ttlclamp(rdataset.ttl);
3242                 if (rdtype == dns_rdatatype_a) {
3243                         adbname->expire_v4 = rdataset.ttl + now;
3244                         if (result == DNS_R_NCACHENXDOMAIN)
3245                                 adbname->fetch_err = FIND_ERR_NXDOMAIN;
3246                         else
3247                                 adbname->fetch_err = FIND_ERR_NXRRSET;
3248                         DP(NCACHE_LEVEL,
3249                           "adb name %p: Caching negative entry for A (ttl %u)",
3250                            adbname, rdataset.ttl);
3251                 } else {
3252                         DP(NCACHE_LEVEL,
3253                        "adb name %p: Caching negative entry for AAAA (ttl %u)",
3254                            adbname, rdataset.ttl);
3255                         adbname->expire_v6 = rdataset.ttl + now;
3256                         if (result == DNS_R_NCACHENXDOMAIN)
3257                                 adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3258                         else
3259                                 adbname->fetch6_err = FIND_ERR_NXRRSET;
3260                 }
3261                 break;
3262         case DNS_R_CNAME:
3263         case DNS_R_DNAME:
3264                 /*
3265                  * Clear the hint and glue flags, so this will match
3266                  * more often.
3267                  */
3268                 adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
3269
3270                 rdataset.ttl = ttlclamp(rdataset.ttl);
3271                 clean_target(adb, &adbname->target);
3272                 adbname->expire_target = INT_MAX;
3273                 result = set_target(adb, &adbname->name, fname, &rdataset,
3274                                     &adbname->target);
3275                 if (result == ISC_R_SUCCESS) {
3276                         result = DNS_R_ALIAS;
3277                         DP(NCACHE_LEVEL,
3278                            "adb name %p: caching alias target",
3279                            adbname);
3280                         adbname->expire_target = rdataset.ttl + now;
3281                 }
3282                 if (rdtype == dns_rdatatype_a)
3283                         adbname->fetch_err = FIND_ERR_SUCCESS;
3284                 else
3285                         adbname->fetch6_err = FIND_ERR_SUCCESS;
3286                 break;
3287         }
3288
3289         if (dns_rdataset_isassociated(&rdataset))
3290                 dns_rdataset_disassociate(&rdataset);
3291
3292         return (result);
3293 }
3294
3295 static isc_result_t
3296 dbfind_a6(dns_adbname_t *adbname, isc_stdtime_t now) {
3297         isc_result_t result;
3298         dns_rdataset_t rdataset;
3299         dns_adb_t *adb;
3300         dns_a6context_t a6ctx;
3301         dns_fixedname_t foundname;
3302         dns_name_t *fname;
3303
3304         INSIST(DNS_ADBNAME_VALID(adbname));
3305         adb = adbname->adb;
3306         INSIST(DNS_ADB_VALID(adb));
3307
3308         result = ISC_R_UNEXPECTED;
3309
3310         dns_fixedname_init(&foundname);
3311         fname = dns_fixedname_name(&foundname);
3312         dns_rdataset_init(&rdataset);
3313
3314         adbname->fetch6_err = FIND_ERR_UNEXPECTED;
3315
3316         result = dns_view_find(adb->view, &adbname->name, dns_rdatatype_a6,
3317                                now, NAME_GLUEOK(adbname),
3318                                ISC_TF(NAME_HINTOK(adbname)),
3319                                NULL, NULL, fname, &rdataset, NULL);
3320
3321         switch (result) {
3322         case DNS_R_GLUE:
3323         case DNS_R_HINT:
3324         case ISC_R_SUCCESS:
3325                 /*
3326                  * Start a6 chain follower.  There is no need to poke people
3327                  * who might be waiting, since this is call requires there
3328                  * are none.
3329                  */
3330                 adbname->fetch6_err = FIND_ERR_SUCCESS;
3331                 dns_a6_init(&a6ctx, a6find, NULL, import_a6,
3332                             a6missing, adbname);
3333                 (void)dns_a6_foreach(&a6ctx, &rdataset, now);
3334                 adbname->flags &= ~NAME_NEEDS_POKE;
3335                 result = ISC_R_SUCCESS;
3336                 break;
3337         case DNS_R_NXDOMAIN:
3338         case DNS_R_NXRRSET:
3339                 /*
3340                  * We're authoritative and the data doesn't exist.
3341                  * Make up a negative cache entry so we don't ask again
3342                  * for a while.
3343                  *
3344                  * XXXRTH  What time should we use?  I'm putting in 30 seconds
3345                  * for now.
3346                  */
3347                 DP(NCACHE_LEVEL,
3348                    "adb name %p: Caching auth negative entry for A6",
3349                    adbname);
3350                 adbname->expire_v6 = now + 30;
3351                 if (result == DNS_R_NXDOMAIN)
3352                         adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3353                 else
3354                         adbname->fetch6_err = FIND_ERR_NXRRSET;
3355                 break;
3356         case DNS_R_NCACHENXDOMAIN:
3357         case DNS_R_NCACHENXRRSET:
3358                 /*
3359                  * We found a negative cache entry.  Pull the TTL from it
3360                  * so we won't ask again for a while.
3361                  */
3362                 DP(NCACHE_LEVEL,
3363                    "adb name %p: Caching negative entry for A6 (ttl %u)",
3364                    adbname, rdataset.ttl);
3365                 adbname->expire_v6 = ISC_MIN(rdataset.ttl + now,
3366                                              adbname->expire_v6);
3367                 if (result == DNS_R_NCACHENXDOMAIN)
3368                         adbname->fetch6_err = FIND_ERR_NXDOMAIN;
3369                 else
3370                         adbname->fetch6_err = FIND_ERR_NXRRSET;
3371                 break;
3372         case DNS_R_CNAME:
3373         case DNS_R_DNAME:
3374                 rdataset.ttl = ttlclamp(rdataset.ttl);
3375                 clean_target(adb, &adbname->target);
3376                 adbname->expire_target = INT_MAX;
3377                 result = set_target(adb, &adbname->name, fname, &rdataset,
3378                                     &adbname->target);
3379                 if (result == ISC_R_SUCCESS) {
3380                         result = DNS_R_ALIAS;
3381                         DP(NCACHE_LEVEL,
3382                            "adb name %p: caching alias target",
3383                            adbname);
3384                         adbname->expire_target = rdataset.ttl + now;
3385                 }
3386                 break;
3387         }
3388
3389         if (dns_rdataset_isassociated(&rdataset))
3390                 dns_rdataset_disassociate(&rdataset);
3391
3392         return (result);
3393 }
3394
3395 static void
3396 fetch_callback(isc_task_t *task, isc_event_t *ev) {
3397         dns_fetchevent_t *dev;
3398         dns_adbname_t *name;
3399         dns_adb_t *adb;
3400         dns_adbfetch_t *fetch;
3401         int bucket;
3402         isc_eventtype_t ev_status;
3403         isc_stdtime_t now;
3404         isc_result_t result;
3405         unsigned int address_type;
3406         isc_boolean_t want_check_exit = ISC_FALSE;
3407
3408         UNUSED(task);
3409
3410         INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3411         dev = (dns_fetchevent_t *)ev;
3412         name = ev->ev_arg;
3413         INSIST(DNS_ADBNAME_VALID(name));
3414         adb = name->adb;
3415         INSIST(DNS_ADB_VALID(adb));
3416
3417         bucket = name->lock_bucket;
3418         LOCK(&adb->namelocks[bucket]);
3419
3420         INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
3421         address_type = 0;
3422         if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
3423                 address_type = DNS_ADBFIND_INET;
3424                 fetch = name->fetch_a;
3425                 name->fetch_a = NULL;
3426         } else if (NAME_FETCH_AAAA(name)
3427                    && (name->fetch_aaaa->fetch == dev->fetch)) {
3428                 address_type = DNS_ADBFIND_INET6;
3429                 fetch = name->fetch_aaaa;
3430                 name->fetch_aaaa = NULL;
3431         }
3432         INSIST(address_type != 0);
3433
3434         dns_resolver_destroyfetch(&fetch->fetch);
3435         dev->fetch = NULL;
3436
3437         ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
3438
3439         /*
3440          * Cleanup things we don't care about.
3441          */
3442         if (dev->node != NULL)
3443                 dns_db_detachnode(dev->db, &dev->node);
3444         if (dev->db != NULL)
3445                 dns_db_detach(&dev->db);
3446
3447         /*
3448          * If this name is marked as dead, clean up, throwing away
3449          * potentially good data.
3450          */
3451         if (NAME_DEAD(name)) {
3452                 free_adbfetch(adb, &fetch);
3453                 isc_event_free(&ev);
3454
3455                 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3456
3457                 UNLOCK(&adb->namelocks[bucket]);
3458
3459                 if (want_check_exit) {
3460                         LOCK(&adb->lock);
3461                         check_exit(adb);
3462                         UNLOCK(&adb->lock);
3463                 }
3464
3465                 return;
3466         }
3467
3468         isc_stdtime_get(&now);
3469
3470         /*
3471          * If we got a negative cache response, remember it.
3472          */
3473         if (NCACHE_RESULT(dev->result)) {
3474                 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3475                 if (address_type == DNS_ADBFIND_INET) {
3476                         DP(NCACHE_LEVEL, "adb fetch name %p: "
3477                            "Caching negative entry for A (ttl %u)",
3478                            name, dev->rdataset->ttl);
3479                         name->expire_v4 = ISC_MIN(name->expire_v4,
3480                                                   dev->rdataset->ttl + now);
3481                         if (dev->result == DNS_R_NCACHENXDOMAIN)
3482                                 name->fetch_err = FIND_ERR_NXDOMAIN;
3483                         else
3484                                 name->fetch_err = FIND_ERR_NXRRSET;
3485                 } else {
3486                         DP(NCACHE_LEVEL, "adb fetch name %p: "
3487                            "Caching negative entry for AAAA (ttl %u)",
3488                            name, dev->rdataset->ttl);
3489                         name->expire_v6 = ISC_MIN(name->expire_v6,
3490                                                   dev->rdataset->ttl + now);
3491                         if (dev->result == DNS_R_NCACHENXDOMAIN)
3492                                 name->fetch6_err = FIND_ERR_NXDOMAIN;
3493                         else
3494                                 name->fetch6_err = FIND_ERR_NXRRSET;
3495                 }
3496                 goto out;
3497         }
3498
3499         /*
3500          * Handle CNAME/DNAME.
3501          */
3502         if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3503                 dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3504                 clean_target(adb, &name->target);
3505                 name->expire_target = INT_MAX;
3506                 result = set_target(adb, &name->name,
3507                                     dns_fixedname_name(&dev->foundname),
3508                                     dev->rdataset,
3509                                     &name->target);
3510                 if (result == ISC_R_SUCCESS) {
3511                         DP(NCACHE_LEVEL,
3512                            "adb fetch name %p: caching alias target",
3513                            name);
3514                         name->expire_target = dev->rdataset->ttl + now;
3515                 }
3516                 goto check_result;
3517         }
3518
3519         /*
3520          * Did we get back junk?  If so, and there are no more fetches
3521          * sitting out there, tell all the finds about it.
3522          */
3523         if (dev->result != ISC_R_SUCCESS) {
3524                 /* XXXMLG Don't pound on bad servers. */
3525                 if (address_type == DNS_ADBFIND_INET) {
3526                         name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
3527                         name->fetch_err = FIND_ERR_FAILURE;
3528                 } else {
3529                         name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
3530                         name->fetch6_err = FIND_ERR_FAILURE;
3531                 }
3532                 goto out;
3533         }
3534
3535         /*
3536          * We got something potentially useful.
3537          */
3538         result = import_rdataset(name, &fetch->rdataset, now);
3539
3540  check_result:
3541         if (result == ISC_R_SUCCESS) {
3542                 ev_status = DNS_EVENT_ADBMOREADDRESSES;
3543                 if (address_type == DNS_ADBFIND_INET)
3544                         name->fetch_err = FIND_ERR_SUCCESS;
3545                 else
3546                         name->fetch6_err = FIND_ERR_SUCCESS;
3547         }
3548
3549  out:
3550         free_adbfetch(adb, &fetch);
3551         isc_event_free(&ev);
3552
3553         clean_finds_at_name(name, ev_status, address_type);
3554
3555         UNLOCK(&adb->namelocks[bucket]);
3556 }
3557
3558 static void
3559 fetch_callback_a6(isc_task_t *task, isc_event_t *ev) {
3560         dns_fetchevent_t *dev;
3561         dns_adbname_t *name;
3562         dns_adb_t *adb;
3563         dns_adbfetch6_t *fetch;
3564         int bucket;
3565         isc_stdtime_t now;
3566         isc_result_t result;
3567         isc_boolean_t want_check_exit = ISC_FALSE;
3568
3569         UNUSED(task);
3570
3571         INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
3572         dev = (dns_fetchevent_t *)ev;
3573         name = ev->ev_arg;
3574         INSIST(DNS_ADBNAME_VALID(name));
3575         adb = name->adb;
3576         INSIST(DNS_ADB_VALID(adb));
3577
3578         bucket = name->lock_bucket;
3579         LOCK(&adb->namelocks[bucket]);
3580
3581         INSIST(!NAME_NEEDSPOKE(name));
3582
3583         for (fetch = ISC_LIST_HEAD(name->fetches_a6);
3584              fetch != NULL;
3585              fetch = ISC_LIST_NEXT(fetch, plink))
3586                 if (fetch->fetch == dev->fetch)
3587                         break;
3588         INSIST(fetch != NULL);
3589         ISC_LIST_UNLINK(name->fetches_a6, fetch, plink);
3590
3591         DP(ENTER_LEVEL, "ENTER: fetch_callback_a6() name %p", name);
3592
3593         dns_resolver_destroyfetch(&fetch->fetch);
3594         dev->fetch = NULL;
3595
3596         /*
3597          * Cleanup things we don't care about.
3598          */
3599         if (dev->node != NULL)
3600                 dns_db_detachnode(dev->db, &dev->node);
3601         if (dev->db != NULL)
3602                 dns_db_detach(&dev->db);
3603
3604         /*
3605          * If this name is marked as dead, clean up, throwing away
3606          * potentially good data.
3607          */
3608         if (NAME_DEAD(name)) {
3609                 free_adbfetch6(adb, &fetch);
3610                 isc_event_free(&ev);
3611
3612                 want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
3613
3614                 UNLOCK(&adb->namelocks[bucket]);
3615
3616                 if (want_check_exit) {
3617                         LOCK(&adb->lock);
3618                         check_exit(adb);
3619                         UNLOCK(&adb->lock);
3620                 }
3621
3622                 return;
3623         }
3624
3625         isc_stdtime_get(&now);
3626
3627         /*
3628          * If the A6 query didn't succeed, and this is the first query
3629          * in the A6 chain, try AAAA records instead.  For later failures,
3630          * don't do this.
3631          */
3632         if (dev->result != ISC_R_SUCCESS) {
3633                 DP(DEF_LEVEL, "name %p: A6 failed: %s",
3634                    name, isc_result_totext(dev->result));
3635
3636                 /*
3637                  * If we got a negative cache response, remember it.
3638                  */
3639                 if (NCACHE_RESULT(dev->result)) {
3640                         dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3641                         DP(NCACHE_LEVEL, "adb fetch name %p: "
3642                            "Caching negative entry for A6 (ttl %u)",
3643                            name, dev->rdataset->ttl);
3644                         name->expire_v6 = ISC_MIN(name->expire_v6,
3645                                                   dev->rdataset->ttl + now);
3646                         if (dev->result == DNS_R_NCACHENXDOMAIN)
3647                                 name->fetch6_err = FIND_ERR_NXDOMAIN;
3648                         else
3649                                 name->fetch6_err = FIND_ERR_NXRRSET;
3650                 }
3651
3652                 /*
3653                  * Handle CNAME/DNAME.
3654                  */
3655                 if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
3656                         dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
3657                         clean_target(adb, &name->target);
3658                         name->expire_target = INT_MAX;
3659                         result = set_target(adb, &name->name,
3660                                           dns_fixedname_name(&dev->foundname),
3661                                             dev->rdataset,
3662                                             &name->target);
3663                         if (result == ISC_R_SUCCESS) {
3664                                 DP(NCACHE_LEVEL,
3665                                   "adb A6 fetch name %p: caching alias target",
3666                                    name);
3667                                 name->expire_target = dev->rdataset->ttl + now;
3668                                 if (FETCH_FIRSTA6(fetch)) {
3669                                         /*
3670                                          * Make this name 'pokeable', since
3671                                          * we've learned that this name is an
3672                                          * alias.
3673                                          */
3674                                         name->flags |= NAME_NEEDS_POKE;
3675                                 }
3676                         }
3677                         goto out;
3678                 }
3679
3680                 if (FETCH_FIRSTA6(fetch) && !NAME_HAS_V6(name)) {
3681                         DP(DEF_LEVEL,
3682                            "name %p: A6 query failed, starting AAAA", name);
3683
3684                         /*
3685                          * Since this is the very first fetch, and it
3686                          * failed, we know there are no more running.
3687                          */
3688                         result = dbfind_name(name, now, dns_rdatatype_aaaa);
3689                         if (result == ISC_R_SUCCESS) {
3690                                 DP(DEF_LEVEL,
3691                                    "name %p: callback_a6: Found AAAA for",
3692                                    name);
3693                                 name->flags |= NAME_NEEDS_POKE;
3694                                 goto out;
3695                         }
3696
3697                         /*
3698                          * Listen to negative cache hints, and don't start
3699                          * another query.
3700                          */
3701                         if (NCACHE_RESULT(result) || AUTH_NX(result)) {
3702                                 if (NXDOMAIN_RESULT(result))
3703                                         name->fetch6_err = NEWERR(name->fetch6_err, FIND_ERR_NXDOMAIN);
3704                                 else
3705                                         name->fetch6_err = NEWERR(name->fetch6_err, FIND_ERR_NXRRSET);
3706                                 goto out;
3707                         }
3708
3709                         /*
3710                          * Try to start fetches for AAAA.
3711                          */
3712                         result = fetch_name_aaaa(name);
3713                         if (result == ISC_R_SUCCESS) {
3714                                 DP(DEF_LEVEL,
3715                                    "name %p: callback_a6: Started AAAA fetch",
3716                                    name);
3717                                 goto out;
3718                         }
3719                 }
3720
3721                 goto out;
3722         }
3723
3724         /*
3725          * We got something potentially useful.  Run the A6 chain
3726          * follower on this A6 rdataset.
3727          */
3728
3729         fetch->a6ctx.chains = name->chains;
3730         (void)dns_a6_foreach(&fetch->a6ctx, dev->rdataset, now);
3731
3732  out:
3733         free_adbfetch6(adb, &fetch);
3734         isc_event_free(&ev);
3735
3736         if (NAME_NEEDSPOKE(name)) {
3737                 clean_finds_at_name(name, DNS_EVENT_ADBMOREADDRESSES,
3738                                     DNS_ADBFIND_INET6);
3739                         name->fetch6_err = FIND_ERR_SUCCESS;
3740         } else if (!NAME_FETCH_V6(name))
3741                 clean_finds_at_name(name, DNS_EVENT_ADBNOMOREADDRESSES,
3742                                     DNS_ADBFIND_INET6);
3743
3744         name->flags &= ~NAME_NEEDS_POKE;
3745
3746         UNLOCK(&adb->namelocks[bucket]);
3747
3748         return;
3749 }
3750
3751 static isc_result_t
3752 fetch_name_v4(dns_adbname_t *adbname, isc_boolean_t start_at_zone) {
3753         isc_result_t result;
3754         dns_adbfetch_t *fetch = NULL;
3755         dns_adb_t *adb;
3756         dns_fixedname_t fixed;
3757         dns_name_t *name;
3758         dns_rdataset_t rdataset;
3759         dns_rdataset_t *nameservers;
3760         unsigned int options;
3761
3762         INSIST(DNS_ADBNAME_VALID(adbname));
3763         adb = adbname->adb;
3764         INSIST(DNS_ADB_VALID(adb));
3765
3766         INSIST(!NAME_FETCH_V4(adbname));
3767
3768         adbname->fetch_err = FIND_ERR_NOTFOUND;
3769
3770         name = NULL;
3771         nameservers = NULL;
3772         dns_rdataset_init(&rdataset);
3773
3774         options = 0;
3775         if (start_at_zone) {
3776                 DP(50, "fetch_name_v4: starting at zone for name %p",
3777                    adbname);
3778                 dns_fixedname_init(&fixed);
3779                 name = dns_fixedname_name(&fixed);
3780                 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3781                                                0, 0, ISC_TRUE, ISC_FALSE,
3782                                                &rdataset, NULL);
3783                 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3784                         goto cleanup;
3785                 nameservers = &rdataset;
3786                 options |= DNS_FETCHOPT_UNSHARED;
3787         }
3788
3789         fetch = new_adbfetch(adb);
3790         if (fetch == NULL) {
3791                 result = ISC_R_NOMEMORY;
3792                 goto cleanup;
3793         }
3794
3795         result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3796                                           dns_rdatatype_a,
3797                                           name, nameservers, NULL, options,
3798                                           adb->task, fetch_callback,
3799                                           adbname, &fetch->rdataset, NULL,
3800                                           &fetch->fetch);
3801         if (result != ISC_R_SUCCESS)
3802                 goto cleanup;
3803
3804         adbname->fetch_a = fetch;
3805         fetch = NULL;  /* keep us from cleaning this up below */
3806
3807  cleanup:
3808         if (fetch != NULL)
3809                 free_adbfetch(adb, &fetch);
3810         if (dns_rdataset_isassociated(&rdataset))
3811                 dns_rdataset_disassociate(&rdataset);
3812
3813         return (result);
3814 }
3815
3816 /* XXXMLG Why doesn't this look a lot like fetch_name_a and fetch_name_a6? */
3817 static isc_result_t
3818 fetch_name_aaaa(dns_adbname_t *adbname) {
3819         isc_result_t result;
3820         dns_adbfetch_t *fetch;
3821         dns_adb_t *adb;
3822
3823         INSIST(DNS_ADBNAME_VALID(adbname));
3824         adb = adbname->adb;
3825         INSIST(DNS_ADB_VALID(adb));
3826
3827         INSIST(!NAME_FETCH_AAAA(adbname));
3828
3829         adbname->fetch6_err = FIND_ERR_NOTFOUND;
3830
3831         fetch = new_adbfetch(adb);
3832         if (fetch == NULL) {
3833                 result = ISC_R_NOMEMORY;
3834                 goto cleanup;
3835         }
3836
3837         result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3838                                           dns_rdatatype_aaaa,
3839                                           NULL, NULL, NULL, 0,
3840                                           adb->task, fetch_callback,
3841                                           adbname, &fetch->rdataset, NULL,
3842                                           &fetch->fetch);
3843         if (result != ISC_R_SUCCESS)
3844                 goto cleanup;
3845
3846         adbname->fetch_aaaa = fetch;
3847         fetch = NULL;  /* keep us from cleaning this up below */
3848
3849  cleanup:
3850         if (fetch != NULL)
3851                 free_adbfetch(adb, &fetch);
3852
3853         return (result);
3854 }
3855
3856 static isc_result_t
3857 fetch_name_a6(dns_adbname_t *adbname, isc_boolean_t start_at_zone) {
3858         isc_result_t result;
3859         dns_adbfetch6_t *fetch = NULL;
3860         dns_adb_t *adb;
3861         dns_fixedname_t fixed;
3862         dns_name_t *name;
3863         dns_rdataset_t rdataset;
3864         dns_rdataset_t *nameservers;
3865         unsigned int options;
3866
3867         INSIST(DNS_ADBNAME_VALID(adbname));
3868         adb = adbname->adb;
3869         INSIST(DNS_ADB_VALID(adb));
3870
3871         INSIST(!NAME_FETCH_V6(adbname));
3872
3873         adbname->fetch6_err = FIND_ERR_NOTFOUND;
3874
3875         name = NULL;
3876         nameservers = NULL;
3877         dns_rdataset_init(&rdataset);
3878
3879         options = 0;
3880         if (start_at_zone) {
3881                 DP(50, "fetch_name_a6: starting at zone for name %p",
3882                    adbname);
3883                 dns_fixedname_init(&fixed);
3884                 name = dns_fixedname_name(&fixed);
3885                 result = dns_view_findzonecut2(adb->view, &adbname->name, name,
3886                                                0, 0, ISC_TRUE, ISC_FALSE,
3887                                                &rdataset, NULL);
3888                 if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
3889                         goto cleanup;
3890                 nameservers = &rdataset;
3891                 options |= DNS_FETCHOPT_UNSHARED;
3892         }
3893
3894         fetch = new_adbfetch6(adb, adbname, NULL);
3895         if (fetch == NULL) {
3896                 result = ISC_R_NOMEMORY;
3897                 goto cleanup;
3898         }
3899         fetch->flags |= FETCH_FIRST_A6;
3900
3901         result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
3902                                           dns_rdatatype_a6,
3903                                           name, nameservers, NULL, options,
3904                                           adb->task, fetch_callback_a6,
3905                                           adbname, &fetch->rdataset, NULL,
3906                                           &fetch->fetch);
3907         if (result != ISC_R_SUCCESS)
3908                 goto cleanup;
3909
3910         ISC_LIST_APPEND(adbname->fetches_a6, fetch, plink);
3911         fetch = NULL;  /* keep us from cleaning this up below */
3912
3913  cleanup:
3914         if (fetch != NULL)
3915                 free_adbfetch6(adb, &fetch);
3916         if (dns_rdataset_isassociated(&rdataset))
3917                 dns_rdataset_disassociate(&rdataset);
3918
3919         return (result);
3920 }
3921
3922 /* 
3923  * XXXMLG Needs to take a find argument and an address info, no zone or adb,
3924  * since these can be extracted from the find itself.
3925  */
3926 isc_result_t
3927 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *zone,
3928                  isc_stdtime_t expire_time)
3929 {
3930         dns_adbzoneinfo_t *zi;
3931         int bucket;
3932         isc_result_t result = ISC_R_SUCCESS;
3933
3934         REQUIRE(DNS_ADB_VALID(adb));
3935         REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3936         REQUIRE(zone != NULL);
3937
3938         bucket = addr->entry->lock_bucket;
3939         LOCK(&adb->entrylocks[bucket]);
3940         zi = ISC_LIST_HEAD(addr->entry->zoneinfo);
3941         while (zi != NULL && dns_name_equal(zone, &zi->zone))
3942                 zi = ISC_LIST_NEXT(zi, plink);
3943         if (zi != NULL) {
3944                 if (expire_time > zi->lame_timer)
3945                         zi->lame_timer = expire_time;
3946                 goto unlock;
3947         }
3948         zi = new_adbzoneinfo(adb, zone);
3949         if (zi == NULL) {
3950                 result = ISC_R_NOMEMORY;
3951                 goto unlock;
3952         }
3953
3954         zi->lame_timer = expire_time;
3955
3956         ISC_LIST_PREPEND(addr->entry->zoneinfo, zi, plink);
3957  unlock:
3958         UNLOCK(&adb->entrylocks[bucket]);
3959
3960         return (ISC_R_SUCCESS);
3961 }
3962
3963 void
3964 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3965                    unsigned int rtt, unsigned int factor)
3966 {
3967         int bucket;
3968         unsigned int new_srtt;
3969         isc_stdtime_t now;
3970
3971         REQUIRE(DNS_ADB_VALID(adb));
3972         REQUIRE(DNS_ADBADDRINFO_VALID(addr));
3973         REQUIRE(factor <= 10);
3974
3975         bucket = addr->entry->lock_bucket;
3976         LOCK(&adb->entrylocks[bucket]);
3977
3978         if (factor == DNS_ADB_RTTADJAGE)
3979                 new_srtt = addr->entry->srtt * 98 / 100;
3980         else
3981                 new_srtt = (addr->entry->srtt / 10 * factor)
3982                         + (rtt / 10 * (10 - factor));
3983
3984         addr->entry->srtt = new_srtt;
3985         addr->srtt = new_srtt;
3986
3987         isc_stdtime_get(&now);
3988         addr->entry->expires = now + ADB_ENTRY_WINDOW;
3989
3990         UNLOCK(&adb->entrylocks[bucket]);
3991 }
3992
3993 void
3994 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
3995                     unsigned int bits, unsigned int mask)
3996 {
3997         int bucket;
3998
3999         REQUIRE(DNS_ADB_VALID(adb));
4000         REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4001
4002         bucket = addr->entry->lock_bucket;
4003         LOCK(&adb->entrylocks[bucket]);
4004
4005         addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
4006         /*
4007          * Note that we do not update the other bits in addr->flags with
4008          * the most recent values from addr->entry->flags.
4009          */
4010         addr->flags = (addr->flags & ~mask) | (bits & mask);
4011
4012         UNLOCK(&adb->entrylocks[bucket]);
4013 }
4014
4015 isc_result_t
4016 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
4017                      dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
4018 {
4019         int bucket;
4020         dns_adbentry_t *entry;
4021         dns_adbaddrinfo_t *addr;
4022         isc_result_t result;
4023         in_port_t port;
4024
4025         REQUIRE(DNS_ADB_VALID(adb));
4026         REQUIRE(addrp != NULL && *addrp == NULL);
4027
4028         UNUSED(now);
4029
4030         result = ISC_R_SUCCESS;
4031         bucket = DNS_ADB_INVALIDBUCKET;
4032         entry = find_entry_and_lock(adb, sa, &bucket);
4033         if (adb->entry_sd[bucket]) {
4034                 result = ISC_R_SHUTTINGDOWN;
4035                 goto unlock;
4036         }
4037         if (entry == NULL) {
4038                 /*
4039                  * We don't know anything about this address.
4040                  */
4041                 entry = new_adbentry(adb);
4042                 if (entry == NULL) {
4043                         result = ISC_R_NOMEMORY;
4044                         goto unlock;
4045                 }
4046                 entry->sockaddr = *sa;
4047                 link_entry(adb, bucket, entry);
4048                 DP(50, "findaddrinfo: new entry %p", entry);
4049         } else
4050                 DP(50, "findaddrinfo: found entry %p", entry);
4051
4052         port = isc_sockaddr_getport(sa);
4053         addr = new_adbaddrinfo(adb, entry, port);
4054         if (addr != NULL) {
4055                 inc_entry_refcnt(adb, entry, ISC_FALSE);
4056                 *addrp = addr;
4057         }
4058
4059  unlock:
4060         UNLOCK(&adb->entrylocks[bucket]);
4061
4062         return (result);
4063 }
4064
4065 void
4066 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
4067         dns_adbaddrinfo_t *addr;
4068         dns_adbentry_t *entry;
4069         int bucket;
4070         isc_stdtime_t now;
4071         isc_boolean_t want_check_exit = ISC_FALSE;
4072
4073         REQUIRE(DNS_ADB_VALID(adb));
4074         REQUIRE(addrp != NULL);
4075         addr = *addrp;
4076         REQUIRE(DNS_ADBADDRINFO_VALID(addr));
4077         entry = addr->entry;
4078         REQUIRE(DNS_ADBENTRY_VALID(entry));
4079
4080         isc_stdtime_get(&now);
4081
4082         *addrp = NULL;
4083
4084         bucket = addr->entry->lock_bucket;
4085         LOCK(&adb->entrylocks[bucket]);
4086
4087         entry->expires = now + ADB_ENTRY_WINDOW;
4088
4089         want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
4090
4091         UNLOCK(&adb->entrylocks[bucket]);
4092
4093         addr->entry = NULL;
4094         free_adbaddrinfo(adb, &addr);
4095
4096         if (want_check_exit) {
4097                 LOCK(&adb->lock);
4098                 check_exit(adb);
4099                 UNLOCK(&adb->lock);
4100         }
4101 }
4102
4103 void
4104 dns_adb_flush(dns_adb_t *adb) {
4105         unsigned int i;
4106
4107         INSIST(DNS_ADB_VALID(adb));
4108
4109         LOCK(&adb->lock);
4110
4111         for (i = 0 ; i < NBUCKETS ; i++) {
4112                 /*
4113                  * Call our cleanup routines.
4114                  */
4115                 RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
4116                 RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
4117         }
4118
4119 #ifdef DUMP_ADB_AFTER_CLEANING
4120         dump_adb(adb, stdout, ISC_TRUE);
4121 #endif
4122
4123         UNLOCK(&adb->lock);
4124 }