📄 main.c
字号:
case SIGUSR1: got_sigusr1 = 1; break; case SIGUSR2: got_sigusr2 = 1; break; case SIGALRM: got_sigalrm = 1; break; case SIGCHLD: got_sigchld = 1; break; default: break; }}/*--- signal_handler() --------------------------------------------------------------------------*//************************************************************************************************** NAMED_CLEANUP**************************************************************************************************/voidnamed_cleanup(int signo){ register TASK *t; shutting_down = 1; server_status(); switch (signo) { case SIGINT: Notice(_("interrupted")); break; case SIGQUIT: Notice(_("quit")); break; case SIGTERM: Notice(_("terminated")); break; default: Notice(_("exiting due to signal %d"), signo); break; } if (is_master) { int n, status; for (n = 0; n < multicpu - 1; n++) { kill(pidlist[n], signo); waitpid(pidlist[n], &status, 0); } } /* Close any TCP connections */ for (t = Tasks->head; t; t = Tasks->head) { if (t->protocol == SOCK_STREAM && t->fd != -1) sockclose(t->fd); dequeue(Tasks, t); } /* Close listening FDs */ if (is_master) { register int n; for (n = 0; n < num_tcp4_fd; n++) sockclose(tcp4_fd[n]); for (n = 0; n < num_udp4_fd; n++) sockclose(udp4_fd[n]);#if HAVE_IPV6 for (n = 0; n < num_tcp6_fd; n++) sockclose(tcp6_fd[n]); for (n = 0; n < num_udp6_fd; n++) sockclose(udp6_fd[n]);#endif /* HAVE_IPV6 */ } cache_empty(ZoneCache);#if USE_NEGATIVE_CACHE cache_empty(NegativeCache);#endif cache_empty(ReplyCache); unlink(conf_get(&Conf, "pidfile", NULL)); exit(EXIT_SUCCESS);}/*--- named_cleanup() ---------------------------------------------------------------------------*//************************************************************************************************** CHILD_CLEANUP**************************************************************************************************/static voidchild_cleanup(int signo){ int n, status, pid; got_sigchld = 0; if (shutting_down) return; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (!WIFEXITED(status)) {#ifdef WCOREDUMP if (WIFSIGNALED(status)) Warnx("pid %d exited due to signal %d%s", pid, WTERMSIG(status), WCOREDUMP(status) ? " (core dumped)" : ""); else Warnx("pid %d exited with status %d%s", pid, WEXITSTATUS(status), WCOREDUMP(status) ? " (core dumped)" : "");#else if (WIFSIGNALED(status)) Warnx("pid %d exited due to signal %d", pid, WTERMSIG(status)); else Warnx("pid %d exited with status %d", pid, WEXITSTATUS(status));#endif } else {#if DEBUG_ENABLED Debug("child pid %d exited successfully", pid);#endif } /* If the dead child is part of pidlist (for multicpu), restart */ for (n = 0; n < multicpu - 1; n++) if (pid == pidlist[n]) Errx("pid %d died", pid); }}/*--- child_cleanup() ---------------------------------------------------------------------------*//************************************************************************************************** SPAWN_MULTICPU**************************************************************************************************/static voidspawn_multicpu(void){ int n; is_master = 1; if (!(pidlist = malloc(multicpu * sizeof(pid_t)))) Err(_("out of memory")); for (n = 1; n < multicpu; n++) { pid_t pid; if ((pid = fork()) < 0) Err("fork"); if (pid > 0) { pidlist[n-1] = pid; } else { is_master = 0; db_connect(); return; } }}/*--- spawn_multicpu() --------------------------------------------------------------------------*//************************************************************************************************** _INIT_RLIMIT Sets a single resource limit and optionally prints out a notification message; called by init_rlimits().**************************************************************************************************/static void_init_rlimit(int resource, const char *desc, long long set){ struct rlimit rl; if (getrlimit(resource, &rl) < 0) Err("getrlimit"); if (set == -1) rl.rlim_cur = rl.rlim_max; else if (set > 0 && rl.rlim_cur < set) rl.rlim_cur = set; setrlimit(resource, &rl); if (getrlimit(resource, &rl) < 0) Err("getrlimit");}/*--- _init_rlimit() ----------------------------------------------------------------------------*//************************************************************************************************** INIT_RLIMITS Max out allowed resource limits.**************************************************************************************************/static voidinit_rlimits(void){#ifdef RLIMIT_CPU _init_rlimit(RLIMIT_CPU, "RLIMIT_CPU", 0);#endif#ifdef RLIMIT_FSIZE _init_rlimit(RLIMIT_FSIZE, "RLIMIT_FSIZE", 0);#endif#ifdef RLIMIT_DATA _init_rlimit(RLIMIT_DATA, "RLIMIT_DATA", 0);#endif#ifdef RLIMIT_STACK _init_rlimit(RLIMIT_STACK, "RLIMIT_STACK", -1);#endif#ifdef RLIMIT_CORE _init_rlimit(RLIMIT_CORE, "RLIMIT_CORE", -1);#endif#ifdef RLIMIT_RSS _init_rlimit(RLIMIT_RSS, "RLIMIT_RSS", 0);#endif#ifdef RLIMIT_NPROC _init_rlimit(RLIMIT_NPROC, "RLIMIT_NPROC", -1);#endif#ifdef RLIMIT_NOFILE _init_rlimit(RLIMIT_NOFILE, "RLIMIT_NOFILE", -1);#endif#ifdef RLIMIT_MEMLOCK _init_rlimit(RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK", 0);#endif#ifdef RLIMIT_AS _init_rlimit(RLIMIT_AS, "RLIMIT_AS", 0);#endif}/*--- init_rlimits() ----------------------------------------------------------------------------*//************************************************************************************************** CLOSE_TIMED_OUT_TASK Check for and dequeue timed out tasks.**************************************************************************************************/static inline voidclose_timed_out_task(register TASK *t){ Status.timedout++; t->reason = ERR_TIMEOUT; t->hdr.rcode = DNS_RCODE_SERVFAIL; /* Close TCP connection */ if (t->protocol == SOCK_STREAM) sockclose(t->fd); dequeue(Tasks, t);}/*--- close_timed_out_task() --------------------------------------------------------------------*//************************************************************************************************** MAIN**************************************************************************************************/intmain(int argc, char **argv){ register int n; int plain_maxfd = 0, maxfd, rv, want_timeout = 0; fd_set rfd, start_rfd, wfd; struct timeval tv; register TASK *t, *next_task; setlocale(LC_ALL, ""); /* Internationalization */ bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); cmdline(argc, argv); /* Process command line */ /* Set hostname */ gethostname(hostname, sizeof(hostname)-1); set_sighandler(SIGHUP, signal_handler); set_sighandler(SIGUSR1, signal_handler); set_sighandler(SIGUSR2, signal_handler); set_sighandler(SIGALRM, signal_handler); set_sighandler(SIGCHLD, child_cleanup); set_sighandler(SIGINT, named_cleanup); set_sighandler(SIGQUIT, named_cleanup); set_sighandler(SIGABRT, named_cleanup); set_sighandler(SIGTERM, named_cleanup); if (opt_daemon) /* Move into background if requested */ become_daemon(); conf_set_logging(); db_connect(); create_pidfile(); /* Create PID file */ Tasks = queue_init(); /* Initialize task queue */ cache_init(); /* Initialize cache */ /* Start listening fd's */ create_listeners(); time(&Status.start_time); /* Spawn a process for each CPU, if multicpu > 1 */ if ((multicpu = atoi(conf_get(&Conf, "multicpu", NULL))) > 1) spawn_multicpu(); if (run_as_root) { init_rlimits(); chdir("/tmp"); Notice("%s", _("WARNING: running with superuser permissions (cwd=/tmp)")); } if (!run_as_root) {#if PROFILING /* If profiling, change to a dir that a user without perms can likely write profiling data to */ chdir("/tmp");#endif /* Drop permissions */ if (getgid() == 0 && setgid(perms_gid)) Err(_("error setting group ID to %u"), (unsigned int)perms_gid); if (getuid() == 0 && setuid(perms_uid)) Err(_("error setting user ID to %u"), (unsigned int)perms_uid); if (!getgid() || !getuid()) Errx(_("refusing to run as superuser")); check_config_file_perms(); } FD_ZERO(&start_rfd); for (n = 0; n < num_udp4_fd; n++) { FD_SET(udp4_fd[n], &start_rfd); if (udp4_fd[n] > plain_maxfd) plain_maxfd = udp4_fd[n]; } for (n = 0; n < num_tcp4_fd; n++) { FD_SET(tcp4_fd[n], &start_rfd); if (tcp4_fd[n] > plain_maxfd) plain_maxfd = tcp4_fd[n]; }#if HAVE_IPV6 for (n = 0; n < num_udp6_fd; n++) { FD_SET(udp6_fd[n], &start_rfd); if (udp6_fd[n] > plain_maxfd) plain_maxfd = udp6_fd[n]; } for (n = 0; n < num_tcp6_fd; n++) { FD_SET(tcp6_fd[n], &start_rfd); if (tcp6_fd[n] > plain_maxfd) plain_maxfd = tcp6_fd[n]; }#endif periodic_task(SIGALRM); /* Initialize alarm state */ /* Main loop: Read connections and process queue */ for (;;) { /* Handle signals */ if (got_sighup) sighup(SIGHUP); if (got_sigusr1) sigusr1(SIGUSR1); if (got_sigusr2) sigusr2(SIGUSR2); if (got_sigalrm) periodic_task(SIGUSR1); if (got_sigchld) child_cleanup(SIGCHLD); memcpy(&rfd, &start_rfd, sizeof(rfd)); maxfd = plain_maxfd; FD_ZERO(&wfd); /* Add TCP requests to fd set */ if (num_tcp4_fd#if HAVE_IPV6 || num_tcp6_fd#endif ) for (want_timeout = 0, t = Tasks->head; t; t = t->next) { if ((t->protocol == SOCK_STREAM) && (t->fd >= 0)) { want_timeout = 10000; switch (t->status) { case NEED_READ: FD_SET(t->fd, &rfd); if (t->fd > maxfd) maxfd = t->fd; break; case NEED_WRITE: FD_SET(t->fd, &wfd); if (t->fd > maxfd) maxfd = t->fd; break; default: break; } } } tv.tv_sec = 0; tv.tv_usec = want_timeout ? want_timeout : 10000; rv = select(maxfd+1, &rfd, &wfd, NULL, &tv); time(¤t_time); if (rv < 0) { if (errno == EINTR) continue; Err("select"); } if (rv > 0) { /* Check incoming connections */ for (n = 0; n < num_tcp4_fd; n++) if (FD_ISSET(tcp4_fd[n], &rfd)) if (accept_tcp_query(tcp4_fd[n], AF_INET) < 0) continue; for (n = 0; n < num_udp4_fd; n++) if (FD_ISSET(udp4_fd[n], &rfd)) if (read_udp_query(udp4_fd[n], AF_INET) < 0) continue;#if HAVE_IPV6 for (n = 0; n < num_tcp6_fd; n++) if (FD_ISSET(tcp6_fd[n], &rfd)) if (accept_tcp_query(tcp6_fd[n], AF_INET6) < 0) continue; for (n = 0; n < num_udp6_fd; n++) if (FD_ISSET(udp6_fd[n], &rfd)) if (read_udp_query(udp6_fd[n], AF_INET6) < 0) continue;#endif } /* Process tasks */ for (t = Tasks->head; t; t = next_task) { next_task = t->next; if (current_time > t->timeout) close_timed_out_task(t); else if (t->protocol == SOCK_DGRAM) task_process(t); else if (t->protocol == SOCK_STREAM && t->status == NEED_READ && FD_ISSET(t->fd, &rfd)) task_process(t); else if (t->protocol == SOCK_STREAM && t->status == NEED_WRITE && FD_ISSET(t->fd, &wfd)) task_process(t); } } return (0);}/*--- main() ------------------------------------------------------------------------------------*//* vi:set ts=3: *//* NEED_PO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -