From: Wietse Venema Date: Thu, 3 Nov 2005 05:00:00 +0000 (-0500) Subject: postfix-2.3-20051103 X-Git-Tag: v2.3-RC1~54 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=242e23744f5cd487f9cf3bf1f74d8776b8378288;p=thirdparty%2Fpostfix.git postfix-2.3-20051103 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 289be98f6..f55941ec6 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -133,6 +133,7 @@ -TMKMAP_DB -TMKMAP_DBM -TMKMAP_OPEN_INFO +-TMSG_STATS -TMULTI_SERVER -TMVECT -TMYSQL diff --git a/postfix/ENHANCED_STATUS_README b/postfix/ENHANCED_STATUS_README index bf0207f62..eaf9435bc 100644 --- a/postfix/ENHANCED_STATUS_README +++ b/postfix/ENHANCED_STATUS_README @@ -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. diff --git a/postfix/HISTORY b/postfix/HISTORY index 523ecbd42..fc583f8eb 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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. diff --git a/postfix/README_FILES/TLS_README b/postfix/README_FILES/TLS_README index 3c8fbb41b..676b4005a 100644 --- a/postfix/README_FILES/TLS_README +++ b/postfix/README_FILES/TLS_README @@ -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 diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index d6b254f51..fa4d681c0 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -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 ====================================== diff --git a/postfix/conf/access b/postfix/conf/access index 835fb448e..ed1c2e003 100644 --- a/postfix/conf/access +++ b/postfix/conf/access @@ -216,146 +216,149 @@ # 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: @@ -370,7 +373,7 @@ # 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 @@ -379,13 +382,13 @@ # 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) diff --git a/postfix/conf/header_checks b/postfix/conf/header_checks index 0389acf58..238599ffd 100644 --- a/postfix/conf/header_checks +++ b/postfix/conf/header_checks @@ -139,57 +139,60 @@ # # 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... @@ -198,18 +201,18 @@ # # 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- @@ -218,46 +221,46 @@ # 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- @@ -266,26 +269,26 @@ # 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:. # @@ -293,11 +296,11 @@ # 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. # @@ -307,32 +310,32 @@ # # 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: @@ -364,7 +367,7 @@ # 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 @@ -372,7 +375,7 @@ # 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) diff --git a/postfix/html/TLS_README.html b/postfix/html/TLS_README.html index 307f40741..0ff0d03f2 100644 --- a/postfix/html/TLS_README.html +++ b/postfix/html/TLS_README.html @@ -262,7 +262,7 @@ the overhead of the TLS exchange.

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_CApat accessible inside the optional chroot jail.

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 diff --git a/postfix/html/access.5.html b/postfix/html/access.5.html index 86500e622..85c10ed26 100644 --- a/postfix/html/access.5.html +++ b/postfix/html/access.5.html @@ -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 + 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: @@ -376,7 +379,7 @@ ACCESS(5) ACCESS(5) 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 @@ -389,7 +392,7 @@ ACCESS(5) ACCESS(5) 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) diff --git a/postfix/html/header_checks.5.html b/postfix/html/header_checks.5.html index 38dfa8eb4..4fd5a9ed0 100644 --- a/postfix/html/header_checks.5.html +++ b/postfix/html/header_checks.5.html @@ -145,57 +145,60 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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... @@ -204,18 +207,18 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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- @@ -224,46 +227,46 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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- @@ -272,26 +275,26 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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:. @@ -299,11 +302,11 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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. @@ -313,32 +316,32 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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: @@ -376,7 +379,7 @@ HEADER_CHECKS(5) HEADER_CHECKS(5) 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) diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 7b018576f..107acd8fb 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -5939,10 +5939,11 @@ delivery performance.

(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.

-

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.

@@ -5958,6 +5959,58 @@ not specify larger values without permission from the remote sites.

This feature is available in Postfix 2.2 and later.

+ + +
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). +

+ +

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.

+ +

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

+ +

This feature is available in Postfix 2.3 and later.

