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 53irs_context_t *irs_g_context = NULL; 54#else 55static isc_boolean_t thread_key_initialized = ISC_FALSE; 56static isc_mutex_t thread_key_mutex; 57static isc_thread_key_t irs_context_key; 58static isc_once_t once = ISC_ONCE_INIT; 59#endif 60 61 62struct 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 79static void 80ctxs_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 100static isc_result_t 101ctxs_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 136static void 137free_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 145static void 146thread_key_mutex_init(void) { 147 RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS); 148} 149 150static isc_result_t 151thread_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 175isc_result_t 176irs_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 213isc_result_t 214irs_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 313void 314irs_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 342isc_mem_t * 343irs_context_getmctx(irs_context_t *context) { 344 REQUIRE(IRS_CONTEXT_VALID(context)); 345 346 return (context->mctx); 347} 348 349isc_appctx_t * 350irs_context_getappctx(irs_context_t *context) { 351 REQUIRE(IRS_CONTEXT_VALID(context)); 352 353 return (context->actx); 354} 355 356isc_taskmgr_t * 357irs_context_gettaskmgr(irs_context_t *context) { 358 REQUIRE(IRS_CONTEXT_VALID(context)); 359 360 return (context->taskmgr); 361} 362 363isc_timermgr_t * 364irs_context_gettimermgr(irs_context_t *context) { 365 REQUIRE(IRS_CONTEXT_VALID(context)); 366 367 return (context->timermgr); 368} 369 370isc_task_t * 371irs_context_gettask(irs_context_t *context) { 372 REQUIRE(IRS_CONTEXT_VALID(context)); 373 374 return (context->task); 375} 376 377dns_client_t * 378irs_context_getdnsclient(irs_context_t *context) { 379 REQUIRE(IRS_CONTEXT_VALID(context)); 380 381 return (context->dnsclient); 382} 383 384irs_resconf_t * 385irs_context_getresconf(irs_context_t *context) { 386 REQUIRE(IRS_CONTEXT_VALID(context)); 387 388 return (context->resconf); 389} 390 391irs_dnsconf_t * 392irs_context_getdnsconf(irs_context_t *context) { 393 REQUIRE(IRS_CONTEXT_VALID(context)); 394 395 return (context->dnsconf); 396} 397