diff --git a/daemon/worker.c b/daemon/worker.c index ac7053abd..cffaecc43 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1672,6 +1672,7 @@ worker_init(struct worker* worker, struct config_file *cfg, if(worker->thread_num == 0) log_set_time(worker->env.now); worker->env.worker = worker; + worker->env.worker_base = worker->base; worker->env.send_query = &worker_send_query; worker->env.alloc = &worker->alloc; worker->env.rnd = worker->rndstate; diff --git a/doc/Changelog b/doc/Changelog index 5f57f656e..73e7ce27a 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +19 October 2017: Wouter + - authzone work, probe timer setup. + 18 October 2017: Wouter - lint for recent authzone commit. diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 4067ef4d2..301a3e856 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -214,6 +214,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) libworker_delete(w); return NULL; } + w->env->worker_base = w->base; if(!w->is_bg || w->is_bg_thread) { lock_basic_lock(&ctx->cfglock); } diff --git a/services/authzone.c b/services/authzone.c index 21a8ee704..26541a28a 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -250,6 +250,7 @@ msg_add_rrset_ar(struct auth_zone* z, struct regional* region, struct auth_zones* auth_zones_create(void) { + /* TODO: create and put in env in worker and libworker */ struct auth_zones* az = (struct auth_zones*)calloc(1, sizeof(*az)); if(!az) { log_err("out of memory"); @@ -1245,8 +1246,62 @@ auth_zones_read_zones(struct auth_zones* az) return 1; } -/** setup all auth zones */ -int +/** Find auth_zone SOA and populate the values in xfr(soa values). */ +static int +xfr_find_soa(struct auth_zone* z, struct auth_xfer* xfr) +{ + struct auth_data* apex; + struct auth_rrset* soa; + struct packed_rrset_data* d; + apex = az_find_name(z, z->name, z->namelen); + if(!apex) return 0; + soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); + if(!soa || soa->data->count==0) + return 0; /* no RRset or no RRs in rrset */ + if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */ + /* SOA record ends with serial, refresh, retry, expiry, minimum, + * as 4 byte fields */ + d = soa->data; + xfr->have_zone = 1; + xfr->serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20)); + xfr->retry = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-16)); + xfr->refresh = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-12)); + xfr->expiry = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-8)); + /* soa minimum at d->rr_len[0]-4 */ + return 1; +} + +/** + * Setup auth_xfer zone + * This populates the have_zone, soa values, next_probe and so on times. + * Doesn't do network traffic yet, sets the timeout. + * @param z: locked by caller, and modified for setup + * @param x: locked by caller, and modified, timers and timeouts. + * @param env: module env with time. + * @return false on failure. + */ +static int +auth_xfer_setup(struct auth_zone* z, struct auth_xfer* x, struct module_env* env) +{ + if(!z || !x) return 1; + if(!xfr_find_soa(z, x)) { + return 1; + } + /* nextprobe setup */ + x->task_nextprobe->next_probe = 0; + if(x->have_zone) + x->task_nextprobe->lease_time = *env->now; + /* nothing for probe and transfer tasks */ + return 1; +} + +/** + * Setup all zones + * @param az: auth zones structure + * @param env: module env with time. + * @return false on failure. + */ +static int auth_zones_setup_zones(struct auth_zones* az, struct module_env* env) { struct auth_zone* z; @@ -1334,7 +1389,8 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c) return 1; } -int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg) +int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, + int setup, struct module_env* env) { struct config_auth* p; for(p = cfg->auths; p; p = p->next) { @@ -1349,6 +1405,10 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg) } if(!auth_zones_read_zones(az)) return 0; + if(setup) { + if(!auth_zones_setup_zones(az, env)) + return 0; + } return 1; } @@ -2635,6 +2695,34 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env, return 1; } +/** set a zone expired */ +static void +auth_xfer_set_expired(struct auth_xfer* xfr, struct module_env* env, + int expired) +{ + struct auth_zone* z; + + /* expire xfr */ + lock_basic_lock(&xfr->lock); + xfr->zone_expired = expired; + lock_basic_unlock(&xfr->lock); + + /* find auth_zone */ + lock_rw_rdlock(&env->auth_zones->lock); + z = auth_zone_find(env->auth_zones, xfr->name, xfr->namelen, + xfr->dclass); + if(!z) { + lock_rw_unlock(&env->auth_zones->lock); + return; + } + lock_rw_wrlock(&z->lock); + lock_rw_unlock(&env->auth_zones->lock); + + /* expire auth_zone */ + z->zone_expired = expired; + lock_rw_unlock(&z->lock); +} + /** the current transfer has finished, apply the results. * set timer for future probe. See if zone is expired now. */ void @@ -2663,37 +2751,99 @@ xfr_master_start(struct auth_xfer* xfr) return 0; } -/** Find auth_zone SOA and populate the values in xfr(soa values). */ -static int -xfr_find_soa(struct auth_zone* z, struct auth_xfer* xfr) +/** xfer nextprobe timeout callback */ +void auth_xfer_timer(void* arg) { - struct auth_data* apex; - struct auth_rrset* soa; - struct packed_rrset_data* d; - apex = az_find_name(z, z->name, z->namelen); - if(!apex) return 0; - soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); - if(!soa || soa->data->count==0) - return 0; /* no RRset or no RRs in rrset */ - if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */ - /* SOA record ends with serial, refresh, retry, expiry, minimum, - * as 4 byte fields */ - d = soa->data; - xfr->have_zone = 1; - xfr->serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20)); - xfr->retry = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-16)); - xfr->refresh = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-12)); - xfr->expiry = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-8)); - /* soa minimum at d->rr_len[0]-4 */ - return 1; + struct auth_xfer* xfr = (struct auth_xfer*)arg; + log_assert(xfr->task_nextprobe); + + /* see if zone has expired, and if so, also set auth_zone expired */ + if(xfr->have_zone && !xfr->zone_expired && + *(xfr->task_nextprobe->env->now) >= xfr->task_nextprobe->lease_time + + xfr->expiry) { + auth_xfer_set_expired(xfr, xfr->task_nextprobe->env, 1); + } + + /* see if we need to start a probe (or maybe it is already in + * progress (due to notify)) */ + /* TODO */ + + /* if we don't end up resetting the timer, delete it, because + * the next worker to pick this up does not have the same + * event base */ + comm_timer_delete(xfr->task_nextprobe->timer); + xfr->task_nextprobe->timer = NULL; + xfr->task_nextprobe->next_probe = 0; + /* we don't own this item anymore */ + xfr->task_nextprobe->worker = NULL; + xfr->task_nextprobe->env = NULL; } -/** determine next timeout for auth_xfer. Also (re)sets timer. */ -void -xfr_set_timeout(struct auth_xfer* xfr) +/** for task_nextprobe. + * determine next timeout for auth_xfer. Also (re)sets timer. + * @param xfr: task structure + * @param env: module environment, with worker and time. + * @param failure: set true if timer should be set for failure retry. + */ +static void +xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env, + int failure) { - (void)xfr; - /* TODO */ + struct timeval tv; + log_assert(xfr->task_nextprobe != NULL); + log_assert(xfr->task_nextprobe->worker == NULL || + xfr->task_nextprobe->worker == env->worker); + /* normally, nextprobe = startoflease + refresh, + * but if expiry is sooner, use that one. + * after a failure, use the retry timer instead. */ + xfr->task_nextprobe->next_probe = *env->now; + if(xfr->task_nextprobe->lease_time) + xfr->task_nextprobe->next_probe = + xfr->task_nextprobe->lease_time; + if(xfr->have_zone) { + time_t wait = xfr->refresh; + if(failure) wait = xfr->retry; + if(xfr->expiry < wait) + xfr->task_nextprobe->next_probe += xfr->expiry; + else xfr->task_nextprobe->next_probe += wait; + } + + if(!xfr->task_nextprobe->timer) { + xfr->task_nextprobe->timer = comm_timer_create( + env->worker_base, auth_xfer_timer, xfr); + if(!xfr->task_nextprobe->timer) { + /* failed to malloc memory. likely zone transfer + * also fails for that. skip the timeout */ + char zname[255+1]; + dname_str(xfr->name, zname); + log_err("cannot allocate timer, no refresh for %s", + zname); + return; + } + } + xfr->task_nextprobe->worker = env->worker; + xfr->task_nextprobe->env = env; + if(*(xfr->task_nextprobe->env->now) <= xfr->task_nextprobe->next_probe) + tv.tv_sec = xfr->task_nextprobe->next_probe - + *(xfr->task_nextprobe->env->now); + else tv.tv_sec = 0; + tv.tv_usec = 0; + comm_timer_set(xfr->task_nextprobe->timer, &tv); +} + +/** initial pick up of worker timeouts, ties events to worker event loop */ +void +auth_xfer_pickup_initial(struct auth_zones* az, struct module_env* env) +{ + struct auth_xfer* x; + lock_rw_wrlock(&az->lock); + RBTREE_FOR(x, struct auth_xfer*, &az->xtree) { + lock_basic_lock(&x->lock); + if(x->task_nextprobe && x->task_nextprobe->worker == NULL) + xfr_set_timeout(x, env, 0); + lock_basic_unlock(&x->lock); + } + lock_rw_unlock(&az->lock); } /** @@ -2723,7 +2873,6 @@ auth_xfer_new(struct auth_zone* z) free(xfr); return NULL; } - xfr->task_nextprobe->workernum = -1; xfr->task_probe = (struct auth_probe*)calloc(1, sizeof(struct auth_probe)); if(!xfr->task_probe) { @@ -2755,26 +2904,6 @@ auth_xfer_new(struct auth_zone* z) return xfr; } -/** - * Setup auth_xfer zone - * This populates the have_zone, soa values, next_probe and so on times. - * Doesn't do network traffic yet, sets the timeout. - */ -int -auth_xfer_setup(struct auth_zone* z, struct auth_xfer* x, struct module_env* env) -{ - if(!z || !x) return 1; - if(!xfr_find_soa(z, x)) { - return 1; - } - /* nextprobe setup */ - x->task_nextprobe->next_probe = 0; - if(x->have_zone) - x->task_nextprobe->lease_time = *env->now; - /* nothing for probe and transfer tasks */ - return 1; -} - /** Create auth_xfer structure. * This populates the have_zone, soa values, next_probe and so on times. * and sets the timeout, if a zone transfer is needed a short timeout is set. diff --git a/services/authzone.h b/services/authzone.h index b22810329..69cfd78ef 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -247,10 +247,10 @@ struct auth_xfer { * if unowned. */ struct auth_nextprobe { - /** worker num (or -1 unowned) that is performing this task */ - int workernum; - /* Worker pointer. Used by the worker during callbacks. */ + /* Worker pointer. NULL means unowned. */ struct worker* worker; + /* module env for this task */ + struct module_env* env; /** Timeout for next probe (for SOA) */ time_t next_probe; @@ -372,8 +372,14 @@ struct auth_zones* auth_zones_create(void); /** * Apply configuration to auth zones. Reads zonefiles. + * @param az: auth zones structure + * @param cfg: config to apply. + * @param setup: if true, also sets up values in the auth zones structure + * @parm env: for setup, with current time. + * @return false on failure. */ -int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg); +int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, + int setup, struct module_env* env); /** * Delete auth zones structure @@ -482,22 +488,4 @@ struct auth_xfer* auth_xfer_create(struct auth_zones* az, struct auth_zone* z); */ int xfer_set_masters(struct auth_master** list, struct config_auth* c); -/** - * Setup auth_xfer zone. Populates timeouts. - * @param z: locked by caller, and modified for setup - * @param x: locked by caller, and modified, timers and timeouts. - * @param env: module env with time. - * @return false on failure. - */ -int auth_xfer_setup(struct auth_zone* z, struct auth_xfer* xfr, - struct module_env* env); - -/** - * Setup all zones - * @param az: auth zones structure - * @param env: module env with time. - * @return false on failure. - */ -int auth_zones_setup_zones(struct auth_zones* az, struct module_env* env); - #endif /* SERVICES_AUTHZONE_H */ diff --git a/smallapp/unbound-checkconf.c b/smallapp/unbound-checkconf.c index 2b6f7faef..2b84aad12 100644 --- a/smallapp/unbound-checkconf.c +++ b/smallapp/unbound-checkconf.c @@ -579,7 +579,7 @@ static void check_auth(struct config_file* cfg) { struct auth_zones* az = auth_zones_create(); - if(!az || !auth_zones_apply_cfg(az, cfg)) { + if(!az || !auth_zones_apply_cfg(az, cfg, 0, NULL)) { fatal_exit("Could not setup authority zones"); } auth_zones_delete(az); diff --git a/util/module.h b/util/module.h index 415865c3d..90894d5ec 100644 --- a/util/module.h +++ b/util/module.h @@ -166,6 +166,8 @@ struct query_info; struct edns_data; struct regional; struct worker; +struct comm_base; +struct auth_zones; struct module_qstate; struct ub_randstate; struct mesh_area; @@ -445,6 +447,8 @@ struct module_env { struct sldns_buffer* scratch_buffer; /** internal data for daemon - worker thread. */ struct worker* worker; + /** the worker event base */ + struct comm_base* worker_base; /** mesh area with query state dependencies */ struct mesh_area* mesh; /** allocation service */ @@ -468,6 +472,8 @@ struct module_env { struct val_neg_cache* neg_cache; /** the 5011-probe timer (if any) */ struct comm_timer* probe_timer; + /** auth zones */ + struct auth_zones* auth_zones; /** Mapping of forwarding zones to targets. * iterator forwarder information. per-thread, created by worker */ struct iter_forwards* fwds;