]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Fix infinite reconnection when server keeps sending corrupted state
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 18 May 2017 16:42:03 +0000 (19:42 +0300)
committerGitLab <gitlab@git.dovecot.net>
Fri, 19 May 2017 07:13:55 +0000 (10:13 +0300)
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.

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

index 467b16fe770536fe01a788b448e7f9275cf34101..c961d2a66c5e858a5a435297f6a014f08cf85f81 100644 (file)
@@ -404,18 +404,12 @@ bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box)
        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)
index 03afe4f752a6a330c0c2c50db7838e3f24bc5469..86709d6661ab124468329e7ac292257d303334f0 100644 (file)
@@ -221,7 +221,8 @@ void imapc_client_mailbox_set_reopen_cb(struct imapc_client_mailbox *box,
                                        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);
index 48a2a6e159ed3e9dd7d8efb65aeb3891124b6614..db31358dab17ee9ae10e57168a053e058b38f815 100644 (file)
@@ -508,17 +508,21 @@ static void imapc_connection_reconnect(struct imapc_connection *conn)
        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;
index 5afaca7348b10d4e206881406a5d37f263d02b8f..b22e4369fe0fff9a37a134dbb56decb5ffec9be1 100644 (file)
@@ -33,6 +33,9 @@ void imapc_connection_set_no_reconnect(struct imapc_connection *conn);
 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);
index 1c76ce702b35ccf583483f6ca9dcb25be627ff87..2100ab0f548b2475e6d2b267f673f3fcd0ee2b12 100644 (file)
 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 @@ void imapc_mailbox_set_corrupted(struct imapc_mailbox *mbox,
                /* 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 *
index 634c6c2ef24ab65f0e47dc5a308bf039840de6ea..fb7d94fddd2e7cc245723c8091f081a70986a839 100644 (file)
@@ -550,10 +550,10 @@ imapc_mailbox_reopen_callback(const struct imapc_command_reply *reply,
        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);
 }