dns_message_t * qmessage;
ISC_LIST(resquery_t) queries;
dns_adbfindlist_t finds;
- dns_adbfind_t * find;
+ dns_adbaddrinfo_t *foundaddrinfo;
dns_adbfindlist_t altfinds;
dns_adbfind_t * altfind;
dns_adbaddrinfolist_t forwaddrs;
ISC_LIST_UNLINK(fctx->finds, find, publink);
dns_adb_destroyfind(&find);
}
- fctx->find = NULL;
+ fctx->foundaddrinfo = NULL;
}
static void
namebuf, typebuf, classbuf, addrbuf);
}
-/*
- * Sort addrinfo list by RTT.
- */
-static void
-sort_adbfind(dns_adbfind_t *find, unsigned int bias) {
- dns_adbaddrinfo_t *best, *curr;
- dns_adbaddrinfolist_t sorted;
- unsigned int best_srtt, curr_srtt;
-
- /* Lame N^2 bubble sort. */
- ISC_LIST_INIT(sorted);
- while (!ISC_LIST_EMPTY(find->list)) {
- best = ISC_LIST_HEAD(find->list);
- best_srtt = best->srtt;
- if (isc_sockaddr_pf(&best->sockaddr) != AF_INET6)
- best_srtt += bias;
- curr = ISC_LIST_NEXT(best, publink);
- while (curr != NULL) {
- curr_srtt = curr->srtt;
- if (isc_sockaddr_pf(&curr->sockaddr) != AF_INET6)
- curr_srtt += bias;
- if (curr_srtt < best_srtt) {
- best = curr;
- best_srtt = curr_srtt;
- }
- curr = ISC_LIST_NEXT(curr, publink);
- }
- ISC_LIST_UNLINK(find->list, best, publink);
- ISC_LIST_APPEND(sorted, best, publink);
- }
- find->list = sorted;
-}
-
-/*
- * Sort a list of finds by server RTT.
- */
-static void
-sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) {
- dns_adbfind_t *best, *curr;
- dns_adbfindlist_t sorted;
- dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
- unsigned int best_srtt, curr_srtt;
-
- /* Sort each find's addrinfo list by SRTT. */
- for (curr = ISC_LIST_HEAD(*findlist);
- curr != NULL;
- curr = ISC_LIST_NEXT(curr, publink))
- sort_adbfind(curr, bias);
-
- /* Lame N^2 bubble sort. */
- ISC_LIST_INIT(sorted);
- while (!ISC_LIST_EMPTY(*findlist)) {
- best = ISC_LIST_HEAD(*findlist);
- bestaddrinfo = ISC_LIST_HEAD(best->list);
- INSIST(bestaddrinfo != NULL);
- best_srtt = bestaddrinfo->srtt;
- if (isc_sockaddr_pf(&bestaddrinfo->sockaddr) != AF_INET6)
- best_srtt += bias;
- curr = ISC_LIST_NEXT(best, publink);
- while (curr != NULL) {
- addrinfo = ISC_LIST_HEAD(curr->list);
- INSIST(addrinfo != NULL);
- curr_srtt = addrinfo->srtt;
- if (isc_sockaddr_pf(&addrinfo->sockaddr) != AF_INET6)
- curr_srtt += bias;
- if (curr_srtt < best_srtt) {
- best = curr;
- best_srtt = curr_srtt;
- }
- curr = ISC_LIST_NEXT(curr, publink);
- }
- ISC_LIST_UNLINK(*findlist, best, publink);
- ISC_LIST_APPEND(sorted, best, publink);
- }
- *findlist = sorted;
-}
-
static void
findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
unsigned int options, unsigned int flags, isc_stdtime_t now,
* We've found some addresses. We might still be looking
* for more addresses.
*/
- sort_finds(&fctx->finds, res->view->v6bias);
- sort_finds(&fctx->altfinds, 0);
result = ISC_R_SUCCESS;
}
}
}
+static dns_adbaddrinfo_t *
+nextaddress(fetchctx_t *fctx) {
+ dns_adbaddrinfo_t *prevai = fctx->foundaddrinfo, *lowestsrttai = NULL;
+ unsigned int v6bias = fctx->res->view->v6bias, lowestsrtt = 0;
+
+ /*
+ * Let's walk through the list of dns_adbaddrinfo_t to find the best
+ * next server address to query. This is linear on the number of
+ * dns_adbaddrinfo_t which are grouped in find list (for each ADB find).
+ */
+ for (dns_adbfind_t *find = ISC_LIST_HEAD(fctx->finds); find != NULL;
+ find = ISC_LIST_NEXT(find, publink))
+ {
+ for (dns_adbaddrinfo_t *ai = ISC_LIST_HEAD(find->list);
+ ai != NULL; ai = ISC_LIST_NEXT(ai, publink))
+ {
+ /*
+ * This address has been marked already, skip it.
+ */
+ if (!UNMARKED(ai)) {
+ continue;
+ }
+
+ /*
+ * This address is the same as the previously used
+ * address, it's a duplicate, mark it and skip it!
+ */
+ if (prevai != NULL) {
+ if (prevai->entry == ai->entry) {
+ ai->flags |= FCTX_ADDRINFO_MARK;
+ continue;
+ }
+ }
+
+ /*
+ * Mark and skip this address if incompatible (i.e. IPv6
+ * address on a v4 only server, or for ACL reason, etc.)
+ */
+ possibly_mark(fctx, ai);
+ if (!UNMARKED(ai)) {
+ continue;
+ }
+
+ /*
+ * This address hasn't been tried yet and is a
+ * good candidate. Let's keep track of it if it
+ * has the lowest SRTT so far (or if there is no
+ * address with lowest SRTT found yet).
+ */
+ unsigned int aisrtt = ai->srtt;
+
+ if (isc_sockaddr_pf(&ai->sockaddr) != AF_INET6) {
+ aisrtt += v6bias;
+ }
+
+ if (lowestsrttai == NULL || aisrtt < lowestsrtt) {
+ lowestsrttai = ai;
+ lowestsrtt = aisrtt;
+ continue;
+ }
+ }
+ }
+
+ /*
+ * This is the next address to query. If this is NULL, we're done.
+ */
+ if (lowestsrttai != NULL) {
+ lowestsrttai->flags |= FCTX_ADDRINFO_MARK;
+ }
+ fctx->foundaddrinfo = lowestsrttai;
+
+ return lowestsrttai;
+}
+
static inline dns_adbaddrinfo_t *
fctx_nextaddress(fetchctx_t *fctx) {
dns_adbfind_t *find, *start;
possibly_mark(fctx, addrinfo);
if (UNMARKED(addrinfo)) {
addrinfo->flags |= FCTX_ADDRINFO_MARK;
- fctx->find = NULL;
return (addrinfo);
}
}
FCTX_ATTR_SET(fctx, FCTX_ATTR_TRIEDFIND);
- find = fctx->find;
- if (find == NULL)
- find = ISC_LIST_HEAD(fctx->finds);
- else {
- find = ISC_LIST_NEXT(find, publink);
- if (find == NULL)
- find = ISC_LIST_HEAD(fctx->finds);
- }
-
- /*
- * Find the first unmarked addrinfo.
- */
- addrinfo = NULL;
- if (find != NULL) {
- start = find;
- do {
- for (addrinfo = ISC_LIST_HEAD(find->list);
- addrinfo != NULL;
- addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
- if (!UNMARKED(addrinfo))
- continue;
- possibly_mark(fctx, addrinfo);
- if (UNMARKED(addrinfo)) {
- addrinfo->flags |= FCTX_ADDRINFO_MARK;
- break;
- }
- }
- if (addrinfo != NULL)
- break;
- find = ISC_LIST_NEXT(find, publink);
- if (find == NULL)
- find = ISC_LIST_HEAD(fctx->finds);
- } while (find != start);
+ faddrinfo = nextaddress(fctx);
+ if (faddrinfo != NULL) {
+ return faddrinfo;
}
- fctx->find = find;
- if (addrinfo != NULL)
- return (addrinfo);
-
/*
* No nameservers left. Try alternates.
*/
ISC_LIST_INIT(fctx->bad_edns);
ISC_LIST_INIT(fctx->validators);
fctx->validator = NULL;
- fctx->find = NULL;
+ fctx->foundaddrinfo = NULL;
fctx->altfind = NULL;
fctx->pending = 0;
fctx->restarts = 0;