worker->env.kill_sub = &mesh_state_delete;
worker->env.query_done = &mesh_query_done;
worker->env.walk_supers = &mesh_walk_supers;
+ worker->env.detect_cycle = &mesh_detect_cycle;
if(!worker->env.mesh) {
worker_delete(worker);
return 0;
+26 July 2007: Wouter
+ - cycle detection, for query state dependencies. Will attempt to
+ circumvent the cycle, but if no other targets available fails.
+
25 July 2007: Wouter
- testbound read ADDRESS and check it.
- test for version.bind and friends.
sel = ub_random(rnd) % m;
return (sel < n);
}
+
+/** detect dependency cycle for query and target */
+static int
+causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
+ uint16_t t, uint16_t c)
+{
+ struct query_info qinf;
+ qinf.qname = name;
+ qinf.qname_len = namelen;
+ qinf.qtype = t;
+ qinf.qclass = c;
+ return (*qstate->env->detect_cycle)(qstate, &qinf);
+}
+
+void
+iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
+{
+ struct delegpt_ns* ns;
+ for(ns = dp->nslist; ns; ns = ns->next) {
+ if(ns->resolved)
+ continue;
+ /* see if this ns as target causes dependency cycle */
+ if(causes_cycle(qstate, ns->name, ns->namelen,
+ LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
+ causes_cycle(qstate, ns->name, ns->namelen,
+ LDNS_RR_TYPE_A, qstate->qinfo.qclass))
+ ns->resolved = 1;
+ }
+}
struct ub_randstate;
struct query_info;
struct reply_info;
+struct module_qstate;
/**
* Process config options and set iterator module state.
*/
int iter_ns_probability(struct ub_randstate* rnd, int n, int m);
+/**
+ * Mark targets that result in a dependency cycle as done, so they
+ * will not get selected as targets.
+ * @param qstate: query state.
+ * @param dp: delegpt to mark ns in.
+ */
+void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
+
#endif /* ITERATOR_ITER_UTILS_H */
{
int query_count = 0;
struct delegpt_ns* ns = iq->dp->nslist;
- int missing = (int)delegpt_count_missing_targets(iq->dp);
+ int missing;
int toget = 0;
+
+ iter_mark_cycle_targets(qstate, iq->dp);
+ missing = (int)delegpt_count_missing_targets(iq->dp);
log_assert(maxtargets != 0); /* that would not be useful */
/* Generate target requests. Basically, any missing targets
missing --;
continue;
}
- if(iq->refetch_glue && dname_subdomain_c(ns->name,
- iq->dp->name)) {
- log_nametypeclass(VERB_DETAIL, "skip double glue "
- "refetch", ns->name, LDNS_RR_TYPE_A,
- iq->qchase.qclass);
- continue;
- }
if(ie->supports_ipv6) {
/* Send the AAAA request. */
}
return s;
}
+
+/** helper recursive rbtree find routine */
+static int
+find_in_subsub(struct mesh_state* m, struct mesh_state* tofind)
+{
+ struct mesh_state_ref* r;
+ RBTREE_FOR(r, struct mesh_state_ref*, &m->sub_set) {
+ if(r->s == tofind || find_in_subsub(r->s, tofind))
+ return 1;
+ }
+ return 0;
+}
+
+int
+mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo)
+{
+ struct mesh_area* mesh = qstate->env->mesh;
+ struct mesh_state* cyc_m = qstate->mesh_info;
+ struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, BIT_RD, 0);
+ if(!dep_m)
+ return 0;
+ if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m))
+ return 1;
+ return 0;
+}
*/
size_t mesh_get_mem(struct mesh_area* mesh);
+/**
+ * Find cycle; see if the given mesh is in the targets sub, or sub-sub, ...
+ * trees.
+ * @param qstate: given mesh querystate.
+ * @param qinfo: query info for dependency.
+ * @return true if the name,type,class exists and the given qstate mesh exists
+ * as a dependency of that name. Thus if qstate becomes dependent on
+ * name,type,class then a cycle is created.
+ */
+int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo);
+
#endif /* SERVICES_MESH_H */
void (*walk_supers)(struct module_qstate* qstate, int id,
void (*cb)(struct module_qstate*, int, struct module_qstate*));
+ /**
+ * Detect if adding a dependency for qstate on name,type,class will
+ * create a dependency cycle.
+ * @param qstate: given mesh querystate.
+ * @param qinfo: query info for dependency. Assumed RDflag and not
+ * priming.
+ * @return true if the name,type,class exists and the given
+ * qstate mesh exists as a dependency of that name. Thus
+ * if qstate becomes dependent on name,type,class then a
+ * cycle is created.
+ */
+ int (*detect_cycle)(struct module_qstate* qstate,
+ struct query_info* qinfo);
+
/** region for temporary usage. May be cleared after operate() call. */
struct region* scratch;
/** internal data for daemon - worker thread. */