感谢支持
我们一直在努力

Squid的main函数源码分析

要分析一款开源的软件除了要弄清楚一些基本的使用和配置之外,其次最重要的就是对源代码进行分析。对源代码进行分析首先应从其main函数分析入手,了解他在启动时的涉及的哪方面的功能,并勾勒出他的运行流程图,现在squid已经支持windows平台了,并且支持以服务的方式启动。其代码如下:



  1. #if USE_WIN32_SERVICE   

  2. /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */  

  3. void WINAPI  

  4. SquidWinSvcMain(int argc, char **argv)  

  5. {  

  6.     SquidMain(argc, argv);  

  7. }  

  8.   

  9. int  

  10. SquidMain(int argc, char **argv)  

  11. #else   

  12. int  

  13. main(int argc, char **argv)  

  14. #endif   

  15. {  

  16.     int errcount = 0;  

  17.     int loop_delay;  

  18. #ifdef _SQUID_WIN32_   

  19.     int WIN32_init_err;  

  20. #endif   

  21.   

  22. #if HAVE_SBRK   

  23.     /* 

  24.     * HAVE_SBRK – 这个宏的产生我说明一下,这个是用configure产生的,在autoconf.h中能看到,这个是configure做系统 

  25.     * 函数fun功能性检查的时候,如果该操作系统支持其系统调用,则在autoconf.h中定义宏HAVE_FUN,FUN是其函数名字的大写 

  26.     * sbrk  – 是从堆中分配空间,本质是移动一个位置,向后移就是分配空间,向前移就是释放空间,返回以页为单位 

  27.     * 的虚拟内存使用情况,squid用它来计算整个进程的内存使用情况。 

  28.     */  

  29.     sbrk_start = sbrk(0);  

  30. #endif   

  31.   

  32.     debug_log = stderr;  

  33.   

  34. #ifdef _SQUID_WIN32_   

  35.     if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))  

  36.     return WIN32_init_err;  

  37. #endif   

  38.   

  39.     /* call mallopt() before anything else */  

  40. #if HAVE_MALLOPT   

  41. #ifdef M_GRAIN   

  42.     /* Round up all sizes to a multiple of this */  

  43.     mallopt(M_GRAIN, 16);  

  44. #endif   

  45. #ifdef M_MXFAST   

  46.     /* biggest size that is considered a small block */  

  47.     mallopt(M_MXFAST, 256);  

  48. #endif   

  49. #ifdef M_NBLKS   

  50.     /* allocate this many small blocks at once */  

  51.     mallopt(M_NLBLKS, 32);  

  52. #endif   

  53. #endif /* HAVE_MALLOPT */   

  54.   

  55.     /* 初始化本地地址local_addr,默认地址any_addr和广播地址no_addr */  

  56.     memset(&local_addr, ‘\0’sizeof(struct in_addr));  

  57.     safe_inet_addr(localhost, &local_addr);  

  58.     memset(&any_addr, ‘\0’sizeof(struct in_addr));  

  59.     safe_inet_addr(“0.0.0.0”, &any_addr);  

  60.     memset(&no_addr, ‘\0’sizeof(struct in_addr));  

  61.     safe_inet_addr(“255.255.255.255”, &no_addr);  

  62.   

  63.     /* 用当前时间生成随机种子 */  

  64.     squid_srandom(time(NULL));  

  65.   

  66.     /* 初始化当前时间 */  

  67.     getCurrentTime();  

  68.     squid_start = current_time;  

  69.     failure_notify = fatal_dump;    /* 设置失败或者出现重大错误时候退出的回调函数指针 */  

  70.   

  71. #if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)   

  72.     WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);  

  73. #endif   

  74.   

  75.     /* 解析命令行参数,如./squid -D -N -d3 之类的 */  

  76.     mainParseOptions(argc, argv);  

  77.   

  78. #if HAVE_SYSLOG && defined(LOG_LOCAL4)   

  79.     /* 打开系统日志,将日志写入系统日志吧 */  

  80.     openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, syslog_facility);  

  81. #endif   

  82.   

  83. #if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)   

  84.     if (opt_install_service) {  

  85.     WIN32_InstallService();  

  86.     return 0;  

  87.     }  

  88.     if (opt_remove_service) {  

  89.     WIN32_RemoveService();  

  90.     return 0;  

  91.     }  

  92.     if (opt_command_line) {  

  93.     WIN32_SetServiceCommandLine();  

  94.     return 0;  

  95.     }  

  96. #endif   

  97.   

  98.     /* parse configuration file 

  99.      * note: in “normal” case this used to be called from mainInitialize() */  

  100.     {  

  101.     /* 配置文件名称初始化,这个可也通过命令行的方式指定,默认是squid.conf */   

  102.     int parse_err;  

  103.     if (!ConfigFile)  

  104.         ConfigFile = xstrdup(DefaultConfigFile);  

  105.     assert(!configured_once);  

  106. #if USE_LEAKFINDER   

  107.     /*  

  108.     * 内存泄漏检测功能初始化,通过–enable-leakfinder打开。创建一个哈希表htable,缓存动态内存分配 

  109.     * 情况,cachemgrRegister注册获取内存泄漏跟踪统计数据的action 。 

  110.     * 但是奇怪的事,我就没看到哪些地方在调用leakAdd leakTouch leakFree之类的接口。 

  111.     */   

  112.     leakInit();  

  113. #endif   

  114.     /*  

  115.     * squid提供的内存池功能,这里主要是对预定义的对象内存分配器初始化,以后这些对象就用这些定义好了的内存分配器来 

  116.     * 分配内存了!cachemgrRegister注册获取内存使用跟踪统计数据的action 。squid实现的内存池功能比apache简单多了! 

  117.     */  

  118.     memInit();  

  119.   

  120.     /*  

  121.     * squid提供的专用于回调函数参数对象内存分配器初始化,用这个种分配器分配的内存保存了一些其他的信息用于识别和验证。 

  122.     * cachemgrRegister注册获取回调参数对象跟踪统计数据的action 。 

  123.     */  

  124.     cbdataInit();  

  125.   

  126.     /*  

  127.     * Squid的事件机制的作用是,提供一种触发机制,可以定时地执行某些操作. Squid任何一个功能模块中的代码可以灵活地指定 

  128.     * “在x秒钟之后,我要做某操作”,而到了x秒钟之后,该操作就可以自动地执行。 

  129.     * 这里主要是对event的对象内存分配器初始化, cachemgrRegister注册获取event对象跟踪统计数据的action 。 

  130.     */  

  131.     eventInit();        /* eventInit() is required for config parsing */  

  132.   

  133.     /* 

  134.     * storeReplSetup()和storeFsSetup(),替换策略模块和存储策略模块选择的初始化,这些模块的选择是通过 

  135.     * ./configure –enable-storeio=afus,diskd,ufs和 ./configure –enable-removal-policies=heap,lru来确定的! 

  136.     * 替换和存储模块都提供了一个兼容层,这些兼容层只是一个管理功能接口的函数指针对象,初始化就是用用户 

  137.     * configure配置的接口来初始化函数指针管理对象。 

  138.     */  

  139.     storeFsInit();      /* required for config parsing */  

  140.   

  141.     /* 

  142.     * authSchemeSetup(),squid配置的验证机制初始化,这个是squid提供给用户的代理认证,可以通过 

  143.     * ./configure –enable-auth=basic,digest,ntlm来配置,默认支持basic认证方式。并且需要配置一种 

  144.     * 对应的外部认证程序,通过–enable-basic-auth-helpers=ncsa完成,这里只是配置了认证机制basic 

  145.     * 使用ncsa外部程序来完成认证,这些外部程序都是通过pipe方式来进行通信完成认证的! 

  146.     */  

  147.     authenticateSchemeInit();   /* required for config parsing */  

  148.   

  149.     /* 

  150.     * 这个没什么的,看起来就像是解析配置文件,默认的配置文件是squid.conf,cachemgrRegister注册获取配置数据的action  

  151.     * 处理过程先设置部分默认值,然后解析配置文件覆盖或者初始化一些配置值,然后看哪些没值的就设置默认值,最后配置信息 

  152.     * 合法化检查,如果配置信息不合理就退出吧!! 

  153.     */  

  154.     parse_err = parseConfigFile(ConfigFile);  

  155.   

  156.     if (opt_parse_cfg_only)  

  157.         return parse_err;  

  158.     }  

  159.     setUmask(Config.umask);  

  160.   

  161.     /* 

  162.     * 重复启动运行监测,如果不是像squid发送进程信号的话,就提示不能重复启动运行的错误。squid进程启动的时候会向squid.pid 

  163.     * 写入当前运行进程的pid,checkRunningPid()就是检查的这个文件来确认squid是不是已经启动了!当squid退出的时候会删除 

  164.     * squid.pid的这个文件。 

  165.     */  

  166.     if (-1 == opt_send_signal)  

  167.     if (checkRunningPid())  

  168.         exit(1);  

  169.   

  170.     /* Make sure the OS allows core dumps if enabled in squid.conf */  

  171.     /* 

  172.     * 这个只是设置os系统参数,允许squid在crash的时候生成coredump文件。 

  173.     */  

  174.     enableCoredumps();  

  175.   

  176. /* 

  177. * 这个看样子是测试access方面宏,如果定义了该宏,会#include “test_access.c”这个文件, 

  178. * 不过哥哥没找到这个文件。我想其他版本有吧,先跳过这个不管算了! 

  179. */  

  180. #if TEST_ACCESS   

  181.     comm_init();  

  182.     comm_select_init();  

  183.     mainInitialize();  

  184.     test_access();  

  185.     return 0;  

  186. #endif   

  187.     /* 

  188.     * squid进程除了可以作为启动进程外,还可以通过一些命令参数作为管理进程,来完成一些基本的管理工作, 

  189.     * 如opt_send_signal选项,如果该选项设置了就可以向正在运行的squid进程发送信号,我看了就发送了kill信号! 

  190.     * 如opt_create_swap_dirs选项,如果该选项设置了就可以创建cache目录,根据cache_dir配置指令来完成创建。 

  191.     */  

  192.     /* send signal to running copy and exit */  

  193.     if (opt_send_signal != -1) {  

  194.     /* chroot if configured to run inside chroot */  

  195.     if (Config.chroot_dir) {  

  196.         if (chroot(Config.chroot_dir))  

  197.         fatal(“failed to chroot”);  

  198.         no_suid();  

  199.     } else {  

  200.         leave_suid();  

  201.     }  

  202.     sendSignal();  

  203.     /* NOTREACHED */  

  204.     }  

  205.     if (opt_create_swap_dirs) {  

  206.     /* chroot if configured to run inside chroot */  

  207.     if (Config.chroot_dir && chroot(Config.chroot_dir)) {  

  208.         fatal(“failed to chroot”);  

  209.     }  

  210.     setEffectiveUser();  

  211.     debug(0, 0) (“Creating Swap Directories\n”);  

  212.     storeCreateSwapDirectories();  

  213.     return 0;  

  214.     }  

  215.   

  216.     /* 

  217.     * 这里squid以后台服务的方式来启动运行。 

  218.     */  

  219.     if (!opt_no_daemon)  

  220.     watch_child(argv);  

  221.     setMaxFD();  

  222.   

  223.     /* init comm module */  

  224.     /* 

  225.     * 现在squid网络模块支持devpoll,poll,epoll,kqueue,select和select_win32模式。 

  226.     * 网络初始化,这里包括client-side和server-side套接字fd,pipe,以及文件fd的管理结构fde,内存分配器和套接字状态管理结构初始化。 

  227.     */  

  228.     comm_init();  

  229.     comm_select_init();  

  230.   

  231.     if (opt_no_daemon) {  

  232.     /* we have to init fdstat here. */  

  233.     if (!opt_stdin_overrides_http_port)  

  234.         fd_open(0, FD_LOG, “stdin”);  

  235.     fd_open(1, FD_LOG, “stdout”);  

  236.     fd_open(2, FD_LOG, “stderr”);  

  237.     }  

  238. #if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)   

  239.     WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);  

  240. #endif   

  241.     /* 

  242.     * squid主要信息初始化,这个会将在mainInitialize()功能做详细的分析。 

  243.     */  

  244.     mainInitialize();  

  245.   

  246. #if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)   

  247.     WIN32_svcstatusupdate(SERVICE_RUNNING, 0);  

  248. #endif   

  249.   

  250.     /* main loop */  

  251.     /* 

  252.     * 这个应该就是squid的心跳系统,这里除了处理squid管理发过来的信号之类外,就只处理event事件和读写处理。 

  253.     * 这里应该就只包括套接字和文件的读写吧,整个框架就3点功能: 

  254.     *   – 处理squid管理发过来的信号,do_reconfigure表示是重新加载配置信息,这个处理起来还不简单啊,要关闭所 

  255.     * 有端口,所有连接,所有文件读写等,然后切换到root用户,解析配置文件,在然后切换回来运行用户,然后启动 

  256.     * 之前关闭的端口,连接等等信息,太多了! 

  257.     *   – eventRun(),运行event,遍历event管理列表tasks,如果event->when中满足当前运行条件,就执行event->func 

  258.     * 中的函数功能,运行完后从tasks中删除之,并释放资源吧。灵活地指定“在x秒钟之后,我要做某操作”,这个可以做 

  259.     * 任何事情,不错。。。 

  260.     *   – 接下来就是网络套接字和文件io的读写!loop_delay = eventNextTime()这个是取得下一个最快将要执行的event 

  261.     * 时间,loop_delay不能超过1000就是1秒,通过这个时间来在一些端口上设置等待超时时间,comm_select(loop_delay) 

  262.     * 就是在网络套接字和文件FD上等待预先设置好了的操作,等成功返回后就用预先设置好了的函数作回调执行处理得到 

  263.     * 的数据。比如listen FD监听到来的请求,receive FD接收到来的request和response data,预先设置好了数据发出去 

  264.     * 去的FD,写入disk的FD,等等!!! 

  265.     */  

  266.     for (;;) {  

  267.     if (do_reconfigure) {  

  268.         mainReconfigure();  

  269.         do_reconfigure = 0;  

  270.     } else if (do_rotate) {  

  271.         mainRotate();  

  272.         do_rotate = 0;  

  273.     } else if (do_shutdown) {  

  274.         time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;  

  275.         debug(1, 1) (“Preparing for shutdown after %d requests\n”,  

  276.         statCounter.client_http.requests);  

  277.         debug(1, 1) (“Waiting %d seconds for active connections to finish\n”,  

  278.         (int) wait);  

  279.         do_shutdown = 0;  

  280.         shutting_down = 1;  

  281. #if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)   

  282.         WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);  

  283. #endif   

  284.         serverConnectionsClose();  

  285.         eventAdd(“SquidShutdown”, SquidShutdown, NULL, (double) (wait + 1), 1);  

  286.     }  

  287.     eventRun();  

  288.     if ((loop_delay = eventNextTime()) < 0)  

  289.         loop_delay = 0;  

  290.     if (debug_log_flush() && loop_delay > 1000)  

  291.         loop_delay = 1000;  

  292.     switch (comm_select(loop_delay)) {  

  293.     case COMM_OK:  

  294.         errcount = 0;   /* reset if successful */  

  295.         break;  

  296.     case COMM_ERROR:  

  297.         errcount++;  

  298.         debug(1, 0) (“Select loop Error. Retry %d\n”, errcount);  

  299.         if (errcount == 10)  

  300.         fatal_dump(“Select Loop failed!”);  

  301.         break;  

  302.     case COMM_TIMEOUT:  

  303.         break;  

  304.     case COMM_SHUTDOWN:  

  305.         SquidShutdown(NULL);  

  306.         break;  

  307.     default:  

  308.         fatal_dump(“MAIN: Internal error — this should never happen.”);  

  309.         break;  

  310.     }  

  311.     }  

  312.     /* NOTREACHED */  

  313.     return 0;  

  314. }  

赞(0) 打赏
转载请注明出处:服务器评测 » Squid的main函数源码分析
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