dovecot-1.2: login-proxy: If proxy destination is known to be do...

dovecot at dovecot.org dovecot at dovecot.org
Wed Aug 12 21:51:43 EEST 2009


details:   http://hg.dovecot.org/dovecot-1.2/rev/1072d2b53f72
changeset: 9308:1072d2b53f72
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Aug 12 14:51:35 2009 -0400
description:
login-proxy: If proxy destination is known to be down, fail immediately.
We'll use a simple rule: If connection failed or timed out more recently
than it succeeded AND there are currently no clients trying to connect to
it, fail it. Since the connect isn't failed unless there is at least one
client already trying to connect to it, the proxy notices immediately when
the server comes back up and then starts serving it again.

diffstat:

5 files changed, 99 insertions(+), 1 deletion(-)
src/login-common/Makefile.am         |    2 +
src/login-common/login-proxy-state.c |   64 ++++++++++++++++++++++++++++++++++
src/login-common/login-proxy.c       |   32 ++++++++++++++++-
src/login-common/login-proxy.h       |    1 
src/login-common/main.c              |    1 

diffs (221 lines):

diff -r dfbcb8ead5ef -r 1072d2b53f72 src/login-common/Makefile.am
--- a/src/login-common/Makefile.am	Wed Aug 12 14:36:05 2009 -0400
+++ b/src/login-common/Makefile.am	Wed Aug 12 14:51:35 2009 -0400
@@ -10,6 +10,7 @@ liblogin_common_a_SOURCES = \
 liblogin_common_a_SOURCES = \
 	client-common.c \
 	login-proxy.c \
+	login-proxy-state.c \
 	main.c \
 	master.c \
 	sasl-server.c \
@@ -20,6 +21,7 @@ noinst_HEADERS = \
 noinst_HEADERS = \
 	client-common.h \
 	login-proxy.h \
+	login-proxy-state.h \
 	common.h \
 	master.h \
 	sasl-server.h \
diff -r dfbcb8ead5ef -r 1072d2b53f72 src/login-common/login-proxy-state.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/login-common/login-proxy-state.c	Wed Aug 12 14:51:35 2009 -0400
@@ -0,0 +1,64 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "network.h"
+#include "hash.h"
+#include "login-proxy-state.h"
+
+struct login_proxy_state {
+	struct hash_table *hash;
+	pool_t pool;
+};
+
+static unsigned int ip_addr_hash(const void *p)
+{
+	const struct ip_addr *ip = p;
+
+	return net_ip_hash(ip);
+}
+
+static int ip_addr_cmp(const void *p1, const void *p2)
+{
+	const struct ip_addr *ip1 = p1, *ip2 = p2;
+
+	return net_ip_compare(ip1, ip2) ? 0 : 1;
+}
+
+struct login_proxy_state *login_proxy_state_init(void)
+{
+	struct login_proxy_state *state;
+
+	state = i_new(struct login_proxy_state, 1);
+	state->pool = pool_alloconly_create("login proxy state", 1024);
+	state->hash = hash_table_create(default_pool, state->pool, 0,
+					ip_addr_hash, ip_addr_cmp);
+	return state;
+}
+
+void login_proxy_state_deinit(struct login_proxy_state **_state)
+{
+	struct login_proxy_state *state = *_state;
+
+	*_state = NULL;
+	hash_table_destroy(&state->hash);
+	pool_unref(&state->pool);
+	i_free(state);
+}
+
+struct login_proxy_record *
+login_proxy_state_get(struct login_proxy_state *state,
+		      const struct ip_addr *ip)
+{
+	struct login_proxy_record *rec;
+	struct ip_addr *new_ip;
+
+	rec = hash_table_lookup(state->hash, ip);
+	if (rec == NULL) {
+		new_ip = p_new(state->pool, struct ip_addr, 1);
+		*new_ip = *ip;
+
+		rec = p_new(state->pool, struct login_proxy_record, 1);
+		hash_table_insert(state->hash, new_ip, rec);
+	}
+	return rec;
+}
diff -r dfbcb8ead5ef -r 1072d2b53f72 src/login-common/login-proxy.c
--- a/src/login-common/login-proxy.c	Wed Aug 12 14:36:05 2009 -0400
+++ b/src/login-common/login-proxy.c	Wed Aug 12 14:51:35 2009 -0400
@@ -8,6 +8,7 @@
 #include "str-sanitize.h"
 #include "client-common.h"
 #include "ssl-proxy.h"
+#include "login-proxy-state.h"
 #include "login-proxy.h"
 
 #define MAX_PROXY_INPUT_SIZE 4096
