BOA代码笔记 3

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.
 *
 */
值得一提的是,支持管道和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;
}
相信我吧,虽然目前为止还没什么真正的困难,但那个select_loop(server_s);绝对是个boss。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值