static void dispatch(isc__timermgr_t *manager, isc_time_t *now) { isc_boolean_t done = ISC_FALSE, post_event, need_schedule; isc_timerevent_t *event; isc_eventtype_t type = 0; isc__timer_t *timer; isc_result_t result; isc_boolean_t idle; /*! * The caller must be holding the manager lock. */ while (manager->nscheduled > 0 && !done) { timer = isc_heap_element(manager->heap, 1); INSIST(timer->type != isc_timertype_inactive); if (isc_time_compare(now, &timer->due) >= 0) { if (timer->type == isc_timertype_ticker) { type = ISC_TIMEREVENT_TICK; post_event = ISC_TRUE; need_schedule = ISC_TRUE; } else if (timer->type == isc_timertype_limited) { int cmp; cmp = isc_time_compare(now, &timer->expires); if (cmp >= 0) { type = ISC_TIMEREVENT_LIFE; post_event = ISC_TRUE; need_schedule = ISC_FALSE; } else { type = ISC_TIMEREVENT_TICK; post_event = ISC_TRUE; need_schedule = ISC_TRUE; } } else if (!isc_time_isepoch(&timer->expires) && isc_time_compare(now, &timer->expires) >= 0) { type = ISC_TIMEREVENT_LIFE; post_event = ISC_TRUE; need_schedule = ISC_FALSE; } else { idle = ISC_FALSE; LOCK(&timer->lock); if (!isc_time_isepoch(&timer->idle) && isc_time_compare(now, &timer->idle) >= 0) { idle = ISC_TRUE; } UNLOCK(&timer->lock); if (idle) { type = ISC_TIMEREVENT_IDLE; post_event = ISC_TRUE; need_schedule = ISC_FALSE; } else { /* * Idle timer has been touched; * reschedule. */ XTRACEID(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_IDLERESCHED, "idle reschedule"), timer); post_event = ISC_FALSE; need_schedule = ISC_TRUE; } } if (post_event) { XTRACEID(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_POSTING, "posting"), timer); /* * XXX We could preallocate this event. */ event = (isc_timerevent_t *)isc_event_allocate(manager->mctx, timer, type, timer->action, timer->arg, sizeof(*event)); if (event != NULL) { event->due = timer->due; isc_task_send(timer->task, ISC_EVENT_PTR(&event)); } else UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_EVENTNOTALLOC, "couldn't " "allocate event")); } timer->index = 0; isc_heap_delete(manager->heap, 1); manager->nscheduled--; if (need_schedule) { result = schedule(timer, now, ISC_FALSE); if (result != ISC_R_SUCCESS) UNEXPECTED_ERROR(__FILE__, __LINE__, "%s: %u", isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, ISC_MSG_SCHEDFAIL, "couldn't schedule " "timer"), result); } } else { manager->due = timer->due; done = ISC_TRUE; } } }
static void lookup_find(dns_lookup_t *lookup, dns_fetchevent_t *event) { isc_result_t result; isc_boolean_t want_restart; isc_boolean_t send_event; dns_name_t *name, *fname, *prefix; dns_fixedname_t foundname, fixed; dns_rdata_t rdata = DNS_RDATA_INIT; unsigned int nlabels; int order; dns_namereln_t namereln; dns_rdata_cname_t cname; dns_rdata_dname_t dname; REQUIRE(VALID_LOOKUP(lookup)); LOCK(&lookup->lock); result = ISC_R_SUCCESS; name = dns_fixedname_name(&lookup->name); do { lookup->restarts++; want_restart = ISC_FALSE; send_event = ISC_TRUE; if (event == NULL && !lookup->canceled) { dns_fixedname_init(&foundname); fname = dns_fixedname_name(&foundname); INSIST(!dns_rdataset_isassociated(&lookup->rdataset)); INSIST(!dns_rdataset_isassociated (&lookup->sigrdataset)); /* * If we have restarted then clear the old node. */ if (lookup->event->node != NULL) { INSIST(lookup->event->db != NULL); dns_db_detachnode(lookup->event->db, &lookup->event->node); } if (lookup->event->db != NULL) dns_db_detach(&lookup->event->db); result = view_find(lookup, fname); if (result == ISC_R_NOTFOUND) { /* * We don't know anything about the name. * Launch a fetch. */ if (lookup->event->node != NULL) { INSIST(lookup->event->db != NULL); dns_db_detachnode(lookup->event->db, &lookup->event->node); } if (lookup->event->db != NULL) dns_db_detach(&lookup->event->db); result = start_fetch(lookup); if (result == ISC_R_SUCCESS) send_event = ISC_FALSE; goto done; } } else if (event != NULL) { result = event->result; fname = dns_fixedname_name(&event->foundname); dns_resolver_destroyfetch(&lookup->fetch); INSIST(event->rdataset == &lookup->rdataset); INSIST(event->sigrdataset == &lookup->sigrdataset); } else fname = NULL; /* Silence compiler warning. */ /* * If we've been canceled, forget about the result. */ if (lookup->canceled) result = ISC_R_CANCELED; switch (result) { case ISC_R_SUCCESS: result = build_event(lookup); if (event == NULL) break; if (event->db != NULL) dns_db_attach(event->db, &lookup->event->db); if (event->node != NULL) dns_db_attachnode(lookup->event->db, event->node, &lookup->event->node); break; case DNS_R_CNAME: /* * Copy the CNAME's target into the lookup's * query name and start over. */ result = dns_rdataset_first(&lookup->rdataset); if (result != ISC_R_SUCCESS) break; dns_rdataset_current(&lookup->rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &cname, NULL); dns_rdata_reset(&rdata); if (result != ISC_R_SUCCESS) break; result = dns_name_copy(&cname.cname, name, NULL); dns_rdata_freestruct(&cname); if (result == ISC_R_SUCCESS) { want_restart = ISC_TRUE; send_event = ISC_FALSE; } break; case DNS_R_DNAME: namereln = dns_name_fullcompare(name, fname, &order, &nlabels); INSIST(namereln == dns_namereln_subdomain); /* * Get the target name of the DNAME. */ result = dns_rdataset_first(&lookup->rdataset); if (result != ISC_R_SUCCESS) break; dns_rdataset_current(&lookup->rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &dname, NULL); dns_rdata_reset(&rdata); if (result != ISC_R_SUCCESS) break; /* * Construct the new query name and start over. */ dns_fixedname_init(&fixed); prefix = dns_fixedname_name(&fixed); dns_name_split(name, nlabels, prefix, NULL); result = dns_name_concatenate(prefix, &dname.dname, name, NULL); dns_rdata_freestruct(&dname); if (result == ISC_R_SUCCESS) { want_restart = ISC_TRUE; send_event = ISC_FALSE; } break; default: send_event = ISC_TRUE; } if (dns_rdataset_isassociated(&lookup->rdataset)) dns_rdataset_disassociate(&lookup->rdataset); if (dns_rdataset_isassociated(&lookup->sigrdataset)) dns_rdataset_disassociate(&lookup->sigrdataset); done: if (event != NULL) { if (event->node != NULL) dns_db_detachnode(event->db, &event->node); if (event->db != NULL) dns_db_detach(&event->db); isc_event_free(ISC_EVENT_PTR(&event)); } /* * Limit the number of restarts. */ if (want_restart && lookup->restarts == MAX_RESTARTS) { want_restart = ISC_FALSE; result = ISC_R_QUOTA; send_event = ISC_TRUE; } } while (want_restart); if (send_event) { lookup->event->result = result; lookup->event->ev_sender = lookup; isc_task_sendanddetach(&lookup->task, (isc_event_t **)(void *)&lookup->event); dns_view_detach(&lookup->view); } UNLOCK(&lookup->lock); }