resolver.c revision f26747f494f2e02ffb72b022cc1c54abb58269f4
#include <config.h>
#include <isc/assertions.h>
#include <dns/dispatch.h>
#include <dns/resolver.h>
#define DNS_RESOLVER_TRACE
#ifdef DNS_RESOLVER_TRACE
#else
#define RTRACE(m)
#define RRTRACE(r, m)
#define FCTXTRACE(m)
#define FTRACE(m)
#endif
typedef struct query {
unsigned char data[512];
} resquery_t;
typedef enum {
fetchstate_init = 0,
} fetchstate;
typedef struct fetchctx {
unsigned int magic;
unsigned int references;
unsigned int locknum;
unsigned int options;
/* Locked by lock. */
isc_timer_t * timer;
} fetchctx_t;
struct dns_resolver {
/* Unlocked */
unsigned int magic;
/* Locked by lock. */
unsigned int references;
unsigned int ntasks;
unsigned int next_task;
isc_task_t ** tasks;
};
/*
* Internal fetch routines. Caller must be holding the proper lock.
*/
static inline dns_result_t
if (iresult != ISC_R_SUCCESS) {
"isc_timer_reset(): %s",
return (DNS_R_UNEXPECTED);
}
return (DNS_R_SUCCESS);
}
static inline void
/*
* We don't return a result if resetting the timer to inactive fails
* since there's nothing to be done about it. Resetting to inactive
* should never fail anyway, since the code as currently written
* cannot fail in that case.
*/
if (iresult != ISC_R_SUCCESS) {
"isc_timer_reset(): %s",
}
}
static void
/*
* The caller must be holding the proper lock.
*/
FCTXTRACE("done");
event = next_event) {
if (iresult != ISC_R_SUCCESS) {
"isc_task_send(): %s",
}
}
}
static dns_result_t
FCTXTRACE("sendquery");
if (result != DNS_R_SUCCESS)
return (result);
return (DNS_R_NOMEMORY);
/*
* XXXRTH get query id from dispatcher...
*/
/*
* Set up question.
*/
/*
* We don't have to set opcode because it defaults to query.
*/
/*
* recipient.
*/
if (result != DNS_R_SUCCESS)
goto done;
DNS_SECTION_QUESTION, 0, 0);
if (result != DNS_R_SUCCESS)
goto done;
DNS_SECTION_ADDITIONAL, 0, 0);
if (result != DNS_R_SUCCESS)
goto done;
DNS_SECTION_TSIG, 0, 0);
if (result != DNS_R_SUCCESS)
goto done;
if (result != DNS_R_SUCCESS)
goto done;
/* XXXRTH do the rest of the work... */
/*
* Finally, we've got everything going!
*/
done:
/*
* It's imperative that we reset the message here, because
* the rdataset used for the question is on our stack, and won't
* be valid after we return.
*/
if (result != DNS_R_SUCCESS)
return (result);
}
static void
FCTXTRACE("cancelqueries");
query = next_query) {
/* XXXRTH do the rest of the work... */
}
}
static void
/*
* Caller must be holding the fetch's lock.
*/
FCTXTRACE("try");
/*
* XXXRTH Consult our try strategy routine here, figure out who to
* send a query (or queries) to next, and then do it. If
* we've exhaused all our servers for this set of tries,
* start again by finding more addresses.
*/
if (result != DNS_R_SUCCESS)
}
static void
FCTXTRACE("destroy");
}
/*
* Fetch event handlers.
*/
static void
(void)task; /* Keep compiler quiet. */
FCTXTRACE("timeout");
} else {
/*
* We could cancel the running queries here, or we could let
* them keep going. Right now we choose the latter...
*/
}
}
static void
(void)task; /* Keep compiler quiet. */
FCTXTRACE("start");
} else {
}
if (need_fctx_destroy)
}
/*
* Fetch Creation, Joining, and Cancelation.
*/
static inline dns_result_t
{
FCTXTRACE("join");
/*
* We store the task we're going to send this event to in the
* sender field. We'll make the fetch the sender when we actually
* send the event.
*/
event = (dns_fetchdoneevent_t *)
return (DNS_R_NOMEMORY);
/*
* XXX other event initialization here.
*/
fctx->references++;
return (DNS_R_SUCCESS);
}
static dns_result_t
unsigned int options,
{
return (DNS_R_NOMEMORY);
FCTXTRACE("create");
if (result != DNS_R_SUCCESS)
goto cleanup_fetch;
fctx->references = 0;
if (result != DNS_R_SUCCESS)
goto cleanup_name;
if (result != DNS_R_SUCCESS)
goto cleanup_qmessage;
/*
* Compute an expiration time for the entire fetch.
*/
if (iresult != ISC_R_SUCCESS) {
"isc_stdtime_get: %s",
goto cleanup_rmessage;
}
/*
* XXX Retry interval initialization. Should be setup by the
* transmission strategy routine (when we have one).
*/
/*
* Create an inactive timer. It will be made active when the fetch
* is actually started.
*/
if (iresult != ISC_R_SUCCESS) {
"isc_timer_create: %s",
goto cleanup_rmessage;
}
if (result != DNS_R_SUCCESS)
goto cleanup_timer;
/*
* 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.
*/
if (iresult != ISC_R_SUCCESS) {
"isc_task_send: %s",
goto cleanup_timer;
}
return (DNS_R_SUCCESS);
return (result);
}
static void
FCTXTRACE("cancel");
if (iresult != ISC_R_SUCCESS)
"isc_timer_reset(): %s",
}
}
/*
* Handle Responses
*/
static inline dns_result_t
/*
* Caller must be holding the fctx lock.
*/
/*
* XXXRTH Currently we support only one question.
*/
return (DNS_R_FORMERR);
if (result != DNS_R_SUCCESS)
return (result);
return (DNS_R_FORMERR);
return (DNS_R_SUCCESS);
}
static void
(void)task;
if (result != DNS_R_SUCCESS) {
switch (result) {
case DNS_R_FORMERR:
case DNS_R_UNEXPECTEDEND:
break;
case DNS_R_MOREDATA:
break;
}
goto done;
}
/*
* 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?
*/
/* XXXRTH Log */
goto done;
}
/*
* Is the remote server broken, or does it dislike us?
*/
/*
* 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?
*/
if (result != DNS_R_SUCCESS) {
/* XXXRTH Log */
if (result == DNS_R_FORMERR)
goto done;
}
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.
*/
} else {
/*
* All is well, or we got an error fatal to the fetch.
* In either case, we're done.
*/
}
}
/***
*** Resolver Methods
***/
static void
unsigned int i;
RTRACE("destroy");
}
}
{
unsigned int i, tasks_created = 0;
return (DNS_R_NOMEMORY);
RTRACE("create");
goto cleanup_res;
}
for (i = 0; i < ntasks; i++) {
if (iresult != ISC_R_SUCCESS) {
"isc_task_create() failed: %s",
goto cleanup_tasks;
}
}
if (iresult != ISC_R_SUCCESS) {
"isc_mutex_init() failed: %s",
goto cleanup_tasks;
}
return (DNS_R_SUCCESS);
for (i = 0; i < tasks_created; i++) {
}
return (result);
}
void
source->references++;
}
void
RTRACE("detach");
res->references--;
if (res->references == 0) {
RTRACE("exiting");
}
if (need_destroy)
}
static inline isc_boolean_t
unsigned int options)
{
return (ISC_FALSE);
}
{
(void)delegation;
(void)forwarders;
/*
* We require !res->exiting, since if it were exiting, that would
* mean that the reference count was wrong!
*/
RTRACE("createfetch");
/* XXXRTH */
if ((options & DNS_FETCHOPT_TCP) != 0)
return (DNS_R_NOTIMPLEMENTED);
return (DNS_R_NOMEMORY);
/*
* XXXRTH This is for correctness, and doesn't represent the final
* way of assigning tasks, or the final form of the fetch table.
*/
if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
break;
}
}
fetch);
if (result == DNS_R_SUCCESS) {
}
} else
if (result == DNS_R_SUCCESS) {
FTRACE("created");
} else
return (result);
}
void
/*
* 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.
*/
FTRACE("destroyfetch");
event = next_event) {
FTRACE("found");
break;
}
}
fctx->references--;
if (fctx->references == 0) {
/*
* 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.
*/
} else {
}
}
}
if (need_fctx_destroy)
}