]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5-20070731
authorWietse Venema <wietse@porcupine.org>
Tue, 31 Jul 2007 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:33:19 +0000 (06:33 +0000)
22 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/html/smtpd.8.html
postfix/man/man8/smtpd.8
postfix/src/cleanup/cleanup_envelope.c
postfix/src/cleanup/cleanup_milter.c
postfix/src/global/mail_version.h
postfix/src/milter/milter.c
postfix/src/milter/milter.h
postfix/src/milter/milter8.c
postfix/src/milter/test-milter.c
postfix/src/oqmgr/qmgr_message.c
postfix/src/qmgr/qmgr_message.c
postfix/src/smtp/smtp_connect.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpstone/qmqp-source.c
postfix/src/smtpstone/smtp-source.c
postfix/src/util/Makefile.in
postfix/src/util/vstream.c
postfix/src/util/vstream.h
postfix/src/util/vstream_tweak.c [new file with mode: 0644]

index 428674f5f9e1624452b56b07ed25f028c83a47e4..1302134b569c101a2a71ad31c5cab4a429e28f36 100644 (file)
@@ -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.
index 68a99aa566235f2f1291aaf69066a5c261c55ae0..69d2600ab7aa240af0c981706d4510c83d1fb0e0 100644 (file)
@@ -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
 ==============================================
index db194c8bb5ce67be38da2b9c2ac694904255859c..e81bb404e05958d6eae3f023dfb0d7b1d4bf3563 100644 (file)
@@ -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.
 
index 509224a17657a2e2209312949a65ad2d1be94ad8..3a7d15e3ad0b7e851d1a37db9d8e0929d615021a 100644 (file)
@@ -12,6 +12,8 @@ SMTPD(8)                                                              SMTPD(8)
 <b>SYNOPSIS</b>
        <b>smtpd</b> [generic Postfix daemon options]
 
+       <b>sendmail -bs</b>
+
 <b>DESCRIPTION</b>
        The  SMTP  server  accepts network connection requests and
        performs zero or more SMTP  transactions  per  connection.
index 1f8606af75e6611bbab51dba57de89edd27770aa..93e343f8aae0451c2d12a995d8f769e47b8428cb 100644 (file)
@@ -9,6 +9,8 @@ Postfix SMTP server
 .na
 .nf
 \fBsmtpd\fR [generic Postfix daemon options]
+
+\fBsendmail -bs\fR
 .SH DESCRIPTION
 .ad
 .fi
index ef4dbc7dc36302c23a15590260a7e1aee5a9fbf8..830f37093dbe10525cab539f608bd011a428f503 100644 (file)
@@ -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;
     }
index 2212604a39bb96fdeba2c21d7c8d7f0eae1929a7..51755e8f308558deed174ab49de95273732e7881 100644 (file)
@@ -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,
index 770cebca47c592477f9b235df1c1d5ae67fed711..2638bce0a08d19d977cdaec77e4020ea621726f4 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20070724"
+#define MAIL_RELEASE_DATE      "20070731"
 #define MAIL_VERSION_NUMBER    "2.5"
 
 #ifdef SNAPSHOT
index 51f968d80bddee06ef0d35a62c41cae2a3117798..2e0c73128459f304fd99077b0fa218399d7918d6 100644 (file)
 /*     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
 /*     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.
      */
index 676322d4a4b9a6b52036676c0f329487c9fbac8c..e0a4067efb3f17ac2ab573f38a2d8b5d061f610c 100644 (file)
@@ -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 {}.
   */
index 8f1745ce72cf8faa9546726222b2187af8752b4e..d690240598a7a15a30ca25f988c55ef9a479e53f 100644 (file)
@@ -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;
index 5999b7add08ee1a5b876c4c9f6f58e57fea1d27f..0c33d8a5a7cf22d114e0de854e62210e27f2bf46 100644 (file)
@@ -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);
     }
 }
index a646daef94558f1c4ccc2aa398518b81469af38b..4e3938506deb90029c16b4e0c5879ad35eeacf8c 100644 (file)
@@ -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;
index 9be26ec1cc0af837f47d9f951967e1c3bc683bd0..eeedefbcfe115f2a7e6c6260e0b273194e4a31bd 100644 (file)
@@ -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;
index 1430c8ced224e75aa5b30440ca6521b17dcc841b..6089f093fe7b8d9f9804e988d7c0f503e71d596b 100644 (file)
@@ -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.
      */
index 71dec8edff0b4d87b838c9069d96dfd80a2dd571..53223c18fdb5b7041190da4223594b501c38ccc2 100644 (file)
@@ -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);
index 33282ac40a5e72aed3cea212f1e62bf3777e63bb..a69089a115a62f5c6ec031e18c26f05b63887dc2 100644 (file)
@@ -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);
     }
 }
index 2bd61592d13d25bb04cc367c7947cc0973a72b14..a2231e94e35be7a577f9eb332a363a0d3ec299d8 100644 (file)
@@ -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);
     }
 }
 
index 707f47cb5aac3d4346f6c4f33669712a9a59d04a..5e8a6c47e73b299db06f7b6bf9faeba4fb853e05 100644 (file)
@@ -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
index ba94a1ce541ed31a008685942e9ad1d5735a0a9f..b2ebf1785dc9fc9405d9976356e97e8720e3ad4d 100644 (file)
 /*     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);
        }
index dc2ebb9f8fea360fdb68175c0e35e7d6ed182574..b8cdca7a5e658563611169f23df5c588d70c9993 100644 (file)
@@ -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 (file)
index 0000000..1456511
--- /dev/null
@@ -0,0 +1,139 @@
+/*++
+/* NAME
+/*     vstream_tweak 3
+/* SUMMARY
+/*     performance tweaks
+/* SYNOPSIS
+/*     #include <vstream.h>
+/*
+/*     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 <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+
+/* 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);
+}