]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap/pop3 proxy: Track "destination down" state separately for IP+ports, not just...
authorTimo Sirainen <tss@iki.fi>
Fri, 16 Oct 2009 19:20:26 +0000 (15:20 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 16 Oct 2009 19:20:26 +0000 (15:20 -0400)
In some systems different ports could get redirected to different servers.

--HG--
branch : HEAD

src/login-common/login-proxy-state.c
src/login-common/login-proxy-state.h
src/login-common/login-proxy.c

index e5e5933d3cd0c810aac4b3e35635de28f5cf53f5..2c88af27e0234469d1cff2c75eb884299c9a4189 100644 (file)
@@ -10,18 +10,21 @@ struct login_proxy_state {
        pool_t pool;
 };
 
-static unsigned int ip_addr_hash(const void *p)
+static unsigned int login_proxy_record_hash(const void *p)
 {
-       const struct ip_addr *ip = p;
+       const struct login_proxy_record *rec = p;
 
-       return net_ip_hash(ip);
+       return net_ip_hash(&rec->ip) ^ rec->port;
 }
 
-static int ip_addr_cmp(const void *p1, const void *p2)
+static int login_proxy_record_cmp(const void *p1, const void *p2)
 {
-       const struct ip_addr *ip1 = p1, *ip2 = p2;
+       const struct login_proxy_record *rec1 = p1, *rec2 = p2;
 
-       return net_ip_compare(ip1, ip2) ? 0 : 1;
+       if (!net_ip_compare(&rec1->ip, &rec2->ip))
+               return 1;
+
+       return (int)rec1->port - (int)rec2->port;
 }
 
 struct login_proxy_state *login_proxy_state_init(void)
@@ -31,7 +34,8 @@ struct login_proxy_state *login_proxy_state_init(void)
        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);
+                                       login_proxy_record_hash,
+                                       login_proxy_record_cmp);
        return state;
 }
 
@@ -47,18 +51,20 @@ void login_proxy_state_deinit(struct login_proxy_state **_state)
 
 struct login_proxy_record *
 login_proxy_state_get(struct login_proxy_state *state,
-                     const struct ip_addr *ip)
+                     const struct ip_addr *ip, unsigned int port)
 {
-       struct login_proxy_record *rec;
-       struct ip_addr *new_ip;
+       struct login_proxy_record *rec, key;
 
-       rec = hash_table_lookup(state->hash, ip);
-       if (rec == NULL) {
-               new_ip = p_new(state->pool, struct ip_addr, 1);
-               *new_ip = *ip;
+       memset(&key, 0, sizeof(key));
+       key.ip = *ip;
+       key.port = port;
 
+       rec = hash_table_lookup(state->hash, &key);
+       if (rec == NULL) {
                rec = p_new(state->pool, struct login_proxy_record, 1);
-               hash_table_insert(state->hash, new_ip, rec);
+               rec->ip = *ip;
+               rec->port = port;
+               hash_table_insert(state->hash, rec, rec);
        }
        return rec;
 }
index a778487722436478172cb679ef1c4cb97cba642d..26c50421e5ef8747a5049a82beeaa5d2c221a4ad 100644 (file)
@@ -4,9 +4,12 @@
 #include <sys/time.h>
 
 struct login_proxy_record {
+       struct ip_addr ip;
+       unsigned int port;
+       unsigned int num_waiting_connections;
+
        struct timeval last_failure;
        struct timeval last_success;
-       unsigned int num_waiting_connections;
 };
 
 struct login_proxy_state *login_proxy_state_init(void);
@@ -14,6 +17,6 @@ void login_proxy_state_deinit(struct login_proxy_state **state);
 
 struct login_proxy_record *
 login_proxy_state_get(struct login_proxy_state *state,
-                     const struct ip_addr *ip);
+                     const struct ip_addr *ip, unsigned int port);
 
 #endif
index 743aed55c1369bc65e48a70d0305b962b1f0e9e9..d0606a4a8fc7682031c693414eb27a2f9ec87c4a 100644 (file)
@@ -205,7 +205,7 @@ login_proxy_new(struct client *client, const struct login_proxy_settings *set,
                return NULL;
        }
 
-       rec = login_proxy_state_get(proxy_state, &ip);
+       rec = login_proxy_state_get(proxy_state, &ip, set->port);
        if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
            rec->num_waiting_connections != 0) {
                /* the server is down. fail immediately */