summaryrefslogtreecommitdiffstats
path: root/src/director/director-host.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/director/director-host.c')
-rw-r--r--src/director/director-host.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/director/director-host.c b/src/director/director-host.c
new file mode 100644
index 0000000..215ad0d
--- /dev/null
+++ b/src/director/director-host.c
@@ -0,0 +1,190 @@
+/* Copyright (c) 2010-2018 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;
+}
+
+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;
+
+ i_assert(director_host_lookup(dir, ip, port) == NULL);
+
+ host = i_new(struct director_host, 1);
+ host->dir = dir;
+ host->refcount = 1;
+ host->ip = *ip;
+ host->ip_str = i_strdup(net_ip2addr(&host->ip));
+ host->port = port;
+ host->name = i_strdup_printf("%s:%u", host->ip_str, port);
+
+ array_push_back(&dir->dir_hosts, &host);
+
+ /* 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->ip_str);
+ 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 *host;
+
+ array_foreach_elem(&dir->dir_hosts, host) {
+ if (net_ip_compare(&host->ip, ip) && host->port == port)
+ return host;
+ }
+ return NULL;
+}
+
+struct director_host *
+director_host_lookup_ip(struct director *dir, const struct ip_addr *ip)
+{
+ struct director_host *host;
+
+ array_foreach_elem(&dir->dir_hosts, host) {
+ if (net_ip_compare(&host->ip, ip))
+ return host;
+ }
+ 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++) {
+ if (director_host_lookup(dir, &ips[i], port) == NULL)
+ (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;
+ }
+}