changeset 10340:26eb1b52a23f HEAD

lmtp proxy: If remote hangs without replying to end-of-DATA dot, don't crash.
author Timo Sirainen <tss@iki.fi>
date Tue, 17 Nov 2009 13:16:11 -0500
parents 278d4da53141
children d784be144b4d
files src/lmtp/lmtp-proxy.c
diffstat 1 files changed, 57 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/lmtp/lmtp-proxy.c	Mon Nov 16 20:00:33 2009 -0500
+++ b/src/lmtp/lmtp-proxy.c	Tue Nov 17 13:16:11 2009 -0500
@@ -293,28 +293,71 @@
 	return 0;
 }
 
-static void lmtp_proxy_output_timeout(struct lmtp_proxy *proxy)
+static size_t lmtp_proxy_find_max_data_input_size(struct lmtp_proxy *proxy)
 {
-	struct lmtp_proxy_connection *const *conns, *max_conn = NULL;
+	struct lmtp_proxy_connection *const *conns;
 	unsigned int i, count;
 	size_t size, max_size = 0;
 
+	conns = array_get(&proxy->connections, &count);
+	for (i = 0; i < count; i++) {
+		(void)i_stream_get_data(conns[i]->data_input, &size);
+		if (max_size < size)
+			max_size = size;
+	}
+	return max_size;
+}
+
+static bool lmtp_proxy_disconnect_hanging_output(struct lmtp_proxy *proxy)
+{
+	struct lmtp_proxy_connection *const *conns;
+	unsigned int i, count;
+	size_t size, max_size;
+
+	max_size = lmtp_proxy_find_max_data_input_size(proxy);
+	if (max_size == 0)
+		return FALSE;
+
+	/* disconnect all connections that are keeping us from reading
+	   more input. */
+	conns = array_get(&proxy->connections, &count);
+	for (i = 0; i < count; i++) {
+		(void)i_stream_get_data(conns[i]->data_input, &size);
+		if (size == max_size) {
+			lmtp_proxy_conn_deinit(conns[i],
+					       ERRSTR_TEMP_REMOTE_FAILURE
+					       " (DATA output timeout)");
+		}
+	}
+	return TRUE;
+}
+
+static void lmtp_proxy_disconnect_unfinished(struct lmtp_proxy *proxy)
+{
+	struct lmtp_proxy_connection *const *conns;
+	unsigned int i, count;
+
+	conns = array_get(&proxy->connections, &count);
+	for (i = 0; i < count; i++) {
+		lmtp_client_fail(conns[i]->client, ERRSTR_TEMP_REMOTE_FAILURE
+				 " (DATA input timeout)");
+	}
+}
+
+static void lmtp_proxy_output_timeout(struct lmtp_proxy *proxy)
+{
 	timeout_remove(&proxy->to);
 
 	/* drop the connection with the most unread data */
-	conns = array_get(&proxy->connections, &count);
-	for (i = 0; i < count; i++) {
-		(void)i_stream_get_data(conns[i]->data_input, &size);
-		if (max_size < size) {
-			max_size = size;
-			max_conn = conns[i];
-		}
+	if (lmtp_proxy_disconnect_hanging_output(proxy))
+		lmtp_proxy_data_input(proxy);
+	else {
+		/* no such connection, so we've already sent everything but
+		   some servers aren't replying to us. disconnect all of
+		   them. */
+		lmtp_proxy_disconnect_unfinished(proxy);
+		lmtp_proxy_try_finish(proxy);
 	}
-	i_assert(max_conn != NULL);
-
-	lmtp_proxy_conn_deinit(max_conn, ERRSTR_TEMP_REMOTE_FAILURE
-			       " (timeout)");
-	lmtp_proxy_data_input(proxy);
 }
 
 static void lmtp_proxy_wait_for_output(struct lmtp_proxy *proxy)