]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20000513
authorWietse Venema <wietse@porcupine.org>
Sat, 13 May 2000 00:00:00 +0000 (00:00 +0000)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 23:10:48 +0000 (18:10 -0500)
14 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/global/mail_version.h
postfix/lmtp/lmtp_chat.c
postfix/local/file.c
postfix/master/multi_server.c
postfix/master/single_server.c
postfix/master/trigger_server.c
postfix/smtp/smtp_chat.c
postfix/smtpd/smtpd_chat.c
postfix/util/sys_defs.h
postfix/util/vbuf.c
postfix/util/vstream.c
postfix/util/vstream.h

index ac69fdd7431da52af57f5f4eb600b28e48b86879..cfdcfd534fb5f0ca19eff9236df69be57ed3b89b 100644 (file)
@@ -3942,5 +3942,23 @@ Apologies for any names omitted.
        Bugfix: Postfix would incorrectly reject domain names with
        adjacent - characters. File: util/valid_hostname.c.
 
-       The 20000505 pipeline tarpit delay flush was wrong and
-       caused SMTP protocol errors.
+       Bugfix: the 20000505 pipeline tarpit delay flush was wrong
+       and caused the client and server to get out of phase. Yuck!
+
+20000513
+
+       Feature: VSTREAMs now have the concept of last fill/flush
+       time, which is needed to prevent timeouts with pipelined
+       SMTP sessions as detailed in the next item.
+
+       Bugfix: automatic SMTP command/reply flushing to prevent
+       delays from accumulating within pipelined SMTP sessions.
+       For example, client-side delays happen when a client does
+       DNS lookups to replace hostname aliases in a MAIL FROM or
+       RCPT TO commands; server-side delays happen when an UCE
+       restriction involves a time-consuming DNS lookup, or when
+       a server generates a tarpit delay.  Files:  */*chat.c.
+
+       Portability: define ANAL_CAST for compilation environments
+       that complain about explicit casts between pointers and
+       integral types. File: util/sys_defs.h, master/*server.c.
index c1fce4090953506b8da9426e236562e8a3477cc5..ed88888b8e2d4c0717499670049f1e9044bbc9e1 100644 (file)
@@ -1,3 +1,15 @@
+Major changes with snapshot-20000513
+====================================
+
+LaMont Jones and Patrik Rak reported two different scenarios in
+which pipelined SMTP sessions could time out forever. Postfix now
+automatically flushes delayed SMTP commands/replies to prevent
+delays from accumulating and causing timeouts in pipelined SMTP
+sessions.  For example, client-side delays happen when a client
+does DNS lookups to replace hostname aliases in a MAIL FROM or RCPT
+TO commands; server-side delays happen when an UCE restriction
+involves DNS lookup, or when a server generates a tarpit delay.
+
 Incompatible changes with snapshot-20000507
 ===========================================
 
index acb928366004e9db140d7a7907a447262ab61237..918df3b7c93a73af90e05bb85d237e7dfbc0bea7 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20000511"
+#define DEF_MAIL_VERSION       "Snapshot-20000513"
 extern char *var_mail_version;
 
 /* LICENSE
index 9fd23f2bf04629fe2e56c880379cc057b4464c05..62131f8e2f2cb13e4d939821ac0479fd35a1381b 100644 (file)
@@ -164,6 +164,15 @@ void    lmtp_chat_cmd(LMTP_STATE *state, char *fmt,...)
      * Send the command to the LMTP server.
      */
     smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
+
+    /*
+     * Flush unsent output if no I/O happened for a while. This avoids
+     * timeouts with pipelined LMTP sessions that have lots of client-side
+     * delays. The code is here so that it applies to the entire
+     * conversation, never mind that it violates layering.
+     */
+    if (time((time_t *) 0) - vstream_ftime(session->stream) > 10)
+       vstream_fflush(session->stream);
 }
 
 /* lmtp_chat_resp - read and process LMTP server response */
index 75a716e201bc0be49cf2a20d04da556fe074ea98..20933a2d9dc9551c8c20b04e4a8359e027feb16d 100644 (file)
@@ -50,6 +50,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <string.h>
 
 /* Utility library. */
 
