changeset 19752:d9a6a40ecf15

login-proxy: Preserve client's istream even after login. This eventually allows things like using lib-ssl-iostream, moving IMAP COMPRESS handling to login process, etc.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 10 Feb 2016 22:02:50 +0200
parents 1e0cfc3dc89a
children 55511e55540d
files src/login-common/login-proxy.c
diffstat 1 files changed, 25 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/login-common/login-proxy.c	Wed Feb 10 22:02:15 2016 +0200
+++ b/src/login-common/login-proxy.c	Wed Feb 10 22:02:50 2016 +0200
@@ -35,7 +35,7 @@
 	struct client *client;
 	int client_fd, server_fd;
 	struct io *client_io, *server_io;
-	struct istream *server_input;
+	struct istream *client_input, *server_input;
 	struct ostream *client_output, *server_output;
 	struct ssl_proxy *ssl_server_proxy;
 	time_t last_io;
@@ -155,8 +155,9 @@
 
 static void proxy_client_input(struct login_proxy *proxy)
 {
-	unsigned char buf[OUTBUF_THRESHOLD];
-	ssize_t ret, ret2;
+	const unsigned char *data;
+	size_t size;
+	ssize_t ret;
 
 	proxy->last_io = ioloop_time;
 	if (o_stream_get_buffer_used_size(proxy->server_output) >
@@ -167,26 +168,30 @@
 		return;
 	}
 
-	ret = net_receive(proxy->client_fd, buf, sizeof(buf));
-	if (ret < 0) {
-		login_proxy_free_errno(&proxy, errno, FALSE);
+	if (i_stream_read_data(proxy->client_input, &data, &size, 0) < 0) {
+		const char *errstr = i_stream_get_error(proxy->client_input);
+		login_proxy_free_errstr(&proxy, errstr, FALSE);
 		return;
 	}
 	o_stream_cork(proxy->server_output);
-	ret2 = o_stream_send(proxy->server_output, buf, ret);
+	ret = o_stream_send(proxy->server_output, data, size);
 	o_stream_uncork(proxy->server_output);
-	if (ret2 != ret)
+	if (ret != (ssize_t)size)
 		login_proxy_free_ostream(&proxy, proxy->server_output, TRUE);
+	else
+		i_stream_skip(proxy->client_input, ret);
 }
 
 static void proxy_client_disconnected_input(struct login_proxy *proxy)
 {
-	unsigned char buf[OUTBUF_THRESHOLD];
-
 	/* we're already disconnected from server. either wait for
 	   disconnection timeout or for client to disconnect itself. */
-	if (net_receive(proxy->client_fd, buf, sizeof(buf)) < 0)
+	if (i_stream_read(proxy->client_input) < 0)
 		login_proxy_free_final(proxy);
+	else {
+		i_stream_skip(proxy->client_input,
+			      i_stream_get_data_size(proxy->client_input));
+	}
 }
 
 static int server_output(struct login_proxy *proxy)
@@ -489,6 +494,8 @@
 
 	if (proxy->client_io != NULL)
 		io_remove(&proxy->client_io);
+	if (proxy->client_input != NULL)
+		i_stream_destroy(&proxy->client_input);
 	if (proxy->client_output != NULL)
 		o_stream_destroy(&proxy->client_output);
 	if (proxy->client_fd != -1)
@@ -591,6 +598,7 @@
 			io_remove(&proxy->client_io);
 	} else {
 		i_assert(proxy->client_io == NULL);
+		i_assert(proxy->client_input == NULL);
 		i_assert(proxy->client_output == NULL);
 		i_assert(proxy->client_fd == -1);
 
@@ -681,20 +689,24 @@
 	size_t size;
 
 	i_assert(proxy->client_fd == -1);
+	i_assert(proxy->server_input != NULL);
 	i_assert(proxy->server_output != NULL);
 
 	if (proxy->to != NULL)
 		timeout_remove(&proxy->to);
 
 	proxy->client_fd = i_stream_get_fd(client->input);
+	proxy->client_input = client->input;
 	proxy->client_output = client->output;
 
+	i_stream_set_persistent_buffers(client->input, FALSE);
 	o_stream_set_max_buffer_size(client->output, (size_t)-1);
 	o_stream_set_flush_callback(client->output, proxy_client_output, proxy);
+	client->input = NULL;
 	client->output = NULL;
 
-	/* send all pending client input to proxy and get rid of the stream */
-	data = i_stream_get_data(client->input, &size);
+	/* send all pending client input to proxy */
+	data = i_stream_get_data(proxy->client_input, &size);
 	if (size != 0)
 		o_stream_nsend(proxy->server_output, data, size);