您的位置:首页 > 编程语言 > PHP开发

5.5 smtpd_service函数(smtpd.c):smtp服务回调函数

2016-04-07 13:58 525 查看
我们先来看一下smtpd.c的主函数。其他各个业务模块的主函数结构和这里的main函数结构类似:

/smtpd/smtpd.c
5570 int    main(int argc, char **argv)
5571 {
5572    static const CONFIG_NINT_TABLE nint_table[] = {
5573        VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim,1, 0,
5574        VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim,1, 0,
5575        VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit,1, 0,
5576        VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT,&var_verify_poll_count, 1, 0,
5577        0,
5578    };
5784    single_server_main(argc, argv, smtpd_service,
5785                       CA_MAIL_SERVER_NINT_TABLE(nint_table),
5786                       CA_MAIL_SERVER_INT_TABLE(int_table),
5787                       CA_MAIL_SERVER_STR_TABLE(str_table),
5788                        CA_MAIL_SERVER_RAW_TABLE(raw_table),
5789                       CA_MAIL_SERVER_BOOL_TABLE(bool_table),
5790                       CA_MAIL_SERVER_NBOOL_TABLE(nbool_table),
5791                       CA_MAIL_SERVER_TIME_TABLE(time_table),
5792                        CA_MAIL_SERVER_PRE_INIT(pre_jail_init),
5793                       CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
5794                       CA_MAIL_SERVER_POST_INIT(post_jail_init),
5795                        0);
5796 }


5572 从5572-5784的200多行均为参数初始化部分。以5573行为例,该行初始化了参数smtpd_soft_error_limit(VAR_SMTPD_SOFT_ERLIM),初始值为10(DEF_SMTPD_SOFT_ERLIM),将该初值记录在变量var_smtpd_soft_erlim中,取值范围为1到无穷。

5748 该main函数以single_server.c中的single_server_main为模板,回调函数为smtpd_service。

5785-5794 除了传入smtpd_service回调函数,业务模块还会向3.4中的模板传入其他函数执行,典型的如pre_jail_init,post_jail_init等,用来初始化变量。见4.4节。

下面我们来看回调函数smtpd_service

/smtpd/smtpd.c

5203 /*smtpd_service - service one client */

5204

5205 static voidsmtpd_service(VSTREAM *stream, char *service, char **argv)

5206 {

smtpd_service的stream参数,或者为网络流,或者为标准输入流,在single_server.c中已经设置好。

5207     SMTPD_STATE state;
5208
5209     /*
5210      * Sanity check. This service takes nocommand-line arguments.
5211      */
5212     if (argv[0])
5213         msg_fatal("unexpectedcommand-line argument: %s", argv[0]);
5214
5215     /*
5216      * For sanity, require that at least oneof INET or INET6 is enabled.
5217      * Otherwise, we can't look up interfaceinformation, and we can't
5218      * convert names or addresses.
5219      */
5220     if (SMTPD_STAND_ALONE_STREAM(stream) == 0
5221         &&inet_proto_info()->ai_family_list[0] == 0)
5222         msg_fatal("all network protocolsare disabled (%s = %s)",
5223                   VAR_INET_PROTOCOLS,var_inet_protocols);


5220-5223 对于非stand-alone模式下的服务器,要确保可以得到当前支持的网络协议:

SMTPD_STAND_ALONE_STREAM宏定义如下:

/*
*If running in stand-alone mode, do not try to talk to Postfix daemons but
*write to queue file instead.
*/
#defineSMTPD_STAND_ALONE_STREAM(stream) \
(stream== VSTREAM_IN && getuid() != var_owner_uid)


inet_proto_info()返回3.2.7节的INET_PROTO_INFO结构体。

5224
5225     /*
5226      * This routine runs when a client hasconnected to our network port, or
5227      * when the smtp server is run instand-alone mode (input from pipe).
5228      *
5229      * Look up and sanitize the peer name,then initialize some connection-
5230      * specific state. When the name serviceis hosed, hostname lookup will
5231      * take a while. This is why I always runa local name server on critical
5232      * machines.
5233      */
5234     smtpd_state_init(&state, stream,service);


5234 使用smtpd_state_init函数初始化SMTPD_STATE结构体,大多数字段会被初始化为0,以下字段会被设置初值:

state->service= mystrdup(service);

设置服务名。

state->notify_mask= name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
var_notify_classes);

设置出错通知掩码位。

state->protocol =mystrdup(MAIL_PROTO_SMTP);
先初始化为smtp协议,在解析过程中可能会修改(见5.6.2)。
state->where= SMTPD_AFTER_CONNECT;

记录当前协议解析进行到哪一步,有如下选择:

/*
* Conversation stages.  This is used for "lost connection afterXXX"
*diagnostics.
*/
#defineSMTPD_AFTER_CONNECT "CONNECT"
#defineSMTPD_AFTER_DATA "DATA content"
#defineSMTPD_AFTER_DOT            "END-OF-MESSAGE"


smtpd_state_init函数中还运行了smtpd_peer_init函数确定客户端ip地址等信息(通过getpeername函数)。如果来自本地则初始化为“localhost”,取不到相关信息则初始化为“unknow”。这里我们远在HELO/EHLO命令解析函数执行前就通过网络函数取得客户端信息了,所以可以不考虑客户在HELO/EHLO命令中提供的客户信息——在helo_cmd和ehlo_cmd函数中没有相关获取客户端信息的代码。

5235     msg_info("connect from %s",state.namaddr);
5236
5237     /*
5238      * Disable TLS when running in stand-alonemode via "sendmail -bs".
5239      */
5240     if (SMTPD_STAND_ALONE((&state))) {
5241         var_smtpd_use_tls = 0;
5242         var_smtpd_enforce_tls = 0;
5243         var_smtpd_tls_auth_only = 0;
5244     }


5240-5244 在stand-alone模式下关闭TLS:既然不通过网络提供服务,当然也就不需要启动TLS。

5245
5246     /*
5247      * XCLIENT must not override its ownaccess control.
5248      */
5249     xclient_allowed =SMTPD_STAND_ALONE((&state)) == 0 &&
5250         namadr_list_match(xclient_hosts,state.name, state.addr);
5251
5252     /*
5253      * Overriding XFORWARD access controlmakes no sense, either.
5254      */
5255     xforward_allowed =SMTPD_STAND_ALONE((&state)) == 0 &&
5256         namadr_list_match(xforward_hosts,state.name, state.addr);


5246-5256根据当前客户端主机名地址是否在smtpd_authorized_xclient_hosts或smtpd_authorized_xforward_hosts参数中设置xclient_allowed和xforward_allowed。这两个参数定义允许使用xclient和xforward命令的客户端主机名和地址。

5257
5258     /*
5259      * See if we need to turn on verboselogging for this client.
5260      */
5261     debug_peer_check(state.name, state.addr);
5262
5263     /*
5264      * Provide the SMTP service.
5265      */
5266     if ((state.flags & SMTPD_FLAG_HANGUP)== 0)
5267         smtpd_proto(&state);


5266-5267 无错情况下调用smtpd_proto函数进行smtp协议解析。该函数为smtp协议解析的主体。

5268
5269     /*
5270      * After the client has gone away, cleanup whatever we have set up at
5271      * connection time.
5272      */
5273     msg_info("disconnect from %s%s",state.namaddr,
5274             smtpd_format_cmd_stats(state.buffer));
5275     smtpd_state_reset(&state);
5276     debug_peer_restore();
5277 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: