介绍
通过这个模块可以实现邮件服务器的代理工作,包含smtp、pop3、imap三种邮件协议的支持。相关源代码一共18个。其中每种协议实现用了三 个文件,一共是9个,另外有三个文件作公共的初始化工作,两个用于处理SSL模式、其余三个分别用于处理邮件协议解析、代理服务、核心模块相关代码。其中 每种协议是主模块的一个子模块。
看一个官方提供的配置例子:
mail {
auth_http 192.168.1.44:80/mail/auth.php;
pop3_capabilities "TOP" "USER";
imap_capabilities "IMAP4rev1" "UIDPLUS";
server {
listen 110;
protocol pop3;
proxy on;
}
server {
listen 143;
protocol imap;
proxy on;
}
}
这是一个mail代理服务器的设置,该系统通过本地PHP进行权限认证。这里包含两个协议pop3和imap。主要指令是vlisten和 protocol。pop3_capabilities等是全局的指令。例如pop3_capabilities在 ngx_mail_pop3_commands中定义,imap_capabilities在ngx_mail_imap_commands中定 义,pop3与imap本身是mail的子模块,例如POP3被定义为ngx_mail_pop3_module。auth_http存在于 ngx_mail_auth_http_module模块中对等的commands内,例如还包含auth_http_timeout、 auth_http_header等。server中的指令存在于ngx_mail_core_module中的对等结构 ngx_mail_core_commands内,例如还包含timeout设置等。
简单流程
以下是调用关系图解:
() 表示 直接被调用函数。
<- 表示 在函数内部被赋值的回调函数,并不会在当前函数中立即执行。
[] 表示此处调用的函数的具体化实例之一的名称,也可能还有其它实例。
分析流程
Nginx的所有处理都始于对配置文件的分析,之后依据配置中的server段落中的信息监听服务器端口,等待用户访问。这个模块的入口函数是 ngx_mail_block()函数,用于处理配置文件信息,并建立服务器监听。与其它模块相同,对配置文件的解析是通过nginx的公共函数 ngx_conf_parse(),之后通过ngx_mail_optimize_servers()函数初始化服务器,并监听端口。
在三种协议中我们跟一种协议,其它两种逻辑是一样的,例如我们熟知的pop3协议,ngx_mail_optimize_servers()内部会 调用两个重要函数,一个用于建立监听是一个全局函数ngx_create_listening(),另一个ls->handler被赋值为 ngx_mail_init_connection,这是mail模块连接的初始化函数,这样的函数在http模块中也有,名字都可以猜到叫 ngx_http_init_connection。对于mail中的ngx_mail_init_connection()最主要的工作是初始化日志及 session对象,被调用的函数是ngx_mail_init_session()这个函数是mail模块特有的函数,作为mail协议中的会话保持。
ngx_mail_init_session()函数主要做两个工作,第一个工作是对c->write->handler对象赋值为 ngx_mail_send,作为mail模块对请求的响应处理回调函数,另外一个工作是初始化session。在上面的配置文件中我们看到 protocol命令,实际上每种协议有自己的session初始化函数,因此这里的代码是 cscf->protocol->init_session(s, c);所对应的初始化函数为ngx_mail_pop3_init_session(),这里必须提到另外一个结构体 ngx_mail_protocol_s,定义如下:
struct ngx_mail_protocol_s {
ngx_str_t name;
in_port_t port[4];
ngx_uint_t type;
ngx_mail_init_session_pt init_session;
ngx_mail_init_protocol_pt init_protocol;
ngx_mail_parse_command_pt parse_command;
ngx_mail_auth_state_pt auth_state;
ngx_str_t internal_server_error;
};
说明对协议的操作一共包含四种基础功能,初始化session,初始化协议、解析命令、获取认证状态等。我们以POP3为例,具体的实例化定义为:
static ngx_mail_protocol_t ngx_mail_pop3_protocol = {
ngx_string("pop3"),
{ 110, 995, 0, 0 },
NGX_MAIL_POP3_PROTOCOL,
ngx_mail_pop3_init_session,
ngx_mail_pop3_init_protocol,
ngx_mail_pop3_parse_command,
ngx_mail_pop3_auth_state,
ngx_string("-ERR internal server error" CRLF)
};
因此我们跳到ngx_mail_pop3_init_session()函数,这里我们看到了另外一个重要过程对 c->read->handler的赋值,代码为 c->read->handler = ngx_mail_pop3_init_protocol;当有请求时首先通过init_protocol函数对请求进行处理。如果确认是pop3协议内 容,重指定到ngx_mail_pop3_auth_state()函数继续处理,并由这个函数处理后续内容,直至返回给客户端信息为止,这个函数实际上 对pop3协议内容进行解析。在nginx中多数地方都会有类似的函数定义,例如这里处理mail命令的ngx_mail_read_command() 函数,实际上从缓存中读取内容。
数据结构
1. ngx_mail_listen_t 监听信息结构,其中ctx指向mail的配置文件上下文,其它都是简单结构,例如地址,socket等。
2. ngx_mail_conf_ctx_t 配置文件上下文,就包含两个内容main_conf、srv_conf的指针。
3. ngx_mail_core_main_conf_t 与 ngx_mail_core_srv_conf_t 负责全局指令和srv指令结构。这些结构基本与配置文件的命令一致,例如protocol指的是server{}环境里的protocol命令等。
4. ngx_mail_conf_port_t 端口信息,例如端口号family信息、地址等。
5. ngx_mail_conf_addr_t 地址信息。
6. ngx_mail_port_t 地址信息结构。
Nginx就是对这些结构封装的比较疯狂,剩下的不一一列举。