unbound  0.1
Functions
mesh.c File Reference

This file contains functions to assist in dealing with a mesh of query states. More...

#include "config.h"
#include <ldns/wire2host.h>
#include "services/mesh.h"
#include "services/outbound_list.h"
#include "services/cache/dns.h"
#include "util/log.h"
#include "util/net_help.h"
#include "util/module.h"
#include "util/regional.h"
#include "util/data/msgencode.h"
#include "util/timehist.h"
#include "util/fptr_wlist.h"
#include "util/alloc.h"
#include "util/config_file.h"

Functions

static void timeval_subtract (struct timeval *d, const struct timeval *end, const struct timeval *start)
 subtract timers and the values do not overflow or become negative
static void timeval_add (struct timeval *d, const struct timeval *add)
 add timers and the values do not overflow or become negative
static void timeval_divide (struct timeval *avg, const struct timeval *sum, size_t d)
 divide sum of timers to get average
static int timeval_smaller (const struct timeval *x, const struct timeval *y)
 histogram compare of time values
int mesh_state_compare (const void *ap, const void *bp)
 compare two mesh_states
int mesh_state_ref_compare (const void *ap, const void *bp)
 compare two mesh references
struct mesh_areamesh_create (struct module_stack *stack, struct module_env *env)
 Allocate mesh, to empty.
static void mesh_delete_helper (rbnode_t *n)
 help mesh delete delete mesh states
void mesh_delete (struct mesh_area *mesh)
 Delete mesh, and all query states and replies in it.
void mesh_delete_all (struct mesh_area *mesh)
 Delete all mesh states from the mesh.
int mesh_make_new_space (struct mesh_area *mesh, ldns_buffer *qbuf)
 Make space for another recursion state for a reply in the mesh.
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 qid)
 New query incoming from clients.
int mesh_new_callback (struct mesh_area *mesh, struct query_info *qinfo, uint16_t qflags, struct edns_data *edns, ldns_buffer *buf, uint16_t qid, mesh_cb_func_t cb, void *cb_arg)
 New query with callback.
void mesh_new_prefetch (struct mesh_area *mesh, struct query_info *qinfo, uint16_t qflags, uint32_t leeway)
 New prefetch message.
void mesh_report_reply (struct mesh_area *mesh, struct outbound_entry *e, struct comm_reply *reply, int what)
 Handle new event from the wire.
struct mesh_statemesh_state_create (struct module_env *env, struct query_info *qinfo, uint16_t qflags, int prime)
 Create and initialize a new mesh state and its query state Does not put the mesh state into rbtrees and so on.
void mesh_state_cleanup (struct mesh_state *mstate)
 Cleanup a mesh state and its query state.
void mesh_state_delete (struct module_qstate *qstate)
 Delete mesh state, cleanup and also rbtrees and so on.
static int find_in_subsub (struct mesh_state *m, struct mesh_state *tofind, size_t *c)
 helper recursive rbtree find routine
static int mesh_detect_cycle_found (struct module_qstate *qstate, struct mesh_state *dep_m)
 find cycle for already looked up mesh_state
void mesh_detach_subs (struct module_qstate *qstate)
 Detach-subqueries.
int mesh_attach_sub (struct module_qstate *qstate, struct query_info *qinfo, uint16_t qflags, int prime, struct module_qstate **newq)
 Attach subquery.
int mesh_state_attachment (struct mesh_state *super, struct mesh_state *sub)
 Setup attachment super/sub relation between super and sub mesh state.
static void mesh_do_callback (struct mesh_state *m, int rcode, struct reply_info *rep, struct mesh_cb *r)
 callback results to mesh cb entry
static void mesh_send_reply (struct mesh_state *m, int rcode, struct reply_info *rep, struct mesh_reply *r, struct mesh_reply *prev)
 Send reply to mesh reply entry.
void mesh_query_done (struct mesh_state *mstate)
 Query state is done, send messages to reply entries.
void mesh_walk_supers (struct mesh_area *mesh, struct mesh_state *mstate)
 Call inform_super for the super query states that are interested in the results from this query state.
struct mesh_statemesh_area_find (struct mesh_area *mesh, struct query_info *qinfo, uint16_t qflags, int prime)
 Find a mesh state in the mesh area.
int mesh_state_add_cb (struct mesh_state *s, struct edns_data *edns, ldns_buffer *buf, mesh_cb_func_t cb, void *cb_arg, uint16_t qid, uint16_t qflags)
 Create new callback structure and attach it to a mesh state.
