Clamav杀毒软件源码分析笔记[五]

 
  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,必须拦截信号函数.





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值