http://blog.csdn.net/jemofh159/article/details/7913120
-
1 boa.c
-
-
主程序:
-
-
----1) 关闭文件
-
for(i=3;i<=1024;i++)
-
close(i);
-
-
----2) 设置进程权限掩码
-
umask(~0600); rw- --- ---;
-
-
----3) 打开黑洞,并将标准输入输出指向它,
-
open("/dev/null", 0);
-
dup2(devnullfd, STDIN_FILENO);
-
dup2(devnullfd, STDOUT_FILENO);
-
-
----4) 更新时间戳,日志要用到。
-
time(¤t_time);
-
-
----5)解析命令行
-
-f
-
server_root = strdup(optaarg);
-
-r
-
chdir(optarg);
-
chroot(optarg);
-
chdir("/");
-
-d
-
do_fork=0;
-
-
----6)
-
fixup_server_root();
-
-
----7)
-
read_config_files();
-
-
----8)
-
open_logs();
-
-
----9)
-
server_s = create_server_socket();
-
-
---10)
-
init_signals();
-
-
---11)
-
drop_privs();
-
-
---12) Set up the environment variables that are common to all CGI scripts
-
create_common_env();
-
-
---13) fork子进程,父进程退出。之后子进程成为守护进程
-
if(do_fork) switch(fork())
-
-
---14) 得到PID,用于产生独一无二的临时文件名或路径。
-
int pid = getpid();
-
-
---15) 更新时间戳,然后进入主循环。
-
timestamp();
-
select_loop(server_s)
-
{
-
1)清空,block_read_fdset、block_write_fdset;
-
2)设置server_s和请求超时时间。
-
3)进入while(1)
-
{
-
1) 处理sighup 、 sigchld 、 sigalrm、 sigterm等信号。
-
2)重设max_fd = -1;
-
3) 将合适的request从block链表里移到ready链表里。
-
if(reques_block) fdset_update();
-
-
4) process_requests(server_s);
-
-
5) if (!sigterm_flag && total_connections < (max_connections - 10)) BOA_FD_SET(server_s, &block_read_fdset);
-
-
6) reset timeout
-
-
7) select
调
用,select(max_fd + 1, &block_read_fdset, &block_write_fdset, NULL, (request_ready || request_block ? &req_timeout : NULL))
-
-
8)更新当前时间,time(&curent_time);
-
9) if (FD_ISSET(server_s, &block_read_fdset)) pending_requests = 1;
-
-
}
-
-
}
一、先来看看 fdset_update()
boa里边有三个请求链表
request *request_ready = NULL; /* ready list head */
request *request_block = NULL; /* blocked list head */
request *request_free = NULL; /* free list head */
-
struct request {
-
int fd;
-
int status;
-
time_t time_last;
-
char *pathname;
-
int simple;
-
int keepalive;
-
int kacount;
-
-
int data_fd;
-
unsigned long filesize;
-
unsigned long filepos;
-
char *data_mem;
-
int method;
-
-
char *logline;
-
-
char *header_line;
-
char *header_end;
-
int parse_pos;
-
int client_stream_pos;
-
-
int buffer_start;
-
int buffer_end;
-
-
char *http_version;
-
int response_status;
-
-
char *if_modified_since;
-
time_t last_modified;
-
-
char local_ip_addr[NI_MAXHOST];
-
-
-
-
int remote_port;
-
-
char remote_ip_addr[NI_MAXHOST];
-
-
int is_cgi;
-
int cgi_status;
-
int cgi_env_index;
-
-
-
char *header_user_agent;
-
char *header_referer;
-
-
int post_data_fd;
-
-
char *path_info;
-
char *path_translated;
-
char *script_name;
-
char *query_string;
-
char *content_type;
-
char *content_length;
-
-
struct mmap_entry *mmap_entry_var;
-
-
struct request *next;
-
struct request *prev;
-
-
-
char buffer[BUFFER_SIZE + 1];
-
char request_uri[MAX_HEADER_LENGTH + 1];
-
char client_stream[CLIENT_STREAM_SIZE];
-
char *cgi_env[CGI_ENV_MAX + 4];
-
-
#ifdef ACCEPT_ON
-
char accept[MAX_ACCEPT_LENGTH];
-
#endif
-
};
-
-
typedef struct request request;
-
static void fdset_update(void)
-
{
-
request *current, *next;
-
-
for (current = request_block; current; current = next)
-
{
-
time_t time_since = current_time - current->time_last;
-
next = current->next;
-
-
-
-
-
if (current->kacount < ka_max &&
-
(time_since >= ka_timeout) &&
-
!current->logline)
-
current->status = DEAD;
-
else if (time_since > REQUEST_TIMEOUT)
-
{
-
log_error_doc(current);
-
fputs("connection timed out\n", stderr);
-
current->status = DEAD;
-
}
-
if (current->buffer_end && current->status < DEAD)
-
{
-
if (FD_ISSET(current->fd, &block_write_fdset))
-
ready_request(current);
-
else
-
{
-
BOA_FD_SET(current->fd, &block_write_fdset);
-
}
-
} else
-
{
-
switch (current->status)
-
{
-
case WRITE:
-
case PIPE_WRITE:
-
if (FD_ISSET(current->fd, &block_write_fdset))
-
ready_request(current);
-
else
-
{
-
BOA_FD_SET(current->fd, &block_write_fdset);
-
}
-
break;
-
case BODY_WRITE:
-
if (FD_ISSET(current->post_data_fd, &block_write_fdset))
-
ready_request(current);
-
else
-
{
-
BOA_FD_SET(current->post_data_fd, &block_write_fdset);
-
}
-
break;
-
case PIPE_READ:
-
if (FD_ISSET(current->data_fd, &block_read_fdset))
-
ready_request(current);
-
else
-
{
-
BOA_FD_SET(current->data_fd, &block_read_fdset);
-
}
-
break;
-
case DONE:
-
if (FD_ISSET(current->fd, &block_write_fdset))
-
ready_request(current);
-
else
-
{
-
BOA_FD_SET(current->fd, &block_write_fdset);
-
}
-
break;
-
case DEAD:
-
ready_request(current);
-
break;
-
default:
-
if (FD_ISSET(current->fd, &block_read_fdset))
-
ready_request(current);
-
else
-
{
-
BOA_FD_SET(current->fd, &block_read_fdset);
-
}
-
break;
-
}
-
}
-
current = next;
-
}
-
}
for循环里面,
首先,获取time_since为距离上次成功操作经历的时间。
如果请求出于keepalive中,time_since已经大于ka_timeout(配置文件里可以配置),而且还没有读取到任何东西,那么request的status变为DEAD。
如果time_since大于REQUEST_TIMEOUT(60),那么status变为DEAD。
如果缓冲区有数据,而且status小于DEAD:
如果不在block_write_fdset里,那么放到block_write_fdset里。
如果fd已经在block_write_fdset里,调用ready_request,将request从block队列里转移到ready队列里,同时清除block_write_fdset里的标志
ready_request函数的功能是根据status,从fdset中清除对应fd。
其他情况:
状态为WRITE,PIPE_WRITE,DONE的请求,如果没有那就放到block_write_fdset里,如果已经在了就调用ready_request。
状态为BODY_WRITE,将request的post_data_fd做以上处理。post_data_fd注释为/* fd for post data tmpfile */,应该是客户端POST方法时的临时文件
状态为PIPE_READ,将request的data_fd做类似处理,不过检查的是block_read_fdset。
状态为DEAD,直接调用ready_request。
其他的,检查fd是否在block_read_fdset,并作相应处理。
二、再看看process_erquests函数。
对于每一个ready queue里的请求遍历处理,返回值-1表示需要进入block queue;返回值0表示请求结束;返回值1表示还要在ready queue里,需进一步处理。
首先检查是否有pending_requests,如果有调用get_request(server_s);,接受一个connection,加入ready_queue。
get_request(server_s);大体功能是,接受一个请求,并做一些简单的初始化,加入ready_queue。
然后开始轮询ready链表:
如果有数据要写,状态不是DEAD或DONE,就调用req_flush(current)。
每一轮最后检查一次,是否还有pending_requests。有的话加入ready_queue。
阅读(2183) | 评论(0) | 转发(0) |