Mercurial > dovecot > core-2.2
changeset 21888:dffc319d8397
lib-imap-client: Fix reconnection
This patch fixes reconnections to actually consider
all IP addresses first and then delay for interval and
retry at most retry count times.
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Fri, 31 Mar 2017 10:12:58 +0300 |
parents | 960920ff9975 |
children | 35f589fd7a93 |
files | src/lib-imap-client/imapc-connection.c |
diffstat | 1 files changed, 36 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-imap-client/imapc-connection.c Fri Mar 31 11:01:15 2017 +0300 +++ b/src/lib-imap-client/imapc-connection.c Fri Mar 31 10:12:58 2017 +0300 @@ -98,6 +98,7 @@ unsigned int cur_tag; uint32_t cur_num; time_t last_connect; + unsigned int reconnect_count; struct imapc_client_mailbox *selecting_box, *selected_box; enum imapc_connection_state state; @@ -181,7 +182,7 @@ conn->name = i_strdup_printf("%s:%u", client->set.host, client->set.port); conn->literal.fd = -1; - conn->reconnect_ok = TRUE; + conn->reconnect_ok = (client->set.connect_retry_count>0); i_array_init(&conn->cmd_send_queue, 8); i_array_init(&conn->cmd_wait_list, 32); i_array_init(&conn->literal_files, 4); @@ -452,6 +453,10 @@ imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED); imapc_connection_abort_commands(conn, NULL, reconnecting); + + if (!reconnecting) { + imapc_client_try_stop(conn->client); + } } void imapc_connection_set_no_reconnect(struct imapc_connection *conn) @@ -503,16 +508,25 @@ 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; + imapc_connection_disconnect_full(conn, TRUE); + imapc_connection_connect(conn, NULL, NULL); + return; + } + if (!imapc_connection_can_reconnect(conn)) { i_error("imapc(%s): %s - disconnecting", conn->name, errstr); imapc_connection_disconnect(conn); } else { - i_warning("imapc(%s): %s - reconnecting", conn->name, errstr); + conn->reconnecting = TRUE; + i_warning("imapc(%s): %s - reconnecting (delay %u)", conn->name, errstr, delay_msecs); if (delay_msecs == 0) imapc_connection_reconnect(conn); else { imapc_connection_disconnect_full(conn, TRUE); conn->to = timeout_add(delay_msecs, imapc_connection_reconnect, conn); + conn->reconnect_count++; } } } @@ -1675,13 +1689,13 @@ static void imapc_connection_connect_next_ip(struct imapc_connection *conn) { - const struct ip_addr *ip; + const struct ip_addr *ip = NULL; unsigned int i; int fd; i_assert(conn->client->set.max_idle_time > 0); - for (i = 0;;) { + for (i = 0; i<conn->ips_count;) { conn->prev_connect_idx = (conn->prev_connect_idx+1) % conn->ips_count; ip = &conn->ips[conn->prev_connect_idx]; fd = net_connect_ip(ip, conn->client->set.port, NULL); @@ -1693,11 +1707,15 @@ before failing completely. */ i_error("net_connect_ip(%s:%u) failed: %m", net_ip2addr(ip), conn->client->set.port); - if (++i == conn->ips_count) { - imapc_connection_set_disconnected(conn); + if (conn->prev_connect_idx+1 == conn->ips_count) { + imapc_connection_try_reconnect(conn, "No more IP address(es) to try", + IMAPC_CONNECT_RETRY_WAIT_MSECS); return; } } + + i_assert(ip != NULL); + conn->fd = fd; conn->input = conn->raw_input = i_stream_create_fd(fd, conn->client->set.max_line_length, FALSE); @@ -1761,8 +1779,10 @@ return; } i_assert(conn->login_callback == NULL || conn->reconnecting); - conn->login_callback = login_callback; - conn->login_context = login_context; + if (!conn->reconnecting) { + conn->login_callback = login_callback; + conn->login_context = login_context; + } conn->reconnecting = FALSE; /* if we get disconnected before we've finished all the pending commands, don't reconnect */ @@ -1772,8 +1792,15 @@ imapc_connection_input_reset(conn); if (!conn->reconnect_ok && - conn->last_connect + IMAPC_RECONNECT_MIN_RETRY_SECS >= ioloop_time) { + conn->last_connect + conn->client->set.connect_retry_interval_secs >= ioloop_time) { + if (conn->to != NULL) + timeout_remove(&conn->to); + conn->reconnecting = TRUE; imapc_connection_set_disconnected(conn); + /* don't wait longer than necessary, the +1 is to avoid ending here again */ + unsigned int delay_msecs = + ((conn->last_connect + conn->client->set.connect_retry_interval_secs) - ioloop_time + 1) * 1000; + conn->to = timeout_add(delay_msecs, imapc_connection_reconnect, conn); return; } conn->last_connect = ioloop_time;