index 3f19860248678dbeea65deed8a63bc85562cb60d..f6c80ee7e7fa7300aa998732c91a7ed6f23daba0 100644 (file)
@@ -267,7 +267,7 @@ static void multi_server_wakeup(int fd)
 
 static void multi_server_accept_local(int unused_event, char *context)
 {
-    int     listen_fd = (int) context;
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
     int     time_left = -1;
     int     fd;
 
@@ -301,7 +301,7 @@ static void multi_server_accept_local(int unused_event, char *context)
 
 static void multi_server_accept_inet(int unused_event, char *context)
 {
-    int     listen_fd = (int) context;
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
     int     time_left = -1;
     int     fd;
 
@@ -595,7 +595,7 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
     if (var_idle_limit > 0)
        event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
     for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
-       event_enable_read(fd, multi_server_accept, (char *) fd);
+       event_enable_read(fd, multi_server_accept, CAST_INT_TO_CHAR_PTR(fd));
        close_on_exec(fd, CLOSE_ON_EXEC);
     }
     event_enable_read(MASTER_STATUS_FD, multi_server_abort, (char *) 0);
index ca927a605d079abaabd5027e5476bb2f6adf6cbc..2227d11e6d4e6088bef0cfb5565860491e326b13 100644 (file)
@@ -241,7 +241,7 @@ static void single_server_wakeup(int fd)
 
 static void single_server_accept_local(int unused_event, char *context)
 {
-    int     listen_fd = (int) context;
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
     int     time_left = -1;
     int     fd;
 
@@ -274,7 +274,7 @@ static void single_server_accept_local(int unused_event, char *context)
 
 static void single_server_accept_inet(int unused_event, char *context)
 {
-    int     listen_fd = (int) context;
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
     int     time_left = -1;
     int     fd;
 
@@ -567,7 +567,7 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
     if (var_idle_limit > 0)
        event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
     for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
-       event_enable_read(fd, single_server_accept, (char *) fd);
+       event_enable_read(fd, single_server_accept, CAST_INT_TO_CHAR_PTR(fd));
        close_on_exec(fd, CLOSE_ON_EXEC);
     }
     event_enable_read(MASTER_STATUS_FD, single_server_abort, (char *) 0);
index 98603d18cfccb8f7ef9f99a17b4bef2139c815c1..8ea502a68487f0544b5ffe5f9de798ed4a314674 100644 (file)
@@ -240,7 +240,7 @@ static void trigger_server_wakeup(int fd)
 static void trigger_server_accept_fifo(int unused_event, char *context)
 {
     char   *myname = "trigger_server_accept_fifo";
-    int     listen_fd = (int) context;
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
 
     if (trigger_server_lock != 0
        && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0)
@@ -263,7 +263,7 @@ static void trigger_server_accept_fifo(int unused_event, char *context)
 static void trigger_server_accept_local(int unused_event, char *context)
 {
     char   *myname = "trigger_server_accept_local";
-    int     listen_fd = (int) context;
+    int     listen_fd = CAST_CHAR_PTR_TO_INT(context);
     int     time_left = 0;
     int     fd;
 
@@ -578,7 +578,7 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
     if (var_idle_limit > 0)
        event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
     for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
-       event_enable_read(fd, trigger_server_accept, (char *) fd);
+       event_enable_read(fd, trigger_server_accept, CAST_INT_TO_CHAR_PTR(fd));
        close_on_exec(fd, CLOSE_ON_EXEC);
     }
     event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0);
index de11387a122625ccf8a81d8a660610bbfd1267a9..faf11a1f0fa1596c8e1e0466bdf99983c99d21e2 100644 (file)
@@ -148,6 +148,15 @@ void    smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
      * Send the command to the SMTP server.
      */
     smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
+
+    /*
+     * Flush unsent output if no I/O happened for a while. This avoids
+     * timeouts with pipelined SMTP sessions that have lots of client-side
+     * delays. The code is here so that it applies to the entire
+     * conversation, never mind that it violates layering.
+     */
+    if (time((time_t *) 0) - vstream_ftime(session->stream) > 10)
+       vstream_fflush(session->stream);
 }
 
 /* smtp_chat_resp - read and process SMTP server response */
index 8f267eb4c933885c52bbf56f5e4299762a9d18d5..276e413efe89981a57cd73e3af39ed0e00c2b751 100644 (file)
@@ -56,6 +56,7 @@
 #include <sys_defs.h>
 #include <setjmp.h>
 #include <unistd.h>
+#include <time.h>
 #include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
 #include <stdarg.h>
 
@@ -133,7 +134,6 @@ void    smtpd_chat_query(SMTPD_STATE *state)
 void    smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
 {
     va_list ap;
-    int     slept = 0;
 
     va_start(ap, format);
     vstring_vsprintf(state->buffer, format, ap);
@@ -150,19 +150,19 @@ void    smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
      * errors within a session.
      */
     if (state->error_count > var_smtpd_soft_erlim)
-       sleep(slept = state->error_count);
+       sleep(state->error_count);
     else if (STR(state->buffer)[0] == '4' || STR(state->buffer)[0] == '5')
-       sleep(slept = var_smtpd_err_sleep);
+       sleep(var_smtpd_err_sleep);
 
     smtp_fputs(STR(state->buffer), LEN(state->buffer), state->client);
 
     /*
-     * Flush unsent output AFTER writing instead of before sleeping (so that
-     * vstream_fflush() flushes the output half of a bidirectional stream).
-     * Pipelined error responses could result in client-side timeouts.
+     * Flush unsent output if no I/O happened for a while. This avoids
+     * timeouts with pipelined SMTP sessions that have lots of server-side
+     * delays (tarpit delays or DNS lookups for UCE restrictions).
      */
-    if (slept)
-       (vstream_fflush(state->client));
+    if (time((time_t *) 0) - vstream_ftime(state->client) > 10)
+       vstream_fflush(state->client);
 }
 
 /* print_line - line_wrap callback */
index 85c56e3117877f0d4fc5ac3500cc5dd8dec3d108..115b21d06d0f470a7016f86d9c168e61f67d2424 100644 (file)
   * directory. Adding support for a new system type means updating the
   * makedefs script, and adding a section below for the new system.
   */
-#if (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 104250000)
-#define ALIAS_DB_MAP   "hash:/etc/mail/aliases"        /* sendmail 8.10 */
-#endif
-
 #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
     || defined(FREEBSD5) \
     || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
     || defined(OPENBSD2) || defined(NETBSD1)
 #define SUPPORTED
 #include <sys/types.h>
+#include <sys/param.h>
 #define USE_PATHS_H
 #define USE_FLOCK_LOCK
 #define HAS_SUN_LEN
@@ -36,6 +33,9 @@
 #define HAS_DB
 #define HAS_SA_LEN
 #define DEF_DB_TYPE    "hash"
+#if (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 104250000)
+#define ALIAS_DB_MAP   "hash:/etc/mail/aliases"        /* sendmail 8.10 */
+#endif
 #ifndef ALIAS_DB_MAP
 #define ALIAS_DB_MAP   "hash:/etc/aliases"
 #endif
@@ -56,6 +56,7 @@
 #endif
 
 #if defined(NETBSD1)
+#define ANAL_CAST
 #define USE_DOT_LOCK
 #endif
 
@@ -649,6 +650,14 @@ extern int h_errno;
 #error "unsupported platform"
 #endif
 
+#ifndef ANAL_CAST
+#define CAST_CHAR_PTR_TO_INT(cptr)     ((int) (long) (cptr))
+#define CAST_INT_TO_CHAR_PTR(ival)     ((char *) (long) (ival))
+#else
+#define CAST_CHAR_PTR_TO_INT(cptr)     ((int) (cptr))
+#define CAST_INT_TO_CHAR_PTR(ival)     ((char *) (ival))
+#endif
+
 #ifdef DUP2_DUPS_CLOSE_ON_EXEC
 /* dup2_pass_on_exec() can be found in util/sys_compat.c */
 extern int dup2_pass_on_exec(int oldd, int newd);
index 66d706389067a82c4fee933f58eeb3e996155e85..1627f706d3fb0403ed4886c92a0a2e2cf2f5fd66 100644 (file)
@@ -37,6 +37,9 @@
 /*     int     vbuf_eof(bp)
 /*     VBUF    *bp;
 /*
+/*     int     vbuf_timeout(bp)
+/*     VBUF    *bp;
+/*
 /*     int     vbuf_clearerr(bp)
 /*     VBUF    *bp;
 /* DESCRIPTION
 /*     number of bytes transferred. A short count is returned in case of
 /*     an error.
 /*
-/*     vbuf_err() (vbuf_eof()) is a macro that returns non-zero if an error
-/*     (end-of-file) condition was detected while reading or writing the
-/*     buffer. The error status can be reset by calling vbuf_clearerr().
+/*     vbuf_timeout() is a macro that returns non-zero if a timeout error
+/*     condition was detected while reading or writing the buffer. The 
+/*     error status can be reset by calling vbuf_clearerr().
+/*
+/*     vbuf_err() is a macro that returns non-zero if a non-EOF error
+/*     (including timeout) condition was detected while reading or writing 
+/*     the buffer. The error status can be reset by calling vbuf_clearerr().
+/*
+/*     vbuf_eof() is a macro that returns non-zero if an end-of-file
+/*     condition was detected while reading or writing the buffer. The error 
+/*     status can be reset by calling vbuf_clearerr().
 /* APPLICATION CALLBACK SYNOPSIS
 /*     int     get_ready(bp)
 /*     VBUF    *bp;
index 96e94c07c51162278619fe2890cec324635e60bb..1f582a45845ae100fd77841eddba6ccadceb38bf 100644 (file)
 /*     void    longjmp(stream, val)
 /*     VSTREAM *stream;
 /*     int     val;
+/*
+/*     time_t  vstream_ftime(stream)
+/*     VSTREAM *stream;
 /* DESCRIPTION
 /*     The \fIvstream\fR module implements light-weight buffered I/O
 /*     similar to the standard I/O routines.
 /*
 /*     NB: non-local jumps such as vstream_longjmp() are not safe
 /*     for jumping out of any vstream routine.
+/*
+/*     vstream_ftime() returns the time of initialization, the last buffer
+/*     fill operation, or the last buffer flush operation for the specified
+/*     stream. This information is maintained only when stream timeouts are
+/*     enabled.
 /* DIAGNOSTICS
 /*     Panics: interface violations. Fatal errors: out of memory.
 /* SEE ALSO
 #include <stddef.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <time.h>
 #include <errno.h>
 #include <string.h>
 
@@ -522,6 +531,8 @@ static int vstream_fflush_some(VSTREAM *stream, int to_flush)
      * any.
      */
     for (data = (char *) bp->data, len = to_flush; len > 0; len -= n, data += n) {
+       if (stream->timeout)
+           stream->iotime = time((time_t *) 0);
        if ((n = stream->write_fn(stream->fd, data, len, stream->timeout, stream->context)) <= 0) {
            bp->flags |= VSTREAM_FLAG_ERR;
            if (errno == ETIMEDOUT)
@@ -648,6 +659,8 @@ static int vstream_buf_get_ready(VBUF *bp)
      * data as is available right now, whichever is less. Update the cached
      * file seek position, if any.
      */
+    if (stream->timeout)
+       stream->iotime = time((time_t *) 0);
     switch (n = stream->read_fn(stream->fd, bp->data, bp->len, stream->timeout, stream->context)) {
     case -1:
        bp->flags |= VSTREAM_FLAG_ERR;
@@ -899,6 +912,7 @@ VSTREAM *vstream_fdopen(int fd, int flags)
     stream->timeout = 0;
     stream->context = 0;
     stream->jbuf = 0;
+    stream->iotime = 0;
     return (stream);
 }
 
@@ -1048,6 +1062,8 @@ void    vstream_control(VSTREAM *stream, int name,...)
            stream->waitpid_fn = va_arg(ap, VSTREAM_WAITPID_FN);
            break;
        case VSTREAM_CTL_TIMEOUT:
+           if (stream->timeout == 0)
+               stream->iotime = time((time_t *) 0);
            stream->timeout = va_arg(ap, int);
            break;
        case VSTREAM_CTL_EXCEPT:
index 246cf492d13e92f971072db6aa4963a7b7d57e85..4ae0b5f04f4221fd23cadace84fb8e47522dd90e 100644 (file)
@@ -14,6 +14,7 @@
  /*
   * System library.
   */
+#include <time.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <setjmp.h>
@@ -46,6 +47,7 @@ typedef struct VSTREAM {
     VSTREAM_WAITPID_FN waitpid_fn;     /* vstream_popen/close() */
     int     timeout;                   /* read/write timout */
     jmp_buf *jbuf;                     /* exception handling */
+    time_t  iotime;                    /* time of last fill/flush */
 } VSTREAM;
 
 extern VSTREAM vstream_fstd[];         /* pre-defined streams */
@@ -93,6 +95,7 @@ extern VSTREAM *vstream_fdopen(int, int);
 #define vstream_ftimeout(vp)   vbuf_timeout(&(vp)->buf)
 #define vstream_clearerr(vp)   vbuf_clearerr(&(vp)->buf)
 #define VSTREAM_PATH(vp)       ((vp)->path ? (vp)->path : "unknown_stream")
+#define vstream_ftime(vp)      ((vp)->iotime)
 
 extern void vstream_control(VSTREAM *, int,...);