up主下午没课,暂时也不知道学什么,所以继续继续~
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.
*
*/
* 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,如下:
- static int create_server_socket(void)
- {
- int server_s;
- /* 如果使用IPV6模式,AF_INET6;否则为AF_INET*/
- server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
- if (server_s == -1) {
- DIE("unable to create socket");
- }
- /* 将fd设为不堵塞 */
- /* server socket is nonblocking */
- if (set_nonblock_fd(server_s) == -1) {
- DIE("fcntl: unable to set server socket to nonblocking");
- }
- /* 将fd设置为exec时关闭,这样防止cgi得到这个fd */
- /* close server socket on exec so cgi's can't write to it */
- if (fcntl(server_s, F_SETFD, 1) == -1) {
- DIE("can't set close-on-exec on server socket!");
- }
- /* 设置SO_REUSEADDR选项。印象中,该选项允许两个socket绑定到相同端口不同接口,目前不知道这么做的明确意义 */
- /* reuse socket addr */
- if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
- sizeof (sock_opt))) == -1) {
- DIE("setsockopt");
- }
- /* 根据是否是IPV6填充不同的struct sockaddr,进行bind() */
- /* internet family-specific code encapsulated in bind_server() */
- if (bind_server(server_s, server_ip) == -1) {
- DIE("unable to bind");
- }
- /* bakclog宏定义为SO_MAXCONN,SO_MAXCONN定义在compat.h中,默认为250。一般系统不允许这么大的backlog,设250是以防你已经将内核设置成支持这么大的连接数了。 */
- /* listen: large number just in case your kernel is nicely tweaked */
- if (listen(server_s, backlog) == -1) {
- DIE("unable to listen");
- }
- return server_s;
- }
该函数在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啊。
代码贴一下,望高手解答。
- unsigned long _needs_escape[(NEEDS_ESCAPE_BITS+NEEDS_ESCAPE_WORD_LENGTH-1)/NEEDS_ESCAPE_WORD_LENGTH];
- void build_needs_escape(void)
- {
- unsigned int a, b;
- const unsigned char special[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-_.!~*'():@&=+$,/?";
- /* 21 Mar 2002 - jnelson - confirm with Apache 1.3.23 that '?'
- * is safe to leave unescaped.
- */
- unsigned short i, j;
- b = 1;
- for (a=0; b!=0; a++) b=b<<1;
- /* I found $a bit positions available in an unsigned long. */
- if (a < NEEDS_ESCAPE_WORD_LENGTH) {
- fprintf(stderr,
- "NEEDS_ESCAPE_SHIFT configuration error -- "\
- "%d should be <= log2(%d)\n",
- NEEDS_ESCAPE_SHIFT, a);
- exit(1);
- } else if (a >= 2*NEEDS_ESCAPE_WORD_LENGTH) {
- /* needs_escape_shift configuration suboptimal */
- } else {
- /* Ahh, just right! */;
- }
- memset(_needs_escape, ~0, sizeof(_needs_escape));
- for(i = 0; i < sizeof(special) - 1; ++i) {
- j=special[i];
- if (j>=NEEDS_ESCAPE_BITS) {
- /* warning: character $j will be needlessly escaped. */
- } else {
- _needs_escape[NEEDS_ESCAPE_INDEX(j)]&=~NEEDS_ESCAPE_MASK(j);
- }
- }
- }
main剩下的不多了,我们先瞅一眼:
- if (max_connections < 1) {
- struct rlimit rl;
- /* has not been set explicitly */
- c = getrlimit(RLIMIT_NOFILE, &rl);
- if (c < 0) {
- perror("getrlimit");
- exit(1);
- }
- max_connections = rl.rlim_cur;
- }
- /* background ourself */
- if (do_fork) {
- switch(fork()) {
- case -1:
- /* error */
- perror("fork");
- exit(1);
- break;
- case 0:
- /* child, success */
- break;
- default:
- /* parent, success */
- exit(0);
- break;
- }
- }
- /* main loop */
- timestamp();
- status.requests = 0;
- status.errors = 0;
- start_time = current_time;
- select_loop(server_s);
- return 0;
- }