libworker.c revision 269257
1139825Simp/*
261926Smckusick * libunbound/worker.c - worker thread or process that resolves
336201Sjulian *
436206Sjulian * Copyright (c) 2007, NLnet Labs. All rights reserved.
536206Sjulian *
636206Sjulian * This software is open source.
736206Sjulian *
836201Sjulian * Redistribution and use in source and binary forms, with or without
961926Smckusick * modification, are permitted provided that the following conditions
1036201Sjulian * are met:
1161926Smckusick *
1261926Smckusick * Redistributions of source code must retain the above copyright notice,
1361926Smckusick * this list of conditions and the following disclaimer.
1436201Sjulian *
1536201Sjulian * Redistributions in binary form must reproduce the above copyright notice,
1636201Sjulian * this list of conditions and the following disclaimer in the documentation
1736201Sjulian * and/or other materials provided with the distribution.
1836201Sjulian *
1936201Sjulian * Neither the name of the NLNET LABS nor the names of its contributors may
2036201Sjulian * be used to endorse or promote products derived from this software without
2136201Sjulian * specific prior written permission.
2236201Sjulian *
2336201Sjulian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2436201Sjulian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2536201Sjulian * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2636201Sjulian * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2736201Sjulian * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2836201Sjulian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2936201Sjulian * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3036201Sjulian * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3136201Sjulian * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3236201Sjulian * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3336201Sjulian * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3436201Sjulian */
3536201Sjulian
3636201Sjulian/**
3736201Sjulian * \file
3861926Smckusick *
3950480Speter * This file contains the worker process or thread that performs
4036201Sjulian * the DNS resolving and validation. The worker is called by a procedure
4136201Sjulian * and if in the background continues until exit, if in the foreground
4236201Sjulian * returns from the procedure when done.
4336201Sjulian */
4436201Sjulian#include "config.h"
4536201Sjulian#ifdef HAVE_SSL
4636201Sjulian#include <openssl/ssl.h>
4736201Sjulian#endif
4836201Sjulian#include "libunbound/libworker.h"
49208287Sjeff#include "libunbound/context.h"
50208287Sjeff#include "libunbound/unbound.h"
51208287Sjeff#include "libunbound/worker.h"
52208287Sjeff#include "libunbound/unbound-event.h"
5336201Sjulian#include "services/outside_network.h"
5436201Sjulian#include "services/mesh.h"
5536201Sjulian#include "services/localzone.h"
5636201Sjulian#include "services/cache/rrset.h"
57208287Sjeff#include "services/outbound_list.h"
58208287Sjeff#include "util/fptr_wlist.h"
59208287Sjeff#include "util/module.h"
60208287Sjeff#include "util/regional.h"
61208287Sjeff#include "util/random.h"
62208287Sjeff#include "util/config_file.h"
63208287Sjeff#include "util/netevent.h"
6436201Sjulian#include "util/storage/lookup3.h"
6536201Sjulian#include "util/storage/slabhash.h"
6636201Sjulian#include "util/net_help.h"
6736201Sjulian#include "util/data/dname.h"
68208287Sjeff#include "util/data/msgreply.h"
69208287Sjeff#include "util/data/msgencode.h"
70208287Sjeff#include "util/tube.h"
71208287Sjeff#include "iterator/iter_fwd.h"
72208287Sjeff#include "iterator/iter_hints.h"
73208287Sjeff#include "ldns/sbuffer.h"
74208287Sjeff#include "ldns/str2wire.h"
75208287Sjeff
76208287Sjeff/** handle new query command for bg worker */
77208287Sjeffstatic void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
78208287Sjeff
79208287Sjeff/** delete libworker env */
80208287Sjeffstatic void
81208287Sjefflibworker_delete_env(struct libworker* w)
82208287Sjeff{
83208287Sjeff	if(w->env) {
84208287Sjeff		outside_network_quit_prepare(w->back);
8536201Sjulian		mesh_delete(w->env->mesh);
8636201Sjulian		context_release_alloc(w->ctx, w->env->alloc,
8736201Sjulian			!w->is_bg || w->is_bg_thread);
88208287Sjeff		sldns_buffer_free(w->env->scratch_buffer);
89208287Sjeff		regional_destroy(w->env->scratch);
90208287Sjeff		forwards_delete(w->env->fwds);
91208287Sjeff		hints_delete(w->env->hints);
92208287Sjeff		ub_randfree(w->env->rnd);
93208287Sjeff		free(w->env);
94208287Sjeff	}
95208287Sjeff#ifdef HAVE_SSL
96208287Sjeff	SSL_CTX_free(w->sslctx);
97208287Sjeff#endif
98208287Sjeff	outside_network_delete(w->back);
99208287Sjeff}
100208287Sjeff
101208287Sjeff/** delete libworker struct */
102208287Sjeffstatic void
103208287Sjefflibworker_delete(struct libworker* w)
104208287Sjeff{
105208287Sjeff	if(!w) return;
106208287Sjeff	libworker_delete_env(w);
107208287Sjeff	comm_base_delete(w->base);
108100344Smckusick	free(w);
109100344Smckusick}
110212617Smckusick
111212617Smckusickvoid
112212617Smckusicklibworker_delete_event(struct libworker* w)
113212617Smckusick{
114212617Smckusick	if(!w) return;
115212617Smckusick	libworker_delete_env(w);
116212617Smckusick	comm_base_delete_no_base(w->base);
117212617Smckusick	free(w);
118212617Smckusick}
11936201Sjulian
120207141Sjeff/** setup fresh libworker struct */
121207141Sjeffstatic struct libworker*
122207141Sjefflibworker_setup(struct ub_ctx* ctx, int is_bg, struct event_base* eb)
123207141Sjeff{
124207141Sjeff	unsigned int seed;
125207141Sjeff	struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
126207141Sjeff	struct config_file* cfg = ctx->env->cfg;
127207141Sjeff	int* ports;
128207141Sjeff	int numports;
129207141Sjeff	if(!w) return NULL;
130222958Sjeff	w->is_bg = is_bg;
131207141Sjeff	w->ctx = ctx;
132207141Sjeff	w->env = (struct module_env*)malloc(sizeof(*w->env));
133207141Sjeff	if(!w->env) {
134207141Sjeff		free(w);
135258403Sjmg		return NULL;
136207141Sjeff	}
137207141Sjeff	*w->env = *ctx->env;
138207141Sjeff	w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
139207141Sjeff	if(!w->env->alloc) {
140207141Sjeff		libworker_delete(w);
141207141Sjeff		return NULL;
142207141Sjeff	}
14336201Sjulian	w->thread_num = w->env->alloc->thread_num;
14436201Sjulian	alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
14536201Sjulian	if(!w->is_bg || w->is_bg_thread) {
14636201Sjulian		lock_basic_lock(&ctx->cfglock);
147256817Smckusick	}
148256817Smckusick	w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
149256817Smckusick	w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
150256817Smckusick	w->env->fwds = forwards_create();
151256817Smckusick	if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
152256817Smckusick		forwards_delete(w->env->fwds);
153256817Smckusick		w->env->fwds = NULL;
154256817Smckusick	}
155256817Smckusick	w->env->hints = hints_create();
156256817Smckusick	if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
157256817Smckusick		hints_delete(w->env->hints);
158256817Smckusick		w->env->hints = NULL;
159256817Smckusick	}
160256817Smckusick	if(cfg->ssl_upstream) {
161256817Smckusick		w->sslctx = connect_sslctx_create(NULL, NULL, NULL);
162256817Smckusick		if(!w->sslctx) {
163256817Smckusick			/* to make the setup fail after unlock */
164256817Smckusick			hints_delete(w->env->hints);
165256817Smckusick			w->env->hints = NULL;
166256817Smckusick		}
167256817Smckusick	}
168256817Smckusick	if(!w->is_bg || w->is_bg_thread) {
169256817Smckusick		lock_basic_unlock(&ctx->cfglock);
170256817Smckusick	}
171256817Smckusick	if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
172256817Smckusick		!w->env->hints) {
173256817Smckusick		libworker_delete(w);
174256817Smckusick		return NULL;
175256817Smckusick	}
176256817Smckusick	w->env->worker = (struct worker*)w;
177256817Smckusick	w->env->probe_timer = NULL;
178256817Smckusick	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
179256817Smckusick		(((unsigned int)w->thread_num)<<17);
18036201Sjulian	seed ^= (unsigned int)w->env->alloc->next_id;
18136201Sjulian	if(!w->is_bg || w->is_bg_thread) {
18236201Sjulian		lock_basic_lock(&ctx->cfglock);
18336201Sjulian	}
18436201Sjulian	if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) {
18536201Sjulian		if(!w->is_bg || w->is_bg_thread) {
18636201Sjulian			lock_basic_unlock(&ctx->cfglock);
18736201Sjulian		}
18836201Sjulian		seed = 0;
18936201Sjulian		libworker_delete(w);
19036201Sjulian		return NULL;
19160938Sjake	}
19236201Sjulian	if(!w->is_bg || w->is_bg_thread) {
19336201Sjulian		lock_basic_unlock(&ctx->cfglock);
19436201Sjulian	}
19536201Sjulian	if(1) {
19636201Sjulian		/* primitive lockout for threading: if it overwrites another
19736201Sjulian		 * thread it is like wiping the cache (which is likely empty
19836201Sjulian		 * at the start) */
19936201Sjulian		/* note we are holding the ctx lock in normal threaded
20036201Sjulian		 * cases so that is solved properly, it is only for many ctx
201207141Sjeff		 * in different threads that this may clash */
202156203Sjeff		static int done_raninit = 0;
203207141Sjeff		if(!done_raninit) {
204207141Sjeff			done_raninit = 1;
20536201Sjulian			hash_set_raninit((uint32_t)ub_random(w->env->rnd));
206262678Spfg		}
207262678Spfg	}
208262678Spfg	seed = 0;
209262678Spfg
210207141Sjeff	if(eb)
211262678Spfg		w->base = comm_base_create_event(eb);
212262678Spfg	else	w->base = comm_base_create(0);
213262678Spfg	if(!w->base) {
214262678Spfg		libworker_delete(w);
215262678Spfg		return NULL;
216262678Spfg	}
217262678Spfg	if(!w->is_bg || w->is_bg_thread) {
218262678Spfg		lock_basic_lock(&ctx->cfglock);
219262678Spfg	}
220262678Spfg	numports = cfg_condense_ports(cfg, &ports);
221262678Spfg	if(numports == 0) {
222207141Sjeff		int locked = !w->is_bg || w->is_bg_thread;
223207141Sjeff		libworker_delete(w);
224207141Sjeff		if(locked) {
225207141Sjeff			lock_basic_unlock(&ctx->cfglock);
226207141Sjeff		}
227207141Sjeff		return NULL;
228207141Sjeff	}
229207141Sjeff	w->back = outside_network_create(w->base, cfg->msg_buffer_size,
230207141Sjeff		(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
231222958Sjeff		cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
232207141Sjeff		cfg->do_tcp?cfg->outgoing_num_tcp:0,
233222958Sjeff		w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
23436201Sjulian		ports, numports, cfg->unwanted_threshold,
23536201Sjulian		&libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx,
23636201Sjulian		cfg->delay_close);
23736201Sjulian	if(!w->is_bg || w->is_bg_thread) {
23860938Sjake		lock_basic_unlock(&ctx->cfglock);
23960938Sjake	}
24060938Sjake	free(ports);
24160938Sjake	if(!w->back) {
24260938Sjake		libworker_delete(w);
24360938Sjake		return NULL;
24460938Sjake	}
245207141Sjeff	w->env->mesh = mesh_create(&ctx->mods, w->env);
246207141Sjeff	if(!w->env->mesh) {
247207141Sjeff		libworker_delete(w);
248207141Sjeff		return NULL;
249207141Sjeff	}
250222958Sjeff	w->env->send_query = &libworker_send_query;
251207141Sjeff	w->env->detach_subs = &mesh_detach_subs;
252222958Sjeff	w->env->attach_sub = &mesh_attach_sub;
253207141Sjeff	w->env->kill_sub = &mesh_state_delete;
254207141Sjeff	w->env->detect_cycle = &mesh_detect_cycle;
255222958Sjeff	comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
25636201Sjulian	return w;
25736201Sjulian}
25836201Sjulian
25936201Sjulianstruct libworker* libworker_create_event(struct ub_ctx* ctx,
26036201Sjulian	struct event_base* eb)
26136201Sjulian{
26236201Sjulian	return libworker_setup(ctx, 0, eb);
26336201Sjulian}
26436201Sjulian
26536201Sjulian/** handle cancel command for bg worker */
26636201Sjulianstatic void
26736201Sjulianhandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
26836201Sjulian{
26936201Sjulian	struct ctx_query* q;
27036201Sjulian	if(w->is_bg_thread) {
27136201Sjulian		lock_basic_lock(&w->ctx->cfglock);
27236201Sjulian		q = context_deserialize_cancel(w->ctx, buf, len);
27336201Sjulian		lock_basic_unlock(&w->ctx->cfglock);
27436201Sjulian	} else {
275262678Spfg		q = context_deserialize_cancel(w->ctx, buf, len);
276262678Spfg	}
27736201Sjulian	if(!q) {
27836201Sjulian		/* probably simply lookup failed, i.e. the message had been
27936201Sjulian		 * processed and answered before the cancel arrived */
28060938Sjake		return;
28136201Sjulian	}
28236201Sjulian	q->cancelled = 1;
283207141Sjeff	free(buf);
28436201Sjulian}
28536201Sjulian
28636201Sjulian/** do control command coming into bg server */
287207141Sjeffstatic void
28836201Sjulianlibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
28936201Sjulian{
29036201Sjulian	switch(context_serial_getcmd(msg, len)) {
29136201Sjulian		default:
29236225Sjulian		case UB_LIBCMD_ANSWER:
29336225Sjulian			log_err("unknown command for bg worker %d",
29436225Sjulian				(int)context_serial_getcmd(msg, len));
29536225Sjulian			/* and fall through to quit */
29636225Sjulian		case UB_LIBCMD_QUIT:
29736225Sjulian			free(msg);
29836225Sjulian			comm_base_exit(w->base);
29936225Sjulian			break;
30036225Sjulian		case UB_LIBCMD_NEWQUERY:
30136225Sjulian			handle_newq(w, msg, len);
30236225Sjulian			break;
30336225Sjulian		case UB_LIBCMD_CANCEL:
30436225Sjulian			handle_cancel(w, msg, len);
30536225Sjulian			break;
30636201Sjulian	}
30736201Sjulian}
30836225Sjulian
30936201Sjulian/** handle control command coming into server */
31036201Sjulianvoid
31136225Sjulianlibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
31236225Sjulian	uint8_t* msg, size_t len, int err, void* arg)
31336225Sjulian{
31436201Sjulian	struct libworker* w = (struct libworker*)arg;
31536201Sjulian
31636201Sjulian	if(err != 0) {
31736225Sjulian		free(msg);
31836225Sjulian		/* it is of no use to go on, exit */
31936225Sjulian		comm_base_exit(w->base);
32036225Sjulian		return;
32136225Sjulian	}
32236225Sjulian	libworker_do_cmd(w, msg, len); /* also frees the buf */
32336225Sjulian}
32436201Sjulian
32536201Sjulian/** the background thread func */
32636201Sjulianstatic void*
32736206Sjulianlibworker_dobg(void* arg)
32836225Sjulian{
32936225Sjulian	/* setup */
33036225Sjulian	uint32_t m;
33136206Sjulian	struct libworker* w = (struct libworker*)arg;
33236206Sjulian	struct ub_ctx* ctx;
33336206Sjulian	if(!w) {
33436206Sjulian		log_err("libunbound bg worker init failed, nomem");
33536206Sjulian		return NULL;
33636201Sjulian	}
33736201Sjulian	ctx = w->ctx;
33836201Sjulian	log_thread_set(&w->thread_num);
33936201Sjulian#ifdef THREADS_DISABLED
34060938Sjake	/* we are forked */
341207141Sjeff	w->is_bg_thread = 0;
34236201Sjulian	/* close non-used parts of the pipes */
34336201Sjulian	tube_close_write(ctx->qq_pipe);
34436201Sjulian	tube_close_read(ctx->rr_pipe);
345207141Sjeff#endif
34660938Sjake	if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
347207141Sjeff		libworker_handle_control_cmd, w)) {
348207141Sjeff		log_err("libunbound bg worker init failed, no bglisten");
349207141Sjeff		return NULL;
350100344Smckusick	}
35136201Sjulian	if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
352207141Sjeff		log_err("libunbound bg worker init failed, no bgwrite");
35336201Sjulian		return NULL;
35436225Sjulian	}
35536225Sjulian
35636201Sjulian	/* do the work */
35736201Sjulian	comm_base_dispatch(w->base);
358100344Smckusick
359100344Smckusick	/* cleanup */
360222958Sjeff	m = UB_LIBCMD_QUIT;
36198542Smckusick	tube_remove_bg_listen(w->ctx->qq_pipe);
36298542Smckusick	tube_remove_bg_write(w->ctx->rr_pipe);
36398542Smckusick	libworker_delete(w);
36498542Smckusick	(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
36536201Sjulian		(uint32_t)sizeof(m), 0);
366262678Spfg#ifdef THREADS_DISABLED
367262678Spfg	/* close pipes from forked process before exit */
36836201Sjulian	tube_close_read(ctx->qq_pipe);
36936201Sjulian	tube_close_write(ctx->rr_pipe);
37036201Sjulian#endif
37136201Sjulian	return NULL;
37236201Sjulian}
37336201Sjulian
37436201Sjulianint libworker_bg(struct ub_ctx* ctx)
37536201Sjulian{
37636201Sjulian	struct libworker* w;
37736201Sjulian	/* fork or threadcreate */
37836201Sjulian	lock_basic_lock(&ctx->cfglock);
37936201Sjulian	if(ctx->dothread) {
38036201Sjulian		lock_basic_unlock(&ctx->cfglock);
381207141Sjeff		w = libworker_setup(ctx, 1, NULL);
382222958Sjeff		if(!w) return UB_NOMEM;
383222958Sjeff		w->is_bg_thread = 1;
384207141Sjeff#ifdef ENABLE_LOCK_CHECKS
38536201Sjulian		w->thread_num = 1; /* for nicer DEBUG checklocks */
38636201Sjulian#endif
387207141Sjeff		ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
38836201Sjulian	} else {
389207141Sjeff		lock_basic_unlock(&ctx->cfglock);
39036201Sjulian#ifndef HAVE_FORK
391207141Sjeff		/* no fork on windows */
39236201Sjulian		return UB_FORKFAIL;
393207141Sjeff#else /* HAVE_FORK */
394207141Sjeff		switch((ctx->bg_pid=fork())) {
395207141Sjeff			case 0:
396222958Sjeff				w = libworker_setup(ctx, 1, NULL);
397222958Sjeff				if(!w) fatal_exit("out of memory");
39836201Sjulian				/* close non-used parts of the pipes */
39936201Sjulian				tube_close_write(ctx->qq_pipe);
40036201Sjulian				tube_close_read(ctx->rr_pipe);
401207141Sjeff				(void)libworker_dobg(w);
402207141Sjeff				exit(0);
403207141Sjeff				break;
404207141Sjeff			case -1:
405212617Smckusick				return UB_FORKFAIL;
406212617Smckusick			default:
407212617Smckusick				/* close non-used parts, so that the worker
408207141Sjeff				 * bgprocess gets 'pipe closed' when the
409207141Sjeff				 * main process exits */
410212617Smckusick				tube_close_read(ctx->qq_pipe);
411207141Sjeff				tube_close_write(ctx->rr_pipe);
412212617Smckusick				break;
413212617Smckusick		}
414207141Sjeff#endif /* HAVE_FORK */
415212617Smckusick	}
416212617Smckusick	return UB_NOERROR;
417207141Sjeff}
418212617Smckusick
419207141Sjeff/** get msg reply struct (in temp region) */
420212617Smckusickstatic struct reply_info*
421207141Sjeffparse_reply(sldns_buffer* pkt, struct regional* region, struct query_info* qi)
422207141Sjeff{
423207141Sjeff	struct reply_info* rep;
42436201Sjulian	struct msg_parse* msg;
42536201Sjulian	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
42636201Sjulian		return NULL;
42736201Sjulian	}
42836201Sjulian	memset(msg, 0, sizeof(*msg));
42936201Sjulian	sldns_buffer_set_position(pkt, 0);
43036201Sjulian	if(parse_packet(pkt, msg, region) != 0)
43136201Sjulian		return 0;
43236201Sjulian	if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
43336201Sjulian		return 0;
43436201Sjulian	}
43536201Sjulian	return rep;
43636201Sjulian}
43736201Sjulian
43876724Smckusick/** insert canonname */
43976724Smckusickstatic int
44076724Smckusickfill_canon(struct ub_result* res, uint8_t* s)
44176724Smckusick{
44276724Smckusick	char buf[255+2];
44376724Smckusick	dname_str(s, buf);
44476724Smckusick	res->canonname = strdup(buf);
44576724Smckusick	return res->canonname != 0;
44676724Smckusick}
44776724Smckusick
44876724Smckusick/** fill data into result */
44936201Sjulianstatic int
45036201Sjulianfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
451207141Sjeff	uint8_t* finalcname, struct query_info* rq, struct reply_info* rep)
452256817Smckusick{
453256817Smckusick	size_t i;
45460938Sjake	struct packed_rrset_data* data;
45536201Sjulian	res->ttl = 0;
456207141Sjeff	if(!answer) {
457207141Sjeff		if(finalcname) {
458207141Sjeff			if(!fill_canon(res, finalcname))
459207141Sjeff				return 0; /* out of memory */
46036201Sjulian		}
461207141Sjeff		if(rep->rrset_count != 0)
462207141Sjeff			res->ttl = (int)rep->ttl;
463207141Sjeff		res->data = (char**)calloc(1, sizeof(char*));
46436201Sjulian		res->len = (int*)calloc(1, sizeof(int));
46536201Sjulian		return (res->data && res->len);
46636201Sjulian	}
46736201Sjulian	data = (struct packed_rrset_data*)answer->entry.data;
46836201Sjulian	if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
46936201Sjulian		if(!fill_canon(res, answer->rk.dname))
47036201Sjulian			return 0; /* out of memory */
47136201Sjulian	} else	res->canonname = NULL;
47236201Sjulian	res->data = (char**)calloc(data->count+1, sizeof(char*));
47336201Sjulian	res->len = (int*)calloc(data->count+1, sizeof(int));
47436201Sjulian	if(!res->data || !res->len)
47536201Sjulian		return 0; /* out of memory */
47636201Sjulian	for(i=0; i<data->count; i++) {
47736201Sjulian		/* remove rdlength from rdata */
47836201Sjulian		res->len[i] = (int)(data->rr_len[i] - 2);
47936201Sjulian		res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
48036201Sjulian		if(!res->data[i])
48136201Sjulian			return 0; /* out of memory */
48236201Sjulian	}
48336201Sjulian	/* ttl for positive answers, from CNAME and answer RRs */
48436201Sjulian	if(data->count != 0) {
485207141Sjeff		size_t j;
486222958Sjeff		res->ttl = (int)data->ttl;
487207141Sjeff		for(j=0; j<rep->an_numrrsets; j++) {
48836201Sjulian			struct packed_rrset_data* d =
489222958Sjeff				(struct packed_rrset_data*)rep->rrsets[j]->
490207141Sjeff				entry.data;
491207141Sjeff			if((int)d->ttl < res->ttl)
49236201Sjulian				res->ttl = (int)d->ttl;
49336201Sjulian		}
494222958Sjeff	}
49536201Sjulian	/* ttl for negative answers */
49636201Sjulian	if(data->count == 0 && rep->rrset_count != 0)
49736201Sjulian		res->ttl = (int)rep->ttl;
49836201Sjulian	res->data[data->count] = NULL;
49936201Sjulian	res->len[data->count] = 0;
50036201Sjulian	return 1;
50136201Sjulian}
50236201Sjulian
50336201Sjulian/** fill result from parsed message, on error fills servfail */
50436201Sjulianvoid
50536201Sjulianlibworker_enter_result(struct ub_result* res, sldns_buffer* buf,
50636201Sjulian	struct regional* temp, enum sec_status msg_security)
50736201Sjulian{
50836201Sjulian	struct query_info rq;
50936201Sjulian	struct reply_info* rep;
51036201Sjulian	res->rcode = LDNS_RCODE_SERVFAIL;
511207141Sjeff	rep = parse_reply(buf, temp, &rq);
512207141Sjeff	if(!rep) {
51360938Sjake		log_err("cannot parse buf");
51436201Sjulian		return; /* error parsing buf, or out of memory */
515207141Sjeff	}
516222958Sjeff	if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
517207141Sjeff		reply_find_final_cname_target(&rq, rep), &rq, rep))
51836201Sjulian		return; /* out of memory */
519207141Sjeff	/* rcode, havedata, nxdomain, secure, bogus */
520207141Sjeff	res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
521207141Sjeff	if(res->data && res->data[0])
52236201Sjulian		res->havedata = 1;
52336201Sjulian	if(res->rcode == LDNS_RCODE_NXDOMAIN)
524207141Sjeff		res->nxdomain = 1;
525207141Sjeff	if(msg_security == sec_status_secure)
526207141Sjeff		res->secure = 1;
527207141Sjeff	if(msg_security == sec_status_bogus)
528207141Sjeff		res->bogus = 1;
529207141Sjeff}
530207141Sjeff
531207141Sjeff/** fillup fg results */
532207141Sjeffstatic void
533207141Sjefflibworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf,
53436201Sjulian	enum sec_status s, char* why_bogus)
53536201Sjulian{
53636201Sjulian	if(why_bogus)
53736201Sjulian		q->res->why_bogus = strdup(why_bogus);
538207141Sjeff	if(rcode != 0) {
53936201Sjulian		q->res->rcode = rcode;
54036201Sjulian		q->msg_security = s;
54136201Sjulian		return;
542207141Sjeff	}
543220406Sjeff
544207141Sjeff	q->res->rcode = LDNS_RCODE_SERVFAIL;
54598542Smckusick	q->msg_security = 0;
54636201Sjulian	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
54736201Sjulian	q->msg_len = sldns_buffer_limit(buf);
548223127Smckusick	if(!q->msg) {
54936201Sjulian		return; /* the error is in the rcode */
55036201Sjulian	}
55136201Sjulian
55236201Sjulian	/* canonname and results */
55336201Sjulian	q->msg_security = s;
55436201Sjulian	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
555207141Sjeff}
556207141Sjeff
557207141Sjeffvoid
558207141Sjefflibworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
55936201Sjulian	char* why_bogus)
56036201Sjulian{
56136201Sjulian	struct ctx_query* q = (struct ctx_query*)arg;
562148608Sups	/* fg query is done; exit comm base */
563222958Sjeff	comm_base_exit(q->w->base);
564222958Sjeff
565207141Sjeff	libworker_fillup_fg(q, rcode, buf, s, why_bogus);
566207141Sjeff}
567222958Sjeff
568222958Sjeff/** setup qinfo and edns */
569222958Sjeffstatic int
570222958Sjeffsetup_qinfo_edns(struct libworker* w, struct ctx_query* q,
571222958Sjeff	struct query_info* qinfo, struct edns_data* edns)
572222958Sjeff{
573223772Sjeff	qinfo->qtype = (uint16_t)q->res->qtype;
574222958Sjeff	qinfo->qclass = (uint16_t)q->res->qclass;
575223127Smckusick	qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len);
57698542Smckusick	if(!qinfo->qname) {
577207141Sjeff		return 0;
578222958Sjeff	}
57936201Sjulian	edns->edns_present = 1;
58036201Sjulian	edns->ext_rcode = 0;
58136201Sjulian	edns->edns_version = 0;
582207141Sjeff	edns->bits = EDNS_DO;
583207141Sjeff	if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
584212617Smckusick		edns->udp_size = (uint16_t)sldns_buffer_capacity(
585207141Sjeff			w->back->udp_buff);
586207141Sjeff	else	edns->udp_size = 65535;
587207141Sjeff	return 1;
588207141Sjeff}
589207141Sjeff
590207141Sjeffint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
591212617Smckusick{
592207141Sjeff	struct libworker* w = libworker_setup(ctx, 0, NULL);
593222958Sjeff	uint16_t qflags, qid;
594222958Sjeff	struct query_info qinfo;
595222958Sjeff	struct edns_data edns;
596207141Sjeff	if(!w)
597207141Sjeff		return UB_INITFAIL;
598222958Sjeff	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
599207141Sjeff		libworker_delete(w);
600207141Sjeff		return UB_SYNTAX;
601222958Sjeff	}
602222958Sjeff	qid = 0;
603222958Sjeff	qflags = BIT_RD;
604222958Sjeff	q->w = w;
605207141Sjeff	/* see if there is a fixed answer */
606207141Sjeff	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
607207141Sjeff	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
608207141Sjeff	if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
609207141Sjeff		w->back->udp_buff, w->env->scratch)) {
610207141Sjeff		regional_free_all(w->env->scratch);
611207141Sjeff		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
612207141Sjeff			w->back->udp_buff, sec_status_insecure, NULL);
613207141Sjeff		libworker_delete(w);
614207141Sjeff		free(qinfo.qname);
615212617Smckusick		return UB_NOERROR;
616207141Sjeff	}
617207141Sjeff	/* process new query */
618207141Sjeff	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
619207141Sjeff		w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
62036201Sjulian		free(qinfo.qname);
62136201Sjulian		return UB_NOMEM;
62236201Sjulian	}
62336201Sjulian	free(qinfo.qname);
62436201Sjulian
62536201Sjulian	/* wait for reply */
62636201Sjulian	comm_base_dispatch(w->base);
62736201Sjulian
62836201Sjulian	libworker_delete(w);
62936201Sjulian	return UB_NOERROR;
630207141Sjeff}
63136201Sjulian
63236201Sjulianvoid
63336201Sjulianlibworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
63436201Sjulian	enum sec_status s, char* why_bogus)
63536201Sjulian{
63636201Sjulian	struct ctx_query* q = (struct ctx_query*)arg;
63736201Sjulian	ub_event_callback_t cb = (ub_event_callback_t)q->cb;
63836201Sjulian	void* cb_arg = q->cb_arg;
63936201Sjulian	int cancelled = q->cancelled;
64036201Sjulian
64136201Sjulian	/* delete it now */
64236201Sjulian	struct ub_ctx* ctx = q->w->ctx;
64336201Sjulian	lock_basic_lock(&ctx->cfglock);
64436201Sjulian	(void)rbtree_delete(&ctx->queries, q->node.key);
64536201Sjulian	ctx->num_async--;
64636201Sjulian	context_query_delete(q);
64736201Sjulian	lock_basic_unlock(&ctx->cfglock);
64836201Sjulian
64936201Sjulian	if(!cancelled) {
65036201Sjulian		/* call callback */
65136201Sjulian		int sec = 0;
65236201Sjulian		if(s == sec_status_bogus)
65336201Sjulian			sec = 1;
65436201Sjulian		else if(s == sec_status_secure)
65536201Sjulian			sec = 2;
65636201Sjulian		(*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf),
65736201Sjulian			(int)sldns_buffer_limit(buf), sec, why_bogus);
65836201Sjulian	}
65936201Sjulian}
66036201Sjulian
66136201Sjulianint libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
66236201Sjulian	int* async_id)
663207141Sjeff{
664207141Sjeff	struct libworker* w = ctx->event_worker;
665207141Sjeff	uint16_t qflags, qid;
666207141Sjeff	struct query_info qinfo;
667207141Sjeff	struct edns_data edns;
66836201Sjulian	if(!w)
66936201Sjulian		return UB_INITFAIL;
67036225Sjulian	if(!setup_qinfo_edns(w, q, &qinfo, &edns))
67136201Sjulian		return UB_SYNTAX;
67260938Sjake	qid = 0;
67336201Sjulian	qflags = BIT_RD;
67436201Sjulian	q->w = w;
67536201Sjulian	/* see if there is a fixed answer */
67636201Sjulian	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
67736201Sjulian	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
67836201Sjulian	if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
679207141Sjeff		w->back->udp_buff, w->env->scratch)) {
68036201Sjulian		regional_free_all(w->env->scratch);
681262678Spfg		free(qinfo.qname);
682262678Spfg		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
68336201Sjulian			w->back->udp_buff, sec_status_insecure, NULL);
68436201Sjulian		return UB_NOERROR;
68536201Sjulian	}
68636201Sjulian	/* process new query */
68736201Sjulian	if(async_id)
68836201Sjulian		*async_id = q->querynum;
68936201Sjulian	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
69036201Sjulian		w->back->udp_buff, qid, libworker_event_done_cb, q)) {
69136201Sjulian		free(qinfo.qname);
69236201Sjulian		return UB_NOMEM;
69336201Sjulian	}
69436201Sjulian	free(qinfo.qname);
69536201Sjulian	return UB_NOERROR;
69636201Sjulian}
69736201Sjulian
69836201Sjulian/** add result to the bg worker result queue */
69936201Sjulianstatic void
70036201Sjulianadd_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt,
70136201Sjulian	int err, char* reason)
70236201Sjulian{
70336201Sjulian	uint8_t* msg = NULL;
70436201Sjulian	uint32_t len = 0;
70536201Sjulian
706207141Sjeff	/* serialize and delete unneeded q */
70736201Sjulian	if(w->is_bg_thread) {
70836201Sjulian		lock_basic_lock(&w->ctx->cfglock);
70936201Sjulian		if(reason)
71036201Sjulian			q->res->why_bogus = strdup(reason);
71136201Sjulian		if(pkt) {
712207141Sjeff			q->msg_len = sldns_buffer_remaining(pkt);
71346618Smckusick			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
71460938Sjake			if(!q->msg)
71536201Sjulian				msg = context_serialize_answer(q, UB_NOMEM,
71636201Sjulian				NULL, &len);
71736201Sjulian			else	msg = context_serialize_answer(q, err,
71836201Sjulian				NULL, &len);
71936201Sjulian		} else msg = context_serialize_answer(q, err, NULL, &len);
72036201Sjulian		lock_basic_unlock(&w->ctx->cfglock);
72136201Sjulian	} else {
72236201Sjulian		if(reason)
72336201Sjulian			q->res->why_bogus = strdup(reason);
72436201Sjulian		msg = context_serialize_answer(q, err, pkt, &len);
72536201Sjulian		(void)rbtree_delete(&w->ctx->queries, q->node.key);
72636201Sjulian		w->ctx->num_async--;
72760938Sjake		context_query_delete(q);
728207141Sjeff	}
729207141Sjeff
73036201Sjulian	if(!msg) {
731222958Sjeff		log_err("out of memory for async answer");
73236201Sjulian		return;
73336201Sjulian	}
73436201Sjulian	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
73536201Sjulian		log_err("out of memory for async answer");
736207141Sjeff		return;
73736201Sjulian	}
738262678Spfg}
739262678Spfg
74076724Smckusickvoid
74176724Smckusicklibworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
74276724Smckusick	char* why_bogus)
74376724Smckusick{
74476724Smckusick	struct ctx_query* q = (struct ctx_query*)arg;
74576724Smckusick
74676724Smckusick	if(q->cancelled) {
74776724Smckusick		if(q->w->is_bg_thread) {
74876724Smckusick			/* delete it now */
74976724Smckusick			struct ub_ctx* ctx = q->w->ctx;
75076724Smckusick			lock_basic_lock(&ctx->cfglock);
75176724Smckusick			(void)rbtree_delete(&ctx->queries, q->node.key);
75276724Smckusick			ctx->num_async--;
75376724Smckusick			context_query_delete(q);
75476724Smckusick			lock_basic_unlock(&ctx->cfglock);
75576724Smckusick		}
75676724Smckusick		/* cancelled, do not give answer */
75776724Smckusick		return;
758207141Sjeff	}
759207141Sjeff	q->msg_security = s;
760207141Sjeff	if(!buf)
761207141Sjeff		buf = q->w->env->scratch_buffer;
76276724Smckusick	if(rcode != 0) {
76376724Smckusick		error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
76476724Smckusick	}
765222958Sjeff	add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus);
76676724Smckusick}
767207141Sjeff
76876724Smckusick
769207141Sjeff/** handle new query command for bg worker */
770207141Sjeffstatic void
771207141Sjeffhandle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
772207141Sjeff{
773207141Sjeff	uint16_t qflags, qid;
774207141Sjeff	struct query_info qinfo;
775212617Smckusick	struct edns_data edns;
776207141Sjeff	struct ctx_query* q;
777207141Sjeff	if(w->is_bg_thread) {
778212617Smckusick		lock_basic_lock(&w->ctx->cfglock);
779207141Sjeff		q = context_lookup_new_query(w->ctx, buf, len);
780207141Sjeff		lock_basic_unlock(&w->ctx->cfglock);
781207141Sjeff	} else {
782207141Sjeff		q = context_deserialize_new_query(w->ctx, buf, len);
783207141Sjeff	}
784207141Sjeff	free(buf);
785207141Sjeff	if(!q) {
786207141Sjeff		log_err("failed to deserialize newq");
787207141Sjeff		return;
788207141Sjeff	}
789207141Sjeff	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
790207141Sjeff		add_bg_result(w, q, NULL, UB_SYNTAX, NULL);
791207141Sjeff		return;
792207141Sjeff	}
793207141Sjeff	qid = 0;
794207141Sjeff	qflags = BIT_RD;
795207141Sjeff	/* see if there is a fixed answer */
796207141Sjeff	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
797207141Sjeff	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
798207141Sjeff	if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns,
799207141Sjeff		w->back->udp_buff, w->env->scratch)) {
800207141Sjeff		regional_free_all(w->env->scratch);
801212617Smckusick		q->msg_security = sec_status_insecure;
802212617Smckusick		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
803207141Sjeff		free(qinfo.qname);
804207141Sjeff		return;
805207141Sjeff	}
806207141Sjeff	q->w = w;
807207141Sjeff	/* process new query */
808207141Sjeff	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
809207141Sjeff		w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
810207141Sjeff		add_bg_result(w, q, NULL, UB_NOMEM, NULL);
811207141Sjeff	}
812207141Sjeff	free(qinfo.qname);
813207141Sjeff}
814207141Sjeff
815207141Sjeffvoid libworker_alloc_cleanup(void* arg)
816207141Sjeff{
817207141Sjeff	struct libworker* w = (struct libworker*)arg;
818207141Sjeff	slabhash_clear(&w->env->rrset_cache->table);
819207141Sjeff        slabhash_clear(w->env->msg_cache);
820207141Sjeff}
821207141Sjeff
822207141Sjeffstruct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
823207141Sjeff        uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
824212617Smckusick	int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
825212617Smckusick	uint8_t* zone, size_t zonelen, struct module_qstate* q)
826207141Sjeff{
827212617Smckusick	struct libworker* w = (struct libworker*)q->env->worker;
828207141Sjeff	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
829207141Sjeff		q->region, sizeof(*e));
830207141Sjeff	if(!e)
831212617Smckusick		return NULL;
832212617Smckusick	e->qstate = q;
833212617Smckusick	e->qsent = outnet_serviced_query(w->back, qname,
834212617Smckusick		qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
835212617Smckusick		q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
836212617Smckusick		addrlen, zone, zonelen, libworker_handle_service_reply, e,
837212617Smckusick		w->back->udp_buff);
838207141Sjeff	if(!e->qsent) {
839212617Smckusick		return NULL;
840212617Smckusick	}
841212617Smckusick	return e;
842212617Smckusick}
843212617Smckusick
844212617Smckusickint
845212617Smckusicklibworker_handle_reply(struct comm_point* c, void* arg, int error,
846207141Sjeff        struct comm_reply* reply_info)
847207141Sjeff{
848207141Sjeff	struct module_qstate* q = (struct module_qstate*)arg;
849207141Sjeff	struct libworker* lw = (struct libworker*)q->env->worker;
850207141Sjeff	struct outbound_entry e;
851207141Sjeff	e.qstate = q;
852207141Sjeff	e.qsent = NULL;
853207141Sjeff
854207141Sjeff	if(error != 0) {
855207141Sjeff		mesh_report_reply(lw->env->mesh, &e, reply_info, error);
856207141Sjeff		return 0;
857212617Smckusick	}
858212617Smckusick	/* sanity check. */
859207141Sjeff	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
860207141Sjeff		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
861212617Smckusick			LDNS_PACKET_QUERY
862207141Sjeff		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
863212617Smckusick		/* error becomes timeout for the module as if this reply
864212617Smckusick		 * never arrived. */
865220406Sjeff		mesh_report_reply(lw->env->mesh, &e, reply_info,
866212617Smckusick			NETEVENT_TIMEOUT);
867212617Smckusick		return 0;
868222958Sjeff	}
869212617Smckusick	mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
870212617Smckusick	return 0;
871207141Sjeff}
872207141Sjeff
873207141Sjeffint
874222958Sjefflibworker_handle_service_reply(struct comm_point* c, void* arg, int error,
875222958Sjeff        struct comm_reply* reply_info)
876222958Sjeff{
877222958Sjeff	struct outbound_entry* e = (struct outbound_entry*)arg;
878222958Sjeff	struct libworker* lw = (struct libworker*)e->qstate->env->worker;
879222958Sjeff
880222958Sjeff	if(error != 0) {
881222958Sjeff		mesh_report_reply(lw->env->mesh, e, reply_info, error);
882222958Sjeff		return 0;
883222958Sjeff	}
884222958Sjeff	/* sanity check. */
885222958Sjeff	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
886207141Sjeff		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
887207141Sjeff			LDNS_PACKET_QUERY
888212617Smckusick		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
889207141Sjeff		/* error becomes timeout for the module as if this reply
890207141Sjeff		 * never arrived. */
891222958Sjeff		mesh_report_reply(lw->env->mesh, e, reply_info,
892212617Smckusick			NETEVENT_TIMEOUT);
893212617Smckusick		return 0;
894222958Sjeff	}
895212617Smckusick	mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
896207141Sjeff	return 0;
897207141Sjeff}
898207141Sjeff
899207141Sjeff/* --- fake callbacks for fptr_wlist to work --- */
900207141Sjeffvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
901207141Sjeff	uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
902207141Sjeff	int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
903207141Sjeff{
904212617Smckusick	log_assert(0);
905207141Sjeff}
906212617Smckusick
907212617Smckusickint worker_handle_request(struct comm_point* ATTR_UNUSED(c),
908212617Smckusick	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
909212617Smckusick        struct comm_reply* ATTR_UNUSED(repinfo))
910222958Sjeff{
911212617Smckusick	log_assert(0);
912207141Sjeff	return 0;
913207141Sjeff}
914207141Sjeff
915222958Sjeffint worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
916207141Sjeff	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
917207141Sjeff        struct comm_reply* ATTR_UNUSED(reply_info))
918222958Sjeff{
919222958Sjeff	log_assert(0);
920222958Sjeff	return 0;
921222958Sjeff}
922207141Sjeff
923207141Sjeffint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
924207141Sjeff	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
925222958Sjeff        struct comm_reply* ATTR_UNUSED(reply_info))
926222958Sjeff{
927222958Sjeff	log_assert(0);
928222958Sjeff	return 0;
929222958Sjeff}
930222958Sjeff
931222958Sjeffint remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
932222958Sjeff	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
933222958Sjeff        struct comm_reply* ATTR_UNUSED(repinfo))
934222958Sjeff{
935222958Sjeff	log_assert(0);
936207141Sjeff	return 0;
937207141Sjeff}
938212617Smckusick
939212617Smckusickint remote_control_callback(struct comm_point* ATTR_UNUSED(c),
940207141Sjeff	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
941207141Sjeff        struct comm_reply* ATTR_UNUSED(repinfo))
942212617Smckusick{
943207141Sjeff	log_assert(0);
944212617Smckusick	return 0;
945207141Sjeff}
946207141Sjeff
947207141Sjeffvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
948207141Sjeff{
949212617Smckusick	log_assert(0);
950207141Sjeff}
951212617Smckusick
952212617Smckusickstruct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
953212617Smckusick	size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
954212617Smckusick	uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
955207141Sjeff	int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
956207141Sjeff	struct sockaddr_storage* ATTR_UNUSED(addr),
957207141Sjeff	socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
958207141Sjeff	size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
959207141Sjeff{
960220511Sjeff	log_assert(0);
961212617Smckusick	return 0;
962207141Sjeff}
963207141Sjeff
964212617Smckusickvoid
965220511Sjeffworker_alloc_cleanup(void* ATTR_UNUSED(arg))
966212617Smckusick{
967212617Smckusick	log_assert(0);
968212617Smckusick}
969207141Sjeff
970207141Sjeffvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg))
971207141Sjeff{
972207141Sjeff	log_assert(0);
973207141Sjeff}
974207141Sjeff
975207141Sjeffvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg))
976212617Smckusick{
977212617Smckusick	log_assert(0);
978207141Sjeff}
979207141Sjeff
980207141Sjeffvoid worker_start_accept(void* ATTR_UNUSED(arg))
981207141Sjeff{
982212617Smckusick	log_assert(0);
983207141Sjeff}
984256817Smckusick
985256817Smckusickvoid worker_stop_accept(void* ATTR_UNUSED(arg))
986256817Smckusick{
987256817Smckusick	log_assert(0);
988256817Smckusick}
989256817Smckusick
990256817Smckusickint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
991256817Smckusick{
992256817Smckusick	log_assert(0);
993256817Smckusick	return 0;
994256817Smckusick}
995256817Smckusick
996256817Smckusickint
997256817Smckusickcodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
998256817Smckusick{
999256817Smckusick	log_assert(0);
1000256817Smckusick	return 0;
1001256817Smckusick}
1002256817Smckusick
1003256817Smckusickint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1004256817Smckusick{
1005256817Smckusick        log_assert(0);
1006256817Smckusick        return 0;
1007256817Smckusick}
1008256817Smckusick
1009256817Smckusickvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
1010256817Smckusick{
1011256817Smckusick        log_assert(0);
1012256817Smckusick}
1013256817Smckusick
1014256817Smckusick#ifdef UB_ON_WINDOWS
1015256817Smckusickvoid
1016256817Smckusickworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
1017256817Smckusick        ATTR_UNUSED(arg)) {
1018256817Smckusick        log_assert(0);
1019256817Smckusick}
1020256817Smckusick
1021256817Smckusickvoid
1022256817Smckusickwsvc_cron_cb(void* ATTR_UNUSED(arg))
1023256817Smckusick{
1024256817Smckusick        log_assert(0);
1025256817Smckusick}
1026256817Smckusick#endif /* UB_ON_WINDOWS */
1027256817Smckusick