]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: istream-timeout could have triggered timeout too early after long-running code.
authorTimo Sirainen <tss@iki.fi>
Fri, 7 Aug 2015 09:58:30 +0000 (12:58 +0300)
committerTimo Sirainen <tss@iki.fi>
Fri, 7 Aug 2015 09:58:30 +0000 (12:58 +0300)
src/lib/istream-timeout.c

index c35f31c9e837bccbe7207ed434440155730fbe8a..b4dce85a6e6d229acd7464873a4963dcc671784c 100644 (file)
@@ -41,6 +41,13 @@ static void i_stream_timeout(struct timeout_istream *tstream)
        unsigned int msecs;
        int diff;
 
+       if (tstream->update_timestamp) {
+               /* we came here after a long-running code. timeouts are handled
+                  before IOs, so wait for i_stream_read() to be called again
+                  before assuming that we've timed out. */
+               return;
+       }
+
        timeout_remove(&tstream->to);
 
        diff = timeval_diff_msecs(&ioloop_timeval, &tstream->last_read_timestamp);
@@ -64,6 +71,17 @@ static void i_stream_timeout(struct timeout_istream *tstream)
        i_stream_set_input_pending(tstream->istream.parent, TRUE);
 }
 
+static void i_stream_timeout_set_pending(struct timeout_istream *tstream)
+{
+       /* make sure we get called again on the next ioloop run. this updates
+          the timeout to the timestamp where we actually would have wanted to
+          start waiting for more data (so if there is long-running code
+          outside the ioloop it's not counted) */
+       tstream->update_timestamp = TRUE;
+       tstream->last_read_timestamp = ioloop_timeval;
+       i_stream_set_input_pending(&tstream->istream.istream, TRUE);
+}
+
 static ssize_t
 i_stream_timeout_read(struct istream_private *stream)
 {
@@ -90,19 +108,11 @@ i_stream_timeout_read(struct istream_private *stream)
                tstream->to = tstream->timeout_msecs == 0 ? NULL :
                        timeout_add(tstream->timeout_msecs,
                                    i_stream_timeout, tstream);
-               tstream->update_timestamp = TRUE;
-               tstream->last_read_timestamp = ioloop_timeval;
+               i_stream_timeout_set_pending(tstream);
        } else if (ret > 0 && tstream->to != NULL) {
                /* we read something, reset the timeout */
                timeout_reset(tstream->to);
-               /* make sure we get called again on the next ioloop run.
-                  this updates the timeout to the timestamp where we actually
-                  would have wanted to start waiting for more data (so if
-                  there is long-running code outside the ioloop it's not
-                  counted) */
-               tstream->update_timestamp = TRUE;
-               tstream->last_read_timestamp = ioloop_timeval;
-               i_stream_set_input_pending(&stream->istream, TRUE);
+               i_stream_timeout_set_pending(tstream);
        } else if (tstream->update_timestamp) {
                tstream->update_timestamp = FALSE;
                tstream->last_read_timestamp = ioloop_timeval;