From: Timo Sirainen Date: Fri, 16 Oct 2009 19:20:26 +0000 (-0400) Subject: imap/pop3 proxy: Track "destination down" state separately for IP+ports, not just... X-Git-Tag: 2.0.alpha2~76 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7dc4bf28c0c4c673a198070edd1ed54e14ae39ae;p=thirdparty%2Fdovecot%2Fcore.git imap/pop3 proxy: Track "destination down" state separately for IP+ports, not just IPs. In some systems different ports could get redirected to different servers. --HG-- branch : HEAD --- diff --git a/src/login-common/login-proxy-state.c b/src/login-common/login-proxy-state.c index e5e5933d3c..2c88af27e0 100644 --- a/src/login-common/login-proxy-state.c +++ b/src/login-common/login-proxy-state.c @@ -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; } diff --git a/src/login-common/login-proxy-state.h b/src/login-common/login-proxy-state.h index a778487722..26c50421e5 100644 --- a/src/login-common/login-proxy-state.h +++ b/src/login-common/login-proxy-state.h @@ -4,9 +4,12 @@ #include 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 diff --git a/src/login-common/login-proxy.c b/src/login-common/login-proxy.c index 743aed55c1..d0606a4a8f 100644 --- a/src/login-common/login-proxy.c +++ b/src/login-common/login-proxy.c @@ -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 */