Clamav殺毒軟體源碼分析筆記[五]

來源:互聯網
上載者:User
   Clamav殺毒軟體源碼分析筆記[五]


刺蝟@http://blog.csdn.net/littlehedgehog





[Socket通訊]

套間字socket常用於服務/客戶模型的應用程式之間的通訊和資料連線,需要重點關注的是這個所謂的服務端/用戶端完全可以是一台電腦的兩個應用程式。前面我們已經提到了,Clamd就是這個服務端,也就是說它是整個程式的頂樑柱,所有的關鍵邏輯處理都是它一人為之,不可不謂之強悍。所有的這些功勞都應該歸功於Clamd中的線程處理,不過我們先還不是來關注線程的,先看看socket的建立。

  1. int localserver(const struct optstruct *opt, const struct cfgstruct *copt, struct cl_node *root)
  2. {
  3.     struct sockaddr_un server;
  4.     int sockfd, backlog;
  5.     struct cfgstruct *cpt;
  6.     struct stat foo;
  7.     char *estr;
  8.     /* 下面是初始化套間字 順便貼上了設定檔中有關localsocket的資訊
  9.     # Path to a local socket file the daemon will listen on.
  10.     # Default: disabled
  11.     LocalSocket /tmp/clamd
  12.     */
  13.     memset((char *) &server, 0, sizeof(server));
  14.     server.sun_family = AF_UNIX;
  15.     strncpy(server.sun_path, cfgopt(copt, "LocalSocket")->strarg, sizeof(server.sun_path));
  16.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  17.     {
  18.         estr = strerror(errno);
  19.         /*
  20.         fprintf(stderr, "ERROR: socket() error: %s/n", estr);
  21.         */
  22.         logg("!Socket allocation error: %s/n", estr);
  23.         exit(1);
  24.     }
  25.     if (bind(sockfd, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) == -1)
  26.     {
  27.         if (errno == EADDRINUSE)        //連接埠號碼或者socket被其他進程使用
  28.         {
  29.             if (connect(sockfd, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) >= 0)  //這裡串連成功表明socket確實是被別的進程使用了
  30.             {
  31.                 close(sockfd);
  32.                 logg("!Socket file %s is in use by another process./n", server.sun_path);
  33.                 exit(1);
  34.             }
  35.             if (cfgopt(copt, "FixStaleSocket"))         //該socket不是被別的進程佔據了,下面我們要做修複工作,設定檔中有FixStaleSocket 意思是要修理失效的socket
  36.             {
  37.                 logg("^Socket file %s exists. Unclean shutdown? Removing.../n", server.sun_path);
  38.                 if (unlink(server.sun_path) == -1)      //從檔案系統中刪除一個名稱。如果名稱是檔案的最後一個串連,並且沒有其它進程將檔案開啟,名稱對應的檔案會實際被刪除。
  39.                 {
  40.                     estr = strerror(errno);
  41.                     logg("!Socket file %s could not be removed: %s/n", server.sun_path, estr);
  42.                     exit(1);
  43.                 }
  44.                 if (bind(sockfd, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) == -1)        //再次bind如果失敗
  45.                 {
  46.                     estr = strerror(errno);
  47.                     logg("!Socket file %s could not be bound: %s (unlink tried)/n", server.sun_path, estr);
  48.                     exit(1);
  49.                 }
  50.             }
  51.             else if (stat(server.sun_path, &foo) != -1)
  52.             {
  53.                 logg("!Socket file %s exists. Either remove it, or configure a different one./n", server.sun_path);
  54.                 exit(1);
  55.             }
  56.         }
  57.         else        //這裡出現了其他錯誤
  58.         {
  59.             estr = strerror(errno);
  60.             logg("!Socket file %s could not be bound: %s/n", server.sun_path, estr);
  61.             exit(1);
  62.         }
  63.     }
  64.     logg("Unix socket file %s/n", server.sun_path);
  65.     if ((cpt = cfgopt(copt, "MaxConnectionQueueLength")))   //Maximum length the queue of pending connections may grow to.  backlog參數為提出串連請求後,在伺服器接收該串連請求時的等待隊列中的串連數
  66.         backlog = cpt->numarg;
  67.     else
  68.         backlog = CL_DEFAULT_BACKLOG;
  69.     logg("Setting connection queue length to %d/n", backlog);
  70.     if (listen(sockfd, backlog) == -1)
  71.     {
  72.         estr = strerror(errno);
  73.         /*
  74.         fprintf(stderr, "ERROR: listen() error: %s/n", estr);
  75.         */
  76.         logg("!listen() error: %s/n", estr);
  77.         exit(1);
  78.     }
  79.     acceptloop_th(sockfd, root, copt);
  80.     return 0;
  81. }

注意這裡建立的是本地socket的,區別比較大,但是在我這裡唯一的區別就是加粗了,形成了很黑很粗壯的效果...

這裡我們主要就是建立個socket的,其實也沒啥好說的,主要是整個函數的調用,將改變整個曆史進程方向──acceptloop_th(sockfd, root, copt);  因為我們要被一直束縛在裡面,貌似永世不得超生了。

acceptloop_th 很長很強大,所以我也就不把源碼貼出來了,否則有湊字數的嫌疑,重點關注下下面一塊:

  1.  /* set up signal handling */
  2.     sigfillset(&sigset);
  3.     sigdelset(&sigset, SIGINT);
  4.     sigdelset(&sigset, SIGTERM);
  5.     sigdelset(&sigset, SIGSEGV);
  6.     sigdelset(&sigset, SIGHUP);
  7.     sigdelset(&sigset, SIGPIPE);
  8.     sigdelset(&sigset, SIGUSR2);
  9.     sigprocmask(SIG_SETMASK, &sigset, NULL);        //通過這條語句 進程有了新的訊號屏蔽集 這裡是屏蔽一些我們不關心的訊號 
  10.     /* SIGINT, SIGTERM, SIGSEGV */
  11.     sigact.sa_handler = sighandler_th;
  12.     sigemptyset(&sigact.sa_mask);
  13.     sigaddset(&sigact.sa_mask, SIGINT);
  14.     sigaddset(&sigact.sa_mask, SIGTERM);
  15.     sigaddset(&sigact.sa_mask, SIGHUP);
  16.     sigaddset(&sigact.sa_mask, SIGPIPE);
  17.     sigaddset(&sigact.sa_mask, SIGUSR2);
  18.     sigaction(SIGINT, &sigact, NULL);               //下面都是安裝新的訊號處理常式 
  19.     sigaction(SIGTERM, &sigact, NULL);
  20.     sigaction(SIGHUP, &sigact, NULL);
  21.     sigaction(SIGPIPE, &sigact, NULL);
  22.     sigaction(SIGUSR2, &sigact, NULL);

為什麼這裡需要重新設定這麼多的訊號處理呢?原因就是我們要屏蔽或者攔截其中有些訊號,做出相應的反應,這貌似是廢話...???? 比如SIGINT,這訊號會導致進程終止,我們需要在終止之前把記錄寫入log檔案,ok,必須攔截訊號函數.



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.