Clamav殺毒軟體源碼分析筆記[七]
刺蝟@http://blog.csdn.net/littlehedgehog
[accept迴圈處理]
上次本來可以在文章五把Clamd的主要函數說完的,不過線程未了,火候未到. 這次火候到了,Clamd的盡頭也就走到底了.
- if ((thr_pool=thrmgr_new(max_threads, idletimeout, scanner_thread)) == NULL)
- {
- logg("!thrmgr_new failed/n");
- exit(-1);
- }
- time(&start_time); //記錄目前時間 儲存在start_time中
- for (;;)
- {
- new_sd = accept(socketd, NULL, NULL);
-
- /* 注意啦注意啦 中斷也會打斷accept阻塞 這裡我們只需要檢查errno是不是EINTR即可 如果傳回值為-1(表示accpet失敗)
- * 又不是中斷打擾所致,那就是出了其他問題了.
- */
- if ((new_sd == -1) && (errno != EINTR))
- {
- /* very bad - need to exit or restart */
- #ifdef HAVE_STRERROR_R
- logg("!accept() failed: %s/n", strerror_r(errno, buff, BUFFSIZE));
- #else
- logg("!accept() failed/n");
- #endif
- continue;
- }
-
- /* 此訊號一出 表示終端斷線了 我們需要重新開啟log檔案*/
- if (sighup)
- {
- logg("SIGHUP caught: re-opening log file./n");
- logg_close();
- sighup = 0;
- if (!logg_file && (cpt = cfgopt(copt, "LogFile")))
- logg_file = cpt->strarg;
- }
-
- /* progexit是我們進程收到了SIGINT相關訊號設定的標識 如果收到很不幸,我們要退出了 */
- if (!progexit && new_sd >= 0)
- {
- client_conn = (client_conn_t *) mmalloc(sizeof(struct client_conn_tag)); //這裡是組裝thrmgr_dispatch的userdata參數
- client_conn->sd = new_sd; //socket 描述符! 後面老是要用到 這個是服務端和用戶端通訊的一個通道
- client_conn->options = options;
- client_conn->copt = copt;
- client_conn->root = cl_dup(root);
- client_conn->root_timestamp = reloaded_time;
- client_conn->limits = &limits;
- client_conn->mainpid = mainpid;
- if (!thrmgr_dispatch(thr_pool, client_conn))
- {
- close(client_conn->sd);
- free(client_conn);
- logg("!thread dispatch failed/n");
- }
- }
- pthread_mutex_lock(&exit_mutex);
- if (progexit)
- {
- if (new_sd >= 0)
- {
- close(new_sd);
- }
- pthread_mutex_unlock(&exit_mutex);
- break;
- }
- pthread_mutex_unlock(&exit_mutex);
-
- //如果設定了自我檢查
- if (selfchk)
- {
- time(¤t_time);
- if ((current_time - start_time) > (time_t)selfchk) //這裡是指病毒庫的時間超過了我們設定的有效時間
- {
- if (reload_db(root, copt, TRUE)) //這個是檢測資料庫是否已經被更改,若是要設定reload 方便下面重新載入點
- {
- pthread_mutex_lock(&reload_mutex);
- reload = 1;
- pthread_mutex_unlock(&reload_mutex);
- }
- time(&start_time);
- }
- }
- pthread_mutex_lock(&reload_mutex);
- if (reload)
- {
- pthread_mutex_unlock(&reload_mutex);
- root = reload_db(root, copt, FALSE);
- pthread_mutex_lock(&reload_mutex);
- reload = 0;
- time(&reloaded_time);
- pthread_mutex_unlock(&reload_mutex);
- #ifdef CLAMUKO
- if (cfgopt(copt, "ClamukoScanOnLine") || cfgopt(copt, "ClamukoScanOnAccess"))
- {
- logg("Stopping and restarting Clamuko./n");
- pthread_kill(clamuko_pid, SIGUSR1);
- pthread_join(clamuko_pid, NULL);
- tharg->root = root;
- pthread_create(&clamuko_pid, &clamuko_attr, clamukoth, tharg);
- }
- #endif
- }
- else
- {
- pthread_mutex_unlock(&reload_mutex);
- }
- }
- /* Destroy the thread manager.
- * This waits for all current tasks to end
- */
- thrmgr_destroy(thr_pool);
這裡一定要貼出 if ((thr_pool=thrmgr_new(max_threads, idletimeout, scanner_thread)) == NULL)
主要是想說在建立線程池的時候我們就已經確定好了線程執行的函數 scanner_thread 大家可以回頭看看線程池建立處理代碼. 下面就是給線程組裝參數結構體了,主要是線程傳參數形式已被定死了,所以我們要裝載結構體.
線程的處理函數也只是一個代理而已,真正辦實事的幹部只有command了.如下所示:
- /* 線程的主函數 在這裡面設定處理job */
- void scanner_thread(void *arg)
- {
- client_conn_t *conn = (client_conn_t *) arg;
- sigset_t sigset;
- int ret, timeout, session=FALSE;
- struct cfgstruct *cpt;
- /* ignore all signals 這裡作者已經注釋了,這裡全設定為1,其實是屏蔽訊號 */
- sigfillset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL); //設定線程的訊號屏蔽碼,語義與sigprocmask()相同,但對不允許屏蔽的Cancel訊號和不允許響應的Restart訊號進行了保護。被屏蔽的訊號儲存在訊號隊列中,可由sigpending()函數取出。
- if ((cpt = cfgopt(conn->copt, "ReadTimeout")))
- {
- timeout = cpt->numarg;
- }
- else
- {
- timeout = CL_DEFAULT_SCANTIMEOUT;
- }
- if (!timeout)
- timeout = -1;
- do
- {
- ret = command(conn->sd, conn->root, conn->limits, conn->options, conn->copt, timeout); //這才是真正幹事兒
- if (ret == -1)
- {
- break;
- }
- switch (ret)
- {
- case COMMAND_SHUTDOWN:
- pthread_mutex_lock(&exit_mutex);
- progexit = 1;
- kill(conn->mainpid, SIGTERM); //這裡給主線程,也就是服務端進程發送關閉訊號
- pthread_mutex_unlock(&exit_mutex);
- break;
- case COMMAND_RELOAD:
- pthread_mutex_lock(&reload_mutex);
- reload = 1;
- pthread_mutex_unlock(&reload_mutex);
- break;
-
- case COMMAND_SESSION: //用戶端傳來命令session 我們仍在一個session當中 這裡還要繼續迴圈擷取命令(但是這個是什麼狀態下要發送嗯這個命令的)
- session = TRUE;
- timeout = 5;
- break;
- case COMMAND_END:
- session = FALSE;
- break;
- }
- if (session)
- {
- pthread_mutex_lock(&exit_mutex);
- if (progexit)
- {
- session = FALSE;
- }
- pthread_mutex_unlock(&exit_mutex);
- pthread_mutex_lock(&reload_mutex);
- if (conn->root_timestamp != reloaded_time)
- {
- session = FALSE;
- }
- pthread_mutex_unlock(&reload_mutex);
- }
- }
- while (session);
- close(conn->sd);
- cl_free(conn->root);
- free(conn);
- return;
- }
就這樣,通過command,我們把任務又推卸給其它函數來做了. command是最終辦事的函數,不過這要等下次再說了,因為實驗室要關門了.