]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.6-20081203
authorWietse Venema <wietse@porcupine.org>
Wed, 3 Dec 2008 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:35:05 +0000 (06:35 +0000)
16 files changed:
postfix/HISTORY
postfix/README_FILES/OVERVIEW
postfix/html/OVERVIEW.html
postfix/html/pcre_table.5.html
postfix/man/man5/pcre_table.5
postfix/proto/OVERVIEW.html
postfix/proto/pcre_table
postfix/src/global/mail_version.h
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_reuse.c
postfix/src/smtp/smtp_session.c
postfix/src/smtpd/smtpd.c
postfix/src/util/myaddrinfo.h
postfix/src/util/vstream.c
postfix/src/util/vstream.h

index 8fbc67cfe37040aacc7effdda7f6432d011d5eff..859cb3b753c958ba137d8ad229bf4e3cef00f2f7 100644 (file)
@@ -14745,8 +14745,8 @@ Apologies for any names omitted.
        Feature: smtp_sasl_tls_verified_security_options is no
        longer #ifdef SNAPSHOT.
 
-       Feature: elliptic curve support. This requires OpenSSL version
-       0.9.9 or later. Victor Duchovni. Files: TLS_README,
+       Feature: elliptic curve support. This requires OpenSSL
+       version 0.9.9 or later. Victor Duchovni. Files: TLS_README,
        smtpd/smtpd.c, smtp/smtp.c, tls/tls_dh.c, tls/tls_certkey.c,
        tls/tls_server.c, tls/tls_client.c, tls/tls.h, tls/tls_misc.c.
 
@@ -14757,3 +14757,29 @@ Apologies for any names omitted.
 20081109
 
        Cleanup: confusing names of variables. File: smtpd/smtpd.c.
+
+20081126
+
+       Bugfix: pcre_table(5) incorrectly claimed that the 'x' flag
+       supports #comment after text. File: proto/pcre_table.
+
+20081202
+
+       Cleanup: vstream_bufstat() provides a more systematic
+       approach to get information about VSTREAM buffers. The
+       vstream_peek() function is now a backwards compatibility
+       wrapper.  Files: util/vstream.[hc].
+
+       Cleanup: the SMTP server should warn about "lost connection
+       after QUIT" only when the "." reply was pipelined together
+       with the "QUIT" reply. File: smtpd/smtpd.c.
+
+       Cleanup: the SMTP client's code was duplicating buffer
+       management that was already done in the VSTREAM module.
+       File: smtp/smtp_proto.c.
+
+20081203
+
+       Cleanup: adjust the VSTREAM buffer strategy when reusing
+       an SMTP connection with a large TCP MSS value. File:
+       smtp/smtp_proto.c.
index cc6e8322203f9feada6e7fd7d0fd11623a305ff6..2cfc28a9d353157bb49938e118e399319651d252 100644 (file)
@@ -4,10 +4,10 @@ P\bPo\bos\bst\btf\bfi\bix\bx A\bAr\brc\bch\bhi\bit\bte\bec\bct\btu\bur\bre\be O\bOv\bve\ber\brv\bvi\bie\be
 
 I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
 
-This document presents an overview of the Postfix architecture, and is the
-place where you find a pointer to every Postfix command or server program. The
-text gives the general context in which each command or server program is used,
-and provides pointers to documents with specific usage examples and background
+This document presents an overview of the Postfix architecture, and provides
+pointers to descriptions of every Postfix command or server program. The text
+gives the general context in which each command or server program is used, and
+provides pointers to documents with specific usage examples and background
 information.
 
 Topics covered by this document:
@@ -63,7 +63,7 @@ programs, while unnumbered names inside shaded areas represent Postfix queues.
     section), and postmaster notifications about problems with Postfix.
 
   * The cleanup(8) server implements the final processing stage before mail is
-    queued. It adds missing From: and other message headers, transforms
+    queued. It adds missing From: and other message headers, and transforms
     addresses as described in the ADDRESS_REWRITING_README document.
     Optionally, the cleanup(8) server can be configured to do light-weight
     content inspection with regular expressions as described in the
