diff options
Diffstat (limited to 'src/lib/ostream-wrapper.h')
-rw-r--r-- | src/lib/ostream-wrapper.h | 165 |
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 |