#include "services/outside_network.h"
#include "services/outbound_list.h"
#include "services/cache/rrset.h"
+#include "services/mesh.h"
#include "util/data/msgparse.h"
#include "util/data/msgencode.h"
sizeof(struct work_query));
if(!q) return 0;
q->state.buf = worker->front->udp_buff;
- q->state.scratch = worker->scratchpad;
q->state.region = region_create_custom(malloc, free, 1024,
64, 16, 0);
if(!q->state.region) {
worker->env.worker = worker;
worker->env.alloc = &worker->alloc;
worker->env.rnd = worker->rndstate;
+ worker->env.scratch = worker->scratchpad;
+ worker->env.mesh = mesh_create(worker->daemon->num_modules,
+ worker->daemon->modfunc);
+ if(!worker->env.mesh) {
+ worker_delete(worker);
+ return 0;
+ }
return 1;
}
if(!worker)
return;
server_stats_log(&worker->stats, worker->thread_num);
+ mesh_delete(worker->env.mesh);
reqs_delete(worker);
qstate_free_recurs_list(worker, worker->slumber_list);
listen_delete(worker->front);
struct edns_data reply_edns;
int r;
if((r=reply_info_parse(qstate->reply->c->buffer, env->alloc,
- &reply_qinfo, &reply_msg, qstate->scratch,
+ &reply_qinfo, &reply_msg, qstate->env->scratch,
&reply_edns))!=0)
return 0;
qstate->edns.bits &= EDNS_DO;
if(!reply_info_answer_encode(&reply_qinfo, reply_msg, 0,
qstate->query_flags, qstate->buf, 0, 0,
- qstate->scratch, us, &qstate->edns,
+ qstate->env->scratch, us, &qstate->edns,
(int)(qstate->edns.bits&EDNS_DO)))
return 0;
dns_cache_store_msg(qstate->env, &reply_qinfo, qstate->query_hash,
edns.ext_rcode = 0;
edns.bits = qstate->edns.bits & EDNS_DO;
if(!reply_info_answer_encode(&qinf, msg->rep, 0, iq->orig_qflags,
- qstate->buf, 0, 1, qstate->scratch, qstate->edns.udp_size,
+ qstate->buf, 0, 1, qstate->env->scratch, qstate->edns.udp_size,
&edns, (int)(qstate->edns.bits & EDNS_DO))) {
/* encode servfail */
error_response(qstate, id, LDNS_RCODE_SERVFAIL);
subq->query_flags = 0; /* OPCODE QUERY, no flags */
subq->edns.udp_size = 65535;
subq->buf = qstate->buf;
- subq->scratch = qstate->scratch;
+ subq->env->scratch = qstate->env->scratch;
subq->region = region_create(malloc, free);
if(!subq->region) {
free(subq->qinfo.qname);
msg = dns_cache_lookup(qstate->env, qstate->qinfo.qname,
qstate->qinfo.qname_len, qstate->qinfo.qtype,
- qstate->qinfo.qclass, qstate->region, qstate->scratch);
+ qstate->qinfo.qclass, qstate->region, qstate->env->scratch);
if(msg) {
/* handle positive cache response */
enum response_type type = response_type_from_cache(msg,
}
/* parse message */
- prs = (struct msg_parse*)region_alloc(qstate->scratch,
+ prs = (struct msg_parse*)region_alloc(qstate->env->scratch,
sizeof(struct msg_parse));
if(!prs) {
log_err("out of memory on incoming message");
memset(&edns, 0, sizeof(edns));
pkt = qstate->reply->c->buffer;
ldns_buffer_set_position(pkt, 0);
- if(parse_packet(pkt, prs, qstate->scratch) != LDNS_RCODE_NOERROR) {
+ if(parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) {
verbose(VERB_ALGO, "parse error on reply packet");
goto handle_it;
}
/* normalize and sanitize: easy to delete items from linked lists */
if(!scrub_message(pkt, prs, &qstate->qinfo, iq->dp->name,
- qstate->scratch))
+ qstate->env->scratch))
goto handle_it;
/* allocate response dns_msg in region */
if(!a->is_priming && b->is_priming)
return 1;
- if((a->state->query_flags&BIT_RD) && !(b->state->query_flags&BIT_RD))
+ if((a->s.query_flags&BIT_RD) && !(b->s.query_flags&BIT_RD))
return -1;
- if(!(a->state->query_flags&BIT_RD) && (b->state->query_flags&BIT_RD))
+ if(!(a->s.query_flags&BIT_RD) && (b->s.query_flags&BIT_RD))
return 1;
- return query_info_compare(&a->state->qinfo, &b->state->qinfo);
+ return query_info_compare(&a->s.qinfo, &b->s.qinfo);
}
/** compare two mesh references */
}
struct mesh_area*
-mesh_create(struct worker* worker)
+mesh_create(int num_modules, struct module_func_block** modfunc)
{
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;
+ mesh->num_modules = num_modules;
+ mesh->modfunc = modfunc;
rbtree_init(&mesh->run, &mesh_state_compare);
rbtree_init(&mesh->all, &mesh_state_compare);
mesh->num_reply_addrs = 0;
void
mesh_delete(struct mesh_area* mesh)
{
+ struct mesh_state* mstate;
if(!mesh)
return;
/* free all query states */
+ RBTREE_FOR(mstate, struct mesh_state*, &mesh->all) {
+ mesh_state_cleanup(mstate);
+ }
free(mesh);
}
+
+struct mesh_state*
+mesh_state_create(struct module_env* env, struct query_info* qinfo,
+ uint16_t qflags, int prime)
+{
+ region_type* region = region_create(malloc, free);
+ struct mesh_state* mstate;
+ int i;
+ if(!region)
+ return NULL;
+ mstate = (struct mesh_state*)region_alloc(region,
+ sizeof(struct mesh_state));
+ if(!mstate) {
+ region_destroy(region);
+ return NULL;
+ }
+ mstate->node = *RBTREE_NULL;
+ mstate->run_node = *RBTREE_NULL;
+ mstate->node.key = mstate;
+ mstate->run_node.key = mstate;
+ mstate->is_priming = prime;
+ mstate->reply_list = NULL;
+ rbtree_init(&mstate->super_set, &mesh_state_ref_compare);
+ rbtree_init(&mstate->sub_set, &mesh_state_ref_compare);
+ /* init module qstate */
+ mstate->s.qinfo.qtype = qinfo->qtype;
+ mstate->s.qinfo.qclass = qinfo->qclass;
+ mstate->s.qinfo.qname_len = qinfo->qname_len;
+ mstate->s.qinfo.qname = region_alloc_init(region, qinfo->qname,
+ qinfo->qname_len);
+ if(!mstate->s.qinfo.qname) {
+ region_destroy(region);
+ return NULL;
+ }
+ /* remove all weird bits from qflags */
+ mstate->s.query_flags = (qflags & BIT_RD);
+ mstate->s.reply = NULL;
+ mstate->s.region = region;
+ mstate->s.curmod = 0;
+ mstate->s.env = env;
+ mstate->s.mesh_info = mstate;
+ /* init modules */
+ for(i=0; i<env->mesh->num_modules; i++) {
+ mstate->s.minfo[i] = NULL;
+ mstate->s.ext_state[i] = module_state_initial;
+ }
+ return mstate;
+}
+
+void
+mesh_state_cleanup(struct mesh_state* mstate)
+{
+ struct mesh_area* mesh;
+ int i;
+ if(!mstate)
+ return;
+ /* de-init modules */
+ mesh = mstate->s.env->mesh;
+ for(i=0; i<mesh->num_modules; i++) {
+ (*mesh->modfunc[i]->clear)(&mstate->s, i);
+ mstate->s.minfo[i] = NULL;
+ mstate->s.ext_state[i] = module_finished;
+ }
+ region_destroy(mstate->s.region);
+}
#include "util/rbtree.h"
#include "util/netevent.h"
#include "util/data/msgparse.h"
-struct module_qstate;
+#include "util/module.h"
struct mesh_state;
struct mesh_reply;
-struct worker;
struct query_info;
struct reply_info;
struct outbound_entry;
* Mesh of query states
*/
struct mesh_area {
- /** what worker this is a part of */
- struct worker* worker;
+ /** the number of modules */
+ int num_modules;
+ /** the module callbacks, array of num_modules length (ref only) */
+ struct module_func_block** modfunc;
+
/** set of runnable queries (mesh_state.run_node) */
rbtree_t run;
/** rbtree of all current queries (mesh_state.node)*/
* region. All parts (rbtree nodes etc) are also allocated in the region.
*/
struct mesh_state {
- /** node in mesh_area all tree, key is this struct */
+ /** node in mesh_area all tree, key is this struct. Must be first. */
rbnode_t node;
/** node in mesh_area runnable tree, key is this struct */
rbnode_t run_node;
int is_priming;
/** the query state. Note that the qinfo and query_flags
* may not change. */
- struct module_qstate* state;
+ struct module_qstate s;
/** the list of replies to clients for the results */
struct mesh_reply* reply_list;
/** set of superstates (that want this state's result)
/**
* Allocate mesh, to empty.
- * @param worker: what worker it is part of.
+ * @param num_modules: number of modules that are present.
+ * @param modfunc: array passed (alloced and deleted by caller), that has
+ * num_modules function callbacks for the modules.
* @return mesh: the new mesh or NULL on error.
*/
-struct mesh_area* mesh_create(struct worker* worker);
+struct mesh_area* mesh_create(int num_modules,
+ struct module_func_block** modfunc);
/**
* Delete mesh, and all query states and replies in it.
/**
* Create and initialize a new mesh state and its query state
+ * Does not put the mesh state into rbtrees and so on.
+ * @param env: module environment to set.
+ * @param qinfo: query info that the mesh is for.
+ * @param qflags: flags for query (RD flag).
+ * @param prime: if true, it is a priming query, set is_priming on mesh state.
+ * @return: new mesh state or NULL on allocation error.
*/
+struct mesh_state* mesh_state_create(struct module_env* env,
+ struct query_info* qinfo, uint16_t qflags, int prime);
/**
* Cleanup a mesh state and its query state. Does not do rbtree or
* reference cleanup.
+ * @param mstate: mesh state to cleanup. Its pointer may no longer be used
+ * afterwards. Cleanup rbtrees before calling this function.
*/
+void mesh_state_cleanup(struct mesh_state* mstate);
#endif /* SERVICES_MESH_H */
struct worker;
struct module_qstate;
struct ub_randstate;
+struct mesh_area;
+struct mesh_state;
/** Maximum number of modules in operation */
#define MAX_MODULE 2
*/
void (*remove_subqueries)(struct module_qstate* qstate);
+ /** region for temporary usage. May be cleared after operate() call. */
+ struct region* scratch;
/** internal data for daemon - worker thread. */
struct worker* worker;
+ /** mesh area with query state dependencies */
+ struct mesh_area* mesh;
/** allocation service */
struct alloc_cache* alloc;
/** random table to generate random numbers */
struct module_qstate {
/** which query is being answered: name, type, class */
struct query_info qinfo;
- /** hash value of the query qinfo */
- hashvalue_t query_hash;
/** flags uint16 from query */
uint16_t query_flags;
- /** edns data from the query */
- struct edns_data edns;
- /** buffer, store resulting reply here.
- * May be cleared when module blocks. */
- ldns_buffer* buf;
/** comm_reply contains server replies */
struct comm_reply* reply;
- /** region for temporary usage. May be cleared when module blocks. */
- struct region* scratch;
/** region for this query. Cleared when query process finishes. */
struct region* region;
void* minfo[MAX_MODULE];
/** environment for this query */
struct module_env* env;
- /** worker related state for this query. NULL for (sub)queries that do
- * not need to have answers sent to a client. */
- struct work_query* work_info;
+ /** mesh related information for this query */
+ struct mesh_state* mesh_info;
+ /** ----- TO DELETE */
+ struct work_query* work_info;
+ /** hash value of the query qinfo */
+ hashvalue_t query_hash;
+ /** edns data from the query */
+ struct edns_data edns;
+ /** buffer, store resulting reply here.
+ * May be cleared when module blocks. */
+ ldns_buffer* buf;
/** parent query, only nonNULL for subqueries */
struct module_qstate* parent;
/** pointer to first subquery below this one; makes list with next */
struct module_qstate* subquery_first;
-
/** pointer to next sibling subquery (not above or below this one) */
struct module_qstate* subquery_next;
/** pointer to prev sibling subquery (not above or below this one) */