Commit 61b103da authored by Bob Halley's avatar Bob Halley
Browse files

RTT support

parent 28ab8277
......@@ -92,6 +92,8 @@ typedef struct query {
unsigned int magic;
fetchctx_t * fctx;
dns_dispatch_t * dispatch;
dns_adbaddrinfo_t * addrinfo;
isc_time_t start;
/* Locked by fctx lock. */
dns_messageid_t id;
dns_dispentry_t * dispentry; /* XXX name */
......@@ -138,9 +140,10 @@ struct fetchctx {
dns_message_t * qmessage;
dns_message_t * rmessage;
ISC_LIST(resquery_t) queries;
ISC_LIST(dns_adbfind_t) finds;
dns_adbfindlist_t finds;
dns_adbfind_t * find;
unsigned int pending;
unsigned int restarts;
};
#define FCTX_MAGIC 0x46212121U /* F!!! */
......@@ -246,17 +249,42 @@ fctx_stoptimer(fetchctx_t *fctx) {
}
}
static inline void
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp) {
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
isc_time_t *finish)
{
fetchctx_t *fctx;
resquery_t *query;
unsigned int rtt;
isc_time_t now;
unsigned int factor;
query = *queryp;
fctx = query->fctx;
FCTXTRACE("cancelquery");
if (finish != NULL) {
rtt = (unsigned int)isc_time_microdiff(finish, &query->start);
factor = 0;
} else {
/*
* We don't have an RTT for this query. Maybe the packet
* was lost, or maybe this server is very slow. We don't
* know. Increase the RTT.
*/
rtt = query->addrinfo->srtt + (100000 * fctx->restarts);
if (rtt > 10000000)
rtt = 10000000;
/*
* We set 'factor' to 1, so that we will replace the current
* RTT.
*/
factor = 1;
}
dns_adb_adjustsrtt(fctx->res->view->adb, query->addrinfo, rtt, factor);
dns_dispatch_removeresponse(query->dispatch, &query->dispentry,
deventp);
ISC_LIST_UNLINK(fctx->queries, query, link);
......@@ -277,7 +305,7 @@ fctx_cancelqueries(fetchctx_t *fctx) {
query != NULL;
query = next_query) {
next_query = ISC_LIST_NEXT(query, link);
fctx_cancelquery(&query, NULL);
fctx_cancelquery(&query, NULL, NULL);
}
}
......@@ -285,6 +313,8 @@ static void
fctx_cleanupfinds(fetchctx_t *fctx) {
dns_adbfind_t *find, *next_find;
REQUIRE(ISC_LIST_EMPTY(fctx->queries));
for (find = ISC_LIST_HEAD(fctx->finds);
find != NULL;
find = next_find) {
......@@ -298,8 +328,8 @@ fctx_cleanupfinds(fetchctx_t *fctx) {
static inline void
fctx_stopeverything(fetchctx_t *fctx) {
FCTXTRACE("stopeverything");
fctx_cleanupfinds(fctx);
fctx_cancelqueries(fctx);
fctx_cleanupfinds(fctx);
fctx_stoptimer(fctx);
}
......@@ -364,13 +394,13 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
(void)task;
if (sevent->result != ISC_R_SUCCESS)
fctx_cancelquery(&query, NULL);
fctx_cancelquery(&query, NULL, NULL);
isc_event_free(&event);
}
static isc_result_t
fctx_sendquery(fetchctx_t *fctx, isc_sockaddr_t *address) {
fctx_sendquery(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
resquery_t *query;
isc_result_t result;
dns_rdataset_t *qrdataset;
......@@ -400,10 +430,20 @@ fctx_sendquery(fetchctx_t *fctx, isc_sockaddr_t *address) {
goto cleanup_temps;
query = isc_mem_get(res->mctx, sizeof *query);
if (query == NULL)
return (ISC_R_NOMEMORY);
if (query == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup_temps;
}
isc_buffer_init(&query->buffer, query->data, sizeof query->data,
ISC_BUFFERTYPE_BINARY);
/*
* Note that the caller MUST guarantee that 'addrinfo' will remain
* valid until this query is canceled.
*/
query->addrinfo = addrinfo;
result = isc_time_now(&query->start);
if (result != ISC_R_SUCCESS)
goto cleanup_query;
/*
* If this is a TCP query, then we need to make a socket and
......@@ -417,7 +457,7 @@ fctx_sendquery(fetchctx_t *fctx, isc_sockaddr_t *address) {
result = DNS_R_NOTIMPLEMENTED;
goto cleanup_query;
} else {
switch (isc_sockaddr_pf(address)) {
switch (isc_sockaddr_pf(addrinfo->sockaddr)) {
case AF_INET:
query->dispatch = res->dispatch4;
break;
......@@ -443,7 +483,7 @@ fctx_sendquery(fetchctx_t *fctx, isc_sockaddr_t *address) {
*/
query->dispentry = NULL;
result = dns_dispatch_addresponse(query->dispatch,
address,
addrinfo->sockaddr,
task,
resquery_response,
query,
......@@ -513,7 +553,7 @@ fctx_sendquery(fetchctx_t *fctx, isc_sockaddr_t *address) {
isc_buffer_used(&query->buffer, &r);
result = isc_socket_sendto(dns_dispatch_getsocket(query->dispatch),
&r, task, resquery_senddone,
query, address);
query, addrinfo->sockaddr);
if (result != ISC_R_SUCCESS)
goto cleanup_message;
......@@ -612,6 +652,61 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
empty_bucket(res);
}
static void
sort_adbfind(dns_adbfind_t *find) {
dns_adbaddrinfo_t *best, *curr;
dns_adbaddrinfolist_t sorted;
/*
* Lame N^2 bubble sort.
*/
ISC_LIST_INIT(sorted);
while (!ISC_LIST_EMPTY(find->list)) {
best = ISC_LIST_HEAD(find->list);
curr = ISC_LIST_NEXT(best, publink);
while (curr != NULL) {
if (curr->srtt < best->srtt)
best = curr;
curr = ISC_LIST_NEXT(curr, publink);
}
ISC_LIST_UNLINK(find->list, best, publink);
ISC_LIST_APPEND(sorted, best, publink);
}
find->list = sorted;
}
static void
sort_finds(fetchctx_t *fctx) {
dns_adbfind_t *best, *curr;
dns_adbfindlist_t sorted;
dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
/*
* Lame N^2 bubble sort.
*/
ISC_LIST_INIT(sorted);
while (!ISC_LIST_EMPTY(fctx->finds)) {
best = ISC_LIST_HEAD(fctx->finds);
bestaddrinfo = ISC_LIST_HEAD(best->list);
INSIST(bestaddrinfo != NULL);
curr = ISC_LIST_NEXT(best, publink);
while (curr != NULL) {
addrinfo = ISC_LIST_HEAD(curr->list);
INSIST(addrinfo != NULL);
if (addrinfo->srtt < bestaddrinfo->srtt) {
best = curr;
bestaddrinfo = addrinfo;
}
curr = ISC_LIST_NEXT(curr, publink);
}
ISC_LIST_UNLINK(fctx->finds, best, publink);
ISC_LIST_APPEND(sorted, best, publink);
}
fctx->finds = sorted;
}
static isc_result_t
fctx_getaddresses(fetchctx_t *fctx) {
dns_rdata_t rdata;
......@@ -625,6 +720,13 @@ fctx_getaddresses(fetchctx_t *fctx) {
FCTXTRACE("getaddresses");
/*
* Don't pound on remote servers.
*/
fctx->restarts++;
if (fctx->restarts > 10)
return (DNS_R_SERVFAIL);
res = fctx->res;
options = DNS_ADBFIND_WANTEVENT|DNS_ADBFIND_EMPTYEVENT;
if (res->dispatch4 != NULL)
......@@ -635,7 +737,7 @@ fctx_getaddresses(fetchctx_t *fctx) {
if (result != ISC_R_SUCCESS)
return (result);
fctx_cleanupfinds(fctx);
INSIST(ISC_LIST_EMPTY(fctx->finds));
result = dns_rdataset_first(&fctx->nameservers);
while (result == ISC_R_SUCCESS) {
......@@ -647,7 +749,7 @@ fctx_getaddresses(fetchctx_t *fctx) {
dns_name_init(&name, NULL);
dns_name_fromregion(&name, &r);
/*
* XXXRTH If this name is the same as QNAME, remember
* XXXRTH If this name is the same as QNAME, remember to
* skip it, and remember that we did so so we can
* use an ancestor QDOMAIN if we find no addresses.
*/
......@@ -668,9 +770,7 @@ fctx_getaddresses(fetchctx_t *fctx) {
* name.
*/
INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
/*
* XXXRTH Sort.
*/
sort_adbfind(find);
ISC_LIST_APPEND(fctx->finds, find, publink);
} else {
/*
......@@ -713,11 +813,7 @@ fctx_getaddresses(fetchctx_t *fctx) {
* We've found some addresses. We might still be looking
* for more addresses.
*/
/*
* XXXRTH Sort.
*/
sort_finds(fctx);
result = ISC_R_SUCCESS;
}
......@@ -732,7 +828,6 @@ static inline dns_adbaddrinfo_t *
fctx_nextaddress(fetchctx_t *fctx) {
dns_adbfind_t *find;
dns_adbaddrinfo_t *addrinfo;
int count = 0;
/*
* Return the next untried address, if any.
......@@ -755,8 +850,6 @@ fctx_nextaddress(fetchctx_t *fctx) {
*/
addrinfo = NULL;
while (find != fctx->find) {
count++;
INSIST(count < 1000);
for (addrinfo = ISC_LIST_HEAD(find->list);
addrinfo != NULL;
addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
......@@ -774,6 +867,10 @@ fctx_nextaddress(fetchctx_t *fctx) {
fctx->find = find;
/* XXX */
if (addrinfo != NULL)
printf("RTT = %u\n", addrinfo->srtt);
return (addrinfo);
}
......@@ -796,6 +893,7 @@ fctx_try(fetchctx_t *fctx) {
* We have no more addresses. Start over.
*/
fctx_cancelqueries(fctx);
fctx_cleanupfinds(fctx);
result = fctx_getaddresses(fctx);
if (result == DNS_R_WAIT) {
/*
......@@ -826,7 +924,7 @@ fctx_try(fetchctx_t *fctx) {
* just send a single query.
*/
result = fctx_sendquery(fctx, addrinfo->sockaddr);
result = fctx_sendquery(fctx, addrinfo);
if (result != ISC_R_SUCCESS)
fctx_done(fctx, result);
}
......@@ -1083,6 +1181,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
ISC_LIST_INIT(fctx->finds);
fctx->find = NULL;
fctx->pending = 0;
fctx->restarts = 0;
fctx->attributes = 0;
fctx->qmessage = NULL;
......@@ -2265,6 +2364,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
dns_name_t *fname;
dns_fixedname_t foundname;
isc_stdtime_t now;
isc_time_t tnow, *finish;
REQUIRE(VALID_QUERY(query));
fctx = query->fctx;
......@@ -2280,11 +2380,22 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
broken_server = ISC_FALSE;
get_nameservers = ISC_FALSE;
covers = 0;
finish = NULL;
/*
* XXXRTH We should really get the current time just once. We
* need a routine to convert from an isc_time_t to an
* isc_stdtime_t.
*/
result = isc_time_now(&tnow);
if (result != ISC_R_SUCCESS)
goto done;
finish = &tnow;
result = isc_stdtime_get(&now);
if (result != ISC_R_SUCCESS)
goto done;
message = fctx->rmessage;
message->querytsig = query->tsig;
message->tsigkey = query->tsigkey;
......@@ -2429,14 +2540,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
done:
/*
* Give the event back to the dispatcher.
* Cancel the query.
*/
dns_dispatch_freeevent(query->dispatch, query->dispentry, &devent);
fctx_cancelquery(&query, &devent, finish);
/*
* XXXRTH Record round-trip statistics here. Note that 'result'
* MUST NOT be changed by this recording process.
*/
if (keep_trying) {
if (result == DNS_R_FORMERR)
broken_server = ISC_TRUE;
......@@ -2496,6 +2603,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
fctx_done(fctx, DNS_R_SERVFAIL);
return;
}
fctx_cancelqueries(fctx);
fctx_cleanupfinds(fctx);
}
/*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment