summaryrefslogtreecommitdiff
path: root/services/mesh.c
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:55:57 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 11:55:57 +0000
commit2bda7bda432fb0f867072224dd97e10435c8ad94 (patch)
tree7ebfd82c2302bee4f9c05fb516c030153fb371d8 /services/mesh.c
parenta6c5280ea59f940be13fd6eb0f94ab8360d3d6c9 (diff)
downloadsrc-test2-2bda7bda432fb0f867072224dd97e10435c8ad94.tar.gz
src-test2-2bda7bda432fb0f867072224dd97e10435c8ad94.zip
Notes
Diffstat (limited to 'services/mesh.c')
-rw-r--r--services/mesh.c77
1 files changed, 74 insertions, 3 deletions
diff --git a/services/mesh.c b/services/mesh.c
index f04ae16ddbcb..3395dc62e674 100644
--- a/services/mesh.c
+++ b/services/mesh.c
@@ -533,9 +533,23 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
return 1;
}
+static void mesh_schedule_prefetch(struct mesh_area* mesh,
+ struct query_info* qinfo, uint16_t qflags, time_t leeway, int run);
+
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, time_t leeway)
{
+ mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
+}
+
+/* Internal backend routine of mesh_new_prefetch(). It takes one additional
+ * parameter, 'run', which controls whether to run the prefetch state
+ * immediately. When this function is called internally 'run' could be
+ * 0 (false), in which case the new state is only made runnable so it
+ * will not be run recursively on top of the current state. */
+static void mesh_schedule_prefetch(struct mesh_area* mesh,
+ struct query_info* qinfo, uint16_t qflags, time_t leeway, int run)
+{
struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
qflags&(BIT_RD|BIT_CD), 0, 0);
#ifdef UNBOUND_DEBUG
@@ -589,6 +603,18 @@ void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
s->list_select = mesh_jostle_list;
}
}
+
+ if(!run) {
+#ifdef UNBOUND_DEBUG
+ n =
+#else
+ (void)
+#endif
+ rbtree_insert(&mesh->run, &s->run_node);
+ log_assert(n != NULL);
+ return;
+ }
+
mesh_run(mesh, s, module_event_new, NULL);
}
@@ -666,6 +692,8 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
mstate->s.prefetch_leeway = 0;
mstate->s.no_cache_lookup = 0;
mstate->s.no_cache_store = 0;
+ mstate->s.need_refetch = 0;
+
/* init modules */
for(i=0; i<env->mesh->mods.num; i++) {
mstate->s.minfo[i] = NULL;
@@ -1288,9 +1316,30 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
return 1;
}
+/* Extract the query info and flags from 'mstate' into '*qinfop' and '*qflags'.
+ * Since this is only used for internal refetch of otherwise-expired answer,
+ * we simply ignore the rare failure mode when memory allocation fails. */
+static void
+mesh_copy_qinfo(struct mesh_state* mstate, struct query_info** qinfop,
+ uint16_t* qflags)
+{
+ struct regional* region = mstate->s.env->scratch;
+ struct query_info* qinfo;
+
+ qinfo = regional_alloc_init(region, &mstate->s.qinfo, sizeof(*qinfo));
+ if(!qinfo)
+ return;
+ qinfo->qname = regional_alloc_init(region, qinfo->qname,
+ qinfo->qname_len);
+ if(!qinfo->qname)
+ return;
+ *qinfop = qinfo;
+ *qflags = mstate->s.query_flags;
+}
+
/**
* Continue processing the mesh state at another module.
- * Handles module to modules tranfer of control.
+ * Handles module to modules transfer of control.
* Handles module finished.
* @param mesh: the mesh area.
* @param mstate: currently active mesh state.
@@ -1310,7 +1359,8 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
mstate->num_activated++;
if(mstate->num_activated > MESH_MAX_ACTIVATION) {
/* module is looping. Stop it. */
- log_err("internal error: looping module stopped");
+ log_err("internal error: looping module (%s) stopped",
+ mesh->mods.mod[mstate->s.curmod]->name);
log_query_info(VERB_QUERY, "pass error for qstate",
&mstate->s.qinfo);
s = module_error;
@@ -1350,11 +1400,32 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
/* error is bad, handle pass back up below */
mstate->s.return_rcode = LDNS_RCODE_SERVFAIL;
}
- if(s == module_error || s == module_finished) {
+ if(s == module_error) {
+ mesh_query_done(mstate);
+ mesh_walk_supers(mesh, mstate);
+ mesh_state_delete(&mstate->s);
+ return 0;
+ }
+ if(s == module_finished) {
if(mstate->s.curmod == 0) {
+ struct query_info* qinfo = NULL;
+ uint16_t qflags;
+
mesh_query_done(mstate);
mesh_walk_supers(mesh, mstate);
+
+ /* If the answer to the query needs to be refetched
+ * from an external DNS server, we'll need to schedule
+ * a prefetch after removing the current state, so
+ * we need to make a copy of the query info here. */
+ if(mstate->s.need_refetch)
+ mesh_copy_qinfo(mstate, &qinfo, &qflags);
+
mesh_state_delete(&mstate->s);
+ if(qinfo) {
+ mesh_schedule_prefetch(mesh, qinfo, qflags,
+ 0, 1);
+ }
return 0;
}
/* pass along the locus of control */