歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

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. }  
Copyright © Linux教程網 All Rights Reserved