]>
Commit | Line | Data |
---|---|---|
89c4ed63 A |
1 | /* |
2 | * daemon/daemon.c - collection of workers that handles requests. | |
3 | * | |
4 | * Copyright (c) 2007, NLnet Labs. All rights reserved. | |
5 | * | |
6 | * This software is open source. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * Redistributions of source code must retain the above copyright notice, | |
13 | * this list of conditions and the following disclaimer. | |
14 | * | |
15 | * Redistributions in binary form must reproduce the above copyright notice, | |
16 | * this list of conditions and the following disclaimer in the documentation | |
17 | * and/or other materials provided with the distribution. | |
18 | * | |
19 | * Neither the name of the NLNET LABS nor the names of its contributors may | |
20 | * be used to endorse or promote products derived from this software without | |
21 | * specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
27 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
29 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 | */ | |
35 | ||
36 | /** | |
37 | * \file | |
38 | * | |
39 | * The daemon consists of global settings and a number of workers. | |
40 | */ | |
41 | ||
42 | #include "config.h" | |
43 | #ifdef HAVE_OPENSSL_ERR_H | |
44 | #include <openssl/err.h> | |
45 | #endif | |
46 | ||
47 | #ifdef HAVE_OPENSSL_RAND_H | |
48 | #include <openssl/rand.h> | |
49 | #endif | |
50 | ||
51 | #ifdef HAVE_OPENSSL_CONF_H | |
52 | #include <openssl/conf.h> | |
53 | #endif | |
54 | ||
55 | #ifdef HAVE_OPENSSL_ENGINE_H | |
56 | #include <openssl/engine.h> | |
57 | #endif | |
58 | ||
59 | #ifdef HAVE_TIME_H | |
60 | #include <time.h> | |
61 | #endif | |
62 | #include <sys/time.h> | |
63 | ||
64 | #ifdef HAVE_NSS | |
65 | /* nss3 */ | |
66 | #include "nss.h" | |
67 | #endif | |
68 | ||
69 | #include "daemon/daemon.h" | |
70 | #include "daemon/worker.h" | |
71 | #include "daemon/remote.h" | |
72 | #include "daemon/acl_list.h" | |
73 | #include "util/log.h" | |
74 | #include "util/config_file.h" | |
75 | #include "util/data/msgreply.h" | |
76 | #include "util/storage/lookup3.h" | |
77 | #include "util/storage/slabhash.h" | |
78 | #include "services/listen_dnsport.h" | |
79 | #include "services/cache/rrset.h" | |
80 | #include "services/cache/infra.h" | |
81 | #include "services/localzone.h" | |
82 | #include "services/modstack.h" | |
83 | #include "util/module.h" | |
84 | #include "util/random.h" | |
85 | #include "util/tube.h" | |
86 | #include "util/net_help.h" | |
87 | #include "ldns/keyraw.h" | |
88 | #include <signal.h> | |
89 | ||
90 | /** How many quit requests happened. */ | |
91 | static int sig_record_quit = 0; | |
92 | /** How many reload requests happened. */ | |
93 | static int sig_record_reload = 0; | |
94 | ||
95 | #if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS | |
96 | /** cleaner ssl memory freeup */ | |
97 | static void* comp_meth = NULL; | |
98 | #endif | |
99 | #ifdef LEX_HAS_YYLEX_DESTROY | |
100 | /** remove buffers for parsing and init */ | |
101 | int ub_c_lex_destroy(void); | |
102 | #endif | |
103 | ||
104 | /** used when no other sighandling happens, so we don't die | |
105 | * when multiple signals in quick succession are sent to us. | |
106 | * @param sig: signal number. | |
107 | * @return signal handler return type (void or int). | |
108 | */ | |
109 | static RETSIGTYPE record_sigh(int sig) | |
110 | { | |
111 | #ifdef LIBEVENT_SIGNAL_PROBLEM | |
112 | /* cannot log, verbose here because locks may be held */ | |
113 | /* quit on signal, no cleanup and statistics, | |
114 | because installed libevent version is not threadsafe */ | |
115 | exit(0); | |
116 | #endif | |
117 | switch(sig) | |
118 | { | |
119 | case SIGTERM: | |
120 | #ifdef SIGQUIT | |
121 | case SIGQUIT: | |
122 | #endif | |
123 | #ifdef SIGBREAK | |
124 | case SIGBREAK: | |
125 | #endif | |
126 | case SIGINT: | |
127 | sig_record_quit++; | |
128 | break; | |
129 | #ifdef SIGHUP | |
130 | case SIGHUP: | |
131 | sig_record_reload++; | |
132 | break; | |
133 | #endif | |
134 | #ifdef SIGPIPE | |
135 | case SIGPIPE: | |
136 | break; | |
137 | #endif | |
138 | default: | |
139 | /* ignoring signal */ | |
140 | break; | |
141 | } | |
142 | } | |
143 | ||
144 | /** | |
145 | * Signal handling during the time when netevent is disabled. | |
146 | * Stores signals to replay later. | |
147 | */ | |
148 | static void | |
149 | signal_handling_record(void) | |
150 | { | |
151 | if( signal(SIGTERM, record_sigh) == SIG_ERR || | |
152 | #ifdef SIGQUIT | |
153 | signal(SIGQUIT, record_sigh) == SIG_ERR || | |
154 | #endif | |
155 | #ifdef SIGBREAK | |
156 | signal(SIGBREAK, record_sigh) == SIG_ERR || | |
157 | #endif | |
158 | #ifdef SIGHUP | |
159 | signal(SIGHUP, record_sigh) == SIG_ERR || | |
160 | #endif | |
161 | #ifdef SIGPIPE | |
162 | signal(SIGPIPE, SIG_IGN) == SIG_ERR || | |
163 | #endif | |
164 | signal(SIGINT, record_sigh) == SIG_ERR | |
165 | ) | |
166 | log_err("install sighandler: %s", strerror(errno)); | |
167 | } | |
168 | ||
169 | /** | |
170 | * Replay old signals. | |
171 | * @param wrk: worker that handles signals. | |
172 | */ | |
173 | static void | |
174 | signal_handling_playback(struct worker* wrk) | |
175 | { | |
176 | #ifdef SIGHUP | |
177 | if(sig_record_reload) | |
178 | worker_sighandler(SIGHUP, wrk); | |
179 | #endif | |
180 | if(sig_record_quit) | |
181 | worker_sighandler(SIGTERM, wrk); | |
182 | sig_record_quit = 0; | |
183 | sig_record_reload = 0; | |
184 | } | |
185 | ||
186 | struct daemon* | |
187 | daemon_init(void) | |
188 | { | |
189 | struct daemon* daemon = (struct daemon*)calloc(1, | |
190 | sizeof(struct daemon)); | |
191 | #ifdef USE_WINSOCK | |
192 | int r; | |
193 | WSADATA wsa_data; | |
194 | #endif | |
195 | if(!daemon) | |
196 | return NULL; | |
197 | #ifdef USE_WINSOCK | |
198 | r = WSAStartup(MAKEWORD(2,2), &wsa_data); | |
199 | if(r != 0) { | |
200 | fatal_exit("could not init winsock. WSAStartup: %s", | |
201 | wsa_strerror(r)); | |
202 | } | |
203 | #endif /* USE_WINSOCK */ | |
204 | signal_handling_record(); | |
205 | checklock_start(); | |
206 | #ifdef HAVE_SSL | |
207 | ERR_load_crypto_strings(); | |
208 | ERR_load_SSL_strings(); | |
209 | # ifdef HAVE_OPENSSL_CONFIG | |
210 | OPENSSL_config("unbound"); | |
211 | # endif | |
212 | # ifdef USE_GOST | |
213 | (void)sldns_key_EVP_load_gost_id(); | |
214 | # endif | |
215 | OpenSSL_add_all_algorithms(); | |
216 | # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS | |
217 | /* grab the COMP method ptr because openssl leaks it */ | |
218 | comp_meth = (void*)SSL_COMP_get_compression_methods(); | |
219 | # endif | |
220 | (void)SSL_library_init(); | |
221 | # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) | |
222 | if(!ub_openssl_lock_init()) | |
223 | fatal_exit("could not init openssl locks"); | |
224 | # endif | |
225 | #elif defined(HAVE_NSS) | |
226 | if(NSS_NoDB_Init(NULL) != SECSuccess) | |
227 | fatal_exit("could not init NSS"); | |
228 | #endif /* HAVE_SSL or HAVE_NSS */ | |
229 | #ifdef HAVE_TZSET | |
230 | /* init timezone info while we are not chrooted yet */ | |
231 | tzset(); | |
232 | #endif | |
233 | /* open /dev/random if needed */ | |
234 | ub_systemseed((unsigned)time(NULL)^(unsigned)getpid()^0xe67); | |
235 | daemon->need_to_exit = 0; | |
236 | modstack_init(&daemon->mods); | |
237 | if(!(daemon->env = (struct module_env*)calloc(1, | |
238 | sizeof(*daemon->env)))) { | |
239 | free(daemon); | |
240 | return NULL; | |
241 | } | |
242 | alloc_init(&daemon->superalloc, NULL, 0); | |
243 | daemon->acl = acl_list_create(); | |
244 | if(!daemon->acl) { | |
245 | free(daemon->env); | |
246 | free(daemon); | |
247 | return NULL; | |
248 | } | |
249 | if(gettimeofday(&daemon->time_boot, NULL) < 0) | |
250 | log_err("gettimeofday: %s", strerror(errno)); | |
251 | daemon->time_last_stat = daemon->time_boot; | |
252 | return daemon; | |
253 | } | |
254 | ||
255 | int | |
256 | daemon_open_shared_ports(struct daemon* daemon) | |
257 | { | |
258 | log_assert(daemon); | |
259 | if(daemon->cfg->port != daemon->listening_port) { | |
260 | size_t i; | |
261 | struct listen_port* p0; | |
262 | daemon->reuseport = 0; | |
263 | /* free and close old ports */ | |
264 | if(daemon->ports != NULL) { | |
265 | for(i=0; i<daemon->num_ports; i++) | |
266 | listening_ports_free(daemon->ports[i]); | |
267 | free(daemon->ports); | |
268 | daemon->ports = NULL; | |
269 | } | |
270 | /* see if we want to reuseport */ | |
271 | #ifdef SO_REUSEPORT | |
272 | if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0) | |
273 | daemon->reuseport = 1; | |
274 | #endif | |
275 | /* try to use reuseport */ | |
276 | p0 = listening_ports_open(daemon->cfg, &daemon->reuseport); | |
277 | if(!p0) { | |
278 | listening_ports_free(p0); | |
279 | return 0; | |
280 | } | |
281 | if(daemon->reuseport) { | |
282 | /* reuseport was successful, allocate for it */ | |
283 | daemon->num_ports = (size_t)daemon->cfg->num_threads; | |
284 | } else { | |
285 | /* do the normal, singleportslist thing, | |
286 | * reuseport not enabled or did not work */ | |
287 | daemon->num_ports = 1; | |
288 | } | |
289 | if(!(daemon->ports = (struct listen_port**)calloc( | |
290 | daemon->num_ports, sizeof(*daemon->ports)))) { | |
291 | listening_ports_free(p0); | |
292 | return 0; | |
293 | } | |
294 | daemon->ports[0] = p0; | |
295 | if(daemon->reuseport) { | |
296 | /* continue to use reuseport */ | |
297 | for(i=1; i<daemon->num_ports; i++) { | |
298 | if(!(daemon->ports[i]= | |
299 | listening_ports_open(daemon->cfg, | |
300 | &daemon->reuseport)) | |
301 | || !daemon->reuseport ) { | |
302 | for(i=0; i<daemon->num_ports; i++) | |
303 | listening_ports_free(daemon->ports[i]); | |
304 | free(daemon->ports); | |
305 | daemon->ports = NULL; | |
306 | return 0; | |
307 | } | |
308 | } | |
309 | } | |
310 | daemon->listening_port = daemon->cfg->port; | |
311 | } | |
312 | if(!daemon->cfg->remote_control_enable && daemon->rc_port) { | |
313 | listening_ports_free(daemon->rc_ports); | |
314 | daemon->rc_ports = NULL; | |
315 | daemon->rc_port = 0; | |
316 | } | |
317 | if(daemon->cfg->remote_control_enable && | |
318 | daemon->cfg->control_port != daemon->rc_port) { | |
319 | listening_ports_free(daemon->rc_ports); | |
320 | if(!(daemon->rc_ports=daemon_remote_open_ports(daemon->cfg))) | |
321 | return 0; | |
322 | daemon->rc_port = daemon->cfg->control_port; | |
323 | } | |
324 | return 1; | |
325 | } | |
326 | ||
327 | /** | |
328 | * Setup modules. setup module stack. | |
329 | * @param daemon: the daemon | |
330 | */ | |
331 | static void daemon_setup_modules(struct daemon* daemon) | |
332 | { | |
333 | daemon->env->cfg = daemon->cfg; | |
334 | daemon->env->alloc = &daemon->superalloc; | |
335 | daemon->env->worker = NULL; | |
336 | daemon->env->need_to_validate = 0; /* set by module init below */ | |
337 | if(!modstack_setup(&daemon->mods, daemon->cfg->module_conf, | |
338 | daemon->env)) { | |
339 | fatal_exit("failed to setup modules"); | |
340 | } | |
341 | } | |
342 | ||
343 | /** | |
344 | * Obtain allowed port numbers, concatenate the list, and shuffle them | |
345 | * (ready to be handed out to threads). | |
346 | * @param daemon: the daemon. Uses rand and cfg. | |
347 | * @param shufport: the portlist output. | |
348 | * @return number of ports available. | |
349 | */ | |
350 | static int daemon_get_shufport(struct daemon* daemon, int* shufport) | |
351 | { | |
352 | int i, n, k, temp; | |
353 | int avail = 0; | |
354 | for(i=0; i<65536; i++) { | |
355 | if(daemon->cfg->outgoing_avail_ports[i]) { | |
356 | shufport[avail++] = daemon->cfg-> | |
357 | outgoing_avail_ports[i]; | |
358 | } | |
359 | } | |
360 | if(avail == 0) | |
361 | fatal_exit("no ports are permitted for UDP, add " | |
362 | "with outgoing-port-permit"); | |
363 | /* Knuth shuffle */ | |
364 | n = avail; | |
365 | while(--n > 0) { | |
366 | k = ub_random_max(daemon->rand, n+1); /* 0<= k<= n */ | |
367 | temp = shufport[k]; | |
368 | shufport[k] = shufport[n]; | |
369 | shufport[n] = temp; | |
370 | } | |
371 | return avail; | |
372 | } | |
373 | ||
374 | /** | |
375 | * Allocate empty worker structures. With backptr and thread-number, | |
376 | * from 0..numthread initialised. Used as user arguments to new threads. | |
377 | * Creates the daemon random generator if it does not exist yet. | |
378 | * The random generator stays existing between reloads with a unique state. | |
379 | * @param daemon: the daemon with (new) config settings. | |
380 | */ | |
381 | static void | |
382 | daemon_create_workers(struct daemon* daemon) | |
383 | { | |
384 | int i, numport; | |
385 | int* shufport; | |
386 | log_assert(daemon && daemon->cfg); | |
387 | if(!daemon->rand) { | |
388 | unsigned int seed = (unsigned int)time(NULL) ^ | |
389 | (unsigned int)getpid() ^ 0x438; | |
390 | daemon->rand = ub_initstate(seed, NULL); | |
391 | if(!daemon->rand) | |
392 | fatal_exit("could not init random generator"); | |
393 | } | |
394 | hash_set_raninit((uint32_t)ub_random(daemon->rand)); | |
395 | shufport = (int*)calloc(65536, sizeof(int)); | |
396 | if(!shufport) | |
397 | fatal_exit("out of memory during daemon init"); | |
398 | numport = daemon_get_shufport(daemon, shufport); | |
399 | verbose(VERB_ALGO, "total of %d outgoing ports available", numport); | |
400 | ||
401 | daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1); | |
402 | daemon->workers = (struct worker**)calloc((size_t)daemon->num, | |
403 | sizeof(struct worker*)); | |
404 | if(daemon->cfg->dnstap) { | |
405 | #ifdef USE_DNSTAP | |
406 | daemon->dtenv = dt_create(daemon->cfg->dnstap_socket_path, | |
407 | (unsigned int)daemon->num); | |
408 | if (!daemon->dtenv) | |
409 | fatal_exit("dt_create failed"); | |
410 | dt_apply_cfg(daemon->dtenv, daemon->cfg); | |
411 | #else | |
412 | fatal_exit("dnstap enabled in config but not built with dnstap support"); | |
413 | #endif | |
414 | } | |
415 | for(i=0; i<daemon->num; i++) { | |
416 | if(!(daemon->workers[i] = worker_create(daemon, i, | |
417 | shufport+numport*i/daemon->num, | |
418 | numport*(i+1)/daemon->num - numport*i/daemon->num))) | |
419 | /* the above is not ports/numthr, due to rounding */ | |
420 | fatal_exit("could not create worker"); | |
421 | } | |
422 | free(shufport); | |
423 | } | |
424 | ||
425 | #ifdef THREADS_DISABLED | |
426 | /** | |
427 | * Close all pipes except for the numbered thread. | |
428 | * @param daemon: daemon to close pipes in. | |
429 | * @param thr: thread number 0..num-1 of thread to skip. | |
430 | */ | |
431 | static void close_other_pipes(struct daemon* daemon, int thr) | |
432 | { | |
433 | int i; | |
434 | for(i=0; i<daemon->num; i++) | |
435 | if(i!=thr) { | |
436 | if(i==0) { | |
437 | /* only close read part, need to write stats */ | |
438 | tube_close_read(daemon->workers[i]->cmd); | |
439 | } else { | |
440 | /* complete close channel to others */ | |
441 | tube_delete(daemon->workers[i]->cmd); | |
442 | daemon->workers[i]->cmd = NULL; | |
443 | } | |
444 | } | |
445 | } | |
446 | #endif /* THREADS_DISABLED */ | |
447 | ||
448 | /** | |
449 | * Function to start one thread. | |
450 | * @param arg: user argument. | |
451 | * @return: void* user return value could be used for thread_join results. | |
452 | */ | |
453 | static void* | |
454 | thread_start(void* arg) | |
455 | { | |
456 | struct worker* worker = (struct worker*)arg; | |
457 | int port_num = 0; | |
458 | log_thread_set(&worker->thread_num); | |
459 | ub_thread_blocksigs(); | |
460 | #ifdef THREADS_DISABLED | |
461 | /* close pipe ends used by main */ | |
462 | tube_close_write(worker->cmd); | |
463 | close_other_pipes(worker->daemon, worker->thread_num); | |
464 | #endif | |
465 | #ifdef SO_REUSEPORT | |
466 | if(worker->daemon->cfg->so_reuseport) | |
467 | port_num = worker->thread_num; | |
468 | else | |
469 | port_num = 0; | |
470 | #endif | |
471 | if(!worker_init(worker, worker->daemon->cfg, | |
472 | worker->daemon->ports[port_num], 0)) | |
473 | fatal_exit("Could not initialize thread"); | |
474 | ||
475 | worker_work(worker); | |
476 | return NULL; | |
477 | } | |
478 | ||
479 | /** | |
480 | * Fork and init the other threads. Main thread returns for special handling. | |
481 | * @param daemon: the daemon with other threads to fork. | |
482 | */ | |
483 | static void | |
484 | daemon_start_others(struct daemon* daemon) | |
485 | { | |
486 | int i; | |
487 | log_assert(daemon); | |
488 | verbose(VERB_ALGO, "start threads"); | |
489 | /* skip i=0, is this thread */ | |
490 | for(i=1; i<daemon->num; i++) { | |
491 | ub_thread_create(&daemon->workers[i]->thr_id, | |
492 | thread_start, daemon->workers[i]); | |
493 | #ifdef THREADS_DISABLED | |
494 | /* close pipe end of child */ | |
495 | tube_close_read(daemon->workers[i]->cmd); | |
496 | #endif /* no threads */ | |
497 | } | |
498 | } | |
499 | ||
500 | /** | |
501 | * Stop the other threads. | |
502 | * @param daemon: the daemon with other threads. | |
503 | */ | |
504 | static void | |
505 | daemon_stop_others(struct daemon* daemon) | |
506 | { | |
507 | int i; | |
508 | log_assert(daemon); | |
509 | verbose(VERB_ALGO, "stop threads"); | |
510 | /* skip i=0, is this thread */ | |
511 | /* use i=0 buffer for sending cmds; because we are #0 */ | |
512 | for(i=1; i<daemon->num; i++) { | |
513 | worker_send_cmd(daemon->workers[i], worker_cmd_quit); | |
514 | } | |
515 | /* wait for them to quit */ | |
516 | for(i=1; i<daemon->num; i++) { | |
517 | /* join it to make sure its dead */ | |
518 | verbose(VERB_ALGO, "join %d", i); | |
519 | ub_thread_join(daemon->workers[i]->thr_id); | |
520 | verbose(VERB_ALGO, "join success %d", i); | |
521 | } | |
522 | } | |
523 | ||
524 | void | |
525 | daemon_fork(struct daemon* daemon) | |
526 | { | |
527 | log_assert(daemon); | |
528 | if(!acl_list_apply_cfg(daemon->acl, daemon->cfg)) | |
529 | fatal_exit("Could not setup access control list"); | |
530 | if(!(daemon->local_zones = local_zones_create())) | |
531 | fatal_exit("Could not create local zones: out of memory"); | |
532 | if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg)) | |
533 | fatal_exit("Could not set up local zones"); | |
534 | ||
535 | /* setup modules */ | |
536 | daemon_setup_modules(daemon); | |
537 | ||
538 | /* first create all the worker structures, so we can pass | |
539 | * them to the newly created threads. | |
540 | */ | |
541 | daemon_create_workers(daemon); | |
542 | ||
543 | #if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) | |
544 | /* in libev the first inited base gets signals */ | |
545 | if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) | |
546 | fatal_exit("Could not initialize main thread"); | |
547 | #endif | |
548 | ||
549 | /* Now create the threads and init the workers. | |
550 | * By the way, this is thread #0 (the main thread). | |
551 | */ | |
552 | daemon_start_others(daemon); | |
553 | ||
554 | /* Special handling for the main thread. This is the thread | |
555 | * that handles signals and remote control. | |
556 | */ | |
557 | #if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) | |
558 | /* libevent has the last inited base get signals (or any base) */ | |
559 | if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) | |
560 | fatal_exit("Could not initialize main thread"); | |
561 | #endif | |
562 | signal_handling_playback(daemon->workers[0]); | |
563 | ||
564 | /* Start resolver service on main thread. */ | |
565 | log_info("start of service (%s).", PACKAGE_STRING); | |
566 | worker_work(daemon->workers[0]); | |
567 | log_info("service stopped (%s).", PACKAGE_STRING); | |
568 | ||
569 | /* we exited! a signal happened! Stop other threads */ | |
570 | daemon_stop_others(daemon); | |
571 | ||
572 | daemon->need_to_exit = daemon->workers[0]->need_to_exit; | |
573 | } | |
574 | ||
575 | void | |
576 | daemon_cleanup(struct daemon* daemon) | |
577 | { | |
578 | int i; | |
579 | log_assert(daemon); | |
580 | /* before stopping main worker, handle signals ourselves, so we | |
581 | don't die on multiple reload signals for example. */ | |
582 | signal_handling_record(); | |
583 | log_thread_set(NULL); | |
584 | /* clean up caches because | |
585 | * a) RRset IDs will be recycled after a reload, causing collisions | |
586 | * b) validation config can change, thus rrset, msg, keycache clear | |
587 | * The infra cache is kept, the timing and edns info is still valid */ | |
588 | slabhash_clear(&daemon->env->rrset_cache->table); | |
589 | slabhash_clear(daemon->env->msg_cache); | |
590 | local_zones_delete(daemon->local_zones); | |
591 | daemon->local_zones = NULL; | |
592 | /* key cache is cleared by module desetup during next daemon_init() */ | |
593 | daemon_remote_clear(daemon->rc); | |
594 | for(i=0; i<daemon->num; i++) | |
595 | worker_delete(daemon->workers[i]); | |
596 | free(daemon->workers); | |
597 | daemon->workers = NULL; | |
598 | daemon->num = 0; | |
599 | #ifdef USE_DNSTAP | |
600 | dt_delete(daemon->dtenv); | |
601 | #endif | |
602 | daemon->cfg = NULL; | |
603 | } | |
604 | ||
605 | void | |
606 | daemon_delete(struct daemon* daemon) | |
607 | { | |
608 | size_t i; | |
609 | if(!daemon) | |
610 | return; | |
611 | modstack_desetup(&daemon->mods, daemon->env); | |
612 | daemon_remote_delete(daemon->rc); | |
613 | for(i = 0; i < daemon->num_ports; i++) | |
614 | listening_ports_free(daemon->ports[i]); | |
615 | free(daemon->ports); | |
616 | listening_ports_free(daemon->rc_ports); | |
617 | if(daemon->env) { | |
618 | slabhash_delete(daemon->env->msg_cache); | |
619 | rrset_cache_delete(daemon->env->rrset_cache); | |
620 | infra_delete(daemon->env->infra_cache); | |
621 | } | |
622 | ub_randfree(daemon->rand); | |
623 | alloc_clear(&daemon->superalloc); | |
624 | acl_list_delete(daemon->acl); | |
625 | free(daemon->chroot); | |
626 | free(daemon->pidfile); | |
627 | free(daemon->env); | |
628 | #ifdef HAVE_SSL | |
629 | SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx); | |
630 | SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx); | |
631 | #endif | |
632 | free(daemon); | |
633 | #ifdef LEX_HAS_YYLEX_DESTROY | |
634 | /* lex cleanup */ | |
635 | ub_c_lex_destroy(); | |
636 | #endif | |
637 | /* libcrypto cleanup */ | |
638 | #ifdef HAVE_SSL | |
639 | # if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST) | |
640 | sldns_key_EVP_unload_gost(); | |
641 | # endif | |
642 | # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE | |
643 | # ifndef S_SPLINT_S | |
644 | sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free); | |
645 | # endif | |
646 | # endif | |
647 | # ifdef HAVE_OPENSSL_CONFIG | |
648 | EVP_cleanup(); | |
649 | ENGINE_cleanup(); | |
650 | CONF_modules_free(); | |
651 | # endif | |
652 | CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */ | |
653 | ERR_remove_state(0); | |
654 | ERR_free_strings(); | |
655 | RAND_cleanup(); | |
656 | # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) | |
657 | ub_openssl_lock_delete(); | |
658 | # endif | |
659 | #elif defined(HAVE_NSS) | |
660 | NSS_Shutdown(); | |
661 | #endif /* HAVE_SSL or HAVE_NSS */ | |
662 | checklock_stop(); | |
663 | #ifdef USE_WINSOCK | |
664 | if(WSACleanup() != 0) { | |
665 | log_err("Could not WSACleanup: %s", | |
666 | wsa_strerror(WSAGetLastError())); | |
667 | } | |
668 | #endif | |
669 | } | |
670 | ||
671 | void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg) | |
672 | { | |
673 | daemon->cfg = cfg; | |
674 | config_apply(cfg); | |
675 | if(!daemon->env->msg_cache || | |
676 | cfg->msg_cache_size != slabhash_get_size(daemon->env->msg_cache) || | |
677 | cfg->msg_cache_slabs != daemon->env->msg_cache->size) { | |
678 | slabhash_delete(daemon->env->msg_cache); | |
679 | daemon->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, | |
680 | HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, | |
681 | msgreply_sizefunc, query_info_compare, | |
682 | query_entry_delete, reply_info_delete, NULL); | |
683 | if(!daemon->env->msg_cache) { | |
684 | fatal_exit("malloc failure updating config settings"); | |
685 | } | |
686 | } | |
687 | if((daemon->env->rrset_cache = rrset_cache_adjust( | |
688 | daemon->env->rrset_cache, cfg, &daemon->superalloc)) == 0) | |
689 | fatal_exit("malloc failure updating config settings"); | |
690 | if((daemon->env->infra_cache = infra_adjust(daemon->env->infra_cache, | |
691 | cfg))==0) | |
692 | fatal_exit("malloc failure updating config settings"); | |
693 | } |