dovecot-2.2: Added istream-timeout, which triggers I/O event and...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Apr 3 16:55:06 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/b1a756176ed2
changeset: 17189:b1a756176ed2
user: Timo Sirainen <tss at iki.fi>
date: Thu Apr 03 19:53:13 2014 +0300
description:
Added istream-timeout, which triggers I/O event and fails with ETIMEDOUT after the timeout.
diffstat:
src/lib/Makefile.am | 2 +
src/lib/istream-timeout.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++
src/lib/istream-timeout.h | 9 +++
3 files changed, 134 insertions(+), 0 deletions(-)
diffs (159 lines):
diff -r fd186eff7325 -r b1a756176ed2 src/lib/Makefile.am
--- a/src/lib/Makefile.am Thu Apr 03 19:51:52 2014 +0300
+++ b/src/lib/Makefile.am Thu Apr 03 19:53:13 2014 +0300
@@ -70,6 +70,7 @@
istream-seekable.c \
istream-sized.c \
istream-tee.c \
+ istream-timeout.c \
ioloop.c \
ioloop-iolist.c \
ioloop-notify-none.c \
@@ -197,6 +198,7 @@
istream-seekable.h \
istream-sized.h \
istream-tee.h \
+ istream-timeout.h \
ioloop.h \
ioloop-iolist.h \
ioloop-private.h \
diff -r fd186eff7325 -r b1a756176ed2 src/lib/istream-timeout.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-timeout.c Thu Apr 03 19:53:13 2014 +0300
@@ -0,0 +1,123 @@
+/* Copyright (c) 2014 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "time-util.h"
+#include "istream-private.h"
+#include "istream-timeout.h"
+
+struct timeout_istream {
+ struct istream_private istream;
+
+ struct timeout *to;
+ struct timeval last_read_timestamp;
+
+ unsigned int timeout_msecs;
+ bool update_timestamp;
+};
+
+static void i_stream_timeout_close(struct iostream_private *stream,
+ bool close_parent)
+{
+ struct timeout_istream *tstream = (struct timeout_istream *)stream;
+
+ if (tstream->to != NULL)
+ timeout_remove(&tstream->to);
+ if (close_parent)
+ i_stream_close(tstream->istream.parent);
+}
+
+static void i_stream_timeout_switch_ioloop(struct istream_private *stream)
+{
+ struct timeout_istream *tstream = (struct timeout_istream *)stream;
+
+ if (tstream->to != NULL)
+ tstream->to = io_loop_move_timeout(&tstream->to);
+}
+
+static void i_stream_timeout(struct timeout_istream *tstream)
+{
+ unsigned int msecs;
+ int diff;
+
+ timeout_remove(&tstream->to);
+
+ diff = timeval_diff_msecs(&ioloop_timeval, &tstream->last_read_timestamp);
+ if (diff < (int)tstream->timeout_msecs) {
+ /* we haven't reached the read timeout yet, update it */
+ if (diff < 0)
+ diff = 0;
+ tstream->to = timeout_add(tstream->timeout_msecs - diff,
+ i_stream_timeout, tstream);
+ return;
+ }
+
+ msecs = tstream->timeout_msecs % 1000;
+ io_stream_set_error(&tstream->istream.iostream,
+ "Read timeout in %u%s s after %"PRIuUOFF_T" bytes",
+ tstream->timeout_msecs/1000,
+ msecs == 0 ? "" : t_strdup_printf(".%u", msecs),
+ tstream->istream.istream.v_offset);
+ tstream->istream.istream.stream_errno = ETIMEDOUT;
+
+ i_stream_set_input_pending(tstream->istream.parent, TRUE);
+}
+
+static ssize_t
+i_stream_timeout_read(struct istream_private *stream)
+{
+ struct timeout_istream *tstream = (struct timeout_istream *)stream;
+ ssize_t ret;
+
+ i_stream_seek(stream->parent, stream->parent_start_offset +
+ stream->istream.v_offset);
+
+ ret = i_stream_read_copy_from_parent(&stream->istream);
+ if (ret < 0) {
+ /* failed */
+ } else if (tstream->to == NULL) {
+ /* first read. add the timeout here instead of in init
+ in case the stream is created long before it's actually
+ read from. */
+ 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;
+ } 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);
+ } else if (tstream->update_timestamp) {
+ tstream->update_timestamp = FALSE;
+ tstream->last_read_timestamp = ioloop_timeval;
+ }
+ return ret;
+}
+
+struct istream *
+i_stream_create_timeout(struct istream *input, unsigned int timeout_msecs)
+{
+ struct timeout_istream *tstream;
+
+ tstream = i_new(struct timeout_istream, 1);
+ tstream->timeout_msecs = timeout_msecs;
+ tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
+ tstream->istream.stream_size_passthrough = TRUE;
+
+ tstream->istream.read = i_stream_timeout_read;
+ tstream->istream.switch_ioloop = i_stream_timeout_switch_ioloop;
+ tstream->istream.iostream.close = i_stream_timeout_close;
+
+ tstream->istream.istream.blocking = input->blocking;
+ tstream->istream.istream.seekable = input->seekable;
+ return i_stream_create(&tstream->istream, input,
+ i_stream_get_fd(input));
+}
diff -r fd186eff7325 -r b1a756176ed2 src/lib/istream-timeout.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-timeout.h Thu Apr 03 19:53:13 2014 +0300
@@ -0,0 +1,9 @@
+#ifndef ISTREAM_TIMEOUT_H
+#define ISTREAM_TIMEOUT_H
+
+/* Return ETIMEDOUT error if read() doesn't return anything for timeout_msecs.
+ If timeout_msecs=0, there is no timeout. */
+struct istream *
+i_stream_create_timeout(struct istream *input, unsigned int timeout_msecs);
+
+#endif
More information about the dovecot-cvs
mailing list