the lookup module, and make byaddr use lookup.
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.108 2000/10/11 17:44:09 mws Exp $
+# $Id: Makefile.in,v 1.109 2000/10/17 01:57:40 bwelling Exp $
srcdir = @srcdir@
VPATH = @srcdir@
cache.@O@ callbacks.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ dispatch.@O@ dnssec.@O@ \
forward.@O@ journal.@O@ keytable.@O@ lib.@O@ log.@O@ \
- master.@O@ masterdump.@O@ message.@O@ \
+ lookup.@O@ master.@O@ masterdump.@O@ message.@O@ \
name.@O@ ncache.@O@ nxt.@O@ opt.@O@ peer.@O@ \
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rdata.@O@ rdatalist.@O@ \
rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \
cache.c callbacks.c compress.c \
db.c dbiterator.c dbtable.c dispatch.c dnssec.c \
forward.c journal.c keytable.c lib.c log.c \
- master.c masterdump.c message.c \
+ lookup.c master.c masterdump.c message.c \
name.c ncache.c nxt.c opt.c peer.c \
rbt.c rbtdb.c rbtdb64.c rdata.c rdatalist.c \
rdataset.c rdatasetiter.c rdataslab.c request.c \
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: byaddr.c,v 1.22 2000/10/07 00:09:19 bwelling Exp $ */
+/* $Id: byaddr.c,v 1.23 2000/10/17 01:57:41 bwelling Exp $ */
#include <config.h>
#include <dns/byaddr.h>
#include <dns/db.h>
#include <dns/events.h>
+#include <dns/lookup.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
dns_fixedname_t name;
/* Locked by lock. */
unsigned int options;
+ dns_lookup_t * lookup;
isc_task_t * task;
- dns_view_t * view;
dns_byaddrevent_t * event;
- dns_fetch_t * fetch;
- unsigned int restarts;
isc_boolean_t canceled;
- dns_rdataset_t rdataset;
};
#define BYADDR_MAGIC 0x42794164U /* ByAd. */
#define MAX_RESTARTS 16
-static void byaddr_find(dns_byaddr_t *byaddr, dns_fetchevent_t *event);
-
static char hex_digits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
}
static inline isc_result_t
-copy_ptr_targets(dns_byaddr_t *byaddr) {
+copy_ptr_targets(dns_byaddr_t *byaddr, dns_rdataset_t *rdataset) {
isc_result_t result;
dns_name_t *name;
dns_rdata_t rdata;
* The caller must be holding the byaddr's lock.
*/
- result = dns_rdataset_first(&byaddr->rdataset);
+ result = dns_rdataset_first(rdataset);
while (result == ISC_R_SUCCESS) {
dns_rdata_ptr_t ptr;
- dns_rdataset_current(&byaddr->rdataset, &rdata);
+ dns_rdataset_current(rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &ptr, NULL);
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_NOMEMORY);
}
ISC_LIST_APPEND(byaddr->event->names, name, link);
- result = dns_rdataset_next(&byaddr->rdataset);
+ result = dns_rdataset_next(rdataset);
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
}
static void
-fetch_done(isc_task_t *task, isc_event_t *event) {
+lookup_done(isc_task_t *task, isc_event_t *event) {
dns_byaddr_t *byaddr = event->ev_arg;
- dns_fetchevent_t *fevent;
+ dns_lookupevent_t *levent;
+ isc_result_t result;
UNUSED(task);
- REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+ REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
REQUIRE(VALID_BYADDR(byaddr));
REQUIRE(byaddr->task == task);
- fevent = (dns_fetchevent_t *)event;
- REQUIRE(fevent->fetch == byaddr->fetch);
-
- byaddr_find(byaddr, fevent);
-}
-
-static inline isc_result_t
-start_fetch(dns_byaddr_t *byaddr) {
- isc_result_t result;
-
- /*
- * The caller must be holding the byaddr's lock.
- */
-
- REQUIRE(byaddr->fetch == NULL);
-
- result = dns_resolver_createfetch(byaddr->view->resolver,
- dns_fixedname_name(&byaddr->name),
- dns_rdatatype_ptr,
- NULL, NULL, NULL, 0,
- byaddr->task, fetch_done, byaddr,
- &byaddr->rdataset, NULL,
- &byaddr->fetch);
-
- return (result);
-}
-
-static void
-byaddr_find(dns_byaddr_t *byaddr, dns_fetchevent_t *event) {
- isc_result_t result;
- isc_boolean_t want_restart;
- isc_boolean_t send_event = ISC_FALSE;
- isc_event_t *ievent;
- dns_name_t *name, *fname, *prefix;
- dns_fixedname_t foundname, fixed;
- dns_rdata_t rdata;
- unsigned int nlabels, nbits;
- int order;
- dns_namereln_t namereln;
- dns_rdata_cname_t cname;
- dns_rdata_dname_t dname;
-
- REQUIRE(VALID_BYADDR(byaddr));
+ levent = (dns_lookupevent_t *)event;
- LOCK(&byaddr->lock);
-
- result = ISC_R_SUCCESS;
- name = dns_fixedname_name(&byaddr->name);
-
- do {
- byaddr->restarts++;
- want_restart = ISC_FALSE;
-
- if (event == NULL && !byaddr->canceled) {
- dns_fixedname_init(&foundname);
- fname = dns_fixedname_name(&foundname);
- INSIST(!dns_rdataset_isassociated(&byaddr->rdataset));
- result = dns_view_find(byaddr->view, name,
- dns_rdatatype_ptr, 0, 0,
- ISC_FALSE, fname,
- &byaddr->rdataset, NULL);
- if (result == ISC_R_NOTFOUND) {
- /*
- * We don't know anything about the name.
- * Launch a fetch.
- */
- result = start_fetch(byaddr);
- if (result != ISC_R_SUCCESS)
- send_event = ISC_TRUE;
- goto done;
- }
- } else {
- result = event->result;
- fname = dns_fixedname_name(&event->foundname);
- dns_resolver_destroyfetch(&byaddr->fetch);
- INSIST(event->rdataset == &byaddr->rdataset);
- INSIST(event->sigrdataset == NULL);
- /*
- * Detach (if necessary) from things we know we
- * don't care about.
- */
- if (event->node != NULL)
- dns_db_detachnode(event->db, &event->node);
- if (event->db != NULL)
- dns_db_detach(&event->db);
- }
-
- /*
- * If we've been canceled, forget about the result.
- */
- if (byaddr->canceled)
- result = ISC_R_CANCELED;
-
- switch (result) {
- case ISC_R_SUCCESS:
- result = copy_ptr_targets(byaddr);
- send_event = ISC_TRUE;
- break;
- case DNS_R_CNAME:
- /*
- * Copy the CNAME's target into the byaddr's
- * query name and start over.
- */
- result = dns_rdataset_first(&byaddr->rdataset);
- if (result != ISC_R_SUCCESS)
- break;
- dns_rdataset_current(&byaddr->rdataset, &rdata);
- result = dns_rdata_tostruct(&rdata, &cname, NULL);
- if (result != ISC_R_SUCCESS)
- break;
- result = dns_name_concatenate(&cname.cname, NULL, name,
- NULL);
- dns_rdata_freestruct(&cname);
- if (result == ISC_R_SUCCESS)
- want_restart = ISC_TRUE;
- break;
- case DNS_R_DNAME:
- namereln = dns_name_fullcompare(name, fname, &order,
- &nlabels, &nbits);
- INSIST(namereln == dns_namereln_subdomain);
- /*
- * Get the target name of the DNAME.
- */
- result = dns_rdataset_first(&byaddr->rdataset);
- if (result != ISC_R_SUCCESS)
- break;
- dns_rdataset_current(&byaddr->rdataset, &rdata);
- result = dns_rdata_tostruct(&rdata, &dname, NULL);
- if (result != ISC_R_SUCCESS)
- break;
- /*
- * Construct the new query name and start over.
- */
- dns_fixedname_init(&fixed);
- prefix = dns_fixedname_name(&fixed);
- result = dns_name_split(name, nlabels, nbits, prefix,
- NULL);
- if (result != ISC_R_SUCCESS) {
- dns_rdata_freestruct(&dname);
- break;
- }
- result = dns_name_concatenate(prefix, &dname.dname,
- name, NULL);
- dns_rdata_freestruct(&dname);
- if (result == ISC_R_SUCCESS)
- want_restart = ISC_TRUE;
- break;
- default:
- send_event = ISC_TRUE;
- }
-
- done:
- if (dns_rdataset_isassociated(&byaddr->rdataset))
- dns_rdataset_disassociate(&byaddr->rdataset);
-
- if (event != NULL) {
- ievent = (isc_event_t *)event;
- isc_event_free(&ievent);
- event = NULL;
- }
-
- /*
- * Limit the number of restarts.
- */
- if (want_restart && byaddr->restarts == MAX_RESTARTS) {
- want_restart = ISC_FALSE;
- result = ISC_R_QUOTA;
- send_event = ISC_TRUE;
- }
-
- } while (want_restart);
-
- if (send_event) {
- byaddr->event->result = result;
- byaddr->event->ev_sender = byaddr;
- ievent = (isc_event_t *)byaddr->event;
- byaddr->event = NULL;
- isc_task_sendanddetach(&byaddr->task, &ievent);
- dns_view_detach(&byaddr->view);
- }
-
- UNLOCK(&byaddr->lock);
+ if (levent->result == ISC_R_SUCCESS)
+ result = copy_ptr_targets(byaddr, levent->rdataset);
+ byaddr->event->result = levent->result;
+ isc_event_free(&event);
+ isc_task_sendanddetach(&byaddr->task, (isc_event_t **)&byaddr->event);
}
static void
if (result != ISC_R_SUCCESS)
goto cleanup_lock;
- byaddr->view = NULL;
- dns_view_attach(view, &byaddr->view);
- byaddr->fetch = NULL;
- byaddr->restarts = 0;
+ byaddr->lookup = NULL;
+ result = dns_lookup_create(mctx, dns_fixedname_name(&byaddr->name),
+ dns_rdatatype_ptr, view, 0, task,
+ lookup_done, byaddr, &byaddr->lookup);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
byaddr->canceled = ISC_FALSE;
- dns_rdataset_init(&byaddr->rdataset);
byaddr->magic = BYADDR_MAGIC;
*byaddrp = byaddr;
- byaddr_find(byaddr, NULL);
-
return (ISC_R_SUCCESS);
cleanup_lock:
if (!byaddr->canceled) {
byaddr->canceled = ISC_TRUE;
- if (byaddr->fetch != NULL) {
- INSIST(byaddr->view != NULL);
- dns_resolver_cancelfetch(byaddr->fetch);
- }
+ if (byaddr->lookup != NULL)
+ dns_lookup_cancel(byaddr->lookup);
}
UNLOCK(&byaddr->lock);
REQUIRE(VALID_BYADDR(byaddr));
REQUIRE(byaddr->event == NULL);
REQUIRE(byaddr->task == NULL);
- REQUIRE(byaddr->view == NULL);
+ dns_lookup_destroy(&byaddr->lookup);
DESTROYLOCK(&byaddr->lock);
byaddr->magic = 0;
--- /dev/null
+/*
+ * Copyright (C) 2000 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lookup.h,v 1.1 2000/10/17 01:57:42 bwelling Exp $ */
+
+#ifndef DNS_LOOKUP_H
+#define DNS_LOOKUP_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*
+ * DNS Lookup
+ *
+ * The lookup module performs simple dns lookups.
+ *
+ * MP:
+ * The module ensures appropriate synchronization of data structures it
+ * creates and manipulates.
+ *
+ * Reliability:
+ * No anticipated impact.
+ *
+ * Resources:
+ * <TBS>
+ *
+ * Security:
+ * No anticipated impact.
+ *
+ * Standards:
+ * RFCs: 1034, 1035, 2181, <TBS>
+ * Drafts: <TBS>
+ */
+
+#include <isc/lang.h>
+#include <isc/event.h>
+
+#include <dns/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*
+ * A 'dns_lookupevent_t' is returned when a lookup completes.
+ * The sender field will be set to the lookup that completed. If 'result'
+ * is ISC_R_SUCCESS, then 'names' will contain a list of names associated
+ * with the address. The recipient of the event must not change the list
+ * and must not refer to any of the name data after the event is freed.
+ */
+typedef struct dns_lookupevent {
+ ISC_EVENT_COMMON(struct dns_lookupevent);
+ isc_result_t result;
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+} dns_lookupevent_t;
+
+isc_result_t
+dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
+ dns_view_t *view, unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg, dns_lookup_t **lookupp);
+/*
+ * Finds the rrsets matching 'name' and 'type'.
+ *
+ * Requires:
+ *
+ * 'mctx' is a valid mctx.
+ *
+ * 'name' is a valid name.
+ *
+ * 'view' is a valid view which has a resolver.
+ *
+ * 'task' is a valid task.
+ *
+ * lookupp != NULL && *lookupp == NULL
+ *
+ * Returns:
+ *
+ * ISC_R_SUCCESS
+ * ISC_R_NOMEMORY
+ *
+ * Any resolver-related error (e.g. ISC_R_SHUTTINGDOWN) may also be
+ * returned.
+ */
+
+void
+dns_lookup_cancel(dns_lookup_t *lookup);
+/*
+ * Cancel 'lookup'.
+ *
+ * Notes:
+ *
+ * If 'lookup' has not completed, post its LOOKUPDONE event with a
+ * result code of ISC_R_CANCELED.
+ *
+ * Requires:
+ *
+ * 'lookup' is a valid lookup.
+ */
+
+void
+dns_lookup_destroy(dns_lookup_t **lookupp);
+/*
+ * Destroy 'lookup'.
+ *
+ * Requires:
+ *
+ * '*lookupp' is a valid lookup.
+ *
+ * The caller has received the LOOKUPDONE event (either because the
+ * lookup completed or because dns_lookup_cancel() was called).
+ *
+ * Ensures:
+ *
+ * *lookupp == NULL.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* DNS_LOOKUP_H */
--- /dev/null
+/*
+ * Copyright (C) 2000 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: lookup.c,v 1.1 2000/10/17 01:57:42 bwelling Exp $ */
+
+#include <config.h>
+
+#include <isc/mem.h>
+#include <isc/netaddr.h>
+#include <isc/string.h> /* Required for HP/UX (and others?) */
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/events.h>
+#include <dns/lookup.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+#include <dns/resolver.h>
+#include <dns/result.h>
+#include <dns/view.h>
+
+struct dns_lookup {
+ /* Unlocked. */
+ unsigned int magic;
+ isc_mem_t * mctx;
+ isc_mutex_t lock;
+ dns_rdatatype_t type;
+ dns_fixedname_t name;
+ /* Locked by lock. */
+ unsigned int options;
+ isc_task_t * task;
+ dns_view_t * view;
+ dns_lookupevent_t * event;
+ dns_fetch_t * fetch;
+ unsigned int restarts;
+ isc_boolean_t canceled;
+ dns_rdataset_t rdataset;
+};
+
+#define LOOKUP_MAGIC ISC_MAGIC('l', 'o', 'o', 'k')
+#define VALID_LOOKUP(l) ISC_MAGIC_VALID((l), LOOKUP_MAGIC)
+
+#define MAX_RESTARTS 16
+
+static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event);
+
+static void
+fetch_done(isc_task_t *task, isc_event_t *event) {
+ dns_lookup_t *lookup = event->ev_arg;
+ dns_fetchevent_t *fevent;
+
+ UNUSED(task);
+ REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+ REQUIRE(VALID_LOOKUP(lookup));
+ REQUIRE(lookup->task == task);
+ fevent = (dns_fetchevent_t *)event;
+ REQUIRE(fevent->fetch == lookup->fetch);
+
+ lookup_find(lookup, fevent);
+}
+
+static inline isc_result_t
+start_fetch(dns_lookup_t *lookup) {
+ isc_result_t result;
+
+ /*
+ * The caller must be holding the lookup's lock.
+ */
+
+ REQUIRE(lookup->fetch == NULL);
+
+ result = dns_resolver_createfetch(lookup->view->resolver,
+ dns_fixedname_name(&lookup->name),
+ lookup->type,
+ NULL, NULL, NULL, 0,
+ lookup->task, fetch_done, lookup,
+ &lookup->rdataset, NULL,
+ &lookup->fetch);
+
+ return (result);
+}
+
+static isc_result_t
+build_event(dns_lookup_t *lookup) {
+ dns_name_t *name = NULL;
+ dns_rdataset_t *rdataset = NULL;
+ isc_result_t result;
+
+ name = isc_mem_get(lookup->mctx, sizeof(dns_name_t));
+ if (name == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ dns_name_init(name, NULL);
+ result = dns_name_dup(dns_fixedname_name(&lookup->name),
+ lookup->mctx, name);
+ if (result != ISC_R_SUCCESS)
+ goto fail;
+
+ rdataset = isc_mem_get(lookup->mctx, sizeof(dns_rdataset_t));
+ if (rdataset == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto fail;
+ }
+ dns_rdataset_init(rdataset);
+ dns_rdataset_clone(&lookup->rdataset, rdataset);
+
+ lookup->event->name = name;
+ lookup->event->rdataset = rdataset;
+
+ return (ISC_R_SUCCESS);
+
+ fail:
+ if (name != NULL) {
+ if (dns_name_dynamic(name))
+ dns_name_free(name, lookup->mctx);
+ isc_mem_put(lookup->mctx, name, sizeof(dns_name_t));
+ }
+ if (rdataset != NULL) {
+ if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+ isc_mem_put(lookup->mctx, rdataset, sizeof(dns_rdataset_t));
+ }
+ return (result);
+}
+
+static void
+lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) {
+ isc_result_t result;
+ isc_boolean_t want_restart;
+ isc_boolean_t send_event = ISC_FALSE;
+ dns_name_t *name, *fname, *prefix;
+ dns_fixedname_t foundname, fixed;
+ dns_rdata_t rdata;
+ unsigned int nlabels, nbits;
+ int order;
+ dns_namereln_t namereln;
+ dns_rdata_cname_t cname;
+ dns_rdata_dname_t dname;
+
+ REQUIRE(VALID_LOOKUP(lookup));
+
+ LOCK(&lookup->lock);
+
+ result = ISC_R_SUCCESS;
+ name = dns_fixedname_name(&lookup->name);
+
+ do {
+ lookup->restarts++;
+ want_restart = ISC_FALSE;
+
+ if (event == NULL && !lookup->canceled) {
+ dns_fixedname_init(&foundname);
+ fname = dns_fixedname_name(&foundname);
+ INSIST(!dns_rdataset_isassociated(&lookup->rdataset));
+ result = dns_view_find(lookup->view, name,
+ lookup->type, 0, 0,
+ ISC_FALSE, fname,
+ &lookup->rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ /*
+ * We don't know anything about the name.
+ * Launch a fetch.
+ */
+ result = start_fetch(lookup);
+ if (result != ISC_R_SUCCESS)
+ send_event = ISC_TRUE;
+ goto done;
+ }
+ } else {
+ result = event->result;
+ fname = dns_fixedname_name(&event->foundname);
+ dns_resolver_destroyfetch(&lookup->fetch);
+ INSIST(event->rdataset == &lookup->rdataset);
+ INSIST(event->sigrdataset == NULL);
+ /*
+ * Detach (if necessary) from things we know we
+ * don't care about.
+ */
+ if (event->node != NULL)
+ dns_db_detachnode(event->db, &event->node);
+ if (event->db != NULL)
+ dns_db_detach(&event->db);
+ }
+
+ /*
+ * If we've been canceled, forget about the result.
+ */
+ if (lookup->canceled)
+ result = ISC_R_CANCELED;
+
+ switch (result) {
+ case ISC_R_SUCCESS:
+ result = build_event(lookup);
+ send_event = ISC_TRUE;
+ break;
+ case DNS_R_CNAME:
+ /*
+ * Copy the CNAME's target into the lookup's
+ * query name and start over.
+ */
+ result = dns_rdataset_first(&lookup->rdataset);
+ if (result != ISC_R_SUCCESS)
+ break;
+ dns_rdataset_current(&lookup->rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &cname, NULL);
+ if (result != ISC_R_SUCCESS)
+ break;
+ result = dns_name_concatenate(&cname.cname, NULL, name,
+ NULL);
+ dns_rdata_freestruct(&cname);
+ if (result == ISC_R_SUCCESS)
+ want_restart = ISC_TRUE;
+ break;
+ case DNS_R_DNAME:
+ namereln = dns_name_fullcompare(name, fname, &order,
+ &nlabels, &nbits);
+ INSIST(namereln == dns_namereln_subdomain);
+ /*
+ * Get the target name of the DNAME.
+ */
+ result = dns_rdataset_first(&lookup->rdataset);
+ if (result != ISC_R_SUCCESS)
+ break;
+ dns_rdataset_current(&lookup->rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &dname, NULL);
+ if (result != ISC_R_SUCCESS)
+ break;
+ /*
+ * Construct the new query name and start over.
+ */
+ dns_fixedname_init(&fixed);
+ prefix = dns_fixedname_name(&fixed);
+ result = dns_name_split(name, nlabels, nbits, prefix,
+ NULL);
+ if (result != ISC_R_SUCCESS) {
+ dns_rdata_freestruct(&dname);
+ break;
+ }
+ result = dns_name_concatenate(prefix, &dname.dname,
+ name, NULL);
+ dns_rdata_freestruct(&dname);
+ if (result == ISC_R_SUCCESS)
+ want_restart = ISC_TRUE;
+ break;
+ default:
+ send_event = ISC_TRUE;
+ }
+
+ done:
+ if (dns_rdataset_isassociated(&lookup->rdataset))
+ dns_rdataset_disassociate(&lookup->rdataset);
+
+ if (event != NULL)
+ isc_event_free((isc_event_t **)&event);
+
+ /*
+ * Limit the number of restarts.
+ */
+ if (want_restart && lookup->restarts == MAX_RESTARTS) {
+ want_restart = ISC_FALSE;
+ result = ISC_R_QUOTA;
+ send_event = ISC_TRUE;
+ }
+
+ } while (want_restart);
+
+ if (send_event) {
+ lookup->event->result = result;
+ lookup->event->ev_sender = lookup;
+ isc_task_sendanddetach(&lookup->task,
+ (isc_event_t **)&lookup->event);
+ dns_view_detach(&lookup->view);
+ }
+
+ UNLOCK(&lookup->lock);
+}
+
+static void
+levent_destroy(isc_event_t *event) {
+ dns_lookupevent_t *levent;
+ isc_mem_t *mctx;
+
+ REQUIRE(event->ev_type == DNS_EVENT_LOOKUPDONE);
+ mctx = event->ev_destroy_arg;
+ levent = (dns_lookupevent_t *)event;
+
+ if (levent->name != NULL) {
+ if (dns_name_dynamic(levent->name))
+ dns_name_free(levent->name, mctx);
+ isc_mem_put(mctx, levent->name, sizeof(dns_name_t));
+ }
+ if (levent->rdataset != NULL) {
+ dns_rdataset_disassociate(levent->rdataset);
+ isc_mem_put(mctx, levent->rdataset, sizeof(dns_rdataset_t));
+ }
+ isc_mem_put(mctx, event, event->ev_size);
+}
+
+
+isc_result_t
+dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
+ dns_view_t *view, unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg, dns_lookup_t **lookupp)
+{
+ isc_result_t result;
+ dns_lookup_t *lookup;
+ isc_event_t *ievent;
+
+ lookup = isc_mem_get(mctx, sizeof *lookup);
+ if (lookup == NULL)
+ return (ISC_R_NOMEMORY);
+ lookup->mctx = mctx;
+ lookup->options = options;
+
+ ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE,
+ action, arg, sizeof *lookup->event);
+ if (ievent == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_lookup;
+ }
+ lookup->event = (dns_lookupevent_t *)ievent;
+ lookup->event->ev_destroy = levent_destroy;
+ lookup->event->ev_destroy_arg = mctx;
+ lookup->event->result = ISC_R_FAILURE;
+ lookup->event->name = NULL;
+ lookup->event->rdataset = NULL;
+
+ lookup->task = NULL;
+ isc_task_attach(task, &lookup->task);
+
+ result = isc_mutex_init(&lookup->lock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_event;
+
+ dns_fixedname_init(&lookup->name);
+
+ result = dns_name_concatenate(name, NULL,
+ dns_fixedname_name(&lookup->name), NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ lookup->type = type;
+ lookup->view = NULL;
+ dns_view_attach(view, &lookup->view);
+ lookup->fetch = NULL;
+ lookup->restarts = 0;
+ lookup->canceled = ISC_FALSE;
+ dns_rdataset_init(&lookup->rdataset);
+ lookup->magic = LOOKUP_MAGIC;
+
+ *lookupp = lookup;
+
+ lookup_find(lookup, NULL);
+
+ return (ISC_R_SUCCESS);
+
+ cleanup_lock:
+ DESTROYLOCK(&lookup->lock);
+
+ cleanup_event:
+ ievent = (isc_event_t *)lookup->event;
+ isc_event_free(&ievent);
+ lookup->event = NULL;
+
+ isc_task_detach(&lookup->task);
+
+ cleanup_lookup:
+ isc_mem_put(mctx, lookup, sizeof *lookup);
+
+ return (result);
+}
+
+void
+dns_lookup_cancel(dns_lookup_t *lookup) {
+ REQUIRE(VALID_LOOKUP(lookup));
+
+ LOCK(&lookup->lock);
+
+ if (!lookup->canceled) {
+ lookup->canceled = ISC_TRUE;
+ if (lookup->fetch != NULL) {
+ INSIST(lookup->view != NULL);
+ dns_resolver_cancelfetch(lookup->fetch);
+ }
+ }
+
+ UNLOCK(&lookup->lock);
+}
+
+void
+dns_lookup_destroy(dns_lookup_t **lookupp) {
+ dns_lookup_t *lookup;
+
+ REQUIRE(lookupp != NULL);
+ lookup = *lookupp;
+ REQUIRE(VALID_LOOKUP(lookup));
+ REQUIRE(lookup->event == NULL);
+ REQUIRE(lookup->task == NULL);
+ REQUIRE(lookup->view == NULL);
+ if (dns_rdataset_isassociated(&lookup->rdataset))
+ dns_rdataset_disassociate(&lookup->rdataset);
+
+ DESTROYLOCK(&lookup->lock);
+ lookup->magic = 0;
+ isc_mem_put(lookup->mctx, lookup, sizeof *lookup);
+
+ *lookupp = NULL;
+}