]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/irs/context.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / irs / context.c
1 /*
2  * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /* $Id: context.c,v 1.3 2009/09/02 23:48:02 tbox Exp $ */
18
19 #include <config.h>
20
21 #include <isc/app.h>
22 #include <isc/lib.h>
23 #include <isc/magic.h>
24 #include <isc/mem.h>
25 #include <isc/once.h>
26 #include <isc/socket.h>
27 #include <isc/task.h>
28 #include <isc/thread.h>
29 #include <isc/timer.h>
30 #include <isc/util.h>
31
32 #include <dns/client.h>
33 #include <dns/lib.h>
34
35 #include <irs/context.h>
36 #include <irs/dnsconf.h>
37 #include <irs/resconf.h>
38
39 #define IRS_CONTEXT_MAGIC               ISC_MAGIC('I', 'R', 'S', 'c')
40 #define IRS_CONTEXT_VALID(c)            ISC_MAGIC_VALID(c, IRS_CONTEXT_MAGIC)
41
42 #ifndef RESOLV_CONF
43 /*% location of resolve.conf */
44 #define RESOLV_CONF "/etc/resolv.conf"
45 #endif
46
47 #ifndef DNS_CONF
48 /*% location of dns.conf */
49 #define DNS_CONF "/etc/dns.conf"
50 #endif
51
52 #ifndef ISC_PLATFORM_USETHREADS
53 irs_context_t *irs_g_context = NULL;
54 #else
55 static isc_boolean_t thread_key_initialized = ISC_FALSE;
56 static isc_mutex_t thread_key_mutex;
57 static isc_thread_key_t irs_context_key;
58 static isc_once_t once = ISC_ONCE_INIT;
59 #endif
60
61
62 struct irs_context {
63         /*
64          * An IRS context is a thread-specific object, and does not need to
65          * be locked.
66          */
67         unsigned int                    magic;
68         isc_mem_t                       *mctx;
69         isc_appctx_t                    *actx;
70         isc_taskmgr_t                   *taskmgr;
71         isc_task_t                      *task;
72         isc_socketmgr_t                 *socketmgr;
73         isc_timermgr_t                  *timermgr;
74         dns_client_t                    *dnsclient;
75         irs_resconf_t                   *resconf;
76         irs_dnsconf_t                   *dnsconf;
77 };
78
79 static void
80 ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp,
81              isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
82              isc_timermgr_t **timermgrp)
83 {
84         if (taskmgrp != NULL)
85                 isc_taskmgr_destroy(taskmgrp);
86
87         if (timermgrp != NULL)
88                 isc_timermgr_destroy(timermgrp);
89
90         if (socketmgrp != NULL)
91                 isc_socketmgr_destroy(socketmgrp);
92
93         if (actxp != NULL)
94                 isc_appctx_destroy(actxp);
95
96         if (mctxp != NULL)
97                 isc_mem_destroy(mctxp);
98 }
99
100 static isc_result_t
101 ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp,
102           isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
103           isc_timermgr_t **timermgrp)
104 {
105         isc_result_t result;
106
107         result = isc_mem_create(0, 0, mctxp);
108         if (result != ISC_R_SUCCESS)
109                 goto fail;
110
111         result = isc_appctx_create(*mctxp, actxp);
112         if (result != ISC_R_SUCCESS)
113                 goto fail;
114
115         result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp);
116         if (result != ISC_R_SUCCESS)
117                 goto fail;
118
119         result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp);
120         if (result != ISC_R_SUCCESS)
121                 goto fail;
122
123         result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp);
124         if (result != ISC_R_SUCCESS)
125                 goto fail;
126
127         return (ISC_R_SUCCESS);
128
129  fail:
130         ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp);
131
132         return (result);
133 }
134
135 #ifdef ISC_PLATFORM_USETHREADS
136 static void
137 free_specific_context(void *arg) {
138         irs_context_t *context = arg;
139
140         irs_context_destroy(&context);
141
142         isc_thread_key_setspecific(irs_context_key, NULL);
143 }
144
145 static void
146 thread_key_mutex_init(void) {
147         RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS);
148 }
149
150 static isc_result_t
151 thread_key_init() {
152         isc_result_t result;
153
154         result = isc_once_do(&once, thread_key_mutex_init);
155         if (result != ISC_R_SUCCESS)
156                 return (result);
157
158         if (!thread_key_initialized) {
159                 LOCK(&thread_key_mutex);
160
161                 if (!thread_key_initialized &&
162                     isc_thread_key_create(&irs_context_key,
163                                           free_specific_context) != 0) {
164                         result = ISC_R_FAILURE;
165                 } else
166                         thread_key_initialized = ISC_TRUE;
167
168                 UNLOCK(&thread_key_mutex);
169         }
170
171         return (result);
172 }
173 #endif /* ISC_PLATFORM_USETHREADS */
174
175 isc_result_t
176 irs_context_get(irs_context_t **contextp) {
177         irs_context_t *context;
178         isc_result_t result;
179
180         REQUIRE(contextp != NULL && *contextp == NULL);
181
182 #ifndef ISC_PLATFORM_USETHREADS
183         if (irs_g_context == NULL) {
184                 result = irs_context_create(&irs_g_context);
185                 if (result != ISC_R_SUCCESS)
186                         return (result);
187         }
188
189         context = irs_g_context;
190 #else
191         result = thread_key_init();
192         if (result != ISC_R_SUCCESS)
193                 return (result);
194
195         context = isc_thread_key_getspecific(irs_context_key);
196         if (context == NULL) {
197                 result = irs_context_create(&context);
198                 if (result != ISC_R_SUCCESS)
199                         return (result);
200                 result = isc_thread_key_setspecific(irs_context_key, context);
201                 if (result != ISC_R_SUCCESS) {
202                         irs_context_destroy(&context);
203                         return (result);
204                 }
205         }
206 #endif /* ISC_PLATFORM_USETHREADS */
207
208         *contextp = context;
209
210         return (ISC_R_SUCCESS);
211 }
212
213 isc_result_t
214 irs_context_create(irs_context_t **contextp) {
215         isc_result_t result;
216         irs_context_t *context;
217         isc_appctx_t *actx = NULL;
218         isc_mem_t *mctx = NULL;
219         isc_taskmgr_t *taskmgr = NULL;
220         isc_socketmgr_t *socketmgr = NULL;
221         isc_timermgr_t *timermgr = NULL;
222         dns_client_t *client = NULL;
223         isc_sockaddrlist_t *nameservers;
224         irs_dnsconf_dnskeylist_t *trustedkeys;
225         irs_dnsconf_dnskey_t *trustedkey;
226
227         isc_lib_register();
228         result = dns_lib_init();
229         if (result != ISC_R_SUCCESS)
230                 return (result);
231
232         result = ctxs_init(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);
233         if (result != ISC_R_SUCCESS)
234                 return (result);
235
236         result = isc_app_ctxstart(actx);
237         if (result != ISC_R_SUCCESS) {
238                 ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);
239                 return (result);
240         }
241
242         context = isc_mem_get(mctx, sizeof(*context));
243         if (context == NULL) {
244                 ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);
245                 return (ISC_R_NOMEMORY);
246         }
247
248         context->mctx = mctx;
249         context->actx = actx;
250         context->taskmgr = taskmgr;
251         context->socketmgr = socketmgr;
252         context->timermgr = timermgr;
253         context->resconf = NULL;
254         context->dnsconf = NULL;
255         context->task = NULL;
256         result = isc_task_create(taskmgr, 0, &context->task);
257         if (result != ISC_R_SUCCESS)
258                 goto fail;
259
260         /* Create a DNS client object */
261         result = dns_client_createx(mctx, actx, taskmgr, socketmgr, timermgr,
262                                     0, &client);
263         if (result != ISC_R_SUCCESS)
264                 goto fail;
265         context->dnsclient = client;
266
267         /* Read resolver configuration file */
268         result = irs_resconf_load(mctx, RESOLV_CONF, &context->resconf);
269         if (result != ISC_R_SUCCESS)
270                 goto fail;
271         /* Set nameservers */
272         nameservers = irs_resconf_getnameservers(context->resconf);
273         result = dns_client_setservers(client, dns_rdataclass_in, NULL,
274                                        nameservers);
275         if (result != ISC_R_SUCCESS)
276                 goto fail;
277
278         /* Read advanced DNS configuration (if any) */
279         result = irs_dnsconf_load(mctx, DNS_CONF, &context->dnsconf);
280         if (result != ISC_R_SUCCESS)
281                 goto fail;
282         trustedkeys = irs_dnsconf_gettrustedkeys(context->dnsconf);
283         for (trustedkey = ISC_LIST_HEAD(*trustedkeys);
284              trustedkey != NULL;
285              trustedkey = ISC_LIST_NEXT(trustedkey, link)) {
286                 result = dns_client_addtrustedkey(client, dns_rdataclass_in,
287                                                   trustedkey->keyname,
288                                                   trustedkey->keydatabuf);
289                 if (result != ISC_R_SUCCESS)
290                         goto fail;
291         }
292
293         context->magic = IRS_CONTEXT_MAGIC;
294         *contextp = context;
295
296         return (ISC_R_SUCCESS);
297
298   fail:
299         if (context->task != NULL)
300                 isc_task_detach(&context->task);
301         if (context->resconf != NULL)
302                 irs_resconf_destroy(&context->resconf);
303         if (context->dnsconf != NULL)
304                 irs_dnsconf_destroy(&context->dnsconf);
305         if (client != NULL)
306                 dns_client_destroy(&client);
307         ctxs_destroy(NULL, &actx, &taskmgr, &socketmgr, &timermgr);
308         isc_mem_putanddetach(&mctx, context, sizeof(*context));
309
310         return (result);
311 }
312
313 void
314 irs_context_destroy(irs_context_t **contextp) {
315         irs_context_t *context;
316
317         REQUIRE(contextp != NULL);
318         context = *contextp;
319         REQUIRE(IRS_CONTEXT_VALID(context));
320
321         isc_task_detach(&context->task);
322         irs_dnsconf_destroy(&context->dnsconf);
323         irs_resconf_destroy(&context->resconf);
324         dns_client_destroy(&context->dnsclient);
325
326         ctxs_destroy(NULL, &context->actx, &context->taskmgr,
327                      &context->socketmgr, &context->timermgr);
328
329         context->magic = 0;
330
331         isc_mem_putanddetach(&context->mctx, context, sizeof(*context));
332
333         *contextp = NULL;
334
335 #ifndef ISC_PLATFORM_USETHREADS
336         irs_g_context = NULL;
337 #else
338         (void)isc_thread_key_setspecific(irs_context_key, NULL);
339 #endif
340 }
341
342 isc_mem_t *
343 irs_context_getmctx(irs_context_t *context) {
344         REQUIRE(IRS_CONTEXT_VALID(context));
345
346         return (context->mctx);
347 }
348
349 isc_appctx_t *
350 irs_context_getappctx(irs_context_t *context) {
351         REQUIRE(IRS_CONTEXT_VALID(context));
352
353         return (context->actx);
354 }
355
356 isc_taskmgr_t *
357 irs_context_gettaskmgr(irs_context_t *context) {
358         REQUIRE(IRS_CONTEXT_VALID(context));
359
360         return (context->taskmgr);
361 }
362
363 isc_timermgr_t *
364 irs_context_gettimermgr(irs_context_t *context) {
365         REQUIRE(IRS_CONTEXT_VALID(context));
366
367         return (context->timermgr);
368 }
369
370 isc_task_t *
371 irs_context_gettask(irs_context_t *context) {
372         REQUIRE(IRS_CONTEXT_VALID(context));
373
374         return (context->task);
375 }
376
377 dns_client_t *
378 irs_context_getdnsclient(irs_context_t *context) {
379         REQUIRE(IRS_CONTEXT_VALID(context));
380
381         return (context->dnsclient);
382 }
383
384 irs_resconf_t *
385 irs_context_getresconf(irs_context_t *context) {
386         REQUIRE(IRS_CONTEXT_VALID(context));
387
388         return (context->resconf);
389 }
390
391 irs_dnsconf_t *
392 irs_context_getdnsconf(irs_context_t *context) {
393         REQUIRE(IRS_CONTEXT_VALID(context));
394
395         return (context->dnsconf);
396 }