]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20051103
authorWietse Venema <wietse@porcupine.org>
Thu, 3 Nov 2005 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:31:33 +0000 (06:31 +0000)
96 files changed:
postfix/.indent.pro
postfix/ENHANCED_STATUS_README
postfix/HISTORY
postfix/README_FILES/TLS_README
postfix/RELEASE_NOTES
postfix/conf/access
postfix/conf/header_checks
postfix/html/TLS_README.html
postfix/html/access.5.html
postfix/html/header_checks.5.html
postfix/html/postconf.5.html
postfix/html/smtp-sink.1.html
postfix/html/smtp.8.html
postfix/makedefs
postfix/man/man1/smtp-sink.1
postfix/man/man5/access.5
postfix/man/man5/header_checks.5
postfix/man/man5/postconf.5
postfix/man/man8/smtp.8
postfix/mantools/postlink
postfix/proto/TLS_README.html
postfix/proto/access
postfix/proto/header_checks
postfix/proto/postconf.proto
postfix/src/bounce/Makefile.in
postfix/src/cleanup/Makefile.in
postfix/src/cleanup/cleanup.h
postfix/src/cleanup/cleanup_bounce.c
postfix/src/cleanup/cleanup_out_recipient.c
postfix/src/discard/Makefile.in
postfix/src/discard/discard.c
postfix/src/error/Makefile.in
postfix/src/error/error.c
postfix/src/global/Makefile.in
postfix/src/global/bounce.c
postfix/src/global/bounce.h
postfix/src/global/defer.c
postfix/src/global/defer.h
postfix/src/global/deliver_pass.c
postfix/src/global/deliver_request.c
postfix/src/global/deliver_request.h
postfix/src/global/log_adhoc.c
postfix/src/global/log_adhoc.h
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/msg_stats.h [new file with mode: 0644]
postfix/src/global/msg_stats_print.c [new file with mode: 0644]
postfix/src/global/msg_stats_scan.c [new file with mode: 0644]
postfix/src/global/rcpt_print.c
postfix/src/global/sent.c
postfix/src/global/sent.h
postfix/src/global/trace.c
postfix/src/global/trace.h
postfix/src/global/verify.c
postfix/src/global/verify.h
postfix/src/lmtp/Makefile.in
postfix/src/lmtp/lmtp_proto.c
postfix/src/lmtp/lmtp_rcpt.c
postfix/src/lmtp/lmtp_trouble.c
postfix/src/local/Makefile.in
postfix/src/local/local.c
postfix/src/local/local.h
postfix/src/oqmgr/Makefile.in
postfix/src/oqmgr/qmgr.h
postfix/src/oqmgr/qmgr_bounce.c
postfix/src/oqmgr/qmgr_defer.c
postfix/src/oqmgr/qmgr_deliver.c
postfix/src/oqmgr/qmgr_message.c
postfix/src/pipe/Makefile.in
postfix/src/pipe/pipe.c
postfix/src/qmgr/Makefile.in
postfix/src/qmgr/qmgr.h
postfix/src/qmgr/qmgr_bounce.c
postfix/src/qmgr/qmgr_defer.c
postfix/src/qmgr/qmgr_deliver.c
postfix/src/qmgr/qmgr_message.c
postfix/src/sendmail/Makefile.in
postfix/src/sendmail/sendmail.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_chat.c
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_rcpt.c
postfix/src/smtp/smtp_session.c
postfix/src/smtp/smtp_trouble.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpstone/smtp-sink.c
postfix/src/tls/Makefile.in
postfix/src/util/Makefile.in
postfix/src/util/sys_defs.h
postfix/src/verify/Makefile.in
postfix/src/virtual/Makefile.in
postfix/src/virtual/virtual.c
postfix/src/virtual/virtual.h

index 289be98f6b86b15a0bf51f7e582fe2e278901d72..f55941ec6eff11a779aaf2302fab60f580188777 100644 (file)
 -TMKMAP_DB
 -TMKMAP_DBM
 -TMKMAP_OPEN_INFO
+-TMSG_STATS
 -TMULTI_SERVER
 -TMVECT
 -TMYSQL
index bf0207f62db8fb2a96caa9af3ed2d56139bb7d1e..eaf9435bcc7702c199da999a7b46e5c5cfe78afc 100644 (file)
@@ -40,9 +40,7 @@ update the diagnostic text separately from the enhanced status code.
 performs or prepares for mail delivery. Instead, have that routine
 update the enhanced status code (and text) when the error happens.
 This was an issue with mailbox, maildir and file delivery.  Currently
-there remain two exceptions to this rule: mail_copy() for historical
-reasons may or may not return explicit error reports (fixing this
-requires that pipe_command() be restructured); and the maildir
+there remains one exception to this errno usage rule; the maildir
 delivery routines log a helpful warning when delivery fails with
 EACCES.  The latter happens to work because mbox_open() does not
 need to unlock the output file, so it won't clobber the errno value.
index 523ecbd42ee55b93d1d66c08b2c4f5925425d435..fc583f8ebf5d350ff6e87f7d6021eb3fd8786d90 100644 (file)
@@ -11222,8 +11222,93 @@ Apologies for any names omitted.
        MAIL FROM command.  This protects before-queue content
        filters against over-size messages.  File: smtpd/smtpd.c.
 
+20051017
+
+       Bugfix: after DSN support was added, smtp_skip_5xx_greeting
+       no longer recognized a 5xx SMTP status as a 4xx one. Found
+       by Ralf Hildebrandt. Fix: use the enhanced status code
+       instead of the SMTP reply code to choose between permanent
+       or transient errors. File: smtp/smtp_trouble.c.
+
+       Feature: smtp-sink can hard-reject, soft-reject or simply
+       drop connection requests.  File: smtpstone/smtp-sink.c.
+
+       Documentation: clarified the processing of server replies,
+       specifically the reply code and the enhanced status code,
+       in smtp_chat.c.
+
+20051024
+
+       Performance: new smtp_connection_reuse_time_limit parameter to
+       limit connection reuse by elapsed time, instead of limiting
+       the number of deliveries per connection.  Bounding by time
+       favors delivery over connections that perform well, while
+       bounding by number of deliveries allows slow connections
+       to drag down the performance.  Insight and initial
+       implementation by Victor Duchovni, Morgan Stanley. Files:
+       smtp_connect.c, smtp_session.c,
+
+       Bugfix: the next-hop logical destination information for
+       connection caching was reset only after a good non-TLS
+       connection, so that cached connections to non-TLS backup
+       servers could suck away traffic from TLS primary servers
+       (the Postfix SMTP client cannot cache an open TLS connection).
+       Found during code review. This is fixed with multi-valued
+       connection caching state: expired, cachable, non-cachable,
+       and bad.  Files: smtp_connect.c, smtp_trouble.c.
+
+       Bugfix: adding support for "sendmail -C" broke "sendmail
+       -q".  File: sendmail/sendmail.c.
+
+20051101
+
+       Migration from a single "arrival time" stamp to a structure
+       with time stamps from different stages of message delivery.
+       The first iteration merely replaces "arrival time" stamps
+       by a structure or pointer to structure, and uses only the
+       arrival time field of that structure.  This is an extensive
+       but straightforward transformation, based on example by
+       Victor Duchovni, Morgan Stanley.  Files: anything that
+       invokes bounce_append etc., the log_adhoc module, and
+       anything that sends or receives a delivery request.
+
+20051102
+
+       Completion of support for time stamps from different stages
+       of message delivery. The information is now logged as
+       "delays=a/b/c/d" where a=time before queue manager, b=time
+       in queue manager, c=connection setup time, d=message
+       transmission time. Unlike Victor's example which used time
+       differences, this implementation uses absolute times. The
+       decision of what numbers to subtract actually depends on
+       program history, so we want to do it in one place.  Files:
+       global/log_adhoc.c, smtp/smtp_connect.c, smtp/smtp_proto.c,
+       smtp/smtp_trouble.c, lmtp/lmtp_proto.c, lmtp/lmtp_trouble.c.
+
+20051103
+
+       Refinement of time stamping and delays formatting.  The
+       hand-off time is now stamped in the delivery agent, so that
+       time is properly attributed when a transport is saturated
+       or throttled.  Delays are now logged if larger than 0.01
+       second. Files: *qmgr/qmgr_deliver.c, global/deliver_request.c,
+       global/log_adhoc.c.
+
 Open problems:
 
+       Is it safe to cache a connection after it has been used
+       for more than some number of address verification probes?
+
+       The code in smtp_connect() that catches server reject and
+       disconnect errors has become redundant. Connections that
+       fail before MAIL FROM no longer count towards the MX session
+       count limit per delivery attempt.
+
+       Access map actions such as FILTER and REDIRECT don't work
+       in smtpd_end_of_data_restrictions (or anything else that
+       generates additional queue file records after the message
+       content is stored).
+
        Try to recognize that Resent- headers appear in blocks,
        newest block first. But don't break on incorrect header
        block organization.
index 3c8fbb41ba48cc1b95d29c6ee431e325bd8adc4b..676b4005ad8a5bac6728d1077793604506f53835 100644 (file)
@@ -154,9 +154,9 @@ If you want the Postfix SMTP server to accept remote SMTP client certificates
 issued by these CAs, append the root certificate to $smtpd_tls_CAfile or
 install it in the $smtpd_tls_CApath directory. When you configure trust in a
 root CA, it is not necessary to explicitly trust intermediary CAs signed by the
-root CA, unless $smtpd_tls_verify_depth is less than the number of CAs in the
-certificate chain for the clients of interest. With a verify depth of 1 you can
-only verify certificates directly signed by a trusted CA, and all trusted
+root CA, unless $smtpd_tls_ccert_verifydepth is less than the number of CAs in
+the certificate chain for the clients of interest. With a verify depth of 1 you
+can only verify certificates directly signed by a trusted CA, and all trusted
 intermediary CAs need to be configured explicitly. With a verify depth of 2 you
 can verify clients signed by a root CA or a direct intermediary CA (so long as
 the client is correctly configured to supply its intermediate CA certificate).
@@ -192,7 +192,7 @@ $smtpd_tls_CApath directory needs to be accessible inside the optional chroot
 jail.
 
 When you configure Postfix to request client certificates (by setting
-$smtpd_tls_asck_ccert = yes), any certificates in $smtpd_tls_CAfile are sent to
+$smtpd_tls_ask_ccert = yes), any certificates in $smtpd_tls_CAfile are sent to
 the client, in order to allow it to choose an identity signed by a CA you
 trust. If no $smtpd_tls_CAfile is specified, no preferred CA list is sent, and
 the client is free to choose an identity signed by any CA. Many clients use a
index d6b254f5128f939e08d5e43009e824d4f0c760c7..fa4d681c0b5e7811a042e6154153b4f668e9533b 100644 (file)
@@ -17,6 +17,92 @@ Incompatibility with Postfix 2.1 and earlier
 If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
 before proceeding.
 
+Incompatibility with snapshot 20051103
+======================================
+
+The queue manager protocol has changed. You need to "postfix reload"
+after "make upgrade".
+
+The logging of recipient status information has changed.  This may
+require changes to logfile processing tools.
+
+- Postfix now logs an additional attribute with detailed delay
+information (delays=a/b/c/d) as described below.
+
+- Postfix now logs an additional attribute with the connection reuse
+count (conn_use=nnn) as described below.
+
+Major changes with snapshot 20051103
+====================================
+
+This release makes a beginning with a series of new attributes in
+Postfix logfile records.
+
+- Better insight into the nature of performance bottle necks, with
+detailed logging of delays in various stages of message delivery.
+Postfix logs additional delay information as "delays=a/b/c/d" where
+a=time before queue manager, b=time in queue manager, c=connection
+setup time, d=message transmission time.
+
+- Logging of the connection reuse count when SMTP connections are
+used for more than one message delivery.  This information is needed
+because Postfix can now reuse connections hundreds of times or more,
+and can help to diagnose interoperability problems with servers
+that suffer from memory leaks or other resource leaks.
+
+Incompatibility with snapshot 20051026
+======================================
+
+The connection cache protocol for SMTP connections has changed.
+You need to "postfix reload" after "make upgrade".
+
+The smtp_connection_cache_reuse_limit parameter (which limits the
+number of deliveries per SMTP connection) is replaced by the new
+smtp_connection_reuse_time_limit parameter (the time after which a
+connection is no longer stored into the connection cache).
+
+Major changes with snapshot 20051026
+====================================
+
+This snapshot addresses a performance stability problem with remote
+SMTP servers. The problem is not specific to Postfix: it can happen
+when any MTA sends large amounts of SMTP email to a site that has
+multiple MX hosts. The insight that led to the solution, as well
+as an initial implementation, are due to Victor Duchovni.
+
+The problem starts when one of a set of MX hosts becomes slower
+than the rest.  Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request.
+
+The slow MX host becomes a connection attractor.  If one MX host
+becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts.
+
+The solution uses connection caching in a way that differs from
+Postfix 2.2.  By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want.
+
+The smtp_connection_reuse_time_limit feature implements the connection
+reuse time limit as discussed above.  It limits the amount of time
+after which an SMTP connection is no longer stored into the connection
+cache. The default limit, 300s, can result in a huge number of
+deliveries over a single connection.
+
+This solution will be complete when Postfix logging is updated to
+include information about the number of times that a connection was
+used. This information is needed to diagnose inter-operability
+problems with servers that exhibit bugs when they receive multiple
+messages over the same connection.
+
 Incompatibility with snapshot 20051011
 ======================================
 
index 835fb448e7da36319d750ee69f604e66abd289de..ed1c2e0030f16f8af90285fe416b2b3082f57a73 100644 (file)
 #               erwise log a generic message.
 # 
 #               Note:  this action currently affects all recipients
-#               of the message.
+#               of the message.   To  discard  only  one  recipient
+#               without  discarding  the  entire  message,  use the
+#               transport(5) table to direct mail to the discard(8)
+#               service.
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
-#        DUNNO  Pretend  that  the  lookup  key was not found. This
-#               prevents Postfix  from  trying  substrings  of  the
-#               lookup  key (such as a subdomain name, or a network
+#        DUNNO  Pretend that the lookup key  was  not  found.  This
+#               prevents  Postfix  from  trying  substrings  of the
+#               lookup key (such as a subdomain name, or a  network
 #               address subnetwork).
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        FILTER transport:destination
-#               After  the  message is queued, send the entire mes-
+#               After the message is queued, send the  entire  mes-
 #               sage through the specified external content filter.
-#               The  transport:destination  syntax  is described in
-#               the transport(5)  manual  page.   More  information
-#               about  external  content  filters is in the Postfix
+#               The transport:destination syntax  is  described  in
+#               the  transport(5)  manual  page.   More information
+#               about external content filters is  in  the  Postfix
 #               FILTER_README file.
 # 
-#               Note:  this  action  overrides  the  main.cf   con-
+#               Note:   this  action  overrides  the  main.cf  con-
 #               tent_filter  setting,  and  currently  affects  all
 #               recipients of the message.
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        HOLD optional text...
-#               Place  the message on the hold queue, where it will
-#               sit until someone either deletes it or releases  it
-#               for  delivery.  Log the optional text if specified,
+#               Place the message on the hold queue, where it  will
+#               sit  until someone either deletes it or releases it
+#               for delivery.  Log the optional text if  specified,
 #               otherwise log a generic message.
 # 
-#               Mail that is placed on hold can  be  examined  with
-#               the  postcat(1)  command,  and  can be destroyed or
+#               Mail  that  is  placed on hold can be examined with
+#               the postcat(1) command, and  can  be  destroyed  or
 #               released with the postsuper(1) command.
 # 
-#               Note: use "postsuper -r" to release mail  that  was
-#               kept  on  hold for a significant fraction of $maxi-
+#               Note:  use  "postsuper -r" to release mail that was
+#               kept on hold for a significant fraction  of  $maxi-
 #               mal_queue_lifetime  or  $bounce_queue_lifetime,  or
 #               longer.
 # 
-#               Note:  this action currently affects all recipients
+#               Note: this action currently affects all  recipients
 #               of the message.
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        PREPEND headername: headervalue
-#               Prepend  the  specified  message header to the mes-
+#               Prepend the specified message header  to  the  mes-
 #               sage.  When this action is used multiple times, the
-#               first  prepended  header  appears before the second
+#               first prepended header appears  before  the  second
 #               etc. prepended header.
 # 
-#               Note: this action does not support multi-line  mes-
+#               Note:  this action does not support multi-line mes-
 #               sage headers.
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        REDIRECT user@domain
-#               After the message is queued, send  the  message  to
+#               After  the  message  is queued, send the message to
 #               the  specified  address  instead  of  the  intended
 #               recipient(s).
 # 
-#               Note: this action overrides the FILTER action,  and
+#               Note:  this action overrides the FILTER action, and
 #               currently affects all recipients of the message.
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        WARN optional text...
 #               Log a warning with the optional text, together with
-#               client  information  and  if  available, with helo,
+#               client information and  if  available,  with  helo,
 #               sender, recipient and protocol information.
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
 # ENHANCED STATUS CODES
 #        When an enhanced status code is specified in an access ta-
-#        ble, it is subject to modification. The  following  trans-
-#        formations  are  needed when the same access table is used
-#        for client, helo, sender,  or  recipient  access  restric-
-#        tions;  they  happen regardless of whether Postfix replies
+#        ble,  it  is subject to modification. The following trans-
+#        formations are needed when the same access table  is  used
+#        for  client,  helo,  sender,  or recipient access restric-
+#        tions; they happen regardless of whether  Postfix  replies
 #        to a MAIL FROM, RCPT TO or other SMTP command.
 # 
-#        o      When a sender address matches a REJECT action,  the
-#               Postfix  SMTP server will transform a recipient DSN
-#               status (e.g., 4.1.1-4.1.6) into  the  corresponding
+#        o      When  a sender address matches a REJECT action, the
+#               Postfix SMTP server will transform a recipient  DSN
+#               status  (e.g.,  4.1.1-4.1.6) into the corresponding
 #               sender DSN status, and vice versa.
 # 
-#        o      When   non-address  information  matches  a  REJECT
-#               action (such as the HELO command  argument  or  the
-#               client  hostname/address),  the Postfix SMTP server
-#               will transform a sender  or  recipient  DSN  status
-#               into   a  generic  non-address  DSN  status  (e.g.,
+#        o      When  non-address  information  matches  a   REJECT
+#               action  (such  as  the HELO command argument or the
+#               client hostname/address), the Postfix  SMTP  server
+#               will  transform  a  sender  or recipient DSN status
+#               into  a  generic  non-address  DSN  status   (e.g.,
 #               4.0.0).
 # 
 # REGULAR EXPRESSION TABLES
-#        This section describes how the table lookups  change  when
+#        This  section  describes how the table lookups change when
 #        the table is given in the form of regular expressions. For
-#        a description of regular expression lookup  table  syntax,
+#        a  description  of regular expression lookup table syntax,
 #        see regexp_table(5) or pcre_table(5).
 # 
-#        Each  pattern  is  a regular expression that is applied to
+#        Each pattern is a regular expression that  is  applied  to
 #        the entire string being looked up. Depending on the appli-
-#        cation,  that  string  is  an  entire  client hostname, an
+#        cation, that string  is  an  entire  client  hostname,  an
 #        entire client IP address, or an entire mail address. Thus,
 #        no  parent  domain  or  parent  network  search  is  done,
-#        user@domain mail addresses are not broken  up  into  their
+#        user@domain  mail  addresses  are not broken up into their
 #        user@ and domain constituent parts, nor is user+foo broken
 #        up into user and foo.
 # 
-#        Patterns are applied in the order as specified in the  ta-
-#        ble,  until  a  pattern  is  found that matches the search
+#        Patterns  are applied in the order as specified in the ta-
+#        ble, until a pattern is  found  that  matches  the  search
 #        string.
 # 
-#        Actions are the same as with indexed  file  lookups,  with
-#        the  additional feature that parenthesized substrings from
+#        Actions  are  the  same as with indexed file lookups, with
+#        the additional feature that parenthesized substrings  from
 #        the pattern can be interpolated as $1, $2 and so on.
 # 
 # TCP-BASED TABLES
-#        This section describes how the table lookups  change  when
+#        This  section  describes how the table lookups change when
 #        lookups are directed to a TCP-based server. For a descrip-
 #        tion of the TCP client/server lookup protocol, see tcp_ta-
 #        ble(5).  This feature is not available up to and including
 #        Postfix version 2.2.
 # 
-#        Each lookup operation uses the entire query  string  once.
-#        Depending  on  the  application,  that string is an entire
+#        Each  lookup  operation uses the entire query string once.
+#        Depending on the application, that  string  is  an  entire
 #        client hostname, an entire client IP address, or an entire
-#        mail  address.   Thus,  no parent domain or parent network
-#        search is done, user@domain mail addresses are not  broken
-#        up  into  their user@ and domain constituent parts, nor is
+#        mail address.  Thus, no parent domain  or  parent  network
+#        search  is done, user@domain mail addresses are not broken
+#        up into their user@ and domain constituent parts,  nor  is
 #        user+foo broken up into user and foo.
 # 
 #        Actions are the same as with indexed file lookups.
 # 
 # EXAMPLE
-#        The following example uses an indexed file,  so  that  the
-#        order  of  table entries does not matter. The example per-
-#        mits access by the client at address 1.2.3.4  but  rejects
-#        all  other  clients  in 1.2.3.0/24. Instead of hash lookup
-#        tables, some systems use dbm.  Use the  command  "postconf
-#        -m"  to  find  out  what lookup tables Postfix supports on
+#        The  following  example  uses an indexed file, so that the
+#        order of table entries does not matter. The  example  per-
+#        mits  access  by the client at address 1.2.3.4 but rejects
+#        all other clients in 1.2.3.0/24. Instead  of  hash  lookup
+#        tables,  some  systems use dbm.  Use the command "postconf
+#        -m" to find out what lookup  tables  Postfix  supports  on
 #        your system.
 # 
 #        /etc/postfix/main.cf:
 #        editing the file.
 # 
 # BUGS
-#        The table format does not understand quoting  conventions.
+#        The  table format does not understand quoting conventions.
 # 
 # SEE ALSO
 #        postmap(1), Postfix lookup table manager
 #        transport(5), transport:nexthop syntax
 # 
 # README FILES
-#        Use  "postconf  readme_directory" or "postconf html_direc-
+#        Use "postconf readme_directory" or  "postconf  html_direc-
 #        tory" to locate this information.
 #        SMTPD_ACCESS_README, built-in SMTP server access control
 #        DATABASE_README, Postfix lookup table overview
 # 
 # LICENSE
-#        The Secure Mailer license must be  distributed  with  this
+#        The  Secure  Mailer  license must be distributed with this
 #        software.
 # 
 # AUTHOR(S)
index 0389acf5883f56df4665a9d3e2065d6d4b166468..238599ffd875d9a7c11d5694aa1f0a641d3289c3 100644 (file)
 # 
 #               Note:   this  action  disables  further  header  or
 #               body_checks inspection of the current  message  and
-#               affects all recipients.
+#               affects all recipients.  To discard only one recip-
+#               ient without discarding the entire message, use the
+#               transport(5) table to direct mail to the discard(8)
+#               service.
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
-#        DUNNO  Pretend that the input line did not match any  pat-
-#               tern,  and inspect the next input line. This action
+#        DUNNO  Pretend  that the input line did not match any pat-
+#               tern, and inspect the next input line. This  action
 #               can be used to shorten the table search.
 # 
-#               For backwards compatibility reasons,  Postfix  also
-#               accepts  OK but it is (and always has been) treated
+#               For  backwards  compatibility reasons, Postfix also
+#               accepts OK but it is (and always has been)  treated
 #               as DUNNO.
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        FILTER transport:destination
-#               Write  a  content  filter request to the queue file
-#               and inspect the next input line.   After  the  com-
-#               plete  message  is received it will be sent through
+#               Write a content filter request to  the  queue  file
+#               and  inspect  the  next input line.  After the com-
+#               plete message is received it will be  sent  through
 #               the specified external content filter.  More infor-
-#               mation  about  external  content  filters is in the
+#               mation about external content  filters  is  in  the
 #               Postfix FILTER_README file.
 # 
-#               Note:  this  action  overrides  the  main.cf   con-
-#               tent_filter  setting, and affects all recipients of
-#               the message.  In  the  case  that  multiple  FILTER
+#               Note:   this  action  overrides  the  main.cf  con-
+#               tent_filter setting, and affects all recipients  of
+#               the  message.  In  the  case  that  multiple FILTER
 #               actions fire, only the last one is executed.
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
 #        HOLD optional text...
-#               Arrange for the message to be placed  on  the  hold
-#               queue,  and  inspect the next input line.  The mes-
-#               sage remains on hold until someone  either  deletes
-#               it  or  releases it for delivery.  Log the optional
+#               Arrange  for  the  message to be placed on the hold
+#               queue, and inspect the next input line.   The  mes-
+#               sage  remains  on hold until someone either deletes
+#               it or releases it for delivery.  Log  the  optional
 #               text if specified, otherwise log a generic message.
 # 
-#               Mail  that  is  placed on hold can be examined with
-#               the postcat(1) command, and  can  be  destroyed  or
+#               Mail that is placed on hold can  be  examined  with
+#               the  postcat(1)  command,  and  can be destroyed or
 #               released with the postsuper(1) command.
 # 
-#               Note:  use  "postsuper -r" to release mail that was
-#               kept on hold for a significant fraction  of  $maxi-
+#               Note: use "postsuper -r" to release mail  that  was
+#               kept  on  hold for a significant fraction of $maxi-
 #               mal_queue_lifetime  or  $bounce_queue_lifetime,  or
 #               longer.
 # 
-#               Note: this action affects  all  recipients  of  the
+#               Note:  this  action  affects  all recipients of the
 #               message.
 # 
 #               This feature is available in Postfix 2.0 and later.
 # 
-#        IGNORE Delete the current line from the input and  inspect
+#        IGNORE Delete  the current line from the input and inspect
 #               the next input line.
 # 
 #        PREPEND text...
 # 
 #               Notes:
 # 
-#               o      The prepended text is output on  a  separate
+#               o      The  prepended  text is output on a separate
 #                      line,  immediately  before  the  input  that
 #                      triggered the PREPEND action.
 # 
 #               o      The prepended text is not considered part of
-#                      the  input  stream:  it  is  not  subject to
+#                      the input  stream:  it  is  not  subject  to
 #                      header/body checks or address rewriting, and
 #                      it does not affect the way that Postfix adds
 #                      missing message headers.
 # 
 #               o      When prepending text before a message header
-#                      line,  the  prepended text must begin with a
+#                      line, the prepended text must begin  with  a
 #                      valid message header label.
 # 
 #               o      This action cannot be used to prepend multi-
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        REDIRECT user@domain
-#               Write a message redirection request  to  the  queue
-#               file  and  inspect  the  next input line. After the
+#               Write  a  message  redirection request to the queue
+#               file and inspect the next  input  line.  After  the
 #               message is queued, it will be sent to the specified
 #               address instead of the intended recipient(s).
 # 
-#               Note:  this action overrides the FILTER action, and
-#               affects all recipients of the message. If  multiple
-#               REDIRECT  actions  fire,  only the last one is exe-
+#               Note: this action overrides the FILTER action,  and
+#               affects  all recipients of the message. If multiple
+#               REDIRECT actions fire, only the last  one  is  exe-
 #               cuted.
 # 
 #               This feature is available in Postfix 2.1 and later.
 # 
 #        REPLACE text...
-#               Replace  the  current  line with the specified text
+#               Replace the current line with  the  specified  text
 #               and inspect the next input line.
 # 
 #               This feature is available in Postfix 2.2 and later.
-#               The  description below applies to Postfix 2.2.2 and
+#               The description below applies to Postfix 2.2.2  and
 #               later.
 # 
 #               Notes:
 # 
-#               o      When replacing a message  header  line,  the
-#                      replacement  text  must  begin  with a valid
+#               o      When  replacing  a  message header line, the
+#                      replacement text must  begin  with  a  valid
 #                      header label.
 # 
-#               o      The replaced text remains part of the  input
-#                      stream.  Unlike  the result from the PREPEND
-#                      action, a replaced  message  header  may  be
-#                      subject  to address rewriting and may affect
-#                      the way that Postfix  adds  missing  message
+#               o      The  replaced text remains part of the input
+#                      stream. Unlike the result from  the  PREPEND
+#                      action,  a  replaced  message  header may be
+#                      subject to address rewriting and may  affect
+#                      the  way  that  Postfix adds missing message
 #                      headers.
 # 
 #        REJECT optional text...
-#               Reject  the  entire  message.  Reply  with optional
+#               Reject the  entire  message.  Reply  with  optional
 #               text... when the optional text is specified, other-
 #               wise reply with a generic error message.
 # 
-#               Note:   this  action  disables  further  header  or
-#               body_checks inspection of the current  message  and
+#               Note:  this  action  disables  further  header   or
+#               body_checks  inspection  of the current message and
 #               affects all recipients.
 # 
 #               Postfix version 2.3 and later support enhanced sta-
 #               enhanced status code of "5.7.1".
 # 
 #        WARN optional text...
-#               Log a warning with the optional text... (or  log  a
-#               generic  message)  and inspect the next input line.
+#               Log  a  warning with the optional text... (or log a
+#               generic message) and inspect the next  input  line.
 #               This action is useful for debugging and for testing
 #               a pattern before applying more drastic actions.
 # 
 # BUGS
-#        Many  people  overlook  the main limitations of header and
-#        body_checks rules.  These rules  operate  on  one  logical
-#        message  header or one body line at a time, and a decision
-#        made for one line is not carried over to  the  next  line.
+#        Many people overlook the main limitations  of  header  and
+#        body_checks  rules.   These  rules  operate on one logical
+#        message header or one body line at a time, and a  decision
+#        made  for  one  line is not carried over to the next line.
 #        If text in the message body is encoded (RFC 2045) then the
