return NULL;
}
mesh->histogram = timehist_setup();
- if(!mesh->histogram) {
+ mesh->qbuf_bak = ldns_buffer_new(env->cfg->msg_buffer_size);
+ if(!mesh->histogram || !mesh->qbuf_bak) {
free(mesh);
log_err("mesh area alloc: out of memory");
return NULL;
while(mesh->all.count)
mesh_delete_helper(mesh->all.root);
timehist_delete(mesh->histogram);
+ ldns_buffer_free(mesh->qbuf_bak);
free(mesh);
}
mesh->jostle_last = NULL;
}
-int mesh_make_new_space(struct mesh_area* mesh)
+int mesh_make_new_space(struct mesh_area* mesh, ldns_buffer* qbuf)
{
struct mesh_state* m = mesh->jostle_first;
/* free space is available */
"make space for a new one",
m->s.qinfo.qname, m->s.qinfo.qtype,
m->s.qinfo.qclass);
+ /* backup the query */
+ if(qbuf) ldns_buffer_copy(mesh->qbuf_bak, qbuf);
/* notify supers */
if(m->super_set.count > 0) {
verbose(VERB_ALGO, "notify supers of failure");
}
mesh->stats_jostled ++;
mesh_state_delete(&m->s);
+ /* restore the query - note that the qinfo ptr to
+ * the querybuffer is then correct again. */
+ if(qbuf) ldns_buffer_copy(qbuf, mesh->qbuf_bak);
return 1;
}
}
int added = 0;
/* does this create a new reply state? */
if(!s || s->list_select == mesh_no_list) {
- if(!mesh_make_new_space(mesh)) {
+ if(!mesh_make_new_space(mesh, rep->c->buffer)) {
verbose(VERB_ALGO, "Too many queries. dropping "
"incoming query.");
comm_point_drop_reply(rep);
s->s.prefetch_leeway = leeway;
return;
}
- if(!mesh_make_new_space(mesh)) {
+ if(!mesh_make_new_space(mesh, NULL)) {
verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
mesh->stats_dropped ++;
return;
{
struct mesh_state* m;
size_t s = sizeof(*mesh) + sizeof(struct timehist) +
- sizeof(struct th_buck)*mesh->histogram->num;
+ sizeof(struct th_buck)*mesh->histogram->num +
+ sizeof(ldns_buffer) + ldns_buffer_capacity(mesh->qbuf_bak);
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
/* all, including m itself allocated in qstate region */
s += regional_get_mem(m->s.region);
/** (extended stats) rcode nodata in replies */
size_t ans_nodata;
+ /** backup of query if other operations recurse and need the
+ * network buffers */
+ ldns_buffer* qbuf_bak;
+
/** double linked list of the run-to-completion query states.
* These are query states with a reply */
struct mesh_state* forever_first;
/**
* Make space for another recursion state for a reply in the mesh
* @param mesh: mesh area
+ * @param qbuf: query buffer to save if recursion is invoked to make space.
+ * This buffer is necessary, because the following sequence in calls
+ * can result in an overwrite of the incoming query:
+ * delete_other_mesh_query - iter_clean - serviced_delete - waiting
+ * udp query is sent - on error callback - callback sends SERVFAIL reply
+ * over the same network channel, and shared UDP buffer is overwritten.
+ * You can pass NULL if there is no buffer that must be backed up.
* @return false if no space is available.
*/
-int mesh_make_new_space(struct mesh_area* mesh);
+int mesh_make_new_space(struct mesh_area* mesh, ldns_buffer* qbuf);
/**
* Insert mesh state into a double linked list. Inserted at end.