index 693f082ccab45559b09d5857e73c0713a02b7672..5c8ff198f1f70397b6199c1974706be60ed74bf5 100644 (file)
@@ -21,7 +21,7 @@ Architecture Overview </h1>
 <h2> Introduction </h2>
 
 <p> This document presents an overview of the Postfix architecture,
-and is the place where you find a pointer to every Postfix command
+and provides pointers to descriptions of every Postfix command
 or server program.  The text gives the general context in which
 each command or server program is used, and provides pointers to
 documents with specific usage examples and background information.
@@ -173,7 +173,8 @@ notifications about problems with Postfix.  </p>
 
 <li> <p> The <a href="cleanup.8.html">cleanup(8)</a> server implements the final processing
 stage before mail is queued. It adds missing From: and other message
-headers, transforms addresses as described in the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a>
+headers, and transforms addresses as described in the
+<a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a>
 document. Optionally, the <a href="cleanup.8.html">cleanup(8)</a> server can be configured to
 do light-weight content inspection with regular expressions as
 described in the <a href="BUILTIN_FILTER_README.html">BUILTIN_FILTER_README</a> document.  The  <a href="cleanup.8.html">cleanup(8)</a>
index a80d3108e17ba2c8414aaee99b7d2d80684b1a07..9db86451e43c45a72d286cee64f73d5e0c1413ba 100644 (file)
@@ -110,12 +110,12 @@ PCRE_TABLE(5)                                                    PCRE_TABLE(5)
 
        <b>x</b> (default: off)
               Toggles  the  pcre extended flag. When this flag is
-              on, whitespace in the  pattern  (other  than  in  a
-              character class) and characters between a <b>#</b> outside
-              a character class and the  next  newline  character
-              are  ignored.  An escaping backslash can be used to
-              include a whitespace or <b>#</b> character as part of  the
-              pattern.
+              on, whitespace characters  in  the  pattern  (other
+              than in a character class) are ignored.  To include
+              a whitespace character  as  part  of  the  pattern,
+              escape it with backslash.
+
+              Note: do not use <b>#</b><i>comment</i> after patterns.
 
        <b>A</b> (default: off)
               Toggles  the PCRE_ANCHORED flag.  When this flag is
index c3c008fb1d157612233010232e477eb3c0f9710e..f7b57a18744556fcefd96c0bcc526812ced5a369 100644 (file)
@@ -100,11 +100,11 @@ default, which is inconvenient for multi-line message header
 matching.
 .IP "\fBx\fR (default: off)"
 Toggles the pcre extended flag. When this flag is on, whitespace
-in the pattern (other than in a character class) and
-characters between a \fB#\fR outside a character class and
-the next newline character are ignored. An escaping backslash
-can be used to include a whitespace or \fB#\fR character
-as part of the pattern.
+characters in the pattern (other than in a character class)
+are ignored.  To include a whitespace character as part of
+the pattern, escape it with backslash.
+.sp
+Note: do not use \fB#\fIcomment\fR after patterns.
 .IP "\fBA\fR (default: off)"
 Toggles the PCRE_ANCHORED flag.  When this flag is on,
 the pattern is forced to be "anchored", that is, it is
index 924f38695dc5d76a0e010de89ebf425c1f6eb7b9..6e25b064d23671c93b75d98a17c4a861ce21afcd 100644 (file)
@@ -21,7 +21,7 @@ Architecture Overview </h1>
 <h2> Introduction </h2>
 
 <p> This document presents an overview of the Postfix architecture,
-and is the place where you find a pointer to every Postfix command
+and provides pointers to descriptions of every Postfix command
 or server program.  The text gives the general context in which
 each command or server program is used, and provides pointers to
 documents with specific usage examples and background information.
@@ -173,7 +173,8 @@ notifications about problems with Postfix.  </p>
 
 <li> <p> The cleanup(8) server implements the final processing
 stage before mail is queued. It adds missing From: and other message
-headers, transforms addresses as described in the ADDRESS_REWRITING_README
+headers, and transforms addresses as described in the
+ADDRESS_REWRITING_README
 document. Optionally, the cleanup(8) server can be configured to
 do light-weight content inspection with regular expressions as
 described in the BUILTIN_FILTER_README document.  The  cleanup(8)
