summaryrefslogtreecommitdiffstats
path: root/src/lib/iostream.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/iostream.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/lib/iostream.c b/src/lib/iostream.c
new file mode 100644
index 0000000..f2ba000
--- /dev/null
+++ b/src/lib/iostream.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "istream.h"
+#include "ostream.h"
+#include "iostream-private.h"
+
+static void
+io_stream_default_close(struct iostream_private *stream ATTR_UNUSED,
+ bool close_parent ATTR_UNUSED)
+{
+}
+
+static void
+io_stream_default_destroy(struct iostream_private *stream ATTR_UNUSED)
+{
+}
+
+void io_stream_init(struct iostream_private *stream)
+{
+ if (stream->close == NULL)
+ stream->close = io_stream_default_close;
+ if (stream->destroy == NULL)
+ stream->destroy = io_stream_default_destroy;
+ stream->ioloop = current_ioloop;
+
+ stream->refcount = 1;
+}
+
+void io_stream_ref(struct iostream_private *stream)
+{
+ i_assert(stream->refcount > 0);
+
+ stream->refcount++;
+}
+
+bool io_stream_unref(struct iostream_private *stream)
+{
+ i_assert(stream->refcount > 0);
+ if (--stream->refcount != 0)
+ return TRUE;
+
+ stream->close(stream, FALSE);
+ stream->destroy(stream);
+ return FALSE;
+}
+
+void io_stream_free(struct iostream_private *stream)
+{
+ const struct iostream_destroy_callback *dc;
+
+ if (array_is_created(&stream->destroy_callbacks)) {
+ array_foreach(&stream->destroy_callbacks, dc)
+ dc->callback(dc->context);
+ array_free(&stream->destroy_callbacks);
+ }
+
+ i_free(stream->error);
+ i_free(stream->name);
+ i_free(stream);
+}
+
+void io_stream_close(struct iostream_private *stream, bool close_parent)
+{
+ stream->close(stream, close_parent);
+}
+
+void io_stream_set_max_buffer_size(struct iostream_private *stream,
+ size_t max_size)
+{
+ stream->set_max_buffer_size(stream, max_size);
+}
+
+void io_stream_add_destroy_callback(struct iostream_private *stream,
+ void (*callback)(void *), void *context)
+{
+ struct iostream_destroy_callback *dc;
+
+ if (!array_is_created(&stream->destroy_callbacks))
+ i_array_init(&stream->destroy_callbacks, 2);
+ dc = array_append_space(&stream->destroy_callbacks);
+ dc->callback = callback;
+ dc->context = context;
+}
+
+void io_stream_remove_destroy_callback(struct iostream_private *stream,
+ void (*callback)(void *))
+{
+ const struct iostream_destroy_callback *dcs;
+ unsigned int i, count;
+
+ dcs = array_get(&stream->destroy_callbacks, &count);
+ for (i = 0; i < count; i++) {
+ if (dcs[i].callback == callback) {
+ array_delete(&stream->destroy_callbacks, i, 1);
+ return;
+ }
+ }
+ i_unreached();
+}
+
+void io_stream_set_error(struct iostream_private *stream,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ io_stream_set_verror(stream, fmt, args);
+ va_end(args);
+}
+
+void io_stream_set_verror(struct iostream_private *stream,
+ const char *fmt, va_list args)
+{
+ /* one of the parameters may be the old stream->error, so don't free
+ it before the new error is created. */
+ char *error = i_strdup_vprintf(fmt, args);
+ i_free(stream->error);
+ stream->error = error;
+}
+
+const char *io_stream_get_disconnect_reason(struct istream *input,
+ struct ostream *output)
+{
+ const char *errstr;
+
+ if (input != NULL && input->stream_errno != 0) {
+ errno = input->stream_errno;
+ errstr = i_stream_get_error(input);
+ } else if (output != NULL && output->stream_errno != 0) {
+ errno = output->stream_errno;
+ errstr = o_stream_get_error(output);
+ } else {
+ errno = 0;
+ errstr = "";
+ }
+
+ if (errno == 0 || errno == EPIPE)
+ return "Connection closed";
+ else
+ return t_strdup_printf("Connection closed: %s", errstr);
+}
+
+void io_stream_switch_ioloop_to(struct iostream_private *stream,
+ struct ioloop *ioloop)
+{
+ stream->ioloop = ioloop;
+}
+
+struct ioloop *io_stream_get_ioloop(struct iostream_private *stream)
+{
+ return (stream->ioloop == NULL ? current_ioloop : stream->ioloop);
+}