diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 4fee592ad6..051597415d 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: zone.c,v 1.117 2000/05/18 02:59:16 marka Exp $ */ +/* $Id: zone.c,v 1.118 2000/05/18 04:43:00 marka Exp $ */ #include @@ -48,9 +48,6 @@ #include #include -/* XXX remove once config changes are in place */ -#define dns_zone_uptodate(x) zone_log(x, me, ISC_LOG_INFO, "dns_zone_uptodate") - #define ZONE_MAGIC 0x5a4f4e45U /* ZONE */ #define NOTIFY_MAGIC 0x4e746679U /* Ntfy */ @@ -223,7 +220,7 @@ static void zone_expire(dns_zone_t *zone); static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump); static isc_result_t default_journal(dns_zone_t *zone); -static void xfrdone(dns_zone_t *zone, isc_result_t result); +static void zone_xfrdone(dns_zone_t *zone, isc_result_t result); static void zone_shutdown(isc_task_t *, isc_event_t *); #if 0 @@ -1264,7 +1261,8 @@ dns_zone_maintenance(dns_zone_t *zone) { default: break; } - (void) zone_settimer(zone, now); /*XXX*/ + if (!DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING)) + (void) zone_settimer(zone, now); } void @@ -1303,6 +1301,9 @@ dns_zone_refresh(dns_zone_t *zone) { isc_stdtime_get(&now); + if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING)) + return; + /* * Set DNS_ZONE_F_REFRESH so that there is only one refresh operation * in progress at the one time. @@ -1454,6 +1455,22 @@ dns_zone_setrefresh(dns_zone_t *zone, isc_uint32_t refresh, zone->retry = retry; } +static isc_boolean_t +notify_isqueued(dns_zone_t *zone, dns_name_t *name, isc_sockaddr_t *addr) { + notify_t *notify; + + for (notify = ISC_LIST_HEAD(zone->notifies); + notify != NULL; + notify = ISC_LIST_NEXT(notify, link)) { + if (name != NULL && dns_name_dynamic(¬ify->ns) && + dns_name_equal(name, ¬ify->ns)) + return (ISC_TRUE); + if (addr != NULL && isc_sockaddr_equal(addr, ¬ify->dst)) + return (ISC_TRUE); + } + return (ISC_FALSE); +} + static void notify_destroy(notify_t *notify) { isc_mem_t *mctx; @@ -1495,6 +1512,7 @@ notify_create(isc_mem_t *mctx, notify_t **notifyp) { notify->zone = NULL; notify->find = NULL; notify->request = NULL; + isc_sockaddr_any(¬ify->dst); dns_name_init(¬ify->ns, NULL); ISC_LINK_INIT(notify, link); notify->magic = NOTIFY_MAGIC; @@ -1585,8 +1603,9 @@ notify_send_queue(notify_t *notify) { if (e == NULL) return (ISC_R_NOMEMORY); e->ev_arg = notify; - e->ev_sender = notify; - result = isc_ratelimiter_enqueue(notify->zone->zmgr->rl, &e); + e->ev_sender = NULL; + result = isc_ratelimiter_enqueue(notify->zone->zmgr->rl, + notify->zone->task, &e); if (result != ISC_R_SUCCESS) isc_event_free(&e); return (result); @@ -1645,11 +1664,14 @@ notify_send(notify_t *notify) { if (result != ISC_R_SUCCESS) return; - ai = ISC_LIST_HEAD(notify->find->list); - while (ai != NULL) { + for (ai = ISC_LIST_HEAD(notify->find->list); + ai != NULL; + ai = ISC_LIST_NEXT(ai, publink)) { dst = *ai->sockaddr; if (isc_sockaddr_getport(&dst) == 0) isc_sockaddr_setport(&dst, 53); /* XXX */ + if (notify_isqueued(notify->zone, NULL, &dst)) + continue; new = NULL; result = notify_create(notify->mctx, &new); if (result != ISC_R_SUCCESS) @@ -1661,7 +1683,6 @@ notify_send(notify_t *notify) { if (result != ISC_R_SUCCESS) goto cleanup; new = NULL; - ai = ISC_LIST_NEXT(ai, publink); } cleanup: @@ -1675,7 +1696,6 @@ void dns_zone_notify(dns_zone_t *zone) { dns_dbnode_t *node = NULL; dns_dbversion_t *version = NULL; - dns_message_t *message = NULL; dns_name_t *origin = NULL; dns_name_t master; dns_rdata_ns_t ns; @@ -1686,49 +1706,48 @@ dns_zone_notify(dns_zone_t *zone) { isc_result_t result; notify_t *notify = NULL; unsigned int i; + isc_sockaddr_t dst; + isc_boolean_t isqueued; REQUIRE(DNS_ZONE_VALID(zone)); - if (!DNS_ZONE_OPTION(zone, DNS_ZONE_O_NOTIFY)) { - LOCK(&zone->lock); - zone->flags &= ~DNS_ZONE_F_NEEDNOTIFY; - UNLOCK(&zone->lock); - return; - } - - origin = &zone->origin; - - result = notify_createmessage(zone, &message); - if (result != ISC_R_SUCCESS) - return; - LOCK(&zone->lock); zone->flags &= ~DNS_ZONE_F_NEEDNOTIFY; UNLOCK(&zone->lock); + if (!DNS_ZONE_OPTION(zone, DNS_ZONE_O_NOTIFY)) { + return; + } + + origin = &zone->origin; + /* * Enqueue notify request. */ + LOCK(&zone->lock); for (i = 0; i < zone->notifycnt; i++) { + dst = zone->notify[i]; + if (isc_sockaddr_getport(&dst) == 0) + isc_sockaddr_setport(&dst, 53); /* XXX */ + if (notify_isqueued(zone, NULL, &dst)) + continue; result = notify_create(zone->mctx, ¬ify); - if (result != ISC_R_SUCCESS) - goto cleanup0; - dns_zone_attach(zone, ¬ify->zone); - notify->dst = zone->notify[i]; - if (isc_sockaddr_getport(¬ify->dst) == 0) - isc_sockaddr_setport(¬ify->dst, 53); /* XXX */ - LOCK(&zone->lock); + if (result != ISC_R_SUCCESS) { + UNLOCK(&zone->lock); + return; + } + zone_attach(zone, ¬ify->zone); + notify->dst = dst; ISC_LIST_APPEND(zone->notifies, notify, link); - UNLOCK(&zone->lock); result = notify_send_queue(notify); if (result != ISC_R_SUCCESS) { - LOCK(&zone->lock); notify_destroy(notify); UNLOCK(&zone->lock); - goto cleanup0; + return; } notify = NULL; } + UNLOCK(&zone->lock); /* * Process NS RRset to generate notifies. @@ -1789,6 +1808,11 @@ dns_zone_notify(dns_zone_t *zone) { result = dns_rdataset_next(&nsrdset); continue; } + LOCK(&zone->lock); + isqueued = notify_isqueued(zone, &ns.name, NULL); + UNLOCK(&zone->lock); + if (isqueued) + continue; result = notify_create(zone->mctx, ¬ify); if (result != ISC_R_SUCCESS) { dns_rdata_freestruct(&ns); @@ -1819,8 +1843,6 @@ dns_zone_notify(dns_zone_t *zone) { dns_db_detachnode(zone->db, &node); cleanup1: dns_db_closeversion(zone->db, &version, ISC_FALSE); - cleanup0: - dns_message_destroy(&message); } /*** @@ -1835,9 +1857,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { dns_message_t *msg = NULL; isc_uint32_t soacnt, cnamecnt, soacount, nscount; isc_stdtime_t now; - char *master; - isc_buffer_t masterbuf; - char mastermem[256]; + char master[ISC_SOCKADDR_FORMATSIZE]; dns_rdataset_t *rdataset; dns_rdata_t rdata; dns_rdata_soa_t soa; @@ -1855,12 +1875,9 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { * if timeout log and next master; */ - isc_buffer_init(&masterbuf, mastermem, sizeof(mastermem)); - result = isc_sockaddr_totext(&zone->masteraddr, &masterbuf); - if (result == ISC_R_SUCCESS) - master = (char *) masterbuf.base; - else - master = ""; + isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); + + isc_stdtime_get(&now); if (revent->result != ISC_R_SUCCESS) { zone_log(zone, me, ISC_LOG_INFO, "failure for %s: %s", @@ -1991,7 +2008,18 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { dns_request_destroy(&zone->request); queue_xfrin(zone); } else if (isc_serial_eq(soa.serial, zone->serial)) { - dns_zone_uptodate(zone); + if (zone->dbname != NULL) { + isc_time_t t; + isc_time_set(&t, now, 0); + result = isc_file_settime(zone->dbname, &t); + if (result != ISC_R_SUCCESS) + zone_log(zone, me, ISC_LOG_ERROR, + "isc_file_settime(%s): %s", + zone->dbname, + dns_result_totext(result)); + } + zone->refreshtime = now + zone->refresh; + zone->expiretime = now + zone->expire; goto next_master; } else { ZONE_LOG(1, "ahead"); @@ -2009,7 +2037,6 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { if (zone->curmaster >= zone->masterscnt) { zone->flags &= ~DNS_ZONE_F_REFRESH; - isc_stdtime_get(&now); zone_settimer(zone, now); UNLOCK(&zone->lock); return; @@ -2028,6 +2055,11 @@ queue_soa_query(dns_zone_t *zone) { DNS_ENTER; + if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING)) { + cancel_refresh(zone); + return; + } + e = isc_event_allocate(zone->mctx, NULL, DNS_EVENT_ZONE, soa_query, zone, sizeof(isc_event_t)); if (e == NULL) { @@ -2039,8 +2071,8 @@ queue_soa_query(dns_zone_t *zone) { * until the event is delivered. */ e->ev_arg = zone; - e->ev_sender = zone; - result = isc_ratelimiter_enqueue(zone->zmgr->rl, &e); + e->ev_sender = NULL; + result = isc_ratelimiter_enqueue(zone->zmgr->rl, zone->task, &e); if (result != ISC_R_SUCCESS) { dns_zone_detach(&dummy); isc_event_free(&e); @@ -2147,6 +2179,7 @@ static void zone_shutdown(isc_task_t *task, isc_event_t *event) { dns_zone_t *zone = (dns_zone_t *) event->ev_arg; notify_t *notify; + isc_result_t result; UNUSED(task); REQUIRE(DNS_ZONE_VALID(zone)); @@ -2183,6 +2216,12 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) { dns_request_cancel(notify->request); } + if (zone->timer != NULL) { + result = isc_timer_reset(zone->timer, isc_timertype_inactive, + NULL, NULL, ISC_TRUE); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } + if (zone->view != NULL) dns_view_weakdetach(&zone->view); @@ -3022,8 +3061,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { } static void -xfrdone(dns_zone_t *zone, isc_result_t result) { - const char me[] = "xfrdone"; +zone_xfrdone(dns_zone_t *zone, isc_result_t result) { + const char me[] = "zone_xfrdone"; isc_stdtime_t now; isc_boolean_t again = ISC_FALSE; @@ -3039,13 +3078,30 @@ xfrdone(dns_zone_t *zone, isc_result_t result) { switch (result) { case ISC_R_SUCCESS: zone->flags |= DNS_ZONE_F_NEEDNOTIFY; - /* FALLTHROUGH */ case DNS_R_UPTODATE: + /* + * This is not neccessary if we just performed a AXFR + * however it is necessary for an IXFR / UPTODATE and + * won't hurt with an AXFR. + */ + if (zone->dbname != NULL) { + isc_time_t t; + isc_time_set(&t, now, 0); + result = isc_file_settime(zone->dbname, &t); + if (result != ISC_R_SUCCESS) + zone_log(zone, me, ISC_LOG_ERROR, + "isc_file_settime(%s): %s", + zone->dbname, + dns_result_totext(result)); + } if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_NEEDREFRESH)) { zone->flags &= ~DNS_ZONE_F_NEEDREFRESH; zone->refreshtime = now; - } else + zone->expire = now + zone->expire; + } else { zone->refreshtime = now + zone->refresh; + zone->expire = now + zone->expire; + } break; default: @@ -3213,7 +3269,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { result = dns_xfrin_create(zone, xfrtype, &zone->masteraddr, tsigkey, zone->mctx, zone->zmgr->timermgr, zone->zmgr->socketmgr, - zone->task, xfrdone, &zone->xfr); + zone->task, zone_xfrdone, &zone->xfr); cleanup: /* * Any failure in this function is handled like a failed @@ -3221,7 +3277,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { * zmgr->xfrin_in_progress. */ if (result != ISC_R_SUCCESS) - xfrdone(zone, result); + zone_xfrdone(zone, result); isc_event_free(&event); @@ -3293,8 +3349,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, &zmgr->rl); if (result != ISC_R_SUCCESS) goto free_task; - /* 100 refresh queries / notifies per second. */ - isc_interval_set(&interval, 0, 1000000000/10); + /* 20 refresh queries / notifies per second. */ + isc_interval_set(&interval, 0, 1000000000/2); result = isc_ratelimiter_setinterval(zmgr->rl, &interval); RUNTIME_CHECK(result == ISC_R_SUCCESS); isc_ratelimiter_setpertic(zmgr->rl, 10); @@ -3518,7 +3574,7 @@ zmgr_resume_xfrs(dns_zonemgr_t *zmgr) { * * Returns: * ISC_R_SUCCESS There was enough quota and we attempted to - * start a transfer. xfrdone() has been or will + * start a transfer. zone_xfrdone() has been or will * be called. * ISC_R_QUOTA Not enough quota. * Others Failure. diff --git a/lib/isc/include/isc/ratelimiter.h b/lib/isc/include/isc/ratelimiter.h index 122e49bd00..b3724aad3f 100644 --- a/lib/isc/include/isc/ratelimiter.h +++ b/lib/isc/include/isc/ratelimiter.h @@ -67,16 +67,23 @@ isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t perint); */ isc_result_t -isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_event_t **eventp); +isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, + isc_event_t **eventp); /* * Queue an event for rate-limited execution. This is similar - * to doing an isc_task_send() to the rate limiter's task, except - * that the execution may be delayed to achieve the desired rate - * of execution. + * to doing an isc_task_send() to the 'task', except that the + * execution may be delayed to achieve the desired rate of + * execution. + * + * '(*eventp)->ev_sender' is used to hold the task. The caller + * must ensure that the task exists until the event is delivered. * * Requires: * An interval has been set by calling * isc_ratelimiter_setinterval(). + * + * 'task' to be non NULL. + * '(*eventp)->ev_sender' to be NULL. */ void diff --git a/lib/isc/ratelimiter.c b/lib/isc/ratelimiter.c index 0ca41753fd..dd3d50d99a 100644 --- a/lib/isc/ratelimiter.c +++ b/lib/isc/ratelimiter.c @@ -122,27 +122,37 @@ isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t pertic) { } isc_result_t -isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_event_t **eventp) { +isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, + isc_event_t **eventp) +{ isc_result_t result = ISC_R_SUCCESS; - INSIST(eventp != NULL && *eventp != NULL); + isc_event_t *ev; + + REQUIRE(eventp != NULL && *eventp != NULL); + REQUIRE(task != NULL); + ev = *eventp; + REQUIRE(ev->ev_sender == NULL); + LOCK(&rl->lock); if (rl->state == isc_ratelimiter_ratelimited) { isc_event_t *ev = *eventp; + ev->ev_sender = task; ISC_LIST_APPEND(rl->pending, ev, ev_link); *eventp = NULL; } else if (rl->state == isc_ratelimiter_worklimited) { result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL, &rl->interval, ISC_FALSE); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { + ev->ev_sender = task; rl->state = isc_ratelimiter_ratelimited; + } } else { INSIST(rl->state == isc_ratelimiter_shuttingdown); result = ISC_R_SHUTTINGDOWN; } UNLOCK(&rl->lock); - if (*eventp != NULL) - isc_task_send(rl->task, eventp); - ENSURE(*eventp == NULL); + if (*eventp != NULL && result == ISC_R_SUCCESS) + isc_task_send(task, eventp); return (result); } @@ -179,8 +189,10 @@ ratelimiter_tick(isc_task_t *task, isc_event_t *event) { pertic = 0; /* Force the loop to exit. */ } UNLOCK(&rl->lock); - if (p != NULL) - isc_task_send(rl->task, &p); + if (p != NULL) { + isc_task_t *evtask = p->ev_sender; + isc_task_send(evtask, &p); + } INSIST(p == NULL); } } @@ -188,6 +200,7 @@ ratelimiter_tick(isc_task_t *task, isc_event_t *event) { void isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) { isc_event_t *ev; + isc_task_t *task; LOCK(&rl->lock); rl->state = isc_ratelimiter_shuttingdown; (void) isc_timer_reset(rl->timer, isc_timertype_inactive, @@ -195,7 +208,8 @@ isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) { while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) { ISC_LIST_UNLINK(rl->pending, ev, ev_link); ev->ev_attributes |= ISC_EVENTATTR_CANCELED; - isc_task_send(rl->task, &ev); + task = ev->ev_sender; + isc_task_send(task, &ev); } UNLOCK(&rl->lock); }