index 679e67ef7ae26aa9558d27ccd2d047d4a4fe4a1e..3c21a4ade311272787cab3c34339b50d9ce04a3a 100644 (file)
 #      matching.
 # .IP "\fBx\fR (default: off)"
 #      Toggles the pcre extended flag. When this flag is on, whitespace
-#      in the pattern (other than in a character class) and
-#      characters between a \fB#\fR outside a character class and
-#      the next newline character are ignored. An escaping backslash
-#      can be used to include a whitespace or \fB#\fR character
-#      as part of the pattern.
+#      characters in the pattern (other than in a character class)
+#      are ignored.  To include a whitespace character as part of
+#      the pattern, escape it with backslash.
+# .sp
+#      Note: do not use \fB#\fIcomment\fR after patterns.
 # .IP "\fBA\fR (default: off)"
 #      Toggles the PCRE_ANCHORED flag.  When this flag is on,
 #      the pattern is forced to be "anchored", that is, it is
index 6af2aa16ad37336542b3d9dab4f198a1b85d8af5..f1e7ab2f9983f53fd28d5be200980fb57396bdbc 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      "20081109"
+#define MAIL_RELEASE_DATE      "20081203"
 #define MAIL_VERSION_NUMBER    "2.6"
 
 #ifdef SNAPSHOT
index da3f3034b565fb58f416762c8a90486f20bb484e..d1ecf37fee9c264ed10f10b0cc8c7f0c93f4701e 100644 (file)
@@ -208,7 +208,6 @@ typedef struct SMTP_SESSION {
     int     error_mask;                        /* error classes */
     struct MIME_STATE *mime_state;     /* mime state machine */
 
-    int     sndbufsize;                        /* PIPELINING buffer size */
     int     send_proto_helo;           /* XFORWARD support */
 
     time_t  expire_time;               /* session reuse expiration time */
index ab80bcc63ab025a30b80c5ad4ce16bcd7eb50bf0..d79828fd89f568d3a6f250304ffcbce62721ea87 100644 (file)
@@ -274,6 +274,7 @@ int     smtp_helo(SMTP_STATE *state)
        0, 0,
     };
     SOCKOPT_SIZE optlen;
+    int     sndbufsize;
     const char *ehlo_words;
     int     discard_mask;
     static const NAME_MASK pix_bug_table[] = {
@@ -559,27 +560,24 @@ int     smtp_helo(SMTP_STATE *state)
      * if we do.
      */
     if (session->features & SMTP_FEATURE_PIPELINING) {
-       optlen = sizeof(session->sndbufsize);
+       optlen = sizeof(sndbufsize);
        if (getsockopt(vstream_fileno(session->stream), SOL_SOCKET,
-                    SO_SNDBUF, (char *) &session->sndbufsize, &optlen) < 0)
+                      SO_SNDBUF, (char *) &sndbufsize, &optlen) < 0)
            msg_fatal("%s: getsockopt: %m", myname);
-       if (session->sndbufsize > VSTREAM_BUFSIZE)
-           session->sndbufsize = VSTREAM_BUFSIZE;
-       if (session->sndbufsize == 0) {
-           session->sndbufsize = VSTREAM_BUFSIZE;
+       if (sndbufsize > VSTREAM_BUFSIZE)
+           sndbufsize = VSTREAM_BUFSIZE;
+       if (sndbufsize < VSTREAM_BUFSIZE) {
+           sndbufsize = VSTREAM_BUFSIZE;
            if (setsockopt(vstream_fileno(session->stream), SOL_SOCKET,
-                     SO_SNDBUF, (char *) &session->sndbufsize, optlen) < 0)
+                          SO_SNDBUF, (char *) &sndbufsize, optlen) < 0)
                msg_fatal("%s: setsockopt: %m", myname);
        }
        if (msg_verbose)
            msg_info("Using %s PIPELINING, TCP send buffer size is %d",
                     (state->misc_flags &
                      SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP",
-                    session->sndbufsize);
-    } else {
-       session->sndbufsize = 0;
+                    sndbufsize);
     }
