director-host.c revision 7c925149e49f7cce41c90d562ff3835b66ddca29
/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "director.h"
#include "director-host.h"
static int director_host_cmp(const struct director_host *b1,
const struct director_host *b2)
{
int ret;
ret = net_ip_cmp(&b1->ip, &b2->ip);
if (ret != 0)
return ret;
return (int)b1->port - (int)b2->port;
}
static int director_host_cmp_p(struct director_host *const *host1,
struct director_host *const *host2)
{
return director_host_cmp(*host1, *host2);
}
struct director_host *
director_host_add(struct director *dir,
const struct ip_addr *ip, in_port_t port)
{
struct director_host *host;
host = i_new(struct director_host, 1);
host->dir = dir;
host->refcount = 1;
host->ip = *ip;
host->port = port;
host->name = i_strdup_printf("%s:%u", net_ip2addr(ip), port);
array_append(&dir->dir_hosts, &host, 1);
/* there are few enough directors that sorting after each
addition should be fine */
array_sort(&dir->dir_hosts, director_host_cmp_p);
return host;
}
void director_host_free(struct director_host **_host)
{
struct director_host *host = *_host;
i_assert(host->refcount == 1);
*_host = NULL;
director_host_unref(host);
}
void director_host_ref(struct director_host *host)
{
i_assert(host->refcount > 0);
host->refcount++;
}
void director_host_unref(struct director_host *host)
{
struct director_host *const *hosts;
unsigned int i, count;
i_assert(host->refcount > 0);
if (--host->refcount > 0)
return;
hosts = array_get(&host->dir->dir_hosts, &count);
for (i = 0; i < count; i++) {
if (hosts[i] == host) {
array_delete(&host->dir->dir_hosts, i, 1);
break;
}
}
i_free(host->name);
i_free(host);
}
void director_host_restarted(struct director_host *host)
{
host->last_seq = 0;
host->last_sync_seq = 0;
host->last_sync_seq_counter = 0;
host->last_sync_timestamp = 0;
}
struct director_host *
director_host_get(struct director *dir, const struct ip_addr *ip,
in_port_t port)
{
struct director_host *host;
host = director_host_lookup(dir, ip, port);
if (host == NULL)
host = director_host_add(dir, ip, port);
return host;
}
struct director_host *
director_host_lookup(struct director *dir, const struct ip_addr *ip,
in_port_t port)
{
struct director_host *const *hostp;
array_foreach(&dir->dir_hosts, hostp) {
if (net_ip_compare(&(*hostp)->ip, ip) &&
(*hostp)->port == port)
return *hostp;
}
return NULL;
}
struct director_host *
director_host_lookup_ip(struct director *dir, const struct ip_addr *ip)
{
struct director_host *const *hostp;
array_foreach(&dir->dir_hosts, hostp) {
if (net_ip_compare(&(*hostp)->ip, ip))
return *hostp;
}
return NULL;
}
int director_host_cmp_to_self(const struct director_host *b1,
const struct director_host *b2,
const struct director_host *self)
{
int ret;
if ((ret = director_host_cmp(b1, b2)) >= 0)
return ret == 0 ? 0 : -director_host_cmp_to_self(b2, b1, self);
/* order -> return:
self, b1, b2 -> b2
b1, self, b2 -> b1
b1, b2, self -> b2
*/
if (director_host_cmp(self, b1) < 0)
return 1; /* self, b1, b2 */
if (director_host_cmp(self, b2) < 0)
return -1; /* b1, self, b2 */
return 1; /* b1, b2, self */
}
static void director_host_add_string(struct director *dir, const char *host)
{
struct ip_addr *ips;
in_port_t port;
unsigned int i, ips_count;
if (net_str2hostport(host, dir->self_port, &host, &port) < 0)
i_fatal("Invalid director host:port in '%s'", host);
if (net_gethostbyname(host, &ips, &ips_count) < 0)
i_fatal("Unknown director host: %s", host);
for (i = 0; i < ips_count; i++)
(void)director_host_add(dir, &ips[i], port);
}
void director_host_add_from_string(struct director *dir, const char *hosts)
{
T_BEGIN {
const char *const *tmp;
tmp = t_strsplit_spaces(hosts, " ");
for (; *tmp != NULL; tmp++)
director_host_add_string(dir, *tmp);
} T_END;
if (array_count(&dir->dir_hosts) == 0) {
/* standalone director */
struct ip_addr ip;
if (net_addr2ip("127.0.0.1", &ip) < 0)
i_unreached();
dir->self_host = director_host_add(dir, &ip, 0);
dir->self_host->self = TRUE;
}
}