-#        rules have to specified for the encoded  form.   Likewise,
+#        rules  have  to specified for the encoded form.  Likewise,
 #        when message headers are encoded (RFC 2047) then the rules
 #        need to be specified for the encoded form.
 # 
-#        Message headers added by the cleanup(8) daemon itself  are
+#        Message  headers added by the cleanup(8) daemon itself are
 #        excluded from inspection. Examples of such message headers
 #        are From:, To:, Message-ID:, Date:.
 # 
-#        Message headers deleted by the cleanup(8) daemon  will  be
+#        Message  headers  deleted by the cleanup(8) daemon will be
 #        examined before they are deleted. Examples are: Bcc:, Con-
 #        tent-Length:, Return-Path:.
 # 
 #        body_checks
 #               Lookup tables with content filter rules for message
 #               body lines.  These filters see one physical line at
-#               a time, in chunks  of  at  most  $line_length_limit
+#               a  time,  in  chunks  of at most $line_length_limit
 #               bytes.
 # 
 #        body_checks_size_limit
-#               The  amount  of  content  per  message body segment
+#               The amount of  content  per  message  body  segment
 #               (attachment) that is subjected to $body_checks fil-
 #               tering.
 # 
 # 
 #        nested_header_checks (default: $header_checks)
 #               Lookup tables with content filter rules for message
-#               header lines: respectively, these  are  applied  to
-#               the  initial  message  headers  (not including MIME
-#               headers), to the MIME headers anywhere in the  mes-
-#               sage,  and  to the initial headers of attached mes-
+#               header  lines:  respectively,  these are applied to
+#               the initial message  headers  (not  including  MIME
+#               headers),  to the MIME headers anywhere in the mes-
+#               sage, and to the initial headers of  attached  mes-
 #               sages.
 # 
-#               Note: these filters see one logical message  header
-#               at  a time, even when a message header spans multi-
-#               ple lines. Message headers  that  are  longer  than
+#               Note:  these filters see one logical message header
+#               at a time, even when a message header spans  multi-
+#               ple  lines.  Message  headers  that are longer than
 #               $header_size_limit characters are truncated.
 # 
 #        disable_mime_input_processing
-#               While  receiving mail, give no special treatment to
-#               MIME related message headers; all  text  after  the
+#               While receiving mail, give no special treatment  to
+#               MIME  related  message  headers; all text after the
 #               initial message headers is considered to be part of
-#               the message body. This means that header_checks  is
-#               applied  to  all  the  initial message headers, and
+#               the  message body. This means that header_checks is
+#               applied to all the  initial  message  headers,  and
 #               that body_checks is applied to the remainder of the
 #               message.
 # 
-#               Note:  when  used  in this manner, body_checks will
-#               process a multi-line message header one line  at  a
+#               Note: when used in this  manner,  body_checks  will
+#               process  a  multi-line message header one line at a
 #               time.
 # 
 # EXAMPLES
-#        Header  pattern  to  block  attachments with bad file name
+#        Header pattern to block attachments  with  bad  file  name
 #        extensions.
 # 
 #        /etc/postfix/main.cf:
 #        RFC 2047, message header encoding for non-ASCII text
 # 
 # README FILES
-#        Use  "postconf  readme_directory" or "postconf html_direc-
+#        Use "postconf readme_directory" or  "postconf  html_direc-
 #        tory" to locate this information.
 #        DATABASE_README, Postfix lookup table overview
 #        CONTENT_INSPECTION_README, Postfix content inspection overview
 #        BACKSCATTER_README, blocking returned forged mail
 # 
 # LICENSE
-#        The Secure Mailer license must be  distributed  with  this
+#        The  Secure  Mailer  license must be distributed with this
 #        software.
 # 
 # AUTHOR(S)
index 307f4074177effc1d95e11a58931e64bd66ecfed..0ff0d03f25fc4633636d5e36171a17c0cce4e3e3 100644 (file)
@@ -262,7 +262,7 @@ the overhead of the TLS exchange. </p>
 certificates issued by these CAs, append the root certificate to
 $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> directory.  When
 you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtpd_tls_verify_depth
+intermediary CAs signed by the root CA, unless $<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a>
 is less than the number of CAs in the certificate chain for the clients
 of interest. With a verify depth of 1 you can only verify certificates
 directly signed by a trusted CA, and all trusted intermediary CAs need to
@@ -315,7 +315,7 @@ is needed. Thus, the $<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApat
 accessible inside the optional chroot jail. </p>
 
 <p> When you configure Postfix to request client certificates (by
-setting $smtpd_tls_asck_ccert = yes), any certificates in
+setting $<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> = yes), any certificates in
 $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> are sent to the client, in order to allow it to
 choose an identity signed by a CA you trust. If no $<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a>
 is specified, no preferred CA list is sent, and the client is free
index 86500e622f84ba834e2272625e3e927a838ef5b1..85c10ed263817f432378d5bd01a28c285d6094b9 100644 (file)
@@ -222,146 +222,149 @@ ACCESS(5)                                                            ACCESS(5)
               erwise log a generic message.
 
               Note:  this action currently affects all recipients
-              of the message.
+              of the message.   To  discard  only  one  recipient
+              without  discarding  the  entire  message,  use the
+              <a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a>
+              service.
 
               This feature is available in Postfix 2.0 and later.
 
-       <b>DUNNO</b>  Pretend  that  the  lookup  key was not found. This
-              prevents Postfix  from  trying  substrings  of  the
-              lookup  key (such as a subdomain name, or a network
+       <b>DUNNO</b>  Pretend that the lookup key  was  not  found.  This
+              prevents  Postfix  from  trying  substrings  of the
+              lookup key (such as a subdomain name, or a  network
               address subnetwork).
 
               This feature is available in Postfix 2.0 and later.
 
        <b>FILTER</b> <i>transport:destination</i>
-              After  the  message is queued, send the entire mes-
+              After the message is queued, send the  entire  mes-
               sage through the specified external content filter.
-              The  <i>transport:destination</i>  syntax  is described in
-              the <a href="transport.5.html"><b>transport</b>(5)</a>  manual  page.   More  information
-              about  external  content  filters is in the Postfix
+              The <i>transport:destination</i> syntax  is  described  in
+              the  <a href="transport.5.html"><b>transport</b>(5)</a>  manual  page.   More information
+              about external content filters is  in  the  Postfix
               <a href="FILTER_README.html">FILTER_README</a> file.
 
-              Note:  this  action  overrides  the  <b>main.cf   <a href="postconf.5.html#content_filter">con</a>-</b>
+              Note:   this  action  overrides  the  <b>main.cf  <a href="postconf.5.html#content_filter">con</a>-</b>
               <b><a href="postconf.5.html#content_filter">tent_filter</a></b>  setting,  and  currently  affects  all
               recipients of the message.
 
               This feature is available in Postfix 2.0 and later.
 
        <b>HOLD</b> <i>optional text...</i>
-              Place  the message on the <b>hold</b> queue, where it will
-              sit until someone either deletes it or releases  it
-              for  delivery.  Log the optional text if specified,
+              Place the message on the <b>hold</b> queue, where it  will
+              sit  until someone either deletes it or releases it
+              for delivery.  Log the optional text if  specified,
               otherwise log a generic message.
 
-              Mail that is placed on hold can  be  examined  with
-              the  <a href="postcat.1.html"><b>postcat</b>(1)</a>  command,  and  can be destroyed or
+              Mail  that  is  placed on hold can be examined with
+              the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and  can  be  destroyed  or
               released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> command.
 
-              Note: use "<b>postsuper -r</b>" to release mail  that  was
-              kept  on  hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+              Note:  use  "<b>postsuper -r</b>" to release mail that was
+              kept on hold for a significant fraction  of  <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
               <b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b>  or  <b>$<a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b>,  or
               longer.
 
-              Note:  this action currently affects all recipients
+              Note: this action currently affects all  recipients
               of the message.
 
               This feature is available in Postfix 2.0 and later.
 
        <b>PREPEND</b> <i>headername: headervalue</i>
-              Prepend  the  specified  message header to the mes-
+              Prepend the specified message header  to  the  mes-
               sage.  When this action is used multiple times, the
-              first  prepended  header  appears before the second
+              first prepended header appears  before  the  second
               etc. prepended header.
 
-              Note: this action does not support multi-line  mes-
+              Note:  this action does not support multi-line mes-
               sage headers.
 
               This feature is available in Postfix 2.1 and later.
 
        <b>REDIRECT</b> <i>user@domain</i>
-              After the message is queued, send  the  message  to
+              After  the  message  is queued, send the message to
               the  specified  address  instead  of  the  intended
               recipient(s).
 
-              Note: this action overrides the FILTER action,  and
+              Note:  this action overrides the FILTER action, and
               currently affects all recipients of the message.
 
               This feature is available in Postfix 2.1 and later.
 
        <b>WARN</b> <i>optional text...</i>
               Log a warning with the optional text, together with
-              client  information  and  if  available, with helo,
+              client information and  if  available,  with  helo,
               sender, recipient and protocol information.
 
               This feature is available in Postfix 2.1 and later.
 
 <b>ENHANCED STATUS CODES</b>
        When an enhanced status code is specified in an access ta-
-       ble, it is subject to modification. The  following  trans-
-       formations  are  needed when the same access table is used
-       for client, helo, sender,  or  recipient  access  restric-
-       tions;  they  happen regardless of whether Postfix replies
+       ble,  it  is subject to modification. The following trans-
+       formations are needed when the same access table  is  used
+       for  client,  helo,  sender,  or recipient access restric-
+       tions; they happen regardless of whether  Postfix  replies
        to a MAIL FROM, RCPT TO or other SMTP command.
 
-       <b>o</b>      When a sender address matches a REJECT action,  the
-              Postfix  SMTP server will transform a recipient DSN
-              status (e.g., 4.1.1-4.1.6) into  the  corresponding
+       <b>o</b>      When  a sender address matches a REJECT action, the
+              Postfix SMTP server will transform a recipient  DSN
+              status  (e.g.,  4.1.1-4.1.6) into the corresponding
               sender DSN status, and vice versa.
 
-       <b>o</b>      When   non-address  information  matches  a  REJECT
-              action (such as the HELO command  argument  or  the
-              client  hostname/address),  the Postfix SMTP server
-              will transform a sender  or  recipient  DSN  status
-              into   a  generic  non-address  DSN  status  (e.g.,
+       <b>o</b>      When  non-address  information  matches  a   REJECT
+              action  (such  as  the HELO command argument or the
+              client hostname/address), the Postfix  SMTP  server
+              will  transform  a  sender  or recipient DSN status
+              into  a  generic  non-address  DSN  status   (e.g.,
               4.0.0).
 
 <b>REGULAR EXPRESSION TABLES</b>
-       This section describes how the table lookups  change  when
+       This  section  describes how the table lookups change when
        the table is given in the form of regular expressions. For
-       a description of regular expression lookup  table  syntax,
+       a  description  of regular expression lookup table syntax,
        see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
 
-       Each  pattern  is  a regular expression that is applied to
+       Each pattern is a regular expression that  is  applied  to
        the entire string being looked up. Depending on the appli-
-       cation,  that  string  is  an  entire  client hostname, an
+       cation, that string  is  an  entire  client  hostname,  an
        entire client IP address, or an entire mail address. Thus,
        no  parent  domain  or  parent  network  search  is  done,
-       <i>user@domain</i> mail addresses are not broken  up  into  their
+       <i>user@domain</i>  mail  addresses  are not broken up into their
        <i>user@</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken
        up into <i>user</i> and <i>foo</i>.
 
-       Patterns are applied in the order as specified in the  ta-
-       ble,  until  a  pattern  is  found that matches the search
+       Patterns  are applied in the order as specified in the ta-
+       ble, until a pattern is  found  that  matches  the  search
        string.
 
-       Actions are the same as with indexed  file  lookups,  with
-       the  additional feature that parenthesized substrings from
+       Actions  are  the  same as with indexed file lookups, with
+       the additional feature that parenthesized substrings  from
        the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
 
 <b>TCP-BASED TABLES</b>
-       This section describes how the table lookups  change  when
+       This  section  describes how the table lookups change when
        lookups are directed to a TCP-based server. For a descrip-
        tion of the TCP client/server lookup protocol, see <a href="tcp_table.5.html"><b>tcp_ta-</b></a>
        <a href="tcp_table.5.html"><b>ble</b>(5)</a>.  This feature is not available up to and including
        Postfix version 2.2.
 
-       Each lookup operation uses the entire query  string  once.
-       Depending  on  the  application,  that string is an entire
+       Each  lookup  operation uses the entire query string once.
+       Depending on the application, that  string  is  an  entire
        client hostname, an entire client IP address, or an entire
-       mail  address.   Thus,  no parent domain or parent network
-       search is done, <i>user@domain</i> mail addresses are not  broken
-       up  into  their <i>user@</i> and <i>domain</i> constituent parts, nor is
+       mail address.  Thus, no parent domain  or  parent  network
+       search  is done, <i>user@domain</i> mail addresses are not broken
+       up into their <i>user@</i> and <i>domain</i> constituent parts,  nor  is
        <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
 
        Actions are the same as with indexed file lookups.
 
 <b>EXAMPLE</b>
-       The following example uses an indexed file,  so  that  the
-       order  of  table entries does not matter. The example per-
-       mits access by the client at address 1.2.3.4  but  rejects
-       all  other  clients  in 1.2.3.0/24. Instead of <b>hash</b> lookup
-       tables, some systems use <b>dbm</b>.  Use the  command  "<b>postconf</b>
-       <b>-m</b>"  to  find  out  what lookup tables Postfix supports on
+       The  following  example  uses an indexed file, so that the
+       order of table entries does not matter. The  example  per-
+       mits  access  by the client at address 1.2.3.4 but rejects
+       all other clients in 1.2.3.0/24. Instead  of  <b>hash</b>  lookup
+       tables,  some  systems use <b>dbm</b>.  Use the command "<b>postconf</b>
+       <b>-m</b>" to find out what lookup  tables  Postfix  supports  on
        your system.
 
        /etc/postfix/main.cf:
@@ -376,7 +379,7 @@ ACCESS(5)                                                            ACCESS(5)
        editing the file.
 
 <b>BUGS</b>
-       The table format does not understand quoting  conventions.
+       The  table format does not understand quoting conventions.
 
 <b>SEE ALSO</b>
        <a href="postmap.1.html">postmap(1)</a>, Postfix lookup table manager
@@ -389,7 +392,7 @@ ACCESS(5)                                                            ACCESS(5)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 38dfa8eb4a827e17cb9eaba8b592159e5c2abb0d..4fd5a9ed09b5784e1d69a60f7cea34219efe34dd 100644 (file)
@@ -145,57 +145,60 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
 
               Note:   this  action  disables  further  header  or
               <a href="postconf.5.html#body_checks">body_checks</a> inspection of the current  message  and
-              affects all recipients.
+              affects all recipients.  To discard only one recip-
+              ient without discarding the entire message, use the
+              <a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a>
+              service.
 
               This feature is available in Postfix 2.0 and later.
 
-       <b>DUNNO</b>  Pretend that the input line did not match any  pat-
-              tern,  and inspect the next input line. This action
+       <b>DUNNO</b>  Pretend  that the input line did not match any pat-
+              tern, and inspect the next input line. This  action
               can be used to shorten the table search.
 
-              For backwards compatibility reasons,  Postfix  also
-              accepts  <b>OK</b> but it is (and always has been) treated
+              For  backwards  compatibility reasons, Postfix also
+              accepts <b>OK</b> but it is (and always has been)  treated
               as <b>DUNNO</b>.
 
               This feature is available in Postfix 2.1 and later.
 
        <b>FILTER</b> <i>transport:destination</i>
-              Write  a  content  filter request to the queue file
-              and inspect the next input line.   After  the  com-
-              plete  message  is received it will be sent through
+              Write a content filter request to  the  queue  file
+              and  inspect  the  next input line.  After the com-
+              plete message is received it will be  sent  through
               the specified external content filter.  More infor-
-              mation  about  external  content  filters is in the
+              mation about external content  filters  is  in  the
               Postfix <a href="FILTER_README.html">FILTER_README</a> file.
 
-              Note:  this  action  overrides  the  <b>main.cf   <a href="postconf.5.html#content_filter">con</a>-</b>
-              <b><a href="postconf.5.html#content_filter">tent_filter</a></b>  setting, and affects all recipients of
-              the message.  In  the  case  that  multiple  <b>FILTER</b>
+              Note:   this  action  overrides  the  <b>main.cf  <a href="postconf.5.html#content_filter">con</a>-</b>
+              <b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and affects all recipients  of
+              the  message.  In  the  case  that  multiple <b>FILTER</b>
               actions fire, only the last one is executed.
 
               This feature is available in Postfix 2.0 and later.
 
        <b>HOLD</b> <i>optional text...</i>
-              Arrange for the message to be placed  on  the  <b>hold</b>
-              queue,  and  inspect the next input line.  The mes-
-              sage remains on <b>hold</b> until someone  either  deletes
-              it  or  releases it for delivery.  Log the optional
+              Arrange  for  the  message to be placed on the <b>hold</b>
+              queue, and inspect the next input line.   The  mes-
+              sage  remains  on <b>hold</b> until someone either deletes
+              it or releases it for delivery.  Log  the  optional
               text if specified, otherwise log a generic message.
 
-              Mail  that  is  placed on hold can be examined with
-              the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and  can  be  destroyed  or
+              Mail that is placed on hold can  be  examined  with
+              the  <a href="postcat.1.html"><b>postcat</b>(1)</a>  command,  and  can be destroyed or
               released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> command.
 
-              Note:  use  "<b>postsuper -r</b>" to release mail that was
-              kept on hold for a significant fraction  of  <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+              Note: use "<b>postsuper -r</b>" to release mail  that  was
+              kept  on  hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
               <b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b>  or  <b>$<a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b>,  or
               longer.
 
-              Note: this action affects  all  recipients  of  the
+              Note:  this  action  affects  all recipients of the
               message.
 
               This feature is available in Postfix 2.0 and later.
 
-       <b>IGNORE</b> Delete the current line from the input and  inspect
+       <b>IGNORE</b> Delete  the current line from the input and inspect
               the next input line.
 
        <b>PREPEND</b> <i>text...</i>
@@ -204,18 +207,18 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
 
               Notes:
 
-              <b>o</b>      The prepended text is output on  a  separate
+              <b>o</b>      The  prepended  text is output on a separate
                      line,  immediately  before  the  input  that
                      triggered the <b>PREPEND</b> action.
 
               <b>o</b>      The prepended text is not considered part of
-                     the  input  stream:  it  is  not  subject to
+                     the input  stream:  it  is  not  subject  to
                      header/body checks or address rewriting, and
                      it does not affect the way that Postfix adds
                      missing message headers.
 
               <b>o</b>      When prepending text before a message header
-                     line,  the  prepended text must begin with a
+                     line, the prepended text must begin  with  a
                      valid message header label.
 
               <b>o</b>      This action cannot be used to prepend multi-
@@ -224,46 +227,46 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
               This feature is available in Postfix 2.1 and later.
 
        <b>REDIRECT</b> <i>user@domain</i>
-              Write a message redirection request  to  the  queue
-              file  and  inspect  the  next input line. After the
+              Write  a  message  redirection request to the queue
+              file and inspect the next  input  line.  After  the
               message is queued, it will be sent to the specified
               address instead of the intended recipient(s).
 
-              Note:  this action overrides the <b>FILTER</b> action, and
-              affects all recipients of the message. If  multiple
-              <b>REDIRECT</b>  actions  fire,  only the last one is exe-
+              Note: this action overrides the <b>FILTER</b> action,  and
+              affects  all recipients of the message. If multiple
+              <b>REDIRECT</b> actions fire, only the last  one  is  exe-
               cuted.
 
               This feature is available in Postfix 2.1 and later.
 
        <b>REPLACE</b> <i>text...</i>
-              Replace  the  current  line with the specified text
+              Replace the current line with  the  specified  text
               and inspect the next input line.
 
               This feature is available in Postfix 2.2 and later.
-              The  description below applies to Postfix 2.2.2 and
+              The description below applies to Postfix 2.2.2  and
               later.
 
               Notes:
 
-              <b>o</b>      When replacing a message  header  line,  the
-                     replacement  text  must  begin  with a valid
+              <b>o</b>      When  replacing  a  message header line, the
+                     replacement text must  begin  with  a  valid
                      header label.
 
-              <b>o</b>      The replaced text remains part of the  input
-                     stream.  Unlike  the result from the <b>PREPEND</b>
-                     action, a replaced  message  header  may  be
-                     subject  to address rewriting and may affect
-                     the way that Postfix  adds  missing  message
+              <b>o</b>      The  replaced text remains part of the input
+                     stream. Unlike the result from  the  <b>PREPEND</b>
+                     action,  a  replaced  message  header may be
+                     subject to address rewriting and may  affect
+                     the  way  that  Postfix adds missing message
                      headers.
 
        <b>REJECT</b> <i>optional text...</i>
-              Reject  the  entire  message.  Reply  with <i>optional</i>
+              Reject the  entire  message.  Reply  with  <i>optional</i>
               <i>text...</i> when the optional text is specified, other-
               wise reply with a generic error message.
 
-              Note:   this  action  disables  further  header  or
-              <a href="postconf.5.html#body_checks">body_checks</a> inspection of the current  message  and
+              Note:  this  action  disables  further  header   or
+              <a href="postconf.5.html#body_checks">body_checks</a>  inspection  of the current message and
               affects all recipients.
 
               Postfix version 2.3 and later support enhanced sta-
@@ -272,26 +275,26 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
               enhanced status code of "5.7.1".
 
        <b>WARN</b> <i>optional text...</i>
-              Log a warning with the <i>optional text...</i> (or  log  a
-              generic  message)  and inspect the next input line.
+              Log  a  warning with the <i>optional text...</i> (or log a
+              generic message) and inspect the next  input  line.
               This action is useful for debugging and for testing
               a pattern before applying more drastic actions.
 
 <b>BUGS</b>
-       Many  people  overlook  the main limitations of header and
-       <a href="postconf.5.html#body_checks">body_checks</a> rules.  These rules  operate  on  one  logical
-       message  header or one body line at a time, and a decision
-       made for one line is not carried over to  the  next  line.
+       Many people overlook the main limitations  of  header  and
+       <a href="postconf.5.html#body_checks">body_checks</a>  rules.   These  rules  operate on one logical
+       message header or one body line at a time, and a  decision
+       made  for  one  line is not carried over to the next line.
        If text in the message body is encoded (<a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a>) then the
-       rules have to specified for the encoded  form.   Likewise,
+       rules  have  to specified for the encoded form.  Likewise,
        when message headers are encoded (<a href="http://www.faqs.org/rfcs/rfc2047.html">RFC 2047</a>) then the rules
        need to be specified for the encoded form.
 
-       Message headers added by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon itself  are
+       Message  headers added by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon itself are
        excluded from inspection. Examples of such message headers
        are <b>From:</b>, <b>To:</b>, <b>Message-ID:</b>, <b>Date:</b>.
 
-       Message headers deleted by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon  will  be
+       Message  headers  deleted by the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon will be
        examined before they are deleted. Examples are: <b>Bcc:, Con-</b>
        <b>tent-Length:</b>, <b>Return-Path:</b>.
 
@@ -299,11 +302,11 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
        <b><a href="postconf.5.html#body_checks">body_checks</a></b>
               Lookup tables with content filter rules for message
               body lines.  These filters see one physical line at
-              a time, in chunks  of  at  most  <b>$<a href="postconf.5.html#line_length_limit">line_length_limit</a></b>
+              a  time,  in  chunks  of at most <b>$<a href="postconf.5.html#line_length_limit">line_length_limit</a></b>
               bytes.
 
        <b><a href="postconf.5.html#body_checks_size_limit">body_checks_size_limit</a></b>
-              The  amount  of  content  per  message body segment
+              The amount of  content  per  message  body  segment
               (attachment) that is subjected to <b>$<a href="postconf.5.html#body_checks">body_checks</a></b> fil-
               tering.
 
@@ -313,32 +316,32 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
 
        <b><a href="postconf.5.html#nested_header_checks">nested_header_checks</a></b> (default: <b>$<a href="postconf.5.html#header_checks">header_checks</a></b>)
               Lookup tables with content filter rules for message
-              header lines: respectively, these  are  applied  to
-              the  initial  message  headers  (not including MIME
-              headers), to the MIME headers anywhere in the  mes-
-              sage,  and  to the initial headers of attached mes-
+              header  lines:  respectively,  these are applied to
+              the initial message  headers  (not  including  MIME
+              headers),  to the MIME headers anywhere in the mes-
+              sage, and to the initial headers of  attached  mes-
               sages.
 
-              Note: these filters see one logical message  header
-              at  a time, even when a message header spans multi-
-              ple lines. Message headers  that  are  longer  than
+              Note:  these filters see one logical message header
+              at a time, even when a message header spans  multi-
+              ple  lines.  Message  headers  that are longer than
               <b>$<a href="postconf.5.html#header_size_limit">header_size_limit</a></b> characters are truncated.
 
        <b><a href="postconf.5.html#disable_mime_input_processing">disable_mime_input_processing</a></b>
-              While  receiving mail, give no special treatment to
-              MIME related message headers; all  text  after  the
+              While receiving mail, give no special treatment  to
+              MIME  related  message  headers; all text after the
               initial message headers is considered to be part of
-              the message body. This means that <b><a href="postconf.5.html#header_checks">header_checks</a></b>  is
-              applied  to  all  the  initial message headers, and
+              the  message body. This means that <b><a href="postconf.5.html#header_checks">header_checks</a></b> is
+              applied to all the  initial  message  headers,  and
               that <b><a href="postconf.5.html#body_checks">body_checks</a></b> is applied to the remainder of the
               message.
 
-              Note:  when  used  in this manner, <b><a href="postconf.5.html#body_checks">body_checks</a></b> will
-              process a multi-line message header one line  at  a
+              Note: when used in this  manner,  <b><a href="postconf.5.html#body_checks">body_checks</a></b>  will
+              process  a  multi-line message header one line at a
               time.
 
 <b>EXAMPLES</b>
-       Header  pattern  to  block  attachments with bad file name
+       Header pattern to block attachments  with  bad  file  name
        extensions.
 
        /etc/postfix/main.cf:
@@ -376,7 +379,7 @@ HEADER_CHECKS(5)                                              HEADER_CHECKS(5)
        <a href="BACKSCATTER_README.html">BACKSCATTER_README</a>, blocking returned forged mail
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 7b018576f56c1ec2634f189d1bc921b0e82d7bee..107acd8fb26a2c2b7e87511d97aac9c60c5aeebe 100644 (file)
@@ -5939,10 +5939,11 @@ delivery performance. </p>
 (default: 10)</b></DT><DD>
 
 <p> When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
+an SMTP session may be reused before it is closed.
 </p>
 
-<p> This feature is available in Postfix 2.2 and later. </p>
+<p> This feature is available in Postfix 2.2. In Postfix 2.3 it is
+replaced by $<a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a>.</p>
 
 
 </DD>
@@ -5958,6 +5959,58 @@ not specify larger values without permission from the remote sites.
 <p> This feature is available in Postfix 2.2 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a>
+(default: 300s)</b></DT><DD>
+
+<p> The amount of time during which Postfix will use an SMTP
+connection repeatedly.  The timer starts when the connection is
+initiated (i.e. it includes the connect, greeting and helo latency,
+in addition to the latencies of subsequent mail delivery transactions).
+</p>
+
+<p> This feature addresses a performance stability problem with
+remote SMTP servers. This problem is not specific to Postfix: it
+can happen when any MTA sends large amounts of SMTP email to a site
+that has multiple MX hosts. </p>
+
+<p> The problem starts when one of a set of MX hosts becomes slower
+than the rest.  Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request. </p>
+
+<p> The slow MX host becomes a connection attractor.  If one MX
+host becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts. </p>
+
+<p> The solution uses connection caching in a way that differs from
+Postfix 2.2.  By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want.  </p>
+
+<p> The default reuse time limit, 300s, is comparable to the various
+smtp transaction timeouts which are fair estimates of maximum excess
+latency for a slow delivery.  Note that hosts may accept thousands
+of messages over a single connection within the default connection
+reuse time limit. This number is much larger than the default Postfix
+2.2 limit of 10 messages per cached connection. It may prove necessary
+to lower the limit to avoid interoperability issues with MTAs that
+exhibit bugs when many messages are delivered via a single connection.
+A lower reuse time limit risks losing the benefit of connection
+reuse when the average connection and mail delivery latency exceeds
+the reuse time limit.  </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtp_data_done_timeout">smtp_data_done_timeout</a>
index 3dfe0f56fa21dd2cfe7ef1f5b884582203d3b4ed..dcd9623de9df3b305176afe6bf3515d6bc10359b 100644 (file)
@@ -51,11 +51,11 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               Reject  the  specified  commands  with a hard (5xx)
               error code.  This option implies <b>-p</b>.
 
-              Examples of commands are HELO,  EHLO,  LHLO,  MAIL,
-              RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
-              command names by white space  or  commas,  and  use
-              quotes  to protect white space from the shell. Com-
-              mand names are case-insensitive.
+              Examples of commands are CONNECT, HELO, EHLO, LHLO,
+              MAIL,  RCPT,  VRFY,  DATA, ., RSET, NOOP, and QUIT.
+              Separate command names by white  space  or  commas,
+              and  use  quotes  to  protect  white space from the
+              shell. Command names are case-insensitive.
 
        <b>-F</b>     Disable XFORWARD support.
 
@@ -80,30 +80,30 @@ SMTP-SINK(1)                                                      SMTP-SINK(1)
               Disconnect  (without  replying) after receiving one
               of the specified commands.
 
-              Examples of commands are HELO,  EHLO,  LHLO,  MAIL,
-              RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
-              command names by white space  or  commas,  and  use
-              quotes  to protect white space from the shell. Com-
-              mand names are case-insensitive.
+              Examples of commands are CONNECT, HELO, EHLO, LHLO,
+              MAIL,  RCPT,  VRFY,  DATA, ., RSET, NOOP, and QUIT.
+              Separate command names by white  space  or  commas,
+              and  use  quotes  to  protect  white space from the
+              shell. Command names are case-insensitive.
 
        <b>-r</b> <i>command,command,...</i>
               Reject the specified commands  with  a  soft  (4xx)
               error code.  This option implies <b>-p</b>.
 
-              Examples  of  commands  are HELO, EHLO, LHLO, MAIL,
-              RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
-              command  names  by  white  space or commas, and use
-              quotes to protect white space from the shell.  Com-
-              mand names are case-insensitive.
+              Examples of commands are CONNECT, HELO, EHLO, LHLO,
+              MAIL, RCPT, VRFY, DATA, ., RSET,  NOOP,  and  QUIT.
+              Separate  command  names  by white space or commas,
+              and use quotes to  protect  white  space  from  the
+              shell. Command names are case-insensitive.
 
        <b>-s</b> <i>command,command,...</i>
               Log the named commands to syslogd.
 
-              Examples  of  commands  are HELO, EHLO, LHLO, MAIL,
-              RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate
-              command  names  by  white  space or commas, and use
-              quotes to protect white space from the shell.  Com-
-              mand names are case-insensitive.
+              Examples of commands are CONNECT, HELO, EHLO, LHLO,
+              MAIL, RCPT, VRFY, DATA, ., RSET,  NOOP,  and  QUIT.
+              Separate  command  names  by white space or commas,
+              and use quotes to  protect  white  space  from  the
+              shell. Command names are case-insensitive.
 
        <b>-t</b> <i>timeout</i> (default: 100)
               Limit the time for receiving a command or sending a
index 4b1d90606e6425b2070a78f8f5cea76c9ffc1752..b96588b21cb8254ec203b032c950db4f9714be54 100644 (file)
@@ -373,58 +373,57 @@ SMTP(8)                                                                SMTP(8)
               destination has a high volume of mail in the active
               queue.
 
-       <b><a href="postconf.5.html#smtp_connection_cache_reuse_limit">smtp_connection_cache_reuse_limit</a> (10)</b>
-              When SMTP connection caching is enabled, the number
-              of times that an SMTP session is reused  before  it
-              is closed.
+       <b><a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a> (300s)</b>
+              The amount of time during which Postfix will use an
+              SMTP connection repeatedly.
 
        <b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
               When SMTP connection caching is enabled, the amount
-              of time that an unused SMTP client socket  is  kept
+              of  time  that an unused SMTP client socket is kept
               open before it is closed.
 
 <b>TROUBLE SHOOTING CONTROLS</b>
        <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
-              The  increment  in  verbose  logging  level  when a
-              remote client or server matches a  pattern  in  the
+              The increment  in  verbose  logging  level  when  a
+              remote  client  or  server matches a pattern in the
               <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
 
        <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
-              Optional  list  of remote client or server hostname
-              or network address patterns that cause the  verbose
-              logging  level  to increase by the amount specified
+              Optional list of remote client or  server  hostname
+              or  network address patterns that cause the verbose
+              logging level to increase by the  amount  specified
               in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
 
        <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
-              The recipient  of  postmaster  notifications  about
-              mail  delivery  problems that are caused by policy,
+              The  recipient  of  postmaster  notifications about
+              mail delivery problems that are caused  by  policy,
               resource, software or protocol errors.
 
        <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
-              The list of error classes that are reported to  the
+              The  list of error classes that are reported to the
               postmaster.
 
 <b>MISCELLANEOUS CONTROLS</b>
        <b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
-              Where  the  Postfix SMTP client should deliver mail
+              Where the Postfix SMTP client should  deliver  mail
               when it detects a "mail loops back to myself" error
               condition.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix main.cf and
+              The default location of  the  Postfix  main.cf  and
               master.cf configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
-              Disable DNS lookups in the Postfix  SMTP  and  LMTP
+              Disable  DNS  lookups  in the Postfix SMTP and LMTP
               clients.
 
        <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
-              Optional  list of relay hosts for SMTP destinations
+              Optional list of relay hosts for SMTP  destinations
               that can't be found or that are unreachable.
 
        <b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
@@ -432,7 +431,7 @@ SMTP(8)                                                                SMTP(8)
               tem receives mail on.
 
        <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
-              The  Internet protocols Postfix will attempt to use
+              The Internet protocols Postfix will attempt to  use
               when making or accepting connections.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -440,55 +439,55 @@ SMTP(8)                                                                SMTP(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
-              The  maximum  amount  of  time that an idle Postfix
-              daemon process waits for the next  service  request
+              The maximum amount of time  that  an  idle  Postfix
+              daemon  process  waits for the next service request
               before exiting.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The  maximal number of connection requests before a
+              The maximal number of connection requests before  a
               Postfix daemon process terminates.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID  of  a  Postfix  command  or  daemon
+              The  process  ID  of  a  Postfix  command or daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The  process  name  of  a Postfix command or daemon
+              The process name of a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on by way of a proxy or network
+              tem receives mail on by way of a proxy  or  network
               address translation unit.
 
        <b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
               An optional numerical network address that the SMTP
-              client  should  bind to when making an IPv4 connec-
+              client should bind to when making an  IPv4  connec-
               tion.
 
        <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
               An optional numerical network address that the SMTP
-              client  should  bind to when making an IPv6 connec-
+              client should bind to when making an  IPv6  connec-
               tion.
 
        <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The hostname to send in the SMTP EHLO or HELO  com-
+              The  hostname to send in the SMTP EHLO or HELO com-
               mand.
 
        <b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
-              What  mechanisms  when the SMTP client uses to look
+              What mechanisms when the SMTP client uses  to  look
               up a host's IP address.
 
        <b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
-              Randomize the order  of  equal-preference  MX  host
+              Randomize  the  order  of  equal-preference MX host
               addresses.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The  mail  system  name  that  is  prepended to the
-              process name in syslog  records,  so  that  "smtpd"
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
               becomes, for example, "postfix/smtpd".
 
 <b>SEE ALSO</b>
@@ -506,7 +505,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index a01cd78a2f85ad8dc732c2f04ba6ec8014ca09e5..d8a3426fc67a5a72964cd80cf3561a80050f9870 100644 (file)
@@ -116,6 +116,8 @@ case "$SYSTEM.$RELEASE" in
                ;;
   FreeBSD.5*)  SYSTYPE=FREEBSD5
                ;;
+  FreeBSD.6*)  SYSTYPE=FREEBSD6
+               ;;
   OpenBSD.2*)  SYSTYPE=OPENBSD2
                ;;
   OpenBSD.3*)  SYSTYPE=OPENBSD3