+ +
smtp_data_done_timeout diff --git a/postfix/html/smtp-sink.1.html b/postfix/html/smtp-sink.1.html index 3dfe0f56f..dcd9623de 100644 --- a/postfix/html/smtp-sink.1.html +++ b/postfix/html/smtp-sink.1.html @@ -51,11 +51,11 @@ SMTP-SINK(1) SMTP-SINK(1) Reject the specified commands with a hard (5xx) error code. This option implies -p. - 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. -F 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. -r command,command,... Reject the specified commands with a soft (4xx) error code. This option implies -p. - 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. -s command,command,... 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. -t timeout (default: 100) Limit the time for receiving a command or sending a diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 4b1d90606..b96588b21 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -373,58 +373,57 @@ SMTP(8) SMTP(8) destination has a high volume of mail in the active queue. - smtp_connection_cache_reuse_limit (10) - When SMTP connection caching is enabled, the number - of times that an SMTP session is reused before it - is closed. + smtp_connection_reuse_time_limit (300s) + The amount of time during which Postfix will use an + SMTP connection repeatedly. smtp_connection_cache_time_limit (2s) 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. TROUBLE SHOOTING CONTROLS debug_peer_level (2) - 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 debug_peer_list parameter. debug_peer_list (empty) - 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 $debug_peer_level. error_notice_recipient (postmaster) - 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. notify_classes (resource, software) - The list of error classes that are reported to the + The list of error classes that are reported to the postmaster. MISCELLANEOUS CONTROLS best_mx_transport (empty) - 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. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. daemon_timeout (18000s) - 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. disable_dns_lookups (no) - Disable DNS lookups in the Postfix SMTP and LMTP + Disable DNS lookups in the Postfix SMTP and LMTP clients. fallback_relay (empty) - 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. inet_interfaces (all) @@ -432,7 +431,7 @@ SMTP(8) SMTP(8) tem receives mail on. inet_protocols (ipv4) - The Internet protocols Postfix will attempt to use + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) @@ -440,55 +439,55 @@ SMTP(8) SMTP(8) over an internal communication channel. max_idle (100s) - 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. max_use (100) - The maximal number of connection requests before a + The maximal number of connection requests before a Postfix daemon process terminates. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. proxy_interfaces (empty) 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. smtp_bind_address (empty) 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. smtp_bind_address6 (empty) 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. smtp_helo_name ($myhostname) - The hostname to send in the SMTP EHLO or HELO com- + The hostname to send in the SMTP EHLO or HELO com- mand. smtp_host_lookup (dns) - What mechanisms when the SMTP client uses to look + What mechanisms when the SMTP client uses to look up a host's IP address. smtp_randomize_addresses (yes) - Randomize the order of equal-preference MX host + Randomize the order of equal-preference MX host addresses. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - 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". SEE ALSO @@ -506,7 +505,7 @@ SMTP(8) SMTP(8) TLS_README, Postfix STARTTLS howto LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/makedefs b/postfix/makedefs index a01cd78a2..d8a3426fc 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -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' <) { s;\bsmtp_connection_cache_on_demand\b;$&;g; s;\bsmtp_connection_cache_reuse_limit\b;$&;g; + s;\bsmtp_connection_reuse_time_limit\b;$&;g; s;\bsmtp_connection_cache_time_limit\b;$&;g; s;\bsmtp_connection_cache_destinations\b;$&;g; diff --git a/postfix/proto/TLS_README.html b/postfix/proto/TLS_README.html index 5e3243b0d..20154a37f 100644 --- a/postfix/proto/TLS_README.html +++ b/postfix/proto/TLS_README.html @@ -262,7 +262,7 @@ the overhead of the TLS exchange.

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.

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 diff --git a/postfix/proto/access b/postfix/proto/access index b612b1dde..69598470f 100644 --- a/postfix/proto/access +++ b/postfix/proto/access @@ -189,6 +189,8 @@ # 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 diff --git a/postfix/proto/header_checks b/postfix/proto/header_checks index 8ae1b465a..736c09e25 100644 --- a/postfix/proto/header_checks +++ b/postfix/proto/header_checks @@ -127,6 +127,8 @@ # .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 diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index adcf4124d..00b60b9b8 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -3532,10 +3532,59 @@ not specify larger values without permission from the remote sites. %PARAM smtp_connection_cache_reuse_limit 10

When SMTP connection caching is enabled, the number of times that -an SMTP session is reused before it is closed. -

- -

This feature is available in Postfix 2.2 and later.

+an SMTP session may be reused before it is closed. +

+ +

This feature is available in Postfix 2.2. In Postfix 2.3 it is +replaced by $smtp_connection_reuse_time_limit.

+ +%PARAM smtp_connection_reuse_time_limit 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). +

