o_stream_switch_ioloop_to(sstream->ssl_io->plain_output, ioloop);
}
-static int plain_flush_callback(struct ssl_ostream *sstream)
-{
- struct ostream *ostream = &sstream->ostream.ostream;
- int ret, ret2;
-
- /* try to actually flush the pending data */
- if ((ret = o_stream_flush(sstream->ssl_io->plain_output)) < 0)
- return -1;
-
- /* we may be able to copy more data, try it */
- o_stream_ref(ostream);
- if (sstream->ostream.callback != NULL)
- ret2 = sstream->ostream.callback(sstream->ostream.context);
- else
- ret2 = o_stream_flush(&sstream->ostream.ostream);
- if (ret2 == 0)
- o_stream_set_flush_pending(sstream->ssl_io->plain_output, TRUE);
- o_stream_unref(&ostream);
- if (ret2 < 0)
- return -1;
- return ret > 0 && ret2 > 0 ? 1 : 0;
-}
-
static size_t
o_stream_ssl_get_buffer_used_size(const struct ostream_private *stream)
{
sstream->ostream.iostream.set_max_buffer_size =
o_stream_ssl_set_max_buffer_size;
- sstream->ostream.callback = ssl_io->plain_output->real_stream->callback;
- sstream->ostream.context = ssl_io->plain_output->real_stream->context;
- o_stream_set_flush_callback(ssl_io->plain_output,
- plain_flush_callback, sstream);
+ o_stream_init_buffering_flush(&sstream->ostream, ssl_io->plain_output);
return o_stream_create(&sstream->ostream, NULL,
o_stream_get_fd(ssl_io->plain_output));
size_t max_buffer_size;
struct ostream *parent; /* for filter streams */
+ struct ostream *buffering_parent;
int fd;
struct timeval last_write_timeval;
copied to this stream. */
int o_stream_flush_parent(struct ostream_private *_stream);
+/* ostreams that buffer data internally need to be able to continue the flush
+ after parent ostream has more space available. This function registers a
+ flush callback to the parent ostream, which triggers flushing on this
+ ostream. If the parent already had a flush callback, it gets first copied to
+ this ostream. */
+void o_stream_init_buffering_flush(struct ostream_private *_stream,
+ struct ostream *parent);
+
#endif
o_stream_close_full(stream, TRUE);
}
+static int o_stream_default_buffering_flush(struct ostream_private *_stream)
+{
+ struct ostream *ostream = &_stream->ostream;
+ int ret, ret2;
+
+ /* try to actually flush the pending data */
+ if ((ret = o_stream_flush(_stream->buffering_parent)) < 0)
+ return -1;
+
+ /* we may be able to copy more data, try it */
+ o_stream_ref(ostream);
+ if (_stream->callback != NULL)
+ ret2 = _stream->callback(_stream->context);
+ else
+ ret2 = o_stream_flush(ostream);
+ if (ret2 == 0)
+ o_stream_set_flush_pending(_stream->buffering_parent, TRUE);
+ o_stream_unref(&ostream);
+ if (ret2 < 0)
+ return -1;
+ return ret > 0 && ret2 > 0 ? 1 : 0;
+}
+
+void o_stream_init_buffering_flush(struct ostream_private *_stream,
+ struct ostream *parent)
+{
+ _stream->buffering_parent = parent;
+ _stream->callback = parent->real_stream->callback;
+ _stream->context = parent->real_stream->context;
+
+ o_stream_set_flush_callback(parent, o_stream_default_buffering_flush,
+ _stream);
+}
+
#undef o_stream_set_flush_callback
void o_stream_set_flush_callback(struct ostream *stream,
stream_flush_callback_t *callback,
stream_flush_callback_t *callback,
void *context)
{
- if (_stream->parent != NULL)
+ if (_stream->parent != NULL && _stream->buffering_parent == NULL)
o_stream_set_flush_callback(_stream->parent, callback, context);
_stream->callback = callback;
_stream->parent = parent;
o_stream_ref(parent);
- _stream->callback = parent->real_stream->callback;
- _stream->context = parent->real_stream->context;
+ if (_stream->buffering_parent == NULL) {
+ _stream->callback = parent->real_stream->callback;
+ _stream->context = parent->real_stream->context;
+ }
_stream->max_buffer_size = parent->real_stream->max_buffer_size;
_stream->error_handling_disabled =
parent->real_stream->error_handling_disabled;