treated as ordinary errors, and one corner-case error in TLS
timeout handling was fixed before it could cause trouble.
File: tls/tls_bio_ops.c.
+
+20110821-24
+
+ Cleanup: simplified the TLS read/write deadline implementation,
+ and documented why this same simplification is not possible
+ higher-up, at the VSTREAM level. Files: tls/tls_bio_ops.c,
+ util/vstream.c.
+
+20110831
+
+ Bugfix: allow for Milters that send an SMTP server reply
+ without RFC 3463 enhanced status code. Reported by Vladimir
+ Vassiliev. File: milter/milter8.c.
+
+20110902
+
+ Cleanup: don't log vstream_tweak "connection reset by peer"
+ errors. File: util/vstream_tweak.c.
+
+20110903
+
+ Bugfix: master daemon panic with an "at process limit X"
+ error, when "postfix reload" reduced the process limit for
+ some Postfix service from (a value larger than the current
+ process count for that service) to (a value <= the current
+ process count), and then a new connection was made to that
+ service. File: master/master_avail.c.
Things to do after the stable release:
+ Investigate viability of Sendmail socket maps (the moral
+ equivalent of tcp_table(5)), and dns maps.
+
Make the rules for how to use close-on-exec more explicit.
Add SASL / TLS note to BASIC_CONFIGURATION_README.html#relay_from.
Find a place to document all the mail routing mechanisms
in one place so people can figure out how Postfix works.
- Investigate viability of Sendmail socket maps (the moral
- equivalent of tcp_table(5)), and dns maps.
-
The access map BCC action is marked "not stable", perhaps
because people would also expect BCC actions in header/body_checks.
How much would it take to make the queue file editing code
<p> Specify the name of a "<a href="DATABASE_README.html">type:table</a>" lookup table. The search
string is a single SMTP reply line as received from the remote SMTP
-server, except that the trailing <CR><LF> are removed. </p>
+server, except that the trailing <CR><LF> are removed.
+When the lookup succeeds, the result replaces the single SMTP reply
+line. </p>
<p> Examples: </p>
Specify the name of a "type:table" lookup table. The search
string is a single SMTP reply line as received from the remote SMTP
server, except that the trailing <CR><LF> are removed.
+When the lookup succeeds, the result replaces the single SMTP reply
+line.
.PP
Examples:
.PP
<p> Specify the name of a "type:table" lookup table. The search
string is a single SMTP reply line as received from the remote SMTP
-server, except that the trailing <CR><LF> are removed. </p>
+server, except that the trailing <CR><LF> are removed.
+When the lookup succeeds, the result replaces the single SMTP reply
+line. </p>
<p> Examples: </p>
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20110820"
+#define MAIL_RELEASE_DATE "20110905"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
if (event == 0) /* XXX Can this happen? */
return;
- if (MASTER_THROTTLED(serv)) { /* XXX interface botch */
+ /* XXX Should check these when the process or service status is changed. */
+ if (!MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)
+ || MASTER_THROTTLED(serv)) { /* XXX interface botch */
for (n = 0; n < serv->listen_fd_count; n++)
event_disable_readwrite(serv->listen_fd[n]);
} else {
MILTER8_DATA_BUFFER, milter->buf,
MILTER8_DATA_END) != 0)
MILTER8_EVENT_BREAK(milter->def_reply);
+ /* XXX Enforce this for each line of a multi-line reply. */
if ((STR(milter->buf)[0] != '4' && STR(milter->buf)[0] != '5')
|| !ISDIGIT(STR(milter->buf)[1])
|| !ISDIGIT(STR(milter->buf)[2])
|| (STR(milter->buf)[3] != ' ' && STR(milter->buf)[3] != '-')
- || STR(milter->buf)[4] != STR(milter->buf)[0]) {
+ || (ISDIGIT(STR(milter->buf)[4])
+ && (STR(milter->buf)[4] != STR(milter->buf)[0]))) {
msg_warn("milter %s: malformed reply: %s",
milter->m.name, STR(milter->buf));
milter8_conf_error(milter);
int status;
int err;
int enable_deadline;
- struct timeval time_limit; /* initial time limit */
struct timeval time_left; /* amount of time left */
- struct timeval time_entry; /* time of tls_bio() entry */
+ struct timeval time_deadline; /* time of deadline */
struct timeval time_now; /* time after SSL_mumble() call */
- struct timeval time_elapsed; /* total elapsed time */
/*
* Compensation for interface mis-match: With VSTREAMs, timeout <= 0
- * means wait forever; with the read/write_wait() calls below, we need
- * to specify timeout < 0 instead.
+ * means wait forever; with the read/write_wait() calls below, we need to
+ * specify timeout < 0 instead.
*
* Safety: no time limit means no deadline.
*/
enable_deadline =
vstream_fstat(TLScontext->stream, VSTREAM_FLAG_DEADLINE);
if (enable_deadline) {
- time_limit.tv_sec = timeout;
- time_limit.tv_usec = 0;
- GETTIMEOFDAY(&time_entry);
+ GETTIMEOFDAY(&time_deadline);
+ time_deadline.tv_sec += timeout;
}
}
case SSL_ERROR_WANT_READ:
if (enable_deadline) {
GETTIMEOFDAY(&time_now);
- timersub(&time_now, &time_entry, &time_elapsed);
- timersub(&time_limit, &time_elapsed, &time_left);
+ timersub(&time_deadline, &time_now, &time_left);
timeout = time_left.tv_sec + (time_left.tv_usec > 0);
if (timeout <= 0) {
errno = ETIMEDOUT;
* When flushing a buffer, allow for partial writes. These can happen
* while talking to a network. Update the cached file seek position, if
* any.
+ *
+ * When deadlines are enabled, we count the elapsed time for each write
+ * operation instead of simply comparing the time-of-day clock with a
+ * per-stream deadline. The latter could result in anomalies when an
+ * application does lengthy processing between write operations. Keep in
+ * mind that a receiver may not be able to keep up when a sender suddenly
+ * floods it with a lot of data as it tries to catch up with a deadline.
*/
for (data = (char *) bp->data, len = to_flush; len > 0; len -= n, data += n) {
if (bp->flags & VSTREAM_FLAG_DEADLINE) {
* Fill the buffer with as much data as we can handle, or with as much
* data as is available right now, whichever is less. Update the cached
* file seek position, if any.
+ *
+ * When deadlines are enabled, we count the elapsed time for each read
+ * operation instead of simply comparing the time-of-day clock with a
+ * per-stream deadline. The latter could result in anomalies when an
+ * application does lengthy processing between read operations. Keep in
+ * mind that a sender may get blocked, and may not be able to keep up
+ * when a receiver suddenly wants to read a lot of data as it tries to
+ * catch up with a deadline.
*/
if (bp->flags & VSTREAM_FLAG_DEADLINE) {
timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0);
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <errno.h>
/* Utility library. */
* whatever value was stored last with setsockopt()).
*/
if ((err = getsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_MAXSEG,
- (char *) &mss, &mss_len)) < 0) {
+ (char *) &mss, &mss_len)) < 0
+ && errno != ECONNRESET) {
msg_warn("%s: getsockopt TCP_MAXSEG: %m", myname);
return (err);
}
int nodelay = 1;
if ((err = setsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_NODELAY,
- (char *) &nodelay, sizeof(nodelay))) < 0)
+ (char *) &nodelay, sizeof(nodelay))) < 0
+ && errno != ECONNRESET)
msg_warn("%s: setsockopt TCP_NODELAY: %m", myname);
}
#endif