@@ -397,7 +399,8 @@ export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS
 # Snapshot only.
 CCARGS="$CCARGS -DSNAPSHOT"
 
-# Non-production, i.e. needs thorough testing.
+# Non-production: needs thorough testing, or major changes are still
+# needed before the code stabilizes.
 #CCARGS="$CCARGS -DNONPROD"
 
 sed 's/  / /g' <<EOF
index 9d84729f0cdf415c898cb49a8ae476d0f916a374..6a792585025507cf00bd00c6bc00732e6fc54a05 100644 (file)
@@ -51,7 +51,7 @@ Do not announce ENHANCEDSTATUSCODES support.
 Reject the specified commands with a hard (5xx) error code.
 This option implies \fB-p\fR.
 .sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 DATA, ., RSET, NOOP, and QUIT. Separate command names by
 white space or commas, and use quotes to protect white space
 from the shell. Command names are case-insensitive.
@@ -73,7 +73,7 @@ a CISCO PIX system. Implies \fB-e\fR.
 Disconnect (without replying) after receiving one of the
 specified commands.
 .sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 DATA, ., RSET, NOOP, and QUIT. Separate command names by
 white space or commas, and use quotes to protect white space
 from the shell. Command names are case-insensitive.
@@ -81,14 +81,14 @@ from the shell. Command names are case-insensitive.
 Reject the specified commands with a soft (4xx) error code.
 This option implies \fB-p\fR.
 .sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 DATA, ., RSET, NOOP, and QUIT. Separate command names by
 white space or commas, and use quotes to protect white space
 from the shell. Command names are case-insensitive.
 .IP "\fB-s \fIcommand,command,...\fR"
 Log the named commands to syslogd.
 .sp
-Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 DATA, ., RSET, NOOP, and QUIT. Separate command names by
 white space or commas, and use quotes to protect white space
 from the shell. Command names are case-insensitive.
index ac48b3d4959be40494cfb5f301645c230e54f37c..b4895794cf5ef2456dbfc63116326aae121de017 100644 (file)
@@ -209,6 +209,8 @@ Log the optional text if specified, otherwise log a generic
 message.
 .sp
 Note: this action currently affects all recipients of the message.
+To discard only one recipient without discarding the entire message,
+use the transport(5) table to direct mail to the discard(8) service.
 .sp
 This feature is available in Postfix 2.0 and later.
 .IP \fBDUNNO\fR
index a376859a0919e958a113fc7895b11b4c7c868fc7..ada40168694c04f2fb094733e99522481c941693 100644 (file)
@@ -141,6 +141,8 @@ message.
 .sp
 Note: this action disables further header or body_checks inspection
 of the current message and affects all recipients.
+To discard only one recipient without discarding the entire message,
+use the transport(5) table to direct mail to the discard(8) service.
 .sp
 This feature is available in Postfix 2.0 and later.
 .IP \fBDUNNO\fR
index f4aa2e9fe091e6cbae9bddb1b9ffdb6006283504..b1395b898645dd986d5420362043757de14a0428 100644 (file)
@@ -3323,15 +3323,61 @@ delivery performance.
 This feature is available in Postfix 2.2 and later.
 .SH smtp_connection_cache_reuse_limit (default: 10)
 When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
+an SMTP session may be reused before it is closed.
 .PP
-This feature is available in Postfix 2.2 and later.
+This feature is available in Postfix 2.2. In Postfix 2.3 it is
+replaced by $smtp_connection_reuse_time_limit.
 .SH smtp_connection_cache_time_limit (default: 2s)
 When SMTP connection caching is enabled, the amount of time that
 an unused SMTP client socket is kept open before it is closed.  Do
 not specify larger values without permission from the remote sites.
 .PP
 This feature is available in Postfix 2.2 and later.
+.SH smtp_connection_reuse_time_limit (default: 300s)
+The amount of time during which Postfix will use an SMTP
+connection repeatedly.  The timer starts when the connection is
+initiated (i.e. it includes the connect, greeting and helo latency,
+in addition to the latencies of subsequent mail delivery transactions).
+.PP
+This feature addresses a performance stability problem with
+remote SMTP servers. This problem is not specific to Postfix: it
+can happen when any MTA sends large amounts of SMTP email to a site
+that has multiple MX hosts.
+.PP
+The problem starts when one of a set of MX hosts becomes slower
+than the rest.  Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request.
+.PP
+The slow MX host becomes a connection attractor.  If one MX
+host becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts.
+.PP
+The solution uses connection caching in a way that differs from
+Postfix 2.2.  By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want.
+.PP
+The default reuse time limit, 300s, is comparable to the various
+smtp transaction timeouts which are fair estimates of maximum excess
+latency for a slow delivery.  Note that hosts may accept thousands
+of messages over a single connection within the default connection
+reuse time limit. This number is much larger than the default Postfix
+2.2 limit of 10 messages per cached connection. It may prove necessary
+to lower the limit to avoid interoperability issues with MTAs that
+exhibit bugs when many messages are delivered via a single connection.
+A lower reuse time limit risks losing the benefit of connection
+reuse when the average connection and mail delivery latency exceeds
+the reuse time limit.
+.PP
+This feature is available in Postfix 2.3 and later.
 .SH smtp_data_done_timeout (default: 600s)
 The SMTP client time limit for sending the SMTP ".", and for receiving
 the server response.
index 9459f0e7d42a5ae98b0da0d3ab16db47b5940af2..6ad4bc4115762a73731c208aa49954390b0ef694 100644 (file)
@@ -302,9 +302,9 @@ destinations.
 .IP "\fBsmtp_connection_cache_on_demand (yes)\fR"
 Temporarily enable SMTP connection caching while a destination
 has a high volume of mail in the active queue.
-.IP "\fBsmtp_connection_cache_reuse_limit (10)\fR"
-When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed.
+.IP "\fBsmtp_connection_reuse_time_limit (300s)\fR"
+The amount of time during which Postfix will use an SMTP
+connection repeatedly.
 .IP "\fBsmtp_connection_cache_time_limit (2s)\fR"
 When SMTP connection caching is enabled, the amount of time that
 an unused SMTP client socket is kept open before it is closed.
index 65704bbbee9682a471d5a106f53d4ba88374b977..ca87611f31bc337d7fb2149400556713e4cfa6ff 100755 (executable)
@@ -320,6 +320,7 @@ while (<>) {
 
     s;\bsmtp_connection_cache_on_demand\b;<a href="postconf.5.html#smtp_connection_cache_on_demand">$&</a>;g;
     s;\bsmtp_connection_cache_reuse_limit\b;<a href="postconf.5.html#smtp_connection_cache_reuse_limit">$&</a>;g;
+    s;\bsmtp_connection_reuse_time_limit\b;<a href="postconf.5.html#smtp_connection_reuse_time_limit">$&</a>;g;
     s;\bsmtp_connection_cache_time_limit\b;<a href="postconf.5.html#smtp_connection_cache_time_limit">$&</a>;g;
     s;\bsmtp_connection_cache_destinations\b;<a href="postconf.5.html#smtp_connection_cache_destinations">$&</a>;g;
 
index 5e3243b0d78780ebff9b96a167c3611c3043faac..20154a37fea4c49b363080f8fba1470679e6f865 100644 (file)
@@ -262,7 +262,7 @@ the overhead of the TLS exchange. </p>
 certificates issued by these CAs, append the root certificate to
 $smtpd_tls_CAfile or install it in the $smtpd_tls_CApath directory.  When
 you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtpd_tls_verify_depth
+intermediary CAs signed by the root CA, unless $smtpd_tls_ccert_verifydepth
 is less than the number of CAs in the certificate chain for the clients
 of interest. With a verify depth of 1 you can only verify certificates
 directly signed by a trusted CA, and all trusted intermediary CAs need to
@@ -315,7 +315,7 @@ is needed. Thus, the $smtpd_tls_CApath directory needs to be
 accessible inside the optional chroot jail. </p>
 
 <p> When you configure Postfix to request client certificates (by
-setting $smtpd_tls_asck_ccert = yes), any certificates in
+setting $smtpd_tls_ask_ccert = yes), any certificates in
 $smtpd_tls_CAfile are sent to the client, in order to allow it to
 choose an identity signed by a CA you trust. If no $smtpd_tls_CAfile
 is specified, no preferred CA list is sent, and the client is free
index b612b1ddea0340c23a4db7857d937b4502ba4e7f..69598470ff3ca09e4b2f319814c45edcff196a2e 100644 (file)
 #      message.
 # .sp
 #      Note: this action currently affects all recipients of the message.
+#      To discard only one recipient without discarding the entire message,
+#      use the transport(5) table to direct mail to the discard(8) service.
 # .sp
 #      This feature is available in Postfix 2.0 and later.
 # .IP \fBDUNNO\fR
index 8ae1b465a4d4c49859c93fb9189ecbf547096b54..736c09e2518f6829dffa51e0690599de31698af1 100644 (file)
 # .sp
 #      Note: this action disables further header or body_checks inspection
 #      of the current message and affects all recipients.
+#      To discard only one recipient without discarding the entire message,
+#      use the transport(5) table to direct mail to the discard(8) service.
 # .sp
 #      This feature is available in Postfix 2.0 and later.
 # .IP \fBDUNNO\fR
index adcf4124d939fbb2b8af97da12a15b9e3970c2ea..00b60b9b88f8c5e956cc062e2686ebe1cb7ef83f 100644 (file)
@@ -3532,10 +3532,59 @@ not specify larger values without permission from the remote sites.
 %PARAM smtp_connection_cache_reuse_limit 10
 
 <p> When SMTP connection caching is enabled, the number of times that
-an SMTP session is reused before it is closed. 
-</p>
-
-<p> This feature is available in Postfix 2.2 and later. </p>
+an SMTP session may be reused before it is closed. 
+</p>
+
+<p> This feature is available in Postfix 2.2. In Postfix 2.3 it is
+replaced by $smtp_connection_reuse_time_limit.</p>
+
+%PARAM smtp_connection_reuse_time_limit 300s
+
+<p> The amount of time during which Postfix will use an SMTP
+connection repeatedly.  The timer starts when the connection is
+initiated (i.e. it includes the connect, greeting and helo latency,
+in addition to the latencies of subsequent mail delivery transactions).
+</p>
+
+<p> This feature addresses a performance stability problem with
+remote SMTP servers. This problem is not specific to Postfix: it
+can happen when any MTA sends large amounts of SMTP email to a site
+that has multiple MX hosts. </p>
+
+<p> The problem starts when one of a set of MX hosts becomes slower
+than the rest.  Even though SMTP clients connect to fast and slow
+MX hosts with equal probability, the slow MX host ends up with more
+simultaneous inbound connections than the faster MX hosts, because
+the slow MX host needs more time to serve each client request. </p>
+
+<p> The slow MX host becomes a connection attractor.  If one MX
+host becomes N times slower than the rest, it dominates mail delivery
+latency unless there are more than N fast MX hosts to counter the
+effect. And if the number of MX hosts is smaller than N, the mail
+delivery latency becomes effectively that of the slowest MX host
+divided by the total number of MX hosts. </p>
+
+<p> The solution uses connection caching in a way that differs from
+Postfix 2.2.  By limiting the amount of time during which a connection
+can be used repeatedly (instead of limiting the number of deliveries
+over that connection), Postfix not only restores fairness in the
+distribution of simultaneous connections across a set of MX hosts,
+it also favors deliveries over connections that perform well, which
+is exactly what we want.  </p>
+
+<p> The default reuse time limit, 300s, is comparable to the various
+smtp transaction timeouts which are fair estimates of maximum excess
+latency for a slow delivery.  Note that hosts may accept thousands
+of messages over a single connection within the default connection
+reuse time limit. This number is much larger than the default Postfix
+2.2 limit of 10 messages per cached connection. It may prove necessary
+to lower the limit to avoid interoperability issues with MTAs that
+exhibit bugs when many messages are delivered via a single connection.
+A lower reuse time limit risks losing the benefit of connection
+reuse when the average connection and mail delivery latency exceeds
+the reuse time limit.  </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
 
 %PARAM smtp_connection_cache_destinations
 
index 66a6a9fa3c939f19be4e16a51d9f87ad5d6f5be7..f8b0a6e43f50c5cf262dffc7b71831f257d24f44 100644 (file)
@@ -75,6 +75,7 @@ bounce.o: ../../include/mail_proto.h
 bounce.o: ../../include/mail_queue.h
 bounce.o: ../../include/mail_server.h
 bounce.o: ../../include/msg.h
+bounce.o: ../../include/msg_stats.h
 bounce.o: ../../include/rcpt_buf.h
 bounce.o: ../../include/recipient_list.h
 bounce.o: ../../include/stringops.h
@@ -134,6 +135,7 @@ bounce_notify_service.o: ../../include/mail_error.h
 bounce_notify_service.o: ../../include/mail_params.h
 bounce_notify_service.o: ../../include/mail_queue.h
 bounce_notify_service.o: ../../include/msg.h
+bounce_notify_service.o: ../../include/msg_stats.h
 bounce_notify_service.o: ../../include/name_mask.h
 bounce_notify_service.o: ../../include/post_mail.h
 bounce_notify_service.o: ../../include/rcpt_buf.h
@@ -193,6 +195,7 @@ bounce_notify_verp.o: ../../include/mail_error.h
 bounce_notify_verp.o: ../../include/mail_params.h
 bounce_notify_verp.o: ../../include/mail_queue.h
 bounce_notify_verp.o: ../../include/msg.h
+bounce_notify_verp.o: ../../include/msg_stats.h
 bounce_notify_verp.o: ../../include/name_mask.h
 bounce_notify_verp.o: ../../include/post_mail.h
 bounce_notify_verp.o: ../../include/rcpt_buf.h
@@ -216,6 +219,7 @@ bounce_one_service.o: ../../include/mail_addr.h
 bounce_one_service.o: ../../include/mail_error.h
 bounce_one_service.o: ../../include/mail_params.h
 bounce_one_service.o: ../../include/msg.h
+bounce_one_service.o: ../../include/msg_stats.h
 bounce_one_service.o: ../../include/name_mask.h
 bounce_one_service.o: ../../include/post_mail.h
 bounce_one_service.o: ../../include/rcpt_buf.h
@@ -238,6 +242,7 @@ bounce_trace_service.o: ../../include/mail_error.h
 bounce_trace_service.o: ../../include/mail_params.h
 bounce_trace_service.o: ../../include/mail_queue.h
 bounce_trace_service.o: ../../include/msg.h
+bounce_trace_service.o: ../../include/msg_stats.h
 bounce_trace_service.o: ../../include/name_mask.h
 bounce_trace_service.o: ../../include/post_mail.h
 bounce_trace_service.o: ../../include/rcpt_buf.h
index f827e1f82221b1df89bff12867a3a026ab4266fd..218c3a48137755ee594869fee92e0599865cae93 100644 (file)
@@ -173,6 +173,7 @@ cleanup_api.o: ../../include/match_list.h
 cleanup_api.o: ../../include/match_ops.h
 cleanup_api.o: ../../include/mime_state.h
 cleanup_api.o: ../../include/msg.h
+cleanup_api.o: ../../include/msg_stats.h
 cleanup_api.o: ../../include/mymalloc.h
 cleanup_api.o: ../../include/nvtable.h
 cleanup_api.o: ../../include/recipient_list.h
@@ -210,6 +211,7 @@ cleanup_bounce.o: ../../include/match_list.h
 cleanup_bounce.o: ../../include/match_ops.h
 cleanup_bounce.o: ../../include/mime_state.h
 cleanup_bounce.o: ../../include/msg.h
+cleanup_bounce.o: ../../include/msg_stats.h
 cleanup_bounce.o: ../../include/mymalloc.h
 cleanup_bounce.o: ../../include/nvtable.h
 cleanup_bounce.o: ../../include/rec_type.h
@@ -497,6 +499,7 @@ cleanup_out_recipient.o: ../../include/match_list.h
 cleanup_out_recipient.o: ../../include/match_ops.h
 cleanup_out_recipient.o: ../../include/mime_state.h
 cleanup_out_recipient.o: ../../include/msg.h
+cleanup_out_recipient.o: ../../include/msg_stats.h
 cleanup_out_recipient.o: ../../include/mymalloc.h
 cleanup_out_recipient.o: ../../include/nvtable.h
 cleanup_out_recipient.o: ../../include/rec_type.h
index fb3283e31c66756e1cbfe733aec2598228133967..57750a8496a545bf1ddb56fca71836e53212ba92 100644 (file)
@@ -230,6 +230,12 @@ extern void cleanup_addr_bcc(CLEANUP_STATE *, const char *);
   */
 extern int cleanup_bounce(CLEANUP_STATE *);
 
+ /*
+  * MSG_STATS compatibility.
+  */
+#define CLEANUP_MSG_STATS(stats, state) \
+    MSG_STATS_INIT1(stats, incoming_arrival, state->time)
+
 /* LICENSE
 /* .ad
 /* .fi
index aa78950aa41f507cec37c02a881acae74f3c807a..6ca62967bb2a48da080abeb011dba43a4354e3bc 100644 (file)
 static void cleanup_bounce_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
                                          DSN *dsn)
 {
-    if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id, state->time,
+    MSG_STATS stats;
+
+    if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+                     CLEANUP_MSG_STATS(&stats, state),
                      rcpt, "none", dsn) != 0) {
        msg_warn("%s: bounce logfile update error", state->queue_id);
        state->errs |= CLEANUP_STAT_WRITE;
index ad3d04b61d707db8546d70f19748051df452d48e..94af4cb78835edc9e836fbc23a9184db0c36c368 100644 (file)
@@ -82,6 +82,7 @@
 #include <trace.h>
 #include <mail_queue.h>                        /* cleanup_trace_path */
 #include <mail_proto.h>
+#include <msg_stats.h>
 
 /* Application-specific. */
 
 static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
                                         DSN *dsn)
 {
+    MSG_STATS stats;
+
     if (cleanup_trace_path == 0) {
        cleanup_trace_path = vstring_alloc(10);
        mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE,
                        state->queue_id);
     }
