]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
library resolution working.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 6 Dec 2007 15:11:07 +0000 (15:11 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 6 Dec 2007 15:11:07 +0000 (15:11 +0000)
git-svn-id: file:///svn/unbound/trunk@809 be551aaa-1e26-0410-a405-d3ace91eadb9

20 files changed:
Makefile.in
daemon/worker.c
doc/Changelog
iterator/iterator.c
libunbound/context.c
libunbound/context.h
libunbound/unbound.c
libunbound/unbound.h
libunbound/worker.c
libunbound/worker.h
services/mesh.c
services/mesh.h
services/outside_network.c
smallapp/unbound-host.c
smallapp/worker_cb.c
util/config_file.c
util/config_file.h
util/fptr_wlist.c
util/log.c
util/netevent.c

index 311446b75d98133a26f45b872d4164a7386688de..0d5a2abd4485ac9117a480937f1c284055001691 100644 (file)
@@ -87,7 +87,7 @@ SIGNIT_OBJ=$(addprefix $(BUILD),$(SIGNIT_SRC:.c=.o)) $(COMPAT_OBJ)
 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) \
index 6f6ee2ac6aa6917ddc057bd1f9d8b406c78ba132..e65290e9d04c47519876090f312287dd6660fe9e 100644 (file)
@@ -1074,3 +1074,45 @@ worker_alloc_cleanup(void* arg)
        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;
+}
index 098554ae91e7e53872bf2f133ef84c4fedb20c3c..0e6a986d890e75dd2aadb2a841811679a10aef87 100644 (file)
@@ -1,3 +1,7 @@
+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.
index a6a568c13cc6acf2fe94160d0a89ef01e409a4d0..0a5cb7a918edbaead2da8462ea791d51e0f03341 100644 (file)
@@ -1174,8 +1174,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                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);
        }
index 1f971f2b51ce1f83cce79372e697b0864272e72f..dc51b1f822e59320f8d5ac2569619b8c33d30182 100644 (file)
@@ -81,6 +81,7 @@ context_finalize(struct ub_val_ctx* ctx)
        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;
 }
 
@@ -149,3 +150,36 @@ context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass,
        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);
+}
index c5fc67ac5f7a36b3d13e720afb1dbd25a205705d..e42509c74a6f3bfd9d743fdfa5ad43b0ce31ae8a 100644 (file)
@@ -75,6 +75,13 @@ struct ub_val_ctx {
         */
        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 */
@@ -155,6 +162,10 @@ enum ub_ctx_err {
        UB_SYNTAX,
        /** DNS service failed */
        UB_SERVFAIL,
+       /** fork() failed */
+       UB_FORKFAIL,
+       /** cfg change after finalize() */
+       UB_AFTERFINAL,
        /** initialization failed (bad settings) */
        UB_INITFAIL
 };
@@ -182,4 +193,18 @@ int context_query_cmp(const void* a, const void* b);
 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 */
index e67daeb849f24093cb9a2e9ef19f769f72943d00..3bb3d55a4756854c4c04d418ccc2034a521e5f5b 100644 (file)
@@ -45,6 +45,7 @@
 #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"
@@ -89,7 +90,7 @@ ub_val_ctx_create()
                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;
@@ -124,9 +125,9 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx)
                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);
@@ -142,6 +143,7 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx)
                config_delete(ctx->env->cfg);
                free(ctx->env);
        }
+       alloc_clear(&ctx->superalloc);
        traverse_postorder(&ctx->queries, delq, NULL);
        free(ctx);
 }
@@ -150,7 +152,10 @@ int
 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;
@@ -165,7 +170,10 @@ ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta)
        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);
@@ -181,7 +189,10 @@ ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname)
        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);
@@ -195,7 +206,10 @@ int
 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;
@@ -233,10 +247,9 @@ int
 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);
@@ -265,10 +278,11 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
        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;
@@ -284,8 +298,23 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
        *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 
@@ -302,8 +331,17 @@ ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype,
                        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;
@@ -336,9 +374,11 @@ ub_val_result_free(struct ub_val_result* result)
        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);
@@ -353,7 +393,9 @@ ub_val_strerror(int err)
                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";
        }
 }
index 4a6d5b6c686b25c46b594cdc059928d3ce6cc0f5..8efab283ee586670a04aeb6024f96443dfae8d14 100644 (file)
@@ -281,6 +281,7 @@ int ub_val_ctx_process(struct ub_val_ctx* ctx);
 /**
  * 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).
@@ -305,6 +306,7 @@ int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
  * @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).
index a4d9564bf8eb49ea5ee253e41c62a28b78b589af..087d39d209463b699b1614d208d03d2da74b87b3 100644 (file)
 #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;
 }
 
@@ -96,38 +166,350 @@ libworker_dobg(void* arg)
 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;
+}
index 8a00bf44f79be565a894e5bce56692f69535fc47..dae67da43b253bd848e790586d4154c19c817116 100644 (file)
@@ -49,6 +49,10 @@ struct comm_base;
 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
@@ -72,8 +76,16 @@ struct libworker {
 
        /** 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;
 };
 
 /**
@@ -97,4 +109,48 @@ int libworker_bg(struct ub_val_ctx* ctx);
  */
 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 */
index 3f6f570a60e984524f7d9de16f2813783fa7992f..a8222056ecfd94d808a4f56337a5855e5d58d132 100644 (file)
@@ -155,9 +155,9 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
                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)) {
@@ -182,6 +182,52 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
                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)
 {
@@ -271,11 +317,12 @@ mesh_state_delete(struct module_qstate* qstate)
        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--;
        }
@@ -299,7 +346,8 @@ void mesh_detach_subs(struct module_qstate* qstate)
        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);
@@ -334,7 +382,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
                *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--;
@@ -413,6 +461,49 @@ timeval_divide(struct timeval* avg, struct timeval* sum, size_t d)
 #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.
@@ -477,11 +568,15 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
 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)
@@ -514,6 +609,26 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
        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)
 {
@@ -637,13 +752,15 @@ mesh_log_list(struct mesh_area* mesh)
        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);
        }
 }
index 7ba98732f3e30a495b0ef69fc238785a8c8924b4..46d4372b7f0d52c0d3ff0afdbeeef5485d1c9356 100644 (file)
@@ -53,6 +53,7 @@
 #include "services/modstack.h"
 struct mesh_state;
 struct mesh_reply;
+struct mesh_cb;
 struct query_info;
 struct reply_info;
 struct outbound_entry;
@@ -116,6 +117,8 @@ struct mesh_state {
        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;
@@ -155,6 +158,35 @@ struct mesh_reply {
        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 -------------------- */
 
 /**
@@ -188,6 +220,25 @@ 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 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
@@ -329,6 +380,22 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub);
 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
index da1dd5462f35b59d3c61348b68febec54bd068b9..9bee14885f740165018c2eaf8c5696005b8bf951 100644 (file)
@@ -288,6 +288,11 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
        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) {
index af4e93f68e1c9667f64744ffb37125e66a35da9a..0babe60d3e921755c9683e0185880bec1786dd1e 100644 (file)
@@ -44,6 +44,9 @@
 #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()
@@ -54,6 +57,7 @@ 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");
@@ -204,11 +208,55 @@ pretty_rcode(char* s, size_t len, int r)
        }
 }
 
+/** 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];
@@ -222,29 +270,41 @@ pretty_output(char* q, int t, int c, int sec, int haved,
                        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;
@@ -264,21 +324,22 @@ lookup(const char* nm, const char* qt, const char* qc)
        /* 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);
@@ -296,7 +357,7 @@ int main(int argc, char* argv[])
        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;
@@ -304,6 +365,9 @@ int main(int argc, char* argv[])
                case 't':
                        qtype = optarg;
                        break;
+               case 'v':
+                       verb++;
+                       break;
                case '?':
                case 'h':
                default:
index fb7dbd091becebfb1ee32818b5d3dbdb4707bb4a..6e6b74f756183a12674f78fdb9948914ac49b6dc 100644 (file)
@@ -114,3 +114,44 @@ acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
        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;
+}
index fd6cb61ac42a6d9e6a71b88a0142328b5ec8ba07..ca5e73d743016c796d1da9de96faa98b98b8e0e3 100644 (file)
@@ -45,6 +45,7 @@
 #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 */
@@ -139,6 +140,24 @@ error_exit:
        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)
@@ -375,3 +394,4 @@ config_apply(struct config_file* config)
 {
        MAX_TTL = (uint32_t)config->max_ttl;
 }
+
index 940450b0c1a3b4fb92ada55add3a4405a4ac5b91..4ed90b3785e09cc0e7fd8144fe13724cdd8ff7e6 100644 (file)
@@ -239,6 +239,12 @@ struct config_str2list {
  */
 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.
index abb7e29a94032150024928eb925231adf5e64996..21a292f1e1d5f76d12f3b6d28de99bef918e0d09 100644 (file)
@@ -67,6 +67,8 @@
 #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)
@@ -110,6 +112,7 @@ fptr_whitelist_pending_udp(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;
 }
 
@@ -118,6 +121,7 @@ fptr_whitelist_pending_tcp(comm_point_callback_t *fptr)
 {
        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;
 }
 
@@ -125,6 +129,7 @@ int
 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;
 }
 
@@ -147,6 +152,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
        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;
 }
 
@@ -212,6 +218,7 @@ fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt,
         struct module_qstate* q, int use_tcp))
 {
        if(fptr == &worker_send_packet) return 1;
+       else if(fptr == &libworker_send_packet) return 1;
        return 0;
 }
 
@@ -222,6 +229,7 @@ fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
         socklen_t addrlen, struct module_qstate* q))
 {
        if(fptr == &worker_send_query) return 1;
+       else if(fptr == &libworker_send_query) return 1;
        return 0;
 }
 
index a63080947d77f6f718f9209d15d40e491dc50110..a0304c2ef006b9b3193fcfe896ea2262f8c1746c 100644 (file)
@@ -195,6 +195,7 @@ fatal_exit(const char *format, ...)
        va_start(args, format);
        log_vmsg(LOG_CRIT, "fatal error", format, args);
        va_end(args);
+       abort();
        exit(1);
 }
 
index 7fdc8e00845589523fcacecb58753648c8b7c52c..3d61a27c00ab3a9201209956bc864db2ecbaf33e 100644 (file)
@@ -168,7 +168,7 @@ comm_point_send_udp_msg(struct comm_point *c, ldns_buffer* packet,
                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",