}
buf[i++] = 'o';
buf[i] = 0;
- log_nametypeclass(VERB_ALGO, buf, p->qinfo.qname, p->qinfo.qtype,
- p->qinfo.qclass);
+ log_query_info(VERB_ALGO, buf, &p->qinfo);
for(p = p->subquery_first; p; p = p->subquery_next) {
run_debug(p, d+1);
}
+22 June 2007: Wouter
+ - removed unused _node iterator value from rbtree_t. Takes up space.
+ - iterator can handle querytargets state without a delegation point
+ set, so that a priming(stub) subquery error can be handled.
+ - iterator stores if it is priming or not.
+ - log_query_info() neater logging.
+
21 June 2007: Wouter
- Fixup secondary buffer in case of error callback.
- cleanup slumber list of runnable states.
iq->num_current_queries = 0;
iq->query_restart_count = 0;
iq->referral_count = 0;
+ iq->priming = 0;
iq->priming_stub = 0;
iq->orig_qflags = qstate->query_flags;
/* remove all weird bits from the query flags */
subiq->dp = dp;
/* suppress any target queries. */
subiq->num_target_queries = 0;
+ subiq->priming = 1;
/* this module stops, our submodule starts, and does the query. */
qstate->ext_state[id] = module_wait_subquery;
/* suppress any target queries -- although there wouldn't be anyway,
* since stub hints never have missing targets.*/
subiq->num_target_queries = 0;
+ subiq->priming = 1;
subiq->priming_stub = 1;
/* this module stops, our submodule starts, and does the query. */
size_t delnamelen;
struct dns_msg* msg;
- log_nametypeclass(VERB_DETAIL, "resolving", qstate->qinfo.qname,
- qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo);
/* check effort */
/* We enforce a maximum number of query restarts. This is primarily a
processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
struct iter_env* ie, int id)
{
- log_nametypeclass(VERB_DETAIL, "resolving (init part 2): ",
- qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "resolving (init part 2): ",
+ &qstate->qinfo);
/* Check to see if we need to prime a stub zone. */
if(prime_stub(qstate, iq, ie, id, qstate->qinfo.qname,
static int
processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq)
{
- log_nametypeclass(VERB_DETAIL, "resolving (init part 3): ",
- qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "resolving (init part 3): ",
+ &qstate->qinfo);
/* If the RD flag wasn't set, then we just finish with the
* cached referral as the response. */
if(!(qstate->query_flags & BIT_RD)) {
* needs to send a query to. That is, at least one per referral,
* more if some targets timeout or return throwaway answers. */
- log_nametypeclass(VERB_DETAIL, "processQueryTargets:",
- qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "processQueryTargets:", &qstate->qinfo);
verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, "
"currentqueries %d", iq->num_target_queries,
iq->num_current_queries);
"number of referrrals with %d", iq->referral_count);
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
+
+ /* Make sure we have a delegation point, otherwise priming failed
+ * or another failure occurred */
+ if(!iq->dp) {
+ verbose(VERB_DETAIL, "Failed to get a delegation, giving up");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
tf_policy = 0;
if(iq->depth <= ie->max_dependency_depth) {
}
/* We have a valid target. */
- log_nametypeclass(VERB_DETAIL, "sending query:", qstate->qinfo.qname,
- qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "sending query:", &qstate->qinfo);
log_name_addr(VERB_DETAIL, "sending to target:", iq->dp->name,
&target->addr, target->addrlen);
outq = (*qstate->env->send_query)(
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
- log_nametypeclass(VERB_DETAIL, "priming successful for",
- qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "priming successful for", &qstate->qinfo);
delegpt_log(dp);
foriq = (struct iter_qstate*)forq->minfo[id];
foriq->dp = dp;
processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
int id)
{
- log_nametypeclass(VERB_DETAIL, "finishing processing for",
- qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+ log_query_info(VERB_DETAIL, "finishing processing for",
+ &qstate->qinfo);
if(!iq->response) {
verbose(VERB_ALGO, "No response is set, servfail");
if(!dpns) {
/* not interested */
verbose(VERB_ALGO, "got subq error, but not interested");
- log_nametypeclass(VERB_ALGO, "errname",
- errinf.qname, errinf.qtype, errinf.qclass);
+ log_query_info(VERB_ALGO, "errname", &errinf);
delegpt_log(iq->dp);
return;
}
struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
verbose(VERB_DETAIL, "iterator[module %d] operate: extstate:%s event:%s",
id, strextstate(qstate->ext_state[id]), strmodulevent(event));
- if(iq) log_nametypeclass(VERB_DETAIL, "iterator operate: query",
- qstate->qinfo.qname, qstate->qinfo.qtype, qstate->qinfo.qclass);
+ if(iq) log_query_info(VERB_DETAIL, "iterator operate: query",
+ &qstate->qinfo);
if(ie->fwd_addrlen != 0) {
perform_forward(qstate, event, id, outbound);
return;
/** the number of times this query as followed a referral. */
int referral_count;
+ /**
+ * This flag, if true, means that this event is a priming query.
+ * In that case priming stub may be set as well.
+ */
+ int priming;
+
/**
* This is flag that, if true, means that this event is
* representing a stub priming query. It is meaningless unless
*/
#include "config.h"
#include "services/mesh.h"
+#include "util/log.h"
+#include "util/net_help.h"
+#include "util/module.h"
+#include "util/region-allocator.h"
+/** compare two mesh_states */
+static int
+mesh_state_compare(const void* ap, const void* bp)
+{
+ struct mesh_state* a = (struct mesh_state*)ap;
+ struct mesh_state* b = (struct mesh_state*)bp;
+
+ if(a->is_priming && !b->is_priming)
+ return -1;
+ if(!a->is_priming && b->is_priming)
+ return 1;
+
+ if((a->state->query_flags&BIT_RD) && !(b->state->query_flags&BIT_RD))
+ return -1;
+ if(!(a->state->query_flags&BIT_RD) && (b->state->query_flags&BIT_RD))
+ return 1;
+
+ return query_info_compare(&a->state->qinfo, &b->state->qinfo);
+}
+
+/** compare two mesh references */
+static int
+mesh_state_ref_compare(const void* ap, const void* bp)
+{
+ struct mesh_state_ref* a = (struct mesh_state_ref*)ap;
+ struct mesh_state_ref* b = (struct mesh_state_ref*)bp;
+ return mesh_state_compare(a->s, b->s);
+}
+
+struct mesh_area*
+mesh_create(struct worker* worker)
+{
+ struct mesh_area* mesh = calloc(1, sizeof(struct mesh_area));
+ if(!mesh) {
+ log_err("mesh area alloc: out of memory");
+ return NULL;
+ }
+ mesh->worker = worker;
+ rbtree_init(&mesh->run, &mesh_state_compare);
+ rbtree_init(&mesh->all, &mesh_state_compare);
+ mesh->num_reply_addrs = 0;
+ mesh->num_reply_states = 0;
+ mesh->num_detached_states = 0;
+ return mesh;
+}
+
+void
+mesh_delete(struct mesh_area* mesh)
+{
+ if(!mesh)
+ return;
+ /* free all query states */
+ free(mesh);
+}
struct worker;
struct query_info;
struct reply_info;
+struct outbound_entry;
/**
* Mesh of query states
*/
-struct query_mesh {
+struct mesh_area {
/** what worker this is a part of */
struct worker* worker;
- /** set of runnable queries (mesh_state_ref*) */
+ /** set of runnable queries (mesh_state.run_node) */
rbtree_t run;
- /** rbtree of all current queries */
+ /** rbtree of all current queries (mesh_state.node)*/
rbtree_t all;
- /** count of the number of mesh_reply entries */
- size_t reply_count;
- /** count of the number of mesh_states that have no mesh_replies
- * i.e. are for internal use. */
- size_t internal_count;
+
+ /** count of the total number of mesh_reply entries */
+ size_t num_reply_addrs;
+ /** count of the number of mesh_states that have mesh_replies
+ * Because a state can send results to multiple reply addresses,
+ * this number must be equal or lower than num_reply_addrs. */
+ size_t num_reply_states;
+ /** number of mesh_states that have no mesh_replies, and also
+ * an empty set of super-states, thus are 'toplevel' or detached
+ * internal opportunistic queries */
+ size_t num_detached_states;
};
/**
* A mesh query state
- * Unique per qname, qtype, qclass.
+ * Unique per qname, qtype, qclass (from the qstate).
* And RD flag; in case a client turns it off.
* And priming queries are different from ordinary queries (because of hints).
+ *
+ * The entire structure is allocated in a region, this region is the qstate
+ * region. All parts (rbtree nodes etc) are also allocated in the region.
*/
struct mesh_state {
- /** node in query_mesh all tree, key is this struct */
+ /** node in mesh_area all tree, key is this struct */
rbnode_t node;
- /** node in query_mesh runnable tree, key is this struct */
+ /** node in mesh_area runnable tree, key is this struct */
rbnode_t run_node;
- /** unique identity for this mesh state: what is it for */
- /* Note that qstate qinfo is changed by iterator */
-
- /** if this is a priming query (with hints) */
+ /** if this is a (stub or root) priming query (with hints) */
int is_priming;
-
- /** the query state */
+ /** the query state. Note that the qinfo and query_flags
+ * may not change. */
struct module_qstate* state;
/** the list of replies to clients for the results */
struct mesh_reply* reply_list;
struct comm_reply query_reply;
/** edns data from query */
struct edns_data edns;
+ /** the time when request was entered */
+ struct timeval start_time;
/** id of query, in network byteorder. */
uint16_t qid;
/** flags of query, for reply flags */
uint16_t qflags;
};
+/* ------------------- Functions for worker -------------------- */
+
/**
* Allocate mesh, to empty.
* @param worker: what worker it is part of.
* @return mesh: the new mesh or NULL on error.
*/
-struct query_mesh* mesh_create(struct worker* worker);
+struct mesh_area* mesh_create(struct worker* worker);
/**
* Delete mesh, and all query states and replies in it.
* @param mesh: the mesh to delete.
*/
-void mesh_delete(struct query_mesh* mesh);
+void mesh_delete(struct mesh_area* mesh);
/**
* New query incoming from clients. Create new query state if needed, and
* add mesh_reply to it. Returns error to client on malloc failures.
+ * Will run the mesh area queries to process if a new query state is created.
+ *
* @param mesh: the mesh.
* @param qinfo: query from client.
* @param qflags: flags from client query.
* @param edns: edns data from client query.
* @param rep: where to reply to.
- * @param id: query id to reply with.
+ * @param qid: query id to reply with.
*/
-void mesh_new_client(struct query_mesh* mesh, struct query_info* qinfo,
+void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
- uint16_t id);
+ uint16_t qid);
+
+/**
+ * Handle new event from the wire. A serviced query has returned.
+ * The query state will be made runnable, and the mesh_area will process
+ * query states until processing is complete.
+ *
+ * @param mesh: the query mesh.
+ * @param e: outbound entry, with query state to run and reply pointer.
+ * @param is_ok: if true, reply is OK, otherwise a timeout happened.
+ * @param reply: the comm point reply info.
+ */
+void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
+ int is_ok, struct comm_reply* reply);
+
+/* ------------------- Functions for module environment --------------- */
/**
* Detach-subqueries.
* the results from the new subquery.
* @param qinfo: what to query for (copied).
* @param qflags: what flags to use (RD flag or not).
- * @param prime: if it is a priming query.
+ * @param prime: if it is a (stub) priming query.
* @param newq: If the new subquery needs initialisation, it is returned,
* otherwise NULL is returned.
* @return: false on error, true if success (and init may be needed).
void mesh_walk_supers(struct module_qstate* qstate, int id, int rcode,
void (*cb)(struct module_qstate*, int, struct module_qstate*, int));
+/* ------------------- Functions for mesh -------------------- */
+
+/**
+ * Create and initialize a new mesh state and its query state
+ */
+
+/**
+ * Cleanup a mesh state and its query state. Does not do rbtree or
+ * reference cleanup.
+ */
+
#endif /* SERVICES_MESH_H */
ldns_buffer_free(buf);
region_destroy(region);
}
+
+void
+log_query_info(enum verbosity_value v, const char* str,
+ struct query_info* qinf)
+{
+ log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
+}
void log_dns_msg(const char* str, struct query_info* qinfo,
struct reply_info* rep);
+/**
+ * Print string with neat domain name, type, class from query info.
+ * @param v: at what verbosity level to print this.
+ * @param str: string of message.
+ * @param qinf: query info structure with name, type and class.
+ */
+void log_query_info(enum verbosity_value v, const char* str,
+ struct query_info* qinf);
+
#endif /* UTIL_DATA_MSGREPLY_H */
/** The number of the nodes in the tree */
size_t count;
- /** Current node for walks... */
- rbnode_t *_node;
-
/**
* Key compare function. <0,0,>0 like strcmp.
* Return 0 on two NULL ptrs.
*/
rbnode_t *rbtree_previous(rbnode_t *rbtree);
-/**
- * Macro to walk through the tree, sets k to key, d to data, for every element.
- */
-#define RBTREE_WALK(rbtree, k, d) \
- for((rbtree)->_node = rbtree_first(rbtree);\
- (rbtree)->_node != RBTREE_NULL && ((k) = (rbtree)->_node->key) && \
- ((d) = (void *) (rbtree)->_node); (rbtree)->_node = rbtree_next((rbtree)->_node))
-
/**
* Call with node=variable of struct* with rbnode_t as first element.
* with type is the type of a pointer to that struct.