dovecot-2.2: login proxy: If proxy_timeout is set, try to reconn...

dovecot at dovecot.org dovecot at dovecot.org
Fri Oct 24 00:55:15 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/52ad54b23e24
changeset: 17991:52ad54b23e24
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Oct 24 03:54:21 2014 +0300
description:
login proxy: If proxy_timeout is set, try to reconnect until the timeout is reached.
This allows quickly restarting/upgrading backend servers without returning
login failures.

diffstat:

 src/login-common/login-proxy.c |  82 +++++++++++++++++++++++++++++++----------
 1 files changed, 61 insertions(+), 21 deletions(-)

diffs (153 lines):

diff -r 4fe5b4e121a4 -r 52ad54b23e24 src/login-common/login-proxy.c
--- a/src/login-common/login-proxy.c	Thu Oct 23 06:38:20 2014 +0300
+++ b/src/login-common/login-proxy.c	Fri Oct 24 03:54:21 2014 +0300
@@ -23,6 +23,7 @@
 #define LOGIN_PROXY_IPC_NAME "proxy"
 #define KILLED_BY_ADMIN_REASON "Killed by admin"
 #define PROXY_IMMEDIATE_FAILURE_SECS 30
+#define PROXY_CONNECT_RETRY_MSECS 1000
 
 struct login_proxy {
 	struct login_proxy *prev, *next;
@@ -44,6 +45,7 @@
 	unsigned int port;
 	unsigned int connect_timeout_msecs;
 	unsigned int notify_refresh_secs;
+	unsigned int reconnect_count;
 	enum login_proxy_ssl_flags ssl_flags;
 
 	proxy_callback_t *callback;
@@ -58,6 +60,8 @@
 static struct login_proxy *login_proxies_pending = NULL;
 static struct ipc_server *login_proxy_ipc_server;
 
+static int login_proxy_connect(struct login_proxy *proxy);
+static void login_proxy_disconnect(struct login_proxy *proxy);
 static void login_proxy_ipc_cmd(struct ipc_cmd *cmd, const char *line);
 
 static void
@@ -224,6 +228,8 @@
 	}
 	str_printfa(str, " (after %u secs",
 		    (unsigned int)(ioloop_time - proxy->created.tv_sec));
+	if (proxy->reconnect_count > 0)
+		str_printfa(str, ", %u reconnects", proxy->reconnect_count);
 
 	if (proxy->server_fd != -1 &&
 	    net_getsockname(proxy->server_fd, &local_ip, &local_port) == 0) {
@@ -238,13 +244,40 @@
 	i_error("%s", str_c(str));
 }
 
+static void proxy_reconnect_timeout(struct login_proxy *proxy)
+{
+	timeout_remove(&proxy->to);
+	(void)login_proxy_connect(proxy);
+}
+
+static bool proxy_try_reconnect(struct login_proxy *proxy)
+{
+	int since_started_msecs, left_msecs;
+
+	since_started_msecs =
+		timeval_diff_msecs(&ioloop_timeval, &proxy->created);
+	if (since_started_msecs < 0)
+		return FALSE; /* time moved backwards */
+	left_msecs = proxy->connect_timeout_msecs - since_started_msecs;
+	if (left_msecs <= 0)
+		return FALSE;
+
+	login_proxy_disconnect(proxy);
+	proxy->to = timeout_add(I_MIN(PROXY_CONNECT_RETRY_MSECS, left_msecs),
+				proxy_reconnect_timeout, proxy);
+	proxy->reconnect_count++;
+	return TRUE;
+}
+
 static void proxy_wait_connect(struct login_proxy *proxy)
 {
 	errno = net_geterror(proxy->server_fd);
 	if (errno != 0) {
-		proxy_log_connect_error(proxy);
 		proxy_fail_connect(proxy);
-                login_proxy_free(&proxy);
+		if (!proxy_try_reconnect(proxy)) {
+			proxy_log_connect_error(proxy);
+			login_proxy_free(&proxy);
+		}
 		return;
 	}
 	proxy->connected = TRUE;
@@ -278,6 +311,11 @@
 	struct login_proxy_record *rec;
 
 	rec = login_proxy_state_get(proxy_state, &proxy->ip, proxy->port);
+	if (rec->last_success.tv_sec == 0) {
+		/* first connect to this IP. don't start immediately failing
+		   the check below. */
+		rec->last_success.tv_sec = ioloop_timeval.tv_sec - 1;
+	}
 	if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
 	    rec->last_failure.tv_sec - rec->last_success.tv_sec > PROXY_IMMEDIATE_FAILURE_SECS &&
 	    rec->num_waiting_connections != 0) {
@@ -358,6 +396,26 @@
 	return 0;
 }
 
+static void login_proxy_disconnect(struct login_proxy *proxy)
+{
+	if (proxy->to != NULL)
+		timeout_remove(&proxy->to);
+	if (proxy->to_notify != NULL)
+		timeout_remove(&proxy->to_notify);
+
+	if (proxy->state_rec != NULL)
+		proxy->state_rec->num_waiting_connections--;
+
+	if (proxy->server_io != NULL)
+		io_remove(&proxy->server_io);
+	if (proxy->server_input != NULL)
+		i_stream_destroy(&proxy->server_input);
+	if (proxy->server_output != NULL)
+		o_stream_destroy(&proxy->server_output);
+	if (proxy->server_fd != -1)
+		net_disconnect(proxy->server_fd);
+}
+
 static void ATTR_NULL(2)
 login_proxy_free_reason(struct login_proxy **_proxy, const char *reason)
 {
@@ -371,22 +429,7 @@
 		return;
 	proxy->destroying = TRUE;
 
-	if (proxy->to != NULL)
-		timeout_remove(&proxy->to);
-	if (proxy->to_notify != NULL)
-		timeout_remove(&proxy->to_notify);
-
-	if (proxy->state_rec != NULL)
-		proxy->state_rec->num_waiting_connections--;
-	if (proxy->to != NULL)
-		timeout_remove(&proxy->to);
-
-	if (proxy->server_io != NULL)
-		io_remove(&proxy->server_io);
-	if (proxy->server_input != NULL)
-		i_stream_destroy(&proxy->server_input);
-	if (proxy->server_output != NULL)
-		o_stream_destroy(&proxy->server_output);
+	login_proxy_disconnect(proxy);
 
 	if (proxy->client_fd != -1) {
 		/* detached proxy */
@@ -414,9 +457,6 @@
 			proxy->callback(proxy->client);
 	}
 
-	if (proxy->server_fd != -1)
-		net_disconnect(proxy->server_fd);
-
 	if (proxy->ssl_server_proxy != NULL)
 		ssl_proxy_free(&proxy->ssl_server_proxy);
 	i_free(proxy->host);


More information about the dovecot-cvs mailing list