bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi */
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#include "lib.h"
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#include "buffer.h"
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#include "str.h"
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#include "iostream-pump.h"
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#include "iostream-proxy.h"
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#include <unistd.h>
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi#undef iostream_proxy_set_completion_callback
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomistruct iostream_proxy {
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi struct iostream_pump *ltr;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi struct iostream_pump *rtl;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi unsigned int ref;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_proxy_callback_t *callback;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi void *context;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi};
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainenstatic void
987c15a5980f53225e60f79325c14cb2acddaabbTimo Siraineniostream_proxy_completion(struct iostream_proxy *proxy,
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen enum iostream_proxy_side side,
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen enum iostream_pump_status pump_status)
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen{
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen enum iostream_proxy_status status;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen switch (pump_status) {
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen case IOSTREAM_PUMP_STATUS_INPUT_EOF:
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen status = IOSTREAM_PROXY_STATUS_INPUT_EOF;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen break;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen case IOSTREAM_PUMP_STATUS_INPUT_ERROR:
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen status = IOSTREAM_PROXY_STATUS_INPUT_ERROR;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen break;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen case IOSTREAM_PUMP_STATUS_OUTPUT_ERROR:
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen status = IOSTREAM_PROXY_STATUS_OTHER_SIDE_OUTPUT_ERROR;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen break;
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen default:
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen i_unreached();
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen }
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen proxy->callback(side, status, proxy->context);
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen}
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomistatic
39435f00a35a276d329283179b3e7e0351482939Timo Sirainenvoid iostream_proxy_rtl_completion(enum iostream_pump_status status,
39435f00a35a276d329283179b3e7e0351482939Timo Sirainen struct iostream_proxy *proxy)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen iostream_proxy_completion(proxy, IOSTREAM_PROXY_SIDE_RIGHT, status);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomistatic
39435f00a35a276d329283179b3e7e0351482939Timo Sirainenvoid iostream_proxy_ltr_completion(enum iostream_pump_status status,
39435f00a35a276d329283179b3e7e0351482939Timo Sirainen struct iostream_proxy *proxy)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
987c15a5980f53225e60f79325c14cb2acddaabbTimo Sirainen iostream_proxy_completion(proxy, IOSTREAM_PROXY_SIDE_LEFT, status);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomistruct iostream_proxy *
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomiiostream_proxy_create(struct istream *left_input, struct ostream *left_output,
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi struct istream *right_input, struct ostream *right_output)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(left_input != NULL &&
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi right_input != NULL &&
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi left_output != NULL &&
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi right_output != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi /* create proxy */
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi struct iostream_proxy *proxy = i_new(struct iostream_proxy, 1);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi proxy->ltr = iostream_pump_create(left_input, right_output);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi proxy->rtl = iostream_pump_create(right_input, left_output);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_set_completion_callback(proxy->ltr, iostream_proxy_ltr_completion, proxy);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_set_completion_callback(proxy->rtl, iostream_proxy_rtl_completion, proxy);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi proxy->ref = 1;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi return proxy;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomivoid iostream_proxy_start(struct iostream_proxy *proxy)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy->callback != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_start(proxy->rtl);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_start(proxy->ltr);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomivoid iostream_proxy_set_completion_callback(struct iostream_proxy *proxy,
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_proxy_callback_t *callback,
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi void *context)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi proxy->callback = callback;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi proxy->context = context;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomistruct istream *iostream_proxy_get_istream(struct iostream_proxy *proxy, enum iostream_proxy_side side)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi switch(side) {
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi case IOSTREAM_PROXY_SIDE_LEFT: return iostream_pump_get_input(proxy->ltr);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi case IOSTREAM_PROXY_SIDE_RIGHT: return iostream_pump_get_input(proxy->rtl);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi default: i_unreached();
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi }
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomistruct ostream *iostream_proxy_get_ostream(struct iostream_proxy *proxy, enum iostream_proxy_side side)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi switch(side) {
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi case IOSTREAM_PROXY_SIDE_LEFT: return iostream_pump_get_output(proxy->ltr);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi case IOSTREAM_PROXY_SIDE_RIGHT: return iostream_pump_get_output(proxy->rtl);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi default: i_unreached();
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi }
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomivoid iostream_proxy_ref(struct iostream_proxy *proxy)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL && proxy->ref > 0);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi proxy->ref++;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomivoid iostream_proxy_unref(struct iostream_proxy **proxy_r)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
ba4cff31455b6dcb89c5d12cd4479b4da55c8596Josef 'Jeff' Sipek struct iostream_proxy *proxy;
ba4cff31455b6dcb89c5d12cd4479b4da55c8596Josef 'Jeff' Sipek
ba4cff31455b6dcb89c5d12cd4479b4da55c8596Josef 'Jeff' Sipek if (proxy_r == NULL || *proxy_r == NULL)
ba4cff31455b6dcb89c5d12cd4479b4da55c8596Josef 'Jeff' Sipek return;
ba4cff31455b6dcb89c5d12cd4479b4da55c8596Josef 'Jeff' Sipek
ba4cff31455b6dcb89c5d12cd4479b4da55c8596Josef 'Jeff' Sipek proxy = *proxy_r;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi *proxy_r = NULL;
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy->ref > 0);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi if (--proxy->ref == 0) {
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi /* pumps will call stop internally
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi if refcount drops to 0 */
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_unref(&proxy->ltr);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_unref(&proxy->rtl);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_free(proxy);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi }
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomivoid iostream_proxy_stop(struct iostream_proxy *proxy)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_stop(proxy->ltr);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_stop(proxy->rtl);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainenbool iostream_proxy_is_waiting_output(struct iostream_proxy *proxy,
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen enum iostream_proxy_side side)
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen{
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen switch (side) {
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen case IOSTREAM_PROXY_SIDE_LEFT:
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen return iostream_pump_is_waiting_output(proxy->ltr);
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen case IOSTREAM_PROXY_SIDE_RIGHT:
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen return iostream_pump_is_waiting_output(proxy->rtl);
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen }
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen i_unreached();
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen}
6ce52edd3de46bdf565ee71f6112a9e7a6090031Timo Sirainen
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomivoid iostream_proxy_switch_ioloop(struct iostream_proxy *proxy)
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi{
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi i_assert(proxy != NULL);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_switch_ioloop(proxy->ltr);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi iostream_pump_switch_ioloop(proxy->rtl);
26e7bc65f13482709c0f6216650582e7705eeeffAki Tuomi}