📄 resolver.c
字号:
return; isc_netaddr_fromsockaddr(&na, sa); isc_netaddr_format(&na, buf, sizeof(buf)); FCTXTRACE2(msg, buf);}static inline dns_adbaddrinfo_t *fctx_nextaddress(fetchctx_t *fctx) { dns_adbfind_t *find, *start; dns_adbaddrinfo_t *addrinfo; dns_adbaddrinfo_t *faddrinfo; /* * Return the next untried address, if any. */ /* * Find the first unmarked forwarder (if any). */ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (!UNMARKED(addrinfo)) continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; fctx->find = NULL; return (addrinfo); } } /* * No forwarders. Move to the next find. */ fctx->attributes |= 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); } fctx->find = find; if (addrinfo != NULL) return (addrinfo); /* * No nameservers left. Try alternates. */ fctx->attributes |= FCTX_ATTR_TRIEDALT; find = fctx->altfind; if (find == NULL) find = ISC_LIST_HEAD(fctx->altfinds); else { find = ISC_LIST_NEXT(find, publink); if (find == NULL) find = ISC_LIST_HEAD(fctx->altfinds); } /* * 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->altfinds); } while (find != start); } faddrinfo = addrinfo; /* * See if we have a better alternate server by address. */ for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (!UNMARKED(addrinfo)) continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo) && (faddrinfo == NULL || addrinfo->srtt < faddrinfo->srtt)) { if (faddrinfo != NULL) faddrinfo->flags &= ~FCTX_ADDRINFO_MARK; addrinfo->flags |= FCTX_ADDRINFO_MARK; break; } } if (addrinfo == NULL) { addrinfo = faddrinfo; fctx->altfind = find; } return (addrinfo);}static voidfctx_try(fetchctx_t *fctx) { isc_result_t result; dns_adbaddrinfo_t *addrinfo; FCTXTRACE("try"); REQUIRE(!ADDRWAIT(fctx)); addrinfo = fctx_nextaddress(fctx); if (addrinfo == NULL) { /* * We have no more addresses. Start over. */ fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); fctx_cleanupaltaddrs(fctx); result = fctx_getaddresses(fctx); if (result == DNS_R_WAIT) { /* * Sleep waiting for addresses. */ FCTXTRACE("addrwait"); fctx->attributes |= FCTX_ATTR_ADDRWAIT; return; } else if (result != ISC_R_SUCCESS) { /* * Something bad happened. */ fctx_done(fctx, result); return; } addrinfo = fctx_nextaddress(fctx); /* * While we may have addresses from the ADB, they * might be bad ones. In this case, return SERVFAIL. */ if (addrinfo == NULL) { fctx_done(fctx, DNS_R_SERVFAIL); return; } } result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) fctx_done(fctx, result);}static isc_boolean_tfctx_destroy(fetchctx_t *fctx) { dns_resolver_t *res; unsigned int bucketnum; isc_sockaddr_t *sa, *next_sa; /* * Caller must be holding the bucket lock. */ REQUIRE(VALID_FCTX(fctx)); REQUIRE(fctx->state == fetchstate_done || fctx->state == fetchstate_init); REQUIRE(ISC_LIST_EMPTY(fctx->events)); REQUIRE(ISC_LIST_EMPTY(fctx->queries)); REQUIRE(ISC_LIST_EMPTY(fctx->finds)); REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); REQUIRE(fctx->pending == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); REQUIRE(fctx->references == 0); FCTXTRACE("destroy"); res = fctx->res; bucketnum = fctx->bucketnum; ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link); /* * Free bad. */ for (sa = ISC_LIST_HEAD(fctx->bad); sa != NULL; sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->bad, sa, link); isc_mem_put(res->mctx, sa, sizeof(*sa)); } isc_timer_detach(&fctx->timer); dns_message_destroy(&fctx->rmessage); dns_message_destroy(&fctx->qmessage); if (dns_name_countlabels(&fctx->domain) > 0) dns_name_free(&fctx->domain, res->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_name_free(&fctx->name, res->mctx); dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); isc_mem_free(res->mctx, fctx->info); isc_mem_put(res->mctx, fctx, sizeof(*fctx)); LOCK(&res->nlock); res->nfctx--; UNLOCK(&res->nlock); if (res->buckets[bucketnum].exiting && ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) return (ISC_TRUE); return (ISC_FALSE);}/* * Fetch event handlers. */static voidfctx_timeout(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); FCTXTRACE("timeout"); if (event->ev_type == ISC_TIMEREVENT_LIFE) { fctx_done(fctx, ISC_R_TIMEDOUT); } else { isc_result_t result; fctx->timeouts++; /* * We could cancel the running queries here, or we could let * them keep going. Right now we choose the latter... */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; /* * Our timer has triggered. Reestablish the fctx lifetime * timer. */ result = fctx_starttimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result); else /* * Keep trying. */ fctx_try(fctx); } isc_event_free(&event);}static voidfctx_shutdown(fetchctx_t *fctx) { isc_event_t *cevent; /* * Start the shutdown process for fctx, if it isn't already underway. */ FCTXTRACE("shutdown"); /* * The caller must be holding the appropriate bucket lock. */ if (fctx->want_shutdown) return; fctx->want_shutdown = ISC_TRUE; /* * Unless we're still initializing (in which case the * control event is still outstanding), we need to post * the control event to tell the fetch we want it to * exit. */ if (fctx->state != fetchstate_init) { cevent = &fctx->control_event; isc_task_send(fctx->res->buckets[fctx->bucketnum].task, &cevent); }}static voidfctx_doshutdown(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; dns_validator_t *validator; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); res = fctx->res; bucketnum = fctx->bucketnum; FCTXTRACE("doshutdown"); /* * An fctx that is shutting down is no longer in ADDRWAIT mode. */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; /* * Cancel all pending validators. Note that this must be done * without the bucket lock held, since that could cause deadlock. */ validator = ISC_LIST_HEAD(fctx->validators); while (validator != NULL) { dns_validator_cancel(validator); validator = ISC_LIST_NEXT(validator, link); } if (fctx->nsfetch != NULL) dns_resolver_cancelfetch(fctx->nsfetch); /* * Shut down anything that is still running on behalf of this * fetch. To avoid deadlock with the ADB, we must do this * before we lock the bucket lock. */ fctx_stopeverything(fctx, ISC_FALSE); LOCK(&res->buckets[bucketnum].lock); fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; INSIST(fctx->state == fetchstate_active || fctx->state == fetchstate_done); INSIST(fctx->want_shutdown); if (fctx->state != fetchstate_done) { fctx->state = fetchstate_done; fctx_sendevents(fctx, ISC_R_CANCELED); } if (fctx->references == 0 && fctx->pending == 0 && ISC_LIST_EMPTY(fctx->validators)) bucket_empty = fctx_destroy(fctx); UNLOCK(&res->buckets[bucketnum].lock); if (bucket_empty) empty_bucket(res);}static voidfctx_start(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); res = fctx->res; bucketnum = fctx->bucketnum; FCTXTRACE("start"); LOCK(&res->buckets[bucketnum].lock); INSIST(fctx->state == fetchstate_init); if (fctx->want_shutdown) { /* * We haven't started this fctx yet, and we've been requested * to shut it down. */ fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; fctx->state = fetchstate_done; fctx_sendevents(fctx, ISC_R_CANCELED); /* * Since we haven't started, we INSIST that we have no * pending ADB finds and no pending validations. */ INSIST(fctx->pending == 0); INSIST(ISC_LIST_EMPTY(fctx->validators)); if (fctx->references == 0) { /* * It's now safe to destroy this fctx. */ bucket_empty = fctx_destroy(fctx); } done = ISC_TRUE; } else { /* * Normal fctx startup. */ fctx->state = fetchstate_active; /* * Reset the control event for later use in shutting down * the fctx. */ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx, NULL, NULL, NULL); } UNLOCK(&res->buckets[bucketnum].lock); if (!done) { isc_result_t result; /* * All is well. Start working on the fetch. */ result = fctx_starttimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result); else fctx_try(fctx); } else if (bucket_empty) empty_bucket(res);}/* * Fetch Creation, Joining, and Cancelation. */static inline isc_result_tfctx_join(fetchctx_t *fctx, isc_task_t *task, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t *fetch){ isc_task_t *clone; dns_fetchevent_t *event; 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. */ clone = NULL; isc_task_attach(task, &clone); event = (dns_fetchevent_t *) isc_event_allocate(fctx->res->mctx, clone, DNS_EVENT_FETCHDONE, action, arg, sizeof(*event)); if (event == NULL) { isc_task_detach(&clone); return (ISC_R_NOMEMORY); } event->result = DNS_R_SERVFAIL; event->qtype = fctx->type; event->db = NULL; event->node = NULL; event->rdataset = rdataset; event->sigrdataset = sigrdataset; event->fetch = fetch; dns_fixedname_init(&event->foundname); /* * Make sure that we can store the sigrdataset in the * first event if it is needed by any of the events. */ if (event->sigrdataset != NULL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -