]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Add iostream-proxy
authorAki Tuomi <aki.tuomi@dovecot.fi>
Thu, 15 Sep 2016 08:33:01 +0000 (11:33 +0300)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Thu, 17 Nov 2016 20:15:19 +0000 (22:15 +0200)
iostream-proxy proxies data between two pairs of
istream/ostream.

src/lib/Makefile.am
src/lib/iostream-proxy.c [new file with mode: 0644]
src/lib/iostream-proxy.h [new file with mode: 0644]

index bb65dbf337d6af1796f1d6a1a987a461f643428c..0812a70e31c9f186057cc2506859c149ecaf8999 100644 (file)
@@ -55,6 +55,7 @@ liblib_la_SOURCES = \
        ipwd.c \
        iostream.c \
        iostream-pump.c \
+       iostream-proxy.c \
        iostream-rawlog.c \
        iostream-temp.c \
        iso8601-date.c \
@@ -205,6 +206,7 @@ headers = \
        iostream.h \
        iostream-private.h \
        iostream-pump.h \
+       iostream-proxy.h \
        iostream-rawlog.h \
        iostream-rawlog-private.h \
        iostream-temp.h \
diff --git a/src/lib/iostream-proxy.c b/src/lib/iostream-proxy.c
new file mode 100644 (file)
index 0000000..2bc6bd1
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file
+ */
+#include "lib.h"
+#include "buffer.h"
+#include "str.h"
+#include "iostream-pump.h"
+#include "iostream-proxy.h"
+#include <unistd.h>
+
+#undef iostream_proxy_set_completion_callback
+
+struct iostream_proxy {
+       struct iostream_pump *ltr;
+       struct iostream_pump *rtl;
+
+       unsigned int ref;
+
+       iostream_proxy_callback_t *callback;
+       void *context;
+};
+
+static
+void iostream_proxy_rtl_completion(bool success, struct iostream_proxy *proxy)
+{
+       proxy->callback(IOSTREAM_PROXY_SIDE_RIGHT, success, proxy->context);
+}
+
+static
+void iostream_proxy_ltr_completion(bool success, struct iostream_proxy *proxy)
+{
+       proxy->callback(IOSTREAM_PROXY_SIDE_LEFT, success, proxy->context);
+}
+
+struct iostream_proxy *
+iostream_proxy_create(struct istream *left_input, struct ostream *left_output,
+                     struct istream *right_input, struct ostream *right_output)
+{
+       i_assert(left_input != NULL &&
+                right_input != NULL &&
+                left_output != NULL &&
+                right_output != NULL);
+
+       /* create proxy */
+       struct iostream_proxy *proxy = i_new(struct iostream_proxy, 1);
+
+       proxy->ltr = iostream_pump_create(left_input, right_output);
+       proxy->rtl = iostream_pump_create(right_input, left_output);
+
+       iostream_pump_set_completion_callback(proxy->ltr, iostream_proxy_ltr_completion, proxy);
+       iostream_pump_set_completion_callback(proxy->rtl, iostream_proxy_rtl_completion, proxy);
+
+       proxy->ref = 1;
+
+       return proxy;
+}
+
+void iostream_proxy_start(struct iostream_proxy *proxy)
+{
+       i_assert(proxy != NULL);
+       i_assert(proxy->callback != NULL);
+
+       iostream_pump_start(proxy->rtl);
+       iostream_pump_start(proxy->ltr);
+}
+
+void iostream_proxy_set_completion_callback(struct iostream_proxy *proxy,
+                                           iostream_proxy_callback_t *callback,
+                                           void *context)
+{
+       i_assert(proxy != NULL);
+
+       proxy->callback = callback;
+       proxy->context = context;
+}
+
+struct istream *iostream_proxy_get_istream(struct iostream_proxy *proxy, enum iostream_proxy_side side)
+{
+       i_assert(proxy != NULL);
+
+       switch(side) {
+       case IOSTREAM_PROXY_SIDE_LEFT: return iostream_pump_get_input(proxy->ltr);
+       case IOSTREAM_PROXY_SIDE_RIGHT: return iostream_pump_get_input(proxy->rtl);
+       default: i_unreached();
+       }
+}
+
+struct ostream *iostream_proxy_get_ostream(struct iostream_proxy *proxy, enum iostream_proxy_side side)
+{
+       i_assert(proxy != NULL);
+
+       switch(side) {
+       case IOSTREAM_PROXY_SIDE_LEFT: return iostream_pump_get_output(proxy->ltr);
+       case IOSTREAM_PROXY_SIDE_RIGHT: return iostream_pump_get_output(proxy->rtl);
+       default: i_unreached();
+       }
+}
+
+void iostream_proxy_ref(struct iostream_proxy *proxy)
+{
+       i_assert(proxy != NULL && proxy->ref > 0);
+       proxy->ref++;
+}
+
+void iostream_proxy_unref(struct iostream_proxy **proxy_r)
+{
+       i_assert(proxy_r != NULL && *proxy_r != NULL);
+       struct iostream_proxy *proxy = *proxy_r;
+       *proxy_r = NULL;
+
+       i_assert(proxy->ref > 0);
+       if (--proxy->ref == 0) {
+               /* pumps will call stop internally
+                  if refcount drops to 0 */
+               iostream_pump_unref(&proxy->ltr);
+               iostream_pump_unref(&proxy->rtl);
+               i_free(proxy);
+       }
+}
+
+void iostream_proxy_stop(struct iostream_proxy *proxy)
+{
+       i_assert(proxy != NULL);
+       iostream_pump_stop(proxy->ltr);
+       iostream_pump_stop(proxy->rtl);
+}
+
+void iostream_proxy_switch_ioloop(struct iostream_proxy *proxy)
+{
+       i_assert(proxy != NULL);
+       iostream_pump_switch_ioloop(proxy->ltr);
+       iostream_pump_switch_ioloop(proxy->rtl);
+}
diff --git a/src/lib/iostream-proxy.h b/src/lib/iostream-proxy.h
new file mode 100644 (file)
index 0000000..8744292
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file
+ */
+#ifndef IOSTREAM_PROXY_H
+#define IOSTREAM_PROXY_H 1
+
+/**
+
+iostream-proxy
+=============
+
+This construct will proxy data between two pairs of
+istream and ostream. Data is proxied from left to right
+and right to left using iostream-pump.
+
+The proxy requires you to provide completion callback. The
+completion callback is called with success parameter to
+indicate whether it ended with error.
+
+The istreams and ostreams are reffed on creation and unreffed
+on unref.
+
+**/
+
+struct istream;
+struct ostream;
+struct iostream_proxy;
+
+enum iostream_proxy_side {
+       IOSTREAM_PROXY_SIDE_LEFT,
+       IOSTREAM_PROXY_SIDE_RIGHT
+};
+
+typedef void iostream_proxy_callback_t(enum iostream_proxy_side side,
+                                      bool success,
+                                      void *context);
+
+struct iostream_proxy *
+iostream_proxy_create(struct istream *left_input, struct ostream *left_output,
+                     struct istream *right_input, struct ostream *right_output);
+
+struct istream *iostream_proxy_get_istream(struct iostream_proxy *proxy, enum iostream_proxy_side);
+struct ostream *iostream_proxy_get_ostream(struct iostream_proxy *proxy, enum iostream_proxy_side);
+
+void iostream_proxy_start(struct iostream_proxy *proxy);
+void iostream_proxy_stop(struct iostream_proxy *proxy);
+
+void iostream_proxy_set_completion_callback(struct iostream_proxy *proxy,
+                                      iostream_proxy_callback_t *callback, void *context);
+#define iostream_proxy_set_completion_callback(proxy, callback, context) \
+       iostream_proxy_set_completion_callback(proxy, (iostream_proxy_callback_t *)callback, context + \
+               CALLBACK_TYPECHECK(callback, void (*)(enum iostream_proxy_side side, bool, typeof(context))))
+
+void iostream_proxy_ref(struct iostream_proxy *proxy);
+void iostream_proxy_unref(struct iostream_proxy **proxy_r);
+
+void iostream_proxy_switch_ioloop(struct iostream_proxy *proxy);
+
+#endif