]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
login-proxy: Support reconnecting on most types of failures
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sun, 3 May 2020 19:24:55 +0000 (22:24 +0300)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Mon, 25 May 2020 08:38:55 +0000 (08:38 +0000)
src/login-common/client-common-auth.c
src/login-common/login-proxy.c
src/login-common/login-proxy.h

index 1b4b059703be8ca2a908072b64d147fa8a3402af..c85ad8089c1e7577d5eec17f1e213cd1cce6d037 100644 (file)
@@ -314,8 +314,6 @@ static void client_proxy_failed(struct client *client, bool send_line)
        if (send_line)
                client_proxy_error(client, PROXY_FAILURE_MSG);
 
-       if (client->proxy_sasl_client != NULL)
-               dsasl_client_free(&client->proxy_sasl_client);
        login_proxy_free(&client->login_proxy);
        proxy_free_password(client);
        i_free_and_null(client->proxy_user);
@@ -369,8 +367,15 @@ static void proxy_input(struct client *client)
 static void proxy_failed(struct client *client,
                         enum login_proxy_failure_type type,
                         const char *reason ATTR_UNUSED,
-                        bool reconnecting ATTR_UNUSED)
+                        bool reconnecting)
 {
+       if (client->proxy_sasl_client != NULL)
+               dsasl_client_free(&client->proxy_sasl_client);
+       if (reconnecting) {
+               client->v.proxy_reset(client);
+               return;
+       }
+
        switch (type) {
        case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
        case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
index e0ac8f3d122fdf548b761a295637265ae7e3f3d1..185a331fa604c95c35de7592e8e149b308233903 100644 (file)
@@ -74,6 +74,7 @@ struct login_proxy {
        bool detached:1;
        bool destroying:1;
        bool delayed_disconnect:1;
+       bool disable_reconnect:1;
        bool num_waiting_connections_updated:1;
 };
 
@@ -189,8 +190,7 @@ void login_proxy_append_success_log_info(struct login_proxy *proxy,
 }
 
 static void
-proxy_connect_error_append(struct login_proxy *proxy, bool reconnect,
-                          string_t *str)
+proxy_connect_error_append(struct login_proxy *proxy, string_t *str)
 {
        struct ip_addr local_ip;
        in_port_t local_port;
@@ -217,10 +217,6 @@ proxy_connect_error_append(struct login_proxy *proxy, bool reconnect,
        }
 
        str_append_c(str, ')');
-       if (reconnect) {
-               str_printfa(str, " - reconnecting (attempt #%d)",
-                           proxy->reconnect_count);
-       }
 }
 
 static void proxy_reconnect_timeout(struct login_proxy *proxy)
@@ -235,6 +231,8 @@ static bool proxy_try_reconnect(struct login_proxy *proxy)
 
        if (proxy->reconnect_count >= proxy->client->set->login_proxy_max_reconnects)
                return FALSE;
+       if (proxy->disable_reconnect)
+               return FALSE;
 
        since_started_msecs =
                timeval_diff_msecs(&ioloop_timeval, &proxy->created);
@@ -254,20 +252,13 @@ static bool proxy_try_reconnect(struct login_proxy *proxy)
 static bool proxy_connect_failed(struct login_proxy *proxy)
 {
        string_t *str = t_str_new(128);
-       bool reconnect;
 
        if (!proxy->connected)
                proxy_fail_connect(proxy);
-       reconnect = proxy_try_reconnect(proxy);
-       proxy_connect_error_append(proxy, reconnect, str);
-       if (reconnect)
-               e_debug(proxy->event, "%s", str_c(str));
-       else {
-               login_proxy_failed(proxy, proxy->event,
-                                  LOGIN_PROXY_FAILURE_TYPE_CONNECT,
-                                  str_c(str));
-       }
-       return reconnect;
+       proxy_connect_error_append(proxy, str);
+       return login_proxy_failed(proxy, proxy->event,
+                                 LOGIN_PROXY_FAILURE_TYPE_CONNECT,
+                                 str_c(str));
 }
 
 static void proxy_wait_connect(struct login_proxy *proxy)
@@ -327,6 +318,7 @@ static int login_proxy_connect(struct login_proxy *proxy)
            rec->last_failure.tv_sec - rec->last_success.tv_sec > PROXY_IMMEDIATE_FAILURE_SECS &&
            rec->num_waiting_connections > 1) {
                /* the server is down. fail immediately */
+               proxy->disable_reconnect = TRUE;
                login_proxy_failed(proxy, proxy->event,
                                   LOGIN_PROXY_FAILURE_TYPE_CONNECT,
                                   "Host is down");
@@ -395,6 +387,7 @@ static void login_proxy_disconnect(struct login_proxy *proxy)
        if (!proxy->num_waiting_connections_updated) {
                i_assert(proxy->state_rec->num_waiting_connections > 0);
                proxy->state_rec->num_waiting_connections--;
+               proxy->num_waiting_connections_updated = TRUE;
        }
        if (proxy->connected) {
                i_assert(proxy->state_rec->num_proxying_connections > 0);
@@ -411,6 +404,7 @@ static void login_proxy_disconnect(struct login_proxy *proxy)
                net_disconnect(proxy->server_fd);
                proxy->server_fd = -1;
        }
+       proxy->connected = FALSE;
 }
 
 static void login_proxy_free_final(struct login_proxy *proxy)
@@ -550,21 +544,28 @@ void login_proxy_free(struct login_proxy **_proxy)
        login_proxy_free_full(_proxy, NULL, 0);
 }
 
