Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / bin / named / lwresd.c
blob93409faaf5bdc2372cc5daa967a1f818049a9213
1 /*
2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: lwresd.c,v 1.55.130.3 2008/07/23 23:31:17 marka Exp $ */
20 /*! \file
21 * \brief
22 * Main program for the Lightweight Resolver Daemon.
24 * To paraphrase the old saying about X11, "It's not a lightweight deamon
25 * for resolvers, it's a deamon for lightweight resolvers".
28 #include <config.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #include <isc/list.h>
34 #include <isc/magic.h>
35 #include <isc/mem.h>
36 #include <isc/once.h>
37 #include <isc/print.h>
38 #include <isc/socket.h>
39 #include <isc/task.h>
40 #include <isc/util.h>
42 #include <isccfg/namedconf.h>
44 #include <dns/log.h>
45 #include <dns/result.h>
46 #include <dns/view.h>
48 #include <named/config.h>
49 #include <named/globals.h>
50 #include <named/log.h>
51 #include <named/lwaddr.h>
52 #include <named/lwresd.h>
53 #include <named/lwdclient.h>
54 #include <named/lwsearch.h>
55 #include <named/server.h>
57 #define LWRESD_MAGIC ISC_MAGIC('L', 'W', 'R', 'D')
58 #define VALID_LWRESD(l) ISC_MAGIC_VALID(l, LWRESD_MAGIC)
60 #define LWRESLISTENER_MAGIC ISC_MAGIC('L', 'W', 'R', 'L')
61 #define VALID_LWRESLISTENER(l) ISC_MAGIC_VALID(l, LWRESLISTENER_MAGIC)
63 /*!
64 * The total number of clients we can handle will be NTASKS * NRECVS.
66 #define NTASKS 2 /*%< tasks to create to handle lwres queries */
67 #define NRECVS 2 /*%< max clients per task */
69 typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t;
71 static ns_lwreslistenerlist_t listeners;
72 static isc_mutex_t listeners_lock;
73 static isc_once_t once = ISC_ONCE_INIT;
76 static void
77 initialize_mutex(void) {
78 RUNTIME_CHECK(isc_mutex_init(&listeners_lock) == ISC_R_SUCCESS);
82 /*%
83 * Wrappers around our memory management stuff, for the lwres functions.
85 void *
86 ns__lwresd_memalloc(void *arg, size_t size) {
87 return (isc_mem_get(arg, size));
90 void
91 ns__lwresd_memfree(void *arg, void *mem, size_t size) {
92 isc_mem_put(arg, mem, size);
96 #define CHECK(op) \
97 do { result = (op); \
98 if (result != ISC_R_SUCCESS) goto cleanup; \
99 } while (0)
101 static isc_result_t
102 buffer_putstr(isc_buffer_t *b, const char *s) {
103 unsigned int len = strlen(s);
104 if (isc_buffer_availablelength(b) <= len)
105 return (ISC_R_NOSPACE);
106 isc_buffer_putmem(b, (const unsigned char *)s, len);
107 return (ISC_R_SUCCESS);
111 * Convert a resolv.conf file into a config structure.
113 isc_result_t
114 ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx,
115 cfg_obj_t **configp)
117 char text[4096];
118 char str[16];
119 isc_buffer_t b;
120 lwres_context_t *lwctx = NULL;
121 lwres_conf_t *lwc = NULL;
122 isc_sockaddr_t sa;
123 isc_netaddr_t na;
124 int i;
125 isc_result_t result;
126 lwres_result_t lwresult;
128 lwctx = NULL;
129 lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc,
130 ns__lwresd_memfree,
131 LWRES_CONTEXT_SERVERMODE);
132 if (lwresult != LWRES_R_SUCCESS) {
133 result = ISC_R_NOMEMORY;
134 goto cleanup;
137 lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile);
138 if (lwresult != LWRES_R_SUCCESS) {
139 result = DNS_R_SYNTAX;
140 goto cleanup;
143 lwc = lwres_conf_get(lwctx);
144 INSIST(lwc != NULL);
146 isc_buffer_init(&b, text, sizeof(text));
148 CHECK(buffer_putstr(&b, "options {\n"));
151 * Build the list of forwarders.
153 if (lwc->nsnext > 0) {
154 CHECK(buffer_putstr(&b, "\tforwarders {\n"));
156 for (i = 0; i < lwc->nsnext; i++) {
157 CHECK(lwaddr_sockaddr_fromlwresaddr(
158 &sa,
159 &lwc->nameservers[i],
160 ns_g_port));
161 isc_netaddr_fromsockaddr(&na, &sa);
162 CHECK(buffer_putstr(&b, "\t\t"));
163 CHECK(isc_netaddr_totext(&na, &b));
164 CHECK(buffer_putstr(&b, ";\n"));
166 CHECK(buffer_putstr(&b, "\t};\n"));
170 * Build the sortlist
172 if (lwc->sortlistnxt > 0) {
173 CHECK(buffer_putstr(&b, "\tsortlist {\n"));
174 CHECK(buffer_putstr(&b, "\t\t{\n"));
175 CHECK(buffer_putstr(&b, "\t\t\tany;\n"));
176 CHECK(buffer_putstr(&b, "\t\t\t{\n"));
177 for (i = 0; i < lwc->sortlistnxt; i++) {
178 lwres_addr_t *lwaddr = &lwc->sortlist[i].addr;
179 lwres_addr_t *lwmask = &lwc->sortlist[i].mask;
180 unsigned int mask;
182 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0));
183 isc_netaddr_fromsockaddr(&na, &sa);
184 result = isc_netaddr_masktoprefixlen(&na, &mask);
185 if (result != ISC_R_SUCCESS) {
186 char addrtext[ISC_NETADDR_FORMATSIZE];
187 isc_netaddr_format(&na, addrtext,
188 sizeof(addrtext));
189 isc_log_write(ns_g_lctx,
190 NS_LOGCATEGORY_GENERAL,
191 NS_LOGMODULE_LWRESD,
192 ISC_LOG_ERROR,
193 "processing sortlist: '%s' is "
194 "not a valid netmask",
195 addrtext);
196 goto cleanup;
199 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0));
200 isc_netaddr_fromsockaddr(&na, &sa);
202 CHECK(buffer_putstr(&b, "\t\t\t\t"));
203 CHECK(isc_netaddr_totext(&na, &b));
204 snprintf(str, sizeof(str), "%u", mask);
205 CHECK(buffer_putstr(&b, "/"));
206 CHECK(buffer_putstr(&b, str));
207 CHECK(buffer_putstr(&b, ";\n"));
209 CHECK(buffer_putstr(&b, "\t\t\t};\n"));
210 CHECK(buffer_putstr(&b, "\t\t};\n"));
211 CHECK(buffer_putstr(&b, "\t};\n"));
214 CHECK(buffer_putstr(&b, "};\n\n"));
216 CHECK(buffer_putstr(&b, "lwres {\n"));
219 * Build the search path
221 if (lwc->searchnxt > 0) {
222 if (lwc->searchnxt > 0) {
223 CHECK(buffer_putstr(&b, "\tsearch {\n"));
224 for (i = 0; i < lwc->searchnxt; i++) {
225 CHECK(buffer_putstr(&b, "\t\t\""));
226 CHECK(buffer_putstr(&b, lwc->search[i]));
227 CHECK(buffer_putstr(&b, "\";\n"));
229 CHECK(buffer_putstr(&b, "\t};\n"));
234 * Build the ndots line
236 if (lwc->ndots != 1) {
237 CHECK(buffer_putstr(&b, "\tndots "));
238 snprintf(str, sizeof(str), "%u", lwc->ndots);
239 CHECK(buffer_putstr(&b, str));
240 CHECK(buffer_putstr(&b, ";\n"));
244 * Build the listen-on line
246 if (lwc->lwnext > 0) {
247 CHECK(buffer_putstr(&b, "\tlisten-on {\n"));
249 for (i = 0; i < lwc->lwnext; i++) {
250 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa,
251 &lwc->lwservers[i],
252 0));
253 isc_netaddr_fromsockaddr(&na, &sa);
254 CHECK(buffer_putstr(&b, "\t\t"));
255 CHECK(isc_netaddr_totext(&na, &b));
256 CHECK(buffer_putstr(&b, ";\n"));
258 CHECK(buffer_putstr(&b, "\t};\n"));
261 CHECK(buffer_putstr(&b, "};\n"));
263 #if 0
264 printf("%.*s\n",
265 (int)isc_buffer_usedlength(&b),
266 (char *)isc_buffer_base(&b));
267 #endif
269 lwres_conf_clear(lwctx);
270 lwres_context_destroy(&lwctx);
272 return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp));
274 cleanup:
276 if (lwctx != NULL) {
277 lwres_conf_clear(lwctx);
278 lwres_context_destroy(&lwctx);
281 return (result);
286 * Handle lwresd manager objects
288 isc_result_t
289 ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres,
290 ns_lwresd_t **lwresdp)
292 ns_lwresd_t *lwresd;
293 const char *vname;
294 dns_rdataclass_t vclass;
295 const cfg_obj_t *obj, *viewobj, *searchobj;
296 const cfg_listelt_t *element;
297 isc_result_t result;
299 INSIST(lwresdp != NULL && *lwresdp == NULL);
301 lwresd = isc_mem_get(mctx, sizeof(ns_lwresd_t));
302 if (lwresd == NULL)
303 return (ISC_R_NOMEMORY);
305 lwresd->mctx = NULL;
306 isc_mem_attach(mctx, &lwresd->mctx);
307 lwresd->view = NULL;
308 lwresd->search = NULL;
309 lwresd->refs = 1;
311 obj = NULL;
312 (void)cfg_map_get(lwres, "ndots", &obj);
313 if (obj != NULL)
314 lwresd->ndots = cfg_obj_asuint32(obj);
315 else
316 lwresd->ndots = 1;
318 RUNTIME_CHECK(isc_mutex_init(&lwresd->lock) == ISC_R_SUCCESS);
320 lwresd->shutting_down = ISC_FALSE;
322 viewobj = NULL;
323 (void)cfg_map_get(lwres, "view", &viewobj);
324 if (viewobj != NULL) {
325 vname = cfg_obj_asstring(cfg_tuple_get(viewobj, "name"));
326 obj = cfg_tuple_get(viewobj, "class");
327 result = ns_config_getclass(obj, dns_rdataclass_in, &vclass);
328 if (result != ISC_R_SUCCESS)
329 goto fail;
330 } else {
331 vname = "_default";
332 vclass = dns_rdataclass_in;
335 result = dns_viewlist_find(&ns_g_server->viewlist, vname, vclass,
336 &lwresd->view);
337 if (result != ISC_R_SUCCESS) {
338 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
339 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
340 "couldn't find view %s", vname);
341 goto fail;
344 searchobj = NULL;
345 (void)cfg_map_get(lwres, "search", &searchobj);
346 if (searchobj != NULL) {
347 lwresd->search = NULL;
348 result = ns_lwsearchlist_create(lwresd->mctx,
349 &lwresd->search);
350 if (result != ISC_R_SUCCESS) {
351 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
352 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
353 "couldn't create searchlist");
354 goto fail;
356 for (element = cfg_list_first(searchobj);
357 element != NULL;
358 element = cfg_list_next(element))
360 const cfg_obj_t *search;
361 const char *searchstr;
362 isc_buffer_t namebuf;
363 dns_fixedname_t fname;
364 dns_name_t *name;
366 search = cfg_listelt_value(element);
367 searchstr = cfg_obj_asstring(search);
369 dns_fixedname_init(&fname);
370 name = dns_fixedname_name(&fname);
371 isc_buffer_init(&namebuf, searchstr,
372 strlen(searchstr));
373 isc_buffer_add(&namebuf, strlen(searchstr));
374 result = dns_name_fromtext(name, &namebuf,
375 dns_rootname, ISC_FALSE,
376 NULL);
377 if (result != ISC_R_SUCCESS) {
378 isc_log_write(ns_g_lctx,
379 NS_LOGCATEGORY_GENERAL,
380 NS_LOGMODULE_LWRESD,
381 ISC_LOG_WARNING,
382 "invalid name %s in searchlist",
383 searchstr);
384 continue;
387 result = ns_lwsearchlist_append(lwresd->search, name);
388 if (result != ISC_R_SUCCESS) {
389 isc_log_write(ns_g_lctx,
390 NS_LOGCATEGORY_GENERAL,
391 NS_LOGMODULE_LWRESD,
392 ISC_LOG_WARNING,
393 "couldn't update searchlist");
394 goto fail;
399 lwresd->magic = LWRESD_MAGIC;
401 *lwresdp = lwresd;
402 return (ISC_R_SUCCESS);
404 fail:
405 if (lwresd->view != NULL)
406 dns_view_detach(&lwresd->view);
407 if (lwresd->search != NULL)
408 ns_lwsearchlist_detach(&lwresd->search);
409 if (lwresd->mctx != NULL)
410 isc_mem_detach(&lwresd->mctx);
411 isc_mem_put(mctx, lwresd, sizeof(ns_lwresd_t));
412 return (result);
415 void
416 ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp) {
417 INSIST(VALID_LWRESD(source));
418 INSIST(targetp != NULL && *targetp == NULL);
420 LOCK(&source->lock);
421 source->refs++;
422 UNLOCK(&source->lock);
424 *targetp = source;
427 void
428 ns_lwdmanager_detach(ns_lwresd_t **lwresdp) {
429 ns_lwresd_t *lwresd;
430 isc_mem_t *mctx;
431 isc_boolean_t done = ISC_FALSE;
433 INSIST(lwresdp != NULL && *lwresdp != NULL);
434 INSIST(VALID_LWRESD(*lwresdp));
436 lwresd = *lwresdp;
437 *lwresdp = NULL;
439 LOCK(&lwresd->lock);
440 INSIST(lwresd->refs > 0);
441 lwresd->refs--;
442 if (lwresd->refs == 0)
443 done = ISC_TRUE;
444 UNLOCK(&lwresd->lock);
446 if (!done)
447 return;
449 dns_view_detach(&lwresd->view);
450 if (lwresd->search != NULL)
451 ns_lwsearchlist_detach(&lwresd->search);
452 mctx = lwresd->mctx;
453 lwresd->magic = 0;
454 isc_mem_put(mctx, lwresd, sizeof(*lwresd));
455 isc_mem_detach(&mctx);
460 * Handle listener objects
462 void
463 ns_lwreslistener_attach(ns_lwreslistener_t *source,
464 ns_lwreslistener_t **targetp)
466 INSIST(VALID_LWRESLISTENER(source));
467 INSIST(targetp != NULL && *targetp == NULL);
469 LOCK(&source->lock);
470 source->refs++;
471 UNLOCK(&source->lock);
473 *targetp = source;
476 void
477 ns_lwreslistener_detach(ns_lwreslistener_t **listenerp) {
478 ns_lwreslistener_t *listener;
479 isc_mem_t *mctx;
480 isc_boolean_t done = ISC_FALSE;
482 INSIST(listenerp != NULL && *listenerp != NULL);
483 INSIST(VALID_LWRESLISTENER(*listenerp));
485 listener = *listenerp;
487 LOCK(&listener->lock);
488 INSIST(listener->refs > 0);
489 listener->refs--;
490 if (listener->refs == 0)
491 done = ISC_TRUE;
492 UNLOCK(&listener->lock);
494 if (!done)
495 return;
497 if (listener->manager != NULL)
498 ns_lwdmanager_detach(&listener->manager);
500 if (listener->sock != NULL)
501 isc_socket_detach(&listener->sock);
503 listener->magic = 0;
504 mctx = listener->mctx;
505 isc_mem_put(mctx, listener, sizeof(*listener));
506 isc_mem_detach(&mctx);
507 listenerp = NULL;
510 static isc_result_t
511 listener_create(isc_mem_t *mctx, ns_lwresd_t *lwresd,
512 ns_lwreslistener_t **listenerp)
514 ns_lwreslistener_t *listener;
515 isc_result_t result;
517 REQUIRE(listenerp != NULL && *listenerp == NULL);
519 listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t));
520 if (listener == NULL)
521 return (ISC_R_NOMEMORY);
523 result = isc_mutex_init(&listener->lock);
524 if (result != ISC_R_SUCCESS) {
525 isc_mem_put(mctx, listener, sizeof(ns_lwreslistener_t));
526 return (result);
529 listener->magic = LWRESLISTENER_MAGIC;
530 listener->refs = 1;
532 listener->sock = NULL;
534 listener->manager = NULL;
535 ns_lwdmanager_attach(lwresd, &listener->manager);
537 listener->mctx = NULL;
538 isc_mem_attach(mctx, &listener->mctx);
540 ISC_LINK_INIT(listener, link);
541 ISC_LIST_INIT(listener->cmgrs);
543 *listenerp = listener;
544 return (ISC_R_SUCCESS);
547 static isc_result_t
548 listener_bind(ns_lwreslistener_t *listener, isc_sockaddr_t *address) {
549 isc_socket_t *sock = NULL;
550 isc_result_t result = ISC_R_SUCCESS;
551 int pf;
553 pf = isc_sockaddr_pf(address);
554 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
555 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
556 return (ISC_R_FAMILYNOSUPPORT);
558 listener->address = *address;
560 if (isc_sockaddr_getport(&listener->address) == 0) {
561 in_port_t port;
562 port = lwresd_g_listenport;
563 if (port == 0)
564 port = LWRES_UDP_PORT;
565 isc_sockaddr_setport(&listener->address, port);
568 sock = NULL;
569 result = isc_socket_create(ns_g_socketmgr, pf,
570 isc_sockettype_udp, &sock);
571 if (result != ISC_R_SUCCESS) {
572 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
573 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
574 "failed to create lwres socket: %s",
575 isc_result_totext(result));
576 return (result);
579 result = isc_socket_bind(sock, &listener->address,
580 ISC_SOCKET_REUSEADDRESS);
581 if (result != ISC_R_SUCCESS) {
582 char socktext[ISC_SOCKADDR_FORMATSIZE];
583 isc_sockaddr_format(&listener->address, socktext,
584 sizeof(socktext));
585 isc_socket_detach(&sock);
586 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
587 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
588 "failed to add lwres socket: %s: %s",
589 socktext, isc_result_totext(result));
590 return (result);
592 listener->sock = sock;
593 return (ISC_R_SUCCESS);
596 static void
597 listener_copysock(ns_lwreslistener_t *oldlistener,
598 ns_lwreslistener_t *newlistener)
600 newlistener->address = oldlistener->address;
601 isc_socket_attach(oldlistener->sock, &newlistener->sock);
604 static isc_result_t
605 listener_startclients(ns_lwreslistener_t *listener) {
606 ns_lwdclientmgr_t *cm;
607 unsigned int i;
608 isc_result_t result;
611 * Create the client managers.
613 result = ISC_R_SUCCESS;
614 for (i = 0; i < NTASKS && result == ISC_R_SUCCESS; i++)
615 result = ns_lwdclientmgr_create(listener, NRECVS,
616 ns_g_taskmgr);
619 * Ensure that we have created at least one.
621 if (ISC_LIST_EMPTY(listener->cmgrs))
622 return (result);
625 * Walk the list of clients and start each one up.
627 LOCK(&listener->lock);
628 cm = ISC_LIST_HEAD(listener->cmgrs);
629 while (cm != NULL) {
630 result = ns_lwdclient_startrecv(cm);
631 if (result != ISC_R_SUCCESS)
632 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
633 NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
634 "could not start lwres "
635 "client handler: %s",
636 isc_result_totext(result));
637 cm = ISC_LIST_NEXT(cm, link);
639 UNLOCK(&listener->lock);
641 return (ISC_R_SUCCESS);
644 static void
645 listener_shutdown(ns_lwreslistener_t *listener) {
646 ns_lwdclientmgr_t *cm;
648 cm = ISC_LIST_HEAD(listener->cmgrs);
649 while (cm != NULL) {
650 isc_task_shutdown(cm->task);
651 cm = ISC_LIST_NEXT(cm, link);
655 static isc_result_t
656 find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) {
657 ns_lwreslistener_t *listener;
659 INSIST(listenerp != NULL && *listenerp == NULL);
661 for (listener = ISC_LIST_HEAD(listeners);
662 listener != NULL;
663 listener = ISC_LIST_NEXT(listener, link))
665 if (!isc_sockaddr_equal(address, &listener->address))
666 continue;
667 *listenerp = listener;
668 return (ISC_R_SUCCESS);
670 return (ISC_R_NOTFOUND);
673 void
674 ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm)
676 REQUIRE(VALID_LWRESLISTENER(listener));
678 LOCK(&listener->lock);
679 ISC_LIST_UNLINK(listener->cmgrs, cm, link);
680 UNLOCK(&listener->lock);
683 void
684 ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) {
685 REQUIRE(VALID_LWRESLISTENER(listener));
688 * This does no locking, since it's called early enough that locking
689 * isn't needed.
691 ISC_LIST_APPEND(listener->cmgrs, cm, link);
694 static isc_result_t
695 configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd,
696 isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners)
698 ns_lwreslistener_t *listener, *oldlistener = NULL;
699 char socktext[ISC_SOCKADDR_FORMATSIZE];
700 isc_result_t result;
702 (void)find_listener(address, &oldlistener);
703 listener = NULL;
704 result = listener_create(mctx, lwresd, &listener);
705 if (result != ISC_R_SUCCESS) {
706 isc_sockaddr_format(address, socktext, sizeof(socktext));
707 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
708 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
709 "lwres failed to configure %s: %s",
710 socktext, isc_result_totext(result));
711 return (result);
715 * If there's already a listener, don't rebind the socket.
717 if (oldlistener == NULL) {
718 result = listener_bind(listener, address);
719 if (result != ISC_R_SUCCESS) {
720 ns_lwreslistener_detach(&listener);
721 return (ISC_R_SUCCESS);
723 } else
724 listener_copysock(oldlistener, listener);
726 result = listener_startclients(listener);
727 if (result != ISC_R_SUCCESS) {
728 isc_sockaddr_format(address, socktext, sizeof(socktext));
729 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
730 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
731 "lwres: failed to start %s: %s", socktext,
732 isc_result_totext(result));
733 ns_lwreslistener_detach(&listener);
734 return (ISC_R_SUCCESS);
737 if (oldlistener != NULL) {
739 * Remove the old listener from the old list and shut it down.
741 ISC_LIST_UNLINK(listeners, oldlistener, link);
742 listener_shutdown(oldlistener);
743 ns_lwreslistener_detach(&oldlistener);
744 } else {
745 isc_sockaddr_format(address, socktext, sizeof(socktext));
746 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
747 NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
748 "lwres listening on %s", socktext);
751 ISC_LIST_APPEND(*newlisteners, listener, link);
752 return (result);
755 isc_result_t
756 ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) {
757 const cfg_obj_t *lwreslist = NULL;
758 const cfg_obj_t *lwres = NULL;
759 const cfg_obj_t *listenerslist = NULL;
760 const cfg_listelt_t *element = NULL;
761 ns_lwreslistener_t *listener;
762 ns_lwreslistenerlist_t newlisteners;
763 isc_result_t result;
764 char socktext[ISC_SOCKADDR_FORMATSIZE];
765 isc_sockaddr_t *addrs = NULL;
766 ns_lwresd_t *lwresd = NULL;
767 isc_uint32_t count = 0;
769 REQUIRE(mctx != NULL);
770 REQUIRE(config != NULL);
772 RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
774 ISC_LIST_INIT(newlisteners);
776 result = cfg_map_get(config, "lwres", &lwreslist);
777 if (result != ISC_R_SUCCESS)
778 return (ISC_R_SUCCESS);
780 LOCK(&listeners_lock);
782 * Run through the new lwres address list, noting sockets that
783 * are already being listened on and moving them to the new list.
785 * Identifying duplicates addr/port combinations is left to either
786 * the underlying config code, or to the bind attempt getting an
787 * address-in-use error.
789 for (element = cfg_list_first(lwreslist);
790 element != NULL;
791 element = cfg_list_next(element))
793 in_port_t port;
795 lwres = cfg_listelt_value(element);
796 CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd));
798 port = lwresd_g_listenport;
799 if (port == 0)
800 port = LWRES_UDP_PORT;
802 listenerslist = NULL;
803 (void)cfg_map_get(lwres, "listen-on", &listenerslist);
804 if (listenerslist == NULL) {
805 struct in_addr localhost;
806 isc_sockaddr_t address;
808 localhost.s_addr = htonl(INADDR_LOOPBACK);
809 isc_sockaddr_fromin(&address, &localhost, port);
810 CHECK(configure_listener(&address, lwresd, mctx,
811 &newlisteners));
812 } else {
813 isc_uint32_t i;
815 CHECK(ns_config_getiplist(config, listenerslist,
816 port, mctx, &addrs, &count));
817 for (i = 0; i < count; i++)
818 CHECK(configure_listener(&addrs[i], lwresd,
819 mctx, &newlisteners));
820 ns_config_putiplist(mctx, &addrs, count);
822 ns_lwdmanager_detach(&lwresd);
826 * Shutdown everything on the listeners list, and remove them from
827 * the list. Then put all of the new listeners on it.
830 while (!ISC_LIST_EMPTY(listeners)) {
831 listener = ISC_LIST_HEAD(listeners);
832 ISC_LIST_UNLINK(listeners, listener, link);
834 isc_sockaddr_format(&listener->address,
835 socktext, sizeof(socktext));
837 listener_shutdown(listener);
838 ns_lwreslistener_detach(&listener);
840 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
841 NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
842 "lwres no longer listening on %s", socktext);
845 cleanup:
846 ISC_LIST_APPENDLIST(listeners, newlisteners, link);
848 if (addrs != NULL)
849 ns_config_putiplist(mctx, &addrs, count);
851 if (lwresd != NULL)
852 ns_lwdmanager_detach(&lwresd);
854 UNLOCK(&listeners_lock);
856 return (result);
859 void
860 ns_lwresd_shutdown(void) {
861 ns_lwreslistener_t *listener;
863 RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
865 while (!ISC_LIST_EMPTY(listeners)) {
866 listener = ISC_LIST_HEAD(listeners);
867 ISC_LIST_UNLINK(listeners, listener, link);
868 ns_lwreslistener_detach(&listener);