int mesh_state_add_reply (struct mesh_state *s, struct edns_data *edns, struct comm_reply *rep, uint16_t qid, uint16_t qflags, uint8_t *qname)
 Create new reply structure and attach it to a mesh state.
static int mesh_continue (struct mesh_area *mesh, struct mesh_state *mstate, enum module_ext_state s, enum module_ev *ev)
 Continue processing the mesh state at another module.
void mesh_run (struct mesh_area *mesh, struct mesh_state *mstate, enum module_ev ev, struct outbound_entry *e)
 Run the mesh.
void mesh_log_list (struct mesh_area *mesh)
 Print all the states in the mesh to the log.
void mesh_stats (struct mesh_area *mesh, const char *str)
 Print some stats about the mesh to the log.
void mesh_stats_clear (struct mesh_area *mesh)
 Clear the stats that the mesh keeps (number of queries serviced)
size_t mesh_get_mem (struct mesh_area *mesh)
 Calculate memory size in use by mesh and all queries inside it.
int mesh_detect_cycle (struct module_qstate *qstate, struct query_info *qinfo, uint16_t flags, int prime)
 Find cycle; see if the given mesh is in the targets sub, or sub-sub, ...
void mesh_list_insert (struct mesh_state *m, struct mesh_state **fp, struct mesh_state **lp)
 Insert mesh state into a double linked list.
void mesh_list_remove (struct mesh_state *m, struct mesh_state **fp, struct mesh_state **lp)
 Remove mesh state from a double linked list.

Detailed Description

This file contains functions to assist in dealing with a mesh of query states.

This mesh is supposed to be thread-specific. It consists of query states (per qname, qtype, qclass) and connections between query states and the super and subquery states, and replies to send back to clients.


Function Documentation

struct mesh_area* mesh_create ( struct module_stack stack,
struct module_env env 
) [read]
void mesh_delete ( struct mesh_area mesh)

Delete mesh, and all query states and replies in it.

Parameters:
mesh,:the mesh to delete.

References mesh_area::all, rbtree_t::count, mesh_area::histogram, mesh_delete_helper(), mesh_area::qbuf_bak, rbtree_t::root, and timehist_delete().

Referenced by libworker_delete(), and worker_delete().

void mesh_delete_all ( struct mesh_area mesh)
int mesh_make_new_space ( struct mesh_area mesh,
ldns_buffer *  qbuf 
)

Make space for another recursion state for a reply in the mesh.

Parameters:
mesh,:mesh area
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.
Returns:
false if no space is available.

References rbtree_t::count, mesh_area::env, mesh_area::jostle_first, mesh_area::jostle_max, log_nametypeclass(), mesh_area::max_reply_states, mesh_state_delete(), mesh_walk_supers(), module_env::now_tv, mesh_area::num_reply_states, mesh_area::qbuf_bak, query_info::qclass, module_qstate::qinfo, query_info::qname, query_info::qtype, mesh_state::reply_list, module_qstate::return_msg, module_qstate::return_rcode, mesh_state::s, mesh_reply::start_time, mesh_area::stats_jostled, mesh_state::super_set, timeval_smaller(), timeval_subtract(), VERB_ALGO, and verbose().

Referenced by mesh_new_client(), and mesh_new_prefetch().

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  qid 
)
int mesh_new_callback ( struct mesh_area mesh,
struct query_info qinfo,
uint16_t  qflags,
struct edns_data edns,
ldns_buffer *  buf,
uint16_t  qid,
mesh_cb_func_t  cb,
void *  cb_arg 
)

New query with callback.

Create new query state if needed, and add mesh_cb to it. Will run the mesh area queries to process if a new query state is created.

Parameters:
mesh,:the mesh.
qinfo,:query from client.
qflags,:flags from client query.
edns,:edns data from client query.
buf,:buffer for reply contents.
qid,:query id to reply with.
cb,:callback function.
cb_arg,:callback user arg.
Returns:
0 on error.

References mesh_area::all, BIT_RD, mesh_state::cb_list, rbtree_t::count, mesh_area::env, log_assert, mesh_area_find(), mesh_run(), mesh_state_add_cb(), mesh_state_create(), mesh_state_delete(), module_event_new, mesh_state::node, mesh_area::num_detached_states, mesh_area::num_reply_addrs, mesh_area::num_reply_states, rbtree_insert(), mesh_state::reply_list, mesh_state::s, and mesh_state::super_set.

Referenced by handle_newq(), libworker_fg(), and probe_anchor().

void mesh_new_prefetch ( struct mesh_area mesh,
struct query_info qinfo,
uint16_t  qflags,
uint32_t  leeway 
)

New prefetch message.

Create new query state if needed. Will run the mesh area queries to process if a new query state is created.

Parameters:
mesh,:the mesh.
qinfo,:query from client.
qflags,:flags from client query.
leeway,:TTL leeway what to expire earlier for this update.

References mesh_area::all, BIT_RD, module_qstate::blacklist, mesh_area::env, mesh_area::forever_first, mesh_area::forever_last, mesh_area::jostle_first, mesh_area::jostle_last, log_assert, log_err(), mesh_area::max_forever_states, mesh_area_find(), mesh_list_insert(), mesh_make_new_space(), mesh_run(), mesh_state_create(), module_event_new, mesh_state::node, mesh_area::num_detached_states, mesh_area::num_forever_states, module_qstate::prefetch_leeway, rbtree_insert(), module_qstate::region, mesh_state::s, sock_list_insert(), mesh_area::stats_dropped, VERB_ALGO, and verbose().

Referenced by reply_and_prefetch().

void mesh_report_reply ( struct mesh_area mesh,
struct outbound_entry e,
struct comm_reply reply,
int  what 
)

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.

Parameters:
mesh,:the query mesh.
e,:outbound entry, with query state to run and reply pointer.
reply,:the comm point reply info.
what,:NETEVENT_* error code (if not 0, what is wrong, TIMEOUT).

References module_qstate::mesh_info, mesh_run(), module_event_capsfail, module_event_noreply, module_event_reply, NETEVENT_CAPSFAIL, NETEVENT_NOERROR, outbound_entry::qstate, and module_qstate::reply.

Referenced by libworker_handle_reply(), libworker_handle_service_reply(), worker_handle_reply(), and worker_handle_service_reply().

struct mesh_state* mesh_state_create ( struct module_env env,
struct query_info qinfo,
uint16_t  qflags,
int  prime 
) [read]
void mesh_state_cleanup ( struct mesh_state mstate)
void mesh_state_delete ( struct module_qstate qstate)
void mesh_detach_subs ( struct module_qstate qstate)
int mesh_attach_sub ( struct module_qstate qstate,
struct query_info qinfo,
uint16_t  qflags,
int  prime,
struct module_qstate **  newq 
)

Attach subquery.

Creates it if it does not exist already. Keeps sub and super references correct. Performs a cycle detection - for double check - and fails if there is one. Also fails if the sub-sub-references become too large. Updates stat items in mesh_area structure. Pass if it is priming query or not. return: o if error (malloc) happened. o need to initialise the new state (module init; it is a new state). so that the next run of the query with this module is successful. o no init needed, attachment successful.

Parameters:
qstate,:the state to find mesh state, and that wants to receive the results from the new subquery.
qinfo,:what to query for (copied).
qflags,:what flags to use (RD / CD flag or not).
prime,:if it is a (stub) priming query.
newq,:If the new subquery needs initialisation, it is returned, otherwise NULL is returned.
Returns:
: false on error, true if success (and init may be needed).

References mesh_area::all, mesh_state::cb_list, rbtree_t::count, module_qstate::env, log_assert, log_err(), module_env::mesh, mesh_area_find(), mesh_detect_cycle_found(), module_qstate::mesh_info, mesh_state_attachment(), mesh_state_create(), mesh_state::node, mesh_area::num_detached_states, rbtree_insert(), mesh_state::reply_list, mesh_area::run, mesh_state::run_node, mesh_state::s, mesh_state::super_set, VERB_ALGO, and verbose().

Referenced by fptr_whitelist_modenv_attach_sub(), libworker_setup(), and worker_init().

int mesh_state_attachment ( struct mesh_state super,
struct mesh_state sub 
)

Setup attachment super/sub relation between super and sub mesh state.

The relation must not be present when calling the function. Does not update stat items in mesh_area.

Parameters:
super,:super state.
sub,:sub state.
Returns:
: 0 on alloc error.

References rbnode_t::key, log_assert, log_err(), mesh_state_ref::node, rbtree_insert(), module_qstate::region, regional_alloc(), mesh_state::s, mesh_state_ref::s, mesh_state::sub_set, and mesh_state::super_set.

Referenced by mesh_attach_sub().

static void mesh_do_callback ( struct mesh_state m,
int  rcode,
struct reply_info rep,
struct mesh_cb r 
) [static]
static void mesh_send_reply ( struct mesh_state m,
int  rcode,
struct reply_info rep,
struct mesh_reply r,
struct mesh_reply prev 
) [static]
void mesh_query_done ( struct mesh_state mstate)

Query state is done, send messages to reply entries.

Encode messages using reply entry values and the querystate (with original qinfo), using given reply_info. Pass errcode != 0 if an error reply is needed. If no reply entries, nothing is done. Must be called before a module can module_finished or return module_error. The module must handle the super query states itself as well.

Parameters:
mstate,:mesh state that is done. return_rcode and return_msg are used for replies. return_rcode: if not 0 (NOERROR) an error is sent back (and return_msg is ignored). return_msg: reply to encode and send back to clients.

References mesh_state::cb_list, mesh_do_callback(), mesh_send_reply(), mesh_reply::next, mesh_cb::next, dns_msg::rep, mesh_state::replies_sent, mesh_state::reply_list, module_qstate::return_msg, module_qstate::return_rcode, and mesh_state::s.

Referenced by mesh_continue().

void mesh_walk_supers ( struct mesh_area mesh,
struct mesh_state mstate 
)

Call inform_super for the super query states that are interested in the results from this query state.

These can then be changed for error or results. Called when a module is module_finished or returns module_error. The super query states become runnable with event module_event_pass, it calls the current module for the super with the inform_super event.

Parameters:
mesh,:mesh area to add newly runnable modules to.
mstate,:the state that has results, used to find mesh state.

References module_qstate::curmod, fptr_ok, fptr_whitelist_mod_inform_super(), module_func_block::inform_super, module_stack::mod, mesh_area::mods, RBTREE_FOR, rbtree_insert(), mesh_area::run, mesh_state::run_node, mesh_state::s, mesh_state_ref::s, and mesh_state::super_set.

Referenced by mesh_continue(), and mesh_make_new_space().

struct mesh_state* mesh_area_find ( struct mesh_area mesh,
struct query_info qinfo,
uint16_t  qflags,
int  prime 
) [read]

Find a mesh state in the mesh area.

Pass relevant flags.

Parameters:
mesh,:the mesh area to look in.
qinfo,:what query
qflags,:if RD / CD bit is set or not.
prime,:if it is a priming query.
Returns:
: mesh state or NULL if not found.

References mesh_area::all, module_qstate::is_priming, rbnode_t::key, mesh_state::node, module_qstate::qinfo, module_qstate::query_flags, rbtree_search(), and mesh_state::s.

Referenced by mesh_attach_sub(), mesh_detect_cycle(), mesh_new_callback(), mesh_new_client(), and mesh_new_prefetch().

int mesh_state_add_cb ( struct mesh_state s,
struct edns_data edns,
ldns_buffer *  buf,
mesh_cb_func_t  cb,
void *  cb_arg,
uint16_t  qid,
uint16_t  qflags 
)

Create new callback structure and attach it to a mesh state.

Does not update stat items in mesh area.

Parameters:
s,:the mesh state.
edns,:edns data for reply (bufsize).
buf,:buffer for reply
cb,:callback to call with results.
cb_arg,:callback user arg.
qid,:ID of reply.
qflags,:original query flags.
Returns:
: 0 on alloc error.

References mesh_cb::buf, mesh_cb::cb, mesh_cb::cb_arg, mesh_state::cb_list, mesh_cb::edns, fptr_whitelist_mesh_cb(), log_assert, mesh_cb::next, mesh_cb::qflags, mesh_cb::qid, module_qstate::region, regional_alloc(), and mesh_state::s.

Referenced by mesh_new_callback().

int mesh_state_add_reply ( struct mesh_state s,
struct edns_data edns,
struct comm_reply rep,
uint16_t  qid,
uint16_t  qflags,
uint8_t *  qname 
)

Create new reply structure and attach it to a mesh state.

Does not update stat items in mesh area.

Parameters:
s,:the mesh state.
edns,:edns data for reply (bufsize).
rep,:comm point reply info.
qid,:ID of reply.
qflags,:original query flags.
qname,:original query name.
Returns:
: 0 on alloc error.

References mesh_reply::edns, module_qstate::env, mesh_reply::next, module_env::now_tv, mesh_reply::qflags, mesh_reply::qid, module_qstate::qinfo, mesh_reply::qname, query_info::qname_len, mesh_reply::query_reply, module_qstate::region, regional_alloc(), regional_alloc_init(), mesh_state::reply_list, mesh_state::s, and mesh_reply::start_time.

Referenced by mesh_new_client().

static int mesh_continue ( struct mesh_area mesh,
struct mesh_state mstate,
enum module_ext_state  s,
enum module_ev ev 
) [static]

Continue processing the mesh state at another module.

Handles module to modules tranfer of control. Handles module finished.

Parameters:
mesh,:the mesh area.
mstate,:currently active mesh state. Deleted if finished, calls _done and _supers to send replies to clients and inform other mesh states. This in turn may create additional runnable mesh states.
s,:state at which the current module exited.
ev,:the event sent to the module. returned is the event to send to the next module.
Returns:
true if continue processing at the new module. false if not continued processing is needed.

References module_func_block::clear, module_qstate::curmod, fptr_ok, fptr_whitelist_mod_clear(), log_err(), log_query_info(), MESH_MAX_ACTIVATION, mesh_query_done(), mesh_state_delete(), mesh_walk_supers(), module_qstate::minfo, module_stack::mod, mesh_area::mods, module_error, module_event_moddone, module_event_pass, module_finished, module_restart_next, module_wait_module, module_stack::num, mesh_state::num_activated, module_qstate::qinfo, module_qstate::return_rcode, mesh_state::s, and VERB_QUERY.

Referenced by mesh_run().

void mesh_run ( struct mesh_area mesh,
struct mesh_state mstate,
enum module_ev  ev,
struct outbound_entry e 
)

Run the mesh.

Run all runnable mesh states. Which can create new runnable mesh states. Until completion. Automatically called by mesh_report_reply and mesh_new_client as needed.

Parameters:
mesh,:mesh area.
mstate,:first mesh state to run.
ev,:event the mstate. Others get event_pass.
e,:if a reply, its outbound entry.

References rbtree_t::count, module_qstate::curmod, module_qstate::env, module_qstate::ext_state, fptr_ok, fptr_whitelist_mod_operate(), rbnode_t::key, mesh_continue(), mesh_log_list(), mesh_stats(), module_stack::mod, mesh_area::mods, module_event_pass, module_func_block::name, module_func_block::operate, rbtree_delete(), regional_free_all(), module_qstate::reply, rbtree_t::root, mesh_area::run, mesh_state::s, module_env::scratch, strextstate(), VERB_ALGO, verbose(), and verbosity.

Referenced by mesh_new_callback(), mesh_new_client(), mesh_new_prefetch(), and mesh_report_reply().

void mesh_log_list ( struct mesh_area mesh)
void mesh_stats ( struct mesh_area mesh,
const char *  str 
)
void mesh_stats_clear ( struct mesh_area mesh)
size_t mesh_get_mem ( struct mesh_area mesh)

Calculate memory size in use by mesh and all queries inside it.

Parameters:
mesh,:the mesh to examine.
Returns:
size in bytes.

References mesh_area::all, mesh_area::histogram, timehist::num, mesh_area::qbuf_bak, RBTREE_FOR, module_qstate::region, regional_get_mem(), and mesh_state::s.

Referenced by worker_mem_report().

int mesh_detect_cycle ( struct module_qstate qstate,
struct query_info qinfo,
uint16_t  flags,
int  prime 
)

Find cycle; see if the given mesh is in the targets sub, or sub-sub, ...

trees. If the sub-sub structure is too large, it returns 'a cycle'=2.

Parameters:
qstate,:given mesh querystate.
qinfo,:query info for dependency.
flags,:query flags of dependency.
prime,:if dependency is a priming query or not.
Returns:
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, this is return value 1. Too large to search is value 2 (also true).

References module_qstate::env, module_env::mesh, mesh_area_find(), and mesh_detect_cycle_found().

Referenced by fptr_whitelist_modenv_detect_cycle(), libworker_setup(), and worker_init().

void mesh_list_insert ( struct mesh_state m,
struct mesh_state **  fp,
struct mesh_state **  lp 
)

Insert mesh state into a double linked list.

Inserted at end.

Parameters:
m,:mesh state.
fp,:pointer to the first-elem-pointer of the list.
lp,:pointer to the last-elem-pointer of the list.

References mesh_state::next, and mesh_state::prev.

Referenced by mesh_new_client(), and mesh_new_prefetch().

void mesh_list_remove ( struct mesh_state m,
struct mesh_state **  fp,
struct mesh_state **  lp 
)

Remove mesh state from a double linked list.

Remove from any position.

Parameters:
m,:mesh state.
fp,:pointer to the first-elem-pointer of the list.
lp,:pointer to the last-elem-pointer of the list.

References mesh_state::next, and mesh_state::prev.

Referenced by mesh_state_delete().