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,如下:
- static int create_server_socket(void)
- {
- int server_s;
-
- server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
- if (server_s == -1) {
- DIE("unable to create socket");
- }
-
-
- if (set_nonblock_fd(server_s) == -1) {
- DIE("fcntl: unable to set server socket to nonblocking");
- }
-
-
- if (fcntl(server_s, F_SETFD, 1) == -1) {
- DIE("can't set close-on-exec on server socket!");
- }
-
-
- if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
- sizeof (sock_opt))) == -1) {
- DIE("setsockopt");
- }
-
-
- if (bind_server(server_s, server_ip) == -1) {
- DIE("unable to bind");
- }
-
-
- 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"
- "-_.!~*'():@&=+$,/?";
-
-
-
- unsigned short i, j;
-
- b = 1;
- for (a=0; b!=0; a++) b=b<<1;
-
- 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) {
-
- } else {
- ;
- }
- memset(_needs_escape, ~0, sizeof(_needs_escape));
- for(i = 0; i < sizeof(special) - 1; ++i) {
- j=special[i];
- if (j>=NEEDS_ESCAPE_BITS) {
-
- } else {
- _needs_escape[NEEDS_ESCAPE_INDEX(j)]&=~NEEDS_ESCAPE_MASK(j);
- }
- }
- }
main剩下的不多了,我们先瞅一眼:
- if (max_connections < 1) {
- struct rlimit rl;
-
-
- c = getrlimit(RLIMIT_NOFILE, &rl);
- if (c < 0) {
- perror("getrlimit");
- exit(1);
- }
- max_connections = rl.rlim_cur;
- }
-
-
- if (do_fork) {
- switch(fork()) {
- case -1:
-
- perror("fork");
- exit(1);
- break;
- case 0:
-
- break;
- default:
-
- exit(0);
- break;
- }
- }
-
-
- timestamp();
-
- status.requests = 0;
- status.errors = 0;
-
- start_time = current_time;
- select_loop(server_s);
- return 0;
- }
相信我吧,虽然目前为止还没什么真正的困难,但那个select_loop(server_s);绝对是个boss。
|