void open_logs(void)
{
int error_log;
/* if error_log_name is set, dup2 stderr to it */
/* otherwise, leave stderr alone */
/* we don't want to tie stderr to /dev/null */
if (error_log_name) {
/* open the log file */
if (!(error_log = open_gen_fd(error_log_name))) {
DIE("unable to open error log");
}
/* redirect stderr to error_log */
if (dup2(error_log, STDERR_FILENO) == -1) {
DIE("unable to dup2 the error log");
}
close(error_log);
}
/* set the close-on-exec to true */
//当使用exec时关闭stderr,防止其他程序写stderr
if (fcntl(STDERR_FILENO, F_SETFD, 1) == -1) {
DIE("unable to fcntl the error log");
}
if (access_log_name) {//权限日志
/* Used the "a" flag with fopen, but fopen_gen_fd builds that in
* implicitly when used as a file, and "a" is incompatible with
* pipes and network sockets. */
if (!(access_log = fopen_gen_fd(access_log_name, "w"))) {
int errno_save = errno;
fprintf(stderr, "Cannot open %s for logging: ",
access_log_name);
errno = errno_save;
perror("logfile open");
exit(errno);
}
/* line buffer the access log */
#ifdef SETVBUF_REVERSED
setvbuf(access_log, _IOLBF, (char *) NULL, 0);
#else
setvbuf(access_log, (char *) NULL, _IOLBF, 0);
#endif
} else
access_log = NULL;
if (cgi_log_name) {//cgi日志
cgi_log_fd = open_gen_fd(cgi_log_name);
if (cgi_log_fd == -1) {
WARN("open cgi_log");
free(cgi_log_name);
cgi_log_name = NULL;
cgi_log_fd = 0;
} else {
if (fcntl(cgi_log_fd, F_SETFD, 1) == -1) {//当exec时关闭cgi_log
WARN("unable to set close-on-exec flag for cgi_log");
close(cgi_log_fd);
cgi_log_fd = 0;
free(cgi_log_name);
cgi_log_name = NULL;
}
}
}
}
open_logs完成了程序所需日志的打开、重定向和设置,并防止新建进程对日志的干扰。
完成 一系列的环境初始化后,接下来就是创建监听socket了。
server_s = create_server_socket();
static int create_server_socket(void)
{
int server_s;
server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP); //创建TCP协议的socket
if (server_s == -1) {
DIE("unable to create socket");
}
/* server socket is nonblocking */
if (set_nonblock_fd(server_s) == -1) {//设置文件描述符为无阻塞模式
DIE("fcntl: unable to set server socket to nonblocking");
}
/* close server socket on exec so cgi's can't write to it */
if (fcntl(server_s, F_SETFD, 1) == -1) { //FD_CLOEXEC
DIE("can't set close-on-exec on server socket!");
}
/* reuse socket addr */
if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
sizeof (sock_opt))) == -1) {
DIE("setsockopt");
}
/* internet family-specific code encapsulated in bind_server() */
if (bind_server(server_s, server_ip) == -1) {//实现了ipv4和ipv6的定制绑定
DIE("unable to bind");
}
/* listen: large number just in case your kernel is nicely tweaked */
if (listen(server_s, backlog) == -1) {//监听
DIE("unable to listen");
}
return server_s;
}
一个标准的socket创建流程后,服务端口已经成功被程序监听。
接下来是对信号处理函数进行设置。
init_signals();
void init_signals(void)
{
struct sigaction sa;
sa.sa_flags = 0;
//设置在信号处理函数中需要屏蔽的信号
sigemptyset(&sa.sa_mask); //清空sa_mask
sigaddset(&sa.sa_mask, SIGSEGV);
sigaddset(&sa.sa_mask, SIGBUS);
sigaddset(&sa.sa_mask, SIGTERM);
sigaddset(&sa.sa_mask, SIGHUP);
sigaddset(&sa.sa_mask, SIGINT);
sigaddset(&sa.sa_mask, SIGPIPE);
sigaddset(&sa.sa_mask, SIGCHLD);
sigaddset(&sa.sa_mask, SIGALRM);
sigaddset(&sa.sa_mask, SIGUSR1);
sigaddset(&sa.sa_mask, SIGUSR2);
//设置信号处理函数
sa.sa_handler = sigsegv;
sigaction(SIGSEGV, &sa, NULL);
sa.sa_handler = sigbus;
sigaction(SIGBUS, &sa, NULL);
sa.sa_handler = sigterm;
sigaction(SIGTERM, &sa, NULL);
sa.sa_handler = sighup;
sigaction(SIGHUP, &sa, NULL);
sa.sa_handler = sigint;
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = sigchld;
sigaction(SIGCHLD, &sa, NULL);
sa.sa_handler = sigalrm;
sigaction(SIGALRM, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction(SIGUSR1, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction(SIGUSR2, &sa, NULL);
}
完成了信号的设置,离程序真正开始工作又近了一步,下次再接着分析下面几步。