2007-11-30 09:53:57 -05:00
|
|
|
/*
|
|
|
|
|
* unbound.c - unbound validating resolver public API implementation
|
|
|
|
|
*
|
|
|
|
|
* 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 functions to resolve DNS queries and
|
|
|
|
|
* validate the answers. Synchonously and asynchronously.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* include the public api first, it should be able to stand alone */
|
|
|
|
|
#include "libunbound/unbound.h"
|
|
|
|
|
#include "config.h"
|
2007-12-04 11:14:09 -05:00
|
|
|
#include "libunbound/context.h"
|
2007-12-06 10:11:07 -05:00
|
|
|
#include "libunbound/worker.h"
|
2007-11-30 09:53:57 -05:00
|
|
|
#include "util/locks.h"
|
|
|
|
|
#include "util/config_file.h"
|
|
|
|
|
#include "util/alloc.h"
|
2007-12-04 11:14:09 -05:00
|
|
|
#include "util/module.h"
|
2008-01-22 06:10:49 -05:00
|
|
|
#include "util/regional.h"
|
2007-12-04 11:14:09 -05:00
|
|
|
#include "util/log.h"
|
|
|
|
|
#include "services/modstack.h"
|
|
|
|
|
#include "services/localzone.h"
|
|
|
|
|
#include "services/cache/infra.h"
|
|
|
|
|
#include "services/cache/rrset.h"
|
2007-11-30 09:53:57 -05:00
|
|
|
|
|
|
|
|
struct ub_val_ctx*
|
|
|
|
|
ub_val_ctx_create()
|
|
|
|
|
{
|
|
|
|
|
struct ub_val_ctx* ctx = (struct ub_val_ctx*)calloc(1, sizeof(*ctx));
|
|
|
|
|
if(!ctx) {
|
|
|
|
|
errno = ENOMEM;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2007-12-03 06:02:31 -05:00
|
|
|
checklock_start();
|
2007-12-04 11:14:09 -05:00
|
|
|
log_ident_set("libunbound");
|
|
|
|
|
verbosity = 0; /* errors only */
|
|
|
|
|
log_init(NULL, 0, NULL); /* logs to stderr */
|
|
|
|
|
alloc_init(&ctx->superalloc, NULL, 0);
|
2007-11-30 09:53:57 -05:00
|
|
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->qqpipe) == -1) {
|
|
|
|
|
free(ctx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->rrpipe) == -1) {
|
|
|
|
|
int e = errno;
|
|
|
|
|
close(ctx->qqpipe[0]);
|
|
|
|
|
close(ctx->qqpipe[1]);
|
|
|
|
|
free(ctx);
|
|
|
|
|
errno = e;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
lock_basic_init(&ctx->qqpipe_lock);
|
|
|
|
|
lock_basic_init(&ctx->rrpipe_lock);
|
2007-12-04 11:14:09 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2007-12-06 10:11:07 -05:00
|
|
|
ctx->env->cfg = config_create_forlib();
|
2007-12-04 11:14:09 -05:00
|
|
|
if(!ctx->env->cfg) {
|
2007-11-30 09:53:57 -05:00
|
|
|
ub_val_ctx_delete(ctx);
|
|
|
|
|
errno = ENOMEM;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
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);
|
2007-11-30 09:53:57 -05:00
|
|
|
return ctx;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-22 06:10:49 -05:00
|
|
|
/** delete q */
|
|
|
|
|
static void
|
|
|
|
|
delq(rbnode_t* n, void* ATTR_UNUSED(arg))
|
|
|
|
|
{
|
|
|
|
|
struct ctx_query* q = (struct ctx_query*)n;
|
|
|
|
|
context_query_delete(q);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-30 09:53:57 -05:00
|
|
|
void
|
|
|
|
|
ub_val_ctx_delete(struct ub_val_ctx* ctx)
|
|
|
|
|
{
|
2007-12-04 11:14:09 -05:00
|
|
|
struct alloc_cache* a, *na;
|
2007-11-30 09:53:57 -05:00
|
|
|
if(!ctx) return;
|
2007-12-04 11:14:09 -05:00
|
|
|
modstack_desetup(&ctx->mods, ctx->env);
|
|
|
|
|
a = ctx->alloc_list;
|
|
|
|
|
while(a) {
|
|
|
|
|
na = a->super;
|
|
|
|
|
a->super = &ctx->superalloc;
|
|
|
|
|
alloc_clear(a);
|
2007-12-06 10:11:07 -05:00
|
|
|
free(a);
|
2007-12-04 11:14:09 -05:00
|
|
|
a = na;
|
|
|
|
|
}
|
|
|
|
|
local_zones_delete(ctx->local_zones);
|
2007-11-30 09:53:57 -05:00
|
|
|
lock_basic_destroy(&ctx->qqpipe_lock);
|
|
|
|
|
lock_basic_destroy(&ctx->rrpipe_lock);
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_destroy(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
close(ctx->qqpipe[0]);
|
|
|
|
|
close(ctx->qqpipe[1]);
|
|
|
|
|
close(ctx->rrpipe[0]);
|
|
|
|
|
close(ctx->rrpipe[1]);
|
2007-12-04 11:14:09 -05:00
|
|
|
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);
|
|
|
|
|
}
|
2007-12-06 10:11:07 -05:00
|
|
|
alloc_clear(&ctx->superalloc);
|
2007-12-04 11:14:09 -05:00
|
|
|
traverse_postorder(&ctx->queries, delq, NULL);
|
2007-11-30 09:53:57 -05:00
|
|
|
free(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname)
|
|
|
|
|
{
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
2007-12-06 10:11:07 -05:00
|
|
|
if(ctx->finalized) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_AFTERFINAL;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
if(!config_read(ctx->env->cfg, fname)) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
return UB_SYNTAX;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta)
|
|
|
|
|
{
|
|
|
|
|
char* dup = strdup(ta);
|
|
|
|
|
if(!dup) return UB_NOMEM;
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
2007-12-06 10:11:07 -05:00
|
|
|
if(ctx->finalized) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_AFTERFINAL;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
free(dup);
|
|
|
|
|
return UB_NOMEM;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-06 12:05:21 -05:00
|
|
|
int
|
|
|
|
|
ub_val_ctx_add_ta_file(struct ub_val_ctx* ctx, char* fname)
|
|
|
|
|
{
|
|
|
|
|
char* dup = strdup(fname);
|
|
|
|
|
if(!dup) return UB_NOMEM;
|
|
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
if(ctx->finalized) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_AFTERFINAL;
|
|
|
|
|
}
|
|
|
|
|
if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
free(dup);
|
|
|
|
|
return UB_NOMEM;
|
|
|
|
|
}
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-30 09:53:57 -05:00
|
|
|
int
|
|
|
|
|
ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname)
|
|
|
|
|
{
|
|
|
|
|
char* dup = strdup(fname);
|
|
|
|
|
if(!dup) return UB_NOMEM;
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
2007-12-06 10:11:07 -05:00
|
|
|
if(ctx->finalized) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_AFTERFINAL;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
free(dup);
|
|
|
|
|
return UB_NOMEM;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-07 03:29:09 -05:00
|
|
|
int
|
|
|
|
|
ub_val_ctx_debuglevel(struct ub_val_ctx* ctx, int d)
|
|
|
|
|
{
|
|
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
verbosity = d;
|
|
|
|
|
ctx->env->cfg->verbosity = d;
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-30 09:53:57 -05:00
|
|
|
int
|
|
|
|
|
ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread)
|
|
|
|
|
{
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
2007-12-06 10:11:07 -05:00
|
|
|
if(ctx->finalized) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_AFTERFINAL;
|
|
|
|
|
}
|
2007-11-30 09:53:57 -05:00
|
|
|
ctx->dothread = dothread;
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-03 03:24:36 -05:00
|
|
|
/** perform a select() on the result read pipe */
|
2007-11-30 09:53:57 -05:00
|
|
|
static int
|
|
|
|
|
pollit(struct ub_val_ctx* ctx, struct timeval* t)
|
|
|
|
|
{
|
|
|
|
|
fd_set r;
|
2007-12-03 03:24:36 -05:00
|
|
|
#ifndef S_SPLINT_S
|
2007-11-30 09:53:57 -05:00
|
|
|
FD_ZERO(&r);
|
|
|
|
|
FD_SET(ctx->rrpipe[0], &r);
|
2007-12-03 03:24:36 -05:00
|
|
|
#endif
|
2007-11-30 09:53:57 -05:00
|
|
|
if(select(ctx->rrpipe[0]+1, &r, NULL, NULL, t) == -1) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
errno = 0;
|
|
|
|
|
return FD_ISSET(ctx->rrpipe[0], &r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_ctx_poll(struct ub_val_ctx* ctx)
|
|
|
|
|
{
|
|
|
|
|
struct timeval t;
|
2007-11-30 13:14:48 -05:00
|
|
|
int r;
|
2007-11-30 09:53:57 -05:00
|
|
|
memset(&t, 0, sizeof(t));
|
2007-11-30 13:14:48 -05:00
|
|
|
lock_basic_lock(&ctx->rrpipe_lock);
|
|
|
|
|
r = pollit(ctx, &t);
|
|
|
|
|
lock_basic_unlock(&ctx->rrpipe_lock);
|
|
|
|
|
return r;
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_ctx_wait(struct ub_val_ctx* ctx)
|
|
|
|
|
{
|
2008-01-22 06:10:49 -05:00
|
|
|
int r;
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
while(ctx->num_async > 0) {
|
2007-12-06 10:11:07 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2008-01-22 06:10:49 -05:00
|
|
|
lock_basic_lock(&ctx->rrpipe_lock);
|
|
|
|
|
r = pollit(ctx, NULL);
|
2007-11-30 13:14:48 -05:00
|
|
|
lock_basic_unlock(&ctx->rrpipe_lock);
|
2008-01-22 06:10:49 -05:00
|
|
|
if(r)
|
|
|
|
|
ub_val_ctx_process(ctx);
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-11-30 09:53:57 -05:00
|
|
|
return UB_NOERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_ctx_fd(struct ub_val_ctx* ctx)
|
|
|
|
|
{
|
2008-01-22 06:10:49 -05:00
|
|
|
int fd;
|
|
|
|
|
lock_basic_lock(&ctx->rrpipe_lock);
|
|
|
|
|
fd = ctx->rrpipe[0];
|
|
|
|
|
lock_basic_unlock(&ctx->rrpipe_lock);
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** process answer from bg worker */
|
|
|
|
|
static int
|
|
|
|
|
process_answer(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
struct ctx_query* q;
|
|
|
|
|
ub_val_callback_t cb;
|
|
|
|
|
void* cbarg;
|
|
|
|
|
struct ub_val_result* res;
|
|
|
|
|
if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
|
|
|
|
|
log_err("error: bad data from bg worker %d",
|
|
|
|
|
(int)context_serial_getcmd(msg, len));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
q = context_deserialize_answer(ctx, msg, len, &err);
|
|
|
|
|
if(!q) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
log_assert(q->async);
|
|
|
|
|
|
|
|
|
|
/* grab cb while locked */
|
|
|
|
|
cb = q->cb;
|
|
|
|
|
cbarg = q->cb_arg;
|
|
|
|
|
if(err) {
|
|
|
|
|
res = NULL;
|
|
|
|
|
ub_val_result_free(q->res);
|
|
|
|
|
} else {
|
|
|
|
|
/* parse the message, extract rcode, fill result */
|
|
|
|
|
ldns_buffer* buf = ldns_buffer_new(q->msg_len);
|
|
|
|
|
struct regional* region = regional_create();
|
|
|
|
|
res = q->res;
|
|
|
|
|
res->rcode = LDNS_RCODE_SERVFAIL;
|
|
|
|
|
if(region && buf) {
|
|
|
|
|
ldns_buffer_clear(buf);
|
|
|
|
|
ldns_buffer_write(buf, q->msg, q->msg_len);
|
|
|
|
|
ldns_buffer_flip(buf);
|
|
|
|
|
libworker_enter_result(res, buf, region,
|
|
|
|
|
q->msg_security);
|
|
|
|
|
}
|
|
|
|
|
ldns_buffer_free(buf);
|
|
|
|
|
regional_destroy(region);
|
|
|
|
|
}
|
|
|
|
|
q->res = NULL;
|
|
|
|
|
/* delete the q from list */
|
|
|
|
|
(void)rbtree_delete(&ctx->queries, q->node.key);
|
|
|
|
|
ctx->num_async--;
|
|
|
|
|
context_query_delete(q);
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
|
|
|
|
|
/* no locks held while calling callback, so that library is
|
|
|
|
|
* re-entrant. */
|
|
|
|
|
(*cb)(cbarg, err, res);
|
|
|
|
|
|
|
|
|
|
return 1;
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_ctx_process(struct ub_val_ctx* ctx)
|
|
|
|
|
{
|
2008-01-22 06:10:49 -05:00
|
|
|
int r;
|
|
|
|
|
uint8_t* msg = NULL;
|
|
|
|
|
uint32_t len = 0;
|
|
|
|
|
while(1) {
|
|
|
|
|
lock_basic_lock(&ctx->rrpipe_lock);
|
|
|
|
|
r = libworker_read_msg(ctx->rrpipe[0], &msg, &len, 1);
|
|
|
|
|
lock_basic_unlock(&ctx->rrpipe_lock);
|
|
|
|
|
if(r == 0)
|
|
|
|
|
return UB_PIPE;
|
|
|
|
|
else if(r == -1)
|
|
|
|
|
return UB_NOERROR;
|
|
|
|
|
if(!process_answer(ctx, msg, len)) {
|
|
|
|
|
free(msg);
|
|
|
|
|
return UB_PIPE;
|
|
|
|
|
}
|
|
|
|
|
free(msg);
|
|
|
|
|
}
|
|
|
|
|
return UB_NOERROR;
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
|
2008-01-18 08:52:22 -05:00
|
|
|
int rrclass, struct ub_val_result** result)
|
2007-11-30 09:53:57 -05:00
|
|
|
{
|
2007-12-04 11:14:09 -05:00
|
|
|
struct ctx_query* q;
|
2007-12-06 10:11:07 -05:00
|
|
|
int r;
|
2007-12-04 11:14:09 -05:00
|
|
|
|
|
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
if(!ctx->finalized) {
|
2007-12-06 10:11:07 -05:00
|
|
|
r = context_finalize(ctx);
|
2007-12-04 11:14:09 -05:00
|
|
|
if(r) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* create new ctx_query and attempt to add to the list */
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-12-05 01:41:39 -05:00
|
|
|
q = context_new(ctx, name, rrtype, rrclass, NULL, NULL);
|
2007-12-04 11:14:09 -05:00
|
|
|
if(!q)
|
|
|
|
|
return UB_NOMEM;
|
2007-11-30 09:53:57 -05:00
|
|
|
/* become a resolver thread for a bit */
|
2007-12-04 11:14:09 -05:00
|
|
|
*result = NULL;
|
2007-11-30 09:53:57 -05:00
|
|
|
|
2007-12-06 10:11:07 -05:00
|
|
|
r = libworker_fg(ctx, q);
|
|
|
|
|
if(r) {
|
2008-01-22 06:10:49 -05:00
|
|
|
context_query_delete(q);
|
2007-12-06 10:11:07 -05:00
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
*result = q->res;
|
2008-01-22 06:10:49 -05:00
|
|
|
q->res = NULL;
|
2007-12-06 10:11:07 -05:00
|
|
|
|
|
|
|
|
(void)rbtree_delete(&ctx->queries, q->node.key);
|
2008-01-22 06:10:49 -05:00
|
|
|
context_query_delete(q);
|
2007-12-06 10:11:07 -05:00
|
|
|
return UB_NOERROR;
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2007-12-04 11:14:09 -05:00
|
|
|
struct ctx_query* q;
|
2008-01-22 06:10:49 -05:00
|
|
|
uint8_t* msg = NULL;
|
|
|
|
|
uint32_t len = 0;
|
2007-12-04 11:14:09 -05:00
|
|
|
|
2008-01-22 06:10:49 -05:00
|
|
|
*async_id = 0;
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
if(!ctx->finalized) {
|
|
|
|
|
int r = context_finalize(ctx);
|
|
|
|
|
if(r) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-12-06 10:11:07 -05:00
|
|
|
if(!ctx->created_bg) {
|
|
|
|
|
int r = libworker_bg(ctx);
|
|
|
|
|
if(r) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
ctx->created_bg = 1;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-12-06 10:11:07 -05:00
|
|
|
|
|
|
|
|
/* create new ctx_query and attempt to add to the list */
|
2007-12-05 01:41:39 -05:00
|
|
|
q = context_new(ctx, name, rrtype, rrclass, callback, mydata);
|
2007-12-04 11:14:09 -05:00
|
|
|
if(!q)
|
|
|
|
|
return UB_NOMEM;
|
2008-01-22 06:10:49 -05:00
|
|
|
|
|
|
|
|
/* write over pipe to background worker */
|
|
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
msg = context_serialize_new_query(q, &len);
|
|
|
|
|
if(!msg) {
|
|
|
|
|
(void)rbtree_delete(&ctx->queries, q->node.key);
|
|
|
|
|
ctx->num_async--;
|
|
|
|
|
context_query_delete(q);
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_NOMEM;
|
|
|
|
|
}
|
2007-12-04 11:14:09 -05:00
|
|
|
*async_id = q->querynum;
|
2008-01-22 06:10:49 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
|
|
|
|
|
lock_basic_lock(&ctx->qqpipe_lock);
|
|
|
|
|
libworker_write_msg(ctx->qqpipe[1], msg, len, 0);
|
|
|
|
|
lock_basic_unlock(&ctx->qqpipe_lock);
|
|
|
|
|
free(msg);
|
|
|
|
|
return UB_NOERROR;
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ub_val_cancel(struct ub_val_ctx* ctx, int async_id)
|
|
|
|
|
{
|
2007-12-04 11:14:09 -05:00
|
|
|
struct ctx_query* q;
|
2008-01-22 06:10:49 -05:00
|
|
|
uint8_t* msg = NULL;
|
|
|
|
|
uint32_t len = 0;
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_lock(&ctx->cfglock);
|
|
|
|
|
q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id);
|
2008-01-22 06:10:49 -05:00
|
|
|
if(!q || !q->async) {
|
|
|
|
|
/* it is not there, so nothing to do */
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2007-12-04 11:14:09 -05:00
|
|
|
return UB_NOERROR;
|
2008-01-22 06:10:49 -05:00
|
|
|
}
|
|
|
|
|
log_assert(q->async);
|
|
|
|
|
msg = context_serialize_cancel(q, &len);
|
|
|
|
|
if(!msg) {
|
|
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
|
|
|
|
return UB_NOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* delete it */
|
|
|
|
|
(void)rbtree_delete(&ctx->queries, q->node.key);
|
2007-12-04 11:14:09 -05:00
|
|
|
ctx->num_async--;
|
2008-01-22 06:10:49 -05:00
|
|
|
context_query_delete(q);
|
2007-12-04 11:14:09 -05:00
|
|
|
lock_basic_unlock(&ctx->cfglock);
|
2008-01-22 06:10:49 -05:00
|
|
|
|
|
|
|
|
/* send cancel to background worker */
|
|
|
|
|
lock_basic_lock(&ctx->qqpipe_lock);
|
|
|
|
|
libworker_write_msg(ctx->qqpipe[1], msg, len, 0);
|
|
|
|
|
lock_basic_unlock(&ctx->qqpipe_lock);
|
|
|
|
|
free(msg);
|
|
|
|
|
return UB_NOERROR;
|
2007-11-30 09:53:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ub_val_result_free(struct ub_val_result* result)
|
|
|
|
|
{
|
|
|
|
|
char** p;
|
|
|
|
|
if(!result) return;
|
|
|
|
|
free(result->qname);
|
2007-12-06 10:11:07 -05:00
|
|
|
if(result->canonname != result->qname)
|
|
|
|
|
free(result->canonname);
|
|
|
|
|
if(result->data)
|
|
|
|
|
for(p = result->data; *p; p++)
|
|
|
|
|
free(*p);
|
2007-11-30 09:53:57 -05:00
|
|
|
free(result->data);
|
|
|
|
|
free(result->len);
|
|
|
|
|
free(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
ub_val_strerror(int err)
|
|
|
|
|
{
|
|
|
|
|
switch(err) {
|
|
|
|
|
case UB_NOERROR: return "no error";
|
|
|
|
|
case UB_SOCKET: return "socket io error";
|
2008-01-18 08:52:22 -05:00
|
|
|
case UB_NOMEM: return "out of memory";
|
2007-11-30 09:53:57 -05:00
|
|
|
case UB_SYNTAX: return "syntax error";
|
|
|
|
|
case UB_SERVFAIL: return "server failure";
|
2007-12-06 10:11:07 -05:00
|
|
|
case UB_FORKFAIL: return "could not fork";
|
2007-12-04 11:14:09 -05:00
|
|
|
case UB_INITFAIL: return "initialization failure";
|
2007-12-06 10:11:07 -05:00
|
|
|
case UB_AFTERFINAL: return "setting change after finalize";
|
2008-01-22 06:10:49 -05:00
|
|
|
case UB_PIPE: return "error in pipe communication with async";
|
2007-11-30 09:53:57 -05:00
|
|
|
default: return "unknown error";
|
|
|
|
|
}
|
|
|
|
|
}
|