-void login_proxy_failed(struct login_proxy *proxy, struct event *event,
+bool login_proxy_failed(struct login_proxy *proxy, struct event *event,
                        enum login_proxy_failure_type type, const char *reason)
 {
        const char *log_prefix;
+       bool try_reconnect = TRUE;
 
        switch (type) {
        case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
                log_prefix = "Aborting due to internal error: ";
+               try_reconnect = FALSE;
                break;
        case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG:
+               log_prefix = "";
+               try_reconnect = FALSE;
+               break;
        case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
                log_prefix = "";
                break;
-       case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
        case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG:
+               try_reconnect = FALSE;
+               /* fall through */
+       case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
                log_prefix = "Aborting due to remote server: ";
                break;
        case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL:
@@ -572,16 +573,25 @@ void login_proxy_failed(struct login_proxy *proxy, struct event *event,
                break;
        case LOGIN_PROXY_FAILURE_TYPE_AUTH:
                log_prefix = "";
+               try_reconnect = FALSE;
                break;
        default:
                i_unreached();
        }
 
+       if (try_reconnect && proxy_try_reconnect(proxy)) {
+               e_debug(event, "%s%s - reconnecting (attempt #%d)",
+                       log_prefix, reason, proxy->reconnect_count);
+               proxy->failure_callback(proxy->client, type, reason, TRUE);
+               return TRUE;
+       }
+
        if (type != LOGIN_PROXY_FAILURE_TYPE_AUTH)
                e_error(event, "%s%s", log_prefix, reason);
        else if (proxy->client->set->auth_verbose)
                client_proxy_log_failure(proxy->client, reason);
        proxy->failure_callback(proxy->client, type, reason, FALSE);
+       return FALSE;
 }
 
 bool login_proxy_is_ourself(const struct client *client, const char *host,
index df964ae4e0d8692e03cc7e61a8160be061edf270..ae460c32e9fea8056c4636fe16f7b57c1f0c9764 100644 (file)
@@ -71,8 +71,9 @@ int login_proxy_new(struct client *client, struct event *event,
 /* Free the proxy. This should be called if authentication fails. */
 void login_proxy_free(struct login_proxy **proxy);
 
-/* Login proxying session has failed. */
-void login_proxy_failed(struct login_proxy *proxy, struct event *event,
+/* Login proxying session has failed. Returns TRUE if the reconnection is
+   attempted. */
+bool login_proxy_failed(struct login_proxy *proxy, struct event *event,
                        enum login_proxy_failure_type type, const char *reason);
 
 /* Return TRUE if host/port/destuser combination points to same as current