-    if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id, state->time,
+    if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id,
+                    CLEANUP_MSG_STATS(&stats, state),
                     rcpt, "none", dsn) != 0) {
        msg_warn("%s: trace logfile update error", state->queue_id);
        state->errs |= CLEANUP_STAT_WRITE;
index d6621171d1a24f9726ce6bc4812d70140a8ceabf..e3df656ad29504e51ca5f049654fdfb379fdab28 100644 (file)
@@ -55,6 +55,7 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+discard.o: ../../include/attr.h
 discard.o: ../../include/bounce.h
 discard.o: ../../include/deliver_completed.h
 discard.o: ../../include/deliver_request.h
@@ -65,6 +66,7 @@ discard.o: ../../include/flush_clnt.h
 discard.o: ../../include/mail_queue.h
 discard.o: ../../include/mail_server.h
 discard.o: ../../include/msg.h
+discard.o: ../../include/msg_stats.h
 discard.o: ../../include/recipient_list.h
 discard.o: ../../include/sent.h
 discard.o: ../../include/sys_defs.h
index c1c00bbf30587597ea66bd1671376c2370f6e0c0..b2feeaeb2fd5787897367285fa139b09cfb4c61f 100644 (file)
@@ -172,7 +172,7 @@ static int deliver_message(DELIVER_REQUEST *request)
        rcpt = request->rcpt_list.info + nrcpt;
        if (rcpt->offset >= 0) {
            status = sent(BOUNCE_FLAGS(request), request->queue_id,
-                         request->arrival_time, rcpt, "none", &dsn);
+                         &request->msg_stats, rcpt, "none", &dsn);
            if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
                deliver_completed(src, rcpt->offset);
            result |= status;
index ac16bc189758db9d974128a951929ad45af4225b..9dd13f5ef65f118543f2201c793886002f5153b1 100644 (file)
@@ -55,6 +55,7 @@ depend: $(MAKES)
        @$(EXPORT) make -f Makefile.in Makefile 1>&2
 
 # do not edit below this line - it is generated by 'make depend'
+error.o: ../../include/attr.h
 error.o: ../../include/bounce.h
 error.o: ../../include/deliver_completed.h
 error.o: ../../include/deliver_request.h
@@ -65,6 +66,7 @@ error.o: ../../include/flush_clnt.h
 error.o: ../../include/mail_queue.h
 error.o: ../../include/mail_server.h
 error.o: ../../include/msg.h
+error.o: ../../include/msg_stats.h
 error.o: ../../include/recipient_list.h
 error.o: ../../include/sys_defs.h
 error.o: ../../include/sys_exits.h
index 803bb2e56ff55b2c267aaed90c5f16399857f498..11343129c6552df78384124dcdadc483fd5f6c3c 100644 (file)
@@ -175,7 +175,7 @@ static int deliver_message(DELIVER_REQUEST *request)
        rcpt = request->rcpt_list.info + nrcpt;
        if (rcpt->offset >= 0) {
            status = bounce_append(BOUNCE_FLAGS(request), request->queue_id,
-                                  request->arrival_time, rcpt, "none",
+                                  &request->msg_stats, rcpt, "none",
                                   &dsn);
            if (status == 0)
                deliver_completed(src, rcpt->offset);
index e950671e52b25887ecb0c6e146b55352aec0f97e..27dda27a01ada9ae2c9d319de3b4a237df4fff53 100644 (file)
@@ -27,7 +27,7 @@ SRCS  = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
        ehlo_mask.c \
        wildcard_inet_addr.c valid_mailhost_addr.c dsn_util.c dsn_mask.c \
        dsn_attr_map.c dsn.c dsn_buf.c rcpt_buf.c rcpt_print.c dsn_print.c \
-       dsb_scan.c mail_conf_long.c
+       dsb_scan.c mail_conf_long.c msg_stats_print.c msg_stats_scan.c
 OBJS   = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
        clnt_stream.o debug_peer.o debug_process.o defer.o db_common.o \
@@ -56,7 +56,7 @@ OBJS  = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        ehlo_mask.o \
        wildcard_inet_addr.o valid_mailhost_addr.o dsn_util.o dsn_mask.o \
        dsn_attr_map.o dsn.o dsn_buf.o rcpt_buf.o rcpt_print.o dsn_print.o \
-       dsb_scan.o mail_conf_long.o
+       dsb_scan.o mail_conf_long.o msg_stats_print.o msg_stats_scan.o
 HDRS   = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
        debug_peer.h debug_process.h defer.h deliver_completed.h \
@@ -80,7 +80,7 @@ HDRS  = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        xtext.h scache.h user_acl.h ehlo_mask.h db_common.h \
        wildcard_inet_addr.h valid_mailhost_addr.h dsn_util.h dsn_mask.h \
        dsn_attr_map.h dsn.h dsn_buf.h rcpt_buf.h rcpt_print.h dsn_print.h \
-       dsb_scan.h
+       dsb_scan.h msg_stats.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -430,6 +430,7 @@ abounce.o: dsn.h
 abounce.o: dsn_buf.h
 abounce.o: mail_params.h
 abounce.o: mail_proto.h
+abounce.o: msg_stats.h
 abounce.o: recipient_list.h
 anvil_clnt.o: ../../include/attr.h
 anvil_clnt.o: ../../include/attr_clnt.h
@@ -473,6 +474,7 @@ bounce.o: dsn_util.h
 bounce.o: log_adhoc.h
 bounce.o: mail_params.h
 bounce.o: mail_proto.h
+bounce.o: msg_stats.h
 bounce.o: rcpt_print.h
 bounce.o: recipient_list.h
 bounce.o: trace.h
@@ -592,6 +594,7 @@ defer.o: log_adhoc.h
 defer.o: mail_params.h
 defer.o: mail_proto.h
 defer.o: mail_queue.h
+defer.o: msg_stats.h
 defer.o: rcpt_print.h
 defer.o: recipient_list.h
 defer.o: trace.h
@@ -630,6 +633,7 @@ deliver_pass.o: dsn.h
 deliver_pass.o: dsn_buf.h
 deliver_pass.o: mail_params.h
 deliver_pass.o: mail_proto.h
+deliver_pass.o: msg_stats.h
 deliver_pass.o: recipient_list.h
 deliver_request.o: ../../include/attr.h
 deliver_request.o: ../../include/iostuff.h
@@ -648,6 +652,7 @@ deliver_request.o: dsn_print.h
 deliver_request.o: mail_open_ok.h
 deliver_request.o: mail_proto.h
 deliver_request.o: mail_queue.h
+deliver_request.o: msg_stats.h
 deliver_request.o: recipient_list.h
 dict_ldap.o: ../../include/argv.h
 dict_ldap.o: ../../include/binhash.h
@@ -867,14 +872,17 @@ input_transp.o: mail_params.h
 is_header.o: ../../include/sys_defs.h
 is_header.o: is_header.c
 is_header.o: is_header.h
+log_adhoc.o: ../../include/attr.h
 log_adhoc.o: ../../include/msg.h
 log_adhoc.o: ../../include/sys_defs.h
 log_adhoc.o: ../../include/vbuf.h
+log_adhoc.o: ../../include/vstream.h
 log_adhoc.o: ../../include/vstring.h
 log_adhoc.o: dsn.h
 log_adhoc.o: dsn_buf.h
 log_adhoc.o: log_adhoc.c
 log_adhoc.o: log_adhoc.h
+log_adhoc.o: msg_stats.h
 log_adhoc.o: recipient_list.h
 mail_addr.o: ../../include/stringops.h
 mail_addr.o: ../../include/sys_defs.h
@@ -1189,6 +1197,7 @@ maps.o: ../../include/vstring.h
 maps.o: mail_conf.h
 maps.o: maps.c
 maps.o: maps.h
+mark_corrupt.o: ../../include/attr.h
 mark_corrupt.o: ../../include/msg.h
 mark_corrupt.o: ../../include/set_eugid.h
 mark_corrupt.o: ../../include/sys_defs.h
@@ -1202,6 +1211,7 @@ mark_corrupt.o: mail_params.h
 mark_corrupt.o: mail_queue.h
 mark_corrupt.o: mark_corrupt.c
 mark_corrupt.o: mark_corrupt.h
+mark_corrupt.o: msg_stats.h
 mark_corrupt.o: recipient_list.h
 match_parent_style.o: ../../include/match_list.h
 match_parent_style.o: ../../include/match_ops.h
@@ -1301,6 +1311,24 @@ mkmap_sdbm.o: ../../include/vstream.h
 mkmap_sdbm.o: ../../include/vstring.h
 mkmap_sdbm.o: mkmap.h
 mkmap_sdbm.o: mkmap_sdbm.c
+msg_stats_print.o: ../../include/attr.h
+msg_stats_print.o: ../../include/iostuff.h
+msg_stats_print.o: ../../include/sys_defs.h
+msg_stats_print.o: ../../include/vbuf.h
+msg_stats_print.o: ../../include/vstream.h
+msg_stats_print.o: mail_proto.h
+msg_stats_print.o: msg_stats.h
+msg_stats_print.o: msg_stats_print.c
+msg_stats_scan.o: ../../include/attr.h
+msg_stats_scan.o: ../../include/iostuff.h
+msg_stats_scan.o: ../../include/msg.h
+msg_stats_scan.o: ../../include/sys_defs.h
+msg_stats_scan.o: ../../include/vbuf.h
+msg_stats_scan.o: ../../include/vstream.h
+msg_stats_scan.o: ../../include/vstring.h
+msg_stats_scan.o: mail_proto.h
+msg_stats_scan.o: msg_stats.h
+msg_stats_scan.o: msg_stats_scan.c
 mynetworks.o: ../../include/argv.h
 mynetworks.o: ../../include/inet_addr_list.h
 mynetworks.o: ../../include/mask_addr.h
@@ -1552,6 +1580,7 @@ scache_single.o: ../../include/vbuf.h
 scache_single.o: ../../include/vstring.h
 scache_single.o: scache.h
 scache_single.o: scache_single.c
+sent.o: ../../include/attr.h
 sent.o: ../../include/msg.h
 sent.o: ../../include/sys_defs.h
 sent.o: ../../include/vbuf.h
@@ -1566,6 +1595,7 @@ sent.o: dsn_mask.h
 sent.o: dsn_util.h
 sent.o: log_adhoc.h
 sent.o: mail_params.h
+sent.o: msg_stats.h
 sent.o: recipient_list.h
 sent.o: sent.c
 sent.o: sent.h
@@ -1682,6 +1712,7 @@ trace.o: dsn_print.h
 trace.o: log_adhoc.h
 trace.o: mail_params.h
 trace.o: mail_proto.h
+trace.o: msg_stats.h
 trace.o: rcpt_print.h
 trace.o: recipient_list.h
 trace.o: trace.c
@@ -1715,6 +1746,7 @@ verify.o: dsn_buf.h
 verify.o: log_adhoc.h
 verify.o: mail_params.h
 verify.o: mail_proto.h
+verify.o: msg_stats.h
 verify.o: recipient_list.h
 verify.o: verify.c
 verify.o: verify.h
@@ -1732,6 +1764,7 @@ verify_clnt.o: dsn.h
 verify_clnt.o: dsn_buf.h
 verify_clnt.o: mail_params.h
 verify_clnt.o: mail_proto.h
+verify_clnt.o: msg_stats.h
 verify_clnt.o: recipient_list.h
 verify_clnt.o: verify_clnt.c
 verify_clnt.o: verify_clnt.h
index 7ae333735c054e105c7c4925716d676b60339d2e..440e4ebcf9233ecf04c6825f63c131912afca6cd 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <bounce.h>
 /*
-/*     int     bounce_append(flags, id, entry, recipient, relay, dsn)
+/*     int     bounce_append(flags, id, stats, recipient, relay, dsn)
 /*     int     flags;
 /*     const char *id;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *rcpt;
 /*     const char *relay;
 /*     DSN     *dsn;
@@ -36,7 +36,7 @@
 /*     const char *verp_delims;
 /*
 /*     int     bounce_one(flags, queue, id, encoding, sender, envid, ret,
-/*                             entry, recipient, relay, dsn)
+/*                             stats, recipient, relay, dsn)
 /*     int     flags;
 /*     const char *queue;
 /*     const char *id;
@@ -44,7 +44,7 @@
 /*     const char *sender;
 /*     const char *dsn_envid;
 /*     int     dsn_ret;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *rcpt;
 /*     const char *relay;
 /*     DSN     *dsn;
@@ -99,8 +99,9 @@
 /* .IP id
 /*     The message queue id if the original message file. The bounce log
 /*     file has the same name as the original message file.
-/* .IP entry
-/*     Message arrival time.
+/* .IP stats
+/*     Time stamps from different message delivery stages
+/*     and session reuse count.
 /* .IP rcpt
 /*     Recipient information. See recipient_list(3).
 /* .IP relay
 
 /* bounce_append - append dsn_text to per-message bounce log */
 
-int     bounce_append(int flags, const char *id, time_t entry,
+int     bounce_append(int flags, const char *id, MSG_STATS *stats,
                              RECIPIENT *rcpt, const char *relay,
                              DSN *dsn)
 {
@@ -186,7 +187,7 @@ int     bounce_append(int flags, const char *id, time_t entry,
      */
     if (flags & DEL_REQ_FLAG_MTA_VRFY) {
        my_dsn.action = "undeliverable";
-       status = verify_append(id, entry, rcpt, relay, &my_dsn,
+       status = verify_append(id, stats, rcpt, relay, &my_dsn,
                               DEL_RCPT_STAT_BOUNCE);
        return (status);
     }
@@ -197,7 +198,7 @@ int     bounce_append(int flags, const char *id, time_t entry,
      */
     if (flags & DEL_REQ_FLAG_USR_VRFY) {
        my_dsn.action = "undeliverable";
-       status = trace_append(flags, id, entry, rcpt, relay, &my_dsn);
+       status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
        return (status);
     }
 
@@ -241,9 +242,9 @@ int     bounce_append(int flags, const char *id, time_t entry,
                                ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
                                ATTR_TYPE_END) == 0
            && ((flags & DEL_REQ_FLAG_RECORD) == 0
-               || trace_append(flags, id, entry, rcpt, relay,
+               || trace_append(flags, id, stats, rcpt, relay,
                                &my_dsn) == 0)) {
-           log_adhoc(id, entry, rcpt, relay, &my_dsn, log_status);
+           log_adhoc(id, stats, rcpt, relay, &my_dsn, log_status);
            status = (var_soft_bounce ? -1 : 0);
        } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
            VSTRING *junk = vstring_alloc(100);
@@ -252,7 +253,7 @@ int     bounce_append(int flags, const char *id, time_t entry,
            vstring_sprintf(junk, "%s or %s service failure",
                            var_bounce_service, var_trace_service);
            my_dsn.reason = vstring_str(junk);
-           status = defer_append(flags, id, entry, rcpt, relay, &my_dsn);
+           status = defer_append(flags, id, stats, rcpt, relay, &my_dsn);
            vstring_free(junk);
        } else {
            status = -1;
@@ -333,7 +334,7 @@ int     bounce_flush_verp(int flags, const char *queue, const char *id,
 int     bounce_one(int flags, const char *queue, const char *id,
                           const char *encoding, const char *sender,
                           const char *dsn_envid, int dsn_ret,
-                          time_t entry, RECIPIENT *rcpt,
+                          MSG_STATS *stats, RECIPIENT *rcpt,
                           const char *relay, DSN *dsn)
 {
     DSN     my_dsn = *dsn;
@@ -353,7 +354,7 @@ int     bounce_one(int flags, const char *queue, const char *id,
      */
     if (flags & DEL_REQ_FLAG_MTA_VRFY) {
        my_dsn.action = "undeliverable";
-       status = verify_append(id, entry, rcpt, relay, &my_dsn,
+       status = verify_append(id, stats, rcpt, relay, &my_dsn,
                               DEL_RCPT_STAT_BOUNCE);
        return (status);
     }
@@ -364,7 +365,7 @@ int     bounce_one(int flags, const char *queue, const char *id,
      */
     if (flags & DEL_REQ_FLAG_USR_VRFY) {
        my_dsn.action = "undeliverable";
-       status = trace_append(flags, id, entry, rcpt, relay, &my_dsn);
+       status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
        return (status);
     }
 
@@ -373,7 +374,7 @@ int     bounce_one(int flags, const char *queue, const char *id,
      * based procedure.
      */
     else if (var_soft_bounce) {
-       return (bounce_append(flags, id, entry, rcpt, relay, &my_dsn));
+       return (bounce_append(flags, id, stats, rcpt, relay, &my_dsn));
     }
 
     /*
@@ -402,9 +403,9 @@ int     bounce_one(int flags, const char *queue, const char *id,
                                ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
                                ATTR_TYPE_END) == 0
            && ((flags & DEL_REQ_FLAG_RECORD) == 0
-               || trace_append(flags, id, entry, rcpt, relay,
+               || trace_append(flags, id, stats, rcpt, relay,
                                &my_dsn) == 0)) {
-           log_adhoc(id, entry, rcpt, relay, &my_dsn, "bounced");
+           log_adhoc(id, stats, rcpt, relay, &my_dsn, "bounced");
            status = 0;
        } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
            VSTRING *junk = vstring_alloc(100);
@@ -413,7 +414,7 @@ int     bounce_one(int flags, const char *queue, const char *id,
            vstring_sprintf(junk, "%s or %s service failure",
                            var_bounce_service, var_trace_service);
            my_dsn.reason = vstring_str(junk);
-           status = defer_append(flags, id, entry, rcpt, relay, &my_dsn);
+           status = defer_append(flags, id, stats, rcpt, relay, &my_dsn);
            vstring_free(junk);
        } else {
            status = -1;
index c8678b1e6c4d7d5fb7f6174242cd43931ac71f93..bde6451c14d399ee895b61b4f7e1d25a26929ca3 100644 (file)
@@ -24,7 +24,7 @@
  /*
   * Client interface.
   */
-extern int bounce_append(int, const char *, time_t, RECIPIENT *,
+extern int bounce_append(int, const char *, MSG_STATS *, RECIPIENT *,
                                 const char *, DSN *);
 extern int bounce_flush(int, const char *, const char *, const char *,
                                const char *, const char *, int);
@@ -32,7 +32,7 @@ extern int bounce_flush_verp(int, const char *, const char *, const char *,
                             const char *, const char *, int, const char *);
 extern int bounce_one(int, const char *, const char *, const char *,
                              const char *, const char *,
-                             int, time_t, RECIPIENT *,
+                             int, MSG_STATS *, RECIPIENT *,
                              const char *, DSN *);
 
  /*
index 32a304c1660dd5cc110719cb38515cbf0f062ffc..0f0a57b988b83d868de1d48ad0e86311e4d48f9c 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <defer.h>
 /*
-/*     int     defer_append(flags, id, entry, rcpt, relay, dsn)
+/*     int     defer_append(flags, id, stats, rcpt, relay, dsn)
 /*     int     flags;
 /*     const char *id;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *rcpt;
 /*     const char *relay;
 /*     DSN     *dsn;
@@ -80,8 +80,9 @@
 /*     The message queue name of the original message file.
 /* .IP id
 /*     The queue id of the original message file.
-/* .IP entry
-/*     Message arrival time.
+/* .IP stats
+/*     Time stamps from different message delivery stages
+/*     and session reuse count.
 /* .IP rcpt
 /*     Recipient information. See recipient_list(3).
 /* .IP relay
 
 /* defer_append - defer message delivery */
 
-int     defer_append(int flags, const char *id, time_t entry,
+int     defer_append(int flags, const char *id, MSG_STATS *stats,
                             RECIPIENT *rcpt, const char *relay,
                             DSN *dsn)
 {
@@ -165,7 +166,7 @@ int     defer_append(int flags, const char *id, time_t entry,
      */
     if (flags & DEL_REQ_FLAG_MTA_VRFY) {
        my_dsn.action = "undeliverable";
-       status = verify_append(id, entry, rcpt, relay, &my_dsn,
+       status = verify_append(id, stats, rcpt, relay, &my_dsn,
                               DEL_RCPT_STAT_DEFER);
        return (status);
     }
@@ -176,7 +177,7 @@ int     defer_append(int flags, const char *id, time_t entry,
      */
     if (flags & DEL_REQ_FLAG_USR_VRFY) {
        my_dsn.action = "undeliverable";
-       status = trace_append(flags, id, entry, rcpt, relay, &my_dsn);
+       status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
        return (status);
     }
 
@@ -202,13 +203,13 @@ int     defer_append(int flags, const char *id, time_t entry,
                                ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
                                ATTR_TYPE_END) != 0)
            msg_warn("%s: %s service failure", id, var_defer_service);
-       log_adhoc(id, entry, rcpt, relay, &my_dsn, "deferred");
+       log_adhoc(id, stats, rcpt, relay, &my_dsn, "deferred");
 
        /*
         * Traced delivery.
         */
        if (flags & DEL_REQ_FLAG_RECORD)
-           if (trace_append(flags, id, entry, rcpt, relay, &my_dsn) != 0)
+           if (trace_append(flags, id, stats, rcpt, relay, &my_dsn) != 0)
                msg_warn("%s: %s service failure", id, var_trace_service);
 
        /*
index fe1f71291dce61dc8cbdd75e79e6f20c03a7ae85..ba9be7d698d07afebf1fcbb60fe281fb98515884 100644 (file)
@@ -19,7 +19,7 @@
  /*
   * External interface.
   */
-extern int defer_append(int, const char *, time_t, RECIPIENT *,
+extern int defer_append(int, const char *, MSG_STATS *, RECIPIENT *,
                                const char *, DSN *);
 extern int defer_flush(int, const char *, const char *, const char *,
                               const char *, const char *, int);
index 1922db7141f54a446dbed2031d864ad81039bd54..943a58c257eaf7be39495da255e4361f24377f29 100644 (file)
@@ -103,7 +103,7 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
               ATTR_TYPE_STR, MAIL_ATTR_SENDER, request->sender,
               ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, request->dsn_envid,
               ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, request->dsn_ret,
-              ATTR_TYPE_LONG, MAIL_ATTR_TIME, request->arrival_time,
+              ATTR_TYPE_FUNC, msg_stats_print, (void *) &request->msg_stats,
               ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, request->client_name,
               ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, request->client_addr,
               ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, request->client_proto,
index 14ddda5131829205704f195db8dfda9907dabc77..fba702725caf81d87353306202112596ac193d8c 100644 (file)
@@ -17,7 +17,7 @@
 /*             char    *nexthop;
 /*             char    *encoding;
 /*             char    *sender;
-/*             long arrival_time;
+/*             MSG_STATS stats;
 /*             RECIPIENT_LIST rcpt_list;
 /*             DSN     *hop_status;
 /*             char    *client_name;
@@ -240,7 +240,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
                  ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
                  ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
                  ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
-                 ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time,
+                 ATTR_TYPE_FUNC, msg_stats_scan, (void *) &request->msg_stats,
                  ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, client_name,
                  ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, client_addr,
                  ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, client_proto,
@@ -257,6 +257,10 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
                     vstring_str(queue_id), &st, &path) == 0)
        return (-1);
 
+    /* Don't override hand-off time after deliver_pass() delegation. */
+    if (request->msg_stats.agent_handoff.tv_sec == 0)
+       GETTIMEOFDAY(&request->msg_stats.agent_handoff);
+
     request->queue_name = mystrdup(vstring_str(queue_name));
     request->queue_id = mystrdup(vstring_str(queue_id));
     request->nexthop = mystrdup(vstring_str(nexthop));
index d676748a56859d3e9d6d3db2483d2a5c9c08c76a..ba3afb5b3c7c667909592ee31416c26285be0417 100644 (file)
@@ -22,6 +22,7 @@
   */
 #include <recipient_list.h>
 #include <dsn.h>
+#include <msg_stats.h>
 
  /*
   * Structure of a server mail delivery request.
@@ -36,7 +37,7 @@ typedef struct DELIVER_REQUEST {
     char   *nexthop;                   /* next hop name */
     char   *encoding;                  /* content encoding */
     char   *sender;                    /* envelope sender */
-    long    arrival_time;              /* arrival time */
+    MSG_STATS msg_stats;               /* time profile */
     RECIPIENT_LIST rcpt_list;          /* envelope recipients */
     DSN    *hop_status;                        /* DSN status */
     char   *client_name;               /* client hostname */
index fd816dee4dd4f6eef4e917537d9eaa9cff1a4e7f..ebb1ce193b64dadfa6a2fe3b354309338e4ce7ff 100644 (file)
@@ -6,9 +6,9 @@
 /* SYNOPSIS
 /*     #include <log_adhoc.h>
 /*
-/*     void    log_adhoc(id, entry, recipient, relay, dsn, status)
+/*     void    log_adhoc(id, stats, recipient, relay, dsn, status)
 /*     const char *id;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *recipient;
 /*     const char *relay;
 /*     DSN *dsn;
@@ -23,8 +23,9 @@
 /*     The message queue name of the original message file.
 /* .IP id
 /*     The queue id of the original message file.
-/* .IP entry
-/*     Message arrival time.
+/* .IP stats
+/*     Time stamps from different message delivery stages
+/*     and session reuse count.
 /* .IP recipient
 /*     Recipient information. See recipient_list(3).
 /* .IP sender
 
 #include <log_adhoc.h>
 
-/* log_adhoc - defer message delivery */
+/* log_adhoc - ad-hoc logging */
 
-void    log_adhoc(const char *id, time_t entry, RECIPIENT *recipient,
+void    log_adhoc(const char *id, MSG_STATS *stats, RECIPIENT *recipient,
                          const char *relay, DSN *dsn,
                          const char *status)
 {
-    int     delay = time((time_t *) 0) - entry;
+    static VSTRING *buf;
+    int     delay;
+    int  pdelay;                       /* time before queue manager */
+    struct timeval adelay;             /* queue manager latency */
+    struct timeval sdelay;             /* connection set-up latency */
+    struct timeval xdelay;             /* transmission latency */
+    struct timeval now;
 
+    /*
+     * Alas, we need an intermediate buffer for the pre-formatted result.
+     * There are several optional fields, and we want to tweak some
+     * formatting depending on delay values.
+     */
+    if (buf == 0)
+       buf = vstring_alloc(100);
+
+    /*
+     * First, general information that identifies the transaction.
+     */
+    vstring_sprintf(buf, "%s: to=<%s>", id, recipient->address);
     if (recipient->orig_addr && *recipient->orig_addr
        && strcasecmp(recipient->address, recipient->orig_addr) != 0)
-       msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, dsn=%s, status=%s (%s)",
-                id, recipient->address, recipient->orig_addr, relay, delay,
-                dsn->status, status, dsn->reason);
+       vstring_sprintf_append(buf, ", orig_to=<%s>", recipient->orig_addr);
+    vstring_sprintf_append(buf, ", relay=%s", relay);
+
+    /*
+     * Next, performance statistics.
+     * 
+     * Use wall clock time to compute pdelay (before active queue latency) if
+     * there is no time stamp for active queue entry. This happens when mail
+     * is bounced by the cleanup server.
+     * 
+     * Otherwise, use wall clock time to compute adelay (active queue latency)
+     * if there is no time stamp for hand-off to delivery agent. This happens
+     * when mail was deferred or bounced by the queue manager.
+     * 
+     * Otherwise, use wall clock time to compute xdelay (message transfer
+     * latency) if there is no time stamp for delivery completion. In the
+     * case of multi-recipient deliveries the delivery agent may specify the
+     * delivery completion time, so that multiple recipient records show the
+     * same delay values.
+     * 
+     * Don't compute the sdelay (connection setup latency) if there is no time
+     * stamp for connection setup completion.
+     * 
+     * Instead of floating point, use integer math where practical.
+     */
+#define DELTA(x, y, z) \
+    do { \
+       (x).tv_sec = (y).tv_sec - (z).tv_sec; \
+       (x).tv_usec = (y).tv_usec - (z).tv_usec; \
+       if ((x).tv_usec < 0) { \
+           (x).tv_usec += 1000000; \
+           (x).tv_sec -= 1; \
+       } \
+       if ((x).tv_sec < 0) \
+           (x).tv_sec = (x).tv_usec = 0; \
+    } while (0)
+
+    if (stats->deliver_done.tv_sec)
+       now = stats->deliver_done;
     else
-       msg_info("%s: to=<%s>, relay=%s, delay=%d, dsn=%s, status=%s (%s)",
-                id, recipient->address, relay, delay, dsn->status,
-                status, dsn->reason);
+       GETTIMEOFDAY(&now);
+    delay = now.tv_sec - stats->incoming_arrival;
+    adelay.tv_sec = adelay.tv_usec =
+       sdelay.tv_sec = sdelay.tv_usec =
+       xdelay.tv_sec = xdelay.tv_usec = 0;
+    if (stats->active_arrival.tv_sec) {
+       pdelay = stats->active_arrival.tv_sec - stats->incoming_arrival;
+       if (stats->agent_handoff.tv_sec) {
+           DELTA(adelay, stats->agent_handoff, stats->active_arrival);
+           if (stats->conn_setup_done.tv_sec) {
+               DELTA(sdelay, stats->conn_setup_done, stats->agent_handoff);
+               DELTA(xdelay, now, stats->conn_setup_done);
+           } else {
+               /* Non-network delivery agent. */
+               DELTA(xdelay, now, stats->agent_handoff);
+           }
+       } else {
+           /* No delivery agent. */
+           DELTA(adelay, now, stats->active_arrival);
+       }
+    } else {
+       /* No queue manager. */
+       pdelay = now.tv_sec - stats->incoming_arrival;
+    }
+    if (stats->reuse_count > 0)
+       vstring_sprintf_append(buf, ", conn_use=%d", stats->reuse_count + 1);
+
+#define PRETTY_FORMAT(b, x) \
+    do { \
+       if ((x).tv_sec > 0 || (x).tv_usec < 10000) { \
+           vstring_sprintf_append((b), "/%ld", (long) (x).tv_sec); \
+       } else { \
+           vstring_sprintf_append((b), "/%.1g", \
+                   (x).tv_sec + (x).tv_usec / 1000000.0); \
+       } \
+    } while (0)
+
+    vstring_sprintf_append(buf, ", delay=%d, delays=%d", delay, pdelay);
+    PRETTY_FORMAT(buf, adelay);
+    PRETTY_FORMAT(buf, sdelay);
+    PRETTY_FORMAT(buf, xdelay);
+
+    /*
+     * Finally, the delivery status.
+     */
+    vstring_sprintf_append(buf, ", dsn=%s, status=%s (%s)",
+                          dsn->status, status, dsn->reason);
+
+    /*
+     * Ship it off.
+     */
+    msg_info("%s", vstring_str(buf));
 }
index 3a8789d2feec2ccc961ba55047839d8f64748bd6..583cb6122b2b976355fc1e9add6341dc6639e63a 100644 (file)
   */
 #include <recipient_list.h>
 #include <dsn.h>
+#include <msg_stats.h>
 
  /*
   * Client interface.
   */
-extern void log_adhoc(const char *, time_t, RECIPIENT *, const char *,
+extern void log_adhoc(const char *, MSG_STATS *, RECIPIENT *, const char *,
                              DSN *, const char *);
 
 /* LICENSE
index 0ca0f9a1bc889d12fcda0747892fb796ff4adae5..da793018013593f4712eabdf41bfaa118c81a2ed 100644 (file)
@@ -848,9 +848,9 @@ extern char *var_bestmx_transp;
 #define DEF_SMTP_CACHE_CONN    "2s"
 extern int var_smtp_cache_conn;
 
-#define VAR_SMTP_REUSE_LIMIT   "smtp_connection_cache_reuse_limit"
-#define DEF_SMTP_REUSE_LIMIT   10
-extern int var_smtp_reuse_limit;
+#define VAR_SMTP_REUSE_TIME    "smtp_connection_reuse_time_limit"
+#define DEF_SMTP_REUSE_TIME    "300s"
+extern int var_smtp_reuse_time;
 
 #define VAR_SMTP_CACHE_DEST    "smtp_connection_cache_destinations"
 #define DEF_SMTP_CACHE_DEST    ""
index 780c2441acd9523a81889cbe9f2084b76d79ea10..274e921fd437ad4d584c5cbfc2cd159e63b0a584 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20051014"
+#define MAIL_RELEASE_DATE      "20051103"
 #define MAIL_VERSION_NUMBER    "2.3"
 
 #ifdef SNAPSHOT
diff --git a/postfix/src/global/msg_stats.h b/postfix/src/global/msg_stats.h
new file mode 100644 (file)
index 0000000..ea24921
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef _MSG_STATS_H_INCLUDED_
+#define _MSG_STATS_H_INCLUDED_
+
+/*++
+/* NAME
+/*     msg_stats 3h
+/* SUMMARY
+/*     message delivery profiling
+/* SYNOPSIS
+/*     #include <msg_stats.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * System library.
+  */
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+
+ /*
+  * Utility library.
+  */
+#include <attr.h>
+#include <vstream.h>
+
+ /*
+  * External interface.
+  * 
+  * This structure contains the time stamps from various mail delivery stages,
+  * as well as the connection reuse count. The time stamps provide additional
+  * insight into the nature of performance bottle necks.
+  * 
+  * For convenience, we record absolute time stamps instead of time differences.
+  * This is because the decision of what numbers to subtract actually depends
+  * on program history. Since we prefer to compute time differences in one
+  * place, we postpone this task until the end, in log_adhoc().
+  * 
+  * A zero time stamp or reuse count means the information is not supplied.
+  * 
+  * Specifically, a zero active_arrival value means that the message did not
+  * reach the queue manager; and a zero agent_handoff time means that the
+  * queue manager did not give the message to a delivery agent.
+  * 
+  * Some network clients update the conn_setup_done value when connection setup
+  * fails or completes.
+  * 
+  * The deliver_done value is usually left at zero, which means use the wall
+  * clock time when reporting recipient status information. The exception is
+  * with delivery agents that can deliver multiple recipients in a single
+  * transaction. These agents explicitly update the deliver_done time stamp
+  * to ensure that multiple recipient records show the exact same delay
+  * values.
+  */
+typedef struct {
+    time_t  incoming_arrival;          /* incoming queue entry */
+    struct timeval active_arrival;     /* active queue entry */
+    struct timeval agent_handoff;      /* delivery agent hand-off */
+    struct timeval conn_setup_done;    /* connection set-up done */
+    struct timeval deliver_done;       /* transmission done */
+    int     reuse_count;               /* connection reuse count */
+} MSG_STATS;
+
+#define MSG_STATS_INIT(st) \
+    ( \
+       memset((char *) (st), 0, sizeof(*(st))), \
+       (st) \
+    )
+
+#define MSG_STATS_INIT1(st, member, value) \
+    ( \
+       memset((char *) (st), 0, sizeof(*(st))), \
+       ((st)->member = (value)), \
+       (st) \
+    )
+
+#define MSG_STATS_INIT2(st, m1, v1, m2, v2) \
+    ( \
+       memset((char *) (st), 0, sizeof(*(st))), \
+       ((st)->m1 = (v1)), \
+       ((st)->m2 = (v2)), \
+       (st) \
+    )
+
+extern int msg_stats_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
+extern int msg_stats_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/global/msg_stats_print.c b/postfix/src/global/msg_stats_print.c
new file mode 100644 (file)
index 0000000..cffc2f1
--- /dev/null
@@ -0,0 +1,63 @@
+/*++
+/* NAME
+/*     msg_stats_print
+/* SUMMARY
+/*     write MSG_STATS structure to stream
+/* SYNOPSIS
+/*     #include <msg_stats_print.h>
+/*
+/*     int     msg_stats_print(print_fn, stream, flags, ptr)
+/*     ATTR_PRINT_MASTER_FN print_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     msg_stats_print() writes a MSG_STATS structure to the named stream using
+/*     the specified attribute print routine. msg_stats_print() is meant
+/*     to be passed as a call-back to attr_print(), thusly:
+/*
+/*     ... ATTR_PRINT_FUNC, msg_stats_print, (void *) stats, ...
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <attr.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <msg_stats.h>
+
+/* msg_stats_print - write MSG_STATS to stream */
+
+int     msg_stats_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
+                         int flags, void *ptr)
+{
+    int     ret;
+
+    /*
+     * Send the entire structure. This is not only simpler but also likely to
+     * be quicker than having the sender figure out what fields need to be
+     * sent, converting numbers to string and back, and having the receiver
+     * initialize the unused fields by hand.
+     */
+    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
+                  ATTR_TYPE_DATA, MAIL_ATTR_TIME, sizeof(MSG_STATS), ptr,
+                  ATTR_TYPE_END);
+    return (ret);
+}
diff --git a/postfix/src/global/msg_stats_scan.c b/postfix/src/global/msg_stats_scan.c
new file mode 100644 (file)
index 0000000..bc7d3c4
--- /dev/null
@@ -0,0 +1,86 @@
+/*++
+/* NAME
+/*     msg_stats_scan
+/* SUMMARY
+/*     read MSG_STATS from stream
+/* SYNOPSIS
+/*     #include <msg_stats.h>
+/*
+/*     int     msg_stats_scan(scan_fn, stream, flags, ptr)
+/*     ATTR_SCAN_MASTER_FN scan_fn;
+/*     VSTREAM *stream;
+/*     int     flags;
+/*     void    *ptr;
+/* DESCRIPTION
+/*     msg_stats_scan() reads a MSG_STATS from the named stream using the
+/*     specified attribute scan routine. msg_stats_scan() is meant
+/*     to be passed as a call-back to attr_scan(), thusly:
+/*
+/*     ... ATTR_SCAN_FUNC, msg_stats_scan, (void *) &stats, ...
+/* DIAGNOSTICS
+/*     Fatal: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <attr.h>
+#include <vstring.h>
+#include <msg.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <msg_stats.h>
+
+ /*
+  * SLMs.
+  */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* msg_stats_scan - read MSG_STATS from stream */
+
+int     msg_stats_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
+                              int flags, void *ptr)
+{
+    MSG_STATS *stats = (MSG_STATS *) ptr;
+    VSTRING *buf = vstring_alloc(sizeof(MSG_STATS) * 2);
+    int     ret;
+
+    /*
+     * Receive the entire structure. This is not only simpler but also likely
+     * to be quicker than having the sender figure out what fields need to be
+     * sent, converting those numbers to string and back, and having the
+     * receiver initialize the unused fields by hand.
+     * 
+     * XXX Would be nice if VSTRINGs could import a fixed-size buffer and
+     * gracefully reject attempts to extend it.
+     */
+    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
+                 ATTR_TYPE_DATA, MAIL_ATTR_TIME, buf,
+                 ATTR_TYPE_END);
+    if (ret == 1) {
+       if (LEN(buf) == sizeof(*stats)) {
+           memcpy((char *) stats, STR(buf), sizeof(*stats));
+       } else {
+           msg_warn("msg_stats_scan: size mis-match: %u != %u",
+                    (unsigned) LEN(buf), (unsigned) sizeof(*stats));
+           ret = (-1);
+       }
+    }
+    vstring_free(buf);
+    return (ret);
+}
index b923e6f04019f2820df7963663e60274ad1a9c77..47af4703277b1f2e82e9977a7e99795089d7a7f7 100644 (file)
@@ -20,7 +20,9 @@
 /*     ... ATTR_PRINT_FUNC, rcpt_print, (void *) recipient, ...
 /* DIAGNOSTICS
 /*     Fatal: out of memory.
-/* LICENSE .ad .fi
+/* LICENSE
+/* .ad
+/* .fi
 /*     The Secure Mailer license must be distributed with this
 /*     software.
 /* AUTHOR(S)
index f055267d9719c9aca6e56c258ceceeab2e50f568..56fdd8e2f2cf4c4bd6701275edac28ec598a8751 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <sent.h>
 /*
-/*     int     sent(flags, queue_id, entry, recipient, relay, dsn)
+/*     int     sent(flags, queue_id, stats, recipient, relay, dsn)
 /*     int     flags;
 /*     const char *queue_id;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *recipient;
 /*     const char *relay;
 /*     DSN *dsn;
@@ -38,8 +38,9 @@
 /*     the message delivery record.
 /* .RE .IP queue_id
 /*     The message queue id.
-/* .IP entry
-/*     Message arrival time.
+/* .IP stats
+/*     Time stamps from different message delivery stages
+/*     and session reuse count.
 /* .IP recipient
 /*     Recipient information. See recipient_list(3).
 /* .IP relay
@@ -95,7 +96,7 @@
 
 /* sent - log that a message was or could be sent */
 
-int     sent(int flags, const char *id, time_t entry,
+int     sent(int flags, const char *id, MSG_STATS *stats,
                     RECIPIENT *recipient, const char *relay,
                     DSN *dsn)
 {
@@ -116,7 +117,7 @@ int     sent(int flags, const char *id, time_t entry,
      */
     if (flags & DEL_REQ_FLAG_MTA_VRFY) {
        my_dsn.action = "deliverable";
-       status = verify_append(id, entry, recipient, relay, &my_dsn,
+       status = verify_append(id, stats, recipient, relay, &my_dsn,
                               DEL_RCPT_STAT_OK);
        return (status);
     }
@@ -127,7 +128,7 @@ int     sent(int flags, const char *id, time_t entry,
      */
     if (flags & DEL_REQ_FLAG_USR_VRFY) {
        my_dsn.action = "deliverable";
-       status = trace_append(flags, id, entry, recipient, relay, &my_dsn);
+       status = trace_append(flags, id, stats, recipient, relay, &my_dsn);
        return (status);
     }
 
@@ -139,10 +140,10 @@ int     sent(int flags, const char *id, time_t entry,
            my_dsn.action = "delivered";
 
        if (((flags & DEL_REQ_FLAG_RECORD) == 0
-         || trace_append(flags, id, entry, recipient, relay, &my_dsn) == 0)
+         || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)
            && ((recipient->dsn_notify & DSN_NOTIFY_SUCCESS) == 0
-       || trace_append(flags, id, entry, recipient, relay, &my_dsn) == 0)) {
-           log_adhoc(id, entry, recipient, relay, &my_dsn, "sent");
+       || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)) {
+           log_adhoc(id, stats, recipient, relay, &my_dsn, "sent");
            status = 0;
        } else {
            VSTRING *junk = vstring_alloc(100);
@@ -151,7 +152,7 @@ int     sent(int flags, const char *id, time_t entry,
                            id, var_trace_service);
            my_dsn.reason = vstring_str(junk);
            my_dsn.status ="4.3.0";
-           status = defer_append(flags, id, entry, recipient, relay, &my_dsn);
+           status = defer_append(flags, id, stats, recipient, relay, &my_dsn);
            vstring_free(junk);
        }
        return (status);
index 66a85c2473b103ea1ec093ee03c3e1a545ca12bb..eb9a23f2f8de8037809023f92e9b7f53fa078f71 100644 (file)
@@ -28,7 +28,7 @@
   */
 #define SENT_FLAG_NONE (0)
 
-extern int sent(int, const char *, time_t, RECIPIENT *, const char *, 
+extern int sent(int, const char *, MSG_STATS *, RECIPIENT *, const char *, 
                        DSN *);
 
 /* LICENSE
index fa9962f4fffcdcd75f5c4d9a19bfd933cd781def..d6d30a09802babb95addb0896ef948f6eda45f0c 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <trace.h>
 /*
-/*     int     trace_append(flags, id, entry, rcpt, relay, dsn)
+/*     int     trace_append(flags, id, stats, rcpt, relay, dsn)
 /*     int     flags;
 /*     const char *id;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *rcpt;
 /*     const char *relay;
 /*     DSN     *dsn;
@@ -54,8 +54,9 @@
 /*     Optional DSN envelope ID.
 /* .IP dsn_ret
 /*     Optional DSN return full/headers option.
-/* .IP entry
-/*     Message arrival time.
+/* .IP stats
+/*     Time stamps from different message delivery stages
+/*     and session reuse count.
 /* .IP rcpt
 /*     Recipient information. See recipient_list(3).
 /* .IP relay
 
 /* trace_append - append to message delivery record */
 
-int     trace_append(int flags, const char *id, time_t entry,
+int     trace_append(int flags, const char *id, MSG_STATS *stats,
                             RECIPIENT *rcpt, const char *relay,
                             DSN *dsn)
 {
@@ -130,7 +131,7 @@ int     trace_append(int flags, const char *id, time_t entry,
        req_stat = -1;
     } else {
        if (flags & DEL_REQ_FLAG_USR_VRFY)
-           log_adhoc(id, entry, rcpt, relay, dsn, my_dsn.action);
+           log_adhoc(id, stats, rcpt, relay, dsn, my_dsn.action);
        req_stat = 0;
     }
     vstring_free(why);
index 13f4f8affaee4788689b76099a882873077eed80..201360198e995a93556c7a74d35522decc9faae5 100644 (file)
@@ -19,7 +19,7 @@
  /*
   * External interface.
   */
-extern int trace_append(int, const char *, time_t, RECIPIENT *,
+extern int trace_append(int, const char *, MSG_STATS *, RECIPIENT *,
                                const char *, DSN *);
 extern int trace_flush(int, const char *, const char *, const char *,
                               const char *, const char *, int);
index a7615ef55c9710c2259575546b8de50ac6feb39c..df83d4ed00a64be90f585f0395e980b62ab07eb0 100644 (file)
@@ -6,10 +6,10 @@
 /* SYNOPSIS
 /*     #include <verify.h>
 /*
-/*     int     verify_append(queue_id, entry, recipient, relay, dsn,
+/*     int     verify_append(queue_id, stats, recipient, relay, dsn,
 /*                             verify_status)
 /*     const char *queue_id;
-/*     time_t  entry;
+/*     MSG_STATS *stats;
 /*     RECIPIENT *recipient;
 /*     const char *relay;
 /*     DSN     *dsn;
@@ -25,8 +25,9 @@
 /*     Arguments:
 /* .IP queue_id
 /*     The message queue id.
-/* .IP entry
-/*     Message arrival time.
+/* .IP stats
+/*     Time stamps from different message delivery stages
+/*     and session reuse count.
 /* .IP recipient
 /*     Recipient information. See recipient_list(3).
 /* .IP relay
@@ -86,7 +87,7 @@
 
 /* verify_append - update address verification database */
 
-int     verify_append(const char *queue_id, time_t entry,
+int     verify_append(const char *queue_id, MSG_STATS *stats,
                              RECIPIENT *recipient, const char *relay,
                              DSN *dsn, int vrfy_stat)
 {
@@ -113,7 +114,7 @@ int     verify_append(const char *queue_id, time_t entry,
        req_stat = VRFY_STAT_OK;
     }
     if (req_stat == VRFY_STAT_OK) {
-       log_adhoc(queue_id, entry, recipient, relay, dsn, my_dsn.action);
+       log_adhoc(queue_id, stats, recipient, relay, dsn, my_dsn.action);
        req_stat = 0;
     } else {
        msg_warn("%s: %s service failure", queue_id, var_verify_service);
index efc43546f91db8739771963ba13d41c543c98794..250eb6d65e9520bb05dcdc972635add49daca067 100644 (file)
@@ -24,7 +24,7 @@
  /*
   * External interface.
   */
-extern int verify_append(const char *, time_t, RECIPIENT *,
+extern int verify_append(const char *, MSG_STATS *, RECIPIENT *,
                                 const char *, DSN *, int);
 
 /* LICENSE
index acecf014270010d669c2d4ec3c28c719fc70bdbd..10210d785c391df4ea873c5a287435314a6dbe7a 100644 (file)
@@ -61,6 +61,7 @@ depend: $(MAKES)
 
 # do not edit below this line - it is generated by 'make depend'
 lmtp.o: ../../include/argv.h
+lmtp.o: ../../include/attr.h
 lmtp.o: ../../include/debug_peer.h
 lmtp.o: ../../include/deliver_request.h
 lmtp.o: ../../include/dict.h
@@ -74,6 +75,7 @@ lmtp.o: ../../include/mail_params.h
 lmtp.o: ../../include/mail_queue.h
 lmtp.o: ../../include/mail_server.h
 lmtp.o: ../../include/msg.h
+lmtp.o: ../../include/msg_stats.h
 lmtp.o: ../../include/mymalloc.h
 lmtp.o: ../../include/name_mask.h
 lmtp.o: ../../include/recipient_list.h
@@ -86,6 +88,7 @@ lmtp.o: lmtp.c
 lmtp.o: lmtp.h
 lmtp.o: lmtp_sasl.h
 lmtp_addr.o: ../../include/argv.h
+lmtp_addr.o: ../../include/attr.h
 lmtp_addr.o: ../../include/deliver_request.h
 lmtp_addr.o: ../../include/dns.h
 lmtp_addr.o: ../../include/dsn.h
@@ -94,6 +97,7 @@ lmtp_addr.o: ../../include/inet_addr_list.h
 lmtp_addr.o: ../../include/inet_proto.h
 lmtp_addr.o: ../../include/mail_params.h
 lmtp_addr.o: ../../include/msg.h
+lmtp_addr.o: ../../include/msg_stats.h
 lmtp_addr.o: ../../include/myaddrinfo.h
 lmtp_addr.o: ../../include/mymalloc.h
 lmtp_addr.o: ../../include/own_inet_addr.h
@@ -108,6 +112,7 @@ lmtp_addr.o: lmtp.h
 lmtp_addr.o: lmtp_addr.c
 lmtp_addr.o: lmtp_addr.h
 lmtp_chat.o: ../../include/argv.h
+lmtp_chat.o: ../../include/attr.h
 lmtp_chat.o: ../../include/cleanup_user.h
 lmtp_chat.o: ../../include/deliver_request.h
 lmtp_chat.o: ../../include/dsn.h
@@ -118,6 +123,7 @@ lmtp_chat.o: ../../include/mail_addr.h
 lmtp_chat.o: ../../include/mail_error.h
 lmtp_chat.o: ../../include/mail_params.h
 lmtp_chat.o: ../../include/msg.h
+lmtp_chat.o: ../../include/msg_stats.h
 lmtp_chat.o: ../../include/mymalloc.h
 lmtp_chat.o: ../../include/name_mask.h
 lmtp_chat.o: ../../include/post_mail.h
@@ -142,6 +148,7 @@ lmtp_connect.o: ../../include/iostuff.h
 lmtp_connect.o: ../../include/mail_params.h
 lmtp_connect.o: ../../include/mail_proto.h
 lmtp_connect.o: ../../include/msg.h
+lmtp_connect.o: ../../include/msg_stats.h
 lmtp_connect.o: ../../include/myaddrinfo.h
 lmtp_connect.o: ../../include/mymalloc.h
 lmtp_connect.o: ../../include/own_inet_addr.h
@@ -159,9 +166,11 @@ lmtp_connect.o: lmtp.h
 lmtp_connect.o: lmtp_addr.h
 lmtp_connect.o: lmtp_connect.c
 lmtp_dsn.o: ../../include/argv.h
+lmtp_dsn.o: ../../include/attr.h
 lmtp_dsn.o: ../../include/deliver_request.h
 lmtp_dsn.o: ../../include/dsn.h
 lmtp_dsn.o: ../../include/dsn_buf.h
+lmtp_dsn.o: ../../include/msg_stats.h
 lmtp_dsn.o: ../../include/recipient_list.h
 lmtp_dsn.o: ../../include/sys_defs.h
 lmtp_dsn.o: ../../include/vbuf.h
@@ -184,6 +193,7 @@ lmtp_proto.o: ../../include/mail_proto.h
 lmtp_proto.o: ../../include/mail_queue.h
 lmtp_proto.o: ../../include/mark_corrupt.h
 lmtp_proto.o: ../../include/msg.h
+lmtp_proto.o: ../../include/msg_stats.h
 lmtp_proto.o: ../../include/mymalloc.h
 lmtp_proto.o: ../../include/name_code.h
 lmtp_proto.o: ../../include/off_cvt.h
@@ -206,6 +216,7 @@ lmtp_proto.o: lmtp.h
 lmtp_proto.o: lmtp_proto.c
 lmtp_proto.o: lmtp_sasl.h
 lmtp_rcpt.o: ../../include/argv.h
+lmtp_rcpt.o: ../../include/attr.h
 lmtp_rcpt.o: ../../include/bounce.h
 lmtp_rcpt.o: ../../include/deliver_completed.h
 lmtp_rcpt.o: ../../include/deliver_request.h
@@ -213,6 +224,7 @@ lmtp_rcpt.o: ../../include/dsn.h
 lmtp_rcpt.o: ../../include/dsn_buf.h
 lmtp_rcpt.o: ../../include/dsn_mask.h
 lmtp_rcpt.o: ../../include/msg.h
+lmtp_rcpt.o: ../../include/msg_stats.h
 lmtp_rcpt.o: ../../include/recipient_list.h
 lmtp_rcpt.o: ../../include/sent.h
 lmtp_rcpt.o: ../../include/sys_defs.h
@@ -222,6 +234,7 @@ lmtp_rcpt.o: ../../include/vstring.h
 lmtp_rcpt.o: lmtp.h
 lmtp_rcpt.o: lmtp_rcpt.c
 lmtp_sasl_glue.o: ../../include/argv.h
+lmtp_sasl_glue.o: ../../include/attr.h
 lmtp_sasl_glue.o: ../../include/deliver_request.h
 lmtp_sasl_glue.o: ../../include/dict.h
 lmtp_sasl_glue.o: ../../include/dsn.h
@@ -231,6 +244,7 @@ lmtp_sasl_glue.o: ../../include/maps.h
 lmtp_sasl_glue.o: ../../include/match_list.h
 lmtp_sasl_glue.o: ../../include/match_ops.h
 lmtp_sasl_glue.o: ../../include/msg.h
+lmtp_sasl_glue.o: ../../include/msg_stats.h
 lmtp_sasl_glue.o: ../../include/mymalloc.h
 lmtp_sasl_glue.o: ../../include/name_mask.h
 lmtp_sasl_glue.o: ../../include/recipient_list.h
@@ -245,11 +259,13 @@ lmtp_sasl_glue.o: lmtp.h
 lmtp_sasl_glue.o: lmtp_sasl.h
 lmtp_sasl_glue.o: lmtp_sasl_glue.c
 lmtp_sasl_proto.o: ../../include/argv.h
+lmtp_sasl_proto.o: ../../include/attr.h
 lmtp_sasl_proto.o: ../../include/deliver_request.h
 lmtp_sasl_proto.o: ../../include/dsn.h
 lmtp_sasl_proto.o: ../../include/dsn_buf.h
 lmtp_sasl_proto.o: ../../include/mail_params.h
 lmtp_sasl_proto.o: ../../include/msg.h
+lmtp_sasl_proto.o: ../../include/msg_stats.h
 lmtp_sasl_proto.o: ../../include/mymalloc.h
 lmtp_sasl_proto.o: ../../include/recipient_list.h
 lmtp_sasl_proto.o: ../../include/sys_defs.h
@@ -260,10 +276,12 @@ lmtp_sasl_proto.o: lmtp.h
 lmtp_sasl_proto.o: lmtp_sasl.h
 lmtp_sasl_proto.o: lmtp_sasl_proto.c
 lmtp_session.o: ../../include/argv.h
+lmtp_session.o: ../../include/attr.h
 lmtp_session.o: ../../include/debug_peer.h
 lmtp_session.o: ../../include/deliver_request.h
 lmtp_session.o: ../../include/dsn.h
 lmtp_session.o: ../../include/dsn_buf.h
+lmtp_session.o: ../../include/msg_stats.h
 lmtp_session.o: ../../include/mymalloc.h
 lmtp_session.o: ../../include/recipient_list.h
 lmtp_session.o: ../../include/stringops.h
@@ -274,10 +292,12 @@ lmtp_session.o: ../../include/vstring.h
 lmtp_session.o: lmtp.h
 lmtp_session.o: lmtp_session.c
 lmtp_state.o: ../../include/argv.h
+lmtp_state.o: ../../include/attr.h
 lmtp_state.o: ../../include/deliver_request.h
 lmtp_state.o: ../../include/dsn.h
 lmtp_state.o: ../../include/dsn_buf.h
 lmtp_state.o: ../../include/mail_conf.h
+lmtp_state.o: ../../include/msg_stats.h
 lmtp_state.o: ../../include/mymalloc.h
 lmtp_state.o: ../../include/recipient_list.h
 lmtp_state.o: ../../include/sys_defs.h
@@ -288,6 +308,7 @@ lmtp_state.o: lmtp.h
 lmtp_state.o: lmtp_sasl.h
 lmtp_state.o: lmtp_state.c
 lmtp_trouble.o: ../../include/argv.h
+lmtp_trouble.o: ../../include/attr.h
 lmtp_trouble.o: ../../include/bounce.h
 lmtp_trouble.o: ../../include/defer.h
 lmtp_trouble.o: ../../include/deliver_completed.h
@@ -296,6 +317,7 @@ lmtp_trouble.o: ../../include/dsn.h
 lmtp_trouble.o: ../../include/dsn_buf.h
 lmtp_trouble.o: ../../include/mail_error.h
 lmtp_trouble.o: ../../include/msg.h
+lmtp_trouble.o: ../../include/msg_stats.h
 lmtp_trouble.o: ../../include/name_mask.h
 lmtp_trouble.o: ../../include/recipient_list.h
 lmtp_trouble.o: ../../include/smtp_stream.h
index be74607508f60d9c4df50761ad22a9a3a1070b96..40eb6cbdda92583c6fd793b0881875ec8c02a0b4 100644 (file)
@@ -437,6 +437,7 @@ static int lmtp_loop(LMTP_STATE *state, NOCLOBBER int send_state,
             * Build the MAIL FROM command.
             */
        case LMTP_STATE_MAIL:
+           GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
            REWRITE_ADDRESS(state->scratch, request->sender);
            vstring_sprintf(next_command, "MAIL FROM:<%s>",
                            vstring_str(state->scratch));
@@ -710,6 +711,7 @@ static int lmtp_loop(LMTP_STATE *state, NOCLOBBER int send_state,
                     * delivered.
                     */
                case LMTP_STATE_DOT:
+                   GETTIMEOFDAY(&request->msg_stats.deliver_done);
                    if (nrcpt > 0) {
                        rcpt = request->rcpt_list.info + survivors[recv_dot];
                        if (resp->code / 100 == 2) {
index 612d7f1ea956748c2234a14b41ffeabf09bc2220..8d2b3e010430eb44b649a61b1f7d47f71f4177d7 100644 (file)
@@ -72,7 +72,7 @@ void    lmtp_rcpt_done(LMTP_STATE *state, LMTP_RESP *resp, RECIPIENT *rcpt)
                           resp->str, resp->str);
 
     status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
-                 request->queue_id, request->arrival_time, rcpt,
+                 request->queue_id, &request->msg_stats, rcpt,
                  session->namaddr, &dsn);
     if (status == 0) {
        if (request->flags & DEL_REQ_FLAG_SUCCESS)
index ce09667391f83f16e8f4a6e6f2c44793f0b6d59a..5ef08f9a220d1e9c07c741681187a0e7888deaa8 100644 (file)
@@ -182,6 +182,22 @@ static int lmtp_bulk_fail(LMTP_STATE *state, DSN *dsn, int throttle_queue)
     int     soft_error = (dsn->dtext[0] == '4');
     int     nrcpt;
 
+    /*
+     * If we are still in the connection set-up phase, update the set-up
+     * completion time here, otherwise the time spent in set-up latency will
+     * be attributed as message transfer latency.
+     * 
+     * All remaining recipients failed at this point, so we update the delivery
+     * completion time stamp so that multiple recipient status records show
+     * the same delay values.
+     */
+    if (request->msg_stats.conn_setup_done.tv_sec == 0) {
+       GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
+       request->msg_stats.deliver_done =
+           request->msg_stats.conn_setup_done;
+    } else
+       GETTIMEOFDAY(&request->msg_stats.deliver_done);
+
     /*
      * If this is a soft error, postpone further deliveries to this domain.
      * Otherwise, generate a bounce record for each recipient.
@@ -192,7 +208,7 @@ static int lmtp_bulk_fail(LMTP_STATE *state, DSN *dsn, int throttle_queue)
            continue;
        status = (soft_error ? defer_append : bounce_append)
            (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
-            request->arrival_time, rcpt,
+            &request->msg_stats, rcpt,
             session ? session->namaddr : "none", dsn);
        if (status == 0) {
            deliver_completed(state->src, rcpt->offset);
@@ -338,7 +354,7 @@ void    lmtp_rcpt_fail(LMTP_STATE *state, const char *mta_name, LMTP_RESP *resp,
      */
     status = (soft_error ? defer_append : bounce_append)
        (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
-        request->arrival_time, rcpt,
+        &request->msg_stats, rcpt,
         session ? session->namaddr : "none", &dsn);
     if (status == 0) {
        deliver_completed(state->src, rcpt->offset);
index 67e85f9e4a7aec8d88fb42137daeafb76623521e..e099b1e4f7ef961bbb2338ace1ff99d9bd185ec9 100644 (file)
@@ -63,6 +63,7 @@ depend: $(MAKES)
 
 # do not edit below this line - it is generated by 'make depend'
 alias.o: ../../include/argv.h
+alias.o: ../../include/attr.h
 alias.o: ../../include/been_here.h
 alias.o: ../../include/bounce.h
 alias.o: ../../include/canon_addr.h
@@ -77,6 +78,7 @@ alias.o: ../../include/mail_params.h
 alias.o: ../../include/maps.h
 alias.o: ../../include/mbox_conf.h
 alias.o: ../../include/msg.h
+alias.o: ../../include/msg_stats.h
 alias.o: ../../include/mymalloc.h
 alias.o: ../../include/mypwd.h
 alias.o: ../../include/recipient_list.h
@@ -96,6 +98,7 @@ biff_notify.o: ../../include/sys_defs.h
 biff_notify.o: biff_notify.c
 biff_notify.o: biff_notify.h
 command.o: ../../include/argv.h
+command.o: ../../include/attr.h
 command.o: ../../include/been_here.h
 command.o: ../../include/bounce.h
 command.o: ../../include/defer.h
@@ -111,6 +114,7 @@ command.o: ../../include/mail_params.h
 command.o: ../../include/maps.h
 command.o: ../../include/mbox_conf.h
 command.o: ../../include/msg.h
+command.o: ../../include/msg_stats.h
 command.o: ../../include/pipe_command.h
 command.o: ../../include/recipient_list.h
 command.o: ../../include/resolve_clnt.h
@@ -123,6 +127,7 @@ command.o: ../../include/vstring.h
 command.o: command.c
 command.o: local.h
 deliver_attr.o: ../../include/argv.h
+deliver_attr.o: ../../include/attr.h
 deliver_attr.o: ../../include/been_here.h
 deliver_attr.o: ../../include/deliver_request.h
 deliver_attr.o: ../../include/dict.h
@@ -132,6 +137,7 @@ deliver_attr.o: ../../include/htable.h
 deliver_attr.o: ../../include/maps.h
 deliver_attr.o: ../../include/mbox_conf.h
 deliver_attr.o: ../../include/msg.h
+deliver_attr.o: ../../include/msg_stats.h
 deliver_attr.o: ../../include/recipient_list.h
 deliver_attr.o: ../../include/resolve_clnt.h
 deliver_attr.o: ../../include/sys_defs.h
@@ -142,6 +148,7 @@ deliver_attr.o: ../../include/vstring.h
 deliver_attr.o: deliver_attr.c
 deliver_attr.o: local.h
 delivered.o: ../../include/argv.h
+delivered.o: ../../include/attr.h
 delivered.o: ../../include/been_here.h
 delivered.o: ../../include/deliver_request.h
 delivered.o: ../../include/dict.h
@@ -153,6 +160,7 @@ delivered.o: ../../include/is_header.h
 delivered.o: ../../include/maps.h
 delivered.o: ../../include/mbox_conf.h
 delivered.o: ../../include/msg.h
+delivered.o: ../../include/msg_stats.h
 delivered.o: ../../include/quote_822_local.h
 delivered.o: ../../include/quote_flags.h
 delivered.o: ../../include/rec_type.h
@@ -169,6 +177,7 @@ delivered.o: ../../include/vstring_vstream.h
 delivered.o: delivered.c
 delivered.o: local.h
 dotforward.o: ../../include/argv.h
+dotforward.o: ../../include/attr.h
 dotforward.o: ../../include/been_here.h
 dotforward.o: ../../include/bounce.h
 dotforward.o: ../../include/deliver_request.h
@@ -187,6 +196,7 @@ dotforward.o: ../../include/mail_params.h
 dotforward.o: ../../include/maps.h
 dotforward.o: ../../include/mbox_conf.h
 dotforward.o: ../../include/msg.h
+dotforward.o: ../../include/msg_stats.h
 dotforward.o: ../../include/mymalloc.h
 dotforward.o: ../../include/mypwd.h
 dotforward.o: ../../include/open_as.h
@@ -203,6 +213,7 @@ dotforward.o: ../../include/vstring.h
 dotforward.o: dotforward.c
 dotforward.o: local.h
 file.o: ../../include/argv.h
+file.o: ../../include/attr.h
 file.o: ../../include/been_here.h
 file.o: ../../include/bounce.h
 file.o: ../../include/defer.h
@@ -219,6 +230,7 @@ file.o: ../../include/maps.h
 file.o: ../../include/mbox_conf.h
 file.o: ../../include/mbox_open.h
 file.o: ../../include/msg.h
+file.o: ../../include/msg_stats.h
 file.o: ../../include/myflock.h
 file.o: ../../include/recipient_list.h
 file.o: ../../include/resolve_clnt.h
@@ -251,6 +263,7 @@ forward.o: ../../include/maps.h
 forward.o: ../../include/mark_corrupt.h
 forward.o: ../../include/mbox_conf.h
 forward.o: ../../include/msg.h
+forward.o: ../../include/msg_stats.h
 forward.o: ../../include/mymalloc.h
 forward.o: ../../include/rec_type.h
 forward.o: ../../include/recipient_list.h
@@ -267,6 +280,7 @@ forward.o: ../../include/vstring_vstream.h
 forward.o: forward.c
 forward.o: local.h
 include.o: ../../include/argv.h
+include.o: ../../include/attr.h
 include.o: ../../include/been_here.h
 include.o: ../../include/bounce.h
 include.o: ../../include/defer.h
@@ -281,6 +295,7 @@ include.o: ../../include/mail_params.h
 include.o: ../../include/maps.h
 include.o: ../../include/mbox_conf.h
 include.o: ../../include/msg.h
+include.o: ../../include/msg_stats.h
 include.o: ../../include/mymalloc.h
 include.o: ../../include/mypwd.h
 include.o: ../../include/open_as.h
@@ -296,6 +311,7 @@ include.o: ../../include/vstring.h
 include.o: include.c
 include.o: local.h
 indirect.o: ../../include/argv.h
+indirect.o: ../../include/attr.h
 indirect.o: ../../include/been_here.h
 indirect.o: ../../include/bounce.h
 indirect.o: ../../include/defer.h
@@ -308,6 +324,7 @@ indirect.o: ../../include/mail_params.h
 indirect.o: ../../include/maps.h
 indirect.o: ../../include/mbox_conf.h
 indirect.o: ../../include/msg.h
+indirect.o: ../../include/msg_stats.h
 indirect.o: ../../include/recipient_list.h
 indirect.o: ../../include/resolve_clnt.h
 indirect.o: ../../include/sent.h
@@ -319,6 +336,7 @@ indirect.o: ../../include/vstring.h
 indirect.o: indirect.c
 indirect.o: local.h
 local.o: ../../include/argv.h
+local.o: ../../include/attr.h
 local.o: ../../include/been_here.h
 local.o: ../../include/deliver_completed.h
 local.o: ../../include/deliver_request.h
@@ -336,6 +354,7 @@ local.o: ../../include/mail_server.h
 local.o: ../../include/maps.h
 local.o: ../../include/mbox_conf.h
 local.o: ../../include/msg.h
+local.o: ../../include/msg_stats.h
 local.o: ../../include/mymalloc.h
 local.o: ../../include/name_mask.h
 local.o: ../../include/recipient_list.h
@@ -349,6 +368,7 @@ local.o: ../../include/vstring.h
 local.o: local.c
 local.o: local.h
 local_expand.o: ../../include/argv.h
+local_expand.o: ../../include/attr.h
 local_expand.o: ../../include/been_here.h
 local_expand.o: ../../include/deliver_request.h
 local_expand.o: ../../include/dict.h
@@ -360,6 +380,7 @@ local_expand.o: ../../include/mac_parse.h
 local_expand.o: ../../include/mail_params.h
 local_expand.o: ../../include/maps.h
 local_expand.o: ../../include/mbox_conf.h
+local_expand.o: ../../include/msg_stats.h
 local_expand.o: ../../include/recipient_list.h
 local_expand.o: ../../include/resolve_clnt.h
 local_expand.o: ../../include/sys_defs.h
@@ -389,6 +410,7 @@ mailbox.o: ../../include/maps.h
 mailbox.o: ../../include/mbox_conf.h
 mailbox.o: ../../include/mbox_open.h
 mailbox.o: ../../include/msg.h
+mailbox.o: ../../include/msg_stats.h
 mailbox.o: ../../include/mymalloc.h
 mailbox.o: ../../include/mypwd.h
 mailbox.o: ../../include/recipient_list.h
@@ -406,6 +428,7 @@ mailbox.o: biff_notify.h
 mailbox.o: local.h
 mailbox.o: mailbox.c
 maildir.o: ../../include/argv.h
+maildir.o: ../../include/attr.h
 maildir.o: ../../include/been_here.h
 maildir.o: ../../include/bounce.h
 maildir.o: ../../include/defer.h
@@ -423,6 +446,7 @@ maildir.o: ../../include/maps.h
 maildir.o: ../../include/mbox_conf.h
 maildir.o: ../../include/mbox_open.h
 maildir.o: ../../include/msg.h
+maildir.o: ../../include/msg_stats.h
 maildir.o: ../../include/mymalloc.h
 maildir.o: ../../include/recipient_list.h
 maildir.o: ../../include/resolve_clnt.h
@@ -439,6 +463,7 @@ maildir.o: ../../include/vstring.h
 maildir.o: local.h
 maildir.o: maildir.c
 recipient.o: ../../include/argv.h
+recipient.o: ../../include/attr.h
 recipient.o: ../../include/been_here.h
 recipient.o: ../../include/bounce.h
 recipient.o: ../../include/canon_addr.h
@@ -453,6 +478,7 @@ recipient.o: ../../include/mail_params.h
 recipient.o: ../../include/maps.h
 recipient.o: ../../include/mbox_conf.h
 recipient.o: ../../include/msg.h
+recipient.o: ../../include/msg_stats.h
 recipient.o: ../../include/mymalloc.h
 recipient.o: ../../include/mypwd.h
 recipient.o: ../../include/recipient_list.h
@@ -485,6 +511,7 @@ resolve.o: ../../include/mail_proto.h
 resolve.o: ../../include/maps.h
 resolve.o: ../../include/mbox_conf.h
 resolve.o: ../../include/msg.h
+resolve.o: ../../include/msg_stats.h
 resolve.o: ../../include/recipient_list.h
 resolve.o: ../../include/resolve_clnt.h
 resolve.o: ../../include/rewrite_clnt.h
@@ -496,6 +523,7 @@ resolve.o: ../../include/vstring.h
 resolve.o: local.h
 resolve.o: resolve.c
 token.o: ../../include/argv.h
+token.o: ../../include/attr.h
 token.o: ../../include/been_here.h
 token.o: ../../include/bounce.h
 token.o: ../../include/defer.h
@@ -508,6 +536,7 @@ token.o: ../../include/mail_params.h
 token.o: ../../include/maps.h
 token.o: ../../include/mbox_conf.h
 token.o: ../../include/msg.h
+token.o: ../../include/msg_stats.h
 token.o: ../../include/mymalloc.h
 token.o: ../../include/readlline.h
 token.o: ../../include/recipient_list.h
@@ -538,6 +567,7 @@ unknown.o: ../../include/mail_proto.h
 unknown.o: ../../include/maps.h
 unknown.o: ../../include/mbox_conf.h
 unknown.o: ../../include/msg.h
+unknown.o: ../../include/msg_stats.h
 unknown.o: ../../include/mymalloc.h
 unknown.o: ../../include/recipient_list.h
 unknown.o: ../../include/resolve_clnt.h
index d01207be71dd5a86f2af00d16f9639f0c99a7557..d505469a19d173a4b91df86fd94dcdaceca71181 100644 (file)
@@ -663,7 +663,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
     state.msg_attr.dsn_envid = rqst->dsn_envid;
     state.msg_attr.dsn_ret = rqst->dsn_ret;
     state.msg_attr.relay = service;
-    state.msg_attr.arrival_time = rqst->arrival_time;
+    state.msg_attr.msg_stats = rqst->msg_stats;
     state.msg_attr.request = rqst;
     RESET_OWNER_ATTR(state.msg_attr, state.level);
     RESET_USER_ATTR(usr_attr, state.level);
index d1dc5d07e3d5b4bb982d606dc87dbc248db3ff4e..2e3d79359d72ee528c1bc1ea56e59fafd07c11be 100644 (file)
@@ -83,7 +83,7 @@ typedef struct DELIVER_ATTR {
     const char *owner;                 /* null or list owner */
     const char *delivered;             /* for loop detection */
     char   *relay;                     /* relay host */
-    long    arrival_time;              /* arrival time */
+    MSG_STATS msg_stats;               /* time profile */
     int     exp_type;                  /* expansion type. see below */
     char   *exp_from;                  /* expanded_from */
     DELIVER_REQUEST *request;          /* the kitchen sink */
@@ -131,15 +131,15 @@ typedef struct LOCAL_STATE {
 #define BOUNCE_FLAGS(request)  DEL_REQ_TRACE_FLAGS((request)->flags)
 
 #define BOUNCE_ATTR(attr) \
-       attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+       attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
        DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
 #define BOUNCE_ONE_ATTR(attr) \
        attr.queue_name, attr.queue_id, attr.encoding, \
        attr.sender, attr.dsn_envid, attr.dsn_ret, \
-       attr.arrival_time, &attr.rcpt, attr.relay, \
+       &attr.msg_stats, &attr.rcpt, attr.relay, \
        DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
 #define SENT_ATTR(attr) \
-       attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+       attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
        DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
 #define OPENED_ATTR(attr) \
        attr.queue_id, attr.sender
index a9783c421c0659cf00fb93d50d50d9dd0a13645e..39c95e71ee4118e69b4863027ee80c4173c364df 100644 (file)
@@ -85,6 +85,7 @@ qmgr.o: ../../include/vstring.h
 qmgr.o: qmgr.c
 qmgr.o: qmgr.h
 qmgr_active.o: ../../include/abounce.h
+qmgr_active.o: ../../include/attr.h
 qmgr_active.o: ../../include/bounce.h
 qmgr_active.o: ../../include/defer.h
 qmgr_active.o: ../../include/deliver_request.h
@@ -96,6 +97,7 @@ qmgr_active.o: ../../include/mail_open_ok.h
 qmgr_active.o: ../../include/mail_params.h
 qmgr_active.o: ../../include/mail_queue.h
 qmgr_active.o: ../../include/msg.h
+qmgr_active.o: ../../include/msg_stats.h
 qmgr_active.o: ../../include/mymalloc.h
 qmgr_active.o: ../../include/qmgr_user.h
 qmgr_active.o: ../../include/rec_type.h
@@ -108,11 +110,13 @@ qmgr_active.o: ../../include/vstream.h
 qmgr_active.o: ../../include/vstring.h
 qmgr_active.o: qmgr.h
 qmgr_active.o: qmgr_active.c
+qmgr_bounce.o: ../../include/attr.h
 qmgr_bounce.o: ../../include/bounce.h
 qmgr_bounce.o: ../../include/deliver_completed.h
 qmgr_bounce.o: ../../include/deliver_request.h
 qmgr_bounce.o: ../../include/dsn.h
 qmgr_bounce.o: ../../include/dsn_buf.h
+qmgr_bounce.o: ../../include/msg_stats.h
 qmgr_bounce.o: ../../include/recipient_list.h
 qmgr_bounce.o: ../../include/scan_dir.h
 qmgr_bounce.o: ../../include/sys_defs.h
@@ -121,12 +125,14 @@ qmgr_bounce.o: ../../include/vstream.h
 qmgr_bounce.o: ../../include/vstring.h
 qmgr_bounce.o: qmgr.h
 qmgr_bounce.o: qmgr_bounce.c
+qmgr_defer.o: ../../include/attr.h
 qmgr_defer.o: ../../include/bounce.h
 qmgr_defer.o: ../../include/defer.h
 qmgr_defer.o: ../../include/deliver_request.h
 qmgr_defer.o: ../../include/dsn.h
 qmgr_defer.o: ../../include/dsn_buf.h
 qmgr_defer.o: ../../include/msg.h
+qmgr_defer.o: ../../include/msg_stats.h
 qmgr_defer.o: ../../include/recipient_list.h
 qmgr_defer.o: ../../include/scan_dir.h
 qmgr_defer.o: ../../include/sys_defs.h
@@ -147,6 +153,7 @@ qmgr_deliver.o: ../../include/mail_params.h
 qmgr_deliver.o: ../../include/mail_proto.h
 qmgr_deliver.o: ../../include/mail_queue.h
 qmgr_deliver.o: ../../include/msg.h
+qmgr_deliver.o: ../../include/msg_stats.h
 qmgr_deliver.o: ../../include/recipient_list.h
 qmgr_deliver.o: ../../include/scan_dir.h
 qmgr_deliver.o: ../../include/stringops.h
@@ -169,12 +176,14 @@ qmgr_enable.o: ../../include/vstream.h
 qmgr_enable.o: ../../include/vstring.h
 qmgr_enable.o: qmgr.h
 qmgr_enable.o: qmgr_enable.c
+qmgr_entry.o: ../../include/attr.h
 qmgr_entry.o: ../../include/deliver_request.h
 qmgr_entry.o: ../../include/dsn.h
 qmgr_entry.o: ../../include/dsn_buf.h
 qmgr_entry.o: ../../include/events.h
 qmgr_entry.o: ../../include/mail_params.h
 qmgr_entry.o: ../../include/msg.h
+qmgr_entry.o: ../../include/msg_stats.h
 qmgr_entry.o: ../../include/mymalloc.h
 qmgr_entry.o: ../../include/recipient_list.h
 qmgr_entry.o: ../../include/scan_dir.h
@@ -200,6 +209,7 @@ qmgr_message.o: ../../include/mail_params.h
 qmgr_message.o: ../../include/mail_proto.h
 qmgr_message.o: ../../include/mail_queue.h
 qmgr_message.o: ../../include/msg.h
+qmgr_message.o: ../../include/msg_stats.h
 qmgr_message.o: ../../include/myflock.h
 qmgr_message.o: ../../include/mymalloc.h
 qmgr_message.o: ../../include/opened.h
index 7e35ec8c50d9e7f31d94ee8c9ded65c5fd3761f8..1ce8bc37767427c1dbab7011e30965ac996f04f5 100644 (file)
@@ -8,6 +8,12 @@
 /* DESCRIPTION
 /* .nf
 
+ /*
+  * System library.
+  */
+#include <sys/time.h>
+#include <time.h>
+
  /*
   * Utility library.
   */
@@ -155,7 +161,7 @@ struct QMGR_QUEUE {
     QMGR_ENTRY_LIST todo;              /* todo queue entries */
     QMGR_ENTRY_LIST busy;              /* messages on the wire */
     QMGR_QUEUE_LIST peers;             /* neighbor queues */
-    DSN   *dsn;                        /* why unavailable */
+    DSN    *dsn;                       /* why unavailable */
     time_t  clog_time_to_warn;         /* time of next warning */
 };
 
@@ -204,6 +210,7 @@ struct QMGR_MESSAGE {
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
     long    arrival_time;              /* time when queued */
+    struct timeval active_time;                /* time of entry into active queue */
     long    warn_offset;               /* warning bounce flag offset */
     time_t  warn_time;                 /* time next warning to be sent */
     long    data_offset;               /* data seek offset */
@@ -246,6 +253,11 @@ extern void qmgr_message_kill_record(QMGR_MESSAGE *, long);
 extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int);
 extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
 
+#define QMGR_MSG_STATS(stats, message) \
+    MSG_STATS_INIT2(stats, \
+                   incoming_arrival, message->arrival_time, \
+                   active_arrival, message->active_time)
+
  /*
   * qmgr_defer.c
   */
index 5a763042d466f11ca46ab7423e907d23191834fd..00ba885bf98fb7aea993eed765feb1668fd3edf2 100644 (file)
 void    qmgr_bounce_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
                                      DSN *dsn)
 {
+    MSG_STATS stats;
     int     status;
 
     status = bounce_append(message->tflags, message->queue_id,
-                          message->arrival_time, recipient,
+                          QMGR_MSG_STATS(&stats, message), recipient,
                           "none", dsn);
 
     if (status == 0)
index 234632cc217e0c33623f62511c835a477285f2d8..51eaf8643890b79d2603358059525a6195d5c973 100644 (file)
@@ -133,11 +133,12 @@ void    qmgr_defer_todo(QMGR_QUEUE *queue, DSN *dsn)
 void    qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
                                     DSN *dsn)
 {
+    MSG_STATS stats;
 
     /*
      * Update the message structure and log the message disposition.
      */
     message->flags |= defer_append(message->tflags, message->queue_id,
-                                  message->arrival_time, recipient,
+                                QMGR_MSG_STATS(&stats, message), recipient,
                                   "none", dsn);
 }
index 38b55198c4416bf94cb6d2389697ab6800b9416b..b3e4cd65685638a176c7de803ee4e50e9f563cf4 100644 (file)
@@ -129,6 +129,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     RECIPIENT *recipient;
     QMGR_MESSAGE *message = entry->message;
     VSTRING *sender_buf = 0;
+    MSG_STATS stats;
     char   *sender;
     int     flags;
 
@@ -149,6 +150,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     flags = message->tflags
        | entry->queue->dflags
        | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
+    QMGR_MSG_STATS(&stats, message);
     attr_print(stream, ATTR_FLAG_MORE,
               ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
               ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
@@ -160,7 +162,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
               ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
               ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, message->dsn_envid,
               ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, message->dsn_ret,
-              ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time,
+              ATTR_TYPE_FUNC, msg_stats_print, (void *) &stats,
               ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name,
               ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr,
               ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto,
index 6df21567968a1df08fbe358adeb6585ca55d100c..cae8af5028b97d30177a5b3dbb82693a60f1d781 100644 (file)
@@ -156,6 +156,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     message->refcount = 0;
     message->single_rcpt = 0;
     message->arrival_time = 0;
+    GETTIMEOFDAY(&message->active_time);
     message->data_offset = 0;
     message->queue_id = mystrdup(queue_id);
     message->queue_name = mystrdup(queue_name);
@@ -883,6 +884,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
     ssize_t len;
     int     status;
     DSN     dsn;
+    MSG_STATS stats;
 
 #define STREQ(x,y)     (strcmp(x,y) == 0)
 #define STR            vstring_str
@@ -996,7 +998,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                            len) == 0
                && !var_double_bounce_sender[len]) {
                status = sent(message->tflags, message->queue_id,
-                             message->arrival_time, recipient,
+                             QMGR_MSG_STATS(&stats, message), recipient,
                              "none", DSN_SIMPLE(&dsn, "2.0.0",
                        "undeliverable postmaster notification discarded"));
                if (status == 0) {
index fd0419281c9c4fb8986d1cc782ef2003550809c7..f4dde9603b15e7750fb7ffdfa7414447479472af 100644 (file)
@@ -56,6 +56,7 @@ depend: $(MAKES)
 
 # do not edit below this line - it is generated by 'make depend'
 pipe.o: ../../include/argv.h
+pipe.o: ../../include/attr.h
 pipe.o: ../../include/bounce.h
 pipe.o: ../../include/canon_addr.h
 pipe.o: ../../include/defer.h
@@ -75,6 +76,7 @@ pipe.o: ../../include/mail_copy.h
 pipe.o: ../../include/mail_params.h
 pipe.o: ../../include/mail_server.h
 pipe.o: ../../include/msg.h
+pipe.o: ../../include/msg_stats.h
 pipe.o: ../../include/mymalloc.h
 pipe.o: ../../include/off_cvt.h
 pipe.o: ../../include/pipe_command.h
index 795030d48cd93322127214a0076243328aee13fe..921f6e40e9cd4f60c0a05f89196088c12ff4711b 100644 (file)
@@ -893,7 +893,7 @@ static int eval_command_status(int command_status, char *service,
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
            status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
-                         request->queue_id, request->arrival_time, rcpt,
+                         request->queue_id, &request->msg_stats, rcpt,
                          service, &dsn);
            if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
                deliver_completed(src, rcpt->offset);
@@ -908,7 +908,7 @@ static int eval_command_status(int command_status, char *service,
                rcpt = request->rcpt_list.info + n;
                status = bounce_append(DEL_REQ_TRACE_FLAGS(request->flags),
                                       request->queue_id,
-                                      request->arrival_time, rcpt,
+                                      &request->msg_stats, rcpt,
                                       service, &dsn);
                if (status == 0)
                    deliver_completed(src, rcpt->offset);
@@ -919,7 +919,7 @@ static int eval_command_status(int command_status, char *service,
                rcpt = request->rcpt_list.info + n;
                result |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
                                       request->queue_id,
-                                      request->arrival_time, rcpt,
+                                      &request->msg_stats, rcpt,
                                       service, &dsn);
            }
        }
@@ -1029,7 +1029,7 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
        for (n = 0; n < request->rcpt_list.len; n++) {
            rcpt = request->rcpt_list.info + n;
            status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
-                         request->queue_id, request->arrival_time,
+                         request->queue_id, &request->msg_stats,
                          rcpt, service, DSN_FROM_DSN_BUF(&dsn, why));
            if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
                deliver_completed(request->fp, rcpt->offset);
index 5565d65d6113ee9cad4a369532b8399aed9dc766..04f540c9ac9e7d2ab627fd65540e0e31e7cbd086 100644 (file)
@@ -87,6 +87,7 @@ qmgr.o: ../../include/vstring.h
 qmgr.o: qmgr.c
 qmgr.o: qmgr.h
 qmgr_active.o: ../../include/abounce.h
+qmgr_active.o: ../../include/attr.h
 qmgr_active.o: ../../include/bounce.h
 qmgr_active.o: ../../include/defer.h
 qmgr_active.o: ../../include/deliver_request.h
@@ -98,6 +99,7 @@ qmgr_active.o: ../../include/mail_open_ok.h
 qmgr_active.o: ../../include/mail_params.h
 qmgr_active.o: ../../include/mail_queue.h
 qmgr_active.o: ../../include/msg.h
+qmgr_active.o: ../../include/msg_stats.h
 qmgr_active.o: ../../include/mymalloc.h
 qmgr_active.o: ../../include/qmgr_user.h
 qmgr_active.o: ../../include/rec_type.h
@@ -110,11 +112,13 @@ qmgr_active.o: ../../include/vstream.h
 qmgr_active.o: ../../include/vstring.h
 qmgr_active.o: qmgr.h
 qmgr_active.o: qmgr_active.c
+qmgr_bounce.o: ../../include/attr.h
 qmgr_bounce.o: ../../include/bounce.h
 qmgr_bounce.o: ../../include/deliver_completed.h
 qmgr_bounce.o: ../../include/deliver_request.h
 qmgr_bounce.o: ../../include/dsn.h
 qmgr_bounce.o: ../../include/dsn_buf.h
+qmgr_bounce.o: ../../include/msg_stats.h
 qmgr_bounce.o: ../../include/recipient_list.h
 qmgr_bounce.o: ../../include/scan_dir.h
 qmgr_bounce.o: ../../include/sys_defs.h
@@ -123,12 +127,14 @@ qmgr_bounce.o: ../../include/vstream.h
 qmgr_bounce.o: ../../include/vstring.h
 qmgr_bounce.o: qmgr.h
 qmgr_bounce.o: qmgr_bounce.c
+qmgr_defer.o: ../../include/attr.h
 qmgr_defer.o: ../../include/bounce.h
 qmgr_defer.o: ../../include/defer.h
 qmgr_defer.o: ../../include/deliver_request.h
 qmgr_defer.o: ../../include/dsn.h
 qmgr_defer.o: ../../include/dsn_buf.h
 qmgr_defer.o: ../../include/msg.h
+qmgr_defer.o: ../../include/msg_stats.h
 qmgr_defer.o: ../../include/recipient_list.h
 qmgr_defer.o: ../../include/scan_dir.h
 qmgr_defer.o: ../../include/sys_defs.h
@@ -149,6 +155,7 @@ qmgr_deliver.o: ../../include/mail_params.h
 qmgr_deliver.o: ../../include/mail_proto.h
 qmgr_deliver.o: ../../include/mail_queue.h
 qmgr_deliver.o: ../../include/msg.h
+qmgr_deliver.o: ../../include/msg_stats.h
 qmgr_deliver.o: ../../include/recipient_list.h
 qmgr_deliver.o: ../../include/scan_dir.h
 qmgr_deliver.o: ../../include/stringops.h
@@ -171,12 +178,14 @@ qmgr_enable.o: ../../include/vstream.h
 qmgr_enable.o: ../../include/vstring.h
 qmgr_enable.o: qmgr.h
 qmgr_enable.o: qmgr_enable.c
+qmgr_entry.o: ../../include/attr.h
 qmgr_entry.o: ../../include/deliver_request.h
 qmgr_entry.o: ../../include/dsn.h
 qmgr_entry.o: ../../include/dsn_buf.h
 qmgr_entry.o: ../../include/events.h
 qmgr_entry.o: ../../include/mail_params.h
 qmgr_entry.o: ../../include/msg.h
+qmgr_entry.o: ../../include/msg_stats.h
 qmgr_entry.o: ../../include/mymalloc.h
 qmgr_entry.o: ../../include/recipient_list.h
 qmgr_entry.o: ../../include/scan_dir.h
@@ -216,6 +225,7 @@ qmgr_message.o: ../../include/mail_params.h
 qmgr_message.o: ../../include/mail_proto.h
 qmgr_message.o: ../../include/mail_queue.h
 qmgr_message.o: ../../include/msg.h
+qmgr_message.o: ../../include/msg_stats.h
 qmgr_message.o: ../../include/myflock.h
 qmgr_message.o: ../../include/mymalloc.h
 qmgr_message.o: ../../include/opened.h
index a51fc032f543501dfbf2f1233298a0167839a77a..7225920eb8e73a24317e50bf5d058cbe57211db3 100644 (file)
@@ -8,6 +8,12 @@
 /* DESCRIPTION
 /* .nf
 
+ /*
+  * System library.
+  */
+#include <sys/time.h>
+#include <time.h>
+
  /*
   * Utility library.
   */
@@ -242,8 +248,9 @@ struct QMGR_MESSAGE {
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
     long    arrival_time;              /* time when queued */
-    time_t  queued_time;               /* time when moved to the active
-                                        * queue */
+    struct timeval active_time;                /* time of entry into active queue */
+    time_t  queued_time;               /* sanitized time when moved to the
+                                        * active queue */
     long    warn_offset;               /* warning bounce flag offset */
     time_t  warn_time;                 /* time next warning to be sent */
     long    data_offset;               /* data seek offset */
@@ -291,6 +298,11 @@ extern void qmgr_message_kill_record(QMGR_MESSAGE *, long);
 extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int);
 extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
 
+#define QMGR_MSG_STATS(stats, message) \
+    MSG_STATS_INIT2(stats, \
+                    incoming_arrival, message->arrival_time, \
+                    active_arrival, message->active_time)
+
  /*
   * Sometimes it's required to access the transport queues and entries on per
   * message basis. That's what the QMGR_JOB structure is for - it groups all
index 31ed814d3a2416a1f470cf5d22f5100b80e5730d..c5ea16178b47dd8a87338f6768431f2c6c446bf7 100644 (file)
 void    qmgr_bounce_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
                                      DSN *dsn)
 {
+    MSG_STATS stats;
     int     status;
 
     status = bounce_append(message->tflags, message->queue_id,
-                          message->arrival_time, recipient,
+                          QMGR_MSG_STATS(&stats, message), recipient,
                           "none", dsn);
 
     if (status == 0)
index 0c86131d278250de4983bf66f245fccc5432cda6..4c70eef76f9fe59fb6b588e42cd048228a4ae416 100644 (file)
@@ -138,11 +138,12 @@ void    qmgr_defer_todo(QMGR_QUEUE *queue, DSN *dsn)
 void    qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
                                     DSN *dsn)
 {
+    MSG_STATS stats;
 
     /*
      * Update the message structure and log the message disposition.
      */
     message->flags |= defer_append(message->tflags, message->queue_id,
-                                  message->arrival_time, recipient,
+                                QMGR_MSG_STATS(&stats, message), recipient,
                                   "none", dsn);
 }
index 38e9409796e378d74c44ab7af041c0c47fdafb45..28f0f2c46c05cdd81ce262ce85966a4a78716e2f 100644 (file)
@@ -134,6 +134,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     RECIPIENT *recipient;
     QMGR_MESSAGE *message = entry->message;
     VSTRING *sender_buf = 0;
+    MSG_STATS stats;
     char   *sender;
     int     flags;
 
@@ -154,6 +155,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     flags = message->tflags
        | entry->queue->dflags
        | (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
+    QMGR_MSG_STATS(&stats, message);
     attr_print(stream, ATTR_FLAG_MORE,
               ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
               ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
@@ -165,7 +167,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
               ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
               ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, message->dsn_envid,
               ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, message->dsn_ret,
-              ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time,
+              ATTR_TYPE_FUNC, msg_stats_print, (void *) &stats,
               ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name,
               ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr,
               ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto,
index e1868d6802306edc4952e06ba9c1e8805a263ea8..da481b847bf9fe02bc8a96049a4f6d67d1cca9ef 100644 (file)
@@ -165,6 +165,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     message->refcount = 0;
     message->single_rcpt = 0;
     message->arrival_time = 0;
+    GETTIMEOFDAY(&message->active_time);
     message->queued_time = sane_time();
     message->data_offset = 0;
     message->queue_id = mystrdup(queue_id);
@@ -925,6 +926,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
     ssize_t len;
     int     status;
     DSN     dsn;
+    MSG_STATS stats;
 
 #define STREQ(x,y)     (strcmp(x,y) == 0)
 #define STR            vstring_str
@@ -1038,7 +1040,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
                            len) == 0
                && !var_double_bounce_sender[len]) {
                status = sent(message->tflags, message->queue_id,
-                             message->arrival_time, recipient,
+                             QMGR_MSG_STATS(&stats, message), recipient,
                              "none", DSN_SIMPLE(&dsn, "2.0.0",
                        "undeliverable postmaster notification discarded"));
                if (status == 0) {
index d5a176ca27c369bf36cee877c7e30cae321fe23c..45f39128188bb00973d92527cebfe9403cf60104 100644 (file)
@@ -77,6 +77,7 @@ sendmail.o: ../../include/mail_stream.h
 sendmail.o: ../../include/mail_task.h
 sendmail.o: ../../include/mime_state.h
 sendmail.o: ../../include/msg.h
+sendmail.o: ../../include/msg_stats.h
 sendmail.o: ../../include/msg_syslog.h
 sendmail.o: ../../include/msg_vstream.h
 sendmail.o: ../../include/mymalloc.h
index 2f21822243f677851185a5d93651ba6dc1ef5a40..88a5b68076267c9a9400f908ce84ae4280f3401b 100644 (file)
@@ -973,15 +973,22 @@ int     main(int argc, char **argv)
 #define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx"
 
     saved_optind = optind;
-    while ((c = GETOPT(argc, argv, GETOPT_LIST)) > 0) {
-       VSTRING *buf = vstring_alloc(1);
+    while (argv[OPTIND] != 0) {
+       if (strcmp(argv[OPTIND], "-q") == 0) {  /* not getopt compatible */
+           optind++;
+           continue;
+       }
+       if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
+           break;
+       if (c == 'C') {
+           VSTRING *buf = vstring_alloc(1);
 
-       if (c == 'C'
-           && setenv(CONF_ENV_PATH,
+           if (setenv(CONF_ENV_PATH,
                   strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ?
-                     sane_dirname(buf, optarg) : optarg, 1) < 0)
-           msg_fatal_status(EX_UNAVAILABLE, "out of memory");
-       vstring_free(buf);
+                      sane_dirname(buf, optarg) : optarg, 1) < 0)
+               msg_fatal_status(EX_UNAVAILABLE, "out of memory");
+           vstring_free(buf);
+       }
     }
     optind = saved_optind;
     mail_conf_read();
index f276a485ad50498c56696beda4c6f579c0de6162..a67da3b554eb0818e472debbaac122c50f6ec2fe 100644 (file)
@@ -80,6 +80,7 @@ depend: $(MAKES)
 
 # do not edit below this line - it is generated by 'make depend'
 smtp.o: ../../include/argv.h
+smtp.o: ../../include/attr.h
 smtp.o: ../../include/debug_peer.h
 smtp.o: ../../include/deliver_request.h
 smtp.o: ../../include/dict.h
@@ -95,6 +96,7 @@ smtp.o: ../../include/maps.h
 smtp.o: ../../include/match_list.h
 smtp.o: ../../include/match_ops.h
 smtp.o: ../../include/msg.h
+smtp.o: ../../include/msg_stats.h
 smtp.o: ../../include/mymalloc.h
 smtp.o: ../../include/name_mask.h
 smtp.o: ../../include/recipient_list.h
@@ -111,6 +113,7 @@ smtp.o: smtp.c
 smtp.o: smtp.h
 smtp.o: smtp_sasl.h
 smtp_addr.o: ../../include/argv.h
+smtp_addr.o: ../../include/attr.h
 smtp_addr.o: ../../include/deliver_request.h
 smtp_addr.o: ../../include/dict.h
 smtp_addr.o: ../../include/dns.h
@@ -124,6 +127,7 @@ smtp_addr.o: ../../include/maps.h
 smtp_addr.o: ../../include/match_list.h
 smtp_addr.o: ../../include/match_ops.h
 smtp_addr.o: ../../include/msg.h
+smtp_addr.o: ../../include/msg_stats.h
 smtp_addr.o: ../../include/myaddrinfo.h
 smtp_addr.o: ../../include/mymalloc.h
 smtp_addr.o: ../../include/own_inet_addr.h
@@ -143,6 +147,7 @@ smtp_addr.o: smtp.h
 smtp_addr.o: smtp_addr.c
 smtp_addr.o: smtp_addr.h
 smtp_chat.o: ../../include/argv.h
+smtp_chat.o: ../../include/attr.h
 smtp_chat.o: ../../include/cleanup_user.h
 smtp_chat.o: ../../include/deliver_request.h
 smtp_chat.o: ../../include/dict.h
@@ -158,6 +163,7 @@ smtp_chat.o: ../../include/maps.h
 smtp_chat.o: ../../include/match_list.h
 smtp_chat.o: ../../include/match_ops.h
 smtp_chat.o: ../../include/msg.h
+smtp_chat.o: ../../include/msg_stats.h
 smtp_chat.o: ../../include/mymalloc.h
 smtp_chat.o: ../../include/name_mask.h
 smtp_chat.o: ../../include/post_mail.h
@@ -194,6 +200,7 @@ smtp_connect.o: ../../include/maps.h
 smtp_connect.o: ../../include/match_list.h
 smtp_connect.o: ../../include/match_ops.h
 smtp_connect.o: ../../include/msg.h
+smtp_connect.o: ../../include/msg_stats.h
 smtp_connect.o: ../../include/myaddrinfo.h
 smtp_connect.o: ../../include/mymalloc.h
 smtp_connect.o: ../../include/name_mask.h
@@ -218,6 +225,7 @@ smtp_connect.o: smtp_addr.h
 smtp_connect.o: smtp_connect.c
 smtp_connect.o: smtp_reuse.h
 smtp_dsn.o: ../../include/argv.h
+smtp_dsn.o: ../../include/attr.h
 smtp_dsn.o: ../../include/deliver_request.h
 smtp_dsn.o: ../../include/dict.h
 smtp_dsn.o: ../../include/dsn.h
@@ -226,6 +234,7 @@ smtp_dsn.o: ../../include/htable.h
 smtp_dsn.o: ../../include/maps.h
 smtp_dsn.o: ../../include/match_list.h
 smtp_dsn.o: ../../include/match_ops.h
+smtp_dsn.o: ../../include/msg_stats.h
 smtp_dsn.o: ../../include/recipient_list.h
 smtp_dsn.o: ../../include/resolve_clnt.h
 smtp_dsn.o: ../../include/scache.h
@@ -239,6 +248,7 @@ smtp_dsn.o: ../../include/vstring.h
 smtp_dsn.o: smtp.h
 smtp_dsn.o: smtp_dsn.c
 smtp_map11.o: ../../include/argv.h
+smtp_map11.o: ../../include/attr.h
 smtp_map11.o: ../../include/deliver_request.h
 smtp_map11.o: ../../include/dict.h
 smtp_map11.o: ../../include/dsn.h
@@ -249,6 +259,7 @@ smtp_map11.o: ../../include/maps.h
 smtp_map11.o: ../../include/match_list.h
 smtp_map11.o: ../../include/match_ops.h
 smtp_map11.o: ../../include/msg.h
+smtp_map11.o: ../../include/msg_stats.h
 smtp_map11.o: ../../include/quote_822_local.h
 smtp_map11.o: ../../include/quote_flags.h
 smtp_map11.o: ../../include/recipient_list.h
@@ -289,6 +300,7 @@ smtp_proto.o: ../../include/match_list.h
 smtp_proto.o: ../../include/match_ops.h
 smtp_proto.o: ../../include/mime_state.h
 smtp_proto.o: ../../include/msg.h
+smtp_proto.o: ../../include/msg_stats.h
 smtp_proto.o: ../../include/mymalloc.h
 smtp_proto.o: ../../include/name_code.h
 smtp_proto.o: ../../include/off_cvt.h
@@ -316,6 +328,7 @@ smtp_proto.o: smtp.h
 smtp_proto.o: smtp_proto.c
 smtp_proto.o: smtp_sasl.h
 smtp_rcpt.o: ../../include/argv.h
+smtp_rcpt.o: ../../include/attr.h
 smtp_rcpt.o: ../../include/bounce.h
 smtp_rcpt.o: ../../include/deliver_completed.h
 smtp_rcpt.o: ../../include/deliver_request.h
@@ -328,6 +341,7 @@ smtp_rcpt.o: ../../include/maps.h
 smtp_rcpt.o: ../../include/match_list.h
 smtp_rcpt.o: ../../include/match_ops.h
 smtp_rcpt.o: ../../include/msg.h
+smtp_rcpt.o: ../../include/msg_stats.h
 smtp_rcpt.o: ../../include/mymalloc.h
 smtp_rcpt.o: ../../include/recipient_list.h
 smtp_rcpt.o: ../../include/resolve_clnt.h
@@ -344,6 +358,7 @@ smtp_rcpt.o: ../../include/vstring.h
 smtp_rcpt.o: smtp.h
 smtp_rcpt.o: smtp_rcpt.c
 smtp_reuse.o: ../../include/argv.h
+smtp_reuse.o: ../../include/attr.h
 smtp_reuse.o: ../../include/deliver_request.h
 smtp_reuse.o: ../../include/dict.h
 smtp_reuse.o: ../../include/dns.h
@@ -355,6 +370,7 @@ smtp_reuse.o: ../../include/maps.h
 smtp_reuse.o: ../../include/match_list.h
 smtp_reuse.o: ../../include/match_ops.h
 smtp_reuse.o: ../../include/msg.h
+smtp_reuse.o: ../../include/msg_stats.h
 smtp_reuse.o: ../../include/myaddrinfo.h
 smtp_reuse.o: ../../include/mymalloc.h
 smtp_reuse.o: ../../include/recipient_list.h
@@ -373,6 +389,7 @@ smtp_reuse.o: smtp.h
 smtp_reuse.o: smtp_reuse.c
 smtp_reuse.o: smtp_reuse.h
 smtp_sasl_glue.o: ../../include/argv.h
+smtp_sasl_glue.o: ../../include/attr.h
 smtp_sasl_glue.o: ../../include/deliver_request.h
 smtp_sasl_glue.o: ../../include/dict.h
 smtp_sasl_glue.o: ../../include/dsn.h
@@ -383,6 +400,7 @@ smtp_sasl_glue.o: ../../include/maps.h
 smtp_sasl_glue.o: ../../include/match_list.h
 smtp_sasl_glue.o: ../../include/match_ops.h
 smtp_sasl_glue.o: ../../include/msg.h
+smtp_sasl_glue.o: ../../include/msg_stats.h
 smtp_sasl_glue.o: ../../include/mymalloc.h
 smtp_sasl_glue.o: ../../include/name_mask.h
 smtp_sasl_glue.o: ../../include/recipient_list.h
@@ -401,6 +419,7 @@ smtp_sasl_glue.o: smtp.h
 smtp_sasl_glue.o: smtp_sasl.h
 smtp_sasl_glue.o: smtp_sasl_glue.c
 smtp_sasl_proto.o: ../../include/argv.h
+smtp_sasl_proto.o: ../../include/attr.h
 smtp_sasl_proto.o: ../../include/deliver_request.h
 smtp_sasl_proto.o: ../../include/dict.h
 smtp_sasl_proto.o: ../../include/dsn.h
@@ -411,6 +430,7 @@ smtp_sasl_proto.o: ../../include/maps.h
 smtp_sasl_proto.o: ../../include/match_list.h
 smtp_sasl_proto.o: ../../include/match_ops.h
 smtp_sasl_proto.o: ../../include/msg.h
+smtp_sasl_proto.o: ../../include/msg_stats.h
 smtp_sasl_proto.o: ../../include/mymalloc.h
 smtp_sasl_proto.o: ../../include/recipient_list.h
 smtp_sasl_proto.o: ../../include/resolve_clnt.h
@@ -427,6 +447,7 @@ smtp_sasl_proto.o: smtp.h
 smtp_sasl_proto.o: smtp_sasl.h
 smtp_sasl_proto.o: smtp_sasl_proto.c
 smtp_session.o: ../../include/argv.h
+smtp_session.o: ../../include/attr.h
 smtp_session.o: ../../include/debug_peer.h
 smtp_session.o: ../../include/deliver_request.h
 smtp_session.o: ../../include/dict.h
@@ -440,6 +461,7 @@ smtp_session.o: ../../include/match_list.h
 smtp_session.o: ../../include/match_ops.h
 smtp_session.o: ../../include/mime_state.h
 smtp_session.o: ../../include/msg.h
+smtp_session.o: ../../include/msg_stats.h
 smtp_session.o: ../../include/mymalloc.h
 smtp_session.o: ../../include/recipient_list.h
 smtp_session.o: ../../include/resolve_clnt.h
@@ -456,6 +478,7 @@ smtp_session.o: smtp.h
 smtp_session.o: smtp_sasl.h
 smtp_session.o: smtp_session.c
 smtp_state.o: ../../include/argv.h
+smtp_state.o: ../../include/attr.h
 smtp_state.o: ../../include/deliver_request.h
 smtp_state.o: ../../include/dict.h
 smtp_state.o: ../../include/dsn.h
@@ -465,6 +488,7 @@ smtp_state.o: ../../include/mail_params.h
 smtp_state.o: ../../include/maps.h
 smtp_state.o: ../../include/match_list.h
 smtp_state.o: ../../include/match_ops.h
+smtp_state.o: ../../include/msg_stats.h
 smtp_state.o: ../../include/mymalloc.h
 smtp_state.o: ../../include/recipient_list.h
 smtp_state.o: ../../include/resolve_clnt.h
@@ -480,6 +504,7 @@ smtp_state.o: smtp.h
 smtp_state.o: smtp_sasl.h
 smtp_state.o: smtp_state.c
 smtp_trouble.o: ../../include/argv.h
+smtp_trouble.o: ../../include/attr.h
 smtp_trouble.o: ../../include/bounce.h
 smtp_trouble.o: ../../include/defer.h
 smtp_trouble.o: ../../include/deliver_completed.h
@@ -493,6 +518,7 @@ smtp_trouble.o: ../../include/maps.h
 smtp_trouble.o: ../../include/match_list.h
 smtp_trouble.o: ../../include/match_ops.h
 smtp_trouble.o: ../../include/msg.h
+smtp_trouble.o: ../../include/msg_stats.h
 smtp_trouble.o: ../../include/name_mask.h
 smtp_trouble.o: ../../include/recipient_list.h
 smtp_trouble.o: ../../include/resolve_clnt.h
@@ -509,6 +535,7 @@ smtp_trouble.o: ../../include/vstring.h
 smtp_trouble.o: smtp.h
 smtp_trouble.o: smtp_trouble.c
 smtp_unalias.o: ../../include/argv.h
+smtp_unalias.o: ../../include/attr.h
 smtp_unalias.o: ../../include/deliver_request.h
 smtp_unalias.o: ../../include/dict.h
 smtp_unalias.o: ../../include/dns.h
@@ -519,6 +546,7 @@ smtp_unalias.o: ../../include/maps.h
 smtp_unalias.o: ../../include/match_list.h
 smtp_unalias.o: ../../include/match_ops.h
 smtp_unalias.o: ../../include/msg.h
+smtp_unalias.o: ../../include/msg_stats.h
 smtp_unalias.o: ../../include/myaddrinfo.h
 smtp_unalias.o: ../../include/recipient_list.h
 smtp_unalias.o: ../../include/resolve_clnt.h
index c2944f7375524775a63eacccaa2e6ed4bc080f67..bf124e6ce56e99e63b407ad52db624f426b86a7b 100644 (file)
 /* .IP "\fBsmtp_connection_cache_on_demand (yes)\fR"
 /*     Temporarily enable SMTP connection caching while a destination
 /*     has a high volume of mail in the active queue.
-/* .IP "\fBsmtp_connection_cache_reuse_limit (10)\fR"
-/*     When SMTP connection caching is enabled, the number of times that
-/*     an SMTP session is reused before it is closed.
+/* .IP "\fBsmtp_connection_reuse_time_limit (300s)\fR"
+/*     The amount of time during which Postfix will use an SMTP
+/*     connection repeatedly.
 /* .IP "\fBsmtp_connection_cache_time_limit (2s)\fR"
 /*     When SMTP connection caching is enabled, the amount of time that
 /*     an unused SMTP client socket is kept open before it is closed.
@@ -484,7 +484,7 @@ bool    var_smtp_send_xforward;
 int     var_smtp_mxaddr_limit;
 int     var_smtp_mxsess_limit;
 int     var_smtp_cache_conn;
-int     var_smtp_reuse_limit;
+int     var_smtp_reuse_time;
 char   *var_smtp_cache_dest;
 char   *var_scache_service;
 bool    var_smtp_cache_demand;
@@ -764,6 +764,7 @@ int     main(int argc, char **argv)
        VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0,
        VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0,
        VAR_SMTP_CACHE_CONN, DEF_SMTP_CACHE_CONN, &var_smtp_cache_conn, 1, 0,
+       VAR_SMTP_REUSE_TIME, DEF_SMTP_REUSE_TIME, &var_smtp_reuse_time, 1, 0,
 #ifdef USE_TLS
        VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0,
 #endif
@@ -773,7 +774,6 @@ int     main(int argc, char **argv)
        VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
        VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
        VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
-       VAR_SMTP_REUSE_LIMIT, DEF_SMTP_REUSE_LIMIT, &var_smtp_reuse_limit, 1, 0,
 #ifdef USE_TLS
        VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
 #endif
index 919cc81322cec34a92fd40cbc0a0ee7e5ce9ae84..6f865f131ca157fedcef86260d17ec3556e99849 100644 (file)
@@ -197,7 +197,8 @@ typedef struct SMTP_SESSION {
     int     sndbufsize;                        /* PIPELINING buffer size */
     int     send_proto_helo;           /* XFORWARD support */
 
-    int     reuse_count;               /* how many uses left */
+    time_t  expire_time;               /* session reuse expiration time */
+    int     reuse_count;               /* # of times reused (for logging) */
 
 #ifdef USE_SASL_AUTH
     char   *sasl_mechanism_list;       /* server mechanism list */
@@ -221,8 +222,8 @@ typedef struct SMTP_SESSION {
 
 } SMTP_SESSION;
 
-extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *,
-                                const char *, const char *, unsigned, int);
+extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *, const char *,
+                                      const char *, unsigned, time_t, int);
 extern void smtp_session_free(SMTP_SESSION *);
 extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *);
 extern SMTP_SESSION *smtp_session_activate(int, VSTRING *, VSTRING *);
@@ -248,6 +249,68 @@ extern int smtp_xfer(SMTP_STATE *);
 extern int smtp_rset(SMTP_STATE *);
 extern int smtp_quit(SMTP_STATE *);
 
+ /*
+  * A connection is re-usable if session->expire_time is > 0 and the
+  * expiration time has not been reached.  This is subtle because the timer
+  * can expire between sending a command and receiving the reply for that
+  * command.
+  * 
+  * But wait, there is more! When SMTP command pipelining is enabled, there are
+  * two protocol loops that execute at very different times: one loop that
+  * generates commands, and one loop that receives replies to those commands.
+  * These will be called "sender loop" and "receiver loop", respectively. At
+  * well-defined protocol synchronization points, the sender loop pauses to
+  * let the receiver loop catch up.
+  * 
+  * When we choose to reuse a connection, both the sender and receiver protocol
+  * loops end with "." (mail delivery) or "RSET" (address probe). When we
+  * choose not to reuse, both the sender and receiver protocol loops end with
+  * "QUIT". The problem is that we must make the same protocol choices in
+  * both the sender and receiver loops, even though those loops may execute
+  * at completely different times.
+  * 
+  * We "freeze" the choice in the sender loop, just before we generate "." or
+  * "RSET". The reader loop leaves the connection cachable even if the timer
+  * expires by the time the response arrives. The connection cleanup code
+  * will call smtp_quit() for connections with an expired cache expiration
+  * timer.
+  * 
+  * We could have made the programmer's life a lot simpler by not making a
+  * choice at all, and always leaving it up to the connection cleanup code to
+  * call smtp_quit() for connections with an expired cache expiration timer.
+  * 
+  * As a general principle, neither the sender loop nor the receiver loop must
+  * modify the connection caching state, if that can affect the receiver
+  * state machine for not-yet processed replies to already-generated
+  * commands. This restriction does not apply when we have to exit the
+  * protocol loops prematurely due to e.g., timeout or connection loss, so
+  * that those pending replies will never be received.
+  * 
+  * But wait, there is even more! Only the first good connection for a specific
+  * destination may be cached under both the next-hop destination name and
+  * the server address; connections to alternate servers must be cached under
+  * the server address alone. This means we must distinguish between bad
+  * connections and other reasons why connections cannot be cached.
+  */
+#define THIS_SESSION_IS_CACHED \
+       (session->expire_time > 0)
+
+#define THIS_SESSION_IS_EXPIRED \
+       (THIS_SESSION_IS_CACHED \
+           && session->expire_time < vstream_ftime(session->stream))
+
+#define THIS_SESSION_IS_BAD \
+       (session->expire_time < 0)
+
+#define DONT_CACHE_THIS_SESSION \
+       (session->expire_time = 0)
+
+#define DONT_CACHE_BAD_SESSION \
+       (session->expire_time = -1)
+
+#define CACHE_THIS_SESSION_UNTIL(when) \
+       (session->expire_time = (when))
+
  /*
   * smtp_chat.c
   */
index 00f4ccbb5cd2d646cf61954ee5de018c17376677..61f7a389e2926613deec34067ef4dddfc5417f38 100644 (file)
@@ -8,9 +8,9 @@
 /*
 /*     typedef struct {
 /* .in +4
-/*             int code;
-/*             char *dsn;
-/*             char *str;
+/*             int code;       /* SMTP code, not sanitized */
+/*             char *dsn;      /* enhanced status, sanitized */
+/*             char *str;      /* unmodified SMTP reply */
 /*             VSTRING *dsn_buf;
 /*             VSTRING *str_buf;
 /* .in -4
 /*     smtp_chat_cmd() formats a command and sends it to an SMTP server.
 /*     Optionally, the command is logged.
 /*
-/*     smtp_chat_resp() reads one SMTP server response. It separates the
-/*     numerical status code from the text, and concatenates multi-line
-/*     responses to one string, using a newline as separator.
-/*     Optionally, the server response is logged.
-/*
+/*     smtp_chat_resp() reads one SMTP server response. It extracts
+/*     the SMTP reply code and enhanced status code from the text,
+/*     and concatenates multi-line responses to one string, using
+/*     a newline as separator.  Optionally, the server response
+/*     is logged.
+/* .IP \(bu
+/*     Postfix never sanitizes the extracted SMTP reply code except
+/*     to ensure that it is a three-digit code. A malformed reply
+/*     results in a null extracted SMTP reply code value.
+/* .IP \(bu
+/*     Postfix always sanitizes the extracted enhanced status code.
+/*     When the server's SMTP status code is 2xx, 4xx or 5xx,
+/*     Postfix requires that the first digit of the server's
+/*     enhanced status code matches the first digit of the server's
+/*     SMTP status code.  In case of a mis-match, or when the
+/*     server specified no status code, the extracted enhanced
+/*     status code is set to 2.0.0, 4.0.0 or 5.0.0 instead.  With
+/*     SMTP reply codes other than 2xx, 4xx or 5xx, the extracted
+/*     enhanced status code is set to a default value of 5.5.0
+/*     (protocol error) for reasons outlined under the next bullet.
+/* .IP \(bu
+/*     Since the SMTP reply code may violate the protocol even
+/*     when it is correctly formatted, Postfix uses the sanitized
+/*     extracted enhanced status code to decide whether an error
+/*     condition is permanent or transient.  This means that the
+/*     caller may have to update the enhanced status code when it
+/*     discovers that a server reply violates the SMTP protocol,
+/*     even though it was correctly formatted. This happens when
+/*     the client and server get out of step due to a broken proxy
+/*     agent.
+/* .PP
 /*     smtp_chat_notify() sends a copy of the SMTP transaction log
 /*     to the postmaster for review. The postmaster notice is sent only
 /*     when delivery is possible immediately. It is an error to call
index 1af797bf546a4e5798d3f4745e24fb017355df21..abe387bb0d4b503eff657b64d086e69e1bcf8e84 100644 (file)
@@ -121,6 +121,7 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr,
     int     ch;
     char   *bind_addr;
     char   *bind_var;
+    time_t  start_time;
 
     smtp_errno = SMTP_ERR_NONE;                        /* Paranoia */
 
@@ -212,6 +213,7 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr,
     if (msg_verbose)
        msg_info("%s: trying: %s[%s] port %d...",
                 myname, addr->name, hostaddr.buf, ntohs(port));
+    start_time = time((time_t *) 0);
     if (var_smtp_conn_tmout > 0) {
        non_blocking(sock, NON_BLOCKING);
        conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout);
@@ -263,8 +265,8 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr,
     /*
      * Bundle up what we have into a nice SMTP_SESSION object.
      */
-    return (smtp_session_alloc(stream, dest, addr->name,
-                              hostaddr.buf, port, sess_flags));
+    return (smtp_session_alloc(stream, dest, addr->name, hostaddr.buf,
+                              port, start_time, sess_flags));
 }
 
 /* smtp_parse_destination - parse destination */
@@ -308,7 +310,9 @@ static char *smtp_parse_destination(char *destination, char *def_service,
 
 static void smtp_cleanup_session(SMTP_STATE *state)
 {
+    DELIVER_REQUEST *request = state->request;
     SMTP_SESSION *session = state->session;
+    int     bad_session;
 
     /*
      * Inform the postmaster of trouble.
@@ -330,24 +334,51 @@ static void smtp_cleanup_session(SMTP_STATE *state)
      * hosts. In fact, this is the only benefit of caching logical to
      * physical bindings; caching a session under its own hostname provides
      * no performance benefit, given the way smtp_connect() works.
-     * 
-     * XXX Should not cache TLS sessions unless we are using a single-session,
-     * in-process, cache. And if we did, we should passivate VSTREAM objects
-     * in addition to passivating SMTP_SESSION objects.
      */
-    if (session->reuse_count > 0) {
+    bad_session = THIS_SESSION_IS_BAD;         /* smtp_quit() may fail */
+    if (THIS_SESSION_IS_EXPIRED)
+       smtp_quit(state);                       /* also disables caching */
+    if (THIS_SESSION_IS_CACHED) {
        smtp_save_session(state);
-       if (HAVE_NEXTHOP_STATE(state))
-           FREE_NEXTHOP_STATE(state);
     } else {
        smtp_session_free(session);
     }
     state->session = 0;
 
+    /*
+     * If this session was good, reset the logical next-hop state, so that we
+     * won't cache connections to alternate servers under the logical
+     * next-hop destination. Otherwise we could end up skipping over the
+     * available and more preferred servers.
+     */
+    if (HAVE_NEXTHOP_STATE(state) && !bad_session)
+       FREE_NEXTHOP_STATE(state);
+
     /*
      * Clean up the lists with todo and dropped recipients.
      */
     smtp_rcpt_cleanup(state);
+
+    /*
+     * Reset profiling info.
+     * 
+     * XXX When one delivery request results in multiple sessions, the set-up
+     * and transmission latencies of the earlier sessions will count as
+     * connection set-up time for the later sessions.
+     * 
+     * XXX On the other hand, when we first try to connect to one or more dead
+     * hosts before we reach a good host, then all that time must be counted
+     * as connection set-up time for the session with the good host.
+     * 
+     * XXX So this set-up attribution problem exists only when we actually
+     * engage in a session, spend a lot of time delivering a message, find
+     * that it fails, and then connect to an alternate host.
+     */
+    memset((char *) &request->msg_stats.conn_setup_done, 0,
+          sizeof(request->msg_stats.conn_setup_done));
+    memset((char *) &request->msg_stats.deliver_done, 0,
+          sizeof(request->msg_stats.deliver_done));
+    request->msg_stats.reuse_count = 0;
 }
 
 /* smtp_scrub_address_list - delete all cached addresses from list */
index a52fd61063225dddf16935fdddd5fc01a61ae768..21a1189e1871e726d1f463354e0caeb5019c628b 100644 (file)
@@ -32,8 +32,8 @@
 /*     accordingly.
 /*
 /*     smtp_rset() sends a single RSET command and waits for the
-/*     response. In case of no response, or negative response, it
-/*     turns off connection caching.
+/*     response. In case of a negative reply it sets the
+/*     CANT_RSET_THIS_SESSION flag.
 /*
 /*     smtp_quit() sends a single QUIT command and waits for the
 /*     response if configured to do so. It always turns off connection
 /*     perform an SMTP conversation, not necessarily the ability
 /*     to deliver mail, or the achievement of server happiness.
 /*
+/*     In case of a rejected or failed connection, a connection
+/*     is marked as "bad, do not cache". Otherwise, connection
+/*     caching may be turned off (without being marked "bad") at
+/*     the discretion of the code that implements the individual
+/*     protocol steps.
+/*
 /*     Warnings: corrupt message file. A corrupt message is marked
 /*     as "corrupt" by changing its queue file permissions.
 /* BUGS
@@ -596,7 +602,7 @@ static int smtp_start_tls(SMTP_STATE *state, int misc_flags)
      * SMTP connection either, because the conversation is in an unknown
      * state.
      */
-    session->reuse_count = 0;
+    DONT_CACHE_THIS_SESSION;
 
     /*
      * The actual TLS handshake may succeed, but tls_client_start() may fail
@@ -889,12 +895,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
 #define SENDING_MAIL \
        (recv_state <= SMTP_STATE_DOT)
 
-#define THIS_SESSION_IS_CACHED \
-       (session->reuse_count > 0)
-
-#define DONT_CACHE_THIS_SESSION \
-       (session->reuse_count = 0)
-
 #define CANT_RSET_THIS_SESSION \
        (session->features |= SMTP_FEATURE_RSET_REJECTED)
 
@@ -1025,6 +1025,8 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
             * Build the MAIL FROM command.
             */
        case SMTP_STATE_MAIL:
+           request->msg_stats.reuse_count = session->reuse_count;
+           GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
            REWRITE_ADDRESS(session->scratch2, request->sender);
            QUOTE_ADDRESS(session->scratch, vstring_str(session->scratch2));
            vstring_sprintf(next_command, "MAIL FROM:<%s>",
@@ -1106,9 +1108,15 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
 
            /*
             * Build the "." command before we have seen the DATA response.
+            * 
+            * Changing the connection caching state here is safe because it
+            * affects none of the not-yet processed replies to
+            * already-generated commands.
             */
        case SMTP_STATE_DOT:
            vstring_strcpy(next_command, ".");
+           if (THIS_SESSION_IS_EXPIRED)
+               DONT_CACHE_THIS_SESSION;
            next_state = THIS_SESSION_IS_CACHED ?
                SMTP_STATE_LAST : SMTP_STATE_QUIT;
            break;
@@ -1118,9 +1126,15 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
             * when it has verified all recipients; or it is entered by the
             * receiver when all recipients are verified or rejected, and is
             * then left before the bottom of the main loop.
+            * 
+            * Changing the connection caching state here is safe because there
+            * are no not-yet processed replies to already-generated
+            * commands.
             */
        case SMTP_STATE_ABORT:
            vstring_strcpy(next_command, "RSET");
+           if (THIS_SESSION_IS_EXPIRED)
+               DONT_CACHE_THIS_SESSION;
            next_state = THIS_SESSION_IS_CACHED ?
                SMTP_STATE_LAST : SMTP_STATE_QUIT;
            break;
@@ -1140,11 +1154,17 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
             * Build the QUIT command before we have seen the "." or RSET
             * response. This is entered as initial state from smtp_quit(),
             * or is reached near the end of any non-cached session.
+            * 
+            * Changing the connection caching state here is safe. If this
+            * command is pipelined together with a preceding command, then
+            * connection caching was already turned off. Do not clobber the
+            * "bad connection" flag.
             */
        case SMTP_STATE_QUIT:
            vstring_strcpy(next_command, "QUIT");
            next_state = SMTP_STATE_LAST;
-           DONT_CACHE_THIS_SESSION;
+           if (THIS_SESSION_IS_CACHED)
+               DONT_CACHE_THIS_SESSION;
            break;
 
            /*
@@ -1306,6 +1326,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
                     * delivered.
                     */
                case SMTP_STATE_DOT:
+                   GETTIMEOFDAY(&request->msg_stats.deliver_done);
                    if (nrcpt > 0) {
                        if (resp->code / 100 != 2) {
                            smtp_mesg_fail(state, session->host, resp,
@@ -1323,17 +1344,35 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
                            }
                        }
                    }
+
+                   /*
+                    * XXX Do not change the connection caching state here,
+                    * even if the connection caching timer expired between
+                    * generating the command and processing the reply,
+                    * otherwise the sender and receiver loops get out of
+                    * sync. The caller will call smtp_quit() if appropriate.
+                    */
                    recv_state = (var_skip_quit_resp || THIS_SESSION_IS_CACHED ?
                                  SMTP_STATE_LAST : SMTP_STATE_QUIT);
                    break;
 
                    /*
-                    * Receive the RSET response, and disable session caching
-                    * in case of failure.
+                    * Receive the RSET response.
+                    * 
+                    * The SMTP_STATE_ABORT sender state is entered by the
+                    * sender when it has verified all recipients; or it is
+                    * entered by the receiver when all recipients are
+                    * verified or rejected, and is then left before the
+                    * bottom of the main loop.
+                    * 
+                    * XXX Do not change the connection caching state here, even
+                    * if the server rejected RSET or if the connection
+                    * caching timer expired between generating the command
+                    * and processing the reply, otherwise the sender and
+                    * receiver loops get out of sync. The caller will call
+                    * smtp_quit() if appropriate.
                     */
                case SMTP_STATE_ABORT:
-                   if (resp->code / 100 != 2)
-                       DONT_CACHE_THIS_SESSION;
                    recv_state = (var_skip_quit_resp || THIS_SESSION_IS_CACHED ?
                                  SMTP_STATE_LAST : SMTP_STATE_QUIT);
                    break;
@@ -1377,6 +1416,8 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
                send_state = recv_state = SMTP_STATE_ABORT;
                send_rcpt = recv_rcpt = 0;
                vstring_strcpy(next_command, "RSET");
+               if (THIS_SESSION_IS_EXPIRED)
+                   DONT_CACHE_THIS_SESSION;
                next_state = THIS_SESSION_IS_CACHED ?
                    SMTP_STATE_LAST : SMTP_STATE_QUIT;
                /* XXX Also: record if non-delivering session. */
@@ -1467,7 +1508,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
            } else if (prev_type == REC_TYPE_CONT)      /* missing newline */
                smtp_fputs("", 0, session->stream);
            if ((session->features & SMTP_FEATURE_MAYBEPIX) != 0
-               && request->arrival_time < vstream_ftime(session->stream)
+               && request->msg_stats.incoming_arrival < vstream_ftime(session->stream)
                - var_smtp_pix_thresh) {
                msg_info("%s: enabling PIX <CRLF>.<CRLF> workaround for %s",
                         request->queue_id, session->namaddr);
index b1cd743026ed2d3a4dfee17eb78461a95ef6ad18..425e939de6c0b8bd33c909e5b586a773e53d5f15 100644 (file)
@@ -149,7 +149,7 @@ void    smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt)
     dsn.action = "relayed";
 
     status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
-                 request->queue_id, request->arrival_time, rcpt,
+                 request->queue_id, &request->msg_stats, rcpt,
                  session->namaddr, &dsn);
     if (status == 0)
        if (request->flags & DEL_REQ_FLAG_SUCCESS)
index e71defd9d498f63c2278af66e990dc5ada406ce7..6347e22069573352fe99b886e597d81f1a6d01b3 100644 (file)
@@ -6,12 +6,14 @@
 /* SYNOPSIS
 /*     #include "smtp.h"
 /*
-/*     SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr, port, flags)
+/*     SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr,
+/*                                     port, start, flags)
 /*     VSTREAM *stream;
 /*     char    *dest;
 /*     char    *host;
 /*     char    *addr;
 /*     unsigned port;
+/*     time_t  start;
 /*     int     flags;
 /*
 /*     void    smtp_session_free(session)
@@ -59,6 +61,8 @@
 /*     The address of the host that we are connected to.
 /* .IP port
 /*     The remote port, network byte order.
+/* .IP start
+/*     The time when this connection was opened.
 /* .IP flags
 /*     Zero or more of the following:
 /* .RS
@@ -188,7 +192,8 @@ static void smtp_tls_site_policy(SMTP_TLS_SITE_POLICY *policy,
 
 SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
                                         const char *host, const char *addr,
-                                        unsigned port, int flags)
+                                        unsigned port, time_t start,
+                                        int flags)
 {
     SMTP_SESSION *session;
 
@@ -214,16 +219,16 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
     session->scratch = vstring_alloc(100);
     session->scratch2 = vstring_alloc(100);
     smtp_chat_init(session);
-    session->features = 0;
     session->mime_state = 0;
 
     session->sndbufsize = 0;
     session->send_proto_helo = 0;
 
     if (flags & SMTP_SESS_FLAG_CACHE)
-       session->reuse_count = var_smtp_reuse_limit;
+       CACHE_THIS_SESSION_UNTIL(start + var_smtp_reuse_time);
     else
-       session->reuse_count = 0;
+       DONT_CACHE_THIS_SESSION;
+    session->reuse_count = 0;
 
 #ifdef USE_SASL_AUTH
     smtp_sasl_connect(session);
@@ -342,12 +347,16 @@ int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
      * how many non-delivering mail transactions there were during this
      * session, and perhaps other statistics, so that we don't reuse a
      * session too much.
+     * 
+     * XXX Be sure to use unsigned types in the format string. Sign characters
+     * would be rejected by the alldig() test on the reading end.
      */
-    vstring_sprintf(endp_prop, "%s\n%s\n%s\n%u\n%u\n%u\n%u",
+    vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu\n%u",
+                   session->reuse_count,
                    session->dest, session->host,
                    session->addr, session->port,
                    session->features & SMTP_FEATURE_ENDPOINT_MASK,
-                   session->reuse_count,
+                   (long) session->expire_time,
                    session->sndbufsize);
 
     /*
@@ -385,7 +394,8 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
     const char *addr;
     unsigned port;
     unsigned features;                 /* server features */
-    unsigned reuse_count;              /* how reuses left */
+    time_t  expire_time;               /* session re-use expiration time */
+    unsigned reuse_count;              /* # times reused */
     unsigned sndbufsize;               /* PIPELINING buffer size */
 
     /*
@@ -397,6 +407,11 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
      * suitable for zero-length fields.
      */
     endp_props = STR(endp_prop);
+    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
+       msg_warn("%s: bad cached session reuse count property", myname);
+       return (0);
+    }
+    reuse_count = atoi(prop);
     if ((dest = mystrtok(&endp_props, "\n")) == 0) {
        msg_warn("%s: missing cached session destination property", myname);
        return (0);
@@ -422,10 +437,14 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
     features = atoi(prop);
 
     if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
-       msg_warn("%s: bad cached session reuse_count property", myname);
+       msg_warn("%s: bad cached session expiration time property", myname);
        return (0);
     }
-    reuse_count = atoi(prop);
+#ifdef MISSING_STRTOUL
+    expire_time = strtol(prop, 0, 10);
+#else
+    expire_time = strtoul(prop, 0, 10);
+#endif
 
     if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
        msg_warn("%s: bad cached session sndbufsize property", myname);
@@ -445,15 +464,19 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
     /*
      * Allright, bundle up what we have sofar.
      */
-    session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR),
-                              dest, host, addr, port, SMTP_SESS_FLAG_NONE);
+    session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), dest, host,
+                              addr, port, (time_t) 0, SMTP_SESS_FLAG_NONE);
     session->features = (features | SMTP_FEATURE_FROM_CACHE);
-    session->reuse_count = reuse_count - 1;
+    CACHE_THIS_SESSION_UNTIL(expire_time);
+    session->reuse_count = ++reuse_count;
     session->sndbufsize = sndbufsize;
 
     if (msg_verbose)
-       msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, reuse=%u, sndbuf=%u",
-                myname, dest, host, addr, ntohs(port), features, reuse_count, sndbufsize);
+       msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, "
+                "ttl=%ld, reuse=%d, sndbuf=%u",
+                myname, dest, host, addr, ntohs(port), features,
+                (long) (expire_time - time((time_t *) 0)), reuse_count,
+                sndbufsize);
 
     /*
      * Re-activate the SASL attributes.
index 73d3abf2b639a453bfe17c058ecdd65f41b4f4d8..9e218daa4da2ce21ce0f1a405fd8784aeb45155b 100644 (file)
@@ -189,7 +189,7 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue)
     SMTP_SESSION *session = state->session;
     RECIPIENT *rcpt;
     int     status;
-    int     soft_error = (dsn->dtext[0] == '4');
+    int     soft_error = (dsn->status[0] == '4');
     int     nrcpt;
 
     /*
@@ -213,13 +213,30 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue)
      * the recipient for delivery to a backup server.
      */
     else {
+
+       /*
+        * If we are still in the connection set-up phase, update the set-up
+        * completion time here, otherwise the time spent in set-up latency
+        * will be attributed as message transfer latency.
+        * 
+        * All remaining recipients have failed at this point, so we update the
+        * delivery completion time stamp so that multiple recipient status
+        * records show the same delay values.
+        */
+       if (request->msg_stats.conn_setup_done.tv_sec == 0) {
+           GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
+           request->msg_stats.deliver_done =
+               request->msg_stats.conn_setup_done;
+       } else
+           GETTIMEOFDAY(&request->msg_stats.deliver_done);
+
        for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
            if (SMTP_RCPT_ISMARKED(rcpt))
                continue;
            status = (soft_error ? defer_append : bounce_append)
                (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
-                request->arrival_time, rcpt,
+                &request->msg_stats, rcpt,
                 session ? session->namaddr : "none", dsn);
            if (status == 0)
                deliver_completed(state->src, rcpt->offset);
@@ -234,7 +251,7 @@ static int smtp_bulk_fail(SMTP_STATE *state, DSN *dsn, int throttle_queue)
      * Don't cache this session. We can't talk to this server.
      */
     if (throttle_queue && session)
-       session->reuse_count = 0;
+       DONT_CACHE_BAD_SESSION;
 
     return (-1);
 }
@@ -366,7 +383,7 @@ void    smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name,
     va_start(ap, format);
     vsmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap);
     va_end(ap);
-    soft_error = dsn.dtext[0] == '4';
+    soft_error = dsn.status[0] == '4';
 
     if (state->session && mta_name)
        smtp_check_code(state->session, resp->code);
@@ -392,7 +409,7 @@ void    smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name,
     else {
        status = (soft_error ? defer_append : bounce_append)
            (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
-            request->arrival_time, rcpt,
+            &request->msg_stats, rcpt,
             session ? session->namaddr : "none", &dsn);
        if (status == 0)
            deliver_completed(state->src, rcpt->offset);
index 5ce6bf6061c5d0194c626337029617e06ece088e..78010673df5a8efba735f161c56bf8513f0047c9 100644 (file)
@@ -237,6 +237,7 @@ smtpd_check.o: ../../include/match_list.h
 smtpd_check.o: ../../include/match_ops.h
 smtpd_check.o: ../../include/match_parent_style.h
 smtpd_check.o: ../../include/msg.h
+smtpd_check.o: ../../include/msg_stats.h
 smtpd_check.o: ../../include/myaddrinfo.h
 smtpd_check.o: ../../include/mymalloc.h
 smtpd_check.o: ../../include/namadr_list.h
index 024eb0c7dccd6b5e727629c9c4c0a9cfb04e52dc..15140378cf1ea9ab992fd5f2264e91ccd3932a1d 100644 (file)
@@ -45,7 +45,7 @@
 /*     Reject the specified commands with a hard (5xx) error code.
 /*     This option implies \fB-p\fR.
 /* .sp
-/*     Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/*     Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 /*     DATA, ., RSET, NOOP, and QUIT. Separate command names by
 /*     white space or commas, and use quotes to protect white space
 /*     from the shell. Command names are case-insensitive.
@@ -67,7 +67,7 @@
 /*     Disconnect (without replying) after receiving one of the
 /*     specified commands.
 /* .sp
-/*     Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/*     Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 /*     DATA, ., RSET, NOOP, and QUIT. Separate command names by
 /*     white space or commas, and use quotes to protect white space
 /*     from the shell. Command names are case-insensitive.
 /*     Reject the specified commands with a soft (4xx) error code.
 /*     This option implies \fB-p\fR.
 /* .sp
-/*     Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/*     Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 /*     DATA, ., RSET, NOOP, and QUIT. Separate command names by
 /*     white space or commas, and use quotes to protect white space
 /*     from the shell. Command names are case-insensitive.
 /* .IP "\fB-s \fIcommand,command,...\fR"
 /*     Log the named commands to syslogd.
 /* .sp
-/*     Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
+/*     Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
 /*     DATA, ., RSET, NOOP, and QUIT. Separate command names by
 /*     white space or commas, and use quotes to protect white space
 /*     from the shell. Command names are case-insensitive.
@@ -345,6 +345,19 @@ static void quit_response(SINK_STATE *state)
        quit_count++;
 }
 
+/* conn_response - respond to connect command */
+
+static void conn_response(SINK_STATE *state)
+{
+    if (pretend_pix)
+       smtp_printf(state->stream, "220 ********");
+    else if (disable_esmtp)
+       smtp_printf(state->stream, "220 %s", var_myhostname);
+    else
+       smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
+    smtp_flush(state->stream);
+}
+
 /* data_read - read data from socket */
 
 static int data_read(SINK_STATE *state)
@@ -426,6 +439,7 @@ typedef struct SINK_COMMAND {
 #define FLAG_DISCONNECT        (1<<4)          /* disconnect */
 
 static SINK_COMMAND command_table[] = {
+    "connect", conn_response, hard_err_resp, soft_err_resp, 0,
     "helo", helo_response, hard_err_resp, soft_err_resp, 0,
     "ehlo", ehlo_response, hard_err_resp, soft_err_resp, 0,
     "lhlo", ehlo_response, hard_err_resp, soft_err_resp, 0,
@@ -485,6 +499,33 @@ static void set_cmds_flags(const char *cmds, int flags)
     myfree(saved_cmds);
 }
 
+/* command_resp - respond to command */
+
+static int command_resp(SINK_STATE *state, SINK_COMMAND *cmdp, const char *command, char *args)
+{
+    /* We use raw syslog. Sanitize data content and length. */
+    if (cmdp->flags & FLAG_SYSLOG)
+       syslog(LOG_INFO, "%s %.100s", command, printable(args, '?'));
+    if (cmdp->flags & FLAG_DISCONNECT)
+       return (-1);
+    if (cmdp->flags & FLAG_HARD_ERR) {
+       cmdp->hard_response(state);
+       return (0);
+    }
+    if (cmdp->flags & FLAG_SOFT_ERR) {
+       cmdp->soft_response(state);
+       return (0);
+    }
+    if (cmdp->response == data_response && fixed_delay > 0) {
+       event_request_timer(data_event, (char *) state, fixed_delay);
+    } else {
+       cmdp->response(state);
+       if (cmdp->response == quit_response)
+           return (-1);
+    }
+    return (0);
+}
+
 /* command_read - talk the SMTP protocol, server side */
 
 static int command_read(SINK_STATE *state)
@@ -584,27 +625,7 @@ static int command_read(SINK_STATE *state)
        smtp_flush(state->stream);
        return (0);
     }
-    /* We use raw syslog. Sanitize data content and length. */
-    if (cmdp->flags & FLAG_SYSLOG)
-       syslog(LOG_INFO, "%s %.100s", command, printable(ptr, '?'));
-    if (cmdp->flags & FLAG_DISCONNECT)
-       return (-1);
-    if (cmdp->flags & FLAG_HARD_ERR) {
-       cmdp->hard_response(state);
-       return (0);
-    }
-    if (cmdp->flags & FLAG_SOFT_ERR) {
-       cmdp->soft_response(state);
-       return (0);
-    }
-    if (cmdp->response == data_response && fixed_delay > 0) {
-       event_request_timer(data_event, (char *) state, fixed_delay);
-    } else {
-       cmdp->response(state);
-       if (cmdp->response == quit_response)
-           return (-1);
-    }
-    return (0);
+    return (command_resp(state, cmdp, command, ptr));
 }
 
 /* read_timeout - handle timer event */
@@ -744,15 +765,12 @@ static void connect_event(int unused_event, char *context)
            return;
 
        case 0:
-           if (pretend_pix)
-               smtp_printf(state->stream, "220 ********");
-           else if (disable_esmtp)
-               smtp_printf(state->stream, "220 %s", var_myhostname);
-           else
-               smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
-           smtp_flush(state->stream);
-           event_enable_read(fd, read_event, (char *) state);
-           event_request_timer(read_timeout, (char *) state, var_tmout);
+           if (command_resp(state, command_table, "connect", "") < 0)
+               disconnect(state);
+           else {
+               event_enable_read(fd, read_event, (char *) state);
+               event_request_timer(read_timeout, (char *) state, var_tmout);
+           }
        }
     }
 }
index fb50f316ad5a45206fe0a8a0a0b26789251b7c71..6ee23df7106cbaa7617fb10f41694d07b11336ca 100644 (file)
@@ -223,6 +223,7 @@ tls_stream.o: ../../include/vstring.h
 tls_stream.o: tls.h
 tls_stream.o: tls_stream.c
 tls_verify.o: ../../include/msg.h
+tls_verify.o: ../../include/mymalloc.h
 tls_verify.o: ../../include/sys_defs.h
 tls_verify.o: ../../include/vbuf.h
 tls_verify.o: ../../include/vstream.h
index df1168c68c07e274e710c3da9172582c8321857b..8010a205146fda90514caf10ba67f72ca962f6c3 100644 (file)
@@ -1309,9 +1309,6 @@ sane_accept.o: msg.h
 sane_accept.o: sane_accept.c
 sane_accept.o: sane_accept.h
 sane_accept.o: sys_defs.h
-sane_basename.o: msg.h
-sane_basename.o: mymalloc.c
-sane_basename.o: mymalloc.h
 sane_basename.o: sane_basename.c
 sane_basename.o: stringops.h
 sane_basename.o: sys_defs.h
index c2ac9313709b0b635039de502bf13352d28eb35e..6c52e02c69343036d79f2218a4f76f968b684500 100644 (file)
@@ -24,7 +24,7 @@
   * 4.4BSD and close derivatives.
   */
 #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
-    || defined(FREEBSD5) \
+    || defined(FREEBSD5) || defined(FREEBSD6) \
     || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
     || defined(OPENBSD2) || defined(OPENBSD3) \
     || defined(NETBSD1) || defined(NETBSD2) \
@@ -275,6 +275,7 @@ extern int opterr;                  /* XXX use <getopt.h> */
 #define fpos_t long
 #define MISSING_SETENV
 #define MISSING_STRERROR
+#define MISSING_STRTOUL
 #define _PATH_MAILDIR  "/var/spool/mail"
 #define _PATH_BSHELL   "/bin/sh"
 #define _PATH_DEFPATH  "/usr/bin:/usr/ucb"
index 5061138a82c4f4fb8f0a8162efbc06719dfaeea4..3592ffaa9eefb1ef08416afbc73a5f93fd686d3f 100644 (file)
@@ -70,6 +70,7 @@ verify.o: ../../include/mail_params.h
 verify.o: ../../include/mail_proto.h
 verify.o: ../../include/mail_server.h
 verify.o: ../../include/msg.h
+verify.o: ../../include/msg_stats.h
 verify.o: ../../include/mymalloc.h
 verify.o: ../../include/post_mail.h
 verify.o: ../../include/recipient_list.h
index 4c664cf7000af1ae9f1099d720187ea66cce1728..4f51bb777a3916dae65d779fa5f965573d255223 100644 (file)
@@ -57,6 +57,7 @@ depend: $(MAKES)
 
 # do not edit below this line - it is generated by 'make depend'
 deliver_attr.o: ../../include/argv.h
+deliver_attr.o: ../../include/attr.h
 deliver_attr.o: ../../include/deliver_request.h
 deliver_attr.o: ../../include/dict.h
 deliver_attr.o: ../../include/dsn.h
@@ -64,6 +65,7 @@ deliver_attr.o: ../../include/dsn_buf.h
 deliver_attr.o: ../../include/maps.h
 deliver_attr.o: ../../include/mbox_conf.h
 deliver_attr.o: ../../include/msg.h
+deliver_attr.o: ../../include/msg_stats.h
 deliver_attr.o: ../../include/recipient_list.h
 deliver_attr.o: ../../include/sys_defs.h
 deliver_attr.o: ../../include/vbuf.h
@@ -72,6 +74,7 @@ deliver_attr.o: ../../include/vstring.h
 deliver_attr.o: deliver_attr.c
 deliver_attr.o: virtual.h
 mailbox.o: ../../include/argv.h
+mailbox.o: ../../include/attr.h
 mailbox.o: ../../include/bounce.h
 mailbox.o: ../../include/defer.h
 mailbox.o: ../../include/deliver_request.h
@@ -86,6 +89,7 @@ mailbox.o: ../../include/maps.h
 mailbox.o: ../../include/mbox_conf.h
 mailbox.o: ../../include/mbox_open.h
 mailbox.o: ../../include/msg.h
+mailbox.o: ../../include/msg_stats.h
 mailbox.o: ../../include/mymalloc.h
 mailbox.o: ../../include/recipient_list.h
 mailbox.o: ../../include/safe_open.h
@@ -99,6 +103,7 @@ mailbox.o: ../../include/vstring.h
 mailbox.o: mailbox.c
 mailbox.o: virtual.h
 maildir.o: ../../include/argv.h
+maildir.o: ../../include/attr.h
 maildir.o: ../../include/bounce.h
 maildir.o: ../../include/defer.h
 maildir.o: ../../include/deliver_request.h
@@ -114,6 +119,7 @@ maildir.o: ../../include/maps.h
 maildir.o: ../../include/mbox_conf.h
 maildir.o: ../../include/mbox_open.h
 maildir.o: ../../include/msg.h
+maildir.o: ../../include/msg_stats.h
 maildir.o: ../../include/mymalloc.h
 maildir.o: ../../include/recipient_list.h
 maildir.o: ../../include/safe_open.h
@@ -128,6 +134,7 @@ maildir.o: ../../include/vstring.h
 maildir.o: maildir.c
 maildir.o: virtual.h
 recipient.o: ../../include/argv.h
+recipient.o: ../../include/attr.h
 recipient.o: ../../include/bounce.h
 recipient.o: ../../include/deliver_request.h
 recipient.o: ../../include/dict.h
@@ -136,6 +143,7 @@ recipient.o: ../../include/dsn_buf.h
 recipient.o: ../../include/maps.h
 recipient.o: ../../include/mbox_conf.h
 recipient.o: ../../include/msg.h
+recipient.o: ../../include/msg_stats.h
 recipient.o: ../../include/mymalloc.h
 recipient.o: ../../include/recipient_list.h
 recipient.o: ../../include/stringops.h
@@ -146,6 +154,7 @@ recipient.o: ../../include/vstring.h
 recipient.o: recipient.c
 recipient.o: virtual.h
 unknown.o: ../../include/argv.h
+unknown.o: ../../include/attr.h
 unknown.o: ../../include/bounce.h
 unknown.o: ../../include/deliver_request.h
 unknown.o: ../../include/dict.h
@@ -154,6 +163,7 @@ unknown.o: ../../include/dsn_buf.h
 unknown.o: ../../include/maps.h
 unknown.o: ../../include/mbox_conf.h
 unknown.o: ../../include/msg.h
+unknown.o: ../../include/msg_stats.h
 unknown.o: ../../include/recipient_list.h
 unknown.o: ../../include/sys_defs.h
 unknown.o: ../../include/vbuf.h
@@ -162,6 +172,7 @@ unknown.o: ../../include/vstring.h
 unknown.o: unknown.c
 unknown.o: virtual.h
 virtual.o: ../../include/argv.h
+virtual.o: ../../include/attr.h
 virtual.o: ../../include/deliver_completed.h
 virtual.o: ../../include/deliver_request.h
 virtual.o: ../../include/dict.h
@@ -177,6 +188,7 @@ virtual.o: ../../include/mail_server.h
 virtual.o: ../../include/maps.h
 virtual.o: ../../include/mbox_conf.h
 virtual.o: ../../include/msg.h
+virtual.o: ../../include/msg_stats.h
 virtual.o: ../../include/recipient_list.h
 virtual.o: ../../include/set_eugid.h
 virtual.o: ../../include/sys_defs.h
index f71aa9b7c92ca2d5510bfae12c0c0c2619dbdc1e..89ca83351a36c0b4c892788a07c7c29914a53e9f 100644 (file)
@@ -359,7 +359,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
     state.msg_attr.dsn_envid = rqst->dsn_envid;
     state.msg_attr.dsn_ret = rqst->dsn_ret;
     state.msg_attr.relay = service;
-    state.msg_attr.arrival_time = rqst->arrival_time;
+    state.msg_attr.msg_stats = rqst->msg_stats;
     RESET_USER_ATTR(usr_attr, state.level);
     state.request = rqst;
 
index 7bd68a20953742a7fba5cc4eda4bb5aa8737f657..b7493606763d7c44a10a3eec425c593bdb7f1d56 100644 (file)
@@ -74,7 +74,7 @@ typedef struct DELIVER_ATTR {
     char   *user;                      /* recipient lookup handle */
     const char *delivered;             /* for loop detection */
     char   *relay;                     /* relay host */
-    long    arrival_time;              /* arrival time */
+    MSG_STATS msg_stats;               /* time profile */
     DSN_BUF *why;                      /* delivery status */
     DSN     dsn;                       /* delivery status */
 } DELIVER_ATTR;
@@ -102,10 +102,10 @@ typedef struct LOCAL_STATE {
 #define BOUNCE_FLAGS(request)  DEL_REQ_TRACE_FLAGS((request)->flags)
 
 #define BOUNCE_ATTR(attr) \
-       attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+       attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
        DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
 #define SENT_ATTR(attr) \
-       attr.queue_id, attr.arrival_time, &attr.rcpt, attr.relay, \
+       attr.queue_id, &attr.msg_stats, &attr.rcpt, attr.relay, \
        DSN_FROM_DSN_BUF(&attr.dsn, attr.why)
 #define COPY_ATTR(attr) \
        attr.sender, attr.rcpt.orig_addr, attr.delivered, attr.fp