istream-timeout.c revision 25fb397382c6f7d39bfeee85774e7675f02bfb3c
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenstatic void i_stream_timeout_close(struct iostream_private *stream,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen struct timeout_istream *tstream = (struct timeout_istream *)stream;
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainenstatic void i_stream_timeout_switch_ioloop(struct istream_private *stream)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen struct timeout_istream *tstream = (struct timeout_istream *)stream;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->to = io_loop_move_timeout(&tstream->to);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainenstatic void i_stream_timeout(struct timeout_istream *tstream)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen unsigned int msecs;
abc79eec93e58e0152cd1d483f37be66c26811b9Timo Sirainen /* we came here after a long-running code. timeouts are handled
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen before IOs, so wait for i_stream_read() to be called again
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen before assuming that we've timed out. */
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen diff = timeval_diff_msecs(&ioloop_timeval, &tstream->last_read_timestamp);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen /* we haven't reached the read timeout yet, update it */
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen tstream->to = timeout_add(tstream->timeout_msecs - diff,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen io_stream_set_error(&tstream->istream.iostream,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen "Read timeout in %u%s s after %"PRIuUOFF_T" bytes",
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen msecs == 0 ? "" : t_strdup_printf(".%u", msecs),
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen tstream->istream.istream.stream_errno = ETIMEDOUT;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_stream_set_input_pending(tstream->istream.parent, TRUE);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic void i_stream_timeout_set_pending(struct timeout_istream *tstream)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* make sure we get called again on the next ioloop run. this updates
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen the timeout to the timestamp where we actually would have wanted to
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen start waiting for more data (so if there is long-running code
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen outside the ioloop it's not counted) */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen tstream->last_read_timestamp = ioloop_timeval;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_stream_set_input_pending(&tstream->istream.istream, TRUE);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Siraineni_stream_timeout_read(struct istream_private *stream)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct timeout_istream *tstream = (struct timeout_istream *)stream;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen io_stream_set_error(&tstream->istream.iostream,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "%s (opened %d secs ago)",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* first read. add the timeout here instead of in init
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen in case the stream is created long before it's actually
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen read from. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->to = tstream->timeout_msecs == 0 ? NULL :
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* we read something, reset the timeout */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->last_read_timestamp = ioloop_timeval;
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Siraineni_stream_create_timeout(struct istream *input, unsigned int timeout_msecs)
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen tstream->istream.stream_size_passthrough = TRUE;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen tstream->istream.read = i_stream_timeout_read;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen tstream->istream.switch_ioloop = i_stream_timeout_switch_ioloop;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen tstream->istream.iostream.close = i_stream_timeout_close;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen tstream->istream.istream.readable_fd = input->readable_fd;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen tstream->istream.istream.blocking = input->blocking;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen tstream->istream.istream.seekable = input->seekable;