Postfix重要数据结构

argv

字符串数组

  • 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

实现了哈希表的基本增删查改等功能,其binhash_hash函数完成哈希值的计算。

  • BINHASH_INFO结构体实现哈希表节点
  • BINHASH结构体表示哈希表本身
  • 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结构体,用来表示“字典类”。

  • 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

中的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

模块与模块通信,模块与命令行程序通信,模块与文件系统通信。这三种通信方式被封装为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)等信息。

map

字典表

  • MAPS结构体将title和ARGV字段包装成一个字典

    /util/maps.h  
    typedef struct MAPS {  
        char   *title;  
        struct ARGV *argv;  
        int     error;          /* last request only */  
    } MAPS; 
    

MASTER_PROC

  • 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:已完成服务数。

MASTER_SERV

  • 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

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请求。

RECIPIENT

    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

实现了基本的增删查改操作。

  • RING结构体实现双向链表功能

    util/ring.h  
    struct RING {  
        RING   *succ;           /* successor */  
        RING   *pred;           /* predecessor */  
    }; 
    

SMTPD_CMD

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_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

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:读、写、扩容回调函数接口。

VSTREAM

    /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

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  

你可能感兴趣的:(技术。)