📄 adb.c
字号:
goto fail0c; result = isc_mutex_init(&adb->reflock); if (result != ISC_R_SUCCESS) goto fail0d; /* * Initialize the bucket locks for names and elements. * May as well initialize the list heads, too. */ result = isc_mutexblock_init(adb->namelocks, NBUCKETS); if (result != ISC_R_SUCCESS) goto fail1; for (i = 0; i < NBUCKETS; i++) { ISC_LIST_INIT(adb->names[i]); adb->name_sd[i] = ISC_FALSE; adb->name_refcnt[i] = 0; adb->irefcnt++; } for (i = 0; i < NBUCKETS; i++) { ISC_LIST_INIT(adb->entries[i]); adb->entry_sd[i] = ISC_FALSE; adb->entry_refcnt[i] = 0; adb->irefcnt++; } result = isc_mutexblock_init(adb->entrylocks, NBUCKETS); if (result != ISC_R_SUCCESS) goto fail2; /* * Memory pools */#define MPINIT(t, p, n) do { \ result = isc_mempool_create(mem, sizeof(t), &(p)); \ if (result != ISC_R_SUCCESS) \ goto fail3; \ isc_mempool_setfreemax((p), FREE_ITEMS); \ isc_mempool_setfillcount((p), FILL_COUNT); \ isc_mempool_setname((p), n); \ isc_mempool_associatelock((p), &adb->mplock); \} while (0) MPINIT(dns_adbname_t, adb->nmp, "adbname"); MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook"); MPINIT(dns_adbzoneinfo_t, adb->zimp, "adbzoneinfo"); MPINIT(dns_adbentry_t, adb->emp, "adbentry"); MPINIT(dns_adbfind_t, adb->ahmp, "adbfind"); MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo"); MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");#undef MPINIT /* * Allocate a timer and a task for our periodic cleanup. */ result = isc_task_create(adb->taskmgr, 0, &adb->task); if (result != ISC_R_SUCCESS) goto fail3; isc_task_setname(adb->task, "ADB", adb); /* * XXXMLG When this is changed to be a config file option, */ isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0); result = isc_timer_create(adb->timermgr, isc_timertype_once, NULL, &adb->tick_interval, adb->task, timer_cleanup, adb, &adb->timer); if (result != ISC_R_SUCCESS) goto fail3; DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: " "%u buckets every %u seconds, %u buckets in system, %u cl.interval", CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD); /* * Normal return. */ adb->magic = DNS_ADB_MAGIC; *newadb = adb; return (ISC_R_SUCCESS); fail3: if (adb->task != NULL) isc_task_detach(&adb->task); if (adb->timer != NULL) isc_timer_detach(&adb->timer); /* clean up entrylocks */ DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); fail2: /* clean up namelocks */ DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS); fail1: /* clean up only allocated memory */ if (adb->nmp != NULL) isc_mempool_destroy(&adb->nmp); if (adb->nhmp != NULL) isc_mempool_destroy(&adb->nhmp); if (adb->zimp != NULL) isc_mempool_destroy(&adb->zimp); if (adb->emp != NULL) isc_mempool_destroy(&adb->emp); if (adb->ahmp != NULL) isc_mempool_destroy(&adb->ahmp); if (adb->aimp != NULL) isc_mempool_destroy(&adb->aimp); if (adb->afmp != NULL) isc_mempool_destroy(&adb->afmp); DESTROYLOCK(&adb->reflock); fail0d: DESTROYLOCK(&adb->mplock); fail0c: DESTROYLOCK(&adb->lock); fail0b: isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); return (result);}voiddns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) { REQUIRE(DNS_ADB_VALID(adb)); REQUIRE(adbx != NULL && *adbx == NULL); inc_adb_erefcnt(adb); *adbx = adb;}voiddns_adb_detach(dns_adb_t **adbx) { dns_adb_t *adb; isc_boolean_t need_exit_check; REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx)); adb = *adbx; *adbx = NULL; INSIST(adb->erefcnt > 0); LOCK(&adb->reflock); adb->erefcnt--; need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0); UNLOCK(&adb->reflock); if (need_exit_check) { LOCK(&adb->lock); INSIST(adb->shutting_down); check_exit(adb); UNLOCK(&adb->lock); }}voiddns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { isc_task_t *clone; isc_event_t *event; isc_boolean_t zeroirefcnt = ISC_FALSE; /* * Send '*eventp' to 'task' when 'adb' has shutdown. */ REQUIRE(DNS_ADB_VALID(adb)); REQUIRE(eventp != NULL); event = *eventp; *eventp = NULL; LOCK(&adb->lock); LOCK(&adb->reflock); zeroirefcnt = ISC_TF(adb->irefcnt == 0); if (adb->shutting_down && zeroirefcnt && isc_mempool_getallocated(adb->ahmp) == 0) { /* * We're already shutdown. Send the event. */ event->ev_sender = adb; isc_task_send(task, &event); } else { clone = NULL; isc_task_attach(task, &clone); event->ev_sender = clone; ISC_LIST_APPEND(adb->whenshutdown, event, ev_link); } UNLOCK(&adb->reflock); UNLOCK(&adb->lock);}voiddns_adb_shutdown(dns_adb_t *adb) { isc_boolean_t need_check_exit; /* * Shutdown 'adb'. */ LOCK(&adb->lock); if (!adb->shutting_down) { adb->shutting_down = ISC_TRUE; isc_mem_setwater(adb->mctx, water, adb, 0, 0); need_check_exit = shutdown_names(adb); if (!need_check_exit) need_check_exit = shutdown_entries(adb); if (need_check_exit) check_exit(adb); } UNLOCK(&adb->lock);}isc_result_tdns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, void *arg, dns_name_t *name, dns_name_t *zone, unsigned int options, isc_stdtime_t now, dns_name_t *target, in_port_t port, dns_adbfind_t **findp){ dns_adbfind_t *find; dns_adbname_t *adbname; int bucket; isc_boolean_t want_event, start_at_zone, alias, have_address; isc_result_t result; unsigned int wanted_addresses; unsigned int wanted_fetches; unsigned int query_pending; REQUIRE(DNS_ADB_VALID(adb)); if (task != NULL) { REQUIRE(action != NULL); } REQUIRE(name != NULL); REQUIRE(zone != NULL); REQUIRE(findp != NULL && *findp == NULL); REQUIRE(target == NULL || dns_name_hasbuffer(target)); REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0); result = ISC_R_UNEXPECTED; wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK); wanted_fetches = 0; query_pending = 0; want_event = ISC_FALSE; start_at_zone = ISC_FALSE; alias = ISC_FALSE; if (now == 0) isc_stdtime_get(&now); /* * XXXMLG Move this comment somewhere else! * * Look up the name in our internal database. * * Possibilities: Note that these are not always exclusive. * * No name found. In this case, allocate a new name header and * an initial namehook or two. If any of these allocations * fail, clean up and return ISC_R_NOMEMORY. * * Name found, valid addresses present. Allocate one addrinfo * structure for each found and append it to the linked list * of addresses for this header. * * Name found, queries pending. In this case, if a task was * passed in, allocate a job id, attach it to the name's job * list and remember to tell the caller that there will be * more info coming later. */ find = new_adbfind(adb); if (find == NULL) return (ISC_R_NOMEMORY); find->port = port; /* * Remember what types of addresses we are interested in. */ find->options = options; find->flags |= wanted_addresses; if (FIND_WANTEVENT(find)) { REQUIRE(task != NULL); } /* * Try to see if we know anything about this name at all. */ bucket = DNS_ADB_INVALIDBUCKET; adbname = find_name_and_lock(adb, name, find->options, &bucket); if (adb->name_sd[bucket]) { DP(DEF_LEVEL, "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN"); RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); result = ISC_R_SHUTTINGDOWN; goto out; } /* * Nothing found. Allocate a new adbname structure for this name. */ if (adbname == NULL) { adbname = new_adbname(adb, name); if (adbname == NULL) { RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); result = ISC_R_NOMEMORY; goto out; } link_name(adb, bucket, adbname); if (FIND_HINTOK(find)) adbname->flags |= NAME_HINT_OK; if (FIND_GLUEOK(find)) adbname->flags |= NAME_GLUE_OK; if (FIND_STARTATZONE(find)) adbname->flags |= NAME_STARTATZONE; } /* * Expire old entries, etc. */ RUNTIME_CHECK(check_expire_namehooks(adbname, now, adb->overmem) == ISC_FALSE); /* * Do we know that the name is an alias? */ if (!EXPIRE_OK(adbname->expire_target, now)) { /* * Yes, it is. */ DP(DEF_LEVEL, "dns_adb_createfind: name %p is an alias (cached)", adbname); alias = ISC_TRUE; goto post_copy; } /* * Try to populate the name from the database and/or * start fetches. First try looking for an A record * in the database. */ if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now) && WANT_INET(wanted_addresses)) { result = dbfind_name(adbname, now, dns_rdatatype_a); if (result == ISC_R_SUCCESS) { DP(DEF_LEVEL, "dns_adb_createfind: found A for name %p in db", adbname); goto v6; } /* * Did we get a CNAME or DNAME? */ if (result == DNS_R_ALIAS) { DP(DEF_LEVEL, "dns_adb_createfind: name %p is an alias", adbname); alias = ISC_TRUE; goto post_copy; } /* * If the name doesn't exist at all, don't bother with * v6 queries; they won't work. * * If the name does exist but we didn't get our data, go * ahead and try AAAA. * * If the result is neither of these, try a fetch for A. */ if (NXDOMAIN_RESULT(result)) goto fetch; else if (NXRRSET_RESULT(result)) goto v6; if (!NAME_FETCH_V4(adbname)) wanted_fetches |= DNS_ADBFIND_INET; } v6: if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now) && WANT_INET6(wanted_addresses)) { result = dbfind_name(adbname, now, dns_rdatatype_aaaa); if (result == ISC_R_SUCCESS) { DP(DEF_LEVEL, "dns_adb_createfind: found AAAA for name %p", adbname); goto fetch; } /* * Did we get a CNAME or DNAME? */ if (result == DNS_R_ALIAS) { DP(DEF_LEVEL, "dns_adb_createfind: name %p is an alias", adbname); alias = ISC_TRUE; goto post_copy; } /* * Listen to negative cache hints, and don't start * another query. */ if (NCACHE_RESULT(result) || AUTH_NX(result)) goto fetch; if (!NAME_FETCH_V6(adbname)) wanted_fetches |= DNS_ADBFIND_INET6; } fetch: if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) || (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname))) have_address = ISC_TRUE; else have_address = ISC_FALSE; if (wanted_fetches != 0 && ! (FIND_AVOIDFETCHES(find) && have_address)) { /* * We're missing at least one address family. Either the * caller hasn't instructed us to avoid fetches, or we don't * know anything about any of the address families that would * be acceptable so we have to launch fetches. */ if (FIND_STARTATZONE(find)) start_at_zone = ISC_TRUE; /* * Start V4. */ if (WANT_INET(wanted_fetches) && fetch_name(adbname, start_at_zone, dns_rdatatype_a) == ISC_R_SUCCESS) { DP(DEF_LEVEL, "dns_adb_createfind: started A fetch for name %p", adbname); } /* * Start V6. */ if (WANT_INET6(wanted_fetches) && fetch_name(adbname, start_at_zone, dns_rdatatype_aaaa) == ISC_R_SUCCESS) { DP(DEF_LEVEL, "dns_adb_createfind: " "started AAAA fetch for name %p", adbname); } } /* * Run through the name and copy out the bits we are * interested in. */ copy_namehook_lists(adb, find, zone, adbname, now); post_copy: if (NAME_FETCH_V4(adbname)) query_pending |= DNS_ADBFIND_INET; if (NAME_FETCH_V6(adbname)) query_pending |= DNS_ADBFIND_INET6; /* * Attach to the name's query list if there are queries * already running, and we have been asked to. */ want_event = ISC_TRUE; if (!FIND_WANTEVENT(find)) want_event = ISC_FALSE; if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find)) want_event = ISC_FALSE; if ((wanted_addresses & query_pending) == 0) want_event = ISC_FALSE; if (alias) want_event = ISC_FALSE; if (want_event) { find->adbname = adbname; find->name_bucket = bucket; ISC_LIST_APPEND(adbname->finds, find, plink); find->query_pending = (query_pending & wanted_addresses); find->flags &= ~DNS_ADBFIND_ADDRESSMASK; find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK); DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p", find, adbname); } else { /* * Remove the flag so the caller knows there will never * be an event, and set internal flags to fake that * the event was sent and freed, so dns_adb_destroyfind() will * do the right thing. */ find->query_pending = (query_pending & wanted_addresses); find->options &= ~DNS_ADBFIND_WANTEVENT; find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED); find->flags &= ~DNS_ADBFIND_ADDRESSMASK; } find->partial_result |= (adbname->partial_result & wanted_addresses); i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -