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是最终办事的函数,不过这要等下次再说了,因为实验室要关门了.