Squid的main函数源码分析

来源:互联网 发布:连云港网络推广 编辑:程序博客网 时间:2024/04/30 11:58

要分析一款开源的软件除了要弄清楚一些基本的使用和配置之外,其次最重要的就是对源代码进行分析。对源代码进行分析首先应从其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.} 
本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2012-02/54052.htm

原创粉丝点击