changeset 22051:a70a741f0ae8

imapc: Fix infinite reconnection when server keeps sending corrupted state When corrupted state was found, imapc_client_mailbox_reconnect() is called to reconnect. This call skipped the normal "is it safe to reconnect?" checks causing potentially infinite reconnections.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 18 May 2017 19:42:03 +0300
parents 37e6375d1978
children c641778fda28
files src/lib-imap-client/imapc-client.c src/lib-imap-client/imapc-client.h src/lib-imap-client/imapc-connection.c src/lib-imap-client/imapc-connection.h src/lib-storage/index/imapc/imapc-mailbox.c src/lib-storage/index/imapc/imapc-storage.c
diffstat 6 files changed, 26 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap-client/imapc-client.c	Thu May 18 19:40:04 2017 +0300
+++ b/src/lib-imap-client/imapc-client.c	Thu May 18 19:42:03 2017 +0300
@@ -404,18 +404,12 @@
 	return box->reopen_callback != NULL && box->reconnect_ok;
 }
 
-void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box)
+void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box,
+				    const char *errmsg)
 {
 	i_assert(!box->reconnecting);
 
-	box->reconnecting = TRUE;
-	/* if we fail again, avoid reconnecting immediately. if the server is
-	   broken we could just get into an infinitely failing reconnection
-	   loop. */
-	box->reconnect_ok = FALSE;
-
-	imapc_connection_disconnect_full(box->conn, TRUE);
-	imapc_connection_connect(box->conn);
+	imapc_connection_try_reconnect(box->conn, errmsg, 0);
 }
 
 void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
--- a/src/lib-imap-client/imapc-client.h	Thu May 18 19:40:04 2017 +0300
+++ b/src/lib-imap-client/imapc-client.h	Thu May 18 19:42:03 2017 +0300
@@ -221,7 +221,8 @@
 					void *context);
 void imapc_client_mailbox_close(struct imapc_client_mailbox **box);
 bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box);
-void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box);
+void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box,
+				    const char *errmsg);
 struct imapc_command *
 imapc_client_mailbox_cmd(struct imapc_client_mailbox *box,
 			 imapc_command_callback_t *callback, void *context);
--- a/src/lib-imap-client/imapc-connection.c	Thu May 18 19:40:04 2017 +0300
+++ b/src/lib-imap-client/imapc-connection.c	Thu May 18 19:42:03 2017 +0300
@@ -508,17 +508,21 @@
 	conn->reconnect_ok = FALSE;
 	conn->reconnect_waiting = FALSE;
 
-	if (conn->selected_box != NULL)
-		imapc_client_mailbox_reconnect(conn->selected_box);
-	else {
-		imapc_connection_disconnect_full(conn, TRUE);
-		imapc_connection_connect(conn);
+	if (conn->selected_box != NULL) {
+		i_assert(!conn->selected_box->reconnecting);
+		conn->selected_box->reconnecting = TRUE;
+		/* if we fail again, avoid reconnecting immediately. if the
+		   server is broken we could just get into an infinitely
+		   failing reconnection loop. */
+		conn->selected_box->reconnect_ok = FALSE;
 	}
+	imapc_connection_disconnect_full(conn, TRUE);
+	imapc_connection_connect(conn);
 }
 
-static void
-imapc_connection_try_reconnect(struct imapc_connection *conn,
-			       const char *errstr, unsigned int delay_msecs)
+void imapc_connection_try_reconnect(struct imapc_connection *conn,
+				    const char *errstr,
+				    unsigned int delay_msecs)
 {
 	if (conn->prev_connect_idx + 1 < conn->ips_count) {
 		conn->reconnect_ok = TRUE;
--- a/src/lib-imap-client/imapc-connection.h	Thu May 18 19:40:04 2017 +0300
+++ b/src/lib-imap-client/imapc-connection.h	Thu May 18 19:42:03 2017 +0300
@@ -33,6 +33,9 @@
 void imapc_connection_disconnect(struct imapc_connection *conn);
 void imapc_connection_disconnect_full(struct imapc_connection *conn,
 				      bool reconnecting);
+void imapc_connection_try_reconnect(struct imapc_connection *conn,
+				    const char *errstr,
+				    unsigned int delay_msecs);
 void imapc_connection_abort_commands(struct imapc_connection *conn,
 				     struct imapc_client_mailbox *only_box,
 				     bool keep_retriable) ATTR_NULL(2);
--- a/src/lib-storage/index/imapc/imapc-mailbox.c	Thu May 18 19:40:04 2017 +0300
+++ b/src/lib-storage/index/imapc/imapc-mailbox.c	Thu May 18 19:42:03 2017 +0300
@@ -17,10 +17,11 @@
 void imapc_mailbox_set_corrupted(struct imapc_mailbox *mbox,
 				 const char *reason, ...)
 {
+	const char *errmsg;
 	va_list va;
 
 	va_start(va, reason);
-	i_error("imapc: Mailbox '%s' state corrupted: %s",
+	errmsg = t_strdup_printf("Mailbox '%s' state corrupted: %s",
 		mbox->box.name, t_strdup_vprintf(reason, va));
 	va_end(va);
 
@@ -34,7 +35,7 @@
 		/* maybe the remote server is buggy and has become confused.
 		   try reconnecting. */
 	}
-	imapc_client_mailbox_reconnect(mbox->client_box);
+	imapc_client_mailbox_reconnect(mbox->client_box, errmsg);
 }
 
 static struct mail_index_view *
--- a/src/lib-storage/index/imapc/imapc-storage.c	Thu May 18 19:40:04 2017 +0300
+++ b/src/lib-storage/index/imapc/imapc-storage.c	Thu May 18 19:42:03 2017 +0300
@@ -550,10 +550,10 @@
 	mbox->storage->reopen_count--;
 	mbox->selecting = FALSE;
 	if (reply->state != IMAPC_COMMAND_STATE_OK) {
-		mail_storage_set_critical(mbox->box.storage,
-			"imapc: Reopening mailbox '%s' failed: %s",
+		const char *errmsg = t_strdup_printf(
+			"Reopening mailbox '%s' failed: %s",
 			mbox->box.name, reply->text_full);
-		imapc_client_mailbox_reconnect(mbox->client_box);
+		imapc_client_mailbox_reconnect(mbox->client_box, errmsg);
 	}
 	imapc_client_stop(mbox->storage->client->client);
 }