xref: /minix3/external/bsd/bind/dist/lib/dns/client.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: client.c,v 1.10 2015/07/08 17:28:58 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2009-2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek  *
10*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek  */
18*00b67f09SDavid van Moolenbroek 
19*00b67f09SDavid van Moolenbroek /* Id: client.c,v 1.14 2011/03/12 04:59:47 tbox Exp  */
20*00b67f09SDavid van Moolenbroek 
21*00b67f09SDavid van Moolenbroek #include <config.h>
22*00b67f09SDavid van Moolenbroek 
23*00b67f09SDavid van Moolenbroek #include <stddef.h>
24*00b67f09SDavid van Moolenbroek 
25*00b67f09SDavid van Moolenbroek #include <isc/app.h>
26*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
27*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
28*00b67f09SDavid van Moolenbroek #include <isc/mutex.h>
29*00b67f09SDavid van Moolenbroek #include <isc/sockaddr.h>
30*00b67f09SDavid van Moolenbroek #include <isc/socket.h>
31*00b67f09SDavid van Moolenbroek #include <isc/task.h>
32*00b67f09SDavid van Moolenbroek #include <isc/timer.h>
33*00b67f09SDavid van Moolenbroek #include <isc/util.h>
34*00b67f09SDavid van Moolenbroek 
35*00b67f09SDavid van Moolenbroek #include <dns/adb.h>
36*00b67f09SDavid van Moolenbroek #include <dns/client.h>
37*00b67f09SDavid van Moolenbroek #include <dns/db.h>
38*00b67f09SDavid van Moolenbroek #include <dns/dispatch.h>
39*00b67f09SDavid van Moolenbroek #include <dns/events.h>
40*00b67f09SDavid van Moolenbroek #include <dns/forward.h>
41*00b67f09SDavid van Moolenbroek #include <dns/keytable.h>
42*00b67f09SDavid van Moolenbroek #include <dns/message.h>
43*00b67f09SDavid van Moolenbroek #include <dns/name.h>
44*00b67f09SDavid van Moolenbroek #include <dns/rdata.h>
45*00b67f09SDavid van Moolenbroek #include <dns/rdatalist.h>
46*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
47*00b67f09SDavid van Moolenbroek #include <dns/rdatatype.h>
48*00b67f09SDavid van Moolenbroek #include <dns/rdatasetiter.h>
49*00b67f09SDavid van Moolenbroek #include <dns/rdatastruct.h>
50*00b67f09SDavid van Moolenbroek #include <dns/request.h>
51*00b67f09SDavid van Moolenbroek #include <dns/resolver.h>
52*00b67f09SDavid van Moolenbroek #include <dns/result.h>
53*00b67f09SDavid van Moolenbroek #include <dns/tsec.h>
54*00b67f09SDavid van Moolenbroek #include <dns/tsig.h>
55*00b67f09SDavid van Moolenbroek #include <dns/view.h>
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek #include <dst/dst.h>
58*00b67f09SDavid van Moolenbroek 
59*00b67f09SDavid van Moolenbroek #define DNS_CLIENT_MAGIC		ISC_MAGIC('D', 'N', 'S', 'c')
60*00b67f09SDavid van Moolenbroek #define DNS_CLIENT_VALID(c)		ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
61*00b67f09SDavid van Moolenbroek 
62*00b67f09SDavid van Moolenbroek #define RCTX_MAGIC			ISC_MAGIC('R', 'c', 't', 'x')
63*00b67f09SDavid van Moolenbroek #define RCTX_VALID(c)			ISC_MAGIC_VALID(c, RCTX_MAGIC)
64*00b67f09SDavid van Moolenbroek 
65*00b67f09SDavid van Moolenbroek #define REQCTX_MAGIC			ISC_MAGIC('R', 'q', 'c', 'x')
66*00b67f09SDavid van Moolenbroek #define REQCTX_VALID(c)			ISC_MAGIC_VALID(c, REQCTX_MAGIC)
67*00b67f09SDavid van Moolenbroek 
68*00b67f09SDavid van Moolenbroek #define UCTX_MAGIC			ISC_MAGIC('U', 'c', 't', 'x')
69*00b67f09SDavid van Moolenbroek #define UCTX_VALID(c)			ISC_MAGIC_VALID(c, UCTX_MAGIC)
70*00b67f09SDavid van Moolenbroek 
71*00b67f09SDavid van Moolenbroek #define MAX_RESTARTS 16
72*00b67f09SDavid van Moolenbroek 
73*00b67f09SDavid van Moolenbroek #ifdef TUNE_LARGE
74*00b67f09SDavid van Moolenbroek #define RESOLVER_NTASKS 523
75*00b67f09SDavid van Moolenbroek #else
76*00b67f09SDavid van Moolenbroek #define RESOLVER_NTASKS 31
77*00b67f09SDavid van Moolenbroek #endif /* TUNE_LARGE */
78*00b67f09SDavid van Moolenbroek 
79*00b67f09SDavid van Moolenbroek /*%
80*00b67f09SDavid van Moolenbroek  * DNS client object
81*00b67f09SDavid van Moolenbroek  */
82*00b67f09SDavid van Moolenbroek struct dns_client {
83*00b67f09SDavid van Moolenbroek 	/* Unlocked */
84*00b67f09SDavid van Moolenbroek 	unsigned int			magic;
85*00b67f09SDavid van Moolenbroek 	unsigned int			attributes;
86*00b67f09SDavid van Moolenbroek 	isc_mutex_t			lock;
87*00b67f09SDavid van Moolenbroek 	isc_mem_t			*mctx;
88*00b67f09SDavid van Moolenbroek 	isc_appctx_t			*actx;
89*00b67f09SDavid van Moolenbroek 	isc_taskmgr_t			*taskmgr;
90*00b67f09SDavid van Moolenbroek 	isc_task_t			*task;
91*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t			*socketmgr;
92*00b67f09SDavid van Moolenbroek 	isc_timermgr_t			*timermgr;
93*00b67f09SDavid van Moolenbroek 	dns_dispatchmgr_t		*dispatchmgr;
94*00b67f09SDavid van Moolenbroek 	dns_dispatch_t			*dispatchv4;
95*00b67f09SDavid van Moolenbroek 	dns_dispatch_t			*dispatchv6;
96*00b67f09SDavid van Moolenbroek 
97*00b67f09SDavid van Moolenbroek 	unsigned int			update_timeout;
98*00b67f09SDavid van Moolenbroek 	unsigned int			update_udptimeout;
99*00b67f09SDavid van Moolenbroek 	unsigned int			update_udpretries;
100*00b67f09SDavid van Moolenbroek 	unsigned int			find_timeout;
101*00b67f09SDavid van Moolenbroek 	unsigned int			find_udpretries;
102*00b67f09SDavid van Moolenbroek 
103*00b67f09SDavid van Moolenbroek 	/* Locked */
104*00b67f09SDavid van Moolenbroek 	unsigned int			references;
105*00b67f09SDavid van Moolenbroek 	dns_viewlist_t			viewlist;
106*00b67f09SDavid van Moolenbroek 	ISC_LIST(struct resctx)		resctxs;
107*00b67f09SDavid van Moolenbroek 	ISC_LIST(struct reqctx)		reqctxs;
108*00b67f09SDavid van Moolenbroek 	ISC_LIST(struct updatectx)	updatectxs;
109*00b67f09SDavid van Moolenbroek };
110*00b67f09SDavid van Moolenbroek 
111*00b67f09SDavid van Moolenbroek /*%
112*00b67f09SDavid van Moolenbroek  * Timeout/retry constants for dynamic update borrowed from nsupdate
113*00b67f09SDavid van Moolenbroek  */
114*00b67f09SDavid van Moolenbroek #define DEF_UPDATE_TIMEOUT	300
115*00b67f09SDavid van Moolenbroek #define MIN_UPDATE_TIMEOUT	30
116*00b67f09SDavid van Moolenbroek #define DEF_UPDATE_UDPTIMEOUT	3
117*00b67f09SDavid van Moolenbroek #define DEF_UPDATE_UDPRETRIES	3
118*00b67f09SDavid van Moolenbroek 
119*00b67f09SDavid van Moolenbroek #define DEF_FIND_TIMEOUT	5
120*00b67f09SDavid van Moolenbroek #define DEF_FIND_UDPRETRIES	3
121*00b67f09SDavid van Moolenbroek 
122*00b67f09SDavid van Moolenbroek #define DNS_CLIENTATTR_OWNCTX			0x01
123*00b67f09SDavid van Moolenbroek 
124*00b67f09SDavid van Moolenbroek #define DNS_CLIENTVIEW_NAME			"dnsclient"
125*00b67f09SDavid van Moolenbroek 
126*00b67f09SDavid van Moolenbroek /*%
127*00b67f09SDavid van Moolenbroek  * Internal state for a single name resolution procedure
128*00b67f09SDavid van Moolenbroek  */
129*00b67f09SDavid van Moolenbroek typedef struct resctx {
130*00b67f09SDavid van Moolenbroek 	/* Unlocked */
131*00b67f09SDavid van Moolenbroek 	unsigned int		magic;
132*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
133*00b67f09SDavid van Moolenbroek 	dns_client_t		*client;
134*00b67f09SDavid van Moolenbroek 	isc_boolean_t		want_dnssec;
135*00b67f09SDavid van Moolenbroek 	isc_boolean_t		want_validation;
136*00b67f09SDavid van Moolenbroek 	isc_boolean_t		want_cdflag;
137*00b67f09SDavid van Moolenbroek 
138*00b67f09SDavid van Moolenbroek 	/* Locked */
139*00b67f09SDavid van Moolenbroek 	ISC_LINK(struct resctx)	link;
140*00b67f09SDavid van Moolenbroek 	isc_task_t		*task;
141*00b67f09SDavid van Moolenbroek 	dns_view_t		*view;
142*00b67f09SDavid van Moolenbroek 	unsigned int		restarts;
143*00b67f09SDavid van Moolenbroek 	dns_fixedname_t		name;
144*00b67f09SDavid van Moolenbroek 	dns_rdatatype_t		type;
145*00b67f09SDavid van Moolenbroek 	dns_fetch_t		*fetch;
146*00b67f09SDavid van Moolenbroek 	dns_namelist_t		namelist;
147*00b67f09SDavid van Moolenbroek 	isc_result_t		result;
148*00b67f09SDavid van Moolenbroek 	dns_clientresevent_t	*event;
149*00b67f09SDavid van Moolenbroek 	isc_boolean_t		canceled;
150*00b67f09SDavid van Moolenbroek 	dns_rdataset_t		*rdataset;
151*00b67f09SDavid van Moolenbroek 	dns_rdataset_t		*sigrdataset;
152*00b67f09SDavid van Moolenbroek } resctx_t;
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek /*%
155*00b67f09SDavid van Moolenbroek  * Argument of an internal event for synchronous name resolution.
156*00b67f09SDavid van Moolenbroek  */
157*00b67f09SDavid van Moolenbroek typedef struct resarg {
158*00b67f09SDavid van Moolenbroek 	/* Unlocked */
159*00b67f09SDavid van Moolenbroek 	isc_appctx_t		*actx;
160*00b67f09SDavid van Moolenbroek 	dns_client_t		*client;
161*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
162*00b67f09SDavid van Moolenbroek 
163*00b67f09SDavid van Moolenbroek 	/* Locked */
164*00b67f09SDavid van Moolenbroek 	isc_result_t		result;
165*00b67f09SDavid van Moolenbroek 	isc_result_t		vresult;
166*00b67f09SDavid van Moolenbroek 	dns_namelist_t		*namelist;
167*00b67f09SDavid van Moolenbroek 	dns_clientrestrans_t	*trans;
168*00b67f09SDavid van Moolenbroek 	isc_boolean_t		canceled;
169*00b67f09SDavid van Moolenbroek } resarg_t;
170*00b67f09SDavid van Moolenbroek 
171*00b67f09SDavid van Moolenbroek /*%
172*00b67f09SDavid van Moolenbroek  * Internal state for a single DNS request
173*00b67f09SDavid van Moolenbroek  */
174*00b67f09SDavid van Moolenbroek typedef struct reqctx {
175*00b67f09SDavid van Moolenbroek 	/* Unlocked */
176*00b67f09SDavid van Moolenbroek 	unsigned int		magic;
177*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
178*00b67f09SDavid van Moolenbroek 	dns_client_t		*client;
179*00b67f09SDavid van Moolenbroek 	unsigned int		parseoptions;
180*00b67f09SDavid van Moolenbroek 
181*00b67f09SDavid van Moolenbroek 	/* Locked */
182*00b67f09SDavid van Moolenbroek 	ISC_LINK(struct reqctx)	link;
183*00b67f09SDavid van Moolenbroek 	isc_boolean_t		canceled;
184*00b67f09SDavid van Moolenbroek 	dns_tsigkey_t		*tsigkey;
185*00b67f09SDavid van Moolenbroek 	dns_request_t		*request;
186*00b67f09SDavid van Moolenbroek 	dns_clientreqevent_t	*event;
187*00b67f09SDavid van Moolenbroek } reqctx_t;
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek /*%
190*00b67f09SDavid van Moolenbroek  * Argument of an internal event for synchronous DNS request.
191*00b67f09SDavid van Moolenbroek  */
192*00b67f09SDavid van Moolenbroek typedef struct reqarg {
193*00b67f09SDavid van Moolenbroek 	/* Unlocked */
194*00b67f09SDavid van Moolenbroek 	isc_appctx_t		*actx;
195*00b67f09SDavid van Moolenbroek 	dns_client_t		*client;
196*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
197*00b67f09SDavid van Moolenbroek 
198*00b67f09SDavid van Moolenbroek 	/* Locked */
199*00b67f09SDavid van Moolenbroek 	isc_result_t		result;
200*00b67f09SDavid van Moolenbroek 	dns_clientreqtrans_t	*trans;
201*00b67f09SDavid van Moolenbroek 	isc_boolean_t		canceled;
202*00b67f09SDavid van Moolenbroek } reqarg_t;
203*00b67f09SDavid van Moolenbroek 
204*00b67f09SDavid van Moolenbroek /*%
205*00b67f09SDavid van Moolenbroek  * Argument of an internal event for synchronous name resolution.
206*00b67f09SDavid van Moolenbroek  */
207*00b67f09SDavid van Moolenbroek typedef struct updatearg {
208*00b67f09SDavid van Moolenbroek 	/* Unlocked */
209*00b67f09SDavid van Moolenbroek 	isc_appctx_t		*actx;
210*00b67f09SDavid van Moolenbroek 	dns_client_t		*client;
211*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
212*00b67f09SDavid van Moolenbroek 
213*00b67f09SDavid van Moolenbroek 	/* Locked */
214*00b67f09SDavid van Moolenbroek 	isc_result_t		result;
215*00b67f09SDavid van Moolenbroek 	dns_clientupdatetrans_t	*trans;
216*00b67f09SDavid van Moolenbroek 	isc_boolean_t		canceled;
217*00b67f09SDavid van Moolenbroek } updatearg_t;
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek /*%
220*00b67f09SDavid van Moolenbroek  * Internal state for a single dynamic update procedure
221*00b67f09SDavid van Moolenbroek  */
222*00b67f09SDavid van Moolenbroek typedef struct updatectx {
223*00b67f09SDavid van Moolenbroek 	/* Unlocked */
224*00b67f09SDavid van Moolenbroek 	unsigned int			magic;
225*00b67f09SDavid van Moolenbroek 	isc_mutex_t			lock;
226*00b67f09SDavid van Moolenbroek 	dns_client_t			*client;
227*00b67f09SDavid van Moolenbroek 
228*00b67f09SDavid van Moolenbroek 	/* Locked */
229*00b67f09SDavid van Moolenbroek 	dns_request_t			*updatereq;
230*00b67f09SDavid van Moolenbroek 	dns_request_t			*soareq;
231*00b67f09SDavid van Moolenbroek 	dns_clientrestrans_t		*restrans;
232*00b67f09SDavid van Moolenbroek 	dns_clientrestrans_t		*restrans2;
233*00b67f09SDavid van Moolenbroek 	isc_boolean_t			canceled;
234*00b67f09SDavid van Moolenbroek 
235*00b67f09SDavid van Moolenbroek 	/* Task Locked */
236*00b67f09SDavid van Moolenbroek 	ISC_LINK(struct updatectx) 	link;
237*00b67f09SDavid van Moolenbroek 	dns_clientupdatestate_t		state;
238*00b67f09SDavid van Moolenbroek 	dns_rdataclass_t		rdclass;
239*00b67f09SDavid van Moolenbroek 	dns_view_t			*view;
240*00b67f09SDavid van Moolenbroek 	dns_message_t			*updatemsg;
241*00b67f09SDavid van Moolenbroek 	dns_message_t			*soaquery;
242*00b67f09SDavid van Moolenbroek 	dns_clientupdateevent_t		*event;
243*00b67f09SDavid van Moolenbroek 	dns_tsigkey_t			*tsigkey;
244*00b67f09SDavid van Moolenbroek 	dst_key_t			*sig0key;
245*00b67f09SDavid van Moolenbroek 	dns_name_t			*firstname;
246*00b67f09SDavid van Moolenbroek 	dns_name_t			soaqname;
247*00b67f09SDavid van Moolenbroek 	dns_fixedname_t			zonefname;
248*00b67f09SDavid van Moolenbroek 	dns_name_t			*zonename;
249*00b67f09SDavid van Moolenbroek 	isc_sockaddrlist_t		servers;
250*00b67f09SDavid van Moolenbroek 	unsigned int			nservers;
251*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t			*currentserver;
252*00b67f09SDavid van Moolenbroek 	struct updatectx		*bp4;
253*00b67f09SDavid van Moolenbroek 	struct updatectx		*bp6;
254*00b67f09SDavid van Moolenbroek } updatectx_t;
255*00b67f09SDavid van Moolenbroek 
256*00b67f09SDavid van Moolenbroek static isc_result_t request_soa(updatectx_t *uctx);
257*00b67f09SDavid van Moolenbroek static void client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
258*00b67f09SDavid van Moolenbroek static isc_result_t send_update(updatectx_t *uctx);
259*00b67f09SDavid van Moolenbroek 
260*00b67f09SDavid van Moolenbroek static isc_result_t
getudpdispatch(int family,dns_dispatchmgr_t * dispatchmgr,isc_socketmgr_t * socketmgr,isc_taskmgr_t * taskmgr,isc_boolean_t is_shared,dns_dispatch_t ** dispp,isc_sockaddr_t * localaddr)261*00b67f09SDavid van Moolenbroek getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
262*00b67f09SDavid van Moolenbroek 	       isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
263*00b67f09SDavid van Moolenbroek 	       isc_boolean_t is_shared, dns_dispatch_t **dispp,
264*00b67f09SDavid van Moolenbroek 	       isc_sockaddr_t *localaddr)
265*00b67f09SDavid van Moolenbroek {
266*00b67f09SDavid van Moolenbroek 	unsigned int attrs, attrmask;
267*00b67f09SDavid van Moolenbroek 	dns_dispatch_t *disp;
268*00b67f09SDavid van Moolenbroek 	unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
269*00b67f09SDavid van Moolenbroek 	isc_result_t result;
270*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t anyaddr;
271*00b67f09SDavid van Moolenbroek 
272*00b67f09SDavid van Moolenbroek 	attrs = 0;
273*00b67f09SDavid van Moolenbroek 	attrs |= DNS_DISPATCHATTR_UDP;
274*00b67f09SDavid van Moolenbroek 	switch (family) {
275*00b67f09SDavid van Moolenbroek 	case AF_INET:
276*00b67f09SDavid van Moolenbroek 		attrs |= DNS_DISPATCHATTR_IPV4;
277*00b67f09SDavid van Moolenbroek 		break;
278*00b67f09SDavid van Moolenbroek 	case AF_INET6:
279*00b67f09SDavid van Moolenbroek 		attrs |= DNS_DISPATCHATTR_IPV6;
280*00b67f09SDavid van Moolenbroek 		break;
281*00b67f09SDavid van Moolenbroek 	default:
282*00b67f09SDavid van Moolenbroek 		INSIST(0);
283*00b67f09SDavid van Moolenbroek 	}
284*00b67f09SDavid van Moolenbroek 	attrmask = 0;
285*00b67f09SDavid van Moolenbroek 	attrmask |= DNS_DISPATCHATTR_UDP;
286*00b67f09SDavid van Moolenbroek 	attrmask |= DNS_DISPATCHATTR_TCP;
287*00b67f09SDavid van Moolenbroek 	attrmask |= DNS_DISPATCHATTR_IPV4;
288*00b67f09SDavid van Moolenbroek 	attrmask |= DNS_DISPATCHATTR_IPV6;
289*00b67f09SDavid van Moolenbroek 
290*00b67f09SDavid van Moolenbroek 	if (localaddr == NULL) {
291*00b67f09SDavid van Moolenbroek 		localaddr = &anyaddr;
292*00b67f09SDavid van Moolenbroek 		isc_sockaddr_anyofpf(localaddr, family);
293*00b67f09SDavid van Moolenbroek 	}
294*00b67f09SDavid van Moolenbroek 
295*00b67f09SDavid van Moolenbroek 	buffersize = 4096;
296*00b67f09SDavid van Moolenbroek 	maxbuffers = is_shared ? 1000 : 8;
297*00b67f09SDavid van Moolenbroek 	maxrequests = 32768;
298*00b67f09SDavid van Moolenbroek 	buckets = is_shared ? 16411 : 3;
299*00b67f09SDavid van Moolenbroek 	increment = is_shared ? 16433 : 5;
300*00b67f09SDavid van Moolenbroek 
301*00b67f09SDavid van Moolenbroek 	disp = NULL;
302*00b67f09SDavid van Moolenbroek 	result = dns_dispatch_getudp(dispatchmgr, socketmgr,
303*00b67f09SDavid van Moolenbroek 				     taskmgr, localaddr,
304*00b67f09SDavid van Moolenbroek 				     buffersize, maxbuffers, maxrequests,
305*00b67f09SDavid van Moolenbroek 				     buckets, increment,
306*00b67f09SDavid van Moolenbroek 				     attrs, attrmask, &disp);
307*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS)
308*00b67f09SDavid van Moolenbroek 		*dispp = disp;
309*00b67f09SDavid van Moolenbroek 
310*00b67f09SDavid van Moolenbroek 	return (result);
311*00b67f09SDavid van Moolenbroek }
312*00b67f09SDavid van Moolenbroek 
313*00b67f09SDavid van Moolenbroek static isc_result_t
createview(isc_mem_t * mctx,dns_rdataclass_t rdclass,unsigned int options,isc_taskmgr_t * taskmgr,unsigned int ntasks,isc_socketmgr_t * socketmgr,isc_timermgr_t * timermgr,dns_dispatchmgr_t * dispatchmgr,dns_dispatch_t * dispatchv4,dns_dispatch_t * dispatchv6,dns_view_t ** viewp)314*00b67f09SDavid van Moolenbroek createview(isc_mem_t *mctx, dns_rdataclass_t rdclass,
315*00b67f09SDavid van Moolenbroek 	   unsigned int options, isc_taskmgr_t *taskmgr,
316*00b67f09SDavid van Moolenbroek 	   unsigned int ntasks, isc_socketmgr_t *socketmgr,
317*00b67f09SDavid van Moolenbroek 	   isc_timermgr_t *timermgr, dns_dispatchmgr_t *dispatchmgr,
318*00b67f09SDavid van Moolenbroek 	   dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
319*00b67f09SDavid van Moolenbroek 	   dns_view_t **viewp)
320*00b67f09SDavid van Moolenbroek {
321*00b67f09SDavid van Moolenbroek 	isc_result_t result;
322*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
323*00b67f09SDavid van Moolenbroek 	const char *dbtype;
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek 	result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
326*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
327*00b67f09SDavid van Moolenbroek 		return (result);
328*00b67f09SDavid van Moolenbroek 
329*00b67f09SDavid van Moolenbroek 	/* Initialize view security roots */
330*00b67f09SDavid van Moolenbroek 	result = dns_view_initsecroots(view, mctx);
331*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
332*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
333*00b67f09SDavid van Moolenbroek 		return (result);
334*00b67f09SDavid van Moolenbroek 	}
335*00b67f09SDavid van Moolenbroek 
336*00b67f09SDavid van Moolenbroek 	result = dns_view_createresolver(view, taskmgr, ntasks, 1,
337*00b67f09SDavid van Moolenbroek 					 socketmgr, timermgr, 0,
338*00b67f09SDavid van Moolenbroek 					 dispatchmgr, dispatchv4, dispatchv6);
339*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
340*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
341*00b67f09SDavid van Moolenbroek 		return (result);
342*00b67f09SDavid van Moolenbroek 	}
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek 	/*
345*00b67f09SDavid van Moolenbroek 	 * Set cache DB.
346*00b67f09SDavid van Moolenbroek 	 * XXX: it may be better if specific DB implementations can be
347*00b67f09SDavid van Moolenbroek 	 * specified via some configuration knob.
348*00b67f09SDavid van Moolenbroek 	 */
349*00b67f09SDavid van Moolenbroek 	if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0)
350*00b67f09SDavid van Moolenbroek 		dbtype = "rbt";
351*00b67f09SDavid van Moolenbroek 	else
352*00b67f09SDavid van Moolenbroek 		dbtype = "ecdb";
353*00b67f09SDavid van Moolenbroek 	result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
354*00b67f09SDavid van Moolenbroek 			       rdclass, 0, NULL, &view->cachedb);
355*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
356*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
357*00b67f09SDavid van Moolenbroek 		return (result);
358*00b67f09SDavid van Moolenbroek 	}
359*00b67f09SDavid van Moolenbroek 
360*00b67f09SDavid van Moolenbroek 	*viewp = view;
361*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
362*00b67f09SDavid van Moolenbroek }
363*00b67f09SDavid van Moolenbroek 
364*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_create(dns_client_t ** clientp,unsigned int options)365*00b67f09SDavid van Moolenbroek dns_client_create(dns_client_t **clientp, unsigned int options) {
366*00b67f09SDavid van Moolenbroek 	isc_result_t result;
367*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx = NULL;
368*00b67f09SDavid van Moolenbroek 	isc_appctx_t *actx = NULL;
369*00b67f09SDavid van Moolenbroek 	isc_taskmgr_t *taskmgr = NULL;
370*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *socketmgr = NULL;
371*00b67f09SDavid van Moolenbroek 	isc_timermgr_t *timermgr = NULL;
372*00b67f09SDavid van Moolenbroek #if 0
373*00b67f09SDavid van Moolenbroek 	/* XXXMPA add debug logging support */
374*00b67f09SDavid van Moolenbroek 	isc_log_t *lctx = NULL;
375*00b67f09SDavid van Moolenbroek 	isc_logconfig_t *logconfig = NULL;
376*00b67f09SDavid van Moolenbroek 	unsigned int logdebuglevel = 0;
377*00b67f09SDavid van Moolenbroek #endif
378*00b67f09SDavid van Moolenbroek 
379*00b67f09SDavid van Moolenbroek 	result = isc_mem_create(0, 0, &mctx);
380*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
381*00b67f09SDavid van Moolenbroek 		return (result);
382*00b67f09SDavid van Moolenbroek 	result = isc_appctx_create(mctx, &actx);
383*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
384*00b67f09SDavid van Moolenbroek 		goto cleanup;
385*00b67f09SDavid van Moolenbroek 	result = isc_app_ctxstart(actx);
386*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
387*00b67f09SDavid van Moolenbroek 		goto cleanup;
388*00b67f09SDavid van Moolenbroek 	result = isc_taskmgr_createinctx(mctx, actx, 1, 0, &taskmgr);
389*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
390*00b67f09SDavid van Moolenbroek 		goto cleanup;
391*00b67f09SDavid van Moolenbroek 	result = isc_socketmgr_createinctx(mctx, actx, &socketmgr);
392*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
393*00b67f09SDavid van Moolenbroek 		goto cleanup;
394*00b67f09SDavid van Moolenbroek 	result = isc_timermgr_createinctx(mctx, actx, &timermgr);
395*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
396*00b67f09SDavid van Moolenbroek 		goto cleanup;
397*00b67f09SDavid van Moolenbroek #if 0
398*00b67f09SDavid van Moolenbroek 	result = isc_log_create(mctx, &lctx, &logconfig);
399*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
400*00b67f09SDavid van Moolenbroek 		goto cleanup;
401*00b67f09SDavid van Moolenbroek 	isc_log_setcontext(lctx);
402*00b67f09SDavid van Moolenbroek 	dns_log_init(lctx);
403*00b67f09SDavid van Moolenbroek 	dns_log_setcontext(lctx);
404*00b67f09SDavid van Moolenbroek 	result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
405*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
406*00b67f09SDavid van Moolenbroek 		goto cleanup;
407*00b67f09SDavid van Moolenbroek 	isc_log_setdebuglevel(lctx, logdebuglevel);
408*00b67f09SDavid van Moolenbroek #endif
409*00b67f09SDavid van Moolenbroek 	result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
410*00b67f09SDavid van Moolenbroek 				    options, clientp);
411*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
412*00b67f09SDavid van Moolenbroek 		goto cleanup;
413*00b67f09SDavid van Moolenbroek 
414*00b67f09SDavid van Moolenbroek 	(*clientp)->attributes |= DNS_CLIENTATTR_OWNCTX;
415*00b67f09SDavid van Moolenbroek 
416*00b67f09SDavid van Moolenbroek 	/* client has its own reference to mctx, so we can detach it here */
417*00b67f09SDavid van Moolenbroek 	isc_mem_detach(&mctx);
418*00b67f09SDavid van Moolenbroek 
419*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
420*00b67f09SDavid van Moolenbroek 
421*00b67f09SDavid van Moolenbroek  cleanup:
422*00b67f09SDavid van Moolenbroek 	if (taskmgr != NULL)
423*00b67f09SDavid van Moolenbroek 		isc_taskmgr_destroy(&taskmgr);
424*00b67f09SDavid van Moolenbroek 	if (timermgr != NULL)
425*00b67f09SDavid van Moolenbroek 		isc_timermgr_destroy(&timermgr);
426*00b67f09SDavid van Moolenbroek 	if (socketmgr != NULL)
427*00b67f09SDavid van Moolenbroek 		isc_socketmgr_destroy(&socketmgr);
428*00b67f09SDavid van Moolenbroek 	if (actx != NULL)
429*00b67f09SDavid van Moolenbroek 		isc_appctx_destroy(&actx);
430*00b67f09SDavid van Moolenbroek 	isc_mem_detach(&mctx);
431*00b67f09SDavid van Moolenbroek 
432*00b67f09SDavid van Moolenbroek 	return (result);
433*00b67f09SDavid van Moolenbroek }
434*00b67f09SDavid van Moolenbroek 
435*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_createx(isc_mem_t * mctx,isc_appctx_t * actx,isc_taskmgr_t * taskmgr,isc_socketmgr_t * socketmgr,isc_timermgr_t * timermgr,unsigned int options,dns_client_t ** clientp)436*00b67f09SDavid van Moolenbroek dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
437*00b67f09SDavid van Moolenbroek 		   isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
438*00b67f09SDavid van Moolenbroek 		   unsigned int options, dns_client_t **clientp)
439*00b67f09SDavid van Moolenbroek {
440*00b67f09SDavid van Moolenbroek 	isc_result_t result;
441*00b67f09SDavid van Moolenbroek 	result = dns_client_createx2(mctx, actx, taskmgr, socketmgr, timermgr,
442*00b67f09SDavid van Moolenbroek 				     options, clientp, NULL, NULL);
443*00b67f09SDavid van Moolenbroek 	return (result);
444*00b67f09SDavid van Moolenbroek }
445*00b67f09SDavid van Moolenbroek 
446*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_createx2(isc_mem_t * mctx,isc_appctx_t * actx,isc_taskmgr_t * taskmgr,isc_socketmgr_t * socketmgr,isc_timermgr_t * timermgr,unsigned int options,dns_client_t ** clientp,isc_sockaddr_t * localaddr4,isc_sockaddr_t * localaddr6)447*00b67f09SDavid van Moolenbroek dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
448*00b67f09SDavid van Moolenbroek 		    isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
449*00b67f09SDavid van Moolenbroek 		    isc_timermgr_t *timermgr, unsigned int options,
450*00b67f09SDavid van Moolenbroek 		    dns_client_t **clientp, isc_sockaddr_t *localaddr4,
451*00b67f09SDavid van Moolenbroek 		    isc_sockaddr_t *localaddr6)
452*00b67f09SDavid van Moolenbroek {
453*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
454*00b67f09SDavid van Moolenbroek 	isc_result_t result;
455*00b67f09SDavid van Moolenbroek 	dns_dispatchmgr_t *dispatchmgr = NULL;
456*00b67f09SDavid van Moolenbroek 	dns_dispatch_t *dispatchv4 = NULL;
457*00b67f09SDavid van Moolenbroek 	dns_dispatch_t *dispatchv6 = NULL;
458*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
459*00b67f09SDavid van Moolenbroek 
460*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
461*00b67f09SDavid van Moolenbroek 	REQUIRE(taskmgr != NULL);
462*00b67f09SDavid van Moolenbroek 	REQUIRE(timermgr != NULL);
463*00b67f09SDavid van Moolenbroek 	REQUIRE(socketmgr != NULL);
464*00b67f09SDavid van Moolenbroek 	REQUIRE(clientp != NULL && *clientp == NULL);
465*00b67f09SDavid van Moolenbroek 
466*00b67f09SDavid van Moolenbroek 	client = isc_mem_get(mctx, sizeof(*client));
467*00b67f09SDavid van Moolenbroek 	if (client == NULL)
468*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
469*00b67f09SDavid van Moolenbroek 
470*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&client->lock);
471*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
472*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, client, sizeof(*client));
473*00b67f09SDavid van Moolenbroek 		return (result);
474*00b67f09SDavid van Moolenbroek 	}
475*00b67f09SDavid van Moolenbroek 
476*00b67f09SDavid van Moolenbroek 	client->actx = actx;
477*00b67f09SDavid van Moolenbroek 	client->taskmgr = taskmgr;
478*00b67f09SDavid van Moolenbroek 	client->socketmgr = socketmgr;
479*00b67f09SDavid van Moolenbroek 	client->timermgr = timermgr;
480*00b67f09SDavid van Moolenbroek 
481*00b67f09SDavid van Moolenbroek 	client->task = NULL;
482*00b67f09SDavid van Moolenbroek 	result = isc_task_create(client->taskmgr, 0, &client->task);
483*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
484*00b67f09SDavid van Moolenbroek 		goto cleanup;
485*00b67f09SDavid van Moolenbroek 
486*00b67f09SDavid van Moolenbroek 	result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
487*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
488*00b67f09SDavid van Moolenbroek 		goto cleanup;
489*00b67f09SDavid van Moolenbroek 	client->dispatchmgr = dispatchmgr;
490*00b67f09SDavid van Moolenbroek 
491*00b67f09SDavid van Moolenbroek 	/*
492*00b67f09SDavid van Moolenbroek 	 * If only one address family is specified, use it.
493*00b67f09SDavid van Moolenbroek 	 * If neither family is specified, or if both are, use both.
494*00b67f09SDavid van Moolenbroek 	 */
495*00b67f09SDavid van Moolenbroek 	client->dispatchv4 = NULL;
496*00b67f09SDavid van Moolenbroek 	if (localaddr4 != NULL || localaddr6 == NULL) {
497*00b67f09SDavid van Moolenbroek 		result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
498*00b67f09SDavid van Moolenbroek 					taskmgr, ISC_TRUE,
499*00b67f09SDavid van Moolenbroek 					&dispatchv4, localaddr4);
500*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
501*00b67f09SDavid van Moolenbroek 			client->dispatchv4 = dispatchv4;
502*00b67f09SDavid van Moolenbroek 	}
503*00b67f09SDavid van Moolenbroek 
504*00b67f09SDavid van Moolenbroek 	client->dispatchv6 = NULL;
505*00b67f09SDavid van Moolenbroek 	if (localaddr6 != NULL || localaddr4 == NULL) {
506*00b67f09SDavid van Moolenbroek 		result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
507*00b67f09SDavid van Moolenbroek 					taskmgr, ISC_TRUE,
508*00b67f09SDavid van Moolenbroek 					&dispatchv6, localaddr6);
509*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
510*00b67f09SDavid van Moolenbroek 			client->dispatchv6 = dispatchv6;
511*00b67f09SDavid van Moolenbroek 	}
512*00b67f09SDavid van Moolenbroek 
513*00b67f09SDavid van Moolenbroek 	/* We need at least one of the dispatchers */
514*00b67f09SDavid van Moolenbroek 	if (dispatchv4 == NULL && dispatchv6 == NULL) {
515*00b67f09SDavid van Moolenbroek 		INSIST(result != ISC_R_SUCCESS);
516*00b67f09SDavid van Moolenbroek 		goto cleanup;
517*00b67f09SDavid van Moolenbroek 	}
518*00b67f09SDavid van Moolenbroek 
519*00b67f09SDavid van Moolenbroek 	/* Create the default view for class IN */
520*00b67f09SDavid van Moolenbroek 	result = createview(mctx, dns_rdataclass_in, options, taskmgr,
521*00b67f09SDavid van Moolenbroek 			    RESOLVER_NTASKS, socketmgr, timermgr,
522*00b67f09SDavid van Moolenbroek 			    dispatchmgr, dispatchv4, dispatchv6, &view);
523*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
524*00b67f09SDavid van Moolenbroek 		goto cleanup;
525*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(client->viewlist);
526*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(client->viewlist, view, link);
527*00b67f09SDavid van Moolenbroek 
528*00b67f09SDavid van Moolenbroek 	dns_view_freeze(view); /* too early? */
529*00b67f09SDavid van Moolenbroek 
530*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(client->resctxs);
531*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(client->reqctxs);
532*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(client->updatectxs);
533*00b67f09SDavid van Moolenbroek 
534*00b67f09SDavid van Moolenbroek 	client->mctx = NULL;
535*00b67f09SDavid van Moolenbroek 	isc_mem_attach(mctx, &client->mctx);
536*00b67f09SDavid van Moolenbroek 
537*00b67f09SDavid van Moolenbroek 	client->update_timeout = DEF_UPDATE_TIMEOUT;
538*00b67f09SDavid van Moolenbroek 	client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
539*00b67f09SDavid van Moolenbroek 	client->update_udpretries = DEF_UPDATE_UDPRETRIES;
540*00b67f09SDavid van Moolenbroek 	client->find_timeout = DEF_FIND_TIMEOUT;
541*00b67f09SDavid van Moolenbroek 	client->find_udpretries = DEF_FIND_UDPRETRIES;
542*00b67f09SDavid van Moolenbroek 	client->attributes = 0;
543*00b67f09SDavid van Moolenbroek 
544*00b67f09SDavid van Moolenbroek 	client->references = 1;
545*00b67f09SDavid van Moolenbroek 	client->magic = DNS_CLIENT_MAGIC;
546*00b67f09SDavid van Moolenbroek 
547*00b67f09SDavid van Moolenbroek 	*clientp = client;
548*00b67f09SDavid van Moolenbroek 
549*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
550*00b67f09SDavid van Moolenbroek 
551*00b67f09SDavid van Moolenbroek  cleanup:
552*00b67f09SDavid van Moolenbroek 	if (dispatchv4 != NULL)
553*00b67f09SDavid van Moolenbroek 		dns_dispatch_detach(&dispatchv4);
554*00b67f09SDavid van Moolenbroek 	if (dispatchv6 != NULL)
555*00b67f09SDavid van Moolenbroek 		dns_dispatch_detach(&dispatchv6);
556*00b67f09SDavid van Moolenbroek 	if (dispatchmgr != NULL)
557*00b67f09SDavid van Moolenbroek 		dns_dispatchmgr_destroy(&dispatchmgr);
558*00b67f09SDavid van Moolenbroek 	if (client->task != NULL)
559*00b67f09SDavid van Moolenbroek 		isc_task_detach(&client->task);
560*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, client, sizeof(*client));
561*00b67f09SDavid van Moolenbroek 
562*00b67f09SDavid van Moolenbroek 	return (result);
563*00b67f09SDavid van Moolenbroek }
564*00b67f09SDavid van Moolenbroek 
565*00b67f09SDavid van Moolenbroek static void
destroyclient(dns_client_t ** clientp)566*00b67f09SDavid van Moolenbroek destroyclient(dns_client_t **clientp) {
567*00b67f09SDavid van Moolenbroek 	dns_client_t *client = *clientp;
568*00b67f09SDavid van Moolenbroek 	dns_view_t *view;
569*00b67f09SDavid van Moolenbroek 
570*00b67f09SDavid van Moolenbroek 	while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
571*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(client->viewlist, view, link);
572*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
573*00b67f09SDavid van Moolenbroek 	}
574*00b67f09SDavid van Moolenbroek 
575*00b67f09SDavid van Moolenbroek 	if (client->dispatchv4 != NULL)
576*00b67f09SDavid van Moolenbroek 		dns_dispatch_detach(&client->dispatchv4);
577*00b67f09SDavid van Moolenbroek 	if (client->dispatchv6 != NULL)
578*00b67f09SDavid van Moolenbroek 		dns_dispatch_detach(&client->dispatchv6);
579*00b67f09SDavid van Moolenbroek 
580*00b67f09SDavid van Moolenbroek 	dns_dispatchmgr_destroy(&client->dispatchmgr);
581*00b67f09SDavid van Moolenbroek 
582*00b67f09SDavid van Moolenbroek 	isc_task_detach(&client->task);
583*00b67f09SDavid van Moolenbroek 
584*00b67f09SDavid van Moolenbroek 	/*
585*00b67f09SDavid van Moolenbroek 	 * If the client has created its own running environments,
586*00b67f09SDavid van Moolenbroek 	 * destroy them.
587*00b67f09SDavid van Moolenbroek 	 */
588*00b67f09SDavid van Moolenbroek 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) != 0) {
589*00b67f09SDavid van Moolenbroek 		isc_taskmgr_destroy(&client->taskmgr);
590*00b67f09SDavid van Moolenbroek 		isc_timermgr_destroy(&client->timermgr);
591*00b67f09SDavid van Moolenbroek 		isc_socketmgr_destroy(&client->socketmgr);
592*00b67f09SDavid van Moolenbroek 
593*00b67f09SDavid van Moolenbroek 		isc_app_ctxfinish(client->actx);
594*00b67f09SDavid van Moolenbroek 		isc_appctx_destroy(&client->actx);
595*00b67f09SDavid van Moolenbroek 	}
596*00b67f09SDavid van Moolenbroek 
597*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&client->lock);
598*00b67f09SDavid van Moolenbroek 	client->magic = 0;
599*00b67f09SDavid van Moolenbroek 
600*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
601*00b67f09SDavid van Moolenbroek 
602*00b67f09SDavid van Moolenbroek 	*clientp = NULL;
603*00b67f09SDavid van Moolenbroek }
604*00b67f09SDavid van Moolenbroek 
605*00b67f09SDavid van Moolenbroek void
dns_client_destroy(dns_client_t ** clientp)606*00b67f09SDavid van Moolenbroek dns_client_destroy(dns_client_t **clientp) {
607*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
608*00b67f09SDavid van Moolenbroek 	isc_boolean_t destroyok = ISC_FALSE;
609*00b67f09SDavid van Moolenbroek 
610*00b67f09SDavid van Moolenbroek 	REQUIRE(clientp != NULL);
611*00b67f09SDavid van Moolenbroek 	client = *clientp;
612*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
613*00b67f09SDavid van Moolenbroek 
614*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
615*00b67f09SDavid van Moolenbroek 	client->references--;
616*00b67f09SDavid van Moolenbroek 	if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
617*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->reqctxs) &&
618*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->updatectxs)) {
619*00b67f09SDavid van Moolenbroek 		destroyok = ISC_TRUE;
620*00b67f09SDavid van Moolenbroek 	}
621*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
622*00b67f09SDavid van Moolenbroek 
623*00b67f09SDavid van Moolenbroek 	if (destroyok)
624*00b67f09SDavid van Moolenbroek 		destroyclient(&client);
625*00b67f09SDavid van Moolenbroek 
626*00b67f09SDavid van Moolenbroek 	*clientp = NULL;
627*00b67f09SDavid van Moolenbroek }
628*00b67f09SDavid van Moolenbroek 
629*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_setservers(dns_client_t * client,dns_rdataclass_t rdclass,dns_name_t * namespace,isc_sockaddrlist_t * addrs)630*00b67f09SDavid van Moolenbroek dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
631*00b67f09SDavid van Moolenbroek 		      dns_name_t *namespace, isc_sockaddrlist_t *addrs)
632*00b67f09SDavid van Moolenbroek {
633*00b67f09SDavid van Moolenbroek 	isc_result_t result;
634*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
635*00b67f09SDavid van Moolenbroek 
636*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
637*00b67f09SDavid van Moolenbroek 	REQUIRE(addrs != NULL);
638*00b67f09SDavid van Moolenbroek 
639*00b67f09SDavid van Moolenbroek 	if (namespace == NULL)
640*00b67f09SDavid van Moolenbroek 		namespace = dns_rootname;
641*00b67f09SDavid van Moolenbroek 
642*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
643*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
644*00b67f09SDavid van Moolenbroek 				   rdclass, &view);
645*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
646*00b67f09SDavid van Moolenbroek 		UNLOCK(&client->lock);
647*00b67f09SDavid van Moolenbroek 		return (result);
648*00b67f09SDavid van Moolenbroek 	}
649*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
650*00b67f09SDavid van Moolenbroek 
651*00b67f09SDavid van Moolenbroek 	result = dns_fwdtable_add(view->fwdtable, namespace, addrs,
652*00b67f09SDavid van Moolenbroek 				  dns_fwdpolicy_only);
653*00b67f09SDavid van Moolenbroek 
654*00b67f09SDavid van Moolenbroek 	dns_view_detach(&view);
655*00b67f09SDavid van Moolenbroek 
656*00b67f09SDavid van Moolenbroek 	return (result);
657*00b67f09SDavid van Moolenbroek }
658*00b67f09SDavid van Moolenbroek 
659*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_clearservers(dns_client_t * client,dns_rdataclass_t rdclass,dns_name_t * namespace)660*00b67f09SDavid van Moolenbroek dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
661*00b67f09SDavid van Moolenbroek 			dns_name_t *namespace)
662*00b67f09SDavid van Moolenbroek {
663*00b67f09SDavid van Moolenbroek 	isc_result_t result;
664*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
665*00b67f09SDavid van Moolenbroek 
666*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
667*00b67f09SDavid van Moolenbroek 
668*00b67f09SDavid van Moolenbroek 	if (namespace == NULL)
669*00b67f09SDavid van Moolenbroek 		namespace = dns_rootname;
670*00b67f09SDavid van Moolenbroek 
671*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
672*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
673*00b67f09SDavid van Moolenbroek 				   rdclass, &view);
674*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
675*00b67f09SDavid van Moolenbroek 		UNLOCK(&client->lock);
676*00b67f09SDavid van Moolenbroek 		return (result);
677*00b67f09SDavid van Moolenbroek 	}
678*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
679*00b67f09SDavid van Moolenbroek 
680*00b67f09SDavid van Moolenbroek 	result = dns_fwdtable_delete(view->fwdtable, namespace);
681*00b67f09SDavid van Moolenbroek 
682*00b67f09SDavid van Moolenbroek 	dns_view_detach(&view);
683*00b67f09SDavid van Moolenbroek 
684*00b67f09SDavid van Moolenbroek 	return (result);
685*00b67f09SDavid van Moolenbroek }
686*00b67f09SDavid van Moolenbroek 
687*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_setdlv(dns_client_t * client,dns_rdataclass_t rdclass,const char * dlvname)688*00b67f09SDavid van Moolenbroek dns_client_setdlv(dns_client_t *client, dns_rdataclass_t rdclass,
689*00b67f09SDavid van Moolenbroek 		  const char *dlvname)
690*00b67f09SDavid van Moolenbroek {
691*00b67f09SDavid van Moolenbroek 	isc_result_t result;
692*00b67f09SDavid van Moolenbroek 	isc_buffer_t b;
693*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
694*00b67f09SDavid van Moolenbroek 
695*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
696*00b67f09SDavid van Moolenbroek 
697*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
698*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
699*00b67f09SDavid van Moolenbroek 				   rdclass, &view);
700*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
701*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
702*00b67f09SDavid van Moolenbroek 		goto cleanup;
703*00b67f09SDavid van Moolenbroek 
704*00b67f09SDavid van Moolenbroek 	if (dlvname == NULL)
705*00b67f09SDavid van Moolenbroek 		view->dlv = NULL;
706*00b67f09SDavid van Moolenbroek 	else {
707*00b67f09SDavid van Moolenbroek 		dns_name_t *newdlv;
708*00b67f09SDavid van Moolenbroek 
709*00b67f09SDavid van Moolenbroek 		isc_buffer_constinit(&b, dlvname, strlen(dlvname));
710*00b67f09SDavid van Moolenbroek 		isc_buffer_add(&b, strlen(dlvname));
711*00b67f09SDavid van Moolenbroek 		newdlv = dns_fixedname_name(&view->dlv_fixed);
712*00b67f09SDavid van Moolenbroek 		result = dns_name_fromtext(newdlv, &b, dns_rootname,
713*00b67f09SDavid van Moolenbroek 					   DNS_NAME_DOWNCASE, NULL);
714*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
715*00b67f09SDavid van Moolenbroek 			goto cleanup;
716*00b67f09SDavid van Moolenbroek 
717*00b67f09SDavid van Moolenbroek 		view->dlv = dns_fixedname_name(&view->dlv_fixed);
718*00b67f09SDavid van Moolenbroek 	}
719*00b67f09SDavid van Moolenbroek 
720*00b67f09SDavid van Moolenbroek  cleanup:
721*00b67f09SDavid van Moolenbroek 	if (view != NULL)
722*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
723*00b67f09SDavid van Moolenbroek 
724*00b67f09SDavid van Moolenbroek 	return (result);
725*00b67f09SDavid van Moolenbroek }
726*00b67f09SDavid van Moolenbroek 
727*00b67f09SDavid van Moolenbroek static isc_result_t
getrdataset(isc_mem_t * mctx,dns_rdataset_t ** rdatasetp)728*00b67f09SDavid van Moolenbroek getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
729*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset;
730*00b67f09SDavid van Moolenbroek 
731*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
732*00b67f09SDavid van Moolenbroek 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
733*00b67f09SDavid van Moolenbroek 
734*00b67f09SDavid van Moolenbroek 	rdataset = isc_mem_get(mctx, sizeof(*rdataset));
735*00b67f09SDavid van Moolenbroek 	if (rdataset == NULL)
736*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
737*00b67f09SDavid van Moolenbroek 
738*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(rdataset);
739*00b67f09SDavid van Moolenbroek 
740*00b67f09SDavid van Moolenbroek 	*rdatasetp = rdataset;
741*00b67f09SDavid van Moolenbroek 
742*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
743*00b67f09SDavid van Moolenbroek }
744*00b67f09SDavid van Moolenbroek 
745*00b67f09SDavid van Moolenbroek static void
putrdataset(isc_mem_t * mctx,dns_rdataset_t ** rdatasetp)746*00b67f09SDavid van Moolenbroek putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
747*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset;
748*00b67f09SDavid van Moolenbroek 
749*00b67f09SDavid van Moolenbroek 	REQUIRE(rdatasetp != NULL);
750*00b67f09SDavid van Moolenbroek 	rdataset = *rdatasetp;
751*00b67f09SDavid van Moolenbroek 	REQUIRE(rdataset != NULL);
752*00b67f09SDavid van Moolenbroek 
753*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(rdataset))
754*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(rdataset);
755*00b67f09SDavid van Moolenbroek 
756*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, rdataset, sizeof(*rdataset));
757*00b67f09SDavid van Moolenbroek 
758*00b67f09SDavid van Moolenbroek 	*rdatasetp = NULL;
759*00b67f09SDavid van Moolenbroek }
760*00b67f09SDavid van Moolenbroek 
761*00b67f09SDavid van Moolenbroek static void
fetch_done(isc_task_t * task,isc_event_t * event)762*00b67f09SDavid van Moolenbroek fetch_done(isc_task_t *task, isc_event_t *event) {
763*00b67f09SDavid van Moolenbroek 	resctx_t *rctx = event->ev_arg;
764*00b67f09SDavid van Moolenbroek 	dns_fetchevent_t *fevent;
765*00b67f09SDavid van Moolenbroek 
766*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
767*00b67f09SDavid van Moolenbroek 	REQUIRE(RCTX_VALID(rctx));
768*00b67f09SDavid van Moolenbroek 	REQUIRE(rctx->task == task);
769*00b67f09SDavid van Moolenbroek 	fevent = (dns_fetchevent_t *)event;
770*00b67f09SDavid van Moolenbroek 
771*00b67f09SDavid van Moolenbroek 	client_resfind(rctx, fevent);
772*00b67f09SDavid van Moolenbroek }
773*00b67f09SDavid van Moolenbroek 
774*00b67f09SDavid van Moolenbroek static inline isc_result_t
start_fetch(resctx_t * rctx)775*00b67f09SDavid van Moolenbroek start_fetch(resctx_t *rctx) {
776*00b67f09SDavid van Moolenbroek 	isc_result_t result;
777*00b67f09SDavid van Moolenbroek 	int fopts = 0;
778*00b67f09SDavid van Moolenbroek 
779*00b67f09SDavid van Moolenbroek 	/*
780*00b67f09SDavid van Moolenbroek 	 * The caller must be holding the rctx's lock.
781*00b67f09SDavid van Moolenbroek 	 */
782*00b67f09SDavid van Moolenbroek 
783*00b67f09SDavid van Moolenbroek 	REQUIRE(rctx->fetch == NULL);
784*00b67f09SDavid van Moolenbroek 
785*00b67f09SDavid van Moolenbroek 	if (!rctx->want_cdflag)
786*00b67f09SDavid van Moolenbroek 		fopts |= DNS_FETCHOPT_NOCDFLAG;
787*00b67f09SDavid van Moolenbroek 	if (!rctx->want_validation)
788*00b67f09SDavid van Moolenbroek 		fopts |= DNS_FETCHOPT_NOVALIDATE;
789*00b67f09SDavid van Moolenbroek 
790*00b67f09SDavid van Moolenbroek 	result = dns_resolver_createfetch(rctx->view->resolver,
791*00b67f09SDavid van Moolenbroek 					  dns_fixedname_name(&rctx->name),
792*00b67f09SDavid van Moolenbroek 					  rctx->type,
793*00b67f09SDavid van Moolenbroek 					  NULL, NULL, NULL, fopts,
794*00b67f09SDavid van Moolenbroek 					  rctx->task, fetch_done, rctx,
795*00b67f09SDavid van Moolenbroek 					  rctx->rdataset,
796*00b67f09SDavid van Moolenbroek 					  rctx->sigrdataset,
797*00b67f09SDavid van Moolenbroek 					  &rctx->fetch);
798*00b67f09SDavid van Moolenbroek 
799*00b67f09SDavid van Moolenbroek 	return (result);
800*00b67f09SDavid van Moolenbroek }
801*00b67f09SDavid van Moolenbroek 
802*00b67f09SDavid van Moolenbroek static isc_result_t
view_find(resctx_t * rctx,dns_db_t ** dbp,dns_dbnode_t ** nodep,dns_name_t * foundname)803*00b67f09SDavid van Moolenbroek view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
804*00b67f09SDavid van Moolenbroek 	  dns_name_t *foundname)
805*00b67f09SDavid van Moolenbroek {
806*00b67f09SDavid van Moolenbroek 	isc_result_t result;
807*00b67f09SDavid van Moolenbroek 	dns_name_t *name = dns_fixedname_name(&rctx->name);
808*00b67f09SDavid van Moolenbroek 	dns_rdatatype_t type;
809*00b67f09SDavid van Moolenbroek 
810*00b67f09SDavid van Moolenbroek 	if (rctx->type == dns_rdatatype_rrsig)
811*00b67f09SDavid van Moolenbroek 		type = dns_rdatatype_any;
812*00b67f09SDavid van Moolenbroek 	else
813*00b67f09SDavid van Moolenbroek 		type = rctx->type;
814*00b67f09SDavid van Moolenbroek 
815*00b67f09SDavid van Moolenbroek 	result = dns_view_find(rctx->view, name, type, 0, 0, ISC_FALSE,
816*00b67f09SDavid van Moolenbroek 			       dbp, nodep, foundname, rctx->rdataset,
817*00b67f09SDavid van Moolenbroek 			       rctx->sigrdataset);
818*00b67f09SDavid van Moolenbroek 
819*00b67f09SDavid van Moolenbroek 	return (result);
820*00b67f09SDavid van Moolenbroek }
821*00b67f09SDavid van Moolenbroek 
822*00b67f09SDavid van Moolenbroek static void
client_resfind(resctx_t * rctx,dns_fetchevent_t * event)823*00b67f09SDavid van Moolenbroek client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
824*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
825*00b67f09SDavid van Moolenbroek 	isc_result_t tresult, result = ISC_R_SUCCESS;
826*00b67f09SDavid van Moolenbroek 	isc_result_t vresult = ISC_R_SUCCESS;
827*00b67f09SDavid van Moolenbroek 	isc_boolean_t want_restart;
828*00b67f09SDavid van Moolenbroek 	isc_boolean_t send_event = ISC_FALSE;
829*00b67f09SDavid van Moolenbroek 	dns_name_t *name, *prefix;
830*00b67f09SDavid van Moolenbroek 	dns_fixedname_t foundname, fixed;
831*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *trdataset;
832*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
833*00b67f09SDavid van Moolenbroek 	unsigned int nlabels;
834*00b67f09SDavid van Moolenbroek 	int order;
835*00b67f09SDavid van Moolenbroek 	dns_namereln_t namereln;
836*00b67f09SDavid van Moolenbroek 	dns_rdata_cname_t cname;
837*00b67f09SDavid van Moolenbroek 	dns_rdata_dname_t dname;
838*00b67f09SDavid van Moolenbroek 
839*00b67f09SDavid van Moolenbroek 	REQUIRE(RCTX_VALID(rctx));
840*00b67f09SDavid van Moolenbroek 
841*00b67f09SDavid van Moolenbroek 	LOCK(&rctx->lock);
842*00b67f09SDavid van Moolenbroek 
843*00b67f09SDavid van Moolenbroek 	mctx = rctx->view->mctx;
844*00b67f09SDavid van Moolenbroek 
845*00b67f09SDavid van Moolenbroek 	name = dns_fixedname_name(&rctx->name);
846*00b67f09SDavid van Moolenbroek 
847*00b67f09SDavid van Moolenbroek 	do {
848*00b67f09SDavid van Moolenbroek 		dns_name_t *fname = NULL;
849*00b67f09SDavid van Moolenbroek 		dns_name_t *ansname = NULL;
850*00b67f09SDavid van Moolenbroek 		dns_db_t *db = NULL;
851*00b67f09SDavid van Moolenbroek 		dns_dbnode_t *node = NULL;
852*00b67f09SDavid van Moolenbroek 
853*00b67f09SDavid van Moolenbroek 		rctx->restarts++;
854*00b67f09SDavid van Moolenbroek 		want_restart = ISC_FALSE;
855*00b67f09SDavid van Moolenbroek 
856*00b67f09SDavid van Moolenbroek 		if (event == NULL && !rctx->canceled) {
857*00b67f09SDavid van Moolenbroek 			dns_fixedname_init(&foundname);
858*00b67f09SDavid van Moolenbroek 			fname = dns_fixedname_name(&foundname);
859*00b67f09SDavid van Moolenbroek 			INSIST(!dns_rdataset_isassociated(rctx->rdataset));
860*00b67f09SDavid van Moolenbroek 			INSIST(rctx->sigrdataset == NULL ||
861*00b67f09SDavid van Moolenbroek 			       !dns_rdataset_isassociated(rctx->sigrdataset));
862*00b67f09SDavid van Moolenbroek 			result = view_find(rctx, &db, &node, fname);
863*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOTFOUND) {
864*00b67f09SDavid van Moolenbroek 				/*
865*00b67f09SDavid van Moolenbroek 				 * We don't know anything about the name.
866*00b67f09SDavid van Moolenbroek 				 * Launch a fetch.
867*00b67f09SDavid van Moolenbroek 				 */
868*00b67f09SDavid van Moolenbroek 				if (node != NULL) {
869*00b67f09SDavid van Moolenbroek 					INSIST(db != NULL);
870*00b67f09SDavid van Moolenbroek 					dns_db_detachnode(db, &node);
871*00b67f09SDavid van Moolenbroek 				}
872*00b67f09SDavid van Moolenbroek 				if (db != NULL)
873*00b67f09SDavid van Moolenbroek 					dns_db_detach(&db);
874*00b67f09SDavid van Moolenbroek 				result = start_fetch(rctx);
875*00b67f09SDavid van Moolenbroek 				if (result != ISC_R_SUCCESS) {
876*00b67f09SDavid van Moolenbroek 					putrdataset(mctx, &rctx->rdataset);
877*00b67f09SDavid van Moolenbroek 					if (rctx->sigrdataset != NULL)
878*00b67f09SDavid van Moolenbroek 						putrdataset(mctx,
879*00b67f09SDavid van Moolenbroek 							    &rctx->sigrdataset);
880*00b67f09SDavid van Moolenbroek 					send_event = ISC_TRUE;
881*00b67f09SDavid van Moolenbroek 				}
882*00b67f09SDavid van Moolenbroek 				goto done;
883*00b67f09SDavid van Moolenbroek 			}
884*00b67f09SDavid van Moolenbroek 		} else {
885*00b67f09SDavid van Moolenbroek 			INSIST(event != NULL);
886*00b67f09SDavid van Moolenbroek 			INSIST(event->fetch == rctx->fetch);
887*00b67f09SDavid van Moolenbroek 			dns_resolver_destroyfetch(&rctx->fetch);
888*00b67f09SDavid van Moolenbroek 			db = event->db;
889*00b67f09SDavid van Moolenbroek 			node = event->node;
890*00b67f09SDavid van Moolenbroek 			result = event->result;
891*00b67f09SDavid van Moolenbroek 			vresult = event->vresult;
892*00b67f09SDavid van Moolenbroek 			fname = dns_fixedname_name(&event->foundname);
893*00b67f09SDavid van Moolenbroek 			INSIST(event->rdataset == rctx->rdataset);
894*00b67f09SDavid van Moolenbroek 			INSIST(event->sigrdataset == rctx->sigrdataset);
895*00b67f09SDavid van Moolenbroek 		}
896*00b67f09SDavid van Moolenbroek 
897*00b67f09SDavid van Moolenbroek 		/*
898*00b67f09SDavid van Moolenbroek 		 * If we've been canceled, forget about the result.
899*00b67f09SDavid van Moolenbroek 		 */
900*00b67f09SDavid van Moolenbroek 		if (rctx->canceled)
901*00b67f09SDavid van Moolenbroek 			result = ISC_R_CANCELED;
902*00b67f09SDavid van Moolenbroek 		else {
903*00b67f09SDavid van Moolenbroek 			/*
904*00b67f09SDavid van Moolenbroek 			 * Otherwise, get some resource for copying the
905*00b67f09SDavid van Moolenbroek 			 * result.
906*00b67f09SDavid van Moolenbroek 			 */
907*00b67f09SDavid van Moolenbroek 			ansname = isc_mem_get(mctx, sizeof(*ansname));
908*00b67f09SDavid van Moolenbroek 			if (ansname == NULL)
909*00b67f09SDavid van Moolenbroek 				tresult = ISC_R_NOMEMORY;
910*00b67f09SDavid van Moolenbroek 			else {
911*00b67f09SDavid van Moolenbroek 				dns_name_t *aname;
912*00b67f09SDavid van Moolenbroek 
913*00b67f09SDavid van Moolenbroek 				aname = dns_fixedname_name(&rctx->name);
914*00b67f09SDavid van Moolenbroek 				dns_name_init(ansname, NULL);
915*00b67f09SDavid van Moolenbroek 				tresult = dns_name_dup(aname, mctx, ansname);
916*00b67f09SDavid van Moolenbroek 				if (tresult != ISC_R_SUCCESS)
917*00b67f09SDavid van Moolenbroek 					isc_mem_put(mctx, ansname,
918*00b67f09SDavid van Moolenbroek 						    sizeof(*ansname));
919*00b67f09SDavid van Moolenbroek 			}
920*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_SUCCESS)
921*00b67f09SDavid van Moolenbroek 				result = tresult;
922*00b67f09SDavid van Moolenbroek 		}
923*00b67f09SDavid van Moolenbroek 
924*00b67f09SDavid van Moolenbroek 		switch (result) {
925*00b67f09SDavid van Moolenbroek 		case ISC_R_SUCCESS:
926*00b67f09SDavid van Moolenbroek 			send_event = ISC_TRUE;
927*00b67f09SDavid van Moolenbroek 			/*
928*00b67f09SDavid van Moolenbroek 			 * This case is handled in the main line below.
929*00b67f09SDavid van Moolenbroek 			 */
930*00b67f09SDavid van Moolenbroek 			break;
931*00b67f09SDavid van Moolenbroek 		case DNS_R_CNAME:
932*00b67f09SDavid van Moolenbroek 			/*
933*00b67f09SDavid van Moolenbroek 			 * Add the CNAME to the answer list.
934*00b67f09SDavid van Moolenbroek 			 */
935*00b67f09SDavid van Moolenbroek 			trdataset = rctx->rdataset;
936*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
937*00b67f09SDavid van Moolenbroek 			rctx->rdataset = NULL;
938*00b67f09SDavid van Moolenbroek 			if (rctx->sigrdataset != NULL) {
939*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(ansname->list,
940*00b67f09SDavid van Moolenbroek 						rctx->sigrdataset, link);
941*00b67f09SDavid van Moolenbroek 				rctx->sigrdataset = NULL;
942*00b67f09SDavid van Moolenbroek 			}
943*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
944*00b67f09SDavid van Moolenbroek 			ansname = NULL;
945*00b67f09SDavid van Moolenbroek 
946*00b67f09SDavid van Moolenbroek 			/*
947*00b67f09SDavid van Moolenbroek 			 * Copy the CNAME's target into the lookup's
948*00b67f09SDavid van Moolenbroek 			 * query name and start over.
949*00b67f09SDavid van Moolenbroek 			 */
950*00b67f09SDavid van Moolenbroek 			tresult = dns_rdataset_first(trdataset);
951*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_SUCCESS)
952*00b67f09SDavid van Moolenbroek 				goto done;
953*00b67f09SDavid van Moolenbroek 			dns_rdataset_current(trdataset, &rdata);
954*00b67f09SDavid van Moolenbroek 			tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
955*00b67f09SDavid van Moolenbroek 			dns_rdata_reset(&rdata);
956*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_SUCCESS)
957*00b67f09SDavid van Moolenbroek 				goto done;
958*00b67f09SDavid van Moolenbroek 			tresult = dns_name_copy(&cname.cname, name, NULL);
959*00b67f09SDavid van Moolenbroek 			dns_rdata_freestruct(&cname);
960*00b67f09SDavid van Moolenbroek 			if (tresult == ISC_R_SUCCESS)
961*00b67f09SDavid van Moolenbroek 				want_restart = ISC_TRUE;
962*00b67f09SDavid van Moolenbroek 			else
963*00b67f09SDavid van Moolenbroek 				result = tresult;
964*00b67f09SDavid van Moolenbroek 			goto done;
965*00b67f09SDavid van Moolenbroek 		case DNS_R_DNAME:
966*00b67f09SDavid van Moolenbroek 			/*
967*00b67f09SDavid van Moolenbroek 			 * Add the DNAME to the answer list.
968*00b67f09SDavid van Moolenbroek 			 */
969*00b67f09SDavid van Moolenbroek 			trdataset = rctx->rdataset;
970*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
971*00b67f09SDavid van Moolenbroek 			rctx->rdataset = NULL;
972*00b67f09SDavid van Moolenbroek 			if (rctx->sigrdataset != NULL) {
973*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(ansname->list,
974*00b67f09SDavid van Moolenbroek 						rctx->sigrdataset, link);
975*00b67f09SDavid van Moolenbroek 				rctx->sigrdataset = NULL;
976*00b67f09SDavid van Moolenbroek 			}
977*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
978*00b67f09SDavid van Moolenbroek 			ansname = NULL;
979*00b67f09SDavid van Moolenbroek 
980*00b67f09SDavid van Moolenbroek 			namereln = dns_name_fullcompare(name, fname, &order,
981*00b67f09SDavid van Moolenbroek 							&nlabels);
982*00b67f09SDavid van Moolenbroek 			INSIST(namereln == dns_namereln_subdomain);
983*00b67f09SDavid van Moolenbroek 			/*
984*00b67f09SDavid van Moolenbroek 			 * Get the target name of the DNAME.
985*00b67f09SDavid van Moolenbroek 			 */
986*00b67f09SDavid van Moolenbroek 			tresult = dns_rdataset_first(trdataset);
987*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_SUCCESS) {
988*00b67f09SDavid van Moolenbroek 				result = tresult;
989*00b67f09SDavid van Moolenbroek 				goto done;
990*00b67f09SDavid van Moolenbroek 			}
991*00b67f09SDavid van Moolenbroek 			dns_rdataset_current(trdataset, &rdata);
992*00b67f09SDavid van Moolenbroek 			tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
993*00b67f09SDavid van Moolenbroek 			dns_rdata_reset(&rdata);
994*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_SUCCESS) {
995*00b67f09SDavid van Moolenbroek 				result = tresult;
996*00b67f09SDavid van Moolenbroek 				goto done;
997*00b67f09SDavid van Moolenbroek 			}
998*00b67f09SDavid van Moolenbroek 			/*
999*00b67f09SDavid van Moolenbroek 			 * Construct the new query name and start over.
1000*00b67f09SDavid van Moolenbroek 			 */
1001*00b67f09SDavid van Moolenbroek 			dns_fixedname_init(&fixed);
1002*00b67f09SDavid van Moolenbroek 			prefix = dns_fixedname_name(&fixed);
1003*00b67f09SDavid van Moolenbroek 			dns_name_split(name, nlabels, prefix, NULL);
1004*00b67f09SDavid van Moolenbroek 			tresult = dns_name_concatenate(prefix, &dname.dname,
1005*00b67f09SDavid van Moolenbroek 						      name, NULL);
1006*00b67f09SDavid van Moolenbroek 			dns_rdata_freestruct(&dname);
1007*00b67f09SDavid van Moolenbroek 			if (tresult == ISC_R_SUCCESS)
1008*00b67f09SDavid van Moolenbroek 				want_restart = ISC_TRUE;
1009*00b67f09SDavid van Moolenbroek 			else
1010*00b67f09SDavid van Moolenbroek 				result = tresult;
1011*00b67f09SDavid van Moolenbroek 			goto done;
1012*00b67f09SDavid van Moolenbroek 		case DNS_R_NCACHENXDOMAIN:
1013*00b67f09SDavid van Moolenbroek 		case DNS_R_NCACHENXRRSET:
1014*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1015*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
1016*00b67f09SDavid van Moolenbroek 			ansname = NULL;
1017*00b67f09SDavid van Moolenbroek 			rctx->rdataset = NULL;
1018*00b67f09SDavid van Moolenbroek 			/* What about sigrdataset? */
1019*00b67f09SDavid van Moolenbroek 			if (rctx->sigrdataset != NULL)
1020*00b67f09SDavid van Moolenbroek 				putrdataset(mctx, &rctx->sigrdataset);
1021*00b67f09SDavid van Moolenbroek 			send_event = ISC_TRUE;
1022*00b67f09SDavid van Moolenbroek 			goto done;
1023*00b67f09SDavid van Moolenbroek 		default:
1024*00b67f09SDavid van Moolenbroek 			if (rctx->rdataset != NULL)
1025*00b67f09SDavid van Moolenbroek 				putrdataset(mctx, &rctx->rdataset);
1026*00b67f09SDavid van Moolenbroek 			if (rctx->sigrdataset != NULL)
1027*00b67f09SDavid van Moolenbroek 				putrdataset(mctx, &rctx->sigrdataset);
1028*00b67f09SDavid van Moolenbroek 			send_event = ISC_TRUE;
1029*00b67f09SDavid van Moolenbroek 			goto done;
1030*00b67f09SDavid van Moolenbroek 		}
1031*00b67f09SDavid van Moolenbroek 
1032*00b67f09SDavid van Moolenbroek 		if (rctx->type == dns_rdatatype_any) {
1033*00b67f09SDavid van Moolenbroek 			int n = 0;
1034*00b67f09SDavid van Moolenbroek 			dns_rdatasetiter_t *rdsiter = NULL;
1035*00b67f09SDavid van Moolenbroek 
1036*00b67f09SDavid van Moolenbroek 			tresult = dns_db_allrdatasets(db, node, NULL, 0,
1037*00b67f09SDavid van Moolenbroek 						      &rdsiter);
1038*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_SUCCESS) {
1039*00b67f09SDavid van Moolenbroek 				result = tresult;
1040*00b67f09SDavid van Moolenbroek 				goto done;
1041*00b67f09SDavid van Moolenbroek 			}
1042*00b67f09SDavid van Moolenbroek 
1043*00b67f09SDavid van Moolenbroek 			tresult = dns_rdatasetiter_first(rdsiter);
1044*00b67f09SDavid van Moolenbroek 			while (tresult == ISC_R_SUCCESS) {
1045*00b67f09SDavid van Moolenbroek 				dns_rdatasetiter_current(rdsiter,
1046*00b67f09SDavid van Moolenbroek 							 rctx->rdataset);
1047*00b67f09SDavid van Moolenbroek 				if (rctx->rdataset->type != 0) {
1048*00b67f09SDavid van Moolenbroek 					ISC_LIST_APPEND(ansname->list,
1049*00b67f09SDavid van Moolenbroek 							rctx->rdataset,
1050*00b67f09SDavid van Moolenbroek 							link);
1051*00b67f09SDavid van Moolenbroek 					n++;
1052*00b67f09SDavid van Moolenbroek 					rctx->rdataset = NULL;
1053*00b67f09SDavid van Moolenbroek 				} else {
1054*00b67f09SDavid van Moolenbroek 					/*
1055*00b67f09SDavid van Moolenbroek 					 * We're not interested in this
1056*00b67f09SDavid van Moolenbroek 					 * rdataset.
1057*00b67f09SDavid van Moolenbroek 					 */
1058*00b67f09SDavid van Moolenbroek 					dns_rdataset_disassociate(
1059*00b67f09SDavid van Moolenbroek 						rctx->rdataset);
1060*00b67f09SDavid van Moolenbroek 				}
1061*00b67f09SDavid van Moolenbroek 				tresult = dns_rdatasetiter_next(rdsiter);
1062*00b67f09SDavid van Moolenbroek 
1063*00b67f09SDavid van Moolenbroek 				if (tresult == ISC_R_SUCCESS &&
1064*00b67f09SDavid van Moolenbroek 				    rctx->rdataset == NULL) {
1065*00b67f09SDavid van Moolenbroek 					tresult = getrdataset(mctx,
1066*00b67f09SDavid van Moolenbroek 							      &rctx->rdataset);
1067*00b67f09SDavid van Moolenbroek 					if (tresult != ISC_R_SUCCESS) {
1068*00b67f09SDavid van Moolenbroek 						result = tresult;
1069*00b67f09SDavid van Moolenbroek 						POST(result);
1070*00b67f09SDavid van Moolenbroek 						break;
1071*00b67f09SDavid van Moolenbroek 					}
1072*00b67f09SDavid van Moolenbroek 				}
1073*00b67f09SDavid van Moolenbroek 			}
1074*00b67f09SDavid van Moolenbroek 			if (n == 0) {
1075*00b67f09SDavid van Moolenbroek 				/*
1076*00b67f09SDavid van Moolenbroek 				 * We didn't match any rdatasets (which means
1077*00b67f09SDavid van Moolenbroek 				 * something went wrong in this
1078*00b67f09SDavid van Moolenbroek 				 * implementation).
1079*00b67f09SDavid van Moolenbroek 				 */
1080*00b67f09SDavid van Moolenbroek 				result = DNS_R_SERVFAIL; /* better code? */
1081*00b67f09SDavid van Moolenbroek 				POST(result);
1082*00b67f09SDavid van Moolenbroek 			} else {
1083*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(rctx->namelist, ansname, link);
1084*00b67f09SDavid van Moolenbroek 				ansname = NULL;
1085*00b67f09SDavid van Moolenbroek 			}
1086*00b67f09SDavid van Moolenbroek 			dns_rdatasetiter_destroy(&rdsiter);
1087*00b67f09SDavid van Moolenbroek 			if (tresult != ISC_R_NOMORE)
1088*00b67f09SDavid van Moolenbroek 				result = DNS_R_SERVFAIL; /* ditto */
1089*00b67f09SDavid van Moolenbroek 			else
1090*00b67f09SDavid van Moolenbroek 				result = ISC_R_SUCCESS;
1091*00b67f09SDavid van Moolenbroek 			goto done;
1092*00b67f09SDavid van Moolenbroek 		} else {
1093*00b67f09SDavid van Moolenbroek 			/*
1094*00b67f09SDavid van Moolenbroek 			 * This is the "normal" case -- an ordinary question
1095*00b67f09SDavid van Moolenbroek 			 * to which we've got the answer.
1096*00b67f09SDavid van Moolenbroek 			 */
1097*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1098*00b67f09SDavid van Moolenbroek 			rctx->rdataset = NULL;
1099*00b67f09SDavid van Moolenbroek 			if (rctx->sigrdataset != NULL) {
1100*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(ansname->list,
1101*00b67f09SDavid van Moolenbroek 						rctx->sigrdataset, link);
1102*00b67f09SDavid van Moolenbroek 				rctx->sigrdataset = NULL;
1103*00b67f09SDavid van Moolenbroek 			}
1104*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(rctx->namelist, ansname, link);
1105*00b67f09SDavid van Moolenbroek 			ansname = NULL;
1106*00b67f09SDavid van Moolenbroek 		}
1107*00b67f09SDavid van Moolenbroek 
1108*00b67f09SDavid van Moolenbroek 	done:
1109*00b67f09SDavid van Moolenbroek 		/*
1110*00b67f09SDavid van Moolenbroek 		 * Free temporary resources
1111*00b67f09SDavid van Moolenbroek 		 */
1112*00b67f09SDavid van Moolenbroek 		if (ansname != NULL) {
1113*00b67f09SDavid van Moolenbroek 			dns_rdataset_t *rdataset;
1114*00b67f09SDavid van Moolenbroek 
1115*00b67f09SDavid van Moolenbroek 			while ((rdataset = ISC_LIST_HEAD(ansname->list))
1116*00b67f09SDavid van Moolenbroek 			       != NULL) {
1117*00b67f09SDavid van Moolenbroek 				ISC_LIST_UNLINK(ansname->list, rdataset, link);
1118*00b67f09SDavid van Moolenbroek 				putrdataset(mctx, &rdataset);
1119*00b67f09SDavid van Moolenbroek 			}
1120*00b67f09SDavid van Moolenbroek 			dns_name_free(ansname, mctx);
1121*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, ansname, sizeof(*ansname));
1122*00b67f09SDavid van Moolenbroek 		}
1123*00b67f09SDavid van Moolenbroek 
1124*00b67f09SDavid van Moolenbroek 		if (node != NULL)
1125*00b67f09SDavid van Moolenbroek 			dns_db_detachnode(db, &node);
1126*00b67f09SDavid van Moolenbroek 		if (db != NULL)
1127*00b67f09SDavid van Moolenbroek 			dns_db_detach(&db);
1128*00b67f09SDavid van Moolenbroek 		if (event != NULL)
1129*00b67f09SDavid van Moolenbroek 			isc_event_free(ISC_EVENT_PTR(&event));
1130*00b67f09SDavid van Moolenbroek 
1131*00b67f09SDavid van Moolenbroek 		/*
1132*00b67f09SDavid van Moolenbroek 		 * Limit the number of restarts.
1133*00b67f09SDavid van Moolenbroek 		 */
1134*00b67f09SDavid van Moolenbroek 		if (want_restart && rctx->restarts == MAX_RESTARTS) {
1135*00b67f09SDavid van Moolenbroek 			want_restart = ISC_FALSE;
1136*00b67f09SDavid van Moolenbroek 			result = ISC_R_QUOTA;
1137*00b67f09SDavid van Moolenbroek 			send_event = ISC_TRUE;
1138*00b67f09SDavid van Moolenbroek 		}
1139*00b67f09SDavid van Moolenbroek 
1140*00b67f09SDavid van Moolenbroek 		/*
1141*00b67f09SDavid van Moolenbroek 		 * Prepare further find with new resources
1142*00b67f09SDavid van Moolenbroek 		 */
1143*00b67f09SDavid van Moolenbroek 		if (want_restart) {
1144*00b67f09SDavid van Moolenbroek 			INSIST(rctx->rdataset == NULL &&
1145*00b67f09SDavid van Moolenbroek 			       rctx->sigrdataset == NULL);
1146*00b67f09SDavid van Moolenbroek 
1147*00b67f09SDavid van Moolenbroek 			result = getrdataset(mctx, &rctx->rdataset);
1148*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1149*00b67f09SDavid van Moolenbroek 				result = getrdataset(mctx, &rctx->sigrdataset);
1150*00b67f09SDavid van Moolenbroek 				if (result != ISC_R_SUCCESS) {
1151*00b67f09SDavid van Moolenbroek 					putrdataset(mctx, &rctx->rdataset);
1152*00b67f09SDavid van Moolenbroek 				}
1153*00b67f09SDavid van Moolenbroek 			}
1154*00b67f09SDavid van Moolenbroek 
1155*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS) {
1156*00b67f09SDavid van Moolenbroek 				want_restart = ISC_FALSE;
1157*00b67f09SDavid van Moolenbroek 				send_event = ISC_TRUE;
1158*00b67f09SDavid van Moolenbroek 			}
1159*00b67f09SDavid van Moolenbroek 		}
1160*00b67f09SDavid van Moolenbroek 	} while (want_restart);
1161*00b67f09SDavid van Moolenbroek 
1162*00b67f09SDavid van Moolenbroek 	if (send_event) {
1163*00b67f09SDavid van Moolenbroek 		isc_task_t *task;
1164*00b67f09SDavid van Moolenbroek 
1165*00b67f09SDavid van Moolenbroek 		while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1166*00b67f09SDavid van Moolenbroek 			ISC_LIST_UNLINK(rctx->namelist, name, link);
1167*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1168*00b67f09SDavid van Moolenbroek 		}
1169*00b67f09SDavid van Moolenbroek 
1170*00b67f09SDavid van Moolenbroek 		rctx->event->result = result;
1171*00b67f09SDavid van Moolenbroek 		rctx->event->vresult = vresult;
1172*00b67f09SDavid van Moolenbroek 		task = rctx->event->ev_sender;
1173*00b67f09SDavid van Moolenbroek 		rctx->event->ev_sender = rctx;
1174*00b67f09SDavid van Moolenbroek 		isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1175*00b67f09SDavid van Moolenbroek 	}
1176*00b67f09SDavid van Moolenbroek 
1177*00b67f09SDavid van Moolenbroek 	UNLOCK(&rctx->lock);
1178*00b67f09SDavid van Moolenbroek }
1179*00b67f09SDavid van Moolenbroek 
1180*00b67f09SDavid van Moolenbroek 
1181*00b67f09SDavid van Moolenbroek static void
suspend(isc_task_t * task,isc_event_t * event)1182*00b67f09SDavid van Moolenbroek suspend(isc_task_t *task, isc_event_t *event) {
1183*00b67f09SDavid van Moolenbroek 	isc_appctx_t *actx = event->ev_arg;
1184*00b67f09SDavid van Moolenbroek 
1185*00b67f09SDavid van Moolenbroek 	UNUSED(task);
1186*00b67f09SDavid van Moolenbroek 
1187*00b67f09SDavid van Moolenbroek 	isc_app_ctxsuspend(actx);
1188*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
1189*00b67f09SDavid van Moolenbroek }
1190*00b67f09SDavid van Moolenbroek 
1191*00b67f09SDavid van Moolenbroek static void
resolve_done(isc_task_t * task,isc_event_t * event)1192*00b67f09SDavid van Moolenbroek resolve_done(isc_task_t *task, isc_event_t *event) {
1193*00b67f09SDavid van Moolenbroek 	resarg_t *resarg = event->ev_arg;
1194*00b67f09SDavid van Moolenbroek 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1195*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
1196*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1197*00b67f09SDavid van Moolenbroek 
1198*00b67f09SDavid van Moolenbroek 	UNUSED(task);
1199*00b67f09SDavid van Moolenbroek 
1200*00b67f09SDavid van Moolenbroek 	LOCK(&resarg->lock);
1201*00b67f09SDavid van Moolenbroek 
1202*00b67f09SDavid van Moolenbroek 	resarg->result = rev->result;
1203*00b67f09SDavid van Moolenbroek 	resarg->vresult = rev->vresult;
1204*00b67f09SDavid van Moolenbroek 	while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1205*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(rev->answerlist, name, link);
1206*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(*resarg->namelist, name, link);
1207*00b67f09SDavid van Moolenbroek 	}
1208*00b67f09SDavid van Moolenbroek 
1209*00b67f09SDavid van Moolenbroek 	dns_client_destroyrestrans(&resarg->trans);
1210*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
1211*00b67f09SDavid van Moolenbroek 
1212*00b67f09SDavid van Moolenbroek 	if (!resarg->canceled) {
1213*00b67f09SDavid van Moolenbroek 		UNLOCK(&resarg->lock);
1214*00b67f09SDavid van Moolenbroek 
1215*00b67f09SDavid van Moolenbroek 		/*
1216*00b67f09SDavid van Moolenbroek 		 * We may or may not be running.  isc__appctx_onrun will
1217*00b67f09SDavid van Moolenbroek 		 * fail if we are currently running otherwise we post a
1218*00b67f09SDavid van Moolenbroek 		 * action to call isc_app_ctxsuspend when we do start
1219*00b67f09SDavid van Moolenbroek 		 * running.
1220*00b67f09SDavid van Moolenbroek 		 */
1221*00b67f09SDavid van Moolenbroek 		result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
1222*00b67f09SDavid van Moolenbroek 					   task, suspend, resarg->actx);
1223*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_ALREADYRUNNING)
1224*00b67f09SDavid van Moolenbroek 			isc_app_ctxsuspend(resarg->actx);
1225*00b67f09SDavid van Moolenbroek 	} else {
1226*00b67f09SDavid van Moolenbroek 		/*
1227*00b67f09SDavid van Moolenbroek 		 * We have already exited from the loop (due to some
1228*00b67f09SDavid van Moolenbroek 		 * unexpected event).  Just clean the arg up.
1229*00b67f09SDavid van Moolenbroek 		 */
1230*00b67f09SDavid van Moolenbroek 		UNLOCK(&resarg->lock);
1231*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&resarg->lock);
1232*00b67f09SDavid van Moolenbroek 		isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1233*00b67f09SDavid van Moolenbroek 	}
1234*00b67f09SDavid van Moolenbroek }
1235*00b67f09SDavid van Moolenbroek 
1236*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_resolve(dns_client_t * client,dns_name_t * name,dns_rdataclass_t rdclass,dns_rdatatype_t type,unsigned int options,dns_namelist_t * namelist)1237*00b67f09SDavid van Moolenbroek dns_client_resolve(dns_client_t *client, dns_name_t *name,
1238*00b67f09SDavid van Moolenbroek 		   dns_rdataclass_t rdclass, dns_rdatatype_t type,
1239*00b67f09SDavid van Moolenbroek 		   unsigned int options, dns_namelist_t *namelist)
1240*00b67f09SDavid van Moolenbroek {
1241*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1242*00b67f09SDavid van Moolenbroek 	isc_appctx_t *actx;
1243*00b67f09SDavid van Moolenbroek 	resarg_t *resarg;
1244*00b67f09SDavid van Moolenbroek 
1245*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1246*00b67f09SDavid van Moolenbroek 	REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1247*00b67f09SDavid van Moolenbroek 
1248*00b67f09SDavid van Moolenbroek 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1249*00b67f09SDavid van Moolenbroek 	    (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
1250*00b67f09SDavid van Moolenbroek 		/*
1251*00b67f09SDavid van Moolenbroek 		 * If the client is run under application's control, we need
1252*00b67f09SDavid van Moolenbroek 		 * to create a new running (sub)environment for this
1253*00b67f09SDavid van Moolenbroek 		 * particular resolution.
1254*00b67f09SDavid van Moolenbroek 		 */
1255*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1256*00b67f09SDavid van Moolenbroek 	} else
1257*00b67f09SDavid van Moolenbroek 		actx = client->actx;
1258*00b67f09SDavid van Moolenbroek 
1259*00b67f09SDavid van Moolenbroek 	resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1260*00b67f09SDavid van Moolenbroek 	if (resarg == NULL)
1261*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
1262*00b67f09SDavid van Moolenbroek 
1263*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&resarg->lock);
1264*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1265*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1266*00b67f09SDavid van Moolenbroek 		return (result);
1267*00b67f09SDavid van Moolenbroek 	}
1268*00b67f09SDavid van Moolenbroek 
1269*00b67f09SDavid van Moolenbroek 	resarg->actx = actx;
1270*00b67f09SDavid van Moolenbroek 	resarg->client = client;
1271*00b67f09SDavid van Moolenbroek 	resarg->result = DNS_R_SERVFAIL;
1272*00b67f09SDavid van Moolenbroek 	resarg->namelist = namelist;
1273*00b67f09SDavid van Moolenbroek 	resarg->trans = NULL;
1274*00b67f09SDavid van Moolenbroek 	resarg->canceled = ISC_FALSE;
1275*00b67f09SDavid van Moolenbroek 	result = dns_client_startresolve(client, name, rdclass, type, options,
1276*00b67f09SDavid van Moolenbroek 					 client->task, resolve_done, resarg,
1277*00b67f09SDavid van Moolenbroek 					 &resarg->trans);
1278*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1279*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&resarg->lock);
1280*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1281*00b67f09SDavid van Moolenbroek 		return (result);
1282*00b67f09SDavid van Moolenbroek 	}
1283*00b67f09SDavid van Moolenbroek 
1284*00b67f09SDavid van Moolenbroek 	/*
1285*00b67f09SDavid van Moolenbroek 	 * Start internal event loop.  It blocks until the entire process
1286*00b67f09SDavid van Moolenbroek 	 * is completed.
1287*00b67f09SDavid van Moolenbroek 	 */
1288*00b67f09SDavid van Moolenbroek 	result = isc_app_ctxrun(actx);
1289*00b67f09SDavid van Moolenbroek 
1290*00b67f09SDavid van Moolenbroek 	LOCK(&resarg->lock);
1291*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1292*00b67f09SDavid van Moolenbroek 		result = resarg->result;
1293*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1294*00b67f09SDavid van Moolenbroek 		/*
1295*00b67f09SDavid van Moolenbroek 		 * If this lookup failed due to some error in DNSSEC
1296*00b67f09SDavid van Moolenbroek 		 * validation, return the validation error code.
1297*00b67f09SDavid van Moolenbroek 		 * XXX: or should we pass the validation result separately?
1298*00b67f09SDavid van Moolenbroek 		 */
1299*00b67f09SDavid van Moolenbroek 		result = resarg->vresult;
1300*00b67f09SDavid van Moolenbroek 	}
1301*00b67f09SDavid van Moolenbroek 	if (resarg->trans != NULL) {
1302*00b67f09SDavid van Moolenbroek 		/*
1303*00b67f09SDavid van Moolenbroek 		 * Unusual termination (perhaps due to signal).  We need some
1304*00b67f09SDavid van Moolenbroek 		 * tricky cleanup process.
1305*00b67f09SDavid van Moolenbroek 		 */
1306*00b67f09SDavid van Moolenbroek 		resarg->canceled = ISC_TRUE;
1307*00b67f09SDavid van Moolenbroek 		dns_client_cancelresolve(resarg->trans);
1308*00b67f09SDavid van Moolenbroek 
1309*00b67f09SDavid van Moolenbroek 		UNLOCK(&resarg->lock);
1310*00b67f09SDavid van Moolenbroek 
1311*00b67f09SDavid van Moolenbroek 		/* resarg will be freed in the event handler. */
1312*00b67f09SDavid van Moolenbroek 	} else {
1313*00b67f09SDavid van Moolenbroek 		UNLOCK(&resarg->lock);
1314*00b67f09SDavid van Moolenbroek 
1315*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&resarg->lock);
1316*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1317*00b67f09SDavid van Moolenbroek 	}
1318*00b67f09SDavid van Moolenbroek 
1319*00b67f09SDavid van Moolenbroek 	return (result);
1320*00b67f09SDavid van Moolenbroek }
1321*00b67f09SDavid van Moolenbroek 
1322*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_startresolve(dns_client_t * client,dns_name_t * name,dns_rdataclass_t rdclass,dns_rdatatype_t type,unsigned int options,isc_task_t * task,isc_taskaction_t action,void * arg,dns_clientrestrans_t ** transp)1323*00b67f09SDavid van Moolenbroek dns_client_startresolve(dns_client_t *client, dns_name_t *name,
1324*00b67f09SDavid van Moolenbroek 			dns_rdataclass_t rdclass, dns_rdatatype_t type,
1325*00b67f09SDavid van Moolenbroek 			unsigned int options, isc_task_t *task,
1326*00b67f09SDavid van Moolenbroek 			isc_taskaction_t action, void *arg,
1327*00b67f09SDavid van Moolenbroek 			dns_clientrestrans_t **transp)
1328*00b67f09SDavid van Moolenbroek {
1329*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
1330*00b67f09SDavid van Moolenbroek 	dns_clientresevent_t *event = NULL;
1331*00b67f09SDavid van Moolenbroek 	resctx_t *rctx = NULL;
1332*00b67f09SDavid van Moolenbroek 	isc_task_t *clone = NULL;
1333*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
1334*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1335*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset, *sigrdataset;
1336*00b67f09SDavid van Moolenbroek 	isc_boolean_t want_dnssec, want_validation, want_cdflag;
1337*00b67f09SDavid van Moolenbroek 
1338*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1339*00b67f09SDavid van Moolenbroek 	REQUIRE(transp != NULL && *transp == NULL);
1340*00b67f09SDavid van Moolenbroek 
1341*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1342*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1343*00b67f09SDavid van Moolenbroek 				   rdclass, &view);
1344*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1345*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1346*00b67f09SDavid van Moolenbroek 		return (result);
1347*00b67f09SDavid van Moolenbroek 
1348*00b67f09SDavid van Moolenbroek 	mctx = client->mctx;
1349*00b67f09SDavid van Moolenbroek 	rdataset = NULL;
1350*00b67f09SDavid van Moolenbroek 	sigrdataset = NULL;
1351*00b67f09SDavid van Moolenbroek 	want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1352*00b67f09SDavid van Moolenbroek 	want_validation = ISC_TF((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
1353*00b67f09SDavid van Moolenbroek 	want_cdflag = ISC_TF((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
1354*00b67f09SDavid van Moolenbroek 
1355*00b67f09SDavid van Moolenbroek 	/*
1356*00b67f09SDavid van Moolenbroek 	 * Prepare some intermediate resources
1357*00b67f09SDavid van Moolenbroek 	 */
1358*00b67f09SDavid van Moolenbroek 	clone = NULL;
1359*00b67f09SDavid van Moolenbroek 	isc_task_attach(task, &clone);
1360*00b67f09SDavid van Moolenbroek 	event = (dns_clientresevent_t *)
1361*00b67f09SDavid van Moolenbroek 		isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE,
1362*00b67f09SDavid van Moolenbroek 				   action, arg, sizeof(*event));
1363*00b67f09SDavid van Moolenbroek 	if (event == NULL) {
1364*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1365*00b67f09SDavid van Moolenbroek 		goto cleanup;
1366*00b67f09SDavid van Moolenbroek 	}
1367*00b67f09SDavid van Moolenbroek 	event->result = DNS_R_SERVFAIL;
1368*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(event->answerlist);
1369*00b67f09SDavid van Moolenbroek 
1370*00b67f09SDavid van Moolenbroek 	rctx = isc_mem_get(mctx, sizeof(*rctx));
1371*00b67f09SDavid van Moolenbroek 	if (rctx == NULL)
1372*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1373*00b67f09SDavid van Moolenbroek 	else {
1374*00b67f09SDavid van Moolenbroek 		result = isc_mutex_init(&rctx->lock);
1375*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1376*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, rctx, sizeof(*rctx));
1377*00b67f09SDavid van Moolenbroek 			rctx = NULL;
1378*00b67f09SDavid van Moolenbroek 		}
1379*00b67f09SDavid van Moolenbroek 	}
1380*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1381*00b67f09SDavid van Moolenbroek 		goto cleanup;
1382*00b67f09SDavid van Moolenbroek 
1383*00b67f09SDavid van Moolenbroek 	result = getrdataset(mctx, &rdataset);
1384*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1385*00b67f09SDavid van Moolenbroek 		goto cleanup;
1386*00b67f09SDavid van Moolenbroek 	rctx->rdataset = rdataset;
1387*00b67f09SDavid van Moolenbroek 
1388*00b67f09SDavid van Moolenbroek 	if (want_dnssec) {
1389*00b67f09SDavid van Moolenbroek 		result = getrdataset(mctx, &sigrdataset);
1390*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1391*00b67f09SDavid van Moolenbroek 			goto cleanup;
1392*00b67f09SDavid van Moolenbroek 	}
1393*00b67f09SDavid van Moolenbroek 	rctx->sigrdataset = sigrdataset;
1394*00b67f09SDavid van Moolenbroek 
1395*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&rctx->name);
1396*00b67f09SDavid van Moolenbroek 	result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL);
1397*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1398*00b67f09SDavid van Moolenbroek 		goto cleanup;
1399*00b67f09SDavid van Moolenbroek 
1400*00b67f09SDavid van Moolenbroek 	rctx->client = client;
1401*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(rctx, link);
1402*00b67f09SDavid van Moolenbroek 	rctx->canceled = ISC_FALSE;
1403*00b67f09SDavid van Moolenbroek 	rctx->task = client->task;
1404*00b67f09SDavid van Moolenbroek 	rctx->type = type;
1405*00b67f09SDavid van Moolenbroek 	rctx->view = view;
1406*00b67f09SDavid van Moolenbroek 	rctx->restarts = 0;
1407*00b67f09SDavid van Moolenbroek 	rctx->fetch = NULL;
1408*00b67f09SDavid van Moolenbroek 	rctx->want_dnssec = want_dnssec;
1409*00b67f09SDavid van Moolenbroek 	rctx->want_validation = want_validation;
1410*00b67f09SDavid van Moolenbroek 	rctx->want_cdflag = want_cdflag;
1411*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(rctx->namelist);
1412*00b67f09SDavid van Moolenbroek 	rctx->event = event;
1413*00b67f09SDavid van Moolenbroek 
1414*00b67f09SDavid van Moolenbroek 	rctx->magic = RCTX_MAGIC;
1415*00b67f09SDavid van Moolenbroek 
1416*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1417*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(client->resctxs, rctx, link);
1418*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1419*00b67f09SDavid van Moolenbroek 
1420*00b67f09SDavid van Moolenbroek 	*transp = (dns_clientrestrans_t *)rctx;
1421*00b67f09SDavid van Moolenbroek 	client_resfind(rctx, NULL);
1422*00b67f09SDavid van Moolenbroek 
1423*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1424*00b67f09SDavid van Moolenbroek 
1425*00b67f09SDavid van Moolenbroek  cleanup:
1426*00b67f09SDavid van Moolenbroek 	if (rdataset != NULL)
1427*00b67f09SDavid van Moolenbroek 		putrdataset(client->mctx, &rdataset);
1428*00b67f09SDavid van Moolenbroek 	if (sigrdataset != NULL)
1429*00b67f09SDavid van Moolenbroek 		putrdataset(client->mctx, &sigrdataset);
1430*00b67f09SDavid van Moolenbroek 	if (rctx != NULL) {
1431*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&rctx->lock);
1432*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, rctx, sizeof(*rctx));
1433*00b67f09SDavid van Moolenbroek 	}
1434*00b67f09SDavid van Moolenbroek 	if (event != NULL)
1435*00b67f09SDavid van Moolenbroek 		isc_event_free(ISC_EVENT_PTR(&event));
1436*00b67f09SDavid van Moolenbroek 	isc_task_detach(&clone);
1437*00b67f09SDavid van Moolenbroek 	dns_view_detach(&view);
1438*00b67f09SDavid van Moolenbroek 
1439*00b67f09SDavid van Moolenbroek 	return (result);
1440*00b67f09SDavid van Moolenbroek }
1441*00b67f09SDavid van Moolenbroek 
1442*00b67f09SDavid van Moolenbroek void
dns_client_cancelresolve(dns_clientrestrans_t * trans)1443*00b67f09SDavid van Moolenbroek dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1444*00b67f09SDavid van Moolenbroek 	resctx_t *rctx;
1445*00b67f09SDavid van Moolenbroek 
1446*00b67f09SDavid van Moolenbroek 	REQUIRE(trans != NULL);
1447*00b67f09SDavid van Moolenbroek 	rctx = (resctx_t *)trans;
1448*00b67f09SDavid van Moolenbroek 	REQUIRE(RCTX_VALID(rctx));
1449*00b67f09SDavid van Moolenbroek 
1450*00b67f09SDavid van Moolenbroek 	LOCK(&rctx->lock);
1451*00b67f09SDavid van Moolenbroek 
1452*00b67f09SDavid van Moolenbroek 	if (!rctx->canceled) {
1453*00b67f09SDavid van Moolenbroek 		rctx->canceled = ISC_TRUE;
1454*00b67f09SDavid van Moolenbroek 		if (rctx->fetch != NULL)
1455*00b67f09SDavid van Moolenbroek 			dns_resolver_cancelfetch(rctx->fetch);
1456*00b67f09SDavid van Moolenbroek 	}
1457*00b67f09SDavid van Moolenbroek 
1458*00b67f09SDavid van Moolenbroek 	UNLOCK(&rctx->lock);
1459*00b67f09SDavid van Moolenbroek }
1460*00b67f09SDavid van Moolenbroek 
1461*00b67f09SDavid van Moolenbroek void
dns_client_freeresanswer(dns_client_t * client,dns_namelist_t * namelist)1462*00b67f09SDavid van Moolenbroek dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1463*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
1464*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset;
1465*00b67f09SDavid van Moolenbroek 
1466*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1467*00b67f09SDavid van Moolenbroek 	REQUIRE(namelist != NULL);
1468*00b67f09SDavid van Moolenbroek 
1469*00b67f09SDavid van Moolenbroek 	while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1470*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(*namelist, name, link);
1471*00b67f09SDavid van Moolenbroek 		while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1472*00b67f09SDavid van Moolenbroek 			ISC_LIST_UNLINK(name->list, rdataset, link);
1473*00b67f09SDavid van Moolenbroek 			putrdataset(client->mctx, &rdataset);
1474*00b67f09SDavid van Moolenbroek 		}
1475*00b67f09SDavid van Moolenbroek 		dns_name_free(name, client->mctx);
1476*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, name, sizeof(*name));
1477*00b67f09SDavid van Moolenbroek 	}
1478*00b67f09SDavid van Moolenbroek }
1479*00b67f09SDavid van Moolenbroek 
1480*00b67f09SDavid van Moolenbroek void
dns_client_destroyrestrans(dns_clientrestrans_t ** transp)1481*00b67f09SDavid van Moolenbroek dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1482*00b67f09SDavid van Moolenbroek 	resctx_t *rctx;
1483*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
1484*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
1485*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_destroyclient = ISC_FALSE;
1486*00b67f09SDavid van Moolenbroek 
1487*00b67f09SDavid van Moolenbroek 	REQUIRE(transp != NULL);
1488*00b67f09SDavid van Moolenbroek 	rctx = (resctx_t *)*transp;
1489*00b67f09SDavid van Moolenbroek 	REQUIRE(RCTX_VALID(rctx));
1490*00b67f09SDavid van Moolenbroek 	REQUIRE(rctx->fetch == NULL);
1491*00b67f09SDavid van Moolenbroek 	REQUIRE(rctx->event == NULL);
1492*00b67f09SDavid van Moolenbroek 	client = rctx->client;
1493*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1494*00b67f09SDavid van Moolenbroek 
1495*00b67f09SDavid van Moolenbroek 	mctx = client->mctx;
1496*00b67f09SDavid van Moolenbroek 	dns_view_detach(&rctx->view);
1497*00b67f09SDavid van Moolenbroek 
1498*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1499*00b67f09SDavid van Moolenbroek 
1500*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LINK_LINKED(rctx, link));
1501*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(client->resctxs, rctx, link);
1502*00b67f09SDavid van Moolenbroek 
1503*00b67f09SDavid van Moolenbroek 	if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1504*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->reqctxs) &&
1505*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->updatectxs))
1506*00b67f09SDavid van Moolenbroek 		need_destroyclient = ISC_TRUE;
1507*00b67f09SDavid van Moolenbroek 
1508*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1509*00b67f09SDavid van Moolenbroek 
1510*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(rctx->namelist));
1511*00b67f09SDavid van Moolenbroek 
1512*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&rctx->lock);
1513*00b67f09SDavid van Moolenbroek 	rctx->magic = 0;
1514*00b67f09SDavid van Moolenbroek 
1515*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, rctx, sizeof(*rctx));
1516*00b67f09SDavid van Moolenbroek 
1517*00b67f09SDavid van Moolenbroek 	if (need_destroyclient)
1518*00b67f09SDavid van Moolenbroek 		destroyclient(&client);
1519*00b67f09SDavid van Moolenbroek 
1520*00b67f09SDavid van Moolenbroek 	*transp = NULL;
1521*00b67f09SDavid van Moolenbroek }
1522*00b67f09SDavid van Moolenbroek 
1523*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_addtrustedkey(dns_client_t * client,dns_rdataclass_t rdclass,dns_name_t * keyname,isc_buffer_t * keydatabuf)1524*00b67f09SDavid van Moolenbroek dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1525*00b67f09SDavid van Moolenbroek 			 dns_name_t *keyname, isc_buffer_t *keydatabuf)
1526*00b67f09SDavid van Moolenbroek {
1527*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1528*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
1529*00b67f09SDavid van Moolenbroek 	dst_key_t *dstkey = NULL;
1530*00b67f09SDavid van Moolenbroek 	dns_keytable_t *secroots = NULL;
1531*00b67f09SDavid van Moolenbroek 
1532*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1533*00b67f09SDavid van Moolenbroek 
1534*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1535*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1536*00b67f09SDavid van Moolenbroek 				   rdclass, &view);
1537*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1538*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1539*00b67f09SDavid van Moolenbroek 		goto cleanup;
1540*00b67f09SDavid van Moolenbroek 
1541*00b67f09SDavid van Moolenbroek 	result = dns_view_getsecroots(view, &secroots);
1542*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1543*00b67f09SDavid van Moolenbroek 		goto cleanup;
1544*00b67f09SDavid van Moolenbroek 
1545*00b67f09SDavid van Moolenbroek 	result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx,
1546*00b67f09SDavid van Moolenbroek 				 &dstkey);
1547*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1548*00b67f09SDavid van Moolenbroek 		goto cleanup;
1549*00b67f09SDavid van Moolenbroek 
1550*00b67f09SDavid van Moolenbroek 	result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
1551*00b67f09SDavid van Moolenbroek 
1552*00b67f09SDavid van Moolenbroek  cleanup:
1553*00b67f09SDavid van Moolenbroek 	if (dstkey != NULL)
1554*00b67f09SDavid van Moolenbroek 		dst_key_free(&dstkey);
1555*00b67f09SDavid van Moolenbroek 	if (view != NULL)
1556*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
1557*00b67f09SDavid van Moolenbroek 	if (secroots != NULL)
1558*00b67f09SDavid van Moolenbroek 		dns_keytable_detach(&secroots);
1559*00b67f09SDavid van Moolenbroek 	return (result);
1560*00b67f09SDavid van Moolenbroek }
1561*00b67f09SDavid van Moolenbroek 
1562*00b67f09SDavid van Moolenbroek /*%
1563*00b67f09SDavid van Moolenbroek  * Simple request routines
1564*00b67f09SDavid van Moolenbroek  */
1565*00b67f09SDavid van Moolenbroek static void
request_done(isc_task_t * task,isc_event_t * event)1566*00b67f09SDavid van Moolenbroek request_done(isc_task_t *task, isc_event_t *event) {
1567*00b67f09SDavid van Moolenbroek 	dns_requestevent_t *reqev = NULL;
1568*00b67f09SDavid van Moolenbroek 	dns_request_t *request;
1569*00b67f09SDavid van Moolenbroek 	isc_result_t result, eresult;
1570*00b67f09SDavid van Moolenbroek 	reqctx_t *ctx;
1571*00b67f09SDavid van Moolenbroek 
1572*00b67f09SDavid van Moolenbroek 	UNUSED(task);
1573*00b67f09SDavid van Moolenbroek 
1574*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1575*00b67f09SDavid van Moolenbroek 	reqev = (dns_requestevent_t *)event;
1576*00b67f09SDavid van Moolenbroek 	request = reqev->request;
1577*00b67f09SDavid van Moolenbroek 	result = eresult = reqev->result;
1578*00b67f09SDavid van Moolenbroek 	ctx = reqev->ev_arg;
1579*00b67f09SDavid van Moolenbroek 	REQUIRE(REQCTX_VALID(ctx));
1580*00b67f09SDavid van Moolenbroek 
1581*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
1582*00b67f09SDavid van Moolenbroek 
1583*00b67f09SDavid van Moolenbroek 	LOCK(&ctx->lock);
1584*00b67f09SDavid van Moolenbroek 
1585*00b67f09SDavid van Moolenbroek 	if (eresult == ISC_R_SUCCESS) {
1586*00b67f09SDavid van Moolenbroek 		result = dns_request_getresponse(request, ctx->event->rmessage,
1587*00b67f09SDavid van Moolenbroek 						 ctx->parseoptions);
1588*00b67f09SDavid van Moolenbroek 	}
1589*00b67f09SDavid van Moolenbroek 
1590*00b67f09SDavid van Moolenbroek 	if (ctx->tsigkey != NULL)
1591*00b67f09SDavid van Moolenbroek 		dns_tsigkey_detach(&ctx->tsigkey);
1592*00b67f09SDavid van Moolenbroek 
1593*00b67f09SDavid van Moolenbroek 	if (ctx->canceled)
1594*00b67f09SDavid van Moolenbroek 		ctx->event->result = ISC_R_CANCELED;
1595*00b67f09SDavid van Moolenbroek 	else
1596*00b67f09SDavid van Moolenbroek 		ctx->event->result = result;
1597*00b67f09SDavid van Moolenbroek 	task = ctx->event->ev_sender;
1598*00b67f09SDavid van Moolenbroek 	ctx->event->ev_sender = ctx;
1599*00b67f09SDavid van Moolenbroek 	isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1600*00b67f09SDavid van Moolenbroek 
1601*00b67f09SDavid van Moolenbroek 	UNLOCK(&ctx->lock);
1602*00b67f09SDavid van Moolenbroek }
1603*00b67f09SDavid van Moolenbroek 
1604*00b67f09SDavid van Moolenbroek static void
localrequest_done(isc_task_t * task,isc_event_t * event)1605*00b67f09SDavid van Moolenbroek localrequest_done(isc_task_t *task, isc_event_t *event) {
1606*00b67f09SDavid van Moolenbroek 	reqarg_t *reqarg = event->ev_arg;
1607*00b67f09SDavid van Moolenbroek 	dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event;
1608*00b67f09SDavid van Moolenbroek 
1609*00b67f09SDavid van Moolenbroek 	UNUSED(task);
1610*00b67f09SDavid van Moolenbroek 
1611*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1612*00b67f09SDavid van Moolenbroek 
1613*00b67f09SDavid van Moolenbroek 	LOCK(&reqarg->lock);
1614*00b67f09SDavid van Moolenbroek 
1615*00b67f09SDavid van Moolenbroek 	reqarg->result = rev->result;
1616*00b67f09SDavid van Moolenbroek 	dns_client_destroyreqtrans(&reqarg->trans);
1617*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
1618*00b67f09SDavid van Moolenbroek 
1619*00b67f09SDavid van Moolenbroek 	if (!reqarg->canceled) {
1620*00b67f09SDavid van Moolenbroek 		UNLOCK(&reqarg->lock);
1621*00b67f09SDavid van Moolenbroek 
1622*00b67f09SDavid van Moolenbroek 		/* Exit from the internal event loop */
1623*00b67f09SDavid van Moolenbroek 		isc_app_ctxsuspend(reqarg->actx);
1624*00b67f09SDavid van Moolenbroek 	} else {
1625*00b67f09SDavid van Moolenbroek 		/*
1626*00b67f09SDavid van Moolenbroek 		 * We have already exited from the loop (due to some
1627*00b67f09SDavid van Moolenbroek 		 * unexpected event).  Just clean the arg up.
1628*00b67f09SDavid van Moolenbroek 		 */
1629*00b67f09SDavid van Moolenbroek 		UNLOCK(&reqarg->lock);
1630*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&reqarg->lock);
1631*00b67f09SDavid van Moolenbroek 		isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1632*00b67f09SDavid van Moolenbroek 	}
1633*00b67f09SDavid van Moolenbroek }
1634*00b67f09SDavid van Moolenbroek 
1635*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_request(dns_client_t * client,dns_message_t * qmessage,dns_message_t * rmessage,isc_sockaddr_t * server,unsigned int options,unsigned int parseoptions,dns_tsec_t * tsec,unsigned int timeout,unsigned int udptimeout,unsigned int udpretries)1636*00b67f09SDavid van Moolenbroek dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1637*00b67f09SDavid van Moolenbroek 		   dns_message_t *rmessage, isc_sockaddr_t *server,
1638*00b67f09SDavid van Moolenbroek 		   unsigned int options, unsigned int parseoptions,
1639*00b67f09SDavid van Moolenbroek 		   dns_tsec_t *tsec, unsigned int timeout,
1640*00b67f09SDavid van Moolenbroek 		   unsigned int udptimeout, unsigned int udpretries)
1641*00b67f09SDavid van Moolenbroek {
1642*00b67f09SDavid van Moolenbroek 	isc_appctx_t *actx;
1643*00b67f09SDavid van Moolenbroek 	reqarg_t *reqarg;
1644*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1645*00b67f09SDavid van Moolenbroek 
1646*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1647*00b67f09SDavid van Moolenbroek 	REQUIRE(qmessage != NULL);
1648*00b67f09SDavid van Moolenbroek 	REQUIRE(rmessage != NULL);
1649*00b67f09SDavid van Moolenbroek 
1650*00b67f09SDavid van Moolenbroek 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1651*00b67f09SDavid van Moolenbroek 	    (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) {
1652*00b67f09SDavid van Moolenbroek 		/*
1653*00b67f09SDavid van Moolenbroek 		 * If the client is run under application's control, we need
1654*00b67f09SDavid van Moolenbroek 		 * to create a new running (sub)environment for this
1655*00b67f09SDavid van Moolenbroek 		 * particular resolution.
1656*00b67f09SDavid van Moolenbroek 		 */
1657*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1658*00b67f09SDavid van Moolenbroek 	} else
1659*00b67f09SDavid van Moolenbroek 		actx = client->actx;
1660*00b67f09SDavid van Moolenbroek 
1661*00b67f09SDavid van Moolenbroek 	reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1662*00b67f09SDavid van Moolenbroek 	if (reqarg == NULL)
1663*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
1664*00b67f09SDavid van Moolenbroek 
1665*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&reqarg->lock);
1666*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1667*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1668*00b67f09SDavid van Moolenbroek 		return (result);
1669*00b67f09SDavid van Moolenbroek 	}
1670*00b67f09SDavid van Moolenbroek 
1671*00b67f09SDavid van Moolenbroek 	reqarg->actx = actx;
1672*00b67f09SDavid van Moolenbroek 	reqarg->client = client;
1673*00b67f09SDavid van Moolenbroek 	reqarg->trans = NULL;
1674*00b67f09SDavid van Moolenbroek 	reqarg->canceled = ISC_FALSE;
1675*00b67f09SDavid van Moolenbroek 
1676*00b67f09SDavid van Moolenbroek 	result = dns_client_startrequest(client, qmessage, rmessage, server,
1677*00b67f09SDavid van Moolenbroek 					 options, parseoptions, tsec, timeout,
1678*00b67f09SDavid van Moolenbroek 					 udptimeout, udpretries,
1679*00b67f09SDavid van Moolenbroek 					 client->task, localrequest_done,
1680*00b67f09SDavid van Moolenbroek 					 reqarg, &reqarg->trans);
1681*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1682*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&reqarg->lock);
1683*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1684*00b67f09SDavid van Moolenbroek 		return (result);
1685*00b67f09SDavid van Moolenbroek 	}
1686*00b67f09SDavid van Moolenbroek 
1687*00b67f09SDavid van Moolenbroek 	/*
1688*00b67f09SDavid van Moolenbroek 	 * Start internal event loop.  It blocks until the entire process
1689*00b67f09SDavid van Moolenbroek 	 * is completed.
1690*00b67f09SDavid van Moolenbroek 	 */
1691*00b67f09SDavid van Moolenbroek 	result = isc_app_ctxrun(actx);
1692*00b67f09SDavid van Moolenbroek 
1693*00b67f09SDavid van Moolenbroek 	LOCK(&reqarg->lock);
1694*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
1695*00b67f09SDavid van Moolenbroek 		result = reqarg->result;
1696*00b67f09SDavid van Moolenbroek 	if (reqarg->trans != NULL) {
1697*00b67f09SDavid van Moolenbroek 		/*
1698*00b67f09SDavid van Moolenbroek 		 * Unusual termination (perhaps due to signal).  We need some
1699*00b67f09SDavid van Moolenbroek 		 * tricky cleanup process.
1700*00b67f09SDavid van Moolenbroek 		 */
1701*00b67f09SDavid van Moolenbroek 		reqarg->canceled = ISC_TRUE;
1702*00b67f09SDavid van Moolenbroek 		dns_client_cancelresolve(reqarg->trans);
1703*00b67f09SDavid van Moolenbroek 
1704*00b67f09SDavid van Moolenbroek 		UNLOCK(&reqarg->lock);
1705*00b67f09SDavid van Moolenbroek 
1706*00b67f09SDavid van Moolenbroek 		/* reqarg will be freed in the event handler. */
1707*00b67f09SDavid van Moolenbroek 	} else {
1708*00b67f09SDavid van Moolenbroek 		UNLOCK(&reqarg->lock);
1709*00b67f09SDavid van Moolenbroek 
1710*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&reqarg->lock);
1711*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1712*00b67f09SDavid van Moolenbroek 	}
1713*00b67f09SDavid van Moolenbroek 
1714*00b67f09SDavid van Moolenbroek 	return (result);
1715*00b67f09SDavid van Moolenbroek }
1716*00b67f09SDavid van Moolenbroek 
1717*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_startrequest(dns_client_t * client,dns_message_t * qmessage,dns_message_t * rmessage,isc_sockaddr_t * server,unsigned int options,unsigned int parseoptions,dns_tsec_t * tsec,unsigned int timeout,unsigned int udptimeout,unsigned int udpretries,isc_task_t * task,isc_taskaction_t action,void * arg,dns_clientreqtrans_t ** transp)1718*00b67f09SDavid van Moolenbroek dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1719*00b67f09SDavid van Moolenbroek 			dns_message_t *rmessage, isc_sockaddr_t *server,
1720*00b67f09SDavid van Moolenbroek 			unsigned int options, unsigned int parseoptions,
1721*00b67f09SDavid van Moolenbroek 			dns_tsec_t *tsec, unsigned int timeout,
1722*00b67f09SDavid van Moolenbroek 			unsigned int udptimeout, unsigned int udpretries,
1723*00b67f09SDavid van Moolenbroek 			isc_task_t *task, isc_taskaction_t action, void *arg,
1724*00b67f09SDavid van Moolenbroek 			dns_clientreqtrans_t **transp)
1725*00b67f09SDavid van Moolenbroek {
1726*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1727*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
1728*00b67f09SDavid van Moolenbroek 	isc_task_t *clone = NULL;
1729*00b67f09SDavid van Moolenbroek 	dns_clientreqevent_t *event = NULL;
1730*00b67f09SDavid van Moolenbroek 	reqctx_t *ctx = NULL;
1731*00b67f09SDavid van Moolenbroek 	dns_tsectype_t tsectype = dns_tsectype_none;
1732*00b67f09SDavid van Moolenbroek 
1733*00b67f09SDavid van Moolenbroek 	UNUSED(options);
1734*00b67f09SDavid van Moolenbroek 
1735*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1736*00b67f09SDavid van Moolenbroek 	REQUIRE(qmessage != NULL);
1737*00b67f09SDavid van Moolenbroek 	REQUIRE(rmessage != NULL);
1738*00b67f09SDavid van Moolenbroek 	REQUIRE(transp != NULL && *transp == NULL);
1739*00b67f09SDavid van Moolenbroek 
1740*00b67f09SDavid van Moolenbroek 	if (tsec != NULL) {
1741*00b67f09SDavid van Moolenbroek 		tsectype = dns_tsec_gettype(tsec);
1742*00b67f09SDavid van Moolenbroek 		if (tsectype != dns_tsectype_tsig)
1743*00b67f09SDavid van Moolenbroek 			return (ISC_R_NOTIMPLEMENTED); /* XXX */
1744*00b67f09SDavid van Moolenbroek 	}
1745*00b67f09SDavid van Moolenbroek 
1746*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1747*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1748*00b67f09SDavid van Moolenbroek 				   qmessage->rdclass, &view);
1749*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1750*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1751*00b67f09SDavid van Moolenbroek 		return (result);
1752*00b67f09SDavid van Moolenbroek 
1753*00b67f09SDavid van Moolenbroek 	clone = NULL;
1754*00b67f09SDavid van Moolenbroek 	isc_task_attach(task, &clone);
1755*00b67f09SDavid van Moolenbroek 	event = (dns_clientreqevent_t *)
1756*00b67f09SDavid van Moolenbroek 		isc_event_allocate(client->mctx, clone,
1757*00b67f09SDavid van Moolenbroek 				   DNS_EVENT_CLIENTREQDONE,
1758*00b67f09SDavid van Moolenbroek 				   action, arg, sizeof(*event));
1759*00b67f09SDavid van Moolenbroek 	if (event == NULL) {
1760*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1761*00b67f09SDavid van Moolenbroek 		goto cleanup;
1762*00b67f09SDavid van Moolenbroek 	}
1763*00b67f09SDavid van Moolenbroek 
1764*00b67f09SDavid van Moolenbroek 	ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1765*00b67f09SDavid van Moolenbroek 	if (ctx == NULL)
1766*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
1767*00b67f09SDavid van Moolenbroek 	else {
1768*00b67f09SDavid van Moolenbroek 		result = isc_mutex_init(&ctx->lock);
1769*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
1770*00b67f09SDavid van Moolenbroek 			isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1771*00b67f09SDavid van Moolenbroek 			ctx = NULL;
1772*00b67f09SDavid van Moolenbroek 		}
1773*00b67f09SDavid van Moolenbroek 	}
1774*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1775*00b67f09SDavid van Moolenbroek 		goto cleanup;
1776*00b67f09SDavid van Moolenbroek 
1777*00b67f09SDavid van Moolenbroek 	ctx->client = client;
1778*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(ctx, link);
1779*00b67f09SDavid van Moolenbroek 	ctx->parseoptions = parseoptions;
1780*00b67f09SDavid van Moolenbroek 	ctx->canceled = ISC_FALSE;
1781*00b67f09SDavid van Moolenbroek 	ctx->event = event;
1782*00b67f09SDavid van Moolenbroek 	ctx->event->rmessage = rmessage;
1783*00b67f09SDavid van Moolenbroek 	ctx->tsigkey = NULL;
1784*00b67f09SDavid van Moolenbroek 	if (tsec != NULL)
1785*00b67f09SDavid van Moolenbroek 		dns_tsec_getkey(tsec, &ctx->tsigkey);
1786*00b67f09SDavid van Moolenbroek 
1787*00b67f09SDavid van Moolenbroek 	ctx->magic = REQCTX_MAGIC;
1788*00b67f09SDavid van Moolenbroek 
1789*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1790*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(client->reqctxs, ctx, link);
1791*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1792*00b67f09SDavid van Moolenbroek 
1793*00b67f09SDavid van Moolenbroek 	ctx->request = NULL;
1794*00b67f09SDavid van Moolenbroek 	result = dns_request_createvia3(view->requestmgr, qmessage, NULL,
1795*00b67f09SDavid van Moolenbroek 					server, options, ctx->tsigkey,
1796*00b67f09SDavid van Moolenbroek 					timeout, udptimeout, udpretries,
1797*00b67f09SDavid van Moolenbroek 					client->task, request_done, ctx,
1798*00b67f09SDavid van Moolenbroek 					&ctx->request);
1799*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
1800*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
1801*00b67f09SDavid van Moolenbroek 		*transp = (dns_clientreqtrans_t *)ctx;
1802*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1803*00b67f09SDavid van Moolenbroek 	}
1804*00b67f09SDavid van Moolenbroek 
1805*00b67f09SDavid van Moolenbroek  cleanup:
1806*00b67f09SDavid van Moolenbroek 	if (ctx != NULL) {
1807*00b67f09SDavid van Moolenbroek 		LOCK(&client->lock);
1808*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1809*00b67f09SDavid van Moolenbroek 		UNLOCK(&client->lock);
1810*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&ctx->lock);
1811*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1812*00b67f09SDavid van Moolenbroek 	}
1813*00b67f09SDavid van Moolenbroek 	if (event != NULL)
1814*00b67f09SDavid van Moolenbroek 		isc_event_free(ISC_EVENT_PTR(&event));
1815*00b67f09SDavid van Moolenbroek 	isc_task_detach(&clone);
1816*00b67f09SDavid van Moolenbroek 	dns_view_detach(&view);
1817*00b67f09SDavid van Moolenbroek 
1818*00b67f09SDavid van Moolenbroek 	return (result);
1819*00b67f09SDavid van Moolenbroek }
1820*00b67f09SDavid van Moolenbroek 
1821*00b67f09SDavid van Moolenbroek void
dns_client_cancelrequest(dns_clientreqtrans_t * trans)1822*00b67f09SDavid van Moolenbroek dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1823*00b67f09SDavid van Moolenbroek 	reqctx_t *ctx;
1824*00b67f09SDavid van Moolenbroek 
1825*00b67f09SDavid van Moolenbroek 	REQUIRE(trans != NULL);
1826*00b67f09SDavid van Moolenbroek 	ctx = (reqctx_t *)trans;
1827*00b67f09SDavid van Moolenbroek 	REQUIRE(REQCTX_VALID(ctx));
1828*00b67f09SDavid van Moolenbroek 
1829*00b67f09SDavid van Moolenbroek 	LOCK(&ctx->lock);
1830*00b67f09SDavid van Moolenbroek 
1831*00b67f09SDavid van Moolenbroek 	if (!ctx->canceled) {
1832*00b67f09SDavid van Moolenbroek 		ctx->canceled = ISC_TRUE;
1833*00b67f09SDavid van Moolenbroek 		if (ctx->request != NULL)
1834*00b67f09SDavid van Moolenbroek 			dns_request_cancel(ctx->request);
1835*00b67f09SDavid van Moolenbroek 	}
1836*00b67f09SDavid van Moolenbroek 
1837*00b67f09SDavid van Moolenbroek 	UNLOCK(&ctx->lock);
1838*00b67f09SDavid van Moolenbroek }
1839*00b67f09SDavid van Moolenbroek 
1840*00b67f09SDavid van Moolenbroek void
dns_client_destroyreqtrans(dns_clientreqtrans_t ** transp)1841*00b67f09SDavid van Moolenbroek dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1842*00b67f09SDavid van Moolenbroek 	reqctx_t *ctx;
1843*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
1844*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
1845*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_destroyclient = ISC_FALSE;
1846*00b67f09SDavid van Moolenbroek 
1847*00b67f09SDavid van Moolenbroek 	REQUIRE(transp != NULL);
1848*00b67f09SDavid van Moolenbroek 	ctx = (reqctx_t *)*transp;
1849*00b67f09SDavid van Moolenbroek 	REQUIRE(REQCTX_VALID(ctx));
1850*00b67f09SDavid van Moolenbroek 	client = ctx->client;
1851*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1852*00b67f09SDavid van Moolenbroek 	REQUIRE(ctx->event == NULL);
1853*00b67f09SDavid van Moolenbroek 	REQUIRE(ctx->request != NULL);
1854*00b67f09SDavid van Moolenbroek 
1855*00b67f09SDavid van Moolenbroek 	dns_request_destroy(&ctx->request);
1856*00b67f09SDavid van Moolenbroek 	mctx = client->mctx;
1857*00b67f09SDavid van Moolenbroek 
1858*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
1859*00b67f09SDavid van Moolenbroek 
1860*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LINK_LINKED(ctx, link));
1861*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1862*00b67f09SDavid van Moolenbroek 
1863*00b67f09SDavid van Moolenbroek 	if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
1864*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->reqctxs) &&
1865*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->updatectxs)) {
1866*00b67f09SDavid van Moolenbroek 		need_destroyclient = ISC_TRUE;
1867*00b67f09SDavid van Moolenbroek 	}
1868*00b67f09SDavid van Moolenbroek 
1869*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
1870*00b67f09SDavid van Moolenbroek 
1871*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&ctx->lock);
1872*00b67f09SDavid van Moolenbroek 	ctx->magic = 0;
1873*00b67f09SDavid van Moolenbroek 
1874*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, ctx, sizeof(*ctx));
1875*00b67f09SDavid van Moolenbroek 
1876*00b67f09SDavid van Moolenbroek 	if (need_destroyclient)
1877*00b67f09SDavid van Moolenbroek 		destroyclient(&client);
1878*00b67f09SDavid van Moolenbroek 
1879*00b67f09SDavid van Moolenbroek 	*transp = NULL;
1880*00b67f09SDavid van Moolenbroek }
1881*00b67f09SDavid van Moolenbroek 
1882*00b67f09SDavid van Moolenbroek /*%
1883*00b67f09SDavid van Moolenbroek  * Dynamic update routines
1884*00b67f09SDavid van Moolenbroek  */
1885*00b67f09SDavid van Moolenbroek static isc_result_t
rcode2result(dns_rcode_t rcode)1886*00b67f09SDavid van Moolenbroek rcode2result(dns_rcode_t rcode) {
1887*00b67f09SDavid van Moolenbroek 	/* XXX: isn't there a similar function? */
1888*00b67f09SDavid van Moolenbroek 	switch (rcode) {
1889*00b67f09SDavid van Moolenbroek 	case dns_rcode_formerr:
1890*00b67f09SDavid van Moolenbroek 		return (DNS_R_FORMERR);
1891*00b67f09SDavid van Moolenbroek 	case dns_rcode_servfail:
1892*00b67f09SDavid van Moolenbroek 		return (DNS_R_SERVFAIL);
1893*00b67f09SDavid van Moolenbroek 	case dns_rcode_nxdomain:
1894*00b67f09SDavid van Moolenbroek 		return (DNS_R_NXDOMAIN);
1895*00b67f09SDavid van Moolenbroek 	case dns_rcode_notimp:
1896*00b67f09SDavid van Moolenbroek 		return (DNS_R_NOTIMP);
1897*00b67f09SDavid van Moolenbroek 	case dns_rcode_refused:
1898*00b67f09SDavid van Moolenbroek 		return (DNS_R_REFUSED);
1899*00b67f09SDavid van Moolenbroek 	case dns_rcode_yxdomain:
1900*00b67f09SDavid van Moolenbroek 		return (DNS_R_YXDOMAIN);
1901*00b67f09SDavid van Moolenbroek 	case dns_rcode_yxrrset:
1902*00b67f09SDavid van Moolenbroek 		return (DNS_R_YXRRSET);
1903*00b67f09SDavid van Moolenbroek 	case dns_rcode_nxrrset:
1904*00b67f09SDavid van Moolenbroek 		return (DNS_R_NXRRSET);
1905*00b67f09SDavid van Moolenbroek 	case dns_rcode_notauth:
1906*00b67f09SDavid van Moolenbroek 		return (DNS_R_NOTAUTH);
1907*00b67f09SDavid van Moolenbroek 	case dns_rcode_notzone:
1908*00b67f09SDavid van Moolenbroek 		return (DNS_R_NOTZONE);
1909*00b67f09SDavid van Moolenbroek 	case dns_rcode_badvers:
1910*00b67f09SDavid van Moolenbroek 		return (DNS_R_BADVERS);
1911*00b67f09SDavid van Moolenbroek 	}
1912*00b67f09SDavid van Moolenbroek 
1913*00b67f09SDavid van Moolenbroek 	return (ISC_R_FAILURE);
1914*00b67f09SDavid van Moolenbroek }
1915*00b67f09SDavid van Moolenbroek 
1916*00b67f09SDavid van Moolenbroek static void
update_sendevent(updatectx_t * uctx,isc_result_t result)1917*00b67f09SDavid van Moolenbroek update_sendevent(updatectx_t *uctx, isc_result_t result) {
1918*00b67f09SDavid van Moolenbroek 	isc_task_t *task;
1919*00b67f09SDavid van Moolenbroek 
1920*00b67f09SDavid van Moolenbroek 	dns_message_destroy(&uctx->updatemsg);
1921*00b67f09SDavid van Moolenbroek 	if (uctx->tsigkey != NULL)
1922*00b67f09SDavid van Moolenbroek 		dns_tsigkey_detach(&uctx->tsigkey);
1923*00b67f09SDavid van Moolenbroek 	if (uctx->sig0key != NULL)
1924*00b67f09SDavid van Moolenbroek 		dst_key_free(&uctx->sig0key);
1925*00b67f09SDavid van Moolenbroek 
1926*00b67f09SDavid van Moolenbroek 	if (uctx->canceled)
1927*00b67f09SDavid van Moolenbroek 		uctx->event->result = ISC_R_CANCELED;
1928*00b67f09SDavid van Moolenbroek 	else
1929*00b67f09SDavid van Moolenbroek 		uctx->event->result = result;
1930*00b67f09SDavid van Moolenbroek 	uctx->event->state = uctx->state;
1931*00b67f09SDavid van Moolenbroek 	task = uctx->event->ev_sender;
1932*00b67f09SDavid van Moolenbroek 	uctx->event->ev_sender = uctx;
1933*00b67f09SDavid van Moolenbroek 	isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1934*00b67f09SDavid van Moolenbroek }
1935*00b67f09SDavid van Moolenbroek 
1936*00b67f09SDavid van Moolenbroek static void
update_done(isc_task_t * task,isc_event_t * event)1937*00b67f09SDavid van Moolenbroek update_done(isc_task_t *task, isc_event_t *event) {
1938*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1939*00b67f09SDavid van Moolenbroek 	dns_requestevent_t *reqev = NULL;
1940*00b67f09SDavid van Moolenbroek 	dns_request_t *request;
1941*00b67f09SDavid van Moolenbroek 	dns_message_t *answer = NULL;
1942*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx = event->ev_arg;
1943*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
1944*00b67f09SDavid van Moolenbroek 	unsigned int timeout;
1945*00b67f09SDavid van Moolenbroek 
1946*00b67f09SDavid van Moolenbroek 	UNUSED(task);
1947*00b67f09SDavid van Moolenbroek 
1948*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1949*00b67f09SDavid van Moolenbroek 	reqev = (dns_requestevent_t *)event;
1950*00b67f09SDavid van Moolenbroek 	request = reqev->request;
1951*00b67f09SDavid van Moolenbroek 	REQUIRE(UCTX_VALID(uctx));
1952*00b67f09SDavid van Moolenbroek 	client = uctx->client;
1953*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
1954*00b67f09SDavid van Moolenbroek 
1955*00b67f09SDavid van Moolenbroek 	result = reqev->result;
1956*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1957*00b67f09SDavid van Moolenbroek 		goto out;
1958*00b67f09SDavid van Moolenbroek 
1959*00b67f09SDavid van Moolenbroek 	result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
1960*00b67f09SDavid van Moolenbroek 				    &answer);
1961*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1962*00b67f09SDavid van Moolenbroek 		goto out;
1963*00b67f09SDavid van Moolenbroek 	uctx->state = dns_clientupdatestate_done;
1964*00b67f09SDavid van Moolenbroek 	result = dns_request_getresponse(request, answer,
1965*00b67f09SDavid van Moolenbroek 					 DNS_MESSAGEPARSE_PRESERVEORDER);
1966*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror)
1967*00b67f09SDavid van Moolenbroek 		result = rcode2result(answer->rcode);
1968*00b67f09SDavid van Moolenbroek 
1969*00b67f09SDavid van Moolenbroek  out:
1970*00b67f09SDavid van Moolenbroek 	if (answer != NULL)
1971*00b67f09SDavid van Moolenbroek 		dns_message_destroy(&answer);
1972*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
1973*00b67f09SDavid van Moolenbroek 
1974*00b67f09SDavid van Moolenbroek 	LOCK(&uctx->lock);
1975*00b67f09SDavid van Moolenbroek 	uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1976*00b67f09SDavid van Moolenbroek 	dns_request_destroy(&uctx->updatereq);
1977*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS && !uctx->canceled &&
1978*00b67f09SDavid van Moolenbroek 	    uctx->currentserver != NULL) {
1979*00b67f09SDavid van Moolenbroek 		dns_message_renderreset(uctx->updatemsg);
1980*00b67f09SDavid van Moolenbroek 		dns_message_settsigkey(uctx->updatemsg, NULL);
1981*00b67f09SDavid van Moolenbroek 
1982*00b67f09SDavid van Moolenbroek 		timeout = client->update_timeout / uctx->nservers;
1983*00b67f09SDavid van Moolenbroek 		if (timeout < MIN_UPDATE_TIMEOUT)
1984*00b67f09SDavid van Moolenbroek 			timeout = MIN_UPDATE_TIMEOUT;
1985*00b67f09SDavid van Moolenbroek 		result = dns_request_createvia3(uctx->view->requestmgr,
1986*00b67f09SDavid van Moolenbroek 						uctx->updatemsg,
1987*00b67f09SDavid van Moolenbroek 						NULL,
1988*00b67f09SDavid van Moolenbroek 						uctx->currentserver, 0,
1989*00b67f09SDavid van Moolenbroek 						uctx->tsigkey,
1990*00b67f09SDavid van Moolenbroek 						timeout,
1991*00b67f09SDavid van Moolenbroek 						client->update_udptimeout,
1992*00b67f09SDavid van Moolenbroek 						client->update_udpretries,
1993*00b67f09SDavid van Moolenbroek 						client->task,
1994*00b67f09SDavid van Moolenbroek 						update_done, uctx,
1995*00b67f09SDavid van Moolenbroek 						&uctx->updatereq);
1996*00b67f09SDavid van Moolenbroek 		UNLOCK(&uctx->lock);
1997*00b67f09SDavid van Moolenbroek 
1998*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
1999*00b67f09SDavid van Moolenbroek 			/* XXX: should we keep the 'done' state here? */
2000*00b67f09SDavid van Moolenbroek 			uctx->state = dns_clientupdatestate_sent;
2001*00b67f09SDavid van Moolenbroek 			return;
2002*00b67f09SDavid van Moolenbroek 		}
2003*00b67f09SDavid van Moolenbroek 	} else
2004*00b67f09SDavid van Moolenbroek 		UNLOCK(&uctx->lock);
2005*00b67f09SDavid van Moolenbroek 
2006*00b67f09SDavid van Moolenbroek 	update_sendevent(uctx, result);
2007*00b67f09SDavid van Moolenbroek }
2008*00b67f09SDavid van Moolenbroek 
2009*00b67f09SDavid van Moolenbroek static isc_result_t
send_update(updatectx_t * uctx)2010*00b67f09SDavid van Moolenbroek send_update(updatectx_t *uctx) {
2011*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2012*00b67f09SDavid van Moolenbroek 	dns_name_t *name = NULL;
2013*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset = NULL;
2014*00b67f09SDavid van Moolenbroek 	dns_client_t *client = uctx->client;
2015*00b67f09SDavid van Moolenbroek 	unsigned int timeout;
2016*00b67f09SDavid van Moolenbroek 
2017*00b67f09SDavid van Moolenbroek 	REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
2018*00b67f09SDavid van Moolenbroek 
2019*00b67f09SDavid van Moolenbroek 	result = dns_message_gettempname(uctx->updatemsg, &name);
2020*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2021*00b67f09SDavid van Moolenbroek 		return (result);
2022*00b67f09SDavid van Moolenbroek 	dns_name_init(name, NULL);
2023*00b67f09SDavid van Moolenbroek 	dns_name_clone(uctx->zonename, name);
2024*00b67f09SDavid van Moolenbroek 	result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
2025*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2026*00b67f09SDavid van Moolenbroek 		dns_message_puttempname(uctx->updatemsg, &name);
2027*00b67f09SDavid van Moolenbroek 		return (result);
2028*00b67f09SDavid van Moolenbroek 	}
2029*00b67f09SDavid van Moolenbroek 	dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2030*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(name->list);
2031*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(name->list, rdataset, link);
2032*00b67f09SDavid van Moolenbroek 	dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
2033*00b67f09SDavid van Moolenbroek 	if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
2034*00b67f09SDavid van Moolenbroek 		result = dns_message_setsig0key(uctx->updatemsg,
2035*00b67f09SDavid van Moolenbroek 						uctx->sig0key);
2036*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2037*00b67f09SDavid van Moolenbroek 			return (result);
2038*00b67f09SDavid van Moolenbroek 	}
2039*00b67f09SDavid van Moolenbroek 	timeout = client->update_timeout / uctx->nservers;
2040*00b67f09SDavid van Moolenbroek 	if (timeout < MIN_UPDATE_TIMEOUT)
2041*00b67f09SDavid van Moolenbroek 		timeout = MIN_UPDATE_TIMEOUT;
2042*00b67f09SDavid van Moolenbroek 	result = dns_request_createvia3(uctx->view->requestmgr,
2043*00b67f09SDavid van Moolenbroek 					uctx->updatemsg,
2044*00b67f09SDavid van Moolenbroek 					NULL, uctx->currentserver, 0,
2045*00b67f09SDavid van Moolenbroek 					uctx->tsigkey, timeout,
2046*00b67f09SDavid van Moolenbroek 					client->update_udptimeout,
2047*00b67f09SDavid van Moolenbroek 					client->update_udpretries,
2048*00b67f09SDavid van Moolenbroek 					client->task, update_done, uctx,
2049*00b67f09SDavid van Moolenbroek 					&uctx->updatereq);
2050*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS &&
2051*00b67f09SDavid van Moolenbroek 	    uctx->state == dns_clientupdatestate_prepare) {
2052*00b67f09SDavid van Moolenbroek 		uctx->state = dns_clientupdatestate_sent;
2053*00b67f09SDavid van Moolenbroek 	}
2054*00b67f09SDavid van Moolenbroek 
2055*00b67f09SDavid van Moolenbroek 	return (result);
2056*00b67f09SDavid van Moolenbroek }
2057*00b67f09SDavid van Moolenbroek 
2058*00b67f09SDavid van Moolenbroek static void
resolveaddr_done(isc_task_t * task,isc_event_t * event)2059*00b67f09SDavid van Moolenbroek resolveaddr_done(isc_task_t *task, isc_event_t *event) {
2060*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2061*00b67f09SDavid van Moolenbroek 	int family;
2062*00b67f09SDavid van Moolenbroek 	dns_rdatatype_t qtype;
2063*00b67f09SDavid van Moolenbroek 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2064*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
2065*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset;
2066*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx;
2067*00b67f09SDavid van Moolenbroek 	isc_boolean_t completed = ISC_FALSE;
2068*00b67f09SDavid van Moolenbroek 
2069*00b67f09SDavid van Moolenbroek 	UNUSED(task);
2070*00b67f09SDavid van Moolenbroek 
2071*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_arg != NULL);
2072*00b67f09SDavid van Moolenbroek 	uctx = *(updatectx_t **)event->ev_arg;
2073*00b67f09SDavid van Moolenbroek 	REQUIRE(UCTX_VALID(uctx));
2074*00b67f09SDavid van Moolenbroek 
2075*00b67f09SDavid van Moolenbroek 	if (event->ev_arg == &uctx->bp4) {
2076*00b67f09SDavid van Moolenbroek 		family = AF_INET;
2077*00b67f09SDavid van Moolenbroek 		qtype = dns_rdatatype_a;
2078*00b67f09SDavid van Moolenbroek 		LOCK(&uctx->lock);
2079*00b67f09SDavid van Moolenbroek 		dns_client_destroyrestrans(&uctx->restrans);
2080*00b67f09SDavid van Moolenbroek 		UNLOCK(&uctx->lock);
2081*00b67f09SDavid van Moolenbroek 	} else {
2082*00b67f09SDavid van Moolenbroek 		INSIST(event->ev_arg == &uctx->bp6);
2083*00b67f09SDavid van Moolenbroek 		family = AF_INET6;
2084*00b67f09SDavid van Moolenbroek 		qtype = dns_rdatatype_aaaa;
2085*00b67f09SDavid van Moolenbroek 		LOCK(&uctx->lock);
2086*00b67f09SDavid van Moolenbroek 		dns_client_destroyrestrans(&uctx->restrans2);
2087*00b67f09SDavid van Moolenbroek 		UNLOCK(&uctx->lock);
2088*00b67f09SDavid van Moolenbroek 	}
2089*00b67f09SDavid van Moolenbroek 
2090*00b67f09SDavid van Moolenbroek 	result = rev->result;
2091*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2092*00b67f09SDavid van Moolenbroek 		goto done;
2093*00b67f09SDavid van Moolenbroek 
2094*00b67f09SDavid van Moolenbroek 	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2095*00b67f09SDavid van Moolenbroek 	     name = ISC_LIST_NEXT(name, link)) {
2096*00b67f09SDavid van Moolenbroek 		for (rdataset = ISC_LIST_HEAD(name->list);
2097*00b67f09SDavid van Moolenbroek 		     rdataset != NULL;
2098*00b67f09SDavid van Moolenbroek 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2099*00b67f09SDavid van Moolenbroek 			if (!dns_rdataset_isassociated(rdataset))
2100*00b67f09SDavid van Moolenbroek 				continue;
2101*00b67f09SDavid van Moolenbroek 			if (rdataset->type != qtype)
2102*00b67f09SDavid van Moolenbroek 				continue;
2103*00b67f09SDavid van Moolenbroek 
2104*00b67f09SDavid van Moolenbroek 			for (result = dns_rdataset_first(rdataset);
2105*00b67f09SDavid van Moolenbroek 			     result == ISC_R_SUCCESS;
2106*00b67f09SDavid van Moolenbroek 			     result = dns_rdataset_next(rdataset)) {
2107*00b67f09SDavid van Moolenbroek 				dns_rdata_t rdata;
2108*00b67f09SDavid van Moolenbroek 				dns_rdata_in_a_t rdata_a;
2109*00b67f09SDavid van Moolenbroek 				dns_rdata_in_aaaa_t rdata_aaaa;
2110*00b67f09SDavid van Moolenbroek 				isc_sockaddr_t *sa;
2111*00b67f09SDavid van Moolenbroek 
2112*00b67f09SDavid van Moolenbroek 				sa = isc_mem_get(uctx->client->mctx,
2113*00b67f09SDavid van Moolenbroek 						 sizeof(*sa));
2114*00b67f09SDavid van Moolenbroek 				if (sa == NULL) {
2115*00b67f09SDavid van Moolenbroek 					/*
2116*00b67f09SDavid van Moolenbroek 					 * If we fail to get a sockaddr,
2117*00b67f09SDavid van Moolenbroek 					 we simply move forward with the
2118*00b67f09SDavid van Moolenbroek 					 * addresses we've got so far.
2119*00b67f09SDavid van Moolenbroek 					 */
2120*00b67f09SDavid van Moolenbroek 					goto done;
2121*00b67f09SDavid van Moolenbroek 				}
2122*00b67f09SDavid van Moolenbroek 
2123*00b67f09SDavid van Moolenbroek 				dns_rdata_init(&rdata);
2124*00b67f09SDavid van Moolenbroek 				switch (family) {
2125*00b67f09SDavid van Moolenbroek 				case AF_INET:
2126*00b67f09SDavid van Moolenbroek 					dns_rdataset_current(rdataset, &rdata);
2127*00b67f09SDavid van Moolenbroek 					result = dns_rdata_tostruct(&rdata, &rdata_a,
2128*00b67f09SDavid van Moolenbroek 								    NULL);
2129*00b67f09SDavid van Moolenbroek 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
2130*00b67f09SDavid van Moolenbroek 					isc_sockaddr_fromin(sa,
2131*00b67f09SDavid van Moolenbroek 							    &rdata_a.in_addr,
2132*00b67f09SDavid van Moolenbroek 							    53);
2133*00b67f09SDavid van Moolenbroek 					dns_rdata_freestruct(&rdata_a);
2134*00b67f09SDavid van Moolenbroek 					break;
2135*00b67f09SDavid van Moolenbroek 				case AF_INET6:
2136*00b67f09SDavid van Moolenbroek 					dns_rdataset_current(rdataset, &rdata);
2137*00b67f09SDavid van Moolenbroek 					result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
2138*00b67f09SDavid van Moolenbroek 								    NULL);
2139*00b67f09SDavid van Moolenbroek 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
2140*00b67f09SDavid van Moolenbroek 					isc_sockaddr_fromin6(sa,
2141*00b67f09SDavid van Moolenbroek 							     &rdata_aaaa.in6_addr,
2142*00b67f09SDavid van Moolenbroek 							     53);
2143*00b67f09SDavid van Moolenbroek 					dns_rdata_freestruct(&rdata_aaaa);
2144*00b67f09SDavid van Moolenbroek 					break;
2145*00b67f09SDavid van Moolenbroek 				}
2146*00b67f09SDavid van Moolenbroek 
2147*00b67f09SDavid van Moolenbroek 				ISC_LINK_INIT(sa, link);
2148*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(uctx->servers, sa, link);
2149*00b67f09SDavid van Moolenbroek 				uctx->nservers++;
2150*00b67f09SDavid van Moolenbroek 			}
2151*00b67f09SDavid van Moolenbroek 		}
2152*00b67f09SDavid van Moolenbroek 	}
2153*00b67f09SDavid van Moolenbroek 
2154*00b67f09SDavid van Moolenbroek  done:
2155*00b67f09SDavid van Moolenbroek 	dns_client_freeresanswer(uctx->client, &rev->answerlist);
2156*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
2157*00b67f09SDavid van Moolenbroek 
2158*00b67f09SDavid van Moolenbroek 	LOCK(&uctx->lock);
2159*00b67f09SDavid van Moolenbroek 	if (uctx->restrans == NULL && uctx->restrans2 == NULL)
2160*00b67f09SDavid van Moolenbroek 		completed = ISC_TRUE;
2161*00b67f09SDavid van Moolenbroek 	UNLOCK(&uctx->lock);
2162*00b67f09SDavid van Moolenbroek 
2163*00b67f09SDavid van Moolenbroek 	if (completed) {
2164*00b67f09SDavid van Moolenbroek 		INSIST(uctx->currentserver == NULL);
2165*00b67f09SDavid van Moolenbroek 		uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2166*00b67f09SDavid van Moolenbroek 		if (uctx->currentserver != NULL && !uctx->canceled)
2167*00b67f09SDavid van Moolenbroek 			send_update(uctx);
2168*00b67f09SDavid van Moolenbroek 		else {
2169*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS)
2170*00b67f09SDavid van Moolenbroek 				result = ISC_R_NOTFOUND;
2171*00b67f09SDavid van Moolenbroek 			update_sendevent(uctx, result);
2172*00b67f09SDavid van Moolenbroek 		}
2173*00b67f09SDavid van Moolenbroek 	}
2174*00b67f09SDavid van Moolenbroek }
2175*00b67f09SDavid van Moolenbroek 
2176*00b67f09SDavid van Moolenbroek static isc_result_t
process_soa(updatectx_t * uctx,dns_rdataset_t * soaset,dns_name_t * soaname)2177*00b67f09SDavid van Moolenbroek process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) {
2178*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2179*00b67f09SDavid van Moolenbroek 	dns_rdata_t soarr = DNS_RDATA_INIT;
2180*00b67f09SDavid van Moolenbroek 	dns_rdata_soa_t soa;
2181*00b67f09SDavid van Moolenbroek 	dns_name_t primary;
2182*00b67f09SDavid van Moolenbroek 
2183*00b67f09SDavid van Moolenbroek 	result = dns_rdataset_first(soaset);
2184*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2185*00b67f09SDavid van Moolenbroek 		return (result);
2186*00b67f09SDavid van Moolenbroek 	dns_rdata_init(&soarr);
2187*00b67f09SDavid van Moolenbroek 	dns_rdataset_current(soaset, &soarr);
2188*00b67f09SDavid van Moolenbroek 	result = dns_rdata_tostruct(&soarr, &soa, NULL);
2189*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2190*00b67f09SDavid van Moolenbroek 		return (result);
2191*00b67f09SDavid van Moolenbroek 
2192*00b67f09SDavid van Moolenbroek 	dns_name_init(&primary, NULL);
2193*00b67f09SDavid van Moolenbroek 	dns_name_clone(&soa.origin, &primary);
2194*00b67f09SDavid van Moolenbroek 
2195*00b67f09SDavid van Moolenbroek 	if (uctx->zonename == NULL) {
2196*00b67f09SDavid van Moolenbroek 		uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2197*00b67f09SDavid van Moolenbroek 		result = dns_name_copy(soaname, uctx->zonename, NULL);
2198*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2199*00b67f09SDavid van Moolenbroek 			goto out;
2200*00b67f09SDavid van Moolenbroek 	}
2201*00b67f09SDavid van Moolenbroek 
2202*00b67f09SDavid van Moolenbroek 	if (uctx->currentserver != NULL)
2203*00b67f09SDavid van Moolenbroek 		result = send_update(uctx);
2204*00b67f09SDavid van Moolenbroek 	else {
2205*00b67f09SDavid van Moolenbroek 		/*
2206*00b67f09SDavid van Moolenbroek 		 * Get addresses of the primary server.  We don't use the ADB
2207*00b67f09SDavid van Moolenbroek 		 * feature so that we could avoid caching data.
2208*00b67f09SDavid van Moolenbroek 		 */
2209*00b67f09SDavid van Moolenbroek 		LOCK(&uctx->lock);
2210*00b67f09SDavid van Moolenbroek 		uctx->bp4 = uctx;
2211*00b67f09SDavid van Moolenbroek 		result = dns_client_startresolve(uctx->client, &primary,
2212*00b67f09SDavid van Moolenbroek 						 uctx->rdclass,
2213*00b67f09SDavid van Moolenbroek 						 dns_rdatatype_a,
2214*00b67f09SDavid van Moolenbroek 						 0, uctx->client->task,
2215*00b67f09SDavid van Moolenbroek 						 resolveaddr_done, &uctx->bp4,
2216*00b67f09SDavid van Moolenbroek 						 &uctx->restrans);
2217*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
2218*00b67f09SDavid van Moolenbroek 			uctx->bp6 = uctx;
2219*00b67f09SDavid van Moolenbroek 			result = dns_client_startresolve(uctx->client,
2220*00b67f09SDavid van Moolenbroek 							 &primary,
2221*00b67f09SDavid van Moolenbroek 							 uctx->rdclass,
2222*00b67f09SDavid van Moolenbroek 							 dns_rdatatype_aaaa,
2223*00b67f09SDavid van Moolenbroek 							 0, uctx->client->task,
2224*00b67f09SDavid van Moolenbroek 							 resolveaddr_done,
2225*00b67f09SDavid van Moolenbroek 							 &uctx->bp6,
2226*00b67f09SDavid van Moolenbroek 							 &uctx->restrans2);
2227*00b67f09SDavid van Moolenbroek 		}
2228*00b67f09SDavid van Moolenbroek 		UNLOCK(&uctx->lock);
2229*00b67f09SDavid van Moolenbroek 	}
2230*00b67f09SDavid van Moolenbroek 
2231*00b67f09SDavid van Moolenbroek  out:
2232*00b67f09SDavid van Moolenbroek 	dns_rdata_freestruct(&soa);
2233*00b67f09SDavid van Moolenbroek 
2234*00b67f09SDavid van Moolenbroek 	return (result);
2235*00b67f09SDavid van Moolenbroek }
2236*00b67f09SDavid van Moolenbroek 
2237*00b67f09SDavid van Moolenbroek static void
receive_soa(isc_task_t * task,isc_event_t * event)2238*00b67f09SDavid van Moolenbroek receive_soa(isc_task_t *task, isc_event_t *event) {
2239*00b67f09SDavid van Moolenbroek 	dns_requestevent_t *reqev = NULL;
2240*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx;
2241*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
2242*00b67f09SDavid van Moolenbroek 	isc_result_t result, eresult;
2243*00b67f09SDavid van Moolenbroek 	dns_request_t *request;
2244*00b67f09SDavid van Moolenbroek 	dns_message_t *rcvmsg = NULL;
2245*00b67f09SDavid van Moolenbroek 	dns_section_t section;
2246*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *soaset = NULL;
2247*00b67f09SDavid van Moolenbroek 	int pass = 0;
2248*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
2249*00b67f09SDavid van Moolenbroek 	dns_message_t *soaquery = NULL;
2250*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *addr;
2251*00b67f09SDavid van Moolenbroek 	isc_boolean_t seencname = ISC_FALSE;
2252*00b67f09SDavid van Moolenbroek 	isc_boolean_t droplabel = ISC_FALSE;
2253*00b67f09SDavid van Moolenbroek 	dns_name_t tname;
2254*00b67f09SDavid van Moolenbroek 	unsigned int nlabels;
2255*00b67f09SDavid van Moolenbroek 
2256*00b67f09SDavid van Moolenbroek 	UNUSED(task);
2257*00b67f09SDavid van Moolenbroek 
2258*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2259*00b67f09SDavid van Moolenbroek 	reqev = (dns_requestevent_t *)event;
2260*00b67f09SDavid van Moolenbroek 	request = reqev->request;
2261*00b67f09SDavid van Moolenbroek 	result = eresult = reqev->result;
2262*00b67f09SDavid van Moolenbroek 	POST(result);
2263*00b67f09SDavid van Moolenbroek 	uctx = reqev->ev_arg;
2264*00b67f09SDavid van Moolenbroek 	client = uctx->client;
2265*00b67f09SDavid van Moolenbroek 	soaquery = uctx->soaquery;
2266*00b67f09SDavid van Moolenbroek 	addr = uctx->currentserver;
2267*00b67f09SDavid van Moolenbroek 	INSIST(addr != NULL);
2268*00b67f09SDavid van Moolenbroek 
2269*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
2270*00b67f09SDavid van Moolenbroek 
2271*00b67f09SDavid van Moolenbroek 	if (eresult != ISC_R_SUCCESS) {
2272*00b67f09SDavid van Moolenbroek 		result = eresult;
2273*00b67f09SDavid van Moolenbroek 		goto out;
2274*00b67f09SDavid van Moolenbroek 	}
2275*00b67f09SDavid van Moolenbroek 
2276*00b67f09SDavid van Moolenbroek 	result = dns_message_create(uctx->client->mctx,
2277*00b67f09SDavid van Moolenbroek 				    DNS_MESSAGE_INTENTPARSE, &rcvmsg);
2278*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2279*00b67f09SDavid van Moolenbroek 		goto out;
2280*00b67f09SDavid van Moolenbroek 	result = dns_request_getresponse(request, rcvmsg,
2281*00b67f09SDavid van Moolenbroek 					 DNS_MESSAGEPARSE_PRESERVEORDER);
2282*00b67f09SDavid van Moolenbroek 
2283*00b67f09SDavid van Moolenbroek 	if (result == DNS_R_TSIGERRORSET) {
2284*00b67f09SDavid van Moolenbroek 		dns_request_t *newrequest = NULL;
2285*00b67f09SDavid van Moolenbroek 
2286*00b67f09SDavid van Moolenbroek 		/* Retry SOA request without TSIG */
2287*00b67f09SDavid van Moolenbroek 		dns_message_destroy(&rcvmsg);
2288*00b67f09SDavid van Moolenbroek 		dns_message_renderreset(uctx->soaquery);
2289*00b67f09SDavid van Moolenbroek 		result = dns_request_createvia3(uctx->view->requestmgr,
2290*00b67f09SDavid van Moolenbroek 						uctx->soaquery, NULL, addr, 0,
2291*00b67f09SDavid van Moolenbroek 						NULL,
2292*00b67f09SDavid van Moolenbroek 						client->find_timeout * 20,
2293*00b67f09SDavid van Moolenbroek 						client->find_timeout, 3,
2294*00b67f09SDavid van Moolenbroek 						uctx->client->task,
2295*00b67f09SDavid van Moolenbroek 						receive_soa, uctx,
2296*00b67f09SDavid van Moolenbroek 						&newrequest);
2297*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
2298*00b67f09SDavid van Moolenbroek 			LOCK(&uctx->lock);
2299*00b67f09SDavid van Moolenbroek 			dns_request_destroy(&uctx->soareq);
2300*00b67f09SDavid van Moolenbroek 			uctx->soareq = newrequest;
2301*00b67f09SDavid van Moolenbroek 			UNLOCK(&uctx->lock);
2302*00b67f09SDavid van Moolenbroek 
2303*00b67f09SDavid van Moolenbroek 			return;
2304*00b67f09SDavid van Moolenbroek 		}
2305*00b67f09SDavid van Moolenbroek 		goto out;
2306*00b67f09SDavid van Moolenbroek 	}
2307*00b67f09SDavid van Moolenbroek 
2308*00b67f09SDavid van Moolenbroek 	section = DNS_SECTION_ANSWER;
2309*00b67f09SDavid van Moolenbroek 	POST(section);
2310*00b67f09SDavid van Moolenbroek 
2311*00b67f09SDavid van Moolenbroek 	if (rcvmsg->rcode != dns_rcode_noerror &&
2312*00b67f09SDavid van Moolenbroek 	    rcvmsg->rcode != dns_rcode_nxdomain) {
2313*00b67f09SDavid van Moolenbroek 		result = rcode2result(rcvmsg->rcode);
2314*00b67f09SDavid van Moolenbroek 		goto out;
2315*00b67f09SDavid van Moolenbroek 	}
2316*00b67f09SDavid van Moolenbroek 
2317*00b67f09SDavid van Moolenbroek  lookforsoa:
2318*00b67f09SDavid van Moolenbroek 	if (pass == 0)
2319*00b67f09SDavid van Moolenbroek 		section = DNS_SECTION_ANSWER;
2320*00b67f09SDavid van Moolenbroek 	else if (pass == 1)
2321*00b67f09SDavid van Moolenbroek 		section = DNS_SECTION_AUTHORITY;
2322*00b67f09SDavid van Moolenbroek 	else {
2323*00b67f09SDavid van Moolenbroek 		droplabel = ISC_TRUE;
2324*00b67f09SDavid van Moolenbroek 		goto out;
2325*00b67f09SDavid van Moolenbroek 	}
2326*00b67f09SDavid van Moolenbroek 
2327*00b67f09SDavid van Moolenbroek 	result = dns_message_firstname(rcvmsg, section);
2328*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2329*00b67f09SDavid van Moolenbroek 		pass++;
2330*00b67f09SDavid van Moolenbroek 		goto lookforsoa;
2331*00b67f09SDavid van Moolenbroek 	}
2332*00b67f09SDavid van Moolenbroek 	while (result == ISC_R_SUCCESS) {
2333*00b67f09SDavid van Moolenbroek 		name = NULL;
2334*00b67f09SDavid van Moolenbroek 		dns_message_currentname(rcvmsg, section, &name);
2335*00b67f09SDavid van Moolenbroek 		soaset = NULL;
2336*00b67f09SDavid van Moolenbroek 		result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2337*00b67f09SDavid van Moolenbroek 					      &soaset);
2338*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
2339*00b67f09SDavid van Moolenbroek 			break;
2340*00b67f09SDavid van Moolenbroek 		if (section == DNS_SECTION_ANSWER) {
2341*00b67f09SDavid van Moolenbroek 			dns_rdataset_t *tset = NULL;
2342*00b67f09SDavid van Moolenbroek 			if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2343*00b67f09SDavid van Moolenbroek 						 &tset) == ISC_R_SUCCESS
2344*00b67f09SDavid van Moolenbroek 			    ||
2345*00b67f09SDavid van Moolenbroek 			    dns_message_findtype(name, dns_rdatatype_dname, 0,
2346*00b67f09SDavid van Moolenbroek 						 &tset) == ISC_R_SUCCESS
2347*00b67f09SDavid van Moolenbroek 			    )
2348*00b67f09SDavid van Moolenbroek 			{
2349*00b67f09SDavid van Moolenbroek 				seencname = ISC_TRUE;
2350*00b67f09SDavid van Moolenbroek 				break;
2351*00b67f09SDavid van Moolenbroek 			}
2352*00b67f09SDavid van Moolenbroek 		}
2353*00b67f09SDavid van Moolenbroek 
2354*00b67f09SDavid van Moolenbroek 		result = dns_message_nextname(rcvmsg, section);
2355*00b67f09SDavid van Moolenbroek 	}
2356*00b67f09SDavid van Moolenbroek 
2357*00b67f09SDavid van Moolenbroek 	if (soaset == NULL && !seencname) {
2358*00b67f09SDavid van Moolenbroek 		pass++;
2359*00b67f09SDavid van Moolenbroek 		goto lookforsoa;
2360*00b67f09SDavid van Moolenbroek 	}
2361*00b67f09SDavid van Moolenbroek 
2362*00b67f09SDavid van Moolenbroek 	if (seencname) {
2363*00b67f09SDavid van Moolenbroek 		droplabel = ISC_TRUE;
2364*00b67f09SDavid van Moolenbroek 		goto out;
2365*00b67f09SDavid van Moolenbroek 	}
2366*00b67f09SDavid van Moolenbroek 
2367*00b67f09SDavid van Moolenbroek 	result = process_soa(uctx, soaset, name);
2368*00b67f09SDavid van Moolenbroek 
2369*00b67f09SDavid van Moolenbroek  out:
2370*00b67f09SDavid van Moolenbroek 	if (droplabel) {
2371*00b67f09SDavid van Moolenbroek 		result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2372*00b67f09SDavid van Moolenbroek 		INSIST(result == ISC_R_SUCCESS);
2373*00b67f09SDavid van Moolenbroek 		name = NULL;
2374*00b67f09SDavid van Moolenbroek 		dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2375*00b67f09SDavid van Moolenbroek 		nlabels = dns_name_countlabels(name);
2376*00b67f09SDavid van Moolenbroek 		if (nlabels == 1)
2377*00b67f09SDavid van Moolenbroek 			result = DNS_R_SERVFAIL; /* is there a better error? */
2378*00b67f09SDavid van Moolenbroek 		else {
2379*00b67f09SDavid van Moolenbroek 			dns_name_init(&tname, NULL);
2380*00b67f09SDavid van Moolenbroek 			dns_name_getlabelsequence(name, 1, nlabels - 1,
2381*00b67f09SDavid van Moolenbroek 						  &tname);
2382*00b67f09SDavid van Moolenbroek 			dns_name_clone(&tname, name);
2383*00b67f09SDavid van Moolenbroek 			dns_request_destroy(&request);
2384*00b67f09SDavid van Moolenbroek 			LOCK(&uctx->lock);
2385*00b67f09SDavid van Moolenbroek 			uctx->soareq = NULL;
2386*00b67f09SDavid van Moolenbroek 			UNLOCK(&uctx->lock);
2387*00b67f09SDavid van Moolenbroek 			dns_message_renderreset(soaquery);
2388*00b67f09SDavid van Moolenbroek 			dns_message_settsigkey(soaquery, NULL);
2389*00b67f09SDavid van Moolenbroek 			result = dns_request_createvia3(uctx->view->requestmgr,
2390*00b67f09SDavid van Moolenbroek 							soaquery, NULL,
2391*00b67f09SDavid van Moolenbroek 							uctx->currentserver, 0,
2392*00b67f09SDavid van Moolenbroek 							uctx->tsigkey,
2393*00b67f09SDavid van Moolenbroek 							client->find_timeout *
2394*00b67f09SDavid van Moolenbroek 							20,
2395*00b67f09SDavid van Moolenbroek 							client->find_timeout,
2396*00b67f09SDavid van Moolenbroek 							3, client->task,
2397*00b67f09SDavid van Moolenbroek 							receive_soa, uctx,
2398*00b67f09SDavid van Moolenbroek 							&uctx->soareq);
2399*00b67f09SDavid van Moolenbroek 		}
2400*00b67f09SDavid van Moolenbroek 	}
2401*00b67f09SDavid van Moolenbroek 
2402*00b67f09SDavid van Moolenbroek 	if (!droplabel || result != ISC_R_SUCCESS) {
2403*00b67f09SDavid van Moolenbroek 		dns_message_destroy(&uctx->soaquery);
2404*00b67f09SDavid van Moolenbroek 		LOCK(&uctx->lock);
2405*00b67f09SDavid van Moolenbroek 		dns_request_destroy(&uctx->soareq);
2406*00b67f09SDavid van Moolenbroek 		UNLOCK(&uctx->lock);
2407*00b67f09SDavid van Moolenbroek 	}
2408*00b67f09SDavid van Moolenbroek 
2409*00b67f09SDavid van Moolenbroek 	if (rcvmsg != NULL)
2410*00b67f09SDavid van Moolenbroek 		dns_message_destroy(&rcvmsg);
2411*00b67f09SDavid van Moolenbroek 
2412*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2413*00b67f09SDavid van Moolenbroek 		update_sendevent(uctx, result);
2414*00b67f09SDavid van Moolenbroek }
2415*00b67f09SDavid van Moolenbroek 
2416*00b67f09SDavid van Moolenbroek static isc_result_t
request_soa(updatectx_t * uctx)2417*00b67f09SDavid van Moolenbroek request_soa(updatectx_t *uctx) {
2418*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2419*00b67f09SDavid van Moolenbroek 	dns_message_t *soaquery = uctx->soaquery;
2420*00b67f09SDavid van Moolenbroek 	dns_name_t *name = NULL;
2421*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset = NULL;
2422*00b67f09SDavid van Moolenbroek 
2423*00b67f09SDavid van Moolenbroek 	if (soaquery == NULL) {
2424*00b67f09SDavid van Moolenbroek 		result = dns_message_create(uctx->client->mctx,
2425*00b67f09SDavid van Moolenbroek 					    DNS_MESSAGE_INTENTRENDER,
2426*00b67f09SDavid van Moolenbroek 					    &soaquery);
2427*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2428*00b67f09SDavid van Moolenbroek 			return (result);
2429*00b67f09SDavid van Moolenbroek 	}
2430*00b67f09SDavid van Moolenbroek 	soaquery->flags |= DNS_MESSAGEFLAG_RD;
2431*00b67f09SDavid van Moolenbroek 	result = dns_message_gettempname(soaquery, &name);
2432*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2433*00b67f09SDavid van Moolenbroek 		goto fail;
2434*00b67f09SDavid van Moolenbroek 	result = dns_message_gettemprdataset(soaquery, &rdataset);
2435*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2436*00b67f09SDavid van Moolenbroek 		goto fail;
2437*00b67f09SDavid van Moolenbroek 	dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2438*00b67f09SDavid van Moolenbroek 	dns_name_clone(uctx->firstname, name);
2439*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(name->list, rdataset, link);
2440*00b67f09SDavid van Moolenbroek 	dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2441*00b67f09SDavid van Moolenbroek 	rdataset = NULL;
2442*00b67f09SDavid van Moolenbroek 	name = NULL;
2443*00b67f09SDavid van Moolenbroek 
2444*00b67f09SDavid van Moolenbroek 	result = dns_request_createvia3(uctx->view->requestmgr,
2445*00b67f09SDavid van Moolenbroek 					soaquery, NULL, uctx->currentserver, 0,
2446*00b67f09SDavid van Moolenbroek 					uctx->tsigkey,
2447*00b67f09SDavid van Moolenbroek 					uctx->client->find_timeout * 20,
2448*00b67f09SDavid van Moolenbroek 					uctx->client->find_timeout, 3,
2449*00b67f09SDavid van Moolenbroek 					uctx->client->task, receive_soa, uctx,
2450*00b67f09SDavid van Moolenbroek 					&uctx->soareq);
2451*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
2452*00b67f09SDavid van Moolenbroek 		uctx->soaquery = soaquery;
2453*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
2454*00b67f09SDavid van Moolenbroek 	}
2455*00b67f09SDavid van Moolenbroek 
2456*00b67f09SDavid van Moolenbroek  fail:
2457*00b67f09SDavid van Moolenbroek 	if (rdataset != NULL) {
2458*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2459*00b67f09SDavid van Moolenbroek 		dns_message_puttemprdataset(soaquery, &rdataset);
2460*00b67f09SDavid van Moolenbroek 	}
2461*00b67f09SDavid van Moolenbroek 	if (name != NULL)
2462*00b67f09SDavid van Moolenbroek 		dns_message_puttempname(soaquery, &name);
2463*00b67f09SDavid van Moolenbroek 	dns_message_destroy(&soaquery);
2464*00b67f09SDavid van Moolenbroek 
2465*00b67f09SDavid van Moolenbroek 	return (result);
2466*00b67f09SDavid van Moolenbroek }
2467*00b67f09SDavid van Moolenbroek 
2468*00b67f09SDavid van Moolenbroek static void
resolvesoa_done(isc_task_t * task,isc_event_t * event)2469*00b67f09SDavid van Moolenbroek resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2470*00b67f09SDavid van Moolenbroek 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2471*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx;
2472*00b67f09SDavid van Moolenbroek 	dns_name_t *name, tname;
2473*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset = NULL;
2474*00b67f09SDavid van Moolenbroek 	isc_result_t result = rev->result;
2475*00b67f09SDavid van Moolenbroek 	unsigned int nlabels;
2476*00b67f09SDavid van Moolenbroek 
2477*00b67f09SDavid van Moolenbroek 	UNUSED(task);
2478*00b67f09SDavid van Moolenbroek 
2479*00b67f09SDavid van Moolenbroek 	uctx = event->ev_arg;
2480*00b67f09SDavid van Moolenbroek 	REQUIRE(UCTX_VALID(uctx));
2481*00b67f09SDavid van Moolenbroek 
2482*00b67f09SDavid van Moolenbroek 	LOCK(&uctx->lock);
2483*00b67f09SDavid van Moolenbroek 	dns_client_destroyrestrans(&uctx->restrans);
2484*00b67f09SDavid van Moolenbroek 	UNLOCK(&uctx->lock);
2485*00b67f09SDavid van Moolenbroek 
2486*00b67f09SDavid van Moolenbroek 	uctx = event->ev_arg;
2487*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS &&
2488*00b67f09SDavid van Moolenbroek 	    result != DNS_R_NCACHENXDOMAIN &&
2489*00b67f09SDavid van Moolenbroek 	    result != DNS_R_NCACHENXRRSET) {
2490*00b67f09SDavid van Moolenbroek 		/* XXX: what about DNSSEC failure? */
2491*00b67f09SDavid van Moolenbroek 		goto out;
2492*00b67f09SDavid van Moolenbroek 	}
2493*00b67f09SDavid van Moolenbroek 
2494*00b67f09SDavid van Moolenbroek 	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2495*00b67f09SDavid van Moolenbroek 	     name = ISC_LIST_NEXT(name, link)) {
2496*00b67f09SDavid van Moolenbroek 		for (rdataset = ISC_LIST_HEAD(name->list);
2497*00b67f09SDavid van Moolenbroek 		     rdataset != NULL;
2498*00b67f09SDavid van Moolenbroek 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2499*00b67f09SDavid van Moolenbroek 			if (dns_rdataset_isassociated(rdataset) &&
2500*00b67f09SDavid van Moolenbroek 			    rdataset->type == dns_rdatatype_soa)
2501*00b67f09SDavid van Moolenbroek 				break;
2502*00b67f09SDavid van Moolenbroek 		}
2503*00b67f09SDavid van Moolenbroek 	}
2504*00b67f09SDavid van Moolenbroek 
2505*00b67f09SDavid van Moolenbroek 	if (rdataset == NULL) {
2506*00b67f09SDavid van Moolenbroek 		/* Drop one label and retry resolution. */
2507*00b67f09SDavid van Moolenbroek 		nlabels = dns_name_countlabels(&uctx->soaqname);
2508*00b67f09SDavid van Moolenbroek 		if (nlabels == 1) {
2509*00b67f09SDavid van Moolenbroek 			result = DNS_R_SERVFAIL; /* is there a better error? */
2510*00b67f09SDavid van Moolenbroek 			goto out;
2511*00b67f09SDavid van Moolenbroek 		}
2512*00b67f09SDavid van Moolenbroek 		dns_name_init(&tname, NULL);
2513*00b67f09SDavid van Moolenbroek 		dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2514*00b67f09SDavid van Moolenbroek 					  &tname);
2515*00b67f09SDavid van Moolenbroek 		dns_name_clone(&tname, &uctx->soaqname);
2516*00b67f09SDavid van Moolenbroek 
2517*00b67f09SDavid van Moolenbroek 		result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2518*00b67f09SDavid van Moolenbroek 						 uctx->rdclass,
2519*00b67f09SDavid van Moolenbroek 						 dns_rdatatype_soa, 0,
2520*00b67f09SDavid van Moolenbroek 						 uctx->client->task,
2521*00b67f09SDavid van Moolenbroek 						 resolvesoa_done, uctx,
2522*00b67f09SDavid van Moolenbroek 						 &uctx->restrans);
2523*00b67f09SDavid van Moolenbroek 	} else
2524*00b67f09SDavid van Moolenbroek 		result = process_soa(uctx, rdataset, &uctx->soaqname);
2525*00b67f09SDavid van Moolenbroek 
2526*00b67f09SDavid van Moolenbroek  out:
2527*00b67f09SDavid van Moolenbroek 	dns_client_freeresanswer(uctx->client, &rev->answerlist);
2528*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
2529*00b67f09SDavid van Moolenbroek 
2530*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2531*00b67f09SDavid van Moolenbroek 		update_sendevent(uctx, result);
2532*00b67f09SDavid van Moolenbroek }
2533*00b67f09SDavid van Moolenbroek 
2534*00b67f09SDavid van Moolenbroek static isc_result_t
copy_name(isc_mem_t * mctx,dns_message_t * msg,dns_name_t * name,dns_name_t ** newnamep)2535*00b67f09SDavid van Moolenbroek copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name,
2536*00b67f09SDavid van Moolenbroek 	  dns_name_t **newnamep)
2537*00b67f09SDavid van Moolenbroek {
2538*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2539*00b67f09SDavid van Moolenbroek 	dns_name_t *newname = NULL;
2540*00b67f09SDavid van Moolenbroek 	isc_region_t r;
2541*00b67f09SDavid van Moolenbroek 	isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2542*00b67f09SDavid van Moolenbroek 	dns_rdatalist_t *rdatalist;
2543*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset, *newrdataset;
2544*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2545*00b67f09SDavid van Moolenbroek 
2546*00b67f09SDavid van Moolenbroek 	result = dns_message_gettempname(msg, &newname);
2547*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2548*00b67f09SDavid van Moolenbroek 		return (result);
2549*00b67f09SDavid van Moolenbroek 	result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2550*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2551*00b67f09SDavid van Moolenbroek 		goto fail;
2552*00b67f09SDavid van Moolenbroek 	dns_name_init(newname, NULL);
2553*00b67f09SDavid van Moolenbroek 	dns_name_setbuffer(newname, namebuf);
2554*00b67f09SDavid van Moolenbroek 	dns_message_takebuffer(msg, &namebuf);
2555*00b67f09SDavid van Moolenbroek 	result = dns_name_copy(name, newname, NULL);
2556*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2557*00b67f09SDavid van Moolenbroek 		goto fail;
2558*00b67f09SDavid van Moolenbroek 
2559*00b67f09SDavid van Moolenbroek 	for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2560*00b67f09SDavid van Moolenbroek 	     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2561*00b67f09SDavid van Moolenbroek 		rdatalist = NULL;
2562*00b67f09SDavid van Moolenbroek 		result = dns_message_gettemprdatalist(msg, &rdatalist);
2563*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2564*00b67f09SDavid van Moolenbroek 			goto fail;
2565*00b67f09SDavid van Moolenbroek 		dns_rdatalist_init(rdatalist);
2566*00b67f09SDavid van Moolenbroek 		rdatalist->type = rdataset->type;
2567*00b67f09SDavid van Moolenbroek 		rdatalist->rdclass = rdataset->rdclass;
2568*00b67f09SDavid van Moolenbroek 		rdatalist->covers = rdataset->covers;
2569*00b67f09SDavid van Moolenbroek 		rdatalist->ttl = rdataset->ttl;
2570*00b67f09SDavid van Moolenbroek 
2571*00b67f09SDavid van Moolenbroek 		result = dns_rdataset_first(rdataset);
2572*00b67f09SDavid van Moolenbroek 		while (result == ISC_R_SUCCESS) {
2573*00b67f09SDavid van Moolenbroek 			dns_rdata_reset(&rdata);
2574*00b67f09SDavid van Moolenbroek 			dns_rdataset_current(rdataset, &rdata);
2575*00b67f09SDavid van Moolenbroek 
2576*00b67f09SDavid van Moolenbroek 			newrdata = NULL;
2577*00b67f09SDavid van Moolenbroek 			result = dns_message_gettemprdata(msg, &newrdata);
2578*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
2579*00b67f09SDavid van Moolenbroek 				goto fail;
2580*00b67f09SDavid van Moolenbroek 			dns_rdata_toregion(&rdata, &r);
2581*00b67f09SDavid van Moolenbroek 			rdatabuf = NULL;
2582*00b67f09SDavid van Moolenbroek 			result = isc_buffer_allocate(mctx, &rdatabuf,
2583*00b67f09SDavid van Moolenbroek 						     r.length);
2584*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
2585*00b67f09SDavid van Moolenbroek 				goto fail;
2586*00b67f09SDavid van Moolenbroek 			isc_buffer_putmem(rdatabuf, r.base, r.length);
2587*00b67f09SDavid van Moolenbroek 			isc_buffer_usedregion(rdatabuf, &r);
2588*00b67f09SDavid van Moolenbroek 			dns_rdata_init(newrdata);
2589*00b67f09SDavid van Moolenbroek 			dns_rdata_fromregion(newrdata, rdata.rdclass,
2590*00b67f09SDavid van Moolenbroek 					     rdata.type, &r);
2591*00b67f09SDavid van Moolenbroek 			newrdata->flags = rdata.flags;
2592*00b67f09SDavid van Moolenbroek 
2593*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2594*00b67f09SDavid van Moolenbroek 			dns_message_takebuffer(msg, &rdatabuf);
2595*00b67f09SDavid van Moolenbroek 
2596*00b67f09SDavid van Moolenbroek 			result = dns_rdataset_next(rdataset);
2597*00b67f09SDavid van Moolenbroek 		}
2598*00b67f09SDavid van Moolenbroek 
2599*00b67f09SDavid van Moolenbroek 		newrdataset = NULL;
2600*00b67f09SDavid van Moolenbroek 		result = dns_message_gettemprdataset(msg, &newrdataset);
2601*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2602*00b67f09SDavid van Moolenbroek 			goto fail;
2603*00b67f09SDavid van Moolenbroek 		dns_rdatalist_tordataset(rdatalist, newrdataset);
2604*00b67f09SDavid van Moolenbroek 
2605*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(newname->list, newrdataset, link);
2606*00b67f09SDavid van Moolenbroek 	}
2607*00b67f09SDavid van Moolenbroek 
2608*00b67f09SDavid van Moolenbroek 	*newnamep = newname;
2609*00b67f09SDavid van Moolenbroek 
2610*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2611*00b67f09SDavid van Moolenbroek 
2612*00b67f09SDavid van Moolenbroek  fail:
2613*00b67f09SDavid van Moolenbroek 	dns_message_puttempname(msg, &newname);
2614*00b67f09SDavid van Moolenbroek 
2615*00b67f09SDavid van Moolenbroek 	return (result);
2616*00b67f09SDavid van Moolenbroek 
2617*00b67f09SDavid van Moolenbroek }
2618*00b67f09SDavid van Moolenbroek 
2619*00b67f09SDavid van Moolenbroek static void
internal_update_callback(isc_task_t * task,isc_event_t * event)2620*00b67f09SDavid van Moolenbroek internal_update_callback(isc_task_t *task, isc_event_t *event) {
2621*00b67f09SDavid van Moolenbroek 	updatearg_t *uarg = event->ev_arg;
2622*00b67f09SDavid van Moolenbroek 	dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2623*00b67f09SDavid van Moolenbroek 
2624*00b67f09SDavid van Moolenbroek 	UNUSED(task);
2625*00b67f09SDavid van Moolenbroek 
2626*00b67f09SDavid van Moolenbroek 	LOCK(&uarg->lock);
2627*00b67f09SDavid van Moolenbroek 
2628*00b67f09SDavid van Moolenbroek 	uarg->result = uev->result;
2629*00b67f09SDavid van Moolenbroek 
2630*00b67f09SDavid van Moolenbroek 	dns_client_destroyupdatetrans(&uarg->trans);
2631*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
2632*00b67f09SDavid van Moolenbroek 
2633*00b67f09SDavid van Moolenbroek 	if (!uarg->canceled) {
2634*00b67f09SDavid van Moolenbroek 		UNLOCK(&uarg->lock);
2635*00b67f09SDavid van Moolenbroek 
2636*00b67f09SDavid van Moolenbroek 		/* Exit from the internal event loop */
2637*00b67f09SDavid van Moolenbroek 		isc_app_ctxsuspend(uarg->actx);
2638*00b67f09SDavid van Moolenbroek 	} else {
2639*00b67f09SDavid van Moolenbroek 		/*
2640*00b67f09SDavid van Moolenbroek 		 * We have already exited from the loop (due to some
2641*00b67f09SDavid van Moolenbroek 		 * unexpected event).  Just clean the arg up.
2642*00b67f09SDavid van Moolenbroek 		 */
2643*00b67f09SDavid van Moolenbroek 		UNLOCK(&uarg->lock);
2644*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&uarg->lock);
2645*00b67f09SDavid van Moolenbroek 		isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2646*00b67f09SDavid van Moolenbroek 	}
2647*00b67f09SDavid van Moolenbroek }
2648*00b67f09SDavid van Moolenbroek 
2649*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_update(dns_client_t * client,dns_rdataclass_t rdclass,dns_name_t * zonename,dns_namelist_t * prerequisites,dns_namelist_t * updates,isc_sockaddrlist_t * servers,dns_tsec_t * tsec,unsigned int options)2650*00b67f09SDavid van Moolenbroek dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2651*00b67f09SDavid van Moolenbroek 		  dns_name_t *zonename, dns_namelist_t *prerequisites,
2652*00b67f09SDavid van Moolenbroek 		  dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2653*00b67f09SDavid van Moolenbroek 		  dns_tsec_t *tsec, unsigned int options)
2654*00b67f09SDavid van Moolenbroek {
2655*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2656*00b67f09SDavid van Moolenbroek 	isc_appctx_t *actx;
2657*00b67f09SDavid van Moolenbroek 	updatearg_t *uarg;
2658*00b67f09SDavid van Moolenbroek 
2659*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
2660*00b67f09SDavid van Moolenbroek 
2661*00b67f09SDavid van Moolenbroek 	if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2662*00b67f09SDavid van Moolenbroek 	    (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) {
2663*00b67f09SDavid van Moolenbroek 		/*
2664*00b67f09SDavid van Moolenbroek 		 * If the client is run under application's control, we need
2665*00b67f09SDavid van Moolenbroek 		 * to create a new running (sub)environment for this
2666*00b67f09SDavid van Moolenbroek 		 * particular resolution.
2667*00b67f09SDavid van Moolenbroek 		 */
2668*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2669*00b67f09SDavid van Moolenbroek 	} else
2670*00b67f09SDavid van Moolenbroek 		actx = client->actx;
2671*00b67f09SDavid van Moolenbroek 
2672*00b67f09SDavid van Moolenbroek 	uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2673*00b67f09SDavid van Moolenbroek 	if (uarg == NULL)
2674*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2675*00b67f09SDavid van Moolenbroek 
2676*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&uarg->lock);
2677*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2678*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2679*00b67f09SDavid van Moolenbroek 		return (result);
2680*00b67f09SDavid van Moolenbroek 	}
2681*00b67f09SDavid van Moolenbroek 
2682*00b67f09SDavid van Moolenbroek 	uarg->actx = actx;
2683*00b67f09SDavid van Moolenbroek 	uarg->client = client;
2684*00b67f09SDavid van Moolenbroek 	uarg->result = ISC_R_FAILURE;
2685*00b67f09SDavid van Moolenbroek 	uarg->trans = NULL;
2686*00b67f09SDavid van Moolenbroek 	uarg->canceled = ISC_FALSE;
2687*00b67f09SDavid van Moolenbroek 
2688*00b67f09SDavid van Moolenbroek 	result = dns_client_startupdate(client, rdclass, zonename,
2689*00b67f09SDavid van Moolenbroek 					prerequisites, updates, servers,
2690*00b67f09SDavid van Moolenbroek 					tsec, options, client->task,
2691*00b67f09SDavid van Moolenbroek 					internal_update_callback, uarg,
2692*00b67f09SDavid van Moolenbroek 					&uarg->trans);
2693*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2694*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&uarg->lock);
2695*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2696*00b67f09SDavid van Moolenbroek 		return (result);
2697*00b67f09SDavid van Moolenbroek 	}
2698*00b67f09SDavid van Moolenbroek 
2699*00b67f09SDavid van Moolenbroek 	/*
2700*00b67f09SDavid van Moolenbroek 	 * Start internal event loop.  It blocks until the entire process
2701*00b67f09SDavid van Moolenbroek 	 * is completed.
2702*00b67f09SDavid van Moolenbroek 	 */
2703*00b67f09SDavid van Moolenbroek 	result = isc_app_ctxrun(actx);
2704*00b67f09SDavid van Moolenbroek 
2705*00b67f09SDavid van Moolenbroek 	LOCK(&uarg->lock);
2706*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND)
2707*00b67f09SDavid van Moolenbroek 		result = uarg->result;
2708*00b67f09SDavid van Moolenbroek 
2709*00b67f09SDavid van Moolenbroek 	if (uarg->trans != NULL) {
2710*00b67f09SDavid van Moolenbroek 		/*
2711*00b67f09SDavid van Moolenbroek 		 * Unusual termination (perhaps due to signal).  We need some
2712*00b67f09SDavid van Moolenbroek 		 * tricky cleanup process.
2713*00b67f09SDavid van Moolenbroek 		 */
2714*00b67f09SDavid van Moolenbroek 		uarg->canceled = ISC_TRUE;
2715*00b67f09SDavid van Moolenbroek 		dns_client_cancelupdate(uarg->trans);
2716*00b67f09SDavid van Moolenbroek 
2717*00b67f09SDavid van Moolenbroek 		UNLOCK(&uarg->lock);
2718*00b67f09SDavid van Moolenbroek 
2719*00b67f09SDavid van Moolenbroek 		/* uarg will be freed in the event handler. */
2720*00b67f09SDavid van Moolenbroek 	} else {
2721*00b67f09SDavid van Moolenbroek 		UNLOCK(&uarg->lock);
2722*00b67f09SDavid van Moolenbroek 
2723*00b67f09SDavid van Moolenbroek 		DESTROYLOCK(&uarg->lock);
2724*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2725*00b67f09SDavid van Moolenbroek 	}
2726*00b67f09SDavid van Moolenbroek 
2727*00b67f09SDavid van Moolenbroek 	return (result);
2728*00b67f09SDavid van Moolenbroek }
2729*00b67f09SDavid van Moolenbroek 
2730*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_startupdate(dns_client_t * client,dns_rdataclass_t rdclass,dns_name_t * zonename,dns_namelist_t * prerequisites,dns_namelist_t * updates,isc_sockaddrlist_t * servers,dns_tsec_t * tsec,unsigned int options,isc_task_t * task,isc_taskaction_t action,void * arg,dns_clientupdatetrans_t ** transp)2731*00b67f09SDavid van Moolenbroek dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2732*00b67f09SDavid van Moolenbroek 		       dns_name_t *zonename, dns_namelist_t *prerequisites,
2733*00b67f09SDavid van Moolenbroek 		       dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2734*00b67f09SDavid van Moolenbroek 		       dns_tsec_t *tsec, unsigned int options,
2735*00b67f09SDavid van Moolenbroek 		       isc_task_t *task, isc_taskaction_t action, void *arg,
2736*00b67f09SDavid van Moolenbroek 		       dns_clientupdatetrans_t **transp)
2737*00b67f09SDavid van Moolenbroek {
2738*00b67f09SDavid van Moolenbroek 	dns_view_t *view = NULL;
2739*00b67f09SDavid van Moolenbroek 	isc_result_t result;
2740*00b67f09SDavid van Moolenbroek 	dns_name_t *name, *newname;
2741*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx;
2742*00b67f09SDavid van Moolenbroek 	isc_task_t *clone = NULL;
2743*00b67f09SDavid van Moolenbroek 	dns_section_t section = DNS_SECTION_UPDATE;
2744*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *server, *sa = NULL;
2745*00b67f09SDavid van Moolenbroek 	dns_tsectype_t tsectype = dns_tsectype_none;
2746*00b67f09SDavid van Moolenbroek 
2747*00b67f09SDavid van Moolenbroek 	UNUSED(options);
2748*00b67f09SDavid van Moolenbroek 
2749*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
2750*00b67f09SDavid van Moolenbroek 	REQUIRE(transp != NULL && *transp == NULL);
2751*00b67f09SDavid van Moolenbroek 	REQUIRE(updates != NULL);
2752*00b67f09SDavid van Moolenbroek 	REQUIRE(task != NULL);
2753*00b67f09SDavid van Moolenbroek 
2754*00b67f09SDavid van Moolenbroek 	if (tsec != NULL) {
2755*00b67f09SDavid van Moolenbroek 		tsectype = dns_tsec_gettype(tsec);
2756*00b67f09SDavid van Moolenbroek 		if (tsectype != dns_tsectype_tsig)
2757*00b67f09SDavid van Moolenbroek 			return (ISC_R_NOTIMPLEMENTED); /* XXX */
2758*00b67f09SDavid van Moolenbroek 	}
2759*00b67f09SDavid van Moolenbroek 
2760*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
2761*00b67f09SDavid van Moolenbroek 	result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2762*00b67f09SDavid van Moolenbroek 				   rdclass, &view);
2763*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
2764*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2765*00b67f09SDavid van Moolenbroek 		return (result);
2766*00b67f09SDavid van Moolenbroek 
2767*00b67f09SDavid van Moolenbroek 	/* Create a context and prepare some resources */
2768*00b67f09SDavid van Moolenbroek 	uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2769*00b67f09SDavid van Moolenbroek 	if (uctx == NULL) {
2770*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
2771*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2772*00b67f09SDavid van Moolenbroek 	}
2773*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&uctx->lock);
2774*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
2775*00b67f09SDavid van Moolenbroek 		dns_view_detach(&view);
2776*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2777*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
2778*00b67f09SDavid van Moolenbroek 	}
2779*00b67f09SDavid van Moolenbroek 	clone = NULL;
2780*00b67f09SDavid van Moolenbroek 	isc_task_attach(task, &clone);
2781*00b67f09SDavid van Moolenbroek 	uctx->client = client;
2782*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(uctx, link);
2783*00b67f09SDavid van Moolenbroek 	uctx->state = dns_clientupdatestate_prepare;
2784*00b67f09SDavid van Moolenbroek 	uctx->view = view;
2785*00b67f09SDavid van Moolenbroek 	uctx->rdclass = rdclass;
2786*00b67f09SDavid van Moolenbroek 	uctx->canceled = ISC_FALSE;
2787*00b67f09SDavid van Moolenbroek 	uctx->updatemsg = NULL;
2788*00b67f09SDavid van Moolenbroek 	uctx->soaquery = NULL;
2789*00b67f09SDavid van Moolenbroek 	uctx->updatereq = NULL;
2790*00b67f09SDavid van Moolenbroek 	uctx->restrans = NULL;
2791*00b67f09SDavid van Moolenbroek 	uctx->restrans2 = NULL;
2792*00b67f09SDavid van Moolenbroek 	uctx->bp4 = NULL;
2793*00b67f09SDavid van Moolenbroek 	uctx->bp6 = NULL;
2794*00b67f09SDavid van Moolenbroek 	uctx->soareq = NULL;
2795*00b67f09SDavid van Moolenbroek 	uctx->event = NULL;
2796*00b67f09SDavid van Moolenbroek 	uctx->tsigkey = NULL;
2797*00b67f09SDavid van Moolenbroek 	uctx->sig0key = NULL;
2798*00b67f09SDavid van Moolenbroek 	uctx->zonename = NULL;
2799*00b67f09SDavid van Moolenbroek 	dns_name_init(&uctx->soaqname, NULL);
2800*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(uctx->servers);
2801*00b67f09SDavid van Moolenbroek 	uctx->nservers = 0;
2802*00b67f09SDavid van Moolenbroek 	uctx->currentserver = NULL;
2803*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&uctx->zonefname);
2804*00b67f09SDavid van Moolenbroek 	if (tsec != NULL)
2805*00b67f09SDavid van Moolenbroek 		dns_tsec_getkey(tsec, &uctx->tsigkey);
2806*00b67f09SDavid van Moolenbroek 	uctx->event = (dns_clientupdateevent_t *)
2807*00b67f09SDavid van Moolenbroek 		isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE,
2808*00b67f09SDavid van Moolenbroek 				   action, arg, sizeof(*uctx->event));
2809*00b67f09SDavid van Moolenbroek 	if (uctx->event == NULL)
2810*00b67f09SDavid van Moolenbroek 		goto fail;
2811*00b67f09SDavid van Moolenbroek 	if (zonename != NULL) {
2812*00b67f09SDavid van Moolenbroek 		uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2813*00b67f09SDavid van Moolenbroek 		result = dns_name_copy(zonename, uctx->zonename, NULL);
2814*00b67f09SDavid van Moolenbroek 	}
2815*00b67f09SDavid van Moolenbroek 	if (servers != NULL) {
2816*00b67f09SDavid van Moolenbroek 		for (server = ISC_LIST_HEAD(*servers);
2817*00b67f09SDavid van Moolenbroek 		     server != NULL;
2818*00b67f09SDavid van Moolenbroek 		     server = ISC_LIST_NEXT(server, link)) {
2819*00b67f09SDavid van Moolenbroek 			sa = isc_mem_get(client->mctx, sizeof(*sa));
2820*00b67f09SDavid van Moolenbroek 			if (sa == NULL)
2821*00b67f09SDavid van Moolenbroek 				goto fail;
2822*00b67f09SDavid van Moolenbroek 			sa->type = server->type;
2823*00b67f09SDavid van Moolenbroek 			sa->length = server->length;
2824*00b67f09SDavid van Moolenbroek 			ISC_LINK_INIT(sa, link);
2825*00b67f09SDavid van Moolenbroek 			ISC_LIST_APPEND(uctx->servers, sa, link);
2826*00b67f09SDavid van Moolenbroek 			if (uctx->currentserver == NULL)
2827*00b67f09SDavid van Moolenbroek 				uctx->currentserver = sa;
2828*00b67f09SDavid van Moolenbroek 			uctx->nservers++;
2829*00b67f09SDavid van Moolenbroek 		}
2830*00b67f09SDavid van Moolenbroek 	}
2831*00b67f09SDavid van Moolenbroek 
2832*00b67f09SDavid van Moolenbroek 	/* Make update message */
2833*00b67f09SDavid van Moolenbroek 	result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2834*00b67f09SDavid van Moolenbroek 				    &uctx->updatemsg);
2835*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2836*00b67f09SDavid van Moolenbroek 		goto fail;
2837*00b67f09SDavid van Moolenbroek 	uctx->updatemsg->opcode = dns_opcode_update;
2838*00b67f09SDavid van Moolenbroek 
2839*00b67f09SDavid van Moolenbroek 	if (prerequisites != NULL) {
2840*00b67f09SDavid van Moolenbroek 		for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2841*00b67f09SDavid van Moolenbroek 		     name = ISC_LIST_NEXT(name, link)) {
2842*00b67f09SDavid van Moolenbroek 			newname = NULL;
2843*00b67f09SDavid van Moolenbroek 			result = copy_name(client->mctx, uctx->updatemsg,
2844*00b67f09SDavid van Moolenbroek 					   name, &newname);
2845*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
2846*00b67f09SDavid van Moolenbroek 				goto fail;
2847*00b67f09SDavid van Moolenbroek 			dns_message_addname(uctx->updatemsg, newname,
2848*00b67f09SDavid van Moolenbroek 					    DNS_SECTION_PREREQUISITE);
2849*00b67f09SDavid van Moolenbroek 		}
2850*00b67f09SDavid van Moolenbroek 	}
2851*00b67f09SDavid van Moolenbroek 
2852*00b67f09SDavid van Moolenbroek 	for (name = ISC_LIST_HEAD(*updates); name != NULL;
2853*00b67f09SDavid van Moolenbroek 	     name = ISC_LIST_NEXT(name, link)) {
2854*00b67f09SDavid van Moolenbroek 		newname = NULL;
2855*00b67f09SDavid van Moolenbroek 		result = copy_name(client->mctx, uctx->updatemsg, name,
2856*00b67f09SDavid van Moolenbroek 				   &newname);
2857*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2858*00b67f09SDavid van Moolenbroek 			goto fail;
2859*00b67f09SDavid van Moolenbroek 		dns_message_addname(uctx->updatemsg, newname,
2860*00b67f09SDavid van Moolenbroek 				    DNS_SECTION_UPDATE);
2861*00b67f09SDavid van Moolenbroek 	}
2862*00b67f09SDavid van Moolenbroek 
2863*00b67f09SDavid van Moolenbroek 	uctx->firstname = NULL;
2864*00b67f09SDavid van Moolenbroek 	result = dns_message_firstname(uctx->updatemsg, section);
2865*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE) {
2866*00b67f09SDavid van Moolenbroek 		section = DNS_SECTION_PREREQUISITE;
2867*00b67f09SDavid van Moolenbroek 		result = dns_message_firstname(uctx->updatemsg, section);
2868*00b67f09SDavid van Moolenbroek 	}
2869*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
2870*00b67f09SDavid van Moolenbroek 		goto fail;
2871*00b67f09SDavid van Moolenbroek 	dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2872*00b67f09SDavid van Moolenbroek 
2873*00b67f09SDavid van Moolenbroek 	uctx->magic = UCTX_MAGIC;
2874*00b67f09SDavid van Moolenbroek 
2875*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
2876*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(client->updatectxs, uctx, link);
2877*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
2878*00b67f09SDavid van Moolenbroek 
2879*00b67f09SDavid van Moolenbroek 	if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2880*00b67f09SDavid van Moolenbroek 		result = send_update(uctx);
2881*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2882*00b67f09SDavid van Moolenbroek 			goto fail;
2883*00b67f09SDavid van Moolenbroek 	} else if (uctx->currentserver != NULL) {
2884*00b67f09SDavid van Moolenbroek 		result = request_soa(uctx);
2885*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2886*00b67f09SDavid van Moolenbroek 			goto fail;
2887*00b67f09SDavid van Moolenbroek 	} else {
2888*00b67f09SDavid van Moolenbroek 		dns_name_clone(uctx->firstname, &uctx->soaqname);
2889*00b67f09SDavid van Moolenbroek 		result = dns_client_startresolve(uctx->client, &uctx->soaqname,
2890*00b67f09SDavid van Moolenbroek 						 uctx->rdclass,
2891*00b67f09SDavid van Moolenbroek 						 dns_rdatatype_soa, 0,
2892*00b67f09SDavid van Moolenbroek 						 client->task, resolvesoa_done,
2893*00b67f09SDavid van Moolenbroek 						 uctx, &uctx->restrans);
2894*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
2895*00b67f09SDavid van Moolenbroek 			goto fail;
2896*00b67f09SDavid van Moolenbroek 	}
2897*00b67f09SDavid van Moolenbroek 
2898*00b67f09SDavid van Moolenbroek 	*transp = (dns_clientupdatetrans_t *)uctx;
2899*00b67f09SDavid van Moolenbroek 
2900*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
2901*00b67f09SDavid van Moolenbroek 
2902*00b67f09SDavid van Moolenbroek  fail:
2903*00b67f09SDavid van Moolenbroek 	if (ISC_LINK_LINKED(uctx, link)) {
2904*00b67f09SDavid van Moolenbroek 		LOCK(&client->lock);
2905*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2906*00b67f09SDavid van Moolenbroek 		UNLOCK(&client->lock);
2907*00b67f09SDavid van Moolenbroek 	}
2908*00b67f09SDavid van Moolenbroek 	if (uctx->updatemsg != NULL)
2909*00b67f09SDavid van Moolenbroek 		dns_message_destroy(&uctx->updatemsg);
2910*00b67f09SDavid van Moolenbroek 	while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2911*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(uctx->servers, sa, link);
2912*00b67f09SDavid van Moolenbroek 		isc_mem_put(client->mctx, sa, sizeof(*sa));
2913*00b67f09SDavid van Moolenbroek 	}
2914*00b67f09SDavid van Moolenbroek 	if (uctx->event != NULL)
2915*00b67f09SDavid van Moolenbroek 		isc_event_free(ISC_EVENT_PTR(&uctx->event));
2916*00b67f09SDavid van Moolenbroek 	if (uctx->tsigkey != NULL)
2917*00b67f09SDavid van Moolenbroek 		dns_tsigkey_detach(&uctx->tsigkey);
2918*00b67f09SDavid van Moolenbroek 	isc_task_detach(&clone);
2919*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&uctx->lock);
2920*00b67f09SDavid van Moolenbroek 	uctx->magic = 0;
2921*00b67f09SDavid van Moolenbroek 	isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2922*00b67f09SDavid van Moolenbroek 	dns_view_detach(&view);
2923*00b67f09SDavid van Moolenbroek 
2924*00b67f09SDavid van Moolenbroek 	return (result);
2925*00b67f09SDavid van Moolenbroek }
2926*00b67f09SDavid van Moolenbroek 
2927*00b67f09SDavid van Moolenbroek void
dns_client_cancelupdate(dns_clientupdatetrans_t * trans)2928*00b67f09SDavid van Moolenbroek dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2929*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx;
2930*00b67f09SDavid van Moolenbroek 
2931*00b67f09SDavid van Moolenbroek 	REQUIRE(trans != NULL);
2932*00b67f09SDavid van Moolenbroek 	uctx = (updatectx_t *)trans;
2933*00b67f09SDavid van Moolenbroek 	REQUIRE(UCTX_VALID(uctx));
2934*00b67f09SDavid van Moolenbroek 
2935*00b67f09SDavid van Moolenbroek 	LOCK(&uctx->lock);
2936*00b67f09SDavid van Moolenbroek 
2937*00b67f09SDavid van Moolenbroek 	if (!uctx->canceled) {
2938*00b67f09SDavid van Moolenbroek 		uctx->canceled = ISC_TRUE;
2939*00b67f09SDavid van Moolenbroek 		if (uctx->updatereq != NULL)
2940*00b67f09SDavid van Moolenbroek 			dns_request_cancel(uctx->updatereq);
2941*00b67f09SDavid van Moolenbroek 		if (uctx->soareq != NULL)
2942*00b67f09SDavid van Moolenbroek 			dns_request_cancel(uctx->soareq);
2943*00b67f09SDavid van Moolenbroek 		if (uctx->restrans != NULL)
2944*00b67f09SDavid van Moolenbroek 			dns_client_cancelresolve(uctx->restrans);
2945*00b67f09SDavid van Moolenbroek 		if (uctx->restrans2 != NULL)
2946*00b67f09SDavid van Moolenbroek 			dns_client_cancelresolve(uctx->restrans2);
2947*00b67f09SDavid van Moolenbroek 	}
2948*00b67f09SDavid van Moolenbroek 
2949*00b67f09SDavid van Moolenbroek 	UNLOCK(&uctx->lock);
2950*00b67f09SDavid van Moolenbroek }
2951*00b67f09SDavid van Moolenbroek 
2952*00b67f09SDavid van Moolenbroek void
dns_client_destroyupdatetrans(dns_clientupdatetrans_t ** transp)2953*00b67f09SDavid van Moolenbroek dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
2954*00b67f09SDavid van Moolenbroek 	updatectx_t *uctx;
2955*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
2956*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
2957*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_destroyclient = ISC_FALSE;
2958*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *sa;
2959*00b67f09SDavid van Moolenbroek 
2960*00b67f09SDavid van Moolenbroek 	REQUIRE(transp != NULL);
2961*00b67f09SDavid van Moolenbroek 	uctx = (updatectx_t *)*transp;
2962*00b67f09SDavid van Moolenbroek 	REQUIRE(UCTX_VALID(uctx));
2963*00b67f09SDavid van Moolenbroek 	client = uctx->client;
2964*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
2965*00b67f09SDavid van Moolenbroek 	REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
2966*00b67f09SDavid van Moolenbroek 		uctx->soareq == NULL && uctx->soaquery == NULL &&
2967*00b67f09SDavid van Moolenbroek 		uctx->event == NULL && uctx->tsigkey == NULL &&
2968*00b67f09SDavid van Moolenbroek 		uctx->sig0key == NULL);
2969*00b67f09SDavid van Moolenbroek 
2970*00b67f09SDavid van Moolenbroek 	mctx = client->mctx;
2971*00b67f09SDavid van Moolenbroek 	dns_view_detach(&uctx->view);
2972*00b67f09SDavid van Moolenbroek 	while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2973*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(uctx->servers, sa, link);
2974*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, sa, sizeof(*sa));
2975*00b67f09SDavid van Moolenbroek 	}
2976*00b67f09SDavid van Moolenbroek 
2977*00b67f09SDavid van Moolenbroek 	LOCK(&client->lock);
2978*00b67f09SDavid van Moolenbroek 
2979*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LINK_LINKED(uctx, link));
2980*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2981*00b67f09SDavid van Moolenbroek 
2982*00b67f09SDavid van Moolenbroek 	if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
2983*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->reqctxs) &&
2984*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(client->updatectxs))
2985*00b67f09SDavid van Moolenbroek 		need_destroyclient = ISC_TRUE;
2986*00b67f09SDavid van Moolenbroek 
2987*00b67f09SDavid van Moolenbroek 	UNLOCK(&client->lock);
2988*00b67f09SDavid van Moolenbroek 
2989*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&uctx->lock);
2990*00b67f09SDavid van Moolenbroek 	uctx->magic = 0;
2991*00b67f09SDavid van Moolenbroek 
2992*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, uctx, sizeof(*uctx));
2993*00b67f09SDavid van Moolenbroek 
2994*00b67f09SDavid van Moolenbroek 	if (need_destroyclient)
2995*00b67f09SDavid van Moolenbroek 		destroyclient(&client);
2996*00b67f09SDavid van Moolenbroek 
2997*00b67f09SDavid van Moolenbroek 	*transp = NULL;
2998*00b67f09SDavid van Moolenbroek }
2999*00b67f09SDavid van Moolenbroek 
3000*00b67f09SDavid van Moolenbroek isc_mem_t *
dns_client_mctx(dns_client_t * client)3001*00b67f09SDavid van Moolenbroek dns_client_mctx(dns_client_t *client) {
3002*00b67f09SDavid van Moolenbroek 
3003*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_CLIENT_VALID(client));
3004*00b67f09SDavid van Moolenbroek 	return (client->mctx);
3005*00b67f09SDavid van Moolenbroek }
3006*00b67f09SDavid van Moolenbroek 
3007*00b67f09SDavid van Moolenbroek typedef struct {
3008*00b67f09SDavid van Moolenbroek 	isc_buffer_t 	buffer;
3009*00b67f09SDavid van Moolenbroek 	dns_rdataset_t	rdataset;
3010*00b67f09SDavid van Moolenbroek 	dns_rdatalist_t	rdatalist;
3011*00b67f09SDavid van Moolenbroek 	dns_rdata_t	rdata;
3012*00b67f09SDavid van Moolenbroek 	size_t		size;
3013*00b67f09SDavid van Moolenbroek 	isc_mem_t *	mctx;
3014*00b67f09SDavid van Moolenbroek 	unsigned char	data[FLEXIBLE_ARRAY_MEMBER];
3015*00b67f09SDavid van Moolenbroek } dns_client_updaterec_t;
3016*00b67f09SDavid van Moolenbroek 
3017*00b67f09SDavid van Moolenbroek isc_result_t
dns_client_updaterec(dns_client_updateop_t op,dns_name_t * owner,dns_rdatatype_t type,dns_rdata_t * source,dns_ttl_t ttl,dns_name_t * target,dns_rdataset_t * rdataset,dns_rdatalist_t * rdatalist,dns_rdata_t * rdata,isc_mem_t * mctx)3018*00b67f09SDavid van Moolenbroek dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner,
3019*00b67f09SDavid van Moolenbroek 		     dns_rdatatype_t type, dns_rdata_t *source,
3020*00b67f09SDavid van Moolenbroek 		     dns_ttl_t ttl, dns_name_t *target,
3021*00b67f09SDavid van Moolenbroek 		     dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist,
3022*00b67f09SDavid van Moolenbroek 		     dns_rdata_t *rdata, isc_mem_t *mctx)
3023*00b67f09SDavid van Moolenbroek {
3024*00b67f09SDavid van Moolenbroek 	dns_client_updaterec_t *updaterec = NULL;
3025*00b67f09SDavid van Moolenbroek 	size_t size = offsetof(dns_client_updaterec_t, data);
3026*00b67f09SDavid van Moolenbroek 
3027*00b67f09SDavid van Moolenbroek 	REQUIRE(op < updateop_max);
3028*00b67f09SDavid van Moolenbroek 	REQUIRE(owner != NULL);
3029*00b67f09SDavid van Moolenbroek 	REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
3030*00b67f09SDavid van Moolenbroek 		(rdataset == NULL && rdatalist == NULL && rdata == NULL &&
3031*00b67f09SDavid van Moolenbroek 		 mctx != NULL));
3032*00b67f09SDavid van Moolenbroek 	if (op == updateop_add)
3033*00b67f09SDavid van Moolenbroek 		REQUIRE(source != NULL);
3034*00b67f09SDavid van Moolenbroek 	if (source != NULL) {
3035*00b67f09SDavid van Moolenbroek 		REQUIRE(source->type == type);
3036*00b67f09SDavid van Moolenbroek 		REQUIRE(op == updateop_add || op == updateop_delete ||
3037*00b67f09SDavid van Moolenbroek 			op == updateop_exist);
3038*00b67f09SDavid van Moolenbroek 	}
3039*00b67f09SDavid van Moolenbroek 
3040*00b67f09SDavid van Moolenbroek 	size += owner->length;
3041*00b67f09SDavid van Moolenbroek 	if (source != NULL)
3042*00b67f09SDavid van Moolenbroek 		size += source->length;
3043*00b67f09SDavid van Moolenbroek 
3044*00b67f09SDavid van Moolenbroek 	if (rdataset == NULL) {
3045*00b67f09SDavid van Moolenbroek 		updaterec = isc_mem_get(mctx, size);
3046*00b67f09SDavid van Moolenbroek 		if (updaterec == NULL)
3047*00b67f09SDavid van Moolenbroek 			return (ISC_R_NOMEMORY);
3048*00b67f09SDavid van Moolenbroek 		rdataset = &updaterec->rdataset;
3049*00b67f09SDavid van Moolenbroek 		rdatalist = &updaterec->rdatalist;
3050*00b67f09SDavid van Moolenbroek 		rdata = &updaterec->rdata;
3051*00b67f09SDavid van Moolenbroek 		dns_rdataset_init(rdataset);
3052*00b67f09SDavid van Moolenbroek 		dns_rdatalist_init(&updaterec->rdatalist);
3053*00b67f09SDavid van Moolenbroek 		dns_rdata_init(&updaterec->rdata);
3054*00b67f09SDavid van Moolenbroek 		isc_buffer_init(&updaterec->buffer, updaterec->data,
3055*00b67f09SDavid van Moolenbroek 				(unsigned int)
3056*00b67f09SDavid van Moolenbroek 				(size -
3057*00b67f09SDavid van Moolenbroek 				 offsetof(dns_client_updaterec_t, data)));
3058*00b67f09SDavid van Moolenbroek 		dns_name_copy(owner, target, &updaterec->buffer);
3059*00b67f09SDavid van Moolenbroek 		if (source != NULL) {
3060*00b67f09SDavid van Moolenbroek 			isc_region_t r;
3061*00b67f09SDavid van Moolenbroek 			dns_rdata_clone(source, rdata);
3062*00b67f09SDavid van Moolenbroek 			dns_rdata_toregion(rdata, &r);
3063*00b67f09SDavid van Moolenbroek 			rdata->data = isc_buffer_used(&updaterec->buffer);
3064*00b67f09SDavid van Moolenbroek 			isc_buffer_copyregion(&updaterec->buffer, &r);
3065*00b67f09SDavid van Moolenbroek 		}
3066*00b67f09SDavid van Moolenbroek 		updaterec->mctx = NULL;
3067*00b67f09SDavid van Moolenbroek 		isc_mem_attach(mctx, &updaterec->mctx);
3068*00b67f09SDavid van Moolenbroek 	} else if (source != NULL)
3069*00b67f09SDavid van Moolenbroek 		dns_rdata_clone(source, rdata);
3070*00b67f09SDavid van Moolenbroek 
3071*00b67f09SDavid van Moolenbroek 	switch (op) {
3072*00b67f09SDavid van Moolenbroek 	case updateop_add:
3073*00b67f09SDavid van Moolenbroek 		break;
3074*00b67f09SDavid van Moolenbroek 	case updateop_delete:
3075*00b67f09SDavid van Moolenbroek 		if (source != NULL) {
3076*00b67f09SDavid van Moolenbroek 			ttl = 0;
3077*00b67f09SDavid van Moolenbroek 			dns_rdata_makedelete(rdata);
3078*00b67f09SDavid van Moolenbroek 		} else
3079*00b67f09SDavid van Moolenbroek 			dns_rdata_deleterrset(rdata, type);
3080*00b67f09SDavid van Moolenbroek 		break;
3081*00b67f09SDavid van Moolenbroek 	case updateop_notexist:
3082*00b67f09SDavid van Moolenbroek 		dns_rdata_notexist(rdata, type);
3083*00b67f09SDavid van Moolenbroek 		break;
3084*00b67f09SDavid van Moolenbroek 	case updateop_exist:
3085*00b67f09SDavid van Moolenbroek 		if (source == NULL) {
3086*00b67f09SDavid van Moolenbroek 			ttl = 0;
3087*00b67f09SDavid van Moolenbroek 			dns_rdata_exists(rdata, type);
3088*00b67f09SDavid van Moolenbroek 		}
3089*00b67f09SDavid van Moolenbroek 	case updateop_none:
3090*00b67f09SDavid van Moolenbroek 		break;
3091*00b67f09SDavid van Moolenbroek 	default:
3092*00b67f09SDavid van Moolenbroek 		INSIST(0);
3093*00b67f09SDavid van Moolenbroek 	}
3094*00b67f09SDavid van Moolenbroek 
3095*00b67f09SDavid van Moolenbroek 	rdatalist->type = rdata->type;
3096*00b67f09SDavid van Moolenbroek 	rdatalist->rdclass = rdata->rdclass;
3097*00b67f09SDavid van Moolenbroek 	if (source != NULL) {
3098*00b67f09SDavid van Moolenbroek 		rdatalist->covers = dns_rdata_covers(rdata);
3099*00b67f09SDavid van Moolenbroek 		rdatalist->ttl = ttl;
3100*00b67f09SDavid van Moolenbroek 	}
3101*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3102*00b67f09SDavid van Moolenbroek 	dns_rdatalist_tordataset(rdatalist, rdataset);
3103*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(target->list, rdataset, link);
3104*00b67f09SDavid van Moolenbroek 	if (updaterec != NULL) {
3105*00b67f09SDavid van Moolenbroek 		target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
3106*00b67f09SDavid van Moolenbroek 		dns_name_setbuffer(target, &updaterec->buffer);
3107*00b67f09SDavid van Moolenbroek 	}
3108*00b67f09SDavid van Moolenbroek 	if (op == updateop_add || op == updateop_delete)
3109*00b67f09SDavid van Moolenbroek 		target->attributes |= DNS_NAMEATTR_UPDATE;
3110*00b67f09SDavid van Moolenbroek 	else
3111*00b67f09SDavid van Moolenbroek 		target->attributes |= DNS_NAMEATTR_PREREQUISITE;
3112*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
3113*00b67f09SDavid van Moolenbroek }
3114*00b67f09SDavid van Moolenbroek 
3115*00b67f09SDavid van Moolenbroek void
dns_client_freeupdate(dns_name_t ** namep)3116*00b67f09SDavid van Moolenbroek dns_client_freeupdate(dns_name_t **namep) {
3117*00b67f09SDavid van Moolenbroek 	dns_client_updaterec_t *updaterec;
3118*00b67f09SDavid van Moolenbroek 	dns_rdatalist_t *rdatalist;
3119*00b67f09SDavid van Moolenbroek 	dns_rdataset_t *rdataset;
3120*00b67f09SDavid van Moolenbroek 	dns_rdata_t *rdata;
3121*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
3122*00b67f09SDavid van Moolenbroek 
3123*00b67f09SDavid van Moolenbroek 	REQUIRE(namep != NULL && *namep != NULL);
3124*00b67f09SDavid van Moolenbroek 
3125*00b67f09SDavid van Moolenbroek 	name = *namep;
3126*00b67f09SDavid van Moolenbroek 	for (rdataset = ISC_LIST_HEAD(name->list);
3127*00b67f09SDavid van Moolenbroek 	     rdataset != NULL;
3128*00b67f09SDavid van Moolenbroek 	     rdataset = ISC_LIST_HEAD(name->list)) {
3129*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(name->list, rdataset, link);
3130*00b67f09SDavid van Moolenbroek 		rdatalist = NULL;
3131*00b67f09SDavid van Moolenbroek 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3132*00b67f09SDavid van Moolenbroek 		if (rdatalist == NULL) {
3133*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(rdataset);
3134*00b67f09SDavid van Moolenbroek 			continue;
3135*00b67f09SDavid van Moolenbroek 		}
3136*00b67f09SDavid van Moolenbroek 		for (rdata = ISC_LIST_HEAD(rdatalist->rdata);
3137*00b67f09SDavid van Moolenbroek 		     rdata != NULL;
3138*00b67f09SDavid van Moolenbroek 		     rdata = ISC_LIST_HEAD(rdatalist->rdata))
3139*00b67f09SDavid van Moolenbroek 			ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3140*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(rdataset);
3141*00b67f09SDavid van Moolenbroek 	}
3142*00b67f09SDavid van Moolenbroek 
3143*00b67f09SDavid van Moolenbroek 	if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3144*00b67f09SDavid van Moolenbroek 		updaterec = (dns_client_updaterec_t *)name->buffer;
3145*00b67f09SDavid van Moolenbroek 		INSIST(updaterec != NULL);
3146*00b67f09SDavid van Moolenbroek 		isc_mem_putanddetach(&updaterec->mctx, updaterec,
3147*00b67f09SDavid van Moolenbroek 				     updaterec->size);
3148*00b67f09SDavid van Moolenbroek 		*namep = NULL;
3149*00b67f09SDavid van Moolenbroek 	}
3150*00b67f09SDavid van Moolenbroek }
3151