+ +

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.

+ +

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

+ +

This feature is available in Postfix 2.3 and later.

%PARAM smtp_connection_cache_destinations diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in index 66a6a9fa3..f8b0a6e43 100644 --- a/postfix/src/bounce/Makefile.in +++ b/postfix/src/bounce/Makefile.in @@ -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 diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index f827e1f82..218c3a481 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -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 diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h index fb3283e31..57750a849 100644 --- a/postfix/src/cleanup/cleanup.h +++ b/postfix/src/cleanup/cleanup.h @@ -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 diff --git a/postfix/src/cleanup/cleanup_bounce.c b/postfix/src/cleanup/cleanup_bounce.c index aa78950aa..6ca62967b 100644 --- a/postfix/src/cleanup/cleanup_bounce.c +++ b/postfix/src/cleanup/cleanup_bounce.c @@ -65,7 +65,10 @@ 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; diff --git a/postfix/src/cleanup/cleanup_out_recipient.c b/postfix/src/cleanup/cleanup_out_recipient.c index ad3d04b61..94af4cb78 100644 --- a/postfix/src/cleanup/cleanup_out_recipient.c +++ b/postfix/src/cleanup/cleanup_out_recipient.c @@ -82,6 +82,7 @@ #include #include /* cleanup_trace_path */ #include +#include /* Application-specific. */ @@ -92,12 +93,15 @@ 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; diff --git a/postfix/src/discard/Makefile.in b/postfix/src/discard/Makefile.in index d6621171d..e3df656ad 100644 --- a/postfix/src/discard/Makefile.in +++ b/postfix/src/discard/Makefile.in @@ -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 diff --git a/postfix/src/discard/discard.c b/postfix/src/discard/discard.c index c1c00bbf3..b2feeaeb2 100644 --- a/postfix/src/discard/discard.c +++ b/postfix/src/discard/discard.c @@ -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; diff --git a/postfix/src/error/Makefile.in b/postfix/src/error/Makefile.in index ac16bc189..9dd13f5ef 100644 --- a/postfix/src/error/Makefile.in +++ b/postfix/src/error/Makefile.in @@ -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 diff --git a/postfix/src/error/error.c b/postfix/src/error/error.c index 803bb2e56..11343129c 100644 --- a/postfix/src/error/error.c +++ b/postfix/src/error/error.c @@ -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); diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index e950671e5..27dda27a0 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -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 diff --git a/postfix/src/global/bounce.c b/postfix/src/global/bounce.c index 7ae333735..440e4ebcf 100644 --- a/postfix/src/global/bounce.c +++ b/postfix/src/global/bounce.c @@ -6,10 +6,10 @@ /* SYNOPSIS /* #include /* -/* 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 @@ -164,7 +165,7 @@ /* 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; diff --git a/postfix/src/global/bounce.h b/postfix/src/global/bounce.h index c8678b1e6..bde6451c1 100644 --- a/postfix/src/global/bounce.h +++ b/postfix/src/global/bounce.h @@ -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 *); /* diff --git a/postfix/src/global/defer.c b/postfix/src/global/defer.c index 32a304c16..0f0a57b98 100644 --- a/postfix/src/global/defer.c +++ b/postfix/src/global/defer.c @@ -6,10 +6,10 @@ /* SYNOPSIS /* #include /* -/* 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 @@ -143,7 +144,7 @@ /* 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); /* diff --git a/postfix/src/global/defer.h b/postfix/src/global/defer.h index fe1f71291..ba9be7d69 100644 --- a/postfix/src/global/defer.h +++ b/postfix/src/global/defer.h @@ -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); diff --git a/postfix/src/global/deliver_pass.c b/postfix/src/global/deliver_pass.c index 1922db714..943a58c25 100644 --- a/postfix/src/global/deliver_pass.c +++ b/postfix/src/global/deliver_pass.c @@ -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, diff --git a/postfix/src/global/deliver_request.c b/postfix/src/global/deliver_request.c index 14ddda513..fba702725 100644 --- a/postfix/src/global/deliver_request.c +++ b/postfix/src/global/deliver_request.c @@ -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)); diff --git a/postfix/src/global/deliver_request.h b/postfix/src/global/deliver_request.h index d676748a5..ba3afb5b3 100644 --- a/postfix/src/global/deliver_request.h +++ b/postfix/src/global/deliver_request.h @@ -22,6 +22,7 @@ */ #include #include +#include /* * 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 */ diff --git a/postfix/src/global/log_adhoc.c b/postfix/src/global/log_adhoc.c index fd816dee4..ebb1ce193 100644 --- a/postfix/src/global/log_adhoc.c +++ b/postfix/src/global/log_adhoc.c @@ -6,9 +6,9 @@ /* SYNOPSIS /* #include /* -/* 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 @@ -67,21 +68,124 @@ #include -/* 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)); } diff --git a/postfix/src/global/log_adhoc.h b/postfix/src/global/log_adhoc.h index 3a8789d2f..583cb6122 100644 --- a/postfix/src/global/log_adhoc.h +++ b/postfix/src/global/log_adhoc.h @@ -21,11 +21,12 @@ */ #include #include +#include /* * 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 diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 0ca0f9a1b..da7930180 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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 "" diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 780c2441a..274e921fd 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 index 000000000..ea24921f0 --- /dev/null +++ b/postfix/src/global/msg_stats.h @@ -0,0 +1,99 @@ +#ifndef _MSG_STATS_H_INCLUDED_ +#define _MSG_STATS_H_INCLUDED_ + +/*++ +/* NAME +/* msg_stats 3h +/* SUMMARY +/* message delivery profiling +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include +#include +#include + + /* + * Utility library. + */ +#include +#include + + /* + * 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 index 000000000..cffc2f1d4 --- /dev/null +++ b/postfix/src/global/msg_stats_print.c @@ -0,0 +1,63 @@ +/*++ +/* NAME +/* msg_stats_print +/* SUMMARY +/* write MSG_STATS structure to stream +/* SYNOPSIS +/* #include +/* +/* 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 + +/* Utility library. */ + +#include + +/* Global library. */ + +#include +#include + +/* 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 index 000000000..bc7d3c4fb --- /dev/null +++ b/postfix/src/global/msg_stats_scan.c @@ -0,0 +1,86 @@ +/*++ +/* NAME +/* msg_stats_scan +/* SUMMARY +/* read MSG_STATS from stream +/* SYNOPSIS +/* #include +/* +/* 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 + +/* Utility library. */ + +#include +#include +#include + +/* Global library. */ + +#include +#include + + /* + * 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); +} diff --git a/postfix/src/global/rcpt_print.c b/postfix/src/global/rcpt_print.c index b923e6f04..47af47032 100644 --- a/postfix/src/global/rcpt_print.c +++ b/postfix/src/global/rcpt_print.c @@ -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) diff --git a/postfix/src/global/sent.c b/postfix/src/global/sent.c index f055267d9..56fdd8e2f 100644 --- a/postfix/src/global/sent.c +++ b/postfix/src/global/sent.c @@ -6,10 +6,10 @@ /* SYNOPSIS /* #include /* -/* 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); diff --git a/postfix/src/global/sent.h b/postfix/src/global/sent.h index 66a85c247..eb9a23f2f 100644 --- a/postfix/src/global/sent.h +++ b/postfix/src/global/sent.h @@ -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 diff --git a/postfix/src/global/trace.c b/postfix/src/global/trace.c index fa9962f4f..d6d30a098 100644 --- a/postfix/src/global/trace.c +++ b/postfix/src/global/trace.c @@ -6,10 +6,10 @@ /* SYNOPSIS /* #include /* -/* 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 @@ -102,7 +103,7 @@ /* 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); diff --git a/postfix/src/global/trace.h b/postfix/src/global/trace.h index 13f4f8aff..201360198 100644 --- a/postfix/src/global/trace.h +++ b/postfix/src/global/trace.h @@ -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); diff --git a/postfix/src/global/verify.c b/postfix/src/global/verify.c index a7615ef55..df83d4ed0 100644 --- a/postfix/src/global/verify.c +++ b/postfix/src/global/verify.c @@ -6,10 +6,10 @@ /* SYNOPSIS /* #include /* -/* 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); diff --git a/postfix/src/global/verify.h b/postfix/src/global/verify.h index efc43546f..250eb6d65 100644 --- a/postfix/src/global/verify.h +++ b/postfix/src/global/verify.h @@ -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 diff --git a/postfix/src/lmtp/Makefile.in b/postfix/src/lmtp/Makefile.in index acecf0142..10210d785 100644 --- a/postfix/src/lmtp/Makefile.in +++ b/postfix/src/lmtp/Makefile.in @@ -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 diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c index be7460750..40eb6cbdd 100644 --- a/postfix/src/lmtp/lmtp_proto.c +++ b/postfix/src/lmtp/lmtp_proto.c @@ -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) { diff --git a/postfix/src/lmtp/lmtp_rcpt.c b/postfix/src/lmtp/lmtp_rcpt.c index 612d7f1ea..8d2b3e010 100644 --- a/postfix/src/lmtp/lmtp_rcpt.c +++ b/postfix/src/lmtp/lmtp_rcpt.c @@ -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) diff --git a/postfix/src/lmtp/lmtp_trouble.c b/postfix/src/lmtp/lmtp_trouble.c index ce0966739..5ef08f9a2 100644 --- a/postfix/src/lmtp/lmtp_trouble.c +++ b/postfix/src/lmtp/lmtp_trouble.c @@ -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); diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in index 67e85f9e4..e099b1e4f 100644 --- a/postfix/src/local/Makefile.in +++ b/postfix/src/local/Makefile.in @@ -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 diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c index d01207be7..d505469a1 100644 --- a/postfix/src/local/local.c +++ b/postfix/src/local/local.c @@ -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); diff --git a/postfix/src/local/local.h b/postfix/src/local/local.h index d1dc5d07e..2e3d79359 100644 --- a/postfix/src/local/local.h +++ b/postfix/src/local/local.h @@ -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 diff --git a/postfix/src/oqmgr/Makefile.in b/postfix/src/oqmgr/Makefile.in index a9783c421..39c95e71e 100644 --- a/postfix/src/oqmgr/Makefile.in +++ b/postfix/src/oqmgr/Makefile.in @@ -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 diff --git a/postfix/src/oqmgr/qmgr.h b/postfix/src/oqmgr/qmgr.h index 7e35ec8c5..1ce8bc377 100644 --- a/postfix/src/oqmgr/qmgr.h +++ b/postfix/src/oqmgr/qmgr.h @@ -8,6 +8,12 @@ /* DESCRIPTION /* .nf + /* + * System library. + */ +#include +#include + /* * 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 */ diff --git a/postfix/src/oqmgr/qmgr_bounce.c b/postfix/src/oqmgr/qmgr_bounce.c index 5a763042d..00ba885bf 100644 --- a/postfix/src/oqmgr/qmgr_bounce.c +++ b/postfix/src/oqmgr/qmgr_bounce.c @@ -57,10 +57,11 @@ 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) diff --git a/postfix/src/oqmgr/qmgr_defer.c b/postfix/src/oqmgr/qmgr_defer.c index 234632cc2..51eaf8643 100644 --- a/postfix/src/oqmgr/qmgr_defer.c +++ b/postfix/src/oqmgr/qmgr_defer.c @@ -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); } diff --git a/postfix/src/oqmgr/qmgr_deliver.c b/postfix/src/oqmgr/qmgr_deliver.c index 38b55198c..b3e4cd656 100644 --- a/postfix/src/oqmgr/qmgr_deliver.c +++ b/postfix/src/oqmgr/qmgr_deliver.c @@ -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, diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index 6df215679..cae8af502 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -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) { diff --git a/postfix/src/pipe/Makefile.in b/postfix/src/pipe/Makefile.in index fd0419281..f4dde9603 100644 --- a/postfix/src/pipe/Makefile.in +++ b/postfix/src/pipe/Makefile.in @@ -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 diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c index 795030d48..921f6e40e 100644 --- a/postfix/src/pipe/pipe.c +++ b/postfix/src/pipe/pipe.c @@ -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); diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index 5565d65d6..04f540c9a 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -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 diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index a51fc032f..7225920eb 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -8,6 +8,12 @@ /* DESCRIPTION /* .nf + /* + * System library. + */ +#include +#include + /* * 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 diff --git a/postfix/src/qmgr/qmgr_bounce.c b/postfix/src/qmgr/qmgr_bounce.c index 31ed814d3..c5ea16178 100644 --- a/postfix/src/qmgr/qmgr_bounce.c +++ b/postfix/src/qmgr/qmgr_bounce.c @@ -62,10 +62,11 @@ 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) diff --git a/postfix/src/qmgr/qmgr_defer.c b/postfix/src/qmgr/qmgr_defer.c index 0c86131d2..4c70eef76 100644 --- a/postfix/src/qmgr/qmgr_defer.c +++ b/postfix/src/qmgr/qmgr_defer.c @@ -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); } diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index 38e940979..28f0f2c46 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -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, diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index e1868d680..da481b847 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -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) { diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in index d5a176ca2..45f391281 100644 --- a/postfix/src/sendmail/Makefile.in +++ b/postfix/src/sendmail/Makefile.in @@ -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 diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index 2f2182224..88a5b6807 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -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(); diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index f276a485a..a67da3b55 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -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 diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index c2944f737..bf124e6ce 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -274,9 +274,9 @@ /* .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 diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 919cc8132..6f865f131 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -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 */ diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index 00f4ccbb5..61f7a389e 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -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 @@ -38,11 +38,37 @@ /* 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 diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index 1af797bf5..abe387bb0 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -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 */ diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index a52fd6106..21a1189e1 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -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 @@ -45,6 +45,12 @@ /* 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 . workaround for %s", request->queue_id, session->namaddr); diff --git a/postfix/src/smtp/smtp_rcpt.c b/postfix/src/smtp/smtp_rcpt.c index b1cd74302..425e939de 100644 --- a/postfix/src/smtp/smtp_rcpt.c +++ b/postfix/src/smtp/smtp_rcpt.c @@ -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) diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index e71defd9d..6347e2206 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -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. diff --git a/postfix/src/smtp/smtp_trouble.c b/postfix/src/smtp/smtp_trouble.c index 73d3abf2b..9e218daa4 100644 --- a/postfix/src/smtp/smtp_trouble.c +++ b/postfix/src/smtp/smtp_trouble.c @@ -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); diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 5ce6bf606..78010673d 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -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 diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c index 024eb0c7d..15140378c 100644 --- a/postfix/src/smtpstone/smtp-sink.c +++ b/postfix/src/smtpstone/smtp-sink.c @@ -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. @@ -75,14 +75,14 @@ /* 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); + } } } } diff --git a/postfix/src/tls/Makefile.in b/postfix/src/tls/Makefile.in index fb50f316a..6ee23df71 100644 --- a/postfix/src/tls/Makefile.in +++ b/postfix/src/tls/Makefile.in @@ -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 diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index df1168c68..8010a2051 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -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 diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index c2ac93137..6c52e02c6 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -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 */ #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" diff --git a/postfix/src/verify/Makefile.in b/postfix/src/verify/Makefile.in index 5061138a8..3592ffaa9 100644 --- a/postfix/src/verify/Makefile.in +++ b/postfix/src/verify/Makefile.in @@ -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 diff --git a/postfix/src/virtual/Makefile.in b/postfix/src/virtual/Makefile.in index 4c664cf70..4f51bb777 100644 --- a/postfix/src/virtual/Makefile.in +++ b/postfix/src/virtual/Makefile.in @@ -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 diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c index f71aa9b7c..89ca83351 100644 --- a/postfix/src/virtual/virtual.c +++ b/postfix/src/virtual/virtual.c @@ -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; diff --git a/postfix/src/virtual/virtual.h b/postfix/src/virtual/virtual.h index 7bd68a209..b74936067 100644 --- a/postfix/src/virtual/virtual.h +++ b/postfix/src/virtual/virtual.h @@ -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