From: Wietse Venema Date: Tue, 31 Jul 2007 05:00:00 +0000 (-0500) Subject: postfix-2.5-20070731 X-Git-Tag: v2.5.0-RC1~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0463e04580f93799b915d9e0dcaff85dc57cc0ea;p=thirdparty%2Fpostfix.git postfix-2.5-20070731 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 428674f5f..1302134b5 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -13647,3 +13647,30 @@ Apologies for any names omitted. and RFC 3848 ("Received ... with ESMTPS?A? ...). Currently, support for the latter is always on. Files: smtpd/smtpd.c, smtpd/smtpd_sasl_proto.c, smtpd/smtpd_sasl_glue.c. + +20070727 + + Workaround: the queue manager no longer logs a warning for + mail sent to the local double-bounce address (normally, the + this is used as the sender while reporting an undeliverable + bounce message to the local postmaster). As of 20070503 + the local double-bounce address is the default sender for + sender/recipient address verification probes, and it now + shows up as a spam target. Files: *qmgr/qmgr_message.c. + +20070729 + + Performance: fix for poor TCP performance for loopback + (127.0.0.1) connections. Problem reported by Mark Martinec. + Files: util/vstream.c, util/vstream_tweak.c, milter/milter8.c, + smtp/smtp_connect.c, smtpstone/*source.c. + +20070730 + + Bugfix: when a milter replied with ACCEPT at or before the + first RCPT command, the cleanup server would apply the + non_smtpd_milters setting as if the message was a local + submission. Problem reported by Jukka Salmi. Also, the + cleanup server would get out of sync with the milter when + a milter replied with ACCEPT at the DATA command. Files: + cleanup/cleanup_envelope.c, smtpd/smtpd.c, milter/milters.c. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 68a99aa56..69d2600ab 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -20,9 +20,10 @@ before proceeding. Major changes with Postfix snapshot 20070724 ============================================ -Not really major. Support for RFC 3848 (ESMTPS, ESMTPA, ESMTPSA -in Received: headers) and updated SASL support with reply codes and -enhanced (DSN) status codes as per RFC 4954. +Not really major. New support for RFC 3848 (Received: headers with +ESMTPS, ESMTPA, or ESMTPSA); updated SASL support according to RFC +4954, resulting in small changes to SMTP reply codes and (DSN) +enhanced status codes. Incompatibility with Postfix snapshot 20070614 ============================================== diff --git a/postfix/WISHLIST b/postfix/WISHLIST index db194c8bb..e81bb404e 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -83,7 +83,7 @@ Wish list: configuration parameters or internal protocol attributes) should be changed from int to off_t. This also requires checking all expressions in which var_message_limit etc. - appears. + appears: qmqpd, netstring, deliver_request, ... Add M flag (enable multi-recipient delivery) to pipe daemon. diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 509224a17..3a7d15e3a 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -12,6 +12,8 @@ SMTPD(8) SMTPD(8) SYNOPSIS smtpd [generic Postfix daemon options] + sendmail -bs + DESCRIPTION The SMTP server accepts network connection requests and performs zero or more SMTP transactions per connection. diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 1f8606af7..93e343f8a 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -9,6 +9,8 @@ Postfix SMTP server .na .nf \fBsmtpd\fR [generic Postfix daemon options] + +\fBsendmail -bs\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c index ef4dbc7dc..830f37093 100644 --- a/postfix/src/cleanup/cleanup_envelope.c +++ b/postfix/src/cleanup/cleanup_envelope.c @@ -148,13 +148,7 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, #endif if (type == REC_TYPE_MILT_COUNT) { /* Not part of queue file format. */ - if (state->milters != 0) { - msg_warn("%s: message rejected: too many milter instances", - state->queue_id); - state->errs |= CLEANUP_STAT_BAD; - return; - } - if ((milter_count = atoi(buf)) > 0) + if ((milter_count = atoi(buf)) >= 0) cleanup_milter_receive(state, milter_count); return; } diff --git a/postfix/src/cleanup/cleanup_milter.c b/postfix/src/cleanup/cleanup_milter.c index 2212604a3..51755e8f3 100644 --- a/postfix/src/cleanup/cleanup_milter.c +++ b/postfix/src/cleanup/cleanup_milter.c @@ -1314,6 +1314,8 @@ static const char *cleanup_milter_eval(const char *name, void *ptr) void cleanup_milter_receive(CLEANUP_STATE *state, int count) { + if (state->milters) + milter_free(state->milters); state->milters = milter_receive(state->src, count); milter_macro_callback(state->milters, cleanup_milter_eval, (void *) state); milter_edit_callback(state->milters, diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 770cebca4..2638bce0a 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 "20070724" +#define MAIL_RELEASE_DATE "20070731" #define MAIL_VERSION_NUMBER "2.5" #ifdef SNAPSHOT diff --git a/postfix/src/milter/milter.c b/postfix/src/milter/milter.c index 51f968d80..2e0c73128 100644 --- a/postfix/src/milter/milter.c +++ b/postfix/src/milter/milter.c @@ -97,6 +97,10 @@ /* MILTERS *milter_receive(fp, count) /* VSTREAM *fp; /* int count; +/* +/* int milter_dummy(milters, fp) +/* MILTERS *milters; +/* VSTREAM *fp; /* DESCRIPTION /* The functions in this module manage one or more milter (mail /* filter) clients. Currently, only the Sendmail 8 filter @@ -192,6 +196,9 @@ /* milter_receive() receives the specified number of mail /* filters over the specified stream. The result is a null /* pointer when no milters were sent, or when an error happened. +/* +/* milter_dummy() is like milter_send(), except that it sends +/* a dummy, but entirely valid, mail filter list. /* SEE ALSO /* milter8(3) Sendmail 8 Milter protocol /* DIAGNOSTICS @@ -587,6 +594,16 @@ void milter_free(MILTERS *milters) #define MAIL_ATTR_MILT_EOD "eod_macros" #define MAIL_ATTR_MILT_UNK "unk_macros" +/* milter_dummy - send empty milter list */ + +int milter_dummy(MILTERS *milters, VSTREAM *stream) +{ + MILTERS dummy = *milters; + + dummy.milter_list = 0; + return (milter_send(&dummy, stream)); +} + /* milter_send - send Milter instances over stream */ int milter_send(MILTERS *milters, VSTREAM *stream) @@ -606,8 +623,6 @@ int milter_send(MILTERS *milters, VSTREAM *stream) for (m = milters->milter_list; m != 0; m = m->next) if (m->active(m)) count++; - if (count == 0) - return (0); (void) rec_fprintf(stream, REC_TYPE_MILT_COUNT, "%d", count); /* @@ -656,9 +671,6 @@ MILTERS *milter_receive(VSTREAM *stream, int count) VSTRING *eod_macros; VSTRING *unk_macros; - if (count == 0) - return (0); - /* * Receive filter macros. */ diff --git a/postfix/src/milter/milter.h b/postfix/src/milter/milter.h index 676322d4a..e0a4067ef 100644 --- a/postfix/src/milter/milter.h +++ b/postfix/src/milter/milter.h @@ -99,6 +99,7 @@ extern const char *milter_unknown_event(MILTERS *, const char *); extern const char *milter_other_event(MILTERS *); extern void milter_abort(MILTERS *); extern void milter_disc_event(MILTERS *); +extern int milter_dummy(MILTERS *, VSTREAM *); extern int milter_send(MILTERS *, VSTREAM *); extern MILTERS *milter_receive(VSTREAM *, int); extern void milter_free(MILTERS *); @@ -109,7 +110,7 @@ extern void milter_free(MILTERS *); #define MILTER_BODY_START 1 /* start message body */ #define MILTER_BODY_LINE 2 /* message body line */ #define MILTER_BODY_END 3 /* end message body */ - + /* * Sendmail 8 macro names. We support forms with and without the {}. */ diff --git a/postfix/src/milter/milter8.c b/postfix/src/milter/milter8.c index 8f1745ce7..d69024059 100644 --- a/postfix/src/milter/milter8.c +++ b/postfix/src/milter/milter8.c @@ -1591,6 +1591,9 @@ static void milter8_connect(MILTER8 *milter) VSTREAM_CTL_DOUBLE, VSTREAM_CTL_TIMEOUT, milter->cmd_timeout, VSTREAM_CTL_END); + /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ + if (connect_fn == inet_connect) + vstream_tweak_tcp(milter->fp); /* * Open the negotiations by sending what actions the Milter may request @@ -2485,7 +2488,7 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent) #endif } else { #define NO_PROTOCOL ((char *) 0) - + if (msg_verbose) msg_info("%s: milter %s", myname, STR(name_buf)); @@ -2493,6 +2496,8 @@ MILTER *milter8_receive(VSTREAM *stream, MILTERS *parent) msg_timeout, NO_PROTOCOL, STR(act_buf), parent); milter->fp = vstream_fdopen(fd, O_RDWR); vstream_control(milter->fp, VSTREAM_CTL_DOUBLE, VSTREAM_CTL_END); + /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ + vstream_tweak_sock(milter->fp); milter->version = version; milter->rq_mask = rq_mask; milter->ev_mask = ev_mask; diff --git a/postfix/src/milter/test-milter.c b/postfix/src/milter/test-milter.c index 5999b7add..0c33d8a5a 100644 --- a/postfix/src/milter/test-milter.c +++ b/postfix/src/milter/test-milter.c @@ -140,8 +140,10 @@ static int test_reply(SMFICTX *ctx, int code) if (code == SMFIR_REPLYCODE) { if (smfi_setreply(ctx, reply_code, reply_dsn, reply_message) == MI_FAILURE) fprintf(stderr, "smfi_setreply failed\n"); + printf("test_reply %s\n", reply_code); return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT); } else { + printf("test_reply %d\n", code); return (code); } } diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index a646daef9..4e3938506 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -1041,8 +1041,11 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) "undeliverable postmaster notification discarded")); if (status == 0) { deliver_completed(message->fp, recipient->offset); +#if 0 + /* It's the default verification probe sender address. */ msg_warn("%s: undeliverable postmaster notification discarded", message->queue_id); +#endif } else message->flags |= status; continue; diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index 9be26ec1c..eeedefbcf 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -1100,8 +1100,11 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message) "undeliverable postmaster notification discarded")); if (status == 0) { deliver_completed(message->fp, recipient->offset); +#if 0 + /* It's the default verification probe sender address. */ msg_warn("%s: undeliverable postmaster notification discarded", message->queue_id); +#endif } else message->flags |= status; continue; diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index 1430c8ced..6089f093f 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -297,12 +297,26 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa, conn_stat = sane_connect(sock, sa, salen); } if (conn_stat < 0) { - dsb_simple(why, "4.4.1", "connect to %s[%s]: %m", name, addr); + if (port) + dsb_simple(why, "4.4.1", "connect to %s[%s]:%d: %m", + name, addr, ntohs(port)); + else + dsb_simple(why, "4.4.1", "connect to %s[%s]: %m", name, addr); close(sock); return (0); } stream = vstream_fdopen(sock, O_RDWR); + /* + * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. + */ + if (sa->sa_family == AF_INET +#ifdef AF_INET6 + || sa->sa_family == AF_INET6 +#endif + ) + vstream_tweak_tcp(stream); + /* * Bundle up what we have into a nice SMTP_SESSION object. */ diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 71dec8edf..53223c18f 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -5,6 +5,8 @@ /* Postfix SMTP server /* SYNOPSIS /* \fBsmtpd\fR [generic Postfix daemon options] +/* +/* \fBsendmail -bs\fR /* DESCRIPTION /* The SMTP server accepts network connection requests /* and performs zero or more SMTP transactions per connection. @@ -1632,7 +1634,8 @@ static int mail_open_stream(SMTPD_STATE *state) if (SMTPD_STAND_ALONE(state) == 0) { if (smtpd_milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0) - (void) milter_send(smtpd_milters, state->dest->stream); + /* Send place-holder smtpd_milters list. */ + (void) milter_dummy(smtpd_milters, state->cleanup); rec_fprintf(state->cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, REC_TYPE_TIME_ARG(state->arrival_time)); if (*var_filter_xport) @@ -2542,6 +2545,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) */ if (state->cleanup) { if (SMTPD_STAND_ALONE(state) == 0) { + if (smtpd_milters != 0 + && (state->saved_flags & MILTER_SKIP_FLAGS) == 0) + /* Send actual smtpd_milters list. */ + (void) milter_send(smtpd_milters, state->cleanup); if (state->saved_flags) rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", state->saved_flags); diff --git a/postfix/src/smtpstone/qmqp-source.c b/postfix/src/smtpstone/qmqp-source.c index 33282ac40..a69089a11 100644 --- a/postfix/src/smtpstone/qmqp-source.c +++ b/postfix/src/smtpstone/qmqp-source.c @@ -356,6 +356,13 @@ static void connect_done(int unused_event, char *context) dequeue_connect(session); non_blocking(fd, BLOCKING); event_disable_readwrite(fd); + /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ + if (sa->sa_family == AF_INET +#ifdef AF_INET6 + || sa->sa_family == AF_INET6 +#endif + ) + vstream_tweak_tcp(session->stream); send_data(session); } } diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c index 2bd61592d..a2231e94e 100644 --- a/postfix/src/smtpstone/smtp-source.c +++ b/postfix/src/smtpstone/smtp-source.c @@ -483,6 +483,13 @@ static void connect_done(int unused_event, char *context) event_disable_readwrite(fd); event_enable_read(fd, read_banner, (char *) session); dequeue_connect(session); + /* Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE. */ + if (sa->sa_family == AF_INET +#ifdef AF_INET6 + || sa->sa_family == AF_INET6 +#endif + ) + vstream_tweak_tcp(session->stream); } } diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 707f47cb5..5e8a6c47e 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -30,7 +30,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \ username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \ vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \ write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \ - allascii.c load_file.c killme_after.c + allascii.c load_file.c killme_after.c vstream_tweak.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ @@ -62,7 +62,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \ vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \ write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \ - allascii.o load_file.o killme_after.o + allascii.o load_file.o killme_after.o vstream_tweak.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ @@ -1600,6 +1600,11 @@ vstream_popen.o: sys_defs.h vstream_popen.o: vbuf.h vstream_popen.o: vstream.h vstream_popen.o: vstream_popen.c +vstream_tweak.o: msg.h +vstream_tweak.o: sys_defs.h +vstream_tweak.o: vbuf.h +vstream_tweak.o: vstream.h +vstream_tweak.o: vstream_tweak.c vstring.o: msg.h vstring.o: mymalloc.h vstring.o: sys_defs.h diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index ba94a1ce5..b2ebf1785 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -277,6 +277,16 @@ /* Enable exception handling with vstream_setjmp() and vstream_longjmp(). /* This involves allocation of additional memory that normally isn't /* used. +/* .IP "VSTREAM_CTL_BUFSIZE (ssize_t)" +/* Specify a non-default write buffer size, or zero to implement +/* a no-op. Requests to shrink an existing buffer size are +/* ignored. Requests to change a fixed-size buffer (stdin, +/* stdout, stderr) are not allowed. +/* +/* NOTE: the VSTREAM_CTL_BUFSIZE argument type is ssize_t, not +/* int. Use an explicit cast to avoid problems on LP64 +/* environments and other environments where ssize_t is larger +/* than int. /* .PP /* vstream_fileno() gives access to the file handle associated with /* a buffered stream. With streams that have separate read/write @@ -384,6 +394,13 @@ static int vstream_buf_space(VBUF *, ssize_t); * Initialization of the three pre-defined streams. Pre-allocate a static * I/O buffer for the standard error stream, so that the error handler can * produce a diagnostic even when memory allocation fails. + * + * XXX We don't (yet) statically initialize the req_bufsize field: it is the + * last VSTREAM member so we don't break Postfix 2.4 binary compatibility, + * and Wietse doesn't know how to specify an initializer for the jmp_buf + * VSTREAM member (which can be a struct or an array) without collateral + * damage to the source code. We can fix the initialization later in the + * Postfix 2.5 development cycle. */ static unsigned char vstream_fstd_buf[VSTREAM_BUFSIZE]; @@ -762,13 +779,14 @@ static int vstream_buf_put_ready(VBUF *bp) /* * Remember the direction. If this is the first PUT operation for this - * stream, allocate a new buffer; obviously there is no data to be - * flushed yet. Otherwise, flush the buffer if it is full. + * stream or if the buffer is smaller than the requested size, allocate a + * new buffer; obviously there is no data to be flushed yet. Otherwise, + * flush the buffer. */ - if (bp->data == 0) { - vstream_buf_alloc(bp, VSTREAM_BUFSIZE); - if (bp->flags & VSTREAM_FLAG_DOUBLE) - VSTREAM_SAVE_STATE(stream, write_buf, write_fd); + if (stream->req_bufsize == 0) + stream->req_bufsize = VSTREAM_BUFSIZE; /* Postfix 2.4 binary compat. */ + if (bp->len < stream->req_bufsize) { + vstream_buf_alloc(bp, stream->req_bufsize); } else if (bp->cnt <= 0) { if (VSTREAM_FFLUSH_SOME(stream)) return (VSTREAM_EOF); @@ -822,12 +840,18 @@ static int vstream_buf_space(VBUF *bp, ssize_t want) #define VSTREAM_ROUNDUP(count, base) VSTREAM_TRUNCATE(count + base - 1, base) if (want > bp->cnt) { - if ((used = bp->len - bp->cnt) > VSTREAM_BUFSIZE) - if (vstream_fflush_some(stream, VSTREAM_TRUNCATE(used, VSTREAM_BUFSIZE))) + if (stream->req_bufsize == 0) + stream->req_bufsize = VSTREAM_BUFSIZE; /* 2.4 binary compat. */ + if ((used = bp->len - bp->cnt) > stream->req_bufsize) + if (vstream_fflush_some(stream, VSTREAM_TRUNCATE(used, stream->req_bufsize))) return (VSTREAM_EOF); if ((shortage = (want - bp->cnt)) > 0) { - incr = VSTREAM_ROUNDUP(shortage, VSTREAM_BUFSIZE); - vstream_buf_alloc(bp, bp->len + incr); + if (shortage > __MAXINT__(ssize_t) -bp->len - stream->req_bufsize) { + bp->flags |= VSTREAM_FLAG_ERR; + } else { + incr = VSTREAM_ROUNDUP(shortage, stream->req_bufsize); + vstream_buf_alloc(bp, bp->len + incr); + } } } return (vstream_ferror(stream) ? VSTREAM_EOF : 0); /* mmap() may fail */ @@ -1027,6 +1051,7 @@ VSTREAM *vstream_fdopen(int fd, int flags) stream->context = 0; stream->jbuf = 0; stream->iotime.tv_sec = stream->iotime.tv_usec = 0; + stream->req_bufsize = VSTREAM_BUFSIZE; return (stream); } @@ -1169,6 +1194,7 @@ void vstream_control(VSTREAM *stream, int name,...) va_list ap; int floor; int old_fd; + ssize_t req_bufsize = 0; for (va_start(ap, name); name != VSTREAM_CTL_END; name = va_arg(ap, int)) { switch (name) { @@ -1248,6 +1274,18 @@ void vstream_control(VSTREAM *stream, int name,...) } break; #endif + + /* + * Postpone memory (re)allocation until the space is needed. + */ + case VSTREAM_CTL_BUFSIZE: + req_bufsize = va_arg(ap, ssize_t); + if (req_bufsize < 0) + msg_panic("VSTREAM_CTL_BUFSIZE with negative size: %ld", + (long) req_bufsize); + if (req_bufsize > stream->req_bufsize) + stream->req_bufsize = req_bufsize; + break; default: msg_panic("%s: bad name %d", myname, name); } diff --git a/postfix/src/util/vstream.h b/postfix/src/util/vstream.h index dc2ebb9f8..b8cdca7a5 100644 --- a/postfix/src/util/vstream.h +++ b/postfix/src/util/vstream.h @@ -50,6 +50,8 @@ typedef struct VSTREAM { int timeout; /* read/write timout */ jmp_buf *jbuf; /* exception handling */ struct timeval iotime; /* time of last fill/flush */ + /* At bottom for Postfix 2.4 binary compatibility. */ + ssize_t req_bufsize; /* write buffer size */ } VSTREAM; extern VSTREAM vstream_fstd[]; /* pre-defined streams */ @@ -123,6 +125,7 @@ extern void vstream_control(VSTREAM *, int,...); #ifdef F_DUPFD #define VSTREAM_CTL_DUPFD 11 #endif +#define VSTREAM_CTL_BUFSIZE 12 extern VSTREAM *PRINTFLIKE(1, 2) vstream_printf(const char *,...); extern VSTREAM *PRINTFLIKE(2, 3) vstream_fprintf(VSTREAM *, const char *,...); @@ -153,6 +156,12 @@ extern ssize_t vstream_peek(VSTREAM *); #define vstream_setjmp(stream) setjmp((stream)->jbuf[0]) #define vstream_longjmp(stream, val) longjmp((stream)->jbuf[0], (val)) + /* + * Tweaks and workarounds. + */ +extern int vstream_tweak_sock(VSTREAM *); +extern int vstream_tweak_tcp(VSTREAM *); + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/util/vstream_tweak.c b/postfix/src/util/vstream_tweak.c new file mode 100644 index 000000000..145651106 --- /dev/null +++ b/postfix/src/util/vstream_tweak.c @@ -0,0 +1,139 @@ +/*++ +/* NAME +/* vstream_tweak 3 +/* SUMMARY +/* performance tweaks +/* SYNOPSIS +/* #include +/* +/* VSTREAM *vstream_tweak_sock(stream) +/* VSTREAM *stream; +/* +/* VSTREAM *vstream_tweak_tcp(stream) +/* VSTREAM *stream; +/* DESCRIPTION +/* vstream_tweak_sock() does a best effort to boost your +/* network performance on the specified generic stream. +/* +/* vstream_tweak_tcp() does a best effort to boost your +/* Internet performance on the specified TCP stream. +/* +/* Arguments: +/* .IP stream +/* The stream being boosted. +/* DIAGNOSTICS +/* Panics: interface violations. +/* 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 +#include +#include +#include + +/* Utility library. */ + +#include +#include + +/* Application-specific. */ + +#ifdef HAS_IPV6 +#define SOCKADDR_STORAGE struct sockaddr_storage +#else +#define SOCKADDR_STORAGE struct sockaddr +#endif + +/* vstream_tweak_sock - boost your generic network performance */ + +int vstream_tweak_sock(VSTREAM *fp) +{ + SOCKADDR_STORAGE ss; + struct sockaddr *sa = (struct sockaddr *) & ss; + SOCKADDR_SIZE sa_length = sizeof(ss); + int ret; + + /* + * If the caller doesn't know if this socket is AF_LOCAL, AF_INET, etc., + * figure it out for them. + */ + if ((ret = getsockname(vstream_fileno(fp), sa, &sa_length)) >= 0) { + switch (sa->sa_family) { +#ifdef AF_INET6 + case AF_INET6: +#endif + case AF_INET: + ret = vstream_tweak_tcp(fp); + break; + } + } + return (ret); +} + +/* vstream_tweak_tcp - boost your TCP performance */ + +int vstream_tweak_tcp(VSTREAM *fp) +{ + const char *myname = "vstream_tweak_tcp"; + int mss; + SOCKOPT_SIZE mss_len = sizeof(mss); + int err; + + /* + * Avoid Nagle delays when VSTREAM buffers are smaller than the MSS. + * + * Forcing TCP_NODELAY to be "always on" would hurt performance in the + * common case where VSTREAM buffers are larger than the MSS. + * + * Instead we ask the kernel what the current MSS is, and take appropriate + * action. Linux <= 2.2 getsockopt(TCP_MAXSEG) always returns zero (or + * whatever value was stored last with setsockopt()). + */ + if ((err = getsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_MAXSEG, + (char *) &mss, &mss_len)) < 0) { + msg_warn("%s: getsockopt TCP_MAXSEG: %m", myname); + return (err); + } + if (msg_verbose) + msg_info("%s: TCP_MAXSEG %d", myname, mss); + + /* + * Fix for recent Postfix versions: increase the VSTREAM buffer size if + * the VSTREAM buffer is smaller than the MSS. Note: the MSS may change + * when the route changes and IP path MTU discovery is turned on, so we + * choose a somewhat larger buffer. + */ +#ifdef VSTREAM_CTL_BUFSIZE + if (mss > 0) { + if (mss < __MAXINT__(ssize_t) /2) + mss *= 2; + vstream_control(fp, + VSTREAM_CTL_BUFSIZE, (ssize_t) mss, + VSTREAM_CTL_END); + } + + /* + * Workaround for older Postfix versions: turn on TCP_NODELAY if the + * VSTREAM buffer size is smaller than the MSS. + */ +#else + if (mss > VSTREAM_BUFSIZE) { + int nodelay = 0; + + if ((err = setsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_NODELAY, + (char *) &nodelay, sizeof(nodelay))) < 0) + msg_warn("%s: setsockopt TCP_NODELAY: %m", myname); + } +#endif + return (err); +}