分享

BOA代码笔记 3

 lchjczw 2012-12-26

boa.c(依然续)

main函数接下来该open_logs()了。顾名思义,这个函数负责日志文件的顺利打开。
注释是这么说明的:
/*
 * Name: open_logs
 *
 * Description: Opens access log, error log, and if specified, cgi log
 * Ties stderr to error log, except during cgi execution, at which
 * time cgi log is the stderr for cgis.
 *
 * Access log is line buffered, error log is not buffered.
 *
 */
值得一提的是,支持管道和socket记录。

如果你的error_log_name写作 “| yourlogprogram”, 那么日志输出将通过管道输出到yourlogprogram中。
执行打开的exec函数使用方式为execl("/bin/sh", "sh", "-c", command, (char *) 0); 
-c的选项代表运行sh的第一个参数的程序,后边参数为运行程序的参数。

如果你的error_log_name写作“: host:port”的形式,那么会向host指定的主机的port进行tcp连接。日志将发送到对端。

将STDERR_FILENO的 close-on-exec 设置为 true:fcntl(STDERR_FILENO, F_SETFD, 1);
使用setvbuf将access_log设置为行缓冲:setvbuf(access_log, (char *) NULL, _IOLBF, 0);


open_logs()完了之后是create_server_socket()返回一个fd,如下:
  1. static int create_server_socket(void)  
  2. {  
  3.     int server_s;  
  4.     /* 如果使用IPV6模式,AF_INET6;否则为AF_INET*/  
  5.     server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);  
  6.     if (server_s == -1) {  
  7.         DIE("unable to create socket");  
  8.     }  
  9.     /* 将fd设为不堵塞 */  
  10.     /* server socket is nonblocking */  
  11.     if (set_nonblock_fd(server_s) == -1) {  
  12.         DIE("fcntl: unable to set server socket to nonblocking");  
  13.     }  
  14.     /* 将fd设置为exec时关闭,这样防止cgi得到这个fd */  
  15.     /* close server socket on exec so cgi's can't write to it */  
  16.     if (fcntl(server_s, F_SETFD, 1) == -1) {  
  17.         DIE("can't set close-on-exec on server socket!");  
  18.     }  
  19.     /* 设置SO_REUSEADDR选项。印象中,该选项允许两个socket绑定到相同端口不同接口,目前不知道这么做的明确意义 */  
  20.     /* reuse socket addr */  
  21.     if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,  
  22.                     sizeof (sock_opt))) == -1) {  
  23.         DIE("setsockopt");  
  24.     }  
  25.     /* 根据是否是IPV6填充不同的struct sockaddr,进行bind() */  
  26.     /* internet family-specific code encapsulated in bind_server()  */  
  27.     if (bind_server(server_s, server_ip) == -1) {  
  28.         DIE("unable to bind");  
  29.     }  
  30.     /* bakclog宏定义为SO_MAXCONN,SO_MAXCONN定义在compat.h中,默认为250。一般系统不允许这么大的backlog,设250是以防你已经将内核设置成支持这么大的连接数了。 */  
  31.     /* listen: large number just in case your kernel is nicely tweaked */  
  32.     if (listen(server_s, backlog) == -1) {  
  33.         DIE("unable to listen");  
  34.     }  
  35.     return server_s;  
  36. }  
该函数在main里调用语句如下,server_s = create_server_socket();


main里接下来的几个函数比较轻松
init_signals();
这个函数设置了一些signal handler,屏蔽了一些信号。init_signals()本身没什么,信号处理函数还是有点讲究的。之后如果用到再分析吧。
drop_privs()
如果以root身份运行,现在可以尝试放弃root身份,转为boa.conf配置文件中的身份。
create_common_env();
将cgi用到的环境变量添加到common_cgi_env[] 里。
build_needs_escape();
说实话,我真一点儿都没看懂这个函数干什么用的,好象是初始化一个转移字符数组。html需要转义的字符?
还有这句 for (a=0; b!=0; a++) b=b<<1; 不是对b的位计数吗?直接sizeof(b)*8不行吗?我测试了一下,a的值最后就是32啊。
代码贴一下,望高手解答。
  1. unsigned long _needs_escape[(NEEDS_ESCAPE_BITS+NEEDS_ESCAPE_WORD_LENGTH-1)/NEEDS_ESCAPE_WORD_LENGTH];  
  2.   
  3. void build_needs_escape(void)  
  4. {  
  5.     unsigned int a, b;  
  6.     const unsigned char special[] =  
  7.         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"  
  8.         "abcdefghijklmnopqrstuvwxyz"  
  9.         "0123456789"  
  10.         "-_.!~*'():@&=+$,/?";  
  11.     /* 21 Mar 2002 - jnelson - confirm with Apache 1.3.23 that '?' 
  12.      * is safe to leave unescaped. 
  13.      */  
  14.     unsigned short i, j;  
  15.   
  16.     b = 1;  
  17.     for (a=0; b!=0; a++) b=b<<1;  
  18.     /* I found $a bit positions available in an unsigned long. */  
  19.     if (a < NEEDS_ESCAPE_WORD_LENGTH) {  
  20.         fprintf(stderr,  
  21.                 "NEEDS_ESCAPE_SHIFT configuration error -- "\  
  22.                 "%d should be <= log2(%d)\n",  
  23.                 NEEDS_ESCAPE_SHIFT, a);  
  24.         exit(1);  
  25.     } else if (a >= 2*NEEDS_ESCAPE_WORD_LENGTH) {  
  26.         /* needs_escape_shift configuration suboptimal */  
  27.     } else {  
  28.         /* Ahh, just right! */;  
  29.     }  
  30.     memset(_needs_escape, ~0, sizeof(_needs_escape));  
  31.     for(i = 0; i < sizeof(special) - 1; ++i) {  
  32.         j=special[i];  
  33.         if (j>=NEEDS_ESCAPE_BITS) {  
  34.             /* warning: character $j will be needlessly escaped. */  
  35.         } else {  
  36.             _needs_escape[NEEDS_ESCAPE_INDEX(j)]&=~NEEDS_ESCAPE_MASK(j);  
  37.         }  
  38.     }  
  39. }  



main剩下的不多了,我们先瞅一眼:
  1.     if (max_connections < 1) {  
  2.         struct rlimit rl;  
  3.   
  4.         /* has not been set explicitly */  
  5.         c = getrlimit(RLIMIT_NOFILE, &rl);  
  6.         if (c < 0) {  
  7.             perror("getrlimit");  
  8.             exit(1);  
  9.         }  
  10.         max_connections = rl.rlim_cur;  
  11.     }  
  12.   
  13.     /* background ourself */  
  14.     if (do_fork) {  
  15.         switch(fork()) {  
  16.         case -1:  
  17.             /* error */  
  18.             perror("fork");  
  19.             exit(1);  
  20.             break;  
  21.         case 0:  
  22.             /* child, success */  
  23.             break;  
  24.         default:  
  25.             /* parent, success */  
  26.             exit(0);  
  27.             break;  
  28.         }  
  29.     }  
  30.   
  31.     /* main loop */  
  32.     timestamp();  
  33.   
  34.     status.requests = 0;  
  35.     status.errors = 0;  
  36.   
  37.     start_time = current_time;  
  38.     select_loop(server_s);  
  39.     return 0;  
  40. }  
相信我吧,虽然目前为止还没什么真正的困难,但那个select_loop(server_s);绝对是个boss。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多