@@ -25,6 +26,7 @@ struct login_proxy {
 	struct ssl_proxy *ssl_proxy;
 
 	struct timeout *to;
+	struct login_proxy_record *state_rec;
 
 	char *host, *user;
 	unsigned int port;
@@ -37,6 +39,7 @@ struct login_proxy {
 	unsigned int disconnecting:1;
 };
 
+static struct login_proxy_state *proxy_state;
 static struct login_proxy *login_proxies = NULL;
 static unsigned int login_proxy_count = 0;
 
@@ -137,9 +140,13 @@ static void proxy_wait_connect(struct lo
 	if (err != 0) {
 		i_error("proxy: connect(%s, %u) failed: %s",
 			proxy->host, proxy->port, strerror(err));
+		proxy->state_rec->last_failure = ioloop_time;
                 login_proxy_free(&proxy);
 		return;
 	}
+	proxy->state_rec->last_success = ioloop_time;
+	proxy->state_rec->num_waiting_connections--;
+	proxy->state_rec = NULL;
 
 	if (proxy->to != NULL)
 		timeout_remove(&proxy->to);
@@ -159,6 +166,7 @@ static void proxy_connect_timeout(struct
 static void proxy_connect_timeout(struct login_proxy *proxy)
 {
 	i_error("proxy: connect(%s, %u) timed out", proxy->host, proxy->port);
+	proxy->state_rec->last_failure = ioloop_time;
 	login_proxy_free(&proxy);
 }
 
@@ -170,6 +178,7 @@ login_proxy_new(struct client *client, c
 		proxy_callback_t *callback, void *context)
 {
 	struct login_proxy *proxy;
+	struct login_proxy_record *rec;
 	struct ip_addr ip;
 	int fd;
 
@@ -181,6 +190,13 @@ login_proxy_new(struct client *client, c
 	if (net_addr2ip(host, &ip) < 0) {
 		i_error("proxy(%s): %s is not a valid IP",
 			client->virtual_user, host);
+		return NULL;
+	}
+
+	rec = login_proxy_state_get(proxy_state, &ip);
+	if (rec->last_failure > rec->last_success &&
+	    rec->num_waiting_connections != 0) {
+		/* the server is down. fail immediately */
 		return NULL;
 	}
 
@@ -210,6 +226,9 @@ login_proxy_new(struct client *client, c
 
 	proxy->ip = client->ip;
 	proxy->client_fd = -1;
+
+	proxy->state_rec = rec;
+	rec->num_waiting_connections++;
 	return proxy;
 }
 
@@ -224,6 +243,11 @@ void login_proxy_free(struct login_proxy
 		return;
 	proxy->destroying = TRUE;
 
+	if (proxy->to != NULL)
+		timeout_remove(&proxy->to);
+
+	if (proxy->state_rec != NULL)
+		proxy->state_rec->num_waiting_connections--;
 	if (proxy->to != NULL)
 		timeout_remove(&proxy->to);
 
@@ -400,6 +424,11 @@ int login_proxy_starttls(struct login_pr
 	return 0;
 }
 
+void login_proxy_init(void)
+{
+	proxy_state = login_proxy_state_init();
+}
+
 void login_proxy_deinit(void)
 {
 	struct login_proxy *proxy;
@@ -408,4 +437,5 @@ void login_proxy_deinit(void)
 		proxy = login_proxies;
 		login_proxy_free(&proxy);
 	}
-}
+	login_proxy_state_deinit(&proxy_state);
+}
diff -r dfbcb8ead5ef -r 1072d2b53f72 src/login-common/login-proxy.h
--- a/src/login-common/login-proxy.h	Wed Aug 12 14:36:05 2009 -0400
+++ b/src/login-common/login-proxy.h	Wed Aug 12 14:51:35 2009 -0400
@@ -63,6 +63,7 @@ login_proxy_get_ssl_flags(const struct l
 /* Return number of active detached login proxies */
 unsigned int login_proxy_get_count(void) ATTR_PURE;
 
+void login_proxy_init(void);
 void login_proxy_deinit(void);
 
 #endif
diff -r dfbcb8ead5ef -r 1072d2b53f72 src/login-common/main.c
--- a/src/login-common/main.c	Wed Aug 12 14:36:05 2009 -0400
+++ b/src/login-common/main.c	Wed Aug 12 14:51:35 2009 -0400
@@ -363,6 +363,7 @@ static void main_init(void)
 	auth_client = auth_client_new(login_process_uid);
         auth_client_set_connect_notify(auth_client, auth_connect_notify, NULL);
 	clients_init();
+	login_proxy_init();
 
 	if (!ssl_initialized && ssl_listen_count > 0) {
 		/* this shouldn't happen, master should have


More information about the dovecot-cvs mailing list