summaryrefslogtreecommitdiffstats
path: root/src/lib/ostream-wrapper.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/ostream-wrapper.h165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/lib/ostream-wrapper.h b/src/lib/ostream-wrapper.h
new file mode 100644
index 0000000..3fb6ccc
--- /dev/null
+++ b/src/lib/ostream-wrapper.h
@@ -0,0 +1,165 @@
+#ifndef OSTREAM_WRAPPER_H
+#define OSTREAM_WRAPPER_H
+
+#include "ostream-private.h"
+
+/* The wrapper output stream allows turning any form* of activity involving data
+ output into a standard Dovecot output stream. The wrapper output stream can
+ operate both in blocking and non-blocking mode. When the wrapped activity is
+ non-blocking, a blocking wrapper output stream will implicitly run its own
+ ioloop.
+
+ It is possible to have the wrapper output stream object available even before
+ the data can be written anywhere, even before any form of output object (a
+ connection) exists. In that case, any data written to the wrapper stream is
+ buffered until the buffer is full. Once that happens, the stream will block
+ or refuse writes until the underlying output becomes available.
+
+ The wrapper output stream is not meant to be used directly. Instead, it is
+ to be used as part of the implementation of an application-specific output
+ stream. The wrapper output stream serves as the means to prevent code
+ duplication between similar output stream implementations. It defines several
+ methods that need to be implemented by the application-specific output
+ stream.
+
+ * Currently, the wrapper stream still expects an output stream object when
+ data is to be written somewhere, but that should be easily circumvented
+ once such behavior is needed (FIXME).
+ */
+
+struct wrapper_ostream {
+ struct ostream_private ostream;
+ struct event *event;
+
+ /* Called when the implementation should start making the parent output
+ stream available, e.g. connect to the server. This happens when data
+ was written to the wrapper ostream (when it is corked this only
+ happens when the wrapper ostream buffer is full or the wrapper
+ ostream is finished). */
+ void (*output_start)(struct wrapper_ostream *wostream);
+ /* Returns TRUE when the output is ready for data. */
+ bool (*output_ready)(struct wrapper_ostream *wostream);
+ /* Called when an error occurred while writing to the output stream. */
+ void (*output_error)(struct wrapper_ostream *wostream);
+ /* Called when the wrapper ostream was finished using o_stream_finish()
+ and the wrapper ostream buffer is empty. Also, the parent output
+ was flushed successfully. */
+ int (*output_finish)(struct wrapper_ostream *wostream);
+ /* Called when the wrapper ostream does not need write to parent output
+ stream. This is will e.g. drop the parent output's flush callback or
+ equivalent notification mechanism. */
+ void (*output_halt)(struct wrapper_ostream *wostream);
+ /* Called when the wrapper ostream has data available for the parent
+ output and wants wrapper_ostream_continue() to be called when the
+ parent stream is writeable. */
+ void (*output_resume)(struct wrapper_ostream *wostream);
+ /* Update the timeouts. The sender_blocking parameter indicates which
+ side of the data transfer is blocking, so whether a timeout needs to
+ be set for limiting the time other side is not doing anything. */
+ void (*output_update_timeouts)(struct wrapper_ostream *wostream,
+ bool sender_blocking);
+
+ /* Called before and after running ioloop for performing blocking I/O
+ wait. Use these vfuncs to switch to and from the temporary ioloop. */
+ struct ioloop *(*wait_begin)(struct wrapper_ostream *wostream,
+ struct ioloop *ioloop);
+ void (*wait_end)(struct wrapper_ostream *wostream,
+ struct ioloop *prev_ioloop);
+
+ /* Called before and after running the flush callback for the ostream.
+ */
+ void (*callback_pre)(struct wrapper_ostream *wostream);
+ void (*callback_post)(struct wrapper_ostream *wostream);
+
+ /* Called when the ostream is switched to a different ioloop. */
+ void (*switch_ioloop_to)(struct wrapper_ostream *wostream,
+ struct ioloop *ioloop);
+
+ /* Called when the wrapper ostream is forcibly closed using
+ o_stream_close() (or indirectly through e.g. o_stream_destroy()). */
+ void (*close)(struct wrapper_ostream *wostream);
+ /* Called when the ostream is destroyed. */
+ void (*destroy)(struct wrapper_ostream *wostream);
+
+ buffer_t *buffer; // FIXME: use a ringbuffer instead (file_ostream)
+
+ /* The (parent) output stream. */
+ struct ostream *output;
+
+ /* The ioloop used while flushing/sending output for when the wrapper
+ ostream is blocking. */
+ struct ioloop *flush_ioloop;
+
+ /* Error set using wrapper_ostream_return_error(). This is returned to
+ the application once it continues using the wrapper ostream. */
+ char *pending_error;
+ int pending_errno;
+
+ /* Timeout for delayed execution of wrapper_ostream_continue(). */
+ struct timeout *to_event;
+
+ /* Output was started (output_start() vfunc was called). */
+ bool output_started:1;
+ /* Output was finished (output_finish() vfunc was called). */
+ bool output_finished:1;
+ /* Output was was closed somehow. This means that the output is no
+ longer available. This is not the same as the ostream close flag. */
+ bool output_closed:1;
+ /* Output was closed directly or indirectly by the application action.
+ */
+ bool output_closed_api:1;
+
+ bool flush_pending:1;
+ bool flush_waiting:1;
+ bool flushing:1;
+ bool continuing:1;
+ bool returned_error:1;
+};
+
+/* Create the wrapper output stream. This function calls o_stream_create()
+ internally. The initial maximum buffer size is set to max_buffer_size. When
+ blocking is TRUE, a blocking output stream will be created. The provided
+ event is used internally for debug logging. */
+struct ostream *
+wrapper_ostream_create(struct wrapper_ostream *wostream,
+ size_t max_buffer_size, bool blocking,
+ struct event *event) ATTR_NULL(4);
+
+/* Continue sending output. Returns 1 if all buffered data is sent so far,
+ 0 if not, and -1 if an error occurred. */
+int wrapper_ostream_continue(struct wrapper_ostream *wostream);
+/* Trigger an (asynchronous) flush on the output stream. */
+void wrapper_ostream_trigger_flush(struct wrapper_ostream *wostream);
+
+/* This function returns the size of the data buffered in the wrapper stream,
+ but only when the output stream is finished using o_stream_finish(). When the
+ output stream is finished, the data is complete and this function returns
+ TRUE and size_r is set to the size. If it is not complete, this function
+ returns FALSE and size_r is not assigned. This function is meant to be called
+ just before sending the first block of data internally for deciding between
+ sending the data using a chunked transfer encoding or, when it is already
+ complete, as a single blob with known size. E.g., for HTTP this is the choice
+ between sending the message using the Transfer-Encoding: chunked header or
+ the Content-Length header. */
+bool wrapper_ostream_get_buffered_size(struct wrapper_ostream *wostream,
+ uoff_t *size_r);
+
+/* Call this when the underlying output stream first becomes available. */
+void wrapper_ostream_output_available(struct wrapper_ostream *wostream,
+ struct ostream *output);
+/* Call this to notify the wrapper that the underlying output is destroyed and
+ no more data can be written ever. */
+void wrapper_ostream_output_destroyed(struct wrapper_ostream *wostream);
+
+/* Call this to notify the wrapper that an error has occurred. It will be
+ returned as such for the next stream write/flush and subsequent
+ o_stream_get_error(). */
+void wrapper_ostream_set_error(struct wrapper_ostream *wostream,
+ int stream_errno, const char *stream_error);
+/* Notify the application immediately about any error condition set earlier
+ using wrapper_ostream_set_error() by calling the ostream flush callback
+ right now.
+ */
+void wrapper_ostream_notify_error(struct wrapper_ostream *wostream);
+
+#endif