字符串数组
ARGV结构体保存一个字符串数组
/util/argv.h
typedef struct ARGV {
ssize_t len; /* number of array elements */
ssize_t argc; /* array elements in use */
char **argv; /* string array */
} ARGV;
实现了哈希表的基本增删查改等功能,其binhash_hash函数完成哈希值的计算。
HTABLE结构体实现了哈希表双向链表(qmgr模块所使用的一系列主要结构体都用HTABLE来存放。)
/util/binhash.h
typedef struct BINHASH_INFO {
void *key; /* lookup key */
ssize_t key_len; /* key length */
void *value; /* associated value */
struct BINHASH_INFO *next; /* colliding entry */
struct BINHASH_INFO *prev; /* colliding entry */
} BINHASH_INFO;
typedef struct BINHASH {
ssize_t size; /* length of entries array */
ssize_t used; /* number of entries in table */
BINHASH_INFO **data; /* entries array, auto-resized */
} BINHASH;
typedef struct HTABLE {
ssize_t size; /* length of entries array */
ssize_t used; /* number of entries in table */
HTABLE_INFO **data; /* entries array, auto-resized */
HTABLE_INFO **seq_bucket; /* current sequence hash bucket */
HTABLE_INFO **seq_element; /* current sequence element */
} HTABLE;
文件中定义了DICT结构体,用来表示“字典类”。
DICT_TCP结构体运用于特定程序dict_tcp.c
/util/dict.h
typedef struct DICT {
char *type; /* for diagnostics */
char *name; /* for diagnostics */
int flags; /* see below */
const char *(*lookup) (struct DICT *, const char *);
int (*update) (struct DICT *, const char *, const char *);
int (*delete) (struct DICT *, const char *);
int (*sequence) (struct DICT *, int, const char **, const char **);
int (*lock) (struct DICT *, int);
void (*close) (struct DICT *);
int lock_type; /* for read/write lock */
int lock_fd; /* for read/write lock */
int stat_fd; /* change detection */
time_t mtime; /* mod time at open */
VSTRING *fold_buf; /* key folding buffer */
DICT_OWNER owner; /* provenance */
int error; /* last operation only */
DICT_JMP_BUF *jbuf; /* exception handling */
struct DICT_UTF8_BACKUP *utf8_backup; /* see below */
} DICT;
typedef struct {
DICT dict; /* generic members */
VSTRING *raw_buf; /* raw I/O buffer */
VSTRING *hex_buf; /* quoted I/O buffer */
VSTREAM *fp; /* I/O stream */
} DICT_TCP;
中的INET_PROTO_INFO结构体的成功初始化是进行网络相关操作的前提。如果该结构体不能成功初始化,说明无法取到任何当前机器支持的网络协议,中断后面的执行流程。
INET_PROTO_INFO结构体用来记录系统所支持的网络协议
/util/inet_proto.h
typedef struct {
unsigned int ai_family; /* PF_UNSPEC, PF_INET, or PF_INET6 */
unsigned int *ai_family_list; /* PF_INET and/or PF_INET6 */
unsigned int *dns_atype_list; /* TAAAA and/or TA */
unsigned char *sa_family_list; /* AF_INET6 and/or AF_INET */
} INET_PROTO_INFO;
模块与模块通信,模块与命令行程序通信,模块与文件系统通信。这三种通信方式被封装为MAIL_STREAM流
struct MAIL_STREAM {
VSTREAM *stream; /* file or pipe or socket */
char *queue; /* (initial) queue name */
char *id; /* queue id */
MAIL_STREAM_FINISH_FN finish; /* finish code */
MAIL_STREAM_CLOSE_FN close; /* close stream */
char *class; /* trigger class */
char *service; /* trigger service */
int mode; /* additional permissions */
#ifdef DELAY_ACTION
int delay; /* deferred delivery */
#endif
struct timeval ctime; /* creation time */
};
MAIL_STREAM流出了要包含“物理”VSTREAM指针(需要最终与文件系统交互的结构体都要包含VSTREAM指针,如qmgr模块的直接与MDA交互的QMGR_ENGRY结构体),还需要提供队列信息(queue,id),使用MAIL_STREAM的模块名(servie)和类型(class)等信息。
字典表
MAPS结构体将title和ARGV字段包装成一个字典
/util/maps.h
typedef struct MAPS {
char *title;
struct ARGV *argv;
int error; /* last request only */
} MAPS;
MASTER_PROC描述一个模块所开启的一个子进程。
一个模块可能开启多个子进程。也即一个模块只有一个MASTER_SERV结构体,但可能有多个MASTER_PROC结构体。这些MASTER_PROC结构体被组织成BINHASH哈希表,MASTER_SERV结构体保有其头指针。
/master/master.h
typedef struct MASTER_PROC {
MASTER_PID pid; /*child process id */
unsigned gen; /*child generation number */
int avail; /* availability */
MASTER_SERV *serv; /*parent linkage */
int use_count; /* number of servicerequests */
} MASTER_PROC;
pid:子进程id。
gen:子进程计数,执行master_spawn时递增。
avail:表示该子进程是否可用,为0或1:
#define MASTER_STAT_TAKEN 0 /*this one is occupied */
#define MASTER_STAT_AVAIL 1 /*this process is idle */
serv:父进程链接。
use_count:已完成服务数。
MSTER_SERV结构体用是master模块的主要结构体,用来描述postfix的各个模块
/master/master.h
typedef struct MASTER_SERV {
int flags; /* status, features, etc. */
char *ext_name; /* service endpointname (master.cf) */
char *name; /* service endpointname (canonical) */
int type; /* UNIX-domain, INET, etc.*/
time_t busy_warn_time; /* limit "all serversbusy" warning */
int wakeup_time; /* wakeup interval */
int *listen_fd; /* incoming requests */
int listen_fd_count; /* nr of descriptors */
union {
struct{
char *port; /* inet listen port*/
struct INET_ADDR_LIST *addr; /* inet listenaddress */
}inet_ep;
#define MASTER_INET_ADDRLIST(s) ((s)->endpoint.inet_ep.addr)
#define MASTER_INET_PORT(s) ((s)->endpoint.inet_ep.port)
}endpoint;
int max_proc; /* upper bound on # processes*/
char *path; /* command pathname*/
struct ARGV *args; /*argument vector */
char *stress_param_val; /* stress value: "yes" orempty */
time_t stress_expire_time; /* stress pulse stretcher */
int avail_proc; /* idle processes */
int total_proc; /* number ofprocesses */
int throttle_delay; /* failure recovery parameter */
int status_fd[2]; /* child status reports */
struct BINHASH *children; /*linkage */
struct MASTER_SERV *next; /*linkage */
} MASTER_SERV;
flags 状态标志。
ext_name master.cf中记录的模块名。
name 服务名。
type 模块服务类型,即inet,fifo,或unix。与master.cf中定义的一致。
busy_warn_time:繁忙警告时间。
wakeup_time:唤醒时间,即master.cf中的唤醒时间。
listen_fd:监听的文件描述符数组指针。
listen_fd_count:listen_fd个数,在MASTER_SERV结构体初始化时候确定,对于unix域协议和fifo管道为1,对于inet由master.cf配置文件中的配置决定。
max_proc:最大进程数,即master.cf中的最大进程数。
path:启动服务的命令路径,即master.cf中的command选项。
args:参数数组指针,即master.cf中的args选项。
stress_param_val:表示模块是否满负荷运行,其值为“yes”或空。业务模块满负荷运转时,master模块重启该模块,并加上“stress=yes”命令行选项,此时stress_param_val为yes。非满负荷运转stress_param_val为空。
avail_proc:可用进程数。
tota_proc:当前总进程数。
throttle_delay:当模块当前无法创建子进程时,flags会设置MASTER_FLAG_THROTTLE标志,throttle_delay就是这个标志的保留时间:serv->flags |= MASTER_FLAG_THROTTLE;
status_fd:汇报子进程状态的管道。master模块要用到3组管道,这里的status_fd用来汇报子进程状态。在/master/master_status.c/master_status_init中构建,另外的两组管道是master_sig_pipe和master_flow_pipe,分别用来报告信号和收信速度。在/master/master_sig.c/master_sigsetup函数和/master/master_flow.c/master_flow_init函数中被初始化。
children: 用BINHASH哈希链表来记录和管理各个子进程信息。
next:组织MASTER_SERV链表。
QMGR_MESSAGE:记录一封邮件的信息
struct QMGR_MESSAGE {
int flags; /* delivery problems */
int qflags; /* queuing flags */
int tflags; /* tracing flags */
long tflags_offset; /* offset for killing */
int rflags; /* queue file readflags */
VSTREAM *fp; /* open queue file or null */
int refcount; /* queue entries */
int single_rcpt; /* send one rcpt at a time */
struct timeval arrival_time; /*start of receive transaction */
time_t create_time; /* queue file create time */
struct timeval active_time; /* time of entry into active queue*/
time_t queued_time; /* sanitized time when moved to the * active queue */
time_t refill_time; /* sanitized time of lastmessage * refill */
long warn_offset; /* warning bounce flag offset */
time_t warn_time; /* time next warningto be sent */
long data_offset; /* data seek offset */
char *queue_name; /* queue name */
char *queue_id; /* queue file */
char *encoding; /* content encoding */
char *sender; /* complete address */
char *dsn_envid; /* DSN envelope ID */
int dsn_ret; /* DSN headers/full */
int smtputf8; /* requires unicode */
char *verp_delims; /* VERP delimiters */
char *filter_xport; /* filtering transport */
char *inspect_xport; /* inspecting transport */
char *redirect_addr; /* [email protected] */
long data_size; /* data segment size*/
long cont_length; /* message content length */
long rcpt_offset; /* more recipients here */
char *client_name; /* client hostname */
char *client_addr; /* client address */
char *client_port; /* client port */
char *client_proto; /* client protocol */
char *client_helo; /* helo parameter */
char *sasl_method; /* SASL method */
char *sasl_username; /* SASL user name */
char *sasl_sender; /* SASL sender */
char *log_ident; /* up-stream queue ID */
char *rewrite_context; /* address qualification */
RECIPIENT_LIST rcpt_list; /*complete addresses */
int rcpt_count; /* used recipientslots */
int rcpt_limit; /* maximum read in-core */
int rcpt_unread; /* # of recipients left in queuefile */
QMGR_JOB_LIST job_list; /* jobs delivering this message (1 * per transport) */
};
flags:表示邮件发送状态,有如下几种状态:
#define DELIVER_STAT_OK 0 /*all recipients delivered */
#define DELIVER_STAT_DEFER 1 /*try some recipients later */
#define DELIVER_STAT_CRASH 2 /*mailer internal problem */
queue_time:记录该邮件被放入active队列的时间:
message->queued_time = sane_time();
create_time:记录邮件被放入队列中的时间。
single_rcpt:表示对同域收件人是否要求每个收件人地址单独发送RCPT请求。
typedef struct RECIPIENT_LIST {
RECIPIENT *info;
int len;
int avail;
int variant;
} RECIPIENT_LIST;
typedef struct RECIPIENT {
long offset; /* REC_TYPE_RCPT byte*/
const char *dsn_orcpt; /* DSN original recipient */
int dsn_notify; /* DSN notify flags*/
const char *orig_addr; /* null or original recipient */
const char *address; /* complete address */
union { /* Application specific. */
int status; /* SMTP client */
structQMGR_QUEUE *queue; /* Queue manager*/
constchar *addr_type; /* DSN */
}u;
} RECIPIENT;
需要注意的是RECIPIENT结构体可以通过queue字段找到其所在的域信息。
实现了基本的增删查改操作。
RING结构体实现双向链表功能
util/ring.h
struct RING {
RING *succ; /* successor */
RING *pred; /* predecessor */
};
smtpd模块使用SMTPD_CMD结构体表示一条smtp命令:
/smtpd/smtpd.c
/*
*The table of all SMTP commands that we know. Set the junk limit flag on
*any command that can be repeated an arbitrary number of times without
*triggering a tarpit delay of some sort.
*/
typedef struct SMTPD_CMD {
char *name;
int (*action) (SMTPD_STATE *,int, SMTPD_TOKEN *);
int flags;
int success_count;
int total_count;
} SMTPD_CMD;
name:命令名。
action:命令回调函数。
flags:状态标志,有如下几种:
#define SMTPD_CMD_FLAG_LIMIT (1<<0) /* limit usage */
#define SMTPD_CMD_FLAG_PRE_TLS (1<<1) /*allow before STARTTLS */
该命令可在STARTTLS命令前执行。
#define SMTPD_CMD_FLAG_LAST (1<<2) /*last in PIPELINING command group */
该命令可作为命令流中的最后命令,即命令EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP(见1.5.1RFC2920的规定)。
success_count:成功执行次数。
total_count:总执行次数。
SMTPD_STATE是smtpd模块的核心结构体
typedef struct {
int flags; /* see below */
int err; /* cleanup server/queue file errors */
VSTREAM *client; /* SMTP client handle */
VSTRING *buffer; /* SMTP client buffer */
VSTRING *addr_buf; /* internalized address buffer */
char *service; /* for event rate control */
struct timeval arrival_time; /* start of MAIL FROM transaction */
char *name; /* verified client hostname */
char *reverse_name; /* unverified client hostname */
char *addr; /* client host address string */
char *port; /* port for logging */
char *namaddr; /* name[address]:port */
char *rfc_addr; /* address for RFC 2821 */
int addr_family; /* address family */
char *dest_addr; /* for Dovecot AUTH */
struct sockaddr_storage sockaddr; /* binary client endpoint */
SOCKADDR_SIZE sockaddr_len; /* binary client endpoint */
int name_status; /* 2=ok 4=soft 5=hard 6=forged */
int reverse_name_status; /* 2=ok 4=soft 5=hard */
int conn_count; /* connections from this client */
int conn_rate; /* connection rate for this client */
int error_count; /* reset after DOT */
int error_mask; /* client errors */
int notify_mask; /* what to report to postmaster */
char *helo_name; /* client HELO/EHLO argument */
char *queue_id; /* from cleanup server/queue file */
VSTREAM *cleanup; /* cleanup server/queue file handle */
MAIL_STREAM *dest; /* another server/file handle */
int rcpt_count; /* number of accepted recipients */
char *access_denied; /* fixme */
ARGV *history; /* protocol transcript */
char *reason; /* cause of connection loss */
char *sender; /* sender address */
char *encoding; /* owned by mail_cmd() */
char *verp_delims; /* owned by mail_cmd() */
char *recipient; /* recipient address */
char *etrn_name; /* client ETRN argument */
char *protocol; /* SMTP or ESMTP */
char *where; /* protocol stage */
int recursion; /* Kellerspeicherpegelanzeiger */
off_t msg_size; /* MAIL FROM message size */
off_t act_size; /* END-OF-DATA message size */
int junk_cmds; /* counter */
int rcpt_overshoot; /* counter */
char *rewrite_context; /* address rewriting context */
/*
* SASL specific.
*/
#ifdef USE_SASL_AUTH
struct XSASL_SERVER *sasl_server;
VSTRING *sasl_reply;
char *sasl_mechanism_list;
char *sasl_method;
char *sasl_username;
char *sasl_sender;
#endif
/*
* Specific to smtpd access checks.
*/
int sender_rcptmap_checked; /* sender validated against maps */
int recipient_rcptmap_checked; /* recipient validated against maps */
int warn_if_reject; /* force reject into warning */
SMTPD_DEFER defer_if_reject; /* force reject into deferral */
SMTPD_DEFER defer_if_permit; /* force permit into deferral */
int defer_if_permit_client; /* force permit into warning */
int defer_if_permit_helo; /* force permit into warning */
int defer_if_permit_sender; /* force permit into warning */
int discard; /* discard message */
char *saved_filter; /* postponed filter action */
char *saved_redirect; /* postponed redirect action */
char *saved_bcc; /* postponed bcc action */
int saved_flags; /* postponed hold/discard */
#ifdef DELAY_ACTION
int saved_delay; /* postponed deferred delay */
#endif
VSTRING *expand_buf; /* scratch space for $name expansion */
ARGV *prepend; /* prepended headers */
VSTRING *instance; /* policy query correlation */
int seqno; /* policy query correlation */
int ehlo_discard_mask; /* suppressed EHLO features */
char *dsn_envid; /* temporary MAIL FROM state */
int dsn_ret; /* temporary MAIL FROM state */
VSTRING *dsn_buf; /* scratch space for xtext expansion */
VSTRING *dsn_orcpt_buf; /* scratch space for ORCPT parsing */
/*
* Pass-through proxy client.
*/
struct SMTPD_PROXY *proxy;
char *proxy_mail; /* owned by mail_cmd() */
/*
* XFORWARD server state.
*/
SMTPD_XFORWARD_ATTR xforward; /* up-stream logging info */
/*
* TLS related state.
*/
#ifdef USE_TLS
#ifdef USE_TLSPROXY
VSTREAM *tlsproxy; /* tlsproxy(8) temp. handle */
#endif
TLS_SESS_STATE *tls_context; /* TLS session state */
#endif
/*
* Milter support.
*/
const char **milter_argv; /* SMTP command vector */
ssize_t milter_argc; /* SMTP command vector */
const char *milter_reject_text; /* input to call-back from Milter */
/*
* EHLO temporary space.
*/
VSTRING *ehlo_buf;
ARGV *ehlo_argv;
} SMTPD_STATE;
client:网络或标准输入流。
buffer:内容缓存。
addr_buf:地址缓存,缓存处理过程中的收件人和发件人地址,该缓存地址最终会被写入收件人或发件人字段:
state->sender= mystrdup(STR(state->addr\_buf));
service:anvil模块使用的服务名。
arrival_time:MAIL命令处理函数mail_cmd中记录的MAIL命令处理时间:GETTIMEOFDAY(&state->arrival_time);宏GETTIMEOFDAY即函数gettimeofday。
name:客户端主机名,客户端主机名通过HELO/EHLO命令得到。如果无法得到,则置为unknow:
state->name= mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name= mystrdup(CLIENT_NAME_UNKNOWN);
如果是非网络客户,则置为localhost:
/*
* If it's not Internet, assume the client is local, and avoid using the
* naming service because that can hang when the machine is disconnected.
*/
state->name= mystrdup("localhost");
state->reverse_name= mystrdup("localhost");
addr:客户端地址
port:客户端端口
namaddr:name[address]:port
conn_count:客户端连接数
conn_rate:客户端连接频率
error_count:错误统计
notify_mask:notify_class参数信息掩码。该参数记录将发给postmaster邮件管理员的错误信息。
helo_name:helo/ehlo命令参数值。
queue_id:队列id:
state->queue_id= mystrdup(state->dest->id);
cleanup:和cleanup模块通信的流:
state->cleanup= state->dest->stream;
dest:和cleanup模块通信的MAIL_STREAM流:
state->dest= mail_stream_service(MAIL_CLASS_PUBLIC,var_cleanup_service);
rcpt_count:收信地址数。
history:命令历史记录。在smtpd_chat_query和smtpd_chat_replay函数中通过smtp_chat_append函数记录,也即每当从客户端读取到信息或向客户端发送信息后,都要做历史记录:
argv_add(state->history,line, (char *) 0);
sender:发件人地址
encoding:在mail_cmd命令解析函数中记录MAIL命令的BODY扩展参数的值
verp_delims:如果mail_cmd命令有XVERP扩展参数,该值置为1
recipient:收件人地址
etrn_name:ETRN命令参数值。当服务器由于网络原因累积大量无法发送的邮件时,由flush模块记录各网域累积邮件列表,ETRN命令可以快速清空队列中的邮件。
protocol:协议名,SMTP或ESMTP。
where:在smtp协议解析个阶段记录当前的解析阶段。
msg_size:MAIL命令传入的SIZE参数的值。
act_size:data命令传入的一行邮件信息的大小。
junk_cmds:NOOP、VRFY、ETRN、RSET命令数统计。
rcpt_overshoot:smtpd_recipient_overshoot_limit参数值。
rewrite_context:trivial-rewrite模块使用,值为local或remote。
sender_rcptmap_checked:saved_flags相关字段,为smtpd acl所使用。
expand_buf:指令是否符合流水线规则的判断而开辟的空间。
dsn_envid:临时邮件状态
dsn_ret:临时邮件状态
dsn_buf:xtext扩展的空白空间
dsn_orcpt_buf:用于ORCPT解析的空白空间
记录dsn扩展参数相关信息。dsn扩展参数有RET,ENVID,NOTIFY,ORCPT四个
VBUF结构体是VSTRING和VSTREAM的基石
struct VBUF {
int flags; /* status, see below */
unsigned char *data; /*variable-length buffer */
ssize_t len; /*buffer length */
ssize_t cnt; /*bytes left to read/write */
unsigned char *ptr; /*read/write position */
VBUF_GET_READY_FN get_ready; /*read buffer empty action */
VBUF_PUT_READY_FN put_ready; /*write buffer full action */
VBUF_SPACE_FN space; /*request for buffer space */
};
flags:错误信息标志。
data :内容指针。
len :缓冲区长度。
cnt :剩余读写数据量。
ptr:读写位置指针。
get_ready、pu\t_ready,space:读、写、扩容回调函数接口。
/util/vstream.h
typedef struct VSTREAM {
VBUF buf; /* generic intelligentbuffer */
int fd; /* file handle, no 256 limit */
VSTREAM_RW_FN read_fn; /*buffer fill action */
VSTREAM_RW_FN write_fn; /*buffer fill action */
ssize_t req_bufsize; /*requested read/write buffer size */
void *context; /* application context */
off_t offset; /* cached seek info*/
char *path; /* give it at leasttry */
int read_fd; /* read channel(double-buffered) */
int write_fd; /* write channel(double-buffered) */
VBUF read_buf; /* read buffer(double-buffered) */
VBUF write_buf; /* write buffer(double-buffered) */
pid_t pid; /* vstream_popen/close()*/
VSTREAM_WAITPID_FN waitpid_fn; /*vstream_popen/close() */
int timeout; /* read/write timout */
VSTREAM_JMP_BUF *jbuf; /*exception handling */
struct timeval iotime; /*time of last fill/flush */
struct timeval time_limit; /*read/write time limit */
} VSTREAM;
VSTREAM结构体共定义了3个VBUF缓冲区和两个回调函数接口。
VSTREAM封装比较特殊的是postfix根据自身需要定义的timeout和jbuf字段。imeout字段定义流操作的超时值,比如需要为smtp会话设置超时。postfix用sigsetjmp来做异常处理。VSTREAM_JMP_BUF即jmp_buf或sigjmp_buf:
#ifdef NO_SIGSETJMP
#define VSTREAM_JMP_BUF jmp_buf
#else
#define VSTREAM_JMP_BUF sigjmp_buf
#endif
VSTRING封装VBUF结构体,加上了最大长度限制字段。
typedef struct VSTRING {
VBUF vbuf;
ssize_t maxlen;
} VSTRING;
record.c将文本信息编码为如下格式:
一个字节类型码 + 一个或多个字节的长度码 + 长度码指定长度的文本信息
这种“二进制”编码方式被用来在postfix模块间传递信息。postfix用该格式在smtpd模块和cleanup模块,cleanup模块和qmgr模块间传递邮件信息。
#define REC_TYPE_FROM 'S' /* sender, required */
#define REC_TYPE_RCPT 'R' /* todo recipient, optional */
#define REC_TYPE_CONT 'L' /* long data record */
#define REC_TYPE_NORM 'N' /* normal data record */
#define REC_TYPE_ATTR 'A' /* named attribute for extensions*/
扩展参数
#define MAIL_ATTR_DSN_ENVID "envelope_id" /* dsn envelope id */
#define MAIL_ATTR_DSN_RET "ret_flags" /* dsn full/headers */
#define MAIL_ATTR_SMTPUTF8 "smtputf8" /* RFC6531 support */
#define MAIL_ATTR_ENCODING "encoding" /* internal encoding */
#define MAIL_ATTR_ENC_8BIT "8bit" /* 8BITMIME equivalent */
#define MAIL_ATTR_ENC_7BIT "7bit" /* 7BIT equivalent */
#define MAIL_ATTR_ENC_NONE "" /* encoding unknown */
#define MAIL_ATTR_DSN_NOTIFY "notify_flags" /* dsn notify flags */
#define MAIL_ATTR_DSN_ORCPT "dsn_orig_rcpt" /* dsn original recipient */
这两种类型与postfix的内容过滤功能有关
#define REC_TYPE_FILT 'L' /* loop filter transport */
#define REC_TYPE_RDR '>' /* redirect target */
record类型的数据主要通过rec_fputs、rec_fprintf等函数传递给下一个模块,此类函数的区别主要在数据格式化形式方面。
事件机制的回调函数类型在event.h中定义:
/util/event.h
typedef void (*EVENT_NOTIFY_FN) (int, void *);
#define EVENT_NOTIFY_TIME_FN EVENT_NOTIFY_FN /* legacy */
#define EVENT_NOTIFY_RDWR_FN EVENT_NOTIFY_FN /* legacy */
event.c将回调函数封装成EVENT_FDTABLE结构体,并在event_init初始化函数中分配EVENT_FDTABLE结构体数组:
/util/event.c
typedef struct EVENT_FDTABLE EVENT_FDTABLE;
struct EVENT_FDTABLE {
EVENT_NOTIFY_RDWR_FN callback; /* 回调函数 */
char *context; /* 挂载回调函数时的上下文(结构体)*/
};
这是一个回调函数和环境的绑定,可以理解为一个“闭包”。
postfix定义了读、写、异常、定时四种事件:
各个类unix系统会提供不同的I/O多路复用系统调用,postfix会根据平台选择合适的I/O多路复用机制:
/util/sys_defs.h
#defineEVENTS_STYLE_SELECT 1 /* Traditional BSD select */
#defineEVENTS_STYLE_KQUEUE 2 /* FreeBSD kqueue */
#defineEVENTS_STYLE_DEVPOLL 3 /* Solaris /dev/poll */
#defineEVENTS_STYLE_EPOLL 4 /* Linux epoll */
/util/sys_defs.h
#ifdefined(LINUX2) || defined(LINUX3)
#ifndefNO_EPOLL
#defineEVENTS_STYLE EVENTS_STYLE_EPOLL /* introduced in 2.5 */
#endif