1. 写数据的时候为什么要把两边的页保护起来?
p_mmap = vsf_sysutil_map_anon_pages(round_up); // 这里面调用的是mmap 什么时候unmap?
/* Map the first and last page inaccessible */
p_no_access_page = p_mmap + round_up - page_size;
vsf_sysutil_memprotect(p_no_access_page, page_size, kVSFSysUtilMapProtNone);
/* Before we make the "before" page inaccessible, store the size in it.
* A little hack so that we don't need to explicitly be passed the size
* when freeing an existing secure buffer
*/
*((unsigned int*)p_mmap) = round_up;
p_no_access_page = p_mmap;
vsf_sysutil_memprotect(p_no_access_page, page_size, kVSFSysUtilMapProtNone);// 里面调到了mprotect(),参考:Linux中mprotect()函数的用法-CSDN博客
一大片内存中,两边的页不让访问。
2. 一个请求结束的时候怎么处理的?
void vsf_cmdio_write_exit(struct vsf_session* p_sess, int status, const char* p_text,
int exit_val)
{
/* Unblock any readers on the dying control channel. This is needed for SSL
* connections, where the SSL control channel slave is in a separate
* process.
*/
vsf_sysutil_activate_noblock(VSFTP_COMMAND_FD);
vsf_sysutil_shutdown_read_failok(VSFTP_COMMAND_FD);
vsf_cmdio_write(p_sess, status, p_text);
vsf_sysutil_shutdown_failok(VSFTP_COMMAND_FD);
vsf_sysutil_exit(exit_val);
}
3. 各种信号处理
子进程创建之前注册信号:
void vsf_two_process_start(struct vsf_session* p_sess)
{
vsf_sysutil_install_sighandler(kVSFSysUtilSigTERM, handle_sigterm, 0, 1); -----注册SIGTERM信号的处理函数,为什么在这里注册?可以尽早捕获这个消息
/* Overrides the SIGKILL setting set by the standalone listener. */
vsf_set_term_if_parent_dies();
/* Create the comms channel between privileged parent and no-priv child */
priv_sock_init(p_sess);
......
vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0, 1);//这是处理SIGCHLD消息的处理函数。放在这里是因为后面需要创建子进程,子进程一创建就可能会发SIGCHLD消息。必须要在之前注册。
.......
}
handle_sigchld函数中会调用wait或者waitpid 函数来等待子进程结束。
关于vsf_set_term_if_parent_dies();函数
void vsf_set_term_if_parent_dies()
{
#ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
if (prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) != 0)
{
die("prctl");
}
#endif
}
prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) 这个函数的目的是,在得知他的父进程退出时,把父进程的退出信号设置成SIGTERM。很强大把?prctl这个函数还有很多功能,可以查询一下。
子进程创建之前先阻塞SIGCHILD信号,等把必要的动作做完之后再重新注册SIGCHILD信号,也是为了防止产生僵尸进程。
static void common_do_login(struct vsf_session* p_sess, const struct mystr* p_user_str,
int do_chroot, int anon)
{
int was_anon = anon;
const struct mystr* p_orig_user_str = p_user_str;
int newpid;
vsf_sysutil_install_null_sighandler(kVSFSysUtilSigCHLD); //----相当于把SigCHLD信号阻塞,就是暂时不处理子进程状态的变化。等下面的动作完了,再来响应SigCHLD消息
priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
if (!p_sess->control_use_ssl)
{
(void) vsf_sysutil_wait();
}
else
{
p_sess->ssl_slave_active = 1;
}
/* Handle loading per-user config options */
handle_per_user_config(p_user_str);
/* Set this before we fork */
p_sess->is_anonymous = anon;
priv_sock_close(p_sess);
priv_sock_init(p_sess);
vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0, 1);//----重新注册SigCHLD信号
.......