-
 #ifdef USE_TLS
 
     /*
@@ -1081,7 +1079,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
     int     except;
     int     rec_type;
     NOCLOBBER int prev_type = 0;
-    NOCLOBBER int sndbuffree;
     NOCLOBBER int mail_from_rejected;
     NOCLOBBER int downgrading;
     int     mime_errs;
@@ -1131,20 +1128,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
 #define CANT_RSET_THIS_SESSION \
        (session->features |= SMTP_FEATURE_RSET_REJECTED)
 
-    /*
-     * Sanity check. We don't want smtp_chat() to inadvertently flush the
-     * output buffer. That means someone broke pipelining support.
-     */
-    if (session->sndbufsize > VSTREAM_BUFSIZE)
-       msg_panic("bad sndbufsize %d > VSTREAM_BUFSIZE %d",
-                 session->sndbufsize, VSTREAM_BUFSIZE);
-
-    /*
-     * Miscellaneous initialization. Some of this might be done in
-     * smtp_xfer() but that just complicates interfaces and data structures.
-     */
-    sndbuffree = session->sndbufsize;
-
     /*
      * Pipelining support requires two loops: one loop for sending and one
      * for receiving. Each loop has its own independent state. Most of the
@@ -1432,8 +1415,12 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
         */
        if (SENDER_IN_WAIT_STATE
            || (SENDER_IS_AHEAD
-               && (VSTRING_LEN(next_command) + 2 > sndbuffree
-           || time((time_t *) 0) - vstream_ftime(session->stream) > 10))) {
+               && ((session->features & SMTP_FEATURE_PIPELINING) == 0
+                   || (VSTRING_LEN(next_command) + 2
+                   + vstream_bufstat(session->stream, VSTREAM_BST_OUT_PEND)
+                       > VSTREAM_BUFSIZE)
+                   || time((time_t *) 0)
+                   - vstream_ftime(session->stream) > 10))) {
            while (SENDER_IS_AHEAD) {
 
                /*
@@ -1707,10 +1694,8 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
            }
 
            /*
-            * At this point, the sender and receiver are fully synchronized,
-            * so that the entire TCP send buffer becomes available again.
+            * At this point, the sender and receiver are fully synchronized.
             */
-           sndbuffree = session->sndbufsize;
 
            /*
             * We know the server response to every command that was sent.
@@ -1874,8 +1859,6 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
         * Copy the next command to the buffer and update the sender state.
         */
        if (except == 0) {
-           if (sndbuffree > 0)
-               sndbuffree -= VSTRING_LEN(next_command) + 2;
            smtp_chat_cmd(session, "%s", vstring_str(next_command));
        } else {
            DONT_CACHE_THIS_SESSION;
index 1ed72d73bd58e7f39c2373c5ccceb5eb4e75f4f3..0eb989f18b8b729c8cb042e38ced7c16df13b7d7 100644 (file)
@@ -213,6 +213,11 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
        return (state->session = 0);
     }
 
+    /*
+     * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
+     */
+    vstream_tweak_sock(session->stream);
+
     /*
      * Update the list of used cached addresses.
      */
index c87fe75351fb4a68d38287ff696c6427fa5e3e29..1a0b15a75663a5f2f0857ed6d5d2f6ec2613ce09 100644 (file)
@@ -585,7 +585,6 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
     } else
        session->namaddrport = mystrdup(session->namaddr);
 
-    session->sndbufsize = 0;
     session->send_proto_helo = 0;
 
     if (flags & SMTP_MISC_FLAG_CONN_STORE)
@@ -695,13 +694,12 @@ int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
      * 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, "%u\n%s\n%s\n%s\n%u\n%u\n%lu\n%u",
+    vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu",
                    session->reuse_count,
                    session->dest, session->host,
                    session->addr, session->port,
                    session->features & SMTP_FEATURE_ENDPOINT_MASK,
-                   (long) session->expire_time,
-                   session->sndbufsize);
+                   (long) session->expire_time);
 
     /*
      * Append the passivated SASL attributes.
@@ -740,7 +738,6 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
     unsigned features;                 /* server features */
     time_t  expire_time;               /* session re-use expiration time */
     unsigned reuse_count;              /* # times reused */
