转载至:不知转载源
一、 说明
参考http://202.120.16.5/lxr/http/source/bin/named/main.c
这是bind解析程序的入口
事件bind程序也事件驱动型,以任务作为主要的执行。
当一个解析请求到来时,就会通过事件的产生来触发任务dispatch处理。这样的处理有相应
if (event->ev_action != NULL) {
862 (event->ev_action)(task,event);
这里 action就是执行函数
本文主要关注整体的运行结构,主要参考文件是main.c
二、 启动入口
870 int
871 main(int argc, char *argv[]) { 命令行参数传入
以上为设置错误消息
895 isc_assertion_setcallback(assertion_failed);
896 isc_error_setfatal(library_fatal_error);
897 isc_error_setunexpected(library_unexpected_error);
898初始化系统日志,权限等
900初始化工作
904 命令行参数分析,如-g将日志输出到front-end
905 parse_command_line(argc, argv);
{注意以下的内存机制,isc_mem可见http://202.120.16.5/lxr/http/source/lib/isc/mem.c#L113定义
注意以
http://202.120.16.5/lxr/http/source/lib/isc/mem.c#L725
用到了锁机制
831 ISC_LIST_INITANDAPPEND(contexts, ctx, link);
内存生成采用标准的系统调用 malloc和free,但考虑到多线程下的竞争情况,对内存块访问需要锁机制。Ns_g_mctx是信号量,要求ns_g_mctx!=NULL&&*ns_g_mctx=NULL
}
919 result = isc_mem_create(0, 0, &ns_g_mctx);
920 if (result != ISC_R_SUCCESS)
921 ns_main_earlyfatal("isc_mem_create() failed: %s",
922 isc_result_totext(result));
对设置
923 isc_mem_setname(ns_g_mctx, "main", NULL);
924 //setup是重要的一部分,见分析三
接下来就是解析主体程序了,是通过循环来做的,直到错误或者接收到退出信号。递
/*
928 * Start things running and then wait for a shutdown request
929 * or reload.
930 */
931 do {
932 result = isc_app_run();是重要部分,见分析四
934 if (result == ISC_R_RELOAD) { //通过我们会做这种操作,当配置了一个新的zone文件时
935 ns_server_reloadwanted(ns_g_server);
936 } else if (result != ISC_R_SUCCESS) {
937 UNEXPECTED_ERROR(__FILE__, __LINE__,
938 "isc_app_run(): %s",
939 isc_result_totext(result));
940 /*
941 * Force exit.
942 */
944 }
945 } while (result != ISC_R_SUCCESS);
947 #ifdef HAVE_LIBSCF
948 if (ns_smf_want_disable == 1) {
949 result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
950 if (result == ISC_R_SUCCESS && instance != NULL) {
951 if (smf_disable_instance(instance, 0) != 0)
952 UNEXPECTED_ERROR(__FILE__, __LINE__,
953 "smf_disable_instance() "
954 "failed for %s : %s",
955 instance,
956 scf_strerror(scf_error()));
957 }
958 if (instance != NULL)
959 isc_mem_free(ns_g_mctx, instance);
960 }
961 #endif /* HAVE_LIBSCF */
965 if (want_stats) {
966 isc_mem_stats(ns_g_mctx, stdout);
967 isc_mutex_stats(stdout);
968 }
970 if (ns_g_memstatistics && memstats != NULL) {
972 result = isc_stdio_open(memstats, "w", &fp);
973 if (result == ISC_R_SUCCESS) {
974 isc_mem_stats(ns_g_mctx, fp);
977 }
978 }
979 isc_mem_destroy(&ns_g_mctx);
980 isc_mem_checkdestroyed(stderr);
982 ns_main_setmemstats(NULL);
990 return (0);
991 }
三、 初始设置setup
595 ns_os_tzset(); 初始化时区
597 ns_os_opendevnull(); 打开空设备以便消息转向
599 #ifdef HAVE_LIBSCF 是否solaris的smf管理机制
600 /* Check if named is under smf control, before chroot. */
601 result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
602 /* We don't care about instance, just check if we got one. */
603 if (result == ISC_R_SUCCESS)
604 ns_smf_got_instance = 1;
605 else
606 ns_smf_got_instance = 0;
607 if (instance != NULL)
608 isc_mem_free(ns_g_mctx, instance);
609 #endif /* HAVE_LIBSCF */
如果是chroot运行方式化,初始化可用资源。Chroot是以普通用户运行超级资源,是unix系统的一种机制
611 #ifdef PATH_RANDOMDEV
612 /*
613 * Initialize system's random device as fallback entropy source
614 * if running chroot'ed.
615 */
616 if (ns_g_chrootdir != NULL) {
617 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
618 if (result != ISC_R_SUCCESS)
619 ns_main_earlyfatal("isc_entropy_create() failed: %s",
620 isc_result_totext(result));
622 result = isc_entropy_createfilesource(ns_g_fallbackentropy,
624 if (result != ISC_R_SUCCESS) {
625 ns_main_earlywarning("could not open pre-chroot "
626 "entropy source %s: %s",
628 isc_result_totext(result));
629 isc_entropy_detach(&ns_g_fallbackentropy);
630 }
631 }
632 #endif
看cpu数目
634 #ifdef ISC_PLATFORM_USETHREADS
635 /*
636 * Check for the number of cpu's before ns_os_chroot().
637 */
638 ns_g_cpus_detected = isc_os_ncpus();
639 #endif
以下说明了最小权限运行机制,读config文件需要有root机制,通过unix的sid置位实现,即setsid()
/*
644 * For operating systems which have a capability mechanism, now
645 * is the time to switch to minimal privs and change our user id.
646 * On traditional UNIX systems, this call will be a no-op, and we
647 * will change the user ID after reading the config file the first
648 * time. (We need to read the config file to know which possibly
649 * privileged ports to bind() to.)
650 */
652 日志初始化
653 result = ns_log_init(ISC_TF(ns_g_username != NULL));
654 if (result != ISC_R_SUCCESS)
655 ns_main_earlyfatal("ns_log_init() failed: %s",
656 isc_result_totext(result));
pid = fork();产生新的子进程,如果是直接named而不是named –g的话,因此,需要派生子进程,并关闭父的一些输入输出句柄,参见fork例程
if (!ns_g_foreground)
/*
669 * We call isc_app_start() here as some versions of FreeBSD's fork()
670 * destroys all the signal handling it sets up.
671 */
Isc_app_start主要是处理fork的信号机制的恢复
672 result = isc_app_start();
673 if (result != ISC_R_SUCCESS)
674 ns_main_earlyfatal("isc_app_start() failed: %s",
675 isc_result_totext(result));
676 写日志文件,开始启动
677 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
678 ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
681 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
682 ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
接下来是资源限制部分,可用#ulimit –a来理解
/*
729 * Record the server's startup time.
730 */
731 result = isc_time_now(&ns_g_boottime);
732 if (result != ISC_R_SUCCESS)
733 ns_main_earlyfatal("isc_time_now() failed: %s",
734 isc_result_totext(result));
生成管理器,如任务、超时、entropy、hash,socket等管理器
736 result = create_managers();
737 if (result != ISC_R_SUCCESS)
738 ns_main_earlyfatal("create_managers() failed: %s",
739 isc_result_totext(result));
743 /*
744 * Add calls to register sdb drivers here.
745 */
746 /* xxdb_init(); */
748 #ifdef DLZ
749 /*
750 * Registyer any DLZ drivers.
751 */
752 result = dlz_drivers_init();
753 if (result != ISC_R_SUCCESS)
754 ns_main_earlyfatal("dlz_drivers_init() failed: %s",
755 isc_result_totext(result));
756 #endif
生成服务,重要部分,见分析六
758 ns_server_create(ns_g_mctx, &ns_g_server);
759 }
四、 运行主体程序
文件http://202.120.16.5/lxr/http/source/lib/isc/unix/app.c#L431
431 isc_app_run(void) {
433 isc_event_t *event, *next_event;
435 #ifdef ISC_PLATFORM_USETHREADS
436 sigset_t sset;
437 char strbuf[ISC_STRERRORSIZE];
438 #ifdef HAVE_SIGWAIT
439 int sig;
440 #endif
441 #endif /* ISC_PLATFORM_USETHREADS */
443 #ifdef HAVE_LINUXTHREADS 如果启用了多线程编译,目前我们编译的是单线程,可用ps –em|grep named查看线程数
444 REQUIRE(main_thread == pthread_self());
445 #endif
446 加锁,事件队列是关键区,race condition
451 事件结构有sender,type,action,arguments,而采用队列ev_link实现,事件FIFO依序处理。
452 /*
453 * Post any on-run events (in FIFO order).
454 */主循环
455 for (event = ISC_LIST_HEAD(on_run);
456 event != NULL;
457 event = next_event) {
458 next_event = ISC_LIST_NEXT(event, ev_link);
459 ISC_LIST_UNLINK(on_run, event, ev_link);
461 event->ev_sender = NULL;
事件任务机制,见分析五
462 isc_task_sendanddetach(&task, &event);
463 }
465 }
468 以下主要为信号捕获处理机制,特别注意shutdown退出时的处理。信号catch处理机制能够使应用更安全退出。
469 #ifndef HAVE_SIGWAIT
470 /*
471 * Catch SIGHUP.
472 *
473 * We do this here to ensure that the signal handler is installed
474 * (i.e. that it wasn't a "one-shot" handler).
475 */
476 result = handle_signal(SIGHUP, reload_action);
477 if (result != ISC_R_SUCCESS)
478 return (ISC_R_SUCCESS);
479 #endif
481 #ifdef ISC_PLATFORM_USETHREADS
482 /*
483 * There is no danger if isc_app_shutdown() is called before we wait
484 * for signals. Signals are blocked, so any such signal will simply
485 * be made pending and we will get it when we call sigwait().
486 */
488 while (!want_shutdown) {
489 #ifdef HAVE_SIGWAIT
490 /*
491 * Wait for SIGHUP, SIGINT, or SIGTERM.
492 */
493 if (sigemptyset(&sset) != 0 ||
494 sigaddset(&sset, SIGHUP) != 0 ||
495 sigaddset(&sset, SIGINT) != 0 ||
496 sigaddset(&sset, SIGTERM) != 0) {
497 isc__strerror(errno, strbuf, sizeof(strbuf));
498 UNEXPECTED_ERROR(__FILE__, __LINE__,
499 "isc_app_run() sigsetops: %s", strbuf);
500 return (ISC_R_UNEXPECTED);
501 }
503 #ifndef HAVE_UNIXWARE_SIGWAIT
504 result = sigwait(&sset, &sig);
506 if (sig == SIGINT ||
507 sig == SIGTERM)
509 else if (sig == SIGHUP)
511 }
513 #else /* Using UnixWare sigwait semantics. */
515 if (sig >= 0) {
516 if (sig == SIGINT ||
517 sig == SIGTERM)
519 else if (sig == SIGHUP)
521 }
523 #endif /* HAVE_UNIXWARE_SIGWAIT */
524 #else /* Don't have sigwait(). */
525 /*
526 * Listen for all signals.
527 */
528 if (sigemptyset(&sset) != 0) {
529 isc__strerror(errno, strbuf, sizeof(strbuf));
530 UNEXPECTED_ERROR(__FILE__, __LINE__,
531 "isc_app_run() sigsetops: %s", strbuf);
532 return (ISC_R_UNEXPECTED);
533 }
534 result = sigsuspend(&sset);
535 #endif /* HAVE_SIGWAIT */
537 if (want_reload) {
539 return (ISC_R_RELOAD);
540 }
542 if (want_shutdown && blocked)
543 exit(1);
544 }
546 #else /* ISC_PLATFORM_USETHREADS */
548 (void)isc__taskmgr_dispatch();
551 if (result != ISC_R_SUCCESS)
554 #endif /* ISC_PLATFORM_USETHREADS */
556 return (ISC_R_SUCCESS);
557 }
正常关闭时,需要将相关线程也中止
560 isc_app_shutdown(void) {
561 isc_boolean_t want_kill = ISC_TRUE;
562 char strbuf[ISC_STRERRORSIZE];
568 if (shutdown_requested)
570 else
571 shutdown_requested = ISC_TRUE;
575 if (want_kill) {
576 #ifdef HAVE_LINUXTHREADS
579 result = pthread_kill(main_thread, SIGTERM);
581 isc__strerror(result, strbuf, sizeof(strbuf));
582 UNEXPECTED_ERROR(__FILE__, __LINE__,
583 "isc_app_shutdown() pthread_kill: %s",
584 strbuf);
585 return (ISC_R_UNEXPECTED);
586 }
587 #else
588 if (kill(getpid(), SIGTERM) < 0) {
589 isc__strerror(errno, strbuf, sizeof(strbuf));
590 UNEXPECTED_ERROR(__FILE__, __LINE__,
591 "isc_app_shutdown() kill: %s", strbuf);
592 return (ISC_R_UNEXPECTED);
593 }
594 #endif
595 }
597 return (ISC_R_SUCCESS);
598 }
五、 事件与任务处理
还没有充分看代码,需要进一步看代码,主要参考文件去理解app.c和Task.c去理解http://202.120.16.5/lxr/http/source/lib/isc/unix/app.c#L303
task = event->ev_sender;
event->ev_sender = NULL;
isc_task_sendanddetach(&task, &event);
void
430 isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) {
431 isc_boolean_t idle1, idle2;
434 /*
435 * Send '*event' to '*taskp' and then detach '*taskp' from its
436 * task.
437 */
441 REQUIRE(VALID_TASK(task));
443 XTRACE("isc_task_sendanddetach");
446 idle1 = task_send(task, eventp);
447 idle2 = task_detach(task);
450 /*
451 * If idle1, then idle2 shouldn't be true as well since we're holding
452 * the task lock, and thus the task cannot switch from ready back to
453 * idle.
454 */
455 INSIST(!(idle1 && idle2));
457 if (idle1 || idle2)
460 *taskp = NULL;
461 }
463 #define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0)
六 服务任务生成(主要与rndc的channel通信)
3826 void
3827 ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
3830 ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
3831 if (server == NULL)
3832 fatal("allocating server object", ISC_R_NOMEMORY);
3837 /* Initialize configuration data with default values. */
3839 result = isc_quota_init(&server->xfroutquota, 10);
3840 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3841 result = isc_quota_init(&server->tcpquota, 10);
3842 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3843 result = isc_quota_init(&server->recursionquota, 100);
3844 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3846 result = dns_aclenv_init(mctx, &server->aclenv);
3847 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3849 /* Initialize server data structures. */
3850 server->zonemgr = NULL; 区管理器
3851 server->interfacemgr = NULL;接口管理器
3852 ISC_LIST_INIT(server->viewlist);
3853 server->in_roothints = NULL;
3854 server->blackholeacl = NULL; 服务的ACL机制
3856 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
3857 &server->in_roothints),
3858 "setting up root hints");
3860 CHECKFATAL(isc_mutex_init(&server->reload_event_lock),
3861 "initializing reload event lock");
绑定reload事件处理
3862 server->reload_event =
3863 isc_event_allocate(ns_g_mctx, server,
3866 server,
3867 sizeof(isc_event_t));
3868 CHECKFATAL(server->reload_event == NULL ?
3869 ISC_R_NOMEMORY : ISC_R_SUCCESS,
3870 "allocating reload event");
3872 CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY), 加密机制dst hmac
3873 "initializing DST");
3874 TKEY加密管理
3875 server->tkeyctx = NULL;
3876 CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
3877 &server->tkeyctx),
3878 "creating TKEY context");
3880 /*
3881 * Setup the server task, which is responsible for coordinating
3882 * startup and shutdown of the server.
3883 */
生成服务器的任务机制
3884 CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task),
3885 "creating server task");
3886 isc_task_setname(server->task, "server", server);
3887 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
3888 "isc_task_onshutdown");
3889 CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server),
3890 "isc_app_onrun");
3892 server->interface_timer = NULL; 接口保活
3893 server->heartbeat_timer = NULL; 心跳定时器
3894 server->pps_timer = NULL;
3896 server->interface_interval = 0;
3897 server->heartbeat_interval = 0;
3898 生成区管理器
3899 CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
3900 ns_g_socketmgr, &server->zonemgr),
3901 "dns_zonemgr_create");
3902 统计文件,注意有以下统计信息:opcode,zone,resolver,receive query等
3903 server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
3904 CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3905 "isc_mem_strdup");
3906 server->nsstats = NULL;
3907 server->rcvquerystats = NULL;
3908 server->opcodestats = NULL;
3909 server->zonestats = NULL;
3910 server->resolverstats = NULL;
3911 转储文件
3912 server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
3913 CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3914 "isc_mem_strdup");
3915 递归文件
3916 server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
3917 CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
3918 "isc_mem_strdup");
3920 server->hostname_set = ISC_FALSE;
3922 server->version_set = ISC_FALSE;
3924 server->server_usehostname = ISC_FALSE;
3925 server->server_id = NULL;
以下处理统计信息收集
3927 CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->nsstats,
3928 dns_nsstatscounter_max),
3929 "dns_stats_create (server)");
3931 CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx,
3932 &server->rcvquerystats),
3933 "dns_stats_create (rcvquery)");
3935 CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats),
3936 "dns_stats_create (opcode)");
3938 CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->zonestats,
3939 dns_zonestatscounter_max),
3940 "dns_stats_create (zone)");
3942 CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->resolverstats,
3943 dns_resstatscounter_max),
3944 "dns_stats_create (resolver)");
3946 server->flushonshutdown = ISC_FALSE;
默认查询日志是关闭的,打开查询日志较大地影响解析性能
3947 server->log_queries = ISC_FALSE;
3949 server->controls = NULL;
3950 CHECKFATAL(ns_controls_create(server, &server->controls),
3951 "ns_controls_create");
3952 server->dispatchgen = 0;
3953 ISC_LIST_INIT(server->dispatches);
3955 ISC_LIST_INIT(server->statschannels);
3957 server->magic = NS_SERVER_MAGIC;
3958 *serverp = server;
3959 }
附录:
事件结构:
81 ISC_EVENT_COMMON(struct isc_event);
而
34 #define ISC_EVENT_COMMON(ltype) \
35 size_t ev_size; \
36 unsigned int ev_attributes; \
37 void * ev_tag; \
38 isc_eventtype_t ev_type; \
39 isc_taskaction_t ev_action; \
40 void * ev_arg; \
41 void * ev_sender; \
42 isc_eventdestructor_t ev_destroy; \
43 void * ev_destroy_arg; \
任务结构:
http://202.120.16.5/lxr/http/source/lib/isc/task.c#L78
79 /* Not locked. */
80 unsigned int magic;
83 /* Locked by task lock. */
85 unsigned int references;
86 isc_eventlist_t events;
87 isc_eventlist_t on_shutdown;
88 unsigned int quantum;
92 void * tag;
93 /* Locked by task manager lock. */
94 LINK(isc_task_t) link;
95 LINK(isc_task_t) ready_link;
96 };