resolver.c revision c0de97d5db2ed05df261e28460e1f477a163ee8f
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff
ca41b452ede6feaa9d8739ec3cae19389a7b0d03Bob Halley#include <config.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/assertions.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/result.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/timer.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/mutex.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/event.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/task.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <isc/stdtime.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/types.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/result.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/name.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/events.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/message.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/dispatch.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#include <dns/resolver.h>
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff#include "../isc/util.h" /* XXX */
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define DNS_RESOLVER_TRACE
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#ifdef DNS_RESOLVER_TRACE
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define RTRACE(m) printf("res %p: %s\n", res, (m))
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define RRTRACE(r, m) printf("res %p: %s\n", (r), (m))
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff#define FCTXTRACE(m) printf("fctx %p: %s\n", fctx, (m))
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff#define FTRACE(m) printf("fetch %p (res %p fctx %p tag %u): %s\n", \
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff fetch, fetch->res, fetch->private, fetch->tag, \
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff (m))
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff#else
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define RTRACE(m)
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define RRTRACE(r, m)
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define FCTXTRACE(m)
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#define FTRACE(m)
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff#endif
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff
74889a341cac183d477e15cfead391a8f7bdba95Michael Grafftypedef struct query {
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_messageid_t id;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff ISC_LINK(struct query) link;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff} resquery_t;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Grafftypedef enum {
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff fetchstate_init = 0,
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff fetchstate_active,
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff fetchstate_exiting,
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff fetchstate_done
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff} fetchstate;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Grafftypedef struct fetchctx {
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int magic;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff fetchstate state;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_resolver_t * res;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int references;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int locknum;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_name_t name;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_rdatatype_t type; /* multiple types??? */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int options;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff /* Locked by lock. */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_timer_t * timer;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_time_t expires;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_interval_t interval;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int next_tag;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff ISC_LIST(dns_fetchdoneevent_t) events;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_event_t start_event;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_dispatch_t * dispatcher;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_message_t * message;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff ISC_LIST(resquery_t) queries;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff ISC_LINK(struct fetchctx) link;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff} fetchctx_t;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff#define FCTX_MAGIC 0x46212121U /* F!!! */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff#define VALID_FCTX(fctx) ((fctx) != NULL && \
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff (fctx)->magic == FCTX_MAGIC)
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graffstruct dns_resolver {
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff /* Unlocked */
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff unsigned int magic;
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff isc_mem_t * mctx;
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff isc_mutex_t lock;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_rdataclass_t rdclass;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_timermgr_t * timermgr;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff /* Locked by lock. */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int references;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_boolean_t exiting;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_dispatch_t * shared_dispatcher;
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff unsigned int ntasks;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff unsigned int next_task;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_task_t ** tasks;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff ISC_LIST(fetchctx_t) fctxs;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff};
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
62e4837585f2d48ce9ef3ad6880d8fb75a578e58Andreas Gustafsson#define RES_MAGIC 0x52657321U /* Res! */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff#define VALID_RESOLVER(res) ((res) != NULL && \
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff (res)->magic == RES_MAGIC)
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graffstatic void destroy(dns_resolver_t *res);
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff/*
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff * Internal fetch routines. Caller must be holding the proper lock.
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graffstatic void
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Grafffctx_done(fetchctx_t *fctx, dns_result_t result) {
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff dns_fetchdoneevent_t *event, *next_event;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_task_t *task;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_result_t iresult;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff /*
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff * The caller must be holding the proper lock.
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff */
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff FCTXTRACE("done");
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff REQUIRE(fctx->state == fetchstate_active);
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff fctx->state = fetchstate_done;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff for (event = ISC_LIST_HEAD(fctx->events);
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff event != NULL;
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff event = next_event) {
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff next_event = ISC_LIST_NEXT(event, link);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff task = event->sender;
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff event->sender = fctx;
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff event->result = result;
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff iresult = isc_task_send(task, (isc_event_t **)&event);
62e4837585f2d48ce9ef3ad6880d8fb75a578e58Andreas Gustafsson if (iresult != ISC_R_SUCCESS) {
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff UNEXPECTED_ERROR(__FILE__, __LINE__,
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff "isc_task_send(): %s",
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff isc_result_totext(iresult));
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff isc_event_free((isc_event_t **)&event);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff }
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff isc_task_detach(&task);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff }
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff ISC_LIST_INIT(fctx->events);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff}
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graffstatic dns_result_t
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Grafffctx_sendquery(fetchctx_t *fctx) {
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff resquery_t *query;
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff FCTXTRACE("sendquery");
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff query = isc_mem_get(fctx->res->mctx, sizeof *query);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff if (query == NULL)
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff return (DNS_R_NOMEMORY);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff ISC_LIST_APPEND(fctx->queries, query, link);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff /* XXXRTH do the rest of the work... */
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff return (DNS_R_SUCCESS);
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff}
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graffstatic void
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Grafffctx_cancelqueries(fetchctx_t *fctx) {
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff resquery_t *query, *next_query;
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff FCTXTRACE("cancelqueries");
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff for (query = ISC_LIST_HEAD(fctx->queries);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff query != NULL;
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff query = next_query) {
e24f605ad64182532640dc6721070456b13112d5Michael Graff next_query = ISC_LIST_NEXT(query, link);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff /* XXXRTH do the rest of the work... */
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff isc_mem_put(fctx->res->mctx, query, sizeof *query);
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff }
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff ISC_LIST_INIT(fctx->queries);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff}
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff
4e675038a097065ff13944232cd7c89ac5961984Michael Graffstatic void
4e675038a097065ff13944232cd7c89ac5961984Michael Grafffctx_restart(fetchctx_t *fctx) {
4e675038a097065ff13944232cd7c89ac5961984Michael Graff isc_result_t iresult;
4e675038a097065ff13944232cd7c89ac5961984Michael Graff dns_result_t result;
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff
4e675038a097065ff13944232cd7c89ac5961984Michael Graff /*
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff * Caller must be holding the fetch's lock.
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff */
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff REQUIRE(fctx->state = fetchstate_active);
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff FCTXTRACE("restart");
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff iresult = isc_timer_reset(fctx->timer, isc_timertype_once,
e24f605ad64182532640dc6721070456b13112d5Michael Graff &fctx->expires, &fctx->interval,
e24f605ad64182532640dc6721070456b13112d5Michael Graff ISC_FALSE);
e24f605ad64182532640dc6721070456b13112d5Michael Graff if (iresult != ISC_R_SUCCESS) {
e24f605ad64182532640dc6721070456b13112d5Michael Graff UNEXPECTED_ERROR(__FILE__, __LINE__,
e24f605ad64182532640dc6721070456b13112d5Michael Graff "isc_timer_reset(): %s",
e24f605ad64182532640dc6721070456b13112d5Michael Graff isc_result_totext(iresult));
e24f605ad64182532640dc6721070456b13112d5Michael Graff fctx_done(fctx, DNS_R_UNEXPECTED);
e24f605ad64182532640dc6721070456b13112d5Michael Graff }
291b0d910d115e41a4b69d0603c3376aebf0c630Michael Graff
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff result = fctx_sendquery(fctx);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff if (result != DNS_R_SUCCESS)
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff fctx_done(fctx, result);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff}
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
e24f605ad64182532640dc6721070456b13112d5Michael Graffstatic void
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Grafffctx_destroy(fetchctx_t *fctx) {
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff REQUIRE(VALID_FCTX(fctx));
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff REQUIRE(fctx->state == fetchstate_done);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff REQUIRE(ISC_LIST_EMPTY(fctx->events));
e24f605ad64182532640dc6721070456b13112d5Michael Graff REQUIRE(ISC_LIST_EMPTY(fctx->queries));
e24f605ad64182532640dc6721070456b13112d5Michael Graff
e24f605ad64182532640dc6721070456b13112d5Michael Graff FCTXTRACE("destroy");
e24f605ad64182532640dc6721070456b13112d5Michael Graff
e24f605ad64182532640dc6721070456b13112d5Michael Graff isc_timer_detach(&fctx->timer);
e24f605ad64182532640dc6721070456b13112d5Michael Graff dns_name_free(&fctx->name, fctx->res->mctx);
e24f605ad64182532640dc6721070456b13112d5Michael Graff isc_mem_put(fctx->res->mctx, fctx, sizeof *fctx);
e24f605ad64182532640dc6721070456b13112d5Michael Graff}
e24f605ad64182532640dc6721070456b13112d5Michael Graff
e24f605ad64182532640dc6721070456b13112d5Michael Graff/*
e24f605ad64182532640dc6721070456b13112d5Michael Graff * Fetch event handlers.
e24f605ad64182532640dc6721070456b13112d5Michael Graff */
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graffstatic void
e24f605ad64182532640dc6721070456b13112d5Michael Grafffctx_timeout(isc_task_t *task, isc_event_t *event) {
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff fetchctx_t *fctx = event->arg;
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff REQUIRE(VALID_FCTX(fctx));
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff (void)task; /* Keep compiler quiet. */
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff FCTXTRACE("timeout");
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff LOCK(&fctx->res->lock);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff INSIST(fctx->state == fetchstate_active);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff if (event->type == ISC_TIMEREVENT_LIFE) {
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff fctx_cancelqueries(fctx);
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff fctx_done(fctx, DNS_R_TIMEDOUT);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff } else {
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff /*
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff * We could cancel the running queries here, or we could let
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff * them keep going. Right now we choose the latter...
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff */
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff fctx_restart(fctx);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff }
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff UNLOCK(&fctx->res->lock);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff isc_event_free(&event);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff}
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graffstatic void
74889a341cac183d477e15cfead391a8f7bdba95Michael Grafffctx_start(isc_task_t *task, isc_event_t *event) {
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff fetchctx_t *fctx = event->arg;
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff isc_boolean_t need_fctx_destroy = ISC_FALSE;
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff isc_boolean_t need_resolver_destroy = ISC_FALSE;
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff dns_resolver_t *res;
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff REQUIRE(VALID_FCTX(fctx));
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff res = fctx->res;
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff (void)task; /* Keep compiler quiet. */
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff FCTXTRACE("start");
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff LOCK(&res->lock);
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff INSIST(fctx->state == fetchstate_init ||
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff fctx->state == fetchstate_exiting);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff if (fctx->state == fetchstate_init) {
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff fctx->state = fetchstate_active;
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff fctx_restart(fctx);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff } else {
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff fctx->state = fetchstate_done;
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff need_fctx_destroy = ISC_TRUE;
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff if (res->exiting && ISC_LIST_EMPTY(res->fctxs))
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff need_resolver_destroy = ISC_TRUE;
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff }
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff UNLOCK(&res->lock);
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff if (need_fctx_destroy)
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff fctx_destroy(fctx);
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff if (need_resolver_destroy)
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff destroy(res);
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff}
7dbf5a0b64237aa3052f04f4c8f7d56be8ec5d79Michael Graff
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff/*
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff * Fetch Creation, Joining, and Cancelation.
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff */
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graffstatic inline dns_result_t
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Grafffctx_join(fetchctx_t *fctx, isc_task_t *task, isc_taskaction_t action,
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff void *arg, dns_fetch_t *fetch)
1a0e33bc2044e1902493111db14cbf793083ac47Michael Graff{
e24f605ad64182532640dc6721070456b13112d5Michael Graff isc_task_t *clone;
4e675038a097065ff13944232cd7c89ac5961984Michael Graff dns_fetchdoneevent_t *event;
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff FCTXTRACE("join");
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff /*
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff * We store the task we're going to send this event to in the
e24f605ad64182532640dc6721070456b13112d5Michael Graff * sender field. We'll make the fetch the sender when we actually
e24f605ad64182532640dc6721070456b13112d5Michael Graff * send the event.
e24f605ad64182532640dc6721070456b13112d5Michael Graff */
c05e003dce672b2f8555a3e56857f29ce89c1677Michael Graff clone = NULL;
2311073ce0ef26c0250e91e4a083d7cc94fa7d33Michael Graff isc_task_attach(task, &clone);
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff event = (dns_fetchdoneevent_t *)
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff isc_event_allocate(fctx->res->mctx, clone,
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff DNS_EVENT_FETCHDONE,
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff action, arg, sizeof *event);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff if (event == NULL)
74889a341cac183d477e15cfead391a8f7bdba95Michael Graff return (DNS_R_NOMEMORY);
ae7d0a4375abaecfd5c5b0816616d9882831e69bMichael Graff event->result = DNS_R_SUCCESS;
e4f074a2c2340ea80099beebecc3b89aa234fa8fMichael Graff event->tag = fctx->next_tag++;
a3ab70dae26d009bf78b0594b2ab5eb9208f4b91Michael Graff INSIST(fctx->next_tag != 0);
/*
* XXX other event initialization here.
*/
ISC_LIST_APPEND(fctx->events, event, link);
fctx->references++;
fetch->magic = DNS_FETCH_MAGIC;
fetch->res = fctx->res;
fetch->private = fctx;
fetch->tag = event->tag;
ISC_LINK_INIT(fetch, link);
return (DNS_R_SUCCESS);
}
static dns_result_t
fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
unsigned int options,
isc_task_t *worker, isc_task_t *task, isc_taskaction_t action,
void *arg, dns_fetch_t *fetch)
{
fetchctx_t *fctx;
dns_result_t result = DNS_R_SUCCESS;
isc_result_t iresult;
isc_event_t *event;
isc_interval_t interval;
fctx = isc_mem_get(res->mctx, sizeof *fctx);
if (fctx == NULL)
return (DNS_R_NOMEMORY);
FCTXTRACE("create");
result = dns_name_dup(name, res->mctx, NULL, &fctx->name);
if (result != DNS_R_SUCCESS)
goto cleanup_fetch;
fctx->type = type;
fctx->options = options;
fctx->res = res;
fctx->references = 0;
fctx->locknum = 0;
fctx->state = fetchstate_init;
fctx->dispatcher = NULL; /* XXX */
fctx->next_tag = 1;
ISC_LIST_INIT(fctx->queries);
fctx->message = NULL;
result = dns_message_create(res->mctx, &fctx->message,
DNS_MESSAGE_INTENTPARSE);
if (result != DNS_R_SUCCESS)
goto cleanup_name;
/*
* Compute an expiration time for the entire fetch.
*/
isc_interval_set(&interval, 10, 0); /* XXXRTH constant */
iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_stdtime_get: %s",
isc_result_totext(iresult));
result = DNS_R_UNEXPECTED;
goto cleanup_message;
}
/*
* XXX Retry interval initialization. Should be setup by the
* transmission strategy routine (when we have one).
*/
isc_interval_set(&fctx->interval, 1, 500000000);
/*
* Create an inactive timer. It will be made active when the fetch
* is actually started.
*/
iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
NULL, NULL,
worker, fctx_timeout,
fctx, &fctx->timer);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_timer_create: %s",
isc_result_totext(iresult));
result = DNS_R_UNEXPECTED;
goto cleanup_message;
}
ISC_LIST_INIT(fctx->events);
result = fctx_join(fctx, task, action, arg, fetch);
if (result != DNS_R_SUCCESS)
goto cleanup_timer;
ISC_LINK_INIT(fctx, link);
fctx->magic = FCTX_MAGIC;
/*
* The fetch is now ready to go. We send the start event to its
* task to get the ball rolling.
*
* XXX we should really send this event from dns_resolver_fetch(),
* after we've unlocked the fetch's lock, otherwise the other task
* could well block on the lock we're about to release.
*/
event = &fctx->start_event;
ISC_EVENT_INIT(event, sizeof *event, 0, 0, DNS_EVENT_FETCH,
fctx_start, fctx, (void *)fctx_create, NULL, NULL);
iresult = isc_task_send(worker, &event);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_task_send: %s",
isc_result_totext(iresult));
result = DNS_R_UNEXPECTED;
goto cleanup_timer;
}
return (DNS_R_SUCCESS);
cleanup_timer:
isc_timer_detach(&fctx->timer);
cleanup_message:
dns_message_destroy(&fctx->message);
cleanup_name:
dns_name_free(&fctx->name, res->mctx);
cleanup_fetch:
isc_mem_put(res->mctx, fctx, sizeof *fctx);
return (result);
}
static void
fctx_cancel(fetchctx_t *fctx) {
isc_result_t iresult;
FCTXTRACE("cancel");
if (fctx->state != fetchstate_done) {
fctx_cancelqueries(fctx);
iresult = isc_timer_reset(fctx->timer, isc_timertype_inactive,
NULL, NULL, ISC_TRUE);
if (iresult != ISC_R_SUCCESS)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_timer_reset(): %s",
isc_result_totext(iresult));
fctx_done(fctx, DNS_R_CANCELED);
}
}
/*
* Handle Responses
*/
static inline dns_result_t
same_question(fetchctx_t *fctx) {
dns_result_t result;
dns_message_t *message = fctx->message;
dns_name_t *name;
dns_rdataset_t *rdataset;
/*
* Caller must be holding the fctx lock.
*/
/*
* XXXRTH Currently we support only one question.
*/
if (message->counts[DNS_SECTION_QUESTION] != 1)
return (DNS_R_FORMERR);
result = dns_message_firstname(message, DNS_SECTION_QUESTION);
if (result != DNS_R_SUCCESS)
return (result);
name = NULL;
dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
rdataset = ISC_LIST_HEAD(name->list);
INSIST(rdataset != NULL);
INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
if (fctx->type != rdataset->type ||
fctx->res->rdclass != rdataset->rdclass ||
!dns_name_equal(&fctx->name, name))
return (DNS_R_FORMERR);
return (DNS_R_SUCCESS);
}
static void
fctx_response(isc_task_t *task, isc_event_t *event) {
dns_result_t result;
fetchctx_t *fctx = event->arg;
dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
isc_boolean_t bad_sender = ISC_FALSE;
dns_message_t *message;
REQUIRE(VALID_FCTX(fctx));
REQUIRE(event->type == DNS_EVENT_DISPATCH);
LOCK(&fctx->res->lock);
INSIST(fctx->state == fetchstate_active);
message = fctx->message;
result = dns_message_parse(message, &devent->buffer);
if (result != DNS_R_SUCCESS) {
switch (result) {
case DNS_R_FORMERR:
case DNS_R_UNEXPECTEDEND:
bad_sender = ISC_TRUE;
break;
case DNS_R_MOREDATA:
result = DNS_R_NOTIMPLEMENTED;
break;
}
goto done;
}
INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
/*
* INSIST() that the message comes from the place we sent it to,
* since the dispatch code should ensure this.
*
* INSIST() that the message id is correct (this should also be
* ensured by the dispatch code).
*/
/*
* Is it a query response?
*/
if (message->opcode != dns_opcode_query) {
/* XXXRTH Log */
bad_sender = ISC_TRUE;
goto done;
}
/*
* Is the remote server broken, or does it dislike us?
*/
if (message->rcode != dns_rcode_noerror &&
message->rcode != dns_rcode_nxdomain) {
bad_sender = ISC_TRUE;
/*
* XXXRTH If we want to catch a FORMERR caused by an EDNS0
* OPT RR, this is the place to do it.
*/
goto done;
}
/*
* Does the it answer the question we asked?
*/
result = same_question(fctx);
if (result != DNS_R_SUCCESS) {
/* XXXRTH Log */
if (result == DNS_R_FORMERR)
bad_sender = ISC_TRUE;
goto done;
}
result = DNS_R_SUCCESS;
done:
/*
* XXXRTH Record round-trip statistics here.
*/
if (bad_sender) {
/*
* XXXRTH We will mark the sender as bad here instead
* of doing the printf().
*/
printf("bad sender\n");
/*
* Keep trying.
*/
fctx_restart(fctx);
} else {
/*
* All is well, or we got an error fatal to the fetch.
* In either case, we're done.
*/
fctx_done(fctx, result);
}
UNLOCK(&fctx->res->lock);
isc_event_free(&event);
}
/***
*** Resolver Methods
***/
static void
destroy(dns_resolver_t *res) {
unsigned int i;
REQUIRE(res->exiting);
REQUIRE(res->references == 0);
REQUIRE(ISC_LIST_EMPTY(res->fctxs));
RTRACE("destroy");
isc_mutex_destroy(&res->lock);
for (i = 0; i < res->ntasks; i++) {
isc_task_shutdown(res->tasks[i]);
isc_task_detach(&res->tasks[i]);
}
isc_mem_put(res->mctx, res->tasks,
res->ntasks * sizeof (isc_task_t *));
res->magic = 0;
isc_mem_put(res->mctx, res, sizeof *res);
}
dns_result_t
dns_resolver_create(isc_mem_t *mctx,
isc_taskmgr_t *taskmgr, unsigned int ntasks,
isc_timermgr_t *timermgr,
dns_rdataclass_t rdclass,
dns_dispatch_t *dispatcher,
dns_resolver_t **resp)
{
dns_resolver_t *res;
dns_result_t result = DNS_R_SUCCESS;
isc_result_t iresult;
unsigned int i, tasks_created = 0;
REQUIRE(resp != NULL && *resp == NULL);
REQUIRE(ntasks > 0);
res = isc_mem_get(mctx, sizeof *res);
if (res == NULL)
return (DNS_R_NOMEMORY);
RTRACE("create");
res->mctx = mctx;
res->rdclass = rdclass;
res->timermgr = timermgr;
res->ntasks = ntasks;
res->next_task = 0;
res->shared_dispatcher = dispatcher; /* XXXRTH: attach! */
res->tasks = isc_mem_get(mctx, ntasks * sizeof (isc_task_t *));
if (res->tasks == NULL) {
result = DNS_R_NOMEMORY;
goto cleanup_res;
}
for (i = 0; i < ntasks; i++) {
res->tasks[i] = NULL;
iresult = isc_task_create(taskmgr, mctx, 0, &res->tasks[i]);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_task_create() failed: %s",
isc_result_totext(iresult));
result = DNS_R_UNEXPECTED;
goto cleanup_tasks;
}
tasks_created++;
}
res->references = 1;
res->exiting = ISC_FALSE;
iresult = isc_mutex_init(&res->lock);
if (iresult != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() failed: %s",
isc_result_totext(iresult));
result = DNS_R_UNEXPECTED;
goto cleanup_tasks;
}
ISC_LIST_INIT(res->fctxs);
res->magic = RES_MAGIC;
*resp = res;
return (DNS_R_SUCCESS);
cleanup_tasks:
for (i = 0; i < tasks_created; i++) {
isc_task_shutdown(res->tasks[i]);
isc_task_detach(&res->tasks[i]);
}
isc_mem_put(mctx, res->tasks, res->ntasks * sizeof (isc_task_t *));
cleanup_res:
isc_mem_put(mctx, res, sizeof *res);
return (result);
}
void
dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
REQUIRE(VALID_RESOLVER(source));
REQUIRE(targetp != NULL && *targetp == NULL);
RRTRACE(source, "attach");
LOCK(&source->lock);
REQUIRE(!source->exiting);
INSIST(source->references > 0);
source->references++;
INSIST(source->references != 0);
UNLOCK(&source->lock);
*targetp = source;
}
void
dns_resolver_detach(dns_resolver_t **resp) {
dns_resolver_t *res;
isc_boolean_t need_destroy = ISC_FALSE;
fetchctx_t *fctx;
REQUIRE(resp != NULL);
res = *resp;
REQUIRE(VALID_RESOLVER(res));
RTRACE("detach");
LOCK(&res->lock);
INSIST(res->references > 0);
res->references--;
if (res->references == 0) {
RTRACE("exiting");
res->exiting = ISC_TRUE;
for (fctx = ISC_LIST_HEAD(res->fctxs);
fctx != NULL;
fctx = ISC_LIST_NEXT(fctx, link))
fctx_cancel(fctx);
if (ISC_LIST_EMPTY(res->fctxs))
need_destroy = ISC_TRUE;
}
UNLOCK(&res->lock);
if (need_destroy)
destroy(res);
*resp = NULL;
}
static inline isc_boolean_t
fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
unsigned int options)
{
if (fctx->type != type || fctx->options != options)
return (ISC_FALSE);
return (dns_name_equal(&fctx->name, name));
}
dns_result_t
dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
dns_rdatatype_t type,
dns_delegation_t *delegation,
dns_forwarders_t *forwarders,
unsigned int options, isc_task_t *task,
isc_taskaction_t action, void *arg,
dns_fetch_t **fetchp)
{
dns_fetch_t *fetch;
fetchctx_t *fctx = NULL;
dns_result_t result;
isc_task_t *worker;
(void)delegation;
(void)forwarders;
REQUIRE(VALID_RESOLVER(res));
REQUIRE(fetchp != NULL && *fetchp == NULL);
/*
* We require !res->exiting, since if it were exiting, that would
* mean that the reference count was wrong!
*/
REQUIRE(!res->exiting);
RTRACE("createfetch");
/* XXXRTH */
if ((options & DNS_FETCHOPT_TCP) != 0)
return (DNS_R_NOTIMPLEMENTED);
fetch = isc_mem_get(res->mctx, sizeof *fetch);
if (fetch == NULL)
return (DNS_R_NOMEMORY);
LOCK(&res->lock);
/*
* XXXRTH This is for correctness, and doesn't represent the final
* way of assigning tasks, or the final form of the fetch table.
*/
worker = res->tasks[res->next_task];
res->next_task++;
if (res->next_task == res->ntasks)
res->next_task = 0;
if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
for (fctx = ISC_LIST_HEAD(res->fctxs);
fctx != NULL;
fctx = ISC_LIST_NEXT(fctx, link)) {
if (fctx_match(fctx, name, type, options))
break;
}
}
if (fctx == NULL || fctx->state == fetchstate_done) {
result = fctx_create(res,
name, type, options,
worker,
task, action, arg,
fetch);
if (result == DNS_R_SUCCESS) {
fctx = fetch->private;
ISC_LIST_APPEND(res->fctxs, fctx, link);
}
} else
result = fctx_join(fctx, task, action, arg, fetch);
UNLOCK(&res->lock);
if (result == DNS_R_SUCCESS) {
FTRACE("created");
*fetchp = fetch;
} else
isc_mem_put(res->mctx, fetch, sizeof *fetch);
return (result);
}
void
dns_resolver_destroyfetch(dns_fetch_t **fetchp, isc_task_t *task) {
dns_fetch_t *fetch;
dns_fetchdoneevent_t *event, *next_event;
fetchctx_t *fctx;
dns_resolver_t *res;
isc_boolean_t need_fctx_destroy = ISC_FALSE;
isc_boolean_t need_resolver_destroy = ISC_FALSE;
isc_task_t *etask;
isc_mem_t *mctx;
/*
* XXXRTH We could make it so that even if all the clients detach
* from the fetch, the fctx keeps going. Perhaps this should be
* a resolver option? Right now if they all go away the fctx will
* be destroyed too.
*/
REQUIRE(fetchp != NULL);
fetch = *fetchp;
REQUIRE(DNS_FETCH_VALID(fetch));
res = fetch->res;
fctx = fetch->private;
FTRACE("destroyfetch");
LOCK(&res->lock);
event = NULL;
if (fctx->state != fetchstate_done) {
for (event = ISC_LIST_HEAD(fctx->events);
event != NULL;
event = next_event) {
next_event = ISC_LIST_NEXT(event, link);
if (event->tag == fetch->tag) {
ISC_LIST_UNLINK(fctx->events, event, link);
FTRACE("found");
break;
}
}
} else if (task != NULL)
(void)isc_task_purge(task, fctx, DNS_EVENT_FETCHDONE,
fetch->tag);
INSIST(fctx->references > 0);
fctx->references--;
if (fctx->references == 0) {
ISC_LIST_UNLINK(res->fctxs, fctx, link);
if (fctx->state == fetchstate_init) {
/*
* The fctx is still initializing, which means that
* the start event either hasn't been delivered, or
* is being processed right now, but is blocked waiting
* for the lock.
*
* Rather than try to purge the event, we simply
* wait for it to happen, deferring further destruction
* until it has been processed.
*/
fctx->state = fetchstate_exiting;
} else {
need_fctx_destroy = ISC_TRUE;
if (res->exiting && ISC_LIST_EMPTY(res->fctxs))
need_resolver_destroy = ISC_TRUE;
}
}
UNLOCK(&res->lock);
isc_mem_put(res->mctx, fetch, sizeof *fetch);
*fetchp = NULL;
if (event != NULL) {
etask = event->sender;
isc_task_detach(&etask);
isc_event_free((isc_event_t **)&event);
}
if (need_fctx_destroy)
fctx_destroy(fctx);
if (need_resolver_destroy)
destroy(res);
}