istream-timeout.c revision 8e0eb6a0cfc2cb66385bdf05a70a38d753bc1e24
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic void i_stream_timeout_close(struct iostream_private *stream,
373492be949e159fda651807b3acda2c5c077027Timo Sirainen struct timeout_istream *tstream = (struct timeout_istream *)stream;
373492be949e159fda651807b3acda2c5c077027Timo Sirainenstatic void i_stream_timeout_switch_ioloop(struct istream_private *stream)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct timeout_istream *tstream = (struct timeout_istream *)stream;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen tstream->to = io_loop_move_timeout(&tstream->to);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void i_stream_timeout(struct timeout_istream *tstream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen unsigned int msecs;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* we came here after a long-running code. timeouts are handled
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen before IOs, so wait for i_stream_read() to be called again
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen before assuming that we've timed out. */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen diff = timeval_diff_msecs(&ioloop_timeval, &tstream->last_read_timestamp);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* we haven't reached the read timeout yet, update it */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen tstream->to = timeout_add(tstream->timeout_msecs - diff,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen io_stream_set_error(&tstream->istream.iostream,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen "Read timeout in %u%s s after %"PRIuUOFF_T" bytes",
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen msecs == 0 ? "" : t_strdup_printf(".%u", msecs),
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen tstream->istream.istream.stream_errno = ETIMEDOUT;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen i_stream_set_input_pending(tstream->istream.parent, TRUE);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic void i_stream_timeout_set_pending(struct timeout_istream *tstream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* make sure we get called again on the next ioloop run. this updates
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen the timeout to the timestamp where we actually would have wanted to
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen start waiting for more data (so if there is long-running code
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen outside the ioloop it's not counted) */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen tstream->last_read_timestamp = ioloop_timeval;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_stream_set_input_pending(&tstream->istream.istream, TRUE);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Siraineni_stream_timeout_read(struct istream_private *stream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct timeout_istream *tstream = (struct timeout_istream *)stream;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_stream_seek(stream->parent, stream->parent_start_offset +
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen ret = i_stream_read_copy_from_parent(&stream->istream);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen io_stream_set_error(&tstream->istream.iostream,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "%s (opened %d secs ago)",
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen } else if (tstream->to == NULL && tstream->timeout_msecs > 0) {
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. */
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen tstream->to = timeout_add(tstream->timeout_msecs,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* we read something, reset the timeout */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen tstream->last_read_timestamp = ioloop_timeval;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Siraineni_stream_create_timeout(struct istream *input, unsigned int timeout_msecs)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen tstream->istream.stream_size_passthrough = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->istream.read = i_stream_timeout_read;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->istream.switch_ioloop = i_stream_timeout_switch_ioloop;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->istream.iostream.close = i_stream_timeout_close;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->istream.istream.readable_fd = input->readable_fd;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen tstream->istream.istream.blocking = input->blocking;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen tstream->istream.istream.seekable = input->seekable;