bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "array.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_host_cmp(const struct director_host *b1,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const struct director_host *b2)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = net_ip_cmp(&b1->ip, &b2->ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret != 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return (int)b1->port - (int)b2->port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
6e54fd2bedbbc0c6316eae8fb569eb9a96aa29abTimo Sirainenint director_host_cmp_p(struct director_host *const *host1,
6e54fd2bedbbc0c6316eae8fb569eb9a96aa29abTimo Sirainen struct director_host *const *host2)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_host_cmp(*host1, *host2);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_host *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_host_add(struct director *dir,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch const struct ip_addr *ip, in_port_t port)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
85601125c9cae82957a57f7b02409c567a59300eTimo Sirainen i_assert(director_host_lookup(dir, ip, port) == NULL);
85601125c9cae82957a57f7b02409c567a59300eTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = i_new(struct director_host, 1);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host->dir = dir;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host->refcount = 1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host->ip = *ip;
b7650f081ff781c39fe00a3b93375e5f2dd14236Timo Sirainen host->ip_str = i_strdup(net_ip2addr(&host->ip));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host->port = port;
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->name = i_strdup_printf("%s:%u", host->ip_str, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_append(&dir->dir_hosts, &host, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* there are few enough directors that sorting after each
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen addition should be fine */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_sort(&dir->dir_hosts, director_host_cmp_p);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid director_host_free(struct director_host **_host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *host = *_host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_assert(host->refcount == 1);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen *_host = NULL;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_host_unref(host);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid director_host_ref(struct director_host *host)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_assert(host->refcount > 0);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host->refcount++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid director_host_unref(struct director_host *host)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *const *hosts;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int i, count;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_assert(host->refcount > 0);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (--host->refcount > 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hosts = array_get(&host->dir->dir_hosts, &count);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen for (i = 0; i < count; i++) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (hosts[i] == host) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen array_delete(&host->dir->dir_hosts, i, 1);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen break;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(host->name);
b7650f081ff781c39fe00a3b93375e5f2dd14236Timo Sirainen i_free(host->ip_str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainenvoid director_host_restarted(struct director_host *host)
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen{
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen host->last_seq = 0;
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen host->last_sync_seq = 0;
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen host->last_sync_seq_counter = 0;
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen host->last_sync_timestamp = 0;
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen}
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_host *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_host_get(struct director *dir, const struct ip_addr *ip,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_lookup(dir, ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_add(dir, ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_host *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_host_lookup(struct director *dir, const struct ip_addr *ip,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&dir->dir_hosts, hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_ip_compare(&(*hostp)->ip, ip) &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (*hostp)->port == port)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_host *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_host_lookup_ip(struct director *dir, const struct ip_addr *ip)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&dir->dir_hosts, hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_ip_compare(&(*hostp)->ip, ip))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint director_host_cmp_to_self(const struct director_host *b1,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const struct director_host *b2,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const struct director_host *self)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen int ret;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if ((ret = director_host_cmp(b1, b2)) >= 0)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return ret == 0 ? 0 : -director_host_cmp_to_self(b2, b1, self);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen /* order -> return:
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen self, b1, b2 -> b2
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen b1, self, b2 -> b1
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen b1, b2, self -> b2
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen */
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (director_host_cmp(self, b1) < 0)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return 1; /* self, b1, b2 */
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (director_host_cmp(self, b2) < 0)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return -1; /* b1, self, b2 */
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return 1; /* b1, b2, self */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_host_add_string(struct director *dir, const char *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr *ips;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch unsigned int i, ips_count;
7c925149e49f7cce41c90d562ff3835b66ddca29Timo Sirainen
7c925149e49f7cce41c90d562ff3835b66ddca29Timo Sirainen if (net_str2hostport(host, dir->self_port, &host, &port) < 0)
7c925149e49f7cce41c90d562ff3835b66ddca29Timo Sirainen i_fatal("Invalid director host:port in '%s'", host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_gethostbyname(host, &ips, &ips_count) < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_fatal("Unknown director host: %s", host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
85601125c9cae82957a57f7b02409c567a59300eTimo Sirainen for (i = 0; i < ips_count; i++) {
85601125c9cae82957a57f7b02409c567a59300eTimo Sirainen if (director_host_lookup(dir, &ips[i], port) == NULL)
85601125c9cae82957a57f7b02409c567a59300eTimo Sirainen (void)director_host_add(dir, &ips[i], port);
85601125c9cae82957a57f7b02409c567a59300eTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_host_add_from_string(struct director *dir, const char *hosts)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *tmp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen tmp = t_strsplit_spaces(hosts, " ");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (; *tmp != NULL; tmp++)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_host_add_string(dir, *tmp);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } T_END;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (array_count(&dir->dir_hosts) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* standalone director */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (net_addr2ip("127.0.0.1", &ip) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_host = director_host_add(dir, &ip, 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_host->self = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}