ostream.c revision 6adf683655750bcb809275cd65dc75fd12214198
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_set_name(struct ostream *stream, const char *name)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen stream->real_stream->iostream.name = i_strdup(name);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenconst char *o_stream_get_name(struct ostream *stream)
1d738cce754bc64bbc66d3355ebdaf3f6eac55f1Timo Sirainen while (stream->real_stream->iostream.name == NULL) {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainenconst char *o_stream_get_error(struct ostream *stream)
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen /* we'll only return errors for streams that have stream_errno set.
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen we might be returning unintended error otherwise. */
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen return "<no error>";
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen for (s = stream; s != NULL; s = s->real_stream->parent) {
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainenstatic void o_stream_close_full(struct ostream *stream, bool close_parents)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!stream->closed && !stream->real_stream->closing) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* first mark the stream as being closed so the
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_copy_error_from_parent() won't recurse us back
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen here. but don't immediately mark the stream closed, because
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen we may still want to write something to it. */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen io_stream_close(&stream->real_stream->iostream, close_parents);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen io_stream_ref(&stream->real_stream->iostream);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (stream->real_stream->last_errors_not_checked &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen !stream->real_stream->error_handling_disabled &&
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen stream->real_stream->iostream.refcount == 1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_panic("output stream %s is missing error handling",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!io_stream_unref(&stream->real_stream->iostream))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen io_stream_free(&stream->real_stream->iostream);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_add_destroy_callback(struct ostream *stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen io_stream_add_destroy_callback(&stream->real_stream->iostream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_remove_destroy_callback(struct ostream *stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen io_stream_remove_destroy_callback(&stream->real_stream->iostream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_set_flush_callback(struct ostream *stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct ostream_private *_stream = stream->real_stream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen _stream->set_flush_callback(_stream, callback, context);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_unset_flush_callback(struct ostream *stream)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct ostream_private *_stream = stream->real_stream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen _stream->set_flush_callback(_stream, NULL, NULL);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainensize_t o_stream_get_max_buffer_size(struct ostream *stream)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct ostream_private *_stream = stream->real_stream;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct ostream_private *_stream = stream->real_stream;
0bf3eac1110a902e7ec7e695c64e8e46c114e623Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenbool o_stream_is_corked(struct ostream *stream)
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen struct ostream_private *_stream = stream->real_stream;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen struct ostream_private *_stream = stream->real_stream;
f153a2cec0319f549388d28f8cfd4d50229d1132Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (unlikely((ret = _stream->flush(_stream)) < 0)) {
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainenvoid o_stream_set_flush_pending(struct ostream *stream, bool set)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct ostream_private *_stream = stream->real_stream;
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainensize_t o_stream_get_buffer_used_size(const struct ostream *stream)
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen const struct ostream_private *_stream = stream->real_stream;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainensize_t o_stream_get_buffer_avail_size(const struct ostream *stream)
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainen size_t used = o_stream_get_buffer_used_size(stream);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return stream->real_stream->max_buffer_size <= used ? 0 :
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint o_stream_seek(struct ostream *stream, uoff_t offset)
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen struct ostream_private *_stream = stream->real_stream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlikely(_stream->seek(_stream, offset) < 0)) {
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainenssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
8d131435ba4648c8821160ec38d508c97177c715Timo Siraineno_stream_sendv_int(struct ostream *stream, const struct const_iovec *iov,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct ostream_private *_stream = stream->real_stream;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i;
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen for (i = 0, total_size = 0; i < iov_count; i++)
b5b3b4c9159f506cdfdce7399faaeeffdf73faf7Timo Sirainen ret = _stream->sendv(_stream, iov, iov_count);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return o_stream_sendv_int(stream, iov, iov_count, &overflow);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenssize_t o_stream_send_str(struct ostream *stream, const char *str)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return o_stream_send(stream, str, strlen(str));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_nsend(struct ostream *stream, const void *data, size_t size)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0 ||
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)o_stream_sendv_int(stream, iov, iov_count, &overflow);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainenvoid o_stream_nsend_str(struct ostream *stream, const char *str)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen stream->real_stream->last_errors_not_checked = TRUE;
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen if (stream->stream_errno == 0 && stream->real_stream->noverflow) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen io_stream_set_error(&stream->real_stream->iostream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Output stream buffer was full (%"PRIuSIZE_T" bytes)",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_ignore_last_errors(struct ostream *stream)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen stream->real_stream->last_errors_not_checked = FALSE;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid o_stream_set_no_error_handling(struct ostream *stream, bool set)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen stream->real_stream->error_handling_disabled = set;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint o_stream_send_istream(struct ostream *outstream, struct istream *instream)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen struct ostream_private *_outstream = outstream->real_stream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uoff_t old_outstream_offset = outstream->offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uoff_t old_instream_offset = instream->v_offset;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlikely(outstream->closed || instream->closed ||
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = _outstream->send_istream(_outstream, instream);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* partial send */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(!outstream->blocking || !instream->blocking);
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen /* fully sent everything */
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen i_assert(!i_stream_have_bytes_left(instream));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert((outstream->offset - old_outstream_offset) ==
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainenint o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (unlikely(stream->closed || stream->stream_errno != 0)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = stream->real_stream->write_at(stream->real_stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint io_stream_copy(struct ostream *outstream, struct istream *instream)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const unsigned char *data;
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen while (i_stream_read_more(instream, &data, &iov.iov_len) > 0) {
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if ((ret = o_stream_sendv(outstream, &iov, 1)) <= 0)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen return i_stream_have_bytes_left(instream) ? 0 : 1;
63e2edd14ae7b1dc4a08e2e659501dbf519462f9Timo Sirainenvoid o_stream_switch_ioloop(struct ostream *stream)
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen struct ostream_private *_stream = stream->real_stream;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainenstatic void o_stream_default_close(struct iostream_private *stream,
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Sirainenstatic void o_stream_default_destroy(struct iostream_private *stream)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
9061a2a9a7f8da780a5b50af3603f828167c6b13Timo Siraineno_stream_default_set_max_buffer_size(struct iostream_private *stream,
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen struct ostream_private *_stream = (struct ostream_private *)stream;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_set_max_buffer_size(_stream->parent, max_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic void o_stream_default_cork(struct ostream_private *_stream, bool set)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainenvoid o_stream_copy_error_from_parent(struct ostream_private *_stream)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainenint o_stream_flush_parent_if_needed(struct ostream_private *_stream)
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
40ad2c4902e9d83557f2e8a4bff3d98fea2c8aa1Timo Sirainen /* we already have quite a lot of data in parent stream.
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen unless we can flush it, don't add any more to it or we
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen could keep wasting memory by just increasing the buffer
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen size all the time. */
aef92409cf369afdd2ecd81a4f80083cd4082f46Timo Sirainen if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int o_stream_default_flush(struct ostream_private *_stream)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if ((ret = o_stream_flush(_stream->parent)) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Siraineno_stream_default_set_flush_callback(struct ostream_private *_stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_set_flush_callback(_stream->parent, callback, context);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Siraineno_stream_default_set_flush_pending(struct ostream_private *_stream, bool set)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen o_stream_set_flush_pending(_stream->parent, set);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Siraineno_stream_default_get_used_size(const struct ostream_private *_stream)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return o_stream_get_buffer_used_size(_stream->parent);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Siraineno_stream_default_seek(struct ostream_private *_stream,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Siraineno_stream_default_sendv(struct ostream_private *stream,
90c23747727c85f80e4e8eed7968f0edbeac7ac5Timo Sirainen const struct const_iovec *iov, unsigned int iov_count)
8f0e6d627f3646e559ac5224c306839669d1a5e0Timo Sirainen if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Siraineno_stream_default_write_at(struct ostream_private *_stream,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen size_t size ATTR_UNUSED, uoff_t offset ATTR_UNUSED)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int o_stream_default_send_istream(struct ostream_private *outstream,
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen return io_stream_copy(&outstream->ostream, instream);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void o_stream_default_switch_ioloop(struct ostream_private *_stream)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Siraineno_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen _stream->callback = parent->real_stream->callback;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen _stream->context = parent->real_stream->context;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen _stream->max_buffer_size = parent->real_stream->max_buffer_size;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->iostream.close = o_stream_default_close;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->iostream.destroy = o_stream_default_destroy;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen if (_stream->iostream.set_max_buffer_size == NULL) {
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->flush_pending = o_stream_default_set_flush_pending;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->get_used_size = o_stream_default_get_used_size;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->write_at = o_stream_default_write_at;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->send_istream = o_stream_default_send_istream;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen _stream->switch_ioloop = o_stream_default_switch_ioloop;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenstruct ostream *o_stream_create_error(int stream_errno)
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Siraineno_stream_create_error_str(int stream_errno, const char *fmt, ...)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen io_stream_set_verror(&output->real_stream->iostream, fmt, args);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstruct ostream *o_stream_create_passthrough(struct ostream *output)