-    unsigned sndbufsize;               /* PIPELINING buffer size */
 
     /*
      * XXX it would be nice to have a VSTRING to VSTREAM adapter so that we
@@ -790,12 +787,6 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
     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);
-       return (0);
-    }
-    sndbufsize = atoi(prop);
-
     if (dest_prop && VSTRING_LEN(dest_prop)) {
        dest_props = STR(dest_prop);
        if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) {
@@ -815,14 +806,12 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
     session->features = (features | SMTP_FEATURE_FROM_CACHE);
     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, "
-                "ttl=%ld, reuse=%d, sndbuf=%u",
+                "ttl=%ld, reuse=%d",
                 myname, dest, host, addr, ntohs(port), features,
-                (long) (expire_time - time((time_t *) 0)), reuse_count,
-                sndbufsize);
+                (long) (expire_time - time((time_t *) 0)), reuse_count);
 
     /*
      * Re-activate the SASL attributes.
index 9b844ae52a6391c34dc461e780cfec63f7dd2c58..204fc838ccc9bae842c6d5251e222087cbde5f8d 100644 (file)
@@ -1266,7 +1266,7 @@ MILTERS *smtpd_milters;
   * TLS initialization status.
   */
 static TLS_APPL_STATE *smtpd_tls_ctx;
-static int require_server_cert;
+static int ask_client_cert;
 
 #endif
 
@@ -3286,7 +3286,8 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
      * XXX When this was added in Postfix 2.1 we used vstream_fflush(). As of
      * Postfix 2.3 we use smtp_flush() for better error reporting.
      */
-    smtp_flush(state->client);
+    if (vstream_bufstat(state->client, VSTREAM_BST_OUT_PEND) > 0)
+       smtp_flush(state->client);
     return (0);
 }
 
@@ -3857,7 +3858,7 @@ static void smtpd_start_tls(SMTPD_STATE *state)
        ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_excl_ciph);
        if (enforce_tls)
            ADD_EXCLUDE(cipher_exclusions, var_smtpd_tls_mand_excl);
-       if (require_server_cert)
+       if (ask_client_cert)
            ADD_EXCLUDE(cipher_exclusions, "aNULL");
     }
 
@@ -4645,7 +4646,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
            const char *cert_file;
            int     have_server_cert;
            int     no_server_cert_ok;
