📄 resolver.c
字号:
factor = DNS_ADB_RTTADJDEFAULT; } 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. */ INSIST(no_response); rtt = query->addrinfo->srtt + (100000 * fctx->restarts); if (rtt > 10000000) rtt = 10000000; /* * Replace the current RTT with our value. */ factor = DNS_ADB_RTTADJREPLACE; } dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor); } /* * Age RTTs of servers not tried. */ factor = DNS_ADB_RTTADJAGE; if (finish != NULL) for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); if (finish != NULL && TRIEDFIND(fctx)) for (find = ISC_LIST_HEAD(fctx->finds); find != NULL; find = ISC_LIST_NEXT(find, publink)) for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); if (finish != NULL && TRIEDALT(fctx)) { for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL; find = ISC_LIST_NEXT(find, publink)) for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); } if (query->dispentry != NULL) dns_dispatch_removeresponse(&query->dispentry, deventp); ISC_LIST_UNLINK(fctx->queries, query, link); if (query->tsig != NULL) isc_buffer_free(&query->tsig); if (query->tsigkey != NULL) dns_tsigkey_detach(&query->tsigkey); /* * Check for any outstanding socket events. If they exist, cancel * them and let the event handlers finish the cleanup. The resolver * only needs to worry about managing the connect and send events; * the dispatcher manages the recv events. */ if (RESQUERY_CONNECTING(query)) /* * Cancel the connect. */ isc_socket_cancel(query->tcpsocket, NULL, ISC_SOCKCANCEL_CONNECT); else if (RESQUERY_SENDING(query)) /* * Cancel the pending send. */ isc_socket_cancel(dns_dispatch_getsocket(query->dispatch), NULL, ISC_SOCKCANCEL_SEND); if (query->dispatch != NULL) dns_dispatch_detach(&query->dispatch); if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query))) /* * It's safe to destroy the query now. */ resquery_destroy(&query);}static voidfctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) { resquery_t *query, *next_query; FCTXTRACE("cancelqueries"); for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; query = next_query) { next_query = ISC_LIST_NEXT(query, link); fctx_cancelquery(&query, NULL, NULL, no_response); }}static voidfctx_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) { next_find = ISC_LIST_NEXT(find, publink); ISC_LIST_UNLINK(fctx->finds, find, publink); dns_adb_destroyfind(&find); } fctx->find = NULL;}static voidfctx_cleanupaltfinds(fetchctx_t *fctx) { dns_adbfind_t *find, *next_find; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL; find = next_find) { next_find = ISC_LIST_NEXT(find, publink); ISC_LIST_UNLINK(fctx->altfinds, find, publink); dns_adb_destroyfind(&find); } fctx->altfind = NULL;}static voidfctx_cleanupforwaddrs(fetchctx_t *fctx) { dns_adbaddrinfo_t *addr, *next_addr; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->forwaddrs); addr != NULL; addr = next_addr) { next_addr = ISC_LIST_NEXT(addr, publink); ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink); dns_adb_freeaddrinfo(fctx->adb, &addr); }}static voidfctx_cleanupaltaddrs(fetchctx_t *fctx) { dns_adbaddrinfo_t *addr, *next_addr; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->altaddrs); addr != NULL; addr = next_addr) { next_addr = ISC_LIST_NEXT(addr, publink); ISC_LIST_UNLINK(fctx->altaddrs, addr, publink); dns_adb_freeaddrinfo(fctx->adb, &addr); }}static inline voidfctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) { FCTXTRACE("stopeverything"); fctx_cancelqueries(fctx, no_response); fctx_cleanupfinds(fctx); fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); fctx_cleanupaltaddrs(fctx); fctx_stoptimer(fctx);}static inline voidfctx_sendevents(fetchctx_t *fctx, isc_result_t result) { dns_fetchevent_t *event, *next_event; isc_task_t *task; /* * Caller must be holding the appropriate bucket lock. */ REQUIRE(fctx->state == fetchstate_done); FCTXTRACE("sendevents"); for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); ISC_LIST_UNLINK(fctx->events, event, ev_link); task = event->ev_sender; event->ev_sender = fctx; if (!HAVE_ANSWER(fctx)) event->result = result; INSIST(result != ISC_R_SUCCESS || dns_rdataset_isassociated(event->rdataset) || fctx->type == dns_rdatatype_any || fctx->type == dns_rdatatype_rrsig); isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event)); }}static voidfctx_done(fetchctx_t *fctx, isc_result_t result) { dns_resolver_t *res; isc_boolean_t no_response; FCTXTRACE("done"); res = fctx->res; if (result == ISC_R_SUCCESS) no_response = ISC_TRUE; else no_response = ISC_FALSE; fctx_stopeverything(fctx, no_response); LOCK(&res->buckets[fctx->bucketnum].lock); fctx->state = fetchstate_done; fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; fctx_sendevents(fctx, result); UNLOCK(&res->buckets[fctx->bucketnum].lock);}static voidresquery_senddone(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; resquery_t *query = event->ev_arg; REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); QTRACE("senddone"); /* * XXXRTH * * Currently we don't wait for the senddone event before retrying * a query. This means that if we get really behind, we may end * up doing extra work! */ UNUSED(task); INSIST(RESQUERY_SENDING(query)); query->sends--; if (RESQUERY_CANCELED(query)) { if (query->sends == 0) { /* * This query was canceled while the * isc_socket_sendto() was in progress. */ if (query->tcpsocket != NULL) isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } } else if (sevent->result != ISC_R_SUCCESS) fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); isc_event_free(&event);}static inline isc_result_tfctx_addopt(dns_message_t *message, dns_resolver_t *res) { dns_rdataset_t *rdataset; dns_rdatalist_t *rdatalist; dns_rdata_t *rdata; isc_result_t result; rdatalist = NULL; result = dns_message_gettemprdatalist(message, &rdatalist); if (result != ISC_R_SUCCESS) return (result); rdata = NULL; result = dns_message_gettemprdata(message, &rdata); if (result != ISC_R_SUCCESS) return (result); rdataset = NULL; result = dns_message_gettemprdataset(message, &rdataset); if (result != ISC_R_SUCCESS) return (result); dns_rdataset_init(rdataset); rdatalist->type = dns_rdatatype_opt; rdatalist->covers = 0; /* * Set Maximum UDP buffer size. */ rdatalist->rdclass = res->udpsize; /* * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1. */ rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO; /* * No EDNS options. */ rdata->data = NULL; rdata->length = 0; rdata->rdclass = rdatalist->rdclass; rdata->type = rdatalist->type; rdata->flags = 0; ISC_LIST_INIT(rdatalist->rdata); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS); return (dns_message_setopt(message, rdataset));}static inline voidfctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { unsigned int seconds; /* * We retry every 2 seconds the first two times through the address * list, and then we do exponential back-off. */ if (fctx->restarts < 3) seconds = 2; else seconds = (2 << (fctx->restarts - 1)); /* * Double the round-trip time and convert to seconds. */ rtt /= 500000; /* * Always wait for at least the doubled round-trip time. */ if (seconds < rtt) seconds = rtt; /* * But don't ever wait for more than 30 seconds. */ if (seconds > 30) seconds = 30; isc_interval_set(&fctx->interval, seconds, 0);}static isc_result_tfctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, unsigned int options){ dns_resolver_t *res; isc_task_t *task; isc_result_t result; resquery_t *query; FCTXTRACE("query"); res = fctx->res; task = res->buckets[fctx->bucketnum].task; fctx_setretryinterval(fctx, addrinfo->srtt); result = fctx_startidletimer(fctx); if (result != ISC_R_SUCCESS) return (result); dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE); query = isc_mem_get(res->mctx, sizeof(*query)); if (query == NULL) { result = ISC_R_NOMEMORY; goto stop_idle_timer; } query->mctx = res->mctx; query->options = options; query->attributes = 0; query->sends = 0; query->connects = 0; /* * Note that the caller MUST guarantee that 'addrinfo' will remain * valid until this query is canceled. */ query->addrinfo = addrinfo; TIME_NOW(&query->start); /* * If this is a TCP query, then we need to make a socket and * a dispatch for it here. Otherwise we use the resolver's * shared dispatch. */ query->dispatchmgr = res->dispatchmgr; query->dispatch = NULL; query->tcpsocket = NULL; if ((query->options & DNS_FETCHOPT_TCP) != 0) { isc_sockaddr_t addr; int pf; pf = isc_sockaddr_pf(&addrinfo->sockaddr); switch (pf) { case PF_INET: result = dns_dispatch_getlocaladdress(res->dispatchv4, &addr); break; case PF_INET6: result = dns_dispatch_getlocaladdress(res->dispatchv6, &addr); break; default: result = ISC_R_NOTIMPLEMENTED; break; } if (result != ISC_R_SUCCESS) goto cleanup_query; isc_sockaddr_setport(&addr, 0); result = isc_socket_create(res->socketmgr, pf, isc_sockettype_tcp, &query->tcpsocket); if (result != ISC_R_SUCCESS) goto cleanup_query; result = isc_socket_bind(query->tcpsocket, &addr); if (result != ISC_R_SUCCESS) goto cleanup_socket; /* * A dispatch will be created once the connect succeeds. */ } else { switch (isc_sockaddr_pf(&addrinfo->sockaddr)) { case PF_INET: dns_dispatch_attach(res->dispatchv4, &query->dispatch); break; case PF_INET6: dns_dispatch_attach(res->dispatchv6, &query->dispatch); break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } /* * We should always have a valid dispatcher here. If we * don't support a protocol family, then its dispatcher * will be NULL, but we shouldn't be finding addresses for * protocol types we don't support, so the dispatcher * we found should never be NULL. */ INSIST(query->dispatch != NULL); } query->dispentry = NULL; query->fctx = fctx; query->tsig = NULL; query->tsigkey = NULL; ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; if ((query->options & DNS_FETCHOPT_TCP) != 0) { /* * Connect to the remote server. * * XXXRTH Should we attach to the socket? */ result = isc_socket_connect(query->tcpsocket, &addrinfo->sockaddr, task, resquery_connected, query); if (result != ISC_R_SUCCESS) goto cleanup_socket; query->connects++; QTRACE("connecting via TCP"); } else { result = resquery_send(query); if (result != ISC_R_SUCCESS) goto cleanup_dispatch; } ISC_LIST_APPEND(fctx->queries, query, link); return (ISC_R_SUCCESS); cleanup_socket: isc_socket_detach(&query->tcpsocket); cleanup_dispatch: if (query->dispatch != NULL) dns_dispatch_detach(&query->dispatch); cleanup_query: query->magic = 0; isc_mem_put(res->mctx, query, sizeof(*query)); stop_idle_timer: RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS); return (result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -