From: Wouter Wijngaards Date: Tue, 4 Dec 2007 16:14:09 +0000 (+0000) Subject: libunbound work. X-Git-Tag: release-0.9~134 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43a2640a9c10fe706e8d3ccc301e2e36a6b877fc;p=thirdparty%2Funbound.git libunbound work. git-svn-id: file:///svn/unbound/trunk@802 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index dc4f349d7..d26a94dce 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,8 @@ - minor Makefile fixup. - moved module-stack code out of daemon/daemon into services/modstack, preparing for code-reuse. + - move context into own header file. + - context query structure. 3 December 2007: Wouter - changed checkconf/ to smallapp/ to make room for more support tools. diff --git a/libunbound/context.c b/libunbound/context.c new file mode 100644 index 000000000..90a38495f --- /dev/null +++ b/libunbound/context.c @@ -0,0 +1,146 @@ +/* + * libunbound/context.c - validating context for unbound internal use + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains the validator context structure. + */ +#include "config.h" +#include "libunbound/context.h" +#include "util/module.h" +#include "util/config_file.h" +#include "services/modstack.h" +#include "services/localzone.h" +#include "services/cache/rrset.h" +#include "services/cache/infra.h" +#include "util/data/msgreply.h" +#include "util/storage/slabhash.h" + +int +context_finalize(struct ub_val_ctx* ctx) +{ + struct config_file* cfg = ctx->env->cfg; + verbosity = cfg->verbosity; + log_init(cfg->logfile, cfg->use_syslog, NULL); + config_apply(cfg); + if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) + return UB_INITFAIL; + ctx->local_zones = local_zones_create(); + if(!ctx->local_zones) + return UB_NOMEM; + if(!local_zones_apply_cfg(ctx->local_zones, cfg)) + return UB_INITFAIL; + if(!ctx->env->msg_cache || + cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) || + cfg->msg_cache_slabs != ctx->env->msg_cache->size) { + slabhash_delete(ctx->env->msg_cache); + ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, + HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, + msgreply_sizefunc, query_info_compare, + query_entry_delete, reply_info_delete, NULL); + if(!ctx->env->msg_cache) + return UB_NOMEM; + } + ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache, + ctx->env->cfg, ctx->env->alloc); + if(!ctx->env->rrset_cache) + return UB_NOMEM; + ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); + if(!ctx->env->infra_cache) + return UB_NOMEM; + return UB_NOERROR; +} + +int context_query_cmp(const void* a, const void* b) +{ + if( *(int*)a < *(int*)b ) + return -1; + if( *(int*)a > *(int*)b ) + return 1; + return 0; +} + +/** How many times to try to find an unused query-id-number for async */ +#define NUM_ID_TRIES 100000 +/** find next useful id number of 0 on error */ +static int +find_id(struct ub_val_ctx* ctx, int* id) +{ + size_t tries = 0; + while(rbtree_search(&ctx->queries, &ctx->next_querynum)) { + ctx->next_querynum++; /* numerical wraparound is fine */ + if(tries++ > NUM_ID_TRIES) + return 0; + } + *id = ctx->next_querynum; + ctx->next_querynum++; + return 1; +} + +struct ctx_query* +context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, + ub_val_callback_t cb, void* cbarg) +{ + struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); + if(!q) return NULL; + if(!find_id(ctx, &q->querynum)) { + free(q); + return NULL; + } + q->node.key = &q->querynum; + q->async = (cb != NULL); + q->cb = cb; + q->cb_arg = cbarg; + q->res = (struct ub_val_result*)calloc(1, sizeof(*q->res)); + if(!q->res) { + free(q); + return NULL; + } + q->res->qname = strdup(name); + if(!q->res->qname) { + free(q->res); + free(q); + return NULL; + } + q->res->qtype = rrtype; + q->res->qclass = rrclass; + + /* add to query list */ + if(q->async) + ctx->num_async ++; + (void)rbtree_insert(&ctx->queries, &q->node); + return q; +} diff --git a/libunbound/context.h b/libunbound/context.h new file mode 100644 index 000000000..1a6dfcf44 --- /dev/null +++ b/libunbound/context.h @@ -0,0 +1,177 @@ +/* + * libunbound/context.h - validating context for unbound internal use + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains the validator context structure. + */ +#ifndef LIBUNBOUND_CONTEXT_H +#define LIBUNBOUND_CONTEXT_H +#include "util/locks.h" +#include "util/alloc.h" +#include "util/rbtree.h" +#include "services/modstack.h" +#include "libunbound/unbound.h" + +/** + * The context structure + * + * Contains two pipes for async service + * qq : write queries to the async service pid/tid. + * rr : read results from the async service pid/tid. + */ +struct ub_val_ctx { + /* --- pipes --- */ + /** mutex on query write pipe */ + lock_basic_t qqpipe_lock; + /** the query write pipe, [0] read from, [1] write on */ + int qqpipe[2]; + /** mutex on result read pipe */ + lock_basic_t rrpipe_lock; + /** the result read pipe, [0] read from, [1] write on */ + int rrpipe[2]; + + /* --- shared data --- */ + /** mutex for access to env.cfg, finalized and dothread */ + lock_basic_t cfglock; + /** + * The context has been finalized + * This is after config when the first resolve is done. + * The modules are inited (module-init()) and shared caches created. + */ + int finalized; + + /** do threading (instead of forking) for async resolution */ + int dothread; + /** next thread number for new threads */ + int thr_next_num; + /** + * List of alloc-cache-id points per threadnum for notinuse threads. + * Simply the entire struct alloc_cache with the 'super' member used + * to link a simply linked list. Reset super member to the superalloc + * before use. + */ + struct alloc_cache* alloc_list; + + /** shared caches, and so on */ + struct alloc_cache superalloc; + /** module env master value */ + struct module_env* env; + /** module stack */ + struct module_stack mods; + /** local authority zones */ + struct local_zones* local_zones; + + /** next query number (to try) to use */ + int next_querynum; + /** number of async queries outstanding */ + size_t num_async; + /** + * Tree of outstanding queries. Indexed by querynum + * Used when results come in for async to lookup. + * Used when cancel is done for lookup (and delete). + * Used to see if querynum is free for use. + * Content of type ctx_query. + */ + rbtree_t queries; +}; + +/** + * The queries outstanding for the libunbound resolver. + * These are outstanding for async resolution. + * But also, outstanding for sync resolution by one of the threads that + * has joined the threadpool. + */ +struct ctx_query { + /** node in rbtree, must be first entry, key is ptr to the querynum */ + struct rbnode_t node; + /** query id number, key for node */ + int querynum; + /** was this an async query? */ + int async; + + /** for async query, the callback function */ + ub_val_callback_t cb; + /** for async query, the callback user arg */ + void* cb_arg; + + /** result structure, also contains original query, type, class. + * malloced ptr ready to hand to the client. */ + struct ub_val_result* res; +}; + +/** + * The error constants + */ +enum ub_ctx_err { + /** no error */ + UB_NOERROR = 0, + /** alloc failure */ + UB_NOMEM, + /** socket operation */ + UB_SOCKET, + /** syntax error */ + UB_SYNTAX, + /** DNS service failed */ + UB_SERVFAIL, + /** initialization failed (bad settings) */ + UB_INITFAIL +}; + +/** + * finalize a context. + * @param ctx: context to finalize. creates shared data. + * @return 0 if OK, or errcode. + */ +int context_finalize(struct ub_val_ctx* ctx); + +/** compare two ctx_query elements */ +int context_query_cmp(const void* a, const void* b); + +/** + * Create new query in context, add to querynum list. + * @param ctx: context + * @param name: query name + * @param rrtype: type + * @param rrclass: class + * @param cb: callback for async, or NULL for sync. + * @param cbarg: user arg for async queries. + * @return new ctx_query or NULL for malloc failure. + */ +struct ctx_query* context_new(struct ub_val_ctx* ctx, char* name, int rrtype, + int rrclass, ub_val_callback_t cb, void* cbarg); + +#endif /* LIBUNBOUND_CONTEXT_H */ diff --git a/libunbound/unbound.c b/libunbound/unbound.c index bf9d236b0..198d42c54 100644 --- a/libunbound/unbound.c +++ b/libunbound/unbound.c @@ -44,67 +44,16 @@ /* include the public api first, it should be able to stand alone */ #include "libunbound/unbound.h" #include "config.h" +#include "libunbound/context.h" #include "util/locks.h" #include "util/config_file.h" #include "util/alloc.h" - -/** - * The context structure - * - * Contains two pipes for async service - * qq : write queries to the async service pid/tid. - * rr : read results from the async service pid/tid. - */ -struct ub_val_ctx { - /** mutex on query write pipe */ - lock_basic_t qqpipe_lock; - /** the query write pipe, [0] read from, [1] write on */ - int qqpipe[2]; - /** mutex on result read pipe */ - lock_basic_t rrpipe_lock; - /** the result read pipe, [0] read from, [1] write on */ - int rrpipe[2]; - - /** configuration options */ - struct config_file* cfg; - /** do threading (instead of forking) for async resolution */ - int dothread; - - /** shared data */ - /* list of alloc-cache-id points and nextthreadnum */ - /*struct shareddata* shared;*/ - /** outstanding querylist and next querynum (to try) */ - - /** shared caches, and so on */ - struct alloc_cache superalloc; - /** module env master value */ - struct module_env* env; - /** number of modules active, ids from 0 to num-1. */ - int num_modules; - /** the module callbacks, array of num_modules length */ - struct module_func_block** modfunc; - /** local authority zones */ - struct local_zones* local_zones; - - /** TODO list of outstanding queries */ -}; - -/** - * The error constants - */ -enum ub_ctx_err { - /** no error */ - UB_NOERROR = 0, - /** alloc failure */ - UB_NOMEM, - /** socket operation */ - UB_SOCKET, - /** syntax error */ - UB_SYNTAX, - /** DNS service failed */ - UB_SERVFAIL -}; - +#include "util/module.h" +#include "util/log.h" +#include "services/modstack.h" +#include "services/localzone.h" +#include "services/cache/infra.h" +#include "services/cache/rrset.h" struct ub_val_ctx* ub_val_ctx_create() @@ -115,6 +64,10 @@ ub_val_ctx_create() return NULL; } checklock_start(); + log_ident_set("libunbound"); + verbosity = 0; /* errors only */ + log_init(NULL, 0, NULL); /* logs to stderr */ + alloc_init(&ctx->superalloc, NULL, 0); if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->qqpipe) == -1) { free(ctx); return NULL; @@ -129,35 +82,80 @@ ub_val_ctx_create() } lock_basic_init(&ctx->qqpipe_lock); lock_basic_init(&ctx->rrpipe_lock); - ctx->cfg = config_create(); - if(!ctx->cfg) { + lock_basic_init(&ctx->cfglock); + ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env)); + if(!ctx->env) { + ub_val_ctx_delete(ctx); + errno = ENOMEM; + return NULL; + } + ctx->env->cfg = config_create(); + if(!ctx->env->cfg) { ub_val_ctx_delete(ctx); errno = ENOMEM; return NULL; } + ctx->env->alloc = &ctx->superalloc; + ctx->env->worker = NULL; + ctx->env->need_to_validate = 0; + modstack_init(&ctx->mods); + rbtree_init(&ctx->queries, &context_query_cmp); return ctx; } +/** delete q */ +static void +delq(rbnode_t* n, void* ATTR_UNUSED(arg)) +{ + struct ctx_query* q = (struct ctx_query*)n; + if(!q) return; + ub_val_result_free(q->res); + free(q); +} + void ub_val_ctx_delete(struct ub_val_ctx* ctx) { + struct alloc_cache* a, *na; if(!ctx) return; + modstack_desetup(&ctx->mods, ctx->env); + a = ctx->alloc_list; + while(a) { + na = a->super; + a->super = &ctx->superalloc; + alloc_clear(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); + lock_basic_destroy(&ctx->cfglock); close(ctx->qqpipe[0]); close(ctx->qqpipe[1]); close(ctx->rrpipe[0]); close(ctx->rrpipe[1]); - config_delete(ctx->cfg); + if(ctx->env) { + slabhash_delete(ctx->env->msg_cache); + rrset_cache_delete(ctx->env->rrset_cache); + infra_delete(ctx->env->infra_cache); + config_delete(ctx->env->cfg); + free(ctx->env); + } + traverse_postorder(&ctx->queries, delq, NULL); free(ctx); } int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname) { - if(!config_read(ctx->cfg, fname)) { + lock_basic_lock(&ctx->cfglock); + ctx->finalized = 0; + if(!config_read(ctx->env->cfg, fname)) { + lock_basic_unlock(&ctx->cfglock); return UB_SYNTAX; } + lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } @@ -166,10 +164,14 @@ ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta) { char* dup = strdup(ta); if(!dup) return UB_NOMEM; - if(!cfg_strlist_insert(&ctx->cfg->trust_anchor_list, dup)) { + lock_basic_lock(&ctx->cfglock); + ctx->finalized = 0; + if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) { + lock_basic_unlock(&ctx->cfglock); free(dup); return UB_NOMEM; } + lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } @@ -178,17 +180,24 @@ ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname) { char* dup = strdup(fname); if(!dup) return UB_NOMEM; - if(!cfg_strlist_insert(&ctx->cfg->trusted_keys_file_list, dup)) { + lock_basic_lock(&ctx->cfglock); + ctx->finalized = 0; + if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) { + lock_basic_unlock(&ctx->cfglock); free(dup); return UB_NOMEM; } + lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } int ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread) { + lock_basic_lock(&ctx->cfglock); + ctx->finalized = 0; ctx->dothread = dothread; + lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } @@ -223,13 +232,17 @@ ub_val_ctx_poll(struct ub_val_ctx* ctx) int ub_val_ctx_wait(struct ub_val_ctx* ctx) { + lock_basic_lock(&ctx->cfglock); /* TODO until no more queries outstanding */ - while(1) { + while(ctx->num_async > 0) { + lock_basic_unlock(&ctx->cfglock); lock_basic_lock(&ctx->rrpipe_lock); (void)pollit(ctx, NULL); lock_basic_unlock(&ctx->rrpipe_lock); ub_val_ctx_process(ctx); + lock_basic_lock(&ctx->cfglock); } + lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } @@ -243,6 +256,7 @@ int ub_val_ctx_process(struct ub_val_ctx* ctx) { /* TODO */ + /* ctx->num_asynx-- when handled; */ return UB_NOMEM; } @@ -250,7 +264,25 @@ int 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; + + lock_basic_lock(&ctx->cfglock); + if(!ctx->finalized) { + int r = context_finalize(ctx); + if(r) { + lock_basic_unlock(&ctx->cfglock); + return r; + } + } + /* create new ctx_query and attempt to add to the list */ + q = context_new(ctx, name, rrtype, rrclass, NULL, NULL); + lock_basic_unlock(&ctx->cfglock); + if(!q) + return UB_NOMEM; /* become a resolver thread for a bit */ + *secure = 0; + *data = 0; + *result = NULL; /* TODO */ return UB_NOMEM; @@ -260,14 +292,41 @@ int ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, void* mydata, ub_val_callback_t callback, int* async_id) { - /* TODO */ + struct ctx_query* q; + + lock_basic_lock(&ctx->cfglock); + if(!ctx->finalized) { + int r = context_finalize(ctx); + if(r) { + lock_basic_unlock(&ctx->cfglock); + return r; + } + } + /* create new ctx_query and attempt to add to the list */ + q = context_new(ctx, name, rrtype, rrclass, callback, mydata); + lock_basic_unlock(&ctx->cfglock); + if(!q) + return UB_NOMEM; + /* TODO write over pipe to background worker */ + *async_id = q->querynum; return UB_NOMEM; } int ub_val_cancel(struct ub_val_ctx* ctx, int async_id) { - /* TODO */ + struct ctx_query* q; + lock_basic_lock(&ctx->cfglock); + q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id); + lock_basic_unlock(&ctx->cfglock); + if(!q || !q->async) /* it is not there, so nothing to do */ + return UB_NOERROR; + /* TODO ; send cancel to background worker */ + + lock_basic_lock(&ctx->cfglock); + (void)rbtree_delete(&ctx->queries, &async_id); + ctx->num_async--; + lock_basic_unlock(&ctx->cfglock); return UB_NOMEM; } @@ -294,6 +353,7 @@ 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_INITFAIL: return "initialization failure"; default: return "unknown error"; } }