-           int     ask_client_cert;
+           int     require_server_cert;
 
            /*
             * Can't use anonymous ciphers if we want client certificates.
index c567eb7d0f95a1924ef6a29bb1debc43056644c3..766eed27aafd821029766ced61ca69c17bc1812d 100644 (file)
@@ -130,6 +130,13 @@ extern char *gai_strerror(int);
   * Routines and data structures to hide some of the complexity of the
   * addrinfo API. They still don't hide that we may get results for address
   * families that we aren't interested in.
+  * 
+  * Note: the getnameinfo() and inet_ntop() system library functions use unsafe
+  * APIs with separate pointer and length arguments. To avoid buffer overflow
+  * problems with these functions, Postfix uses pointers to structures
+  * internally. This way the compiler can enforce that callers provide
+  * buffers with the appropriate length, instead of having to trust that
+  * callers will never mess up some length calculation.
   */
 typedef struct {
     char    buf[MAI_HOSTNAME_STRSIZE];
index b3b9fce5616a2226e6a3e73f30eca8f6b13a2cb3..299899795f9fb72556f9d1f2109faadd53fc62b9 100644 (file)
 /*     const char *format;
 /*     va_list *ap;
 /*
+/*     ssize_t vstream_bufstat(stream, command)
+/*     VSTREAM *stream;
+/*     int     command;
+/*
 /*     ssize_t vstream_peek(stream)
 /*     VSTREAM *stream;
 /*
 /*     vstream_vfprintf() provides an alternate interface
 /*     for formatting an argument list according to a format string.
 /*
+/*     vstream_bufstat() provides input and output buffer status
+/*     information.  The command is one of the following:
+/* .IP VSTREAM_BST_IN_PEND
+/*     Return the number of characters that can be read without
+/*     refilling the read buffer.
+/* .IP VSTREAM_BST_OUT_PEND
+/*     Return the number of characters that are waiting in the
+/*     write buffer.
+/* .PP
 /*     vstream_peek() returns the number of characters that can be
 /*     read from the named stream without refilling the read buffer.
+/*     This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND).
 /*
 /*     vstream_setjmp() saves processing context and makes that context
 /*     available for use with vstream_longjmp().  Normally, vstream_setjmp()
@@ -703,8 +717,10 @@ static int vstream_buf_get_ready(VBUF *bp)
      * allocation gives the application a chance to override the default
      * buffering policy.
      */
-    if (bp->data == 0)
-       vstream_buf_alloc(bp, VSTREAM_BUFSIZE);
+    if (stream->req_bufsize == 0)
+       stream->req_bufsize = VSTREAM_BUFSIZE;
+    if (bp->len < stream->req_bufsize)
+       vstream_buf_alloc(bp, stream->req_bufsize);
 
     /*
      * If the stream is double-buffered and the write buffer is not empty,
@@ -1306,6 +1322,47 @@ VSTREAM *vstream_vfprintf(VSTREAM *vp, const char *format, va_list ap)
     return (vp);
 }
 
+/* vstream_bufstat - get stream buffer status */
+
+ssize_t vstream_bufstat(VSTREAM *vp, int command)
+{
+    VBUF   *bp;
+
+    switch (command & VSTREAM_BST_MASK_DIR) {
+    case VSTREAM_BST_FLAG_IN:
+       if (vp->buf.flags & VSTREAM_FLAG_READ) {
+           bp = &vp->buf;
+       } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
+           bp = &vp->read_buf;
+       } else {
+           bp = 0;
+       }
+       switch (command & ~VSTREAM_BST_MASK_DIR) {
+       case VSTREAM_BST_FLAG_PEND:
+           return (bp ? -bp->cnt : 0);
+           /* Add other requests below. */
+       }
+       break;
+    case VSTREAM_BST_FLAG_OUT:
+       if (vp->buf.flags & VSTREAM_FLAG_WRITE) {
+           bp = &vp->buf;
+       } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
+           bp = &vp->write_buf;
+       } else {
+           bp = 0;
+       }
+       switch (command & ~VSTREAM_BST_MASK_DIR) {
+       case VSTREAM_BST_FLAG_PEND:
+           return (bp ? bp->len - bp->cnt : 0);
+           /* Add other requests below. */
+       }
+       break;
+    }
+    msg_panic("vstream_bufstat: unknown command: %d", command);
+}
+
+#undef vstream_peek                    /* API binary compatibility. */
+
 /* vstream_peek - peek at a stream */
 
 ssize_t vstream_peek(VSTREAM *vp)
index 845be337f8b440f77990f3d21c77d3c44b2cfd16..7695c23025df5756e1f018e7c20a539746e04aa3 100644 (file)
@@ -154,6 +154,17 @@ extern int vstream_pclose(VSTREAM *);
 extern VSTREAM *vstream_vfprintf(VSTREAM *, const char *, va_list);
 
 extern ssize_t vstream_peek(VSTREAM *);
+extern ssize_t vstream_bufstat(VSTREAM *, int);
+
+#define VSTREAM_BST_FLAG_IN            (1<<0)
+#define VSTREAM_BST_FLAG_OUT           (1<<1)
+#define VSTREAM_BST_FLAG_PEND          (1<<2)
+
+#define VSTREAM_BST_MASK_DIR   (VSTREAM_BST_FLAG_IN | VSTREAM_BST_FLAG_OUT)
+#define VSTREAM_BST_IN_PEND    (VSTREAM_BST_FLAG_IN | VSTREAM_BST_FLAG_PEND)
+#define VSTREAM_BST_OUT_PEND   (VSTREAM_BST_FLAG_OUT | VSTREAM_BST_FLAG_PEND)
+
+#define vstream_peek(vp) vstream_bufstat((vp), VSTREAM_BST_IN_PEND)
 
  /*
   * Exception handling. We use pointer to jmp_buf to avoid a lot of unused