Skip to content

Commit

Permalink
imapc: Fix infinite reconnection when server keeps sending corrupted …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
sirainen committed May 19, 2017
1 parent 5e1694a commit ec7aec9
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 23 deletions.
12 changes: 3 additions & 9 deletions src/lib-imap-client/imapc-client.c
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/lib-imap-client/imapc-client.h
Expand Up @@ -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);
Expand Down
20 changes: 12 additions & 8 deletions src/lib-imap-client/imapc-connection.c
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/lib-imap-client/imapc-connection.h
Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions src/lib-storage/index/imapc/imapc-mailbox.c
Expand Up @@ -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);

Expand All @@ -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 *
Expand Down
6 changes: 3 additions & 3 deletions src/lib-storage/index/imapc/imapc-storage.c
Expand Up @@ -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);
}
Expand Down

0 comments on commit ec7aec9

Please sign in to comment.