MEMSTATS_SRC=testcode/memstats.c smallapp/worker_cb.c $(COMMON_SRC)
MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ)
LIBUNBOUND_SRC=$(patsubst $(srcdir)/%,%, \
- $(wildcard $(srcdir)/libunbound/*.c) smallapp/worker_cb.c $(COMMON_SRC))
+ $(wildcard $(srcdir)/libunbound/*.c) $(COMMON_SRC))
LIBUNBOUND_OBJ=$(addprefix $(BUILD),$(LIBUNBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
$(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
slabhash_clear(&worker->env.rrset_cache->table);
slabhash_clear(worker->env.msg_cache);
}
+
+/* --- fake callbacks for fptr_wlist to work --- */
+int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
+ struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
+ struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp))
+{
+ log_assert(0);
+ return 0;
+}
+
+struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname),
+ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
+ uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
+ int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
+{
+ log_assert(0);
+ return 0;
+}
+
+int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
+{
+ log_assert(0);
+ return 0;
+}
+6 December 2007: Wouter
+ - library resolution works in foreground mode, unbound-host app
+ receives data.
+
5 December 2007: Wouter
- locking in context_new() inside the function.
- setup of libworker.
iq->chase_flags, EDNS_DO|BIT_CD,
&target->addr, target->addrlen, qstate);
if(!outq) {
- log_err("error sending query to auth server; skip this address");
- log_addr(0, "error for address:",
+ verbose(VERB_OPS, "error sending query to auth server; "
+ "skip this address");
+ log_addr(VERB_OPS, "error for address:",
&target->addr, target->addrlen);
return next_state(iq, QUERYTARGETS_STATE);
}
ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
if(!ctx->env->infra_cache)
return UB_NOMEM;
+ ctx->finalized = 1;
return UB_NOERROR;
}
lock_basic_unlock(&ctx->cfglock);
return q;
}
+
+struct alloc_cache*
+context_obtain_alloc(struct ub_val_ctx* ctx)
+{
+ struct alloc_cache* a;
+ int tnum = 0;
+ lock_basic_lock(&ctx->cfglock);
+ a = ctx->alloc_list;
+ if(a)
+ ctx->alloc_list = a->super; /* snip off list */
+ else tnum = ctx->thr_next_num++;
+ lock_basic_unlock(&ctx->cfglock);
+ if(a) {
+ a->super = &ctx->superalloc;
+ return a;
+ }
+ a = (struct alloc_cache*)calloc(1, sizeof(*a));
+ if(!a)
+ return NULL;
+ alloc_init(a, &ctx->superalloc, tnum);
+ return a;
+}
+
+void
+context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc)
+{
+ if(!ctx || !alloc)
+ return;
+ lock_basic_lock(&ctx->cfglock);
+ alloc->super = ctx->alloc_list;
+ ctx->alloc_list = alloc;
+ lock_basic_unlock(&ctx->cfglock);
+}
*/
int finalized;
+ /** is bg worker created yet ? */
+ int created_bg;
+ /** pid of bg worker process */
+ pid_t bg_pid;
+ /** tid of bg worker thread */
+ ub_thread_t bg_tid;
+
/** do threading (instead of forking) for async resolution */
int dothread;
/** next thread number for new threads */
UB_SYNTAX,
/** DNS service failed */
UB_SERVFAIL,
+ /** fork() failed */
+ UB_FORKFAIL,
+ /** cfg change after finalize() */
+ UB_AFTERFINAL,
/** initialization failed (bad settings) */
UB_INITFAIL
};
struct ctx_query* context_new(struct ub_val_ctx* ctx, char* name, int rrtype,
int rrclass, ub_val_callback_t cb, void* cbarg);
+/**
+ * Get a new alloc. Creates a new one or uses a cached one.
+ * @param ctx: context
+ * @return an alloc, or NULL on mem error.
+ */
+struct alloc_cache* context_obtain_alloc(struct ub_val_ctx* ctx);
+
+/**
+ * Release an alloc. Puts it into the cache.
+ * @param ctx: context
+ * @param alloc: alloc to relinquish.
+ */
+void context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc);
+
#endif /* LIBUNBOUND_CONTEXT_H */
#include "libunbound/unbound.h"
#include "config.h"
#include "libunbound/context.h"
+#include "libunbound/worker.h"
#include "util/locks.h"
#include "util/config_file.h"
#include "util/alloc.h"
errno = ENOMEM;
return NULL;
}
- ctx->env->cfg = config_create();
+ ctx->env->cfg = config_create_forlib();
if(!ctx->env->cfg) {
ub_val_ctx_delete(ctx);
errno = ENOMEM;
na = a->super;
a->super = &ctx->superalloc;
alloc_clear(a);
+ free(a);
a = na;
}
- alloc_clear(&ctx->superalloc);
local_zones_delete(ctx->local_zones);
lock_basic_destroy(&ctx->qqpipe_lock);
lock_basic_destroy(&ctx->rrpipe_lock);
config_delete(ctx->env->cfg);
free(ctx->env);
}
+ alloc_clear(&ctx->superalloc);
traverse_postorder(&ctx->queries, delq, NULL);
free(ctx);
}
ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname)
{
lock_basic_lock(&ctx->cfglock);
- ctx->finalized = 0;
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
if(!config_read(ctx->env->cfg, fname)) {
lock_basic_unlock(&ctx->cfglock);
return UB_SYNTAX;
char* dup = strdup(ta);
if(!dup) return UB_NOMEM;
lock_basic_lock(&ctx->cfglock);
- ctx->finalized = 0;
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
lock_basic_unlock(&ctx->cfglock);
free(dup);
char* dup = strdup(fname);
if(!dup) return UB_NOMEM;
lock_basic_lock(&ctx->cfglock);
- ctx->finalized = 0;
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
lock_basic_unlock(&ctx->cfglock);
free(dup);
ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread)
{
lock_basic_lock(&ctx->cfglock);
- ctx->finalized = 0;
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
ctx->dothread = dothread;
lock_basic_unlock(&ctx->cfglock);
return UB_NOERROR;
ub_val_ctx_wait(struct ub_val_ctx* ctx)
{
lock_basic_lock(&ctx->cfglock);
- /* TODO until no more queries outstanding */
while(ctx->num_async > 0) {
- lock_basic_unlock(&ctx->cfglock);
lock_basic_lock(&ctx->rrpipe_lock);
+ lock_basic_unlock(&ctx->cfglock);
(void)pollit(ctx, NULL);
lock_basic_unlock(&ctx->rrpipe_lock);
ub_val_ctx_process(ctx);
int rrclass, int* secure, int* data, struct ub_val_result** result)
{
struct ctx_query* q;
+ int r;
lock_basic_lock(&ctx->cfglock);
if(!ctx->finalized) {
- int r = context_finalize(ctx);
+ r = context_finalize(ctx);
if(r) {
lock_basic_unlock(&ctx->cfglock);
return r;
*data = 0;
*result = NULL;
- /* TODO */
- return UB_NOMEM;
+ r = libworker_fg(ctx, q);
+ if(r) {
+ ub_val_result_free(q->res);
+ free(q);
+ return r;
+ }
+
+ if(q->msg_security == sec_status_secure)
+ *secure = 1;
+ if(q->res->data && q->res->data[0])
+ *data = 1;
+ *result = q->res;
+
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ free(q->msg);
+ free(q);
+ return UB_NOERROR;
}
int
return r;
}
}
- /* create new ctx_query and attempt to add to the list */
+ if(!ctx->created_bg) {
+ int r = libworker_bg(ctx);
+ if(r) {
+ lock_basic_unlock(&ctx->cfglock);
+ return r;
+ }
+ ctx->created_bg = 1;
+ }
lock_basic_unlock(&ctx->cfglock);
+
+ /* create new ctx_query and attempt to add to the list */
q = context_new(ctx, name, rrtype, rrclass, callback, mydata);
if(!q)
return UB_NOMEM;
char** p;
if(!result) return;
free(result->qname);
- free(result->canonname);
- for(p = result->data; *p; p++)
- free(*p);
+ if(result->canonname != result->qname)
+ free(result->canonname);
+ if(result->data)
+ for(p = result->data; *p; p++)
+ free(*p);
free(result->data);
free(result->len);
free(result);
case UB_SOCKET: return "socket io error";
case UB_SYNTAX: return "syntax error";
case UB_SERVFAIL: return "server failure";
+ case UB_FORKFAIL: return "could not fork";
case UB_INITFAIL: return "initialization failure";
+ case UB_AFTERFINAL: return "setting change after finalize";
default: return "unknown error";
}
}
/**
* Perform resolution and validation of the target name.
* @param ctx: context.
+ * The context is finalized, and can no longer accept config changes.
* @param name: domain name in text format (a zero terminated text string).
* @param rrtype: type of RR in host order, 1 is A (address).
* @param rrclass: class of RR in host order, 1 is IN (for internet).
* @param ctx: context.
* If no thread or process has been created yet to perform the
* work in the background, it is created now.
+ * The context is finalized, and can no longer accept config changes.
* @param name: domain name in text format (a string).
* @param rrtype: type of RR in host order, 1 is A.
* @param rrclass: class of RR in host order, 1 is IN (for internet).
#include "libunbound/worker.h"
#include "libunbound/context.h"
#include "libunbound/unbound.h"
+#include "services/outside_network.h"
+#include "services/mesh.h"
+#include "services/cache/rrset.h"
+#include "services/outbound_list.h"
+#include "util/module.h"
+#include "util/regional.h"
+#include "util/random.h"
+#include "util/config_file.h"
+#include "util/netevent.h"
+#include "util/storage/slabhash.h"
+#include "util/net_help.h"
+#include "util/data/dname.h"
+
+/** size of table used for random numbers. large to be more secure. */
+#define RND_STATE_SIZE 256
/** delete libworker struct */
static void
libworker_delete(struct libworker* w)
{
if(!w) return;
- lock_basic_lock(&w->ctx->cfglock);
- /* return alloc */
- lock_basic_unlock(&w->ctx->cfglock);
-
+ if(w->env) {
+ mesh_delete(w->env->mesh);
+ context_release_alloc(w->ctx, w->env->alloc);
+ ldns_buffer_free(w->env->scratch_buffer);
+ regional_destroy(w->env->scratch);
+ ub_randfree(w->env->rnd);
+ free(w->env->rnd);
+ free(w->env);
+ }
+ outside_network_delete(w->back);
+ comm_base_delete(w->base);
+ free(w);
}
/** setup fresh libworker struct */
static struct libworker*
libworker_setup(struct ub_val_ctx* ctx)
{
+ unsigned int seed;
struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
+ struct config_file* cfg = ctx->env->cfg;
if(!w) return NULL;
w->ctx = ctx;
- lock_basic_lock(&ctx->cfglock);
- /* obtain a new alloc */
- lock_basic_unlock(&ctx->cfglock);
- /* setup event base */
- /* setup outnet */
- /* setup rnd */
- /* setup env */
- /* setup env.scratch */
- /* setup env.scratch_buffer */
- /* setup env.worker */
- /* setup env.mesh */
- /* setup env.alloc */
- /* setup env.rnd */
- /* setup env - callback ptrs */
+ w->env = (struct module_env*)malloc(sizeof(*w->env));
+ if(!w->env) {
+ free(w);
+ return NULL;
+ }
+ *w->env = *ctx->env;
+ w->env->alloc = context_obtain_alloc(ctx);
+ if(!w->env->alloc) {
+ libworker_delete(w);
+ return NULL;
+ }
+ alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
+ w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
+ w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size);
+ if(!w->env->scratch || !w->env->scratch_buffer) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->rnd = (struct ub_randstate*)calloc(1, sizeof(*w->env->rnd));
+ if(!w->env->rnd) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->worker = (struct worker*)w;
+ seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
+ (((unsigned int)w->thread_num)<<17);
+ seed ^= (unsigned int)w->env->alloc->next_id;
+ if(!ub_initstate(seed, w->env->rnd, RND_STATE_SIZE)) {
+ seed = 0;
+ libworker_delete(w);
+ return NULL;
+ }
+ seed = 0;
+
+ w->base = comm_base_create();
+ if(!w->base) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->back = outside_network_create(w->base, cfg->msg_buffer_size,
+ (size_t)cfg->outgoing_num_ports, cfg->out_ifs,
+ cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, -1,
+ cfg->do_tcp?cfg->outgoing_num_tcp:0,
+ w->env->infra_cache, w->env->rnd);
+ if(!w->back) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->mesh = mesh_create(&ctx->mods, w->env);
+ if(!w->env->mesh) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->send_packet = &libworker_send_packet;
+ w->env->send_query = &libworker_send_query;
+ w->env->detach_subs = &mesh_detach_subs;
+ w->env->attach_sub = &mesh_attach_sub;
+ w->env->kill_sub = &mesh_state_delete;
+ w->env->detect_cycle = &mesh_detect_cycle;
return w;
}
int libworker_bg(struct ub_val_ctx* ctx)
{
/* fork or threadcreate */
- lock_basic_lock(&ctx->cfglock);
if(ctx->dothread) {
- ub_thread_t t;
- lock_basic_unlock(&ctx->cfglock);
- ub_thread_create(&t, libworker_dobg, ctx);
- /* ctx.tid = t or so */
+ ub_thread_create(&ctx->bg_tid, libworker_dobg, ctx);
} else {
- pid_t p;
- lock_basic_unlock(&ctx->cfglock);
- switch((p=fork())) {
+ switch((ctx->bg_pid=fork())) {
case 0:
+ lock_basic_unlock(&ctx->cfglock);
(void)libworker_dobg(ctx);
exit(0);
break;
case -1:
- /* TODO make UB_FORKFAILED */
- return UB_SOCKET;
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_FORKFAIL;
default:
- /* ctx.pid = p or so */
break;
}
}
+ lock_basic_unlock(&ctx->cfglock);
return UB_NOERROR;
}
+/** get msg reply struct (in temp region) */
+static struct reply_info*
+parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi)
+{
+ struct reply_info* rep;
+ struct msg_parse* msg;
+ if(!(msg = regional_alloc(region, sizeof(*msg)))) {
+ return NULL;
+ }
+ memset(msg, 0, sizeof(*msg));
+ ldns_buffer_set_position(pkt, 0);
+ if(parse_packet(pkt, msg, region) != 0)
+ return 0;
+ if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
+ return 0;
+ }
+ return rep;
+}
+
+/** fill data into result */
+static int
+fill_res(struct ub_val_result* res, struct ub_packed_rrset_key* answer,
+ struct query_info* rq)
+{
+ size_t i;
+ struct packed_rrset_data* data;
+ if(!answer) {
+ res->data = calloc(1, sizeof(char*));
+ res->len = calloc(1, sizeof(size_t));
+ return (res->data && res->len);
+ }
+ data = (struct packed_rrset_data*)answer->entry.data;
+ if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
+ char buf[255+2];
+ dname_str(answer->rk.dname, buf);
+ res->canonname = strdup(buf);
+ if(!res->canonname)
+ return 0; /* out of memory */
+ } else
+ res->canonname = res->qname;
+ res->data = calloc(data->count+1, sizeof(char*));
+ res->len = calloc(data->count+1, sizeof(size_t));
+ if(!res->data || !res->len)
+ return 0; /* out of memory */
+ for(i=0; i<data->count; i++) {
+ /* remove rdlength from rdata */
+ res->len[i] = data->rr_len[i] - 2;
+ res->data[i] = memdup(data->rr_data[i]+2, res->len[i]);
+ if(!res->data[i])
+ return 0; /* out of memory */
+ }
+ res->data[data->count] = NULL;
+ res->len[data->count] = 0;
+ return 1;
+}
+
+/** callback with fg results */
+static void
+libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s)
+{
+ struct query_info rq; /* replied query */
+ struct reply_info* rep;
+ struct libworker_fg_data* d = (struct libworker_fg_data*)arg;
+ /* fg query is done; exit comm base */
+ comm_base_exit(d->w->base);
+
+ if(rcode != 0) {
+ d->q->res->rcode = rcode;
+ d->q->msg_security = 0;
+ return;
+ }
+
+ d->q->res->rcode = LDNS_RCODE_SERVFAIL;
+ d->q->msg_security = 0;
+ d->q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf));
+ d->q->msg_len = ldns_buffer_limit(buf);
+ if(!d->q->msg) {
+ return; /* error in rcode */
+ }
+
+ /* canonname and results */
+ rep = parse_reply(buf, d->w->env->scratch, &rq);
+ if(!rep) {
+ return; /* error parsing buf, or out of memory */
+ }
+ /* log_dns_msg("fg reply", &rq, rep); @@@ DEBUG */
+ if(!fill_res(d->q->res, reply_find_answer_rrset(&rq, rep), &rq))
+ return; /* out of memory */
+ /* rcode, nxdomain, bogus */
+ d->q->res->rcode = (int)LDNS_RCODE_WIRE(d->q->msg);
+ if(d->q->res->rcode == LDNS_RCODE_NXDOMAIN)
+ d->q->res->nxdomain = 1;
+ if(d->q->msg_security == sec_status_bogus)
+ d->q->res->bogus = 1;
+
+ d->q->msg_security = s;
+}
+
+/** setup qinfo and edns */
+static int
+setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
+ struct query_info* qinfo, struct edns_data* edns)
+{
+ ldns_rdf* rdf;
+ qinfo->qtype = (uint16_t)q->res->qtype;
+ qinfo->qclass = (uint16_t)q->res->qclass;
+ rdf = ldns_dname_new_frm_str(q->res->qname);
+ if(!rdf) {
+ return 0;
+ }
+ qinfo->qname = ldns_rdf_data(rdf);
+ qinfo->qname_len = ldns_rdf_size(rdf);
+ edns->edns_present = 1;
+ edns->ext_rcode = 0;
+ edns->edns_version = 0;
+ edns->bits = EDNS_DO;
+ if(ldns_buffer_capacity(w->back->udp_buff) < 65535)
+ edns->udp_size = (uint16_t)ldns_buffer_capacity(
+ w->back->udp_buff);
+ else edns->udp_size = 65535;
+ ldns_rdf_free(rdf);
+ return 1;
+}
+
int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q)
{
struct libworker* w = libworker_setup(ctx);
+ uint16_t qflags, qid;
+ struct query_info qinfo;
+ struct edns_data edns;
+ struct libworker_fg_data d;
if(!w)
+ return UB_INITFAIL;
+ if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
+ libworker_delete(w);
+ return UB_SYNTAX;
+ }
+ qid = 0;
+ qflags = BIT_RD;
+ d.q = q;
+ d.w = w;
+ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
+ w->back->udp_buff, qid, libworker_fg_done_cb, &d)) {
+ free(qinfo.qname);
return UB_NOMEM;
- /* TODO */
- q->res->bogus = 1;
+ }
+ free(qinfo.qname);
+ comm_base_dispatch(w->base);
libworker_delete(w);
return UB_NOERROR;
}
+
+void libworker_alloc_cleanup(void* arg)
+{
+ struct libworker* w = (struct libworker*)arg;
+ slabhash_clear(&w->env->rrset_cache->table);
+ slabhash_clear(w->env->msg_cache);
+}
+
+int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
+ socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp)
+{
+ struct libworker* w = (struct libworker*)q->env->worker;
+ if(use_tcp) {
+ return pending_tcp_query(w->back, pkt, addr, addrlen,
+ timeout, libworker_handle_reply, q,
+ q->env->rnd) != 0;
+ }
+ return pending_udp_query(w->back, pkt, addr, addrlen,
+ timeout*1000, libworker_handle_reply, q,
+ q->env->rnd) != 0;
+}
+
+/** compare outbound entry qstates */
+static int
+outbound_entry_compare(void* a, void* b)
+{
+ struct outbound_entry* e1 = (struct outbound_entry*)a;
+ struct outbound_entry* e2 = (struct outbound_entry*)b;
+ if(e1->qstate == e2->qstate)
+ return 1;
+ return 0;
+}
+
+struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ struct module_qstate* q)
+{
+ struct libworker* w = (struct libworker*)q->env->worker;
+ struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
+ q->region, sizeof(*e));
+ if(!e)
+ return NULL;
+ e->qstate = q;
+ e->qsent = outnet_serviced_query(w->back, qname,
+ qnamelen, qtype, qclass, flags, dnssec, addr, addrlen,
+ libworker_handle_service_reply, e, w->back->udp_buff,
+ &outbound_entry_compare);
+ if(!e->qsent) {
+ return NULL;
+ }
+ return e;
+}
+
+int
+libworker_handle_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info)
+{
+ struct module_qstate* q = (struct module_qstate*)arg;
+ struct libworker* lw = (struct libworker*)q->env->worker;
+ struct outbound_entry e;
+ e.qstate = q;
+ e.qsent = NULL;
+
+ if(error != 0) {
+ mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
+ return 0;
+ }
+ /* sanity check. */
+ if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
+ || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
+ LDNS_PACKET_QUERY
+ || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
+ /* error becomes timeout for the module as if this reply
+ * never arrived. */
+ mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
+ return 0;
+ }
+ mesh_report_reply(lw->env->mesh, &e, 1, reply_info);
+ return 0;
+}
+
+int
+libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info)
+{
+ struct outbound_entry* e = (struct outbound_entry*)arg;
+ struct libworker* lw = (struct libworker*)e->qstate->env->worker;
+
+ if(error != 0) {
+ mesh_report_reply(lw->env->mesh, e, 0, reply_info);
+ return 0;
+ }
+ /* sanity check. */
+ if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
+ || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
+ LDNS_PACKET_QUERY
+ || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
+ /* error becomes timeout for the module as if this reply
+ * never arrived. */
+ mesh_report_reply(lw->env->mesh, e, 0, reply_info);
+ return 0;
+ }
+ mesh_report_reply(lw->env->mesh, e, 1, reply_info);
+ return 0;
+}
+
+/* --- fake callbacks for fptr_wlist to work --- */
+int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(repinfo))
+{
+ log_assert(0);
+ return 0;
+}
+
+int worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+int worker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
+ struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
+ struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp))
+{
+ log_assert(0);
+ return 0;
+}
+
+struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
+ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
+ uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
+ int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
+{
+ log_assert(0);
+ return 0;
+}
+
+void
+worker_alloc_cleanup(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+int
+acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
+{
+ log_assert(0);
+ return 0;
+}
struct outside_network;
struct ub_randstate;
struct ctx_query;
+struct outbound_entry;
+struct module_qstate;
+struct comm_point;
+struct comm_reply;
/**
* The library-worker status structure
/** random() table for this worker. */
struct ub_randstate* rndstate;
- /** do we need to exit (when done) */
- int need_to_exit;
+};
+
+/**
+ * Foreground query cb struct
+ */
+struct libworker_fg_data {
+ /** the worker involved */
+ struct libworker* w;
+ /** the query involved */
+ struct ctx_query* q;
};
/**
*/
int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q);
+/** cleanup the cache to remove all rrset IDs from it, arg is libworker */
+void libworker_alloc_cleanup(void* arg);
+
+/**
+ * Worker service routine to send udp messages for modules.
+ * @param pkt: packet to send.
+ * @param addr: where to.
+ * @param addrlen: length of addr.
+ * @param timeout: seconds to wait until timeout.
+ * @param q: wich query state to reactivate upon return.
+ * @param use_tcp: true to use TCP, false for UDP.
+ * @return: false on failure (memory or socket related). no query was
+ * sent.
+ */
+int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
+ socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp);
+
+/**
+ * Worker service routine to send serviced queries to authoritative servers.
+ * @param qname: query name. (host order)
+ * @param qnamelen: length in bytes of qname, including trailing 0.
+ * @param qtype: query type. (host order)
+ * @param qclass: query class. (host order)
+ * @param flags: host order flags word, with opcode and CD bit.
+ * @param dnssec: if set, EDNS record will have DO bit set.
+ * @param addr: where to.
+ * @param addrlen: length of addr.
+ * @param q: wich query state to reactivate upon return.
+ * @return: false on failure (memory or socket related). no query was
+ * sent.
+ */
+struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ struct module_qstate* q);
+
+/** process incoming replies from the network */
+int libworker_handle_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info);
+
+/** process incoming serviced query replies from the network */
+int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info);
+
#endif /* LIBUNBOUND_WORKER_H */
mesh->num_detached_states++;
added = 1;
}
- if(!s->reply_list && s->super_set.count == 0)
+ if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
was_detached = 1;
- if(!s->reply_list)
+ if(!s->reply_list && !s->cb_list)
was_noreply = 1;
/* add reply to s */
if(!mesh_state_add_reply(s, edns, rep, qid, qflags)) {
mesh_run(mesh, s, module_event_new, NULL);
}
+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)
+{
+ struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags, 0);
+ int was_detached = 0;
+ int was_noreply = 0;
+ int added = 0;
+ /* see if it already exists, if not, create one */
+ if(!s) {
+ struct rbnode_t* n;
+ s = mesh_state_create(mesh->env,qinfo, qflags, 0);
+ if(!s) {
+ return 0;
+ }
+ n = rbtree_insert(&mesh->all, &s->node);
+ log_assert(n != NULL);
+ /* set detached (it is now) */
+ mesh->num_detached_states++;
+ added = 1;
+ }
+ if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
+ was_detached = 1;
+ if(!s->reply_list && !s->cb_list)
+ was_noreply = 1;
+ /* add reply to s */
+ if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) {
+ if(added)
+ mesh_state_delete(&s->s);
+ return 0;
+ }
+ /* update statistics */
+ if(was_detached) {
+ log_assert(mesh->num_detached_states > 0);
+ mesh->num_detached_states--;
+ }
+ if(was_noreply) {
+ mesh->num_reply_states ++;
+ }
+ mesh->num_reply_addrs++;
+ if(added)
+ mesh_run(mesh, s, module_event_new, NULL);
+ return 1;
+}
+
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
int is_ok, struct comm_reply* reply)
{
mstate = qstate->mesh_info;
mesh = mstate->s.env->mesh;
mesh_detach_subs(&mstate->s);
- if(!mstate->reply_list && mstate->super_set.count == 0) {
+ if(!mstate->reply_list && !mstate->cb_list
+ && mstate->super_set.count == 0) {
log_assert(mesh->num_detached_states > 0);
mesh->num_detached_states--;
}
- if(mstate->reply_list) {
+ if(mstate->reply_list || mstate->cb_list) {
log_assert(mesh->num_reply_states > 0);
mesh->num_reply_states--;
}
RBTREE_FOR(ref, struct mesh_state_ref*, &qstate->mesh_info->sub_set) {
n = rbtree_delete(&ref->s->super_set, &lookup);
log_assert(n != NULL); /* must have been present */
- if(!ref->s->reply_list && ref->s->super_set.count == 0) {
+ if(!ref->s->reply_list && !ref->s->cb_list
+ && ref->s->super_set.count == 0) {
mesh->num_detached_states++;
log_assert(mesh->num_detached_states +
mesh->num_reply_states <= mesh->all.count);
*newq = NULL;
if(!mesh_state_attachment(qstate->mesh_info, sub))
return 0;
- if(!sub->reply_list && sub->super_set.count == 1) {
+ if(!sub->reply_list && !sub->cb_list && sub->super_set.count == 1) {
/* it used to be detached, before this one got added */
log_assert(mesh->num_detached_states > 0);
mesh->num_detached_states--;
#endif
}
+/**
+ * callback results to mesh cb entry
+ * @param m: mesh state to send it for.
+ * @param rcode: if not 0, error code.
+ * @param rep: reply to send (or NULL if rcode is set).
+ * @param r: callback entry
+ */
+static void
+mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
+ struct mesh_cb* r)
+{
+ int secure;
+ /* bogus messages are not made into servfail, sec_status passed
+ * to the callback function */
+ if(rep && rep->security == sec_status_secure)
+ secure = 1;
+ else secure = 0;
+ if(!rep && rcode == LDNS_RCODE_NOERROR)
+ rcode = LDNS_RCODE_SERVFAIL;
+ /* send the reply */
+ if(rcode) {
+ (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked);
+ } else {
+ size_t udp_size = r->edns.udp_size;
+ ldns_buffer_clear(r->buf);
+ r->edns.edns_version = EDNS_ADVERTISED_VERSION;
+ r->edns.udp_size = EDNS_ADVERTISED_SIZE;
+ r->edns.ext_rcode = 0;
+ r->edns.bits &= EDNS_DO;
+ if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
+ r->qflags, r->buf, 0, 1,
+ m->s.env->scratch, udp_size, &r->edns,
+ (int)(r->edns.bits & EDNS_DO), secure))
+ {
+ (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf,
+ sec_status_unchecked);
+ }
+ else (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf,
+ rep->security);
+ }
+ m->s.env->mesh->num_reply_addrs--;
+}
+
/**
* Send reply to mesh reply entry
* @param m: mesh state to send it for.
void mesh_query_done(struct mesh_state* mstate)
{
struct mesh_reply* r;
+ struct mesh_cb* c;
struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL);
for(r = mstate->reply_list; r; r = r->next) {
mesh_send_reply(mstate, mstate->s.return_rcode, rep, r);
}
+ for(c = mstate->cb_list; c; c = c->next) {
+ mesh_do_callback(mstate, mstate->s.return_rcode, rep, c);
+ }
}
void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate)
return result;
}
+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)
+{
+ struct mesh_cb* r = regional_alloc(s->s.region,
+ sizeof(struct mesh_cb));
+ if(!r)
+ return 0;
+ r->buf = buf;
+ r->cb = cb;
+ r->cb_arg = cb_arg;
+ r->edns = *edns;
+ r->qid = qid;
+ r->qflags = qflags;
+ r->next = s->cb_list;
+ s->cb_list = r;
+ return 1;
+
+}
+
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
struct comm_reply* rep, uint16_t qid, uint16_t qflags)
{
struct mesh_state* m;
int num = 0;
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
- snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s",
+ snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s%s",
num++, (m->s.is_priming)?"p":"", /* prime */
(m->s.query_flags&BIT_RD)?"RD":"",
(m->s.query_flags&BIT_CD)?"CD":"",
(m->super_set.count==0)?"d":"", /* detached */
(m->sub_set.count!=0)?"c":"", /* children */
- m->s.curmod, (m->reply_list)?"hr":"nr"); /*hasreply*/
+ m->s.curmod, (m->reply_list)?"rep":"", /*hasreply*/
+ (m->cb_list)?"cb":"" /* callbacks */
+ );
log_query_info(VERB_ALGO, buf, &m->s.qinfo);
}
}
#include "services/modstack.h"
struct mesh_state;
struct mesh_reply;
+struct mesh_cb;
struct query_info;
struct reply_info;
struct outbound_entry;
struct module_qstate s;
/** the list of replies to clients for the results */
struct mesh_reply* reply_list;
+ /** the list of callbacks for the results */
+ struct mesh_cb* cb_list;
/** set of superstates (that want this state's result)
* contains struct mesh_state_ref* */
rbtree_t super_set;
uint16_t qflags;
};
+/**
+ * Mesh result callback func.
+ * called as func(cb_arg, rcode, buffer_with_reply, security);
+ * */
+typedef void (*mesh_cb_func_t)(void*, int, ldns_buffer*, enum sec_status);
+
+/**
+ * Callback to result routine
+ */
+struct mesh_cb {
+ /** next in list */
+ struct mesh_cb* next;
+ /** edns data from query */
+ struct edns_data edns;
+ /** id of query, in network byteorder. */
+ uint16_t qid;
+ /** flags of query, for reply flags */
+ uint16_t qflags;
+ /** buffer for reply */
+ ldns_buffer* buf;
+
+ /** callback routine for results. if rcode != 0 buf has message.
+ * called as cb(cb_arg, rcode, buf);
+ */
+ mesh_cb_func_t cb;
+ /** user arg for callback */
+ void* cb_arg;
+};
+
/* ------------------- Functions for worker -------------------- */
/**
uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
uint16_t qid);
+/**
+ * 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.
+ *
+ * @param mesh: the mesh.
+ * @param qinfo: query from client.
+ * @param qflags: flags from client query.
+ * @param edns: edns data from client query.
+ * @param buf: buffer for reply contents.
+ * @param qid: query id to reply with.
+ * @param cb: callback function.
+ * @param cb_arg: callback user arg.
+ * @return 0 on error.
+ */
+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);
+
/**
* Handle new event from the wire. A serviced query has returned.
* The query state will be made runnable, and the mesh_area will process
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
struct comm_reply* rep, 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.
+ * @param s: the mesh state.
+ * @param edns: edns data for reply (bufsize).
+ * @param buf: buffer for reply
+ * @param cb: callback to call with results.
+ * @param cb_arg: callback user arg.
+ * @param qid: ID of reply.
+ * @param qflags: original query flags.
+ * @return: 0 on alloc error.
+ */
+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);
+
/**
* Run the mesh. Run all runnable mesh states. Which can create new
* runnable mesh states. Until completion. Automatically called by
char portstr[32];
if(porthint != -1)
snprintf(portstr, sizeof(portstr), "%d", porthint);
+ else if(!ifname) {
+ if(hints->ai_family == AF_INET)
+ ifname = "0.0.0.0";
+ else ifname="::";
+ }
if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints,
&res)) != 0 || !res) {
#include "libunbound/unbound.h"
#include <ldns/ldns.h>
+/** verbosity for unbound-host app */
+static int verb = 0;
+
/** Give unbound-host usage, and exit (1). */
static void
usage()
printf(" If an ip-address is given a reverse lookup is done.\n");
printf("-t type what type to look for.\n");
printf("-c class what class to look for, if not class IN.\n");
+ printf("-v be more verbose.\n");
printf("-h show this usage help.\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
}
}
+/** convert and print rdata */
+static void
+print_rd(int t, char* data, size_t len)
+{
+ /*
+ size_t i, pos = 0;
+ ldns_status status;
+ ldns_rr* rr = ldns_rr_new_frm_type(t);
+ ldns_rr_set_owner(rr, NULL);
+ status = ldns_wire2rdf(rr, (uint8_t*)data, len, &pos);
+ if(status != LDNS_STATUS_OK) {
+
+ printf("error_printing_data");
+ }
+ printf("len = %d\n", len);
+ for(i=0; i<ldns_rr_rd_count(rr); i++) {
+ ldns_rdf_print(stdout, ldns_rr_rdf(rr, i));
+ }
+ ldns_rr_free(rr);
+ */
+ printf("TODO");
+}
+
+/** pretty line of RR data for results */
+static void
+pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec,
+ char* data, size_t len)
+{
+ printf("%s", q);
+ if(strcmp(cstr, "IN") != 0)
+ printf(" in class %s", cstr);
+ if(t == LDNS_RR_TYPE_A)
+ printf(" has address ");
+ else if(t == LDNS_RR_TYPE_AAAA)
+ printf(" has IPv6 address ");
+ else if(t == LDNS_RR_TYPE_MX)
+ printf(" mail is handled by ");
+ else printf(" has %s record ", tstr);
+ print_rd(t, data, len);
+ printf(" %s", sec);
+ printf("\n");
+}
+
/** pretty line of output for results */
static void
pretty_output(char* q, int t, int c, int sec, int haved,
- struct ub_val_result* result)
+ struct ub_val_result* result, int docname)
{
+ int i;
const char *secstatus = statstr(sec, result);
char tstr[16];
char cstr[16];
q, result->rcode, rcodestr, secstatus);
return;
}
+ if(docname && result->canonname &&
+ result->canonname != result->qname)
+ printf("%s is an alias for %s\n", result->qname,
+ result->canonname);
if(!haved) {
- printf("%s %s %s: no data. %s\n",
- q, cstr, tstr, secstatus);
+ if(verb > 0)
+ printf("%s %s %s: no data. %s\n",
+ q, cstr, tstr, secstatus);
+ /* else: emptiness to indicate no data */
return;
}
- printf("%s %s %s: have data. %s\n",
- q, cstr, tstr, secstatus);
- /* TODO print the data nicely */
+ i=0;
+ while(result->data[i])
+ {
+ pretty_rdata(
+ result->canonname?result->canonname:q,
+ cstr, tstr, t, secstatus, result->data[i],
+ result->len[i]);
+ i++;
+ }
}
/** perform a lookup and printout return if domain existed */
static int
-dnslook(struct ub_val_ctx* ctx, char* q, int t, int c)
+dnslook(struct ub_val_ctx* ctx, char* q, int t, int c, int docname)
{
int ret, sec, haved;
struct ub_val_result* result;
ret = ub_val_resolve(ctx, q, t, c, &sec, &haved, &result);
if(ret != 0) {
- fprintf(stderr, "error: %s\n", ub_val_strerror(ret));
+ fprintf(stderr, "resolve error: %s\n", ub_val_strerror(ret));
exit(1);
}
- pretty_output(q, t, c, sec, haved, result);
+ pretty_output(q, t, c, sec, haved, result, docname);
ret = result->nxdomain;
ub_val_result_free(result);
return ret;
/* perform the query */
struct ub_val_ctx* ctx = NULL;
- printf("lookup %s %d %d reverse=%d multi=%d\n",
- realq, t, c, reverse, multi);
+ if(verb>0)
+ printf("lookup %s %d %d reverse=%d multi=%d\n",
+ realq, t, c, reverse, multi);
ctx = ub_val_ctx_create();
if(!ctx) {
fprintf(stderr, "error: out of memory\n");
exit(1);
}
if(multi) {
- if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c)) {
+ if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) {
/* domain exists, lookup more */
- (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c);
- (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c);
+ (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0);
+ (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0);
}
} else {
- (void)dnslook(ctx, realq, t, c);
+ (void)dnslook(ctx, realq, t, c, 1);
}
ub_val_ctx_delete(ctx);
free(realq);
char* qclass = NULL;
char* qtype = NULL;
/* parse the options */
- while( (c=getopt(argc, argv, "c:ht:")) != -1) {
+ while( (c=getopt(argc, argv, "c:ht:v")) != -1) {
switch(c) {
case 'c':
qclass = optarg;
case 't':
qtype = optarg;
break;
+ case 'v':
+ verb++;
+ break;
case '?':
case 'h':
default:
log_assert(0);
return 0;
}
+
+int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
+ struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
+ struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp))
+{
+ log_assert(0);
+ return 0;
+}
+
+struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname),
+ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
+ uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
+ int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
+{
+ log_assert(0);
+ return 0;
+}
+
+int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
+{
+ log_assert(0);
+ return 0;
+}
#include "util/configyyrename.h"
#include "util/config_file.h"
#include "util/configparser.h"
+#include "util/net_help.h"
/** global config during parsing */
struct config_parser_state* cfg_parser = 0;
/** lex in file */
return NULL;
}
+struct config_file* config_create_forlib()
+{
+ struct config_file* cfg = config_create();
+ if(!cfg) return NULL;
+ /* modifications for library use, less verbose, less memory */
+ cfg->verbosity = 0;
+ cfg->outgoing_num_tcp = 2;
+ cfg->msg_cache_size = 1024*1024;
+ cfg->msg_cache_slabs = 1;
+ cfg->rrset_cache_size = 1024*1024;
+ cfg->rrset_cache_slabs = 1;
+ cfg->infra_cache_slabs = 1;
+ cfg->use_syslog = 0;
+ cfg->key_cache_size = 1024*1024;
+ cfg->key_cache_slabs = 1;
+ return cfg;
+}
+
/** initialize the global cfg_parser object */
static void
create_cfg_parser(struct config_file* cfg, char* filename)
{
MAX_TTL = (uint32_t)config->max_ttl;
}
+
*/
struct config_file* config_create();
+/**
+ * Create config file structure for library use. Filled with default values.
+ * @return: the new structure or NULL on memory error.
+ */
+struct config_file* config_create_forlib();
+
/**
* Read the config file from the specified filename.
* @param config: where options are stored into, must be freshly created.
#include "util/locks.h"
#include "testcode/checklocks.h"
#include "daemon/acl_list.h"
+#include "libunbound/worker.h"
+#include "libunbound/context.h"
int
fptr_whitelist_comm_point(comm_point_callback_t *fptr)
{
if(fptr == &serviced_udp_callback) return 1;
else if(fptr == &worker_handle_reply) return 1;
+ else if(fptr == &libworker_handle_reply) return 1;
return 0;
}
{
if(fptr == &serviced_tcp_callback) return 1;
else if(fptr == &worker_handle_reply) return 1;
+ else if(fptr == &libworker_handle_reply) return 1;
return 0;
}
fptr_whitelist_serviced_query(comm_point_callback_t *fptr)
{
if(fptr == &worker_handle_service_reply) return 1;
+ else if(fptr == &libworker_handle_service_reply) return 1;
return 0;
}
else if(fptr == &mini_ev_cmp) return 1;
else if(fptr == &anchor_cmp) return 1;
else if(fptr == &canonical_tree_compare) return 1;
+ else if(fptr == &context_query_cmp) return 1;
return 0;
}
struct module_qstate* q, int use_tcp))
{
if(fptr == &worker_send_packet) return 1;
+ else if(fptr == &libworker_send_packet) return 1;
return 0;
}
socklen_t addrlen, struct module_qstate* q))
{
if(fptr == &worker_send_query) return 1;
+ else if(fptr == &libworker_send_query) return 1;
return 0;
}
va_start(args, format);
log_vmsg(LOG_CRIT, "fatal error", format, args);
va_end(args);
+ abort();
exit(1);
}
ldns_buffer_remaining(packet), 0,
addr, addrlen);
if(sent == -1) {
- log_err("sendto failed: %s", strerror(errno));
+ verbose(VERB_OPS, "sendto failed: %s", strerror(errno));
return 0;
} else if((size_t)sent != ldns_buffer_remaining(packet)) {
log_err("sent %d in place of %d bytes",