1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file
2  */
3 #ifndef IOSTREAM_PROXY_H
4 #define IOSTREAM_PROXY_H 1
5 
6 /**
7 
8 iostream-proxy
9 =============
10 
11 This construct will proxy data between two pairs of
12 istream and ostream. Data is proxied from left to right
13 and right to left using iostream-pump.
14 
15 The proxy requires you to provide completion callback. The
16 completion callback is called with success parameter to
17 indicate whether it ended with error.
18 
19 The istreams and ostreams are reffed on creation and unreffed
20 on unref.
21 
22 **/
23 
24 struct istream;
25 struct ostream;
26 struct iostream_proxy;
27 
28 enum iostream_proxy_side {
29 	/* Input is coming from left side's istream and is proxied to
30 	   right side's ostream. */
31 	IOSTREAM_PROXY_SIDE_LEFT,
32 	/* Input is coming from right side's istream and is proxied to
33 	   left side's ostream. */
34 	IOSTREAM_PROXY_SIDE_RIGHT
35 };
36 
37 enum iostream_proxy_status {
38 	/* proxy succeeded - EOF received from istream and all output was
39 	   written successfully to ostream. */
40 	IOSTREAM_PROXY_STATUS_INPUT_EOF,
41 	/* proxy failed - istream returned an error */
42 	IOSTREAM_PROXY_STATUS_INPUT_ERROR,
43 	/* proxy failed - other side's ostream returned an error */
44 	IOSTREAM_PROXY_STATUS_OTHER_SIDE_OUTPUT_ERROR,
45 };
46 
47 /* The callback maybe be called once or twice. Usually the first call should
48    destroy the proxy, but it's possible for it to just wait for the other
49    direction of the proxy to finish as well and call the callback.
50 
51    Note that the sides mean which side is the reader side. If the failure is in
52    ostream, it's the other side's ostream that failed. So for example if
53    side=left, the write failed to the right side's ostream.
54 
55    The callback is called when the proxy succeeds or fails due to
56    iostreams. (It's not called if proxy is destroyed.) */
57 typedef void iostream_proxy_callback_t(enum iostream_proxy_side side,
58 				       enum iostream_proxy_status status,
59 				       void *context);
60 
61 struct iostream_proxy *
62 iostream_proxy_create(struct istream *left_input, struct ostream *left_output,
63 		      struct istream *right_input, struct ostream *right_output);
64 
65 struct istream *iostream_proxy_get_istream(struct iostream_proxy *proxy, enum iostream_proxy_side);
66 struct ostream *iostream_proxy_get_ostream(struct iostream_proxy *proxy, enum iostream_proxy_side);
67 
68 void iostream_proxy_start(struct iostream_proxy *proxy);
69 void iostream_proxy_stop(struct iostream_proxy *proxy);
70 
71 /* See iostream_pump_is_waiting_output() */
72 bool iostream_proxy_is_waiting_output(struct iostream_proxy *proxy,
73 				      enum iostream_proxy_side side);
74 
75 void iostream_proxy_set_completion_callback(struct iostream_proxy *proxy,
76 				       iostream_proxy_callback_t *callback, void *context);
77 #define iostream_proxy_set_completion_callback(proxy, callback, context) \
78 	iostream_proxy_set_completion_callback(proxy, (iostream_proxy_callback_t *)callback, \
79 		TRUE ? context : \
80 		CALLBACK_TYPECHECK(callback, void (*)(enum iostream_proxy_side side, enum iostream_proxy_status, typeof(context))))
81 
82 void iostream_proxy_ref(struct iostream_proxy *proxy);
83 void iostream_proxy_unref(struct iostream_proxy **proxy_r);
84 
85 void iostream_proxy_switch_ioloop(struct iostream_proxy *proxy);
86 
87 #endif
88