]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib, lib-ssl-iostream: Split off o_stream_init_buffering_flush()
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 4 Jun 2025 06:56:26 +0000 (09:56 +0300)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Sat, 12 Jul 2025 06:49:23 +0000 (06:49 +0000)
src/lib-ssl-iostream/ostream-openssl.c
src/lib/ostream-private.h
src/lib/ostream.c

index fe50535376f1293947f750b6019aa45b43584a71..530aa29bb294fe8a1fcfd596e374c4cac0f6ab75 100644 (file)
@@ -217,29 +217,6 @@ static void o_stream_ssl_switch_ioloop_to(struct ostream_private *stream,
        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)
 {
@@ -310,10 +287,7 @@ struct ostream *openssl_o_stream_create_ssl(struct ssl_iostream *ssl_io)
        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));
index 6222aa08d3b42bded8548698e066fa300d62b697..b4d08f5b4722e558ed54c3f3d25317efe8b73239 100644 (file)
@@ -34,6 +34,7 @@ struct ostream_private {
        size_t max_buffer_size;
 
        struct ostream *parent; /* for filter streams */
+       struct ostream *buffering_parent;
 
        int fd;
        struct timeval last_write_timeval;
@@ -70,4 +71,12 @@ int o_stream_flush_parent_if_needed(struct ostream_private *_stream);
    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
index 11b358ff1d6a0bf9dff12fa3100e57a47e046ec5..55ecb8b826e3cee3bbbddf77e5866dd5d8be1bfc 100644 (file)
@@ -139,6 +139,40 @@ void o_stream_close(struct ostream *stream)
                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,
@@ -641,7 +675,7 @@ o_stream_default_set_flush_callback(struct ostream_private *_stream,
                                    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;
@@ -734,8 +768,10 @@ o_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
                _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;