director.c revision 6f8d511666b292196f305d40b9e5e8b017c27a3c
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "array.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "str.h"
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen#include "strescape.h"
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen#include "ipc-client.h"
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#include "user-directory.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "mail-host.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "director-host.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "director-connection.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "director.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_IPC_PROXY_PATH "ipc"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_RECONNECT_RETRY_SECS 60
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_RECONNECT_TIMEOUT_MSECS (30*1000)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_USER_MOVE_TIMEOUT_MSECS (30*1000)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_SYNC_TIMEOUT_MSECS (5*1000)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#define DIRECTOR_RING_MIN_WAIT_SECS 20
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#define DIRECTOR_QUICK_RECONNECT_TIMEOUT_MSECS 1000
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen#define DIRECTOR_DELAYED_DIR_REMOVE_MSECS (1000*30)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenbool director_debug;
4865df74dad010a65ab63734b3ca1349ce38dc57Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainenstatic bool director_is_self_ip_set(struct director *dir)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct ip_addr ip;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen net_get_ip_any4(&ip);
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (net_ip_compare(&dir->self_ip, &ip))
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen return FALSE;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen net_get_ip_any6(&ip);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen if (net_ip_compare(&dir->self_ip, &ip))
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen return FALSE;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen return TRUE;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistatic void director_find_self_ip(struct director *dir)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct director_host *const *hosts;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
db623deb12c3566618faba5a35a44ceed83c3dc0Martti Rannanjärvi hosts = array_get(&dir->dir_hosts, &count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 0; i < count; i++) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_try_bind(&hosts[i]->ip) == 0) {
db623deb12c3566618faba5a35a44ceed83c3dc0Martti Rannanjärvi dir->self_ip = hosts[i]->ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_fatal("director_servers doesn't list ourself");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_find_self(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->self_host != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_is_self_ip_set(dir))
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen director_find_self_ip(dir);
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen dir->self_host = director_host_lookup(dir, &dir->self_ip,
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen dir->self_port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->self_host == NULL) {
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen i_fatal("director_servers doesn't list ourself (%s:%u)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&dir->self_ip), dir->self_port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen dir->self_host->self = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic unsigned int director_find_self_idx(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
34a45b80c8ed18861c6e343fe40adbe360fc6badTimo Sirainen struct director_host *const *hosts;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(dir->self_host != NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hosts = array_get(&dir->dir_hosts, &count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 0; i < count; i++) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (hosts[i] == dir->self_host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return i;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_unreached();
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_has_outgoing_connection(struct director *dir,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *const *connp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&dir->connections, connp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (director_connection_get_host(*connp) == host &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen !director_connection_is_incoming(*connp))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainenint director_connect_host(struct director *dir, struct director_host *host)
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen{
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen in_port_t port;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen int fd;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen if (director_has_outgoing_connection(dir, host))
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen return 0;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen if (director_debug) {
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen string_t *str = t_str_new(128);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen str_printfa(str, "Connecting to %s:%u (as %s",
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen net_ip2addr(&host->ip), host->port,
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen net_ip2addr(&dir->self_ip));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->last_network_failure > 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, ", last network failure %ds ago",
009217abb57a24a4076092e8e4e165545747839eStephan Bosch (int)(ioloop_time - host->last_network_failure));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->last_protocol_failure > 0) {
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen str_printfa(str, ", last protocol failure %ds ago",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen (int)(ioloop_time - host->last_protocol_failure));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen dir_debug("%s", str_c(str));
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen }
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen port = dir->test_port != 0 ? dir->test_port : host->port;
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen fd = net_connect_ip(&host->ip, port, &dir->self_ip);
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen if (fd == -1) {
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen host->last_network_failure = ioloop_time;
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen i_error("connect(%s) failed: %m", host->name);
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen return -1;
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen }
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen /* Reset timestamp so that director_connect() won't skip this host
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen while we're still trying to connect to it */
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen host->last_network_failure = 0;
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen (void)director_connection_init_out(dir, fd, host);
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen return 0;
447653aca14335b7096fb2dd2c7103631b336094Timo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct director_host *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_get_preferred_right_host(struct director *dir)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hosts, *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, count, self_idx;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen hosts = array_get(&dir->dir_hosts, &count);
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen if (count == 1) {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* self */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return NULL;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen self_idx = director_find_self_idx(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 0; i < count; i++) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host = hosts[(self_idx + i + 1) % count];
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (!host->removed)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* self, with some removed hosts */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return NULL;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainenstatic bool director_wait_for_others(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen struct director_host *const *hostp;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* don't assume we're alone until we've attempted to connect
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen to others for a while */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (dir->ring_first_alone != 0 &&
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ioloop_time - dir->ring_first_alone > DIRECTOR_RING_MIN_WAIT_SECS)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return FALSE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (dir->ring_first_alone == 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen dir->ring_first_alone = ioloop_time;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* reset all failures and try again */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen array_foreach(&dir->dir_hosts, hostp) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen (*hostp)->last_network_failure = 0;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen (*hostp)->last_protocol_failure = 0;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->to_reconnect != NULL)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen timeout_remove(&dir->to_reconnect);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->to_reconnect = timeout_add(DIRECTOR_QUICK_RECONNECT_TIMEOUT_MSECS,
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_connect, dir);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen return TRUE;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen}
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainenvoid director_connect(struct director *dir)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen{
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen struct director_host *const *hosts;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen unsigned int i, count, self_idx;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen self_idx = director_find_self_idx(dir);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* try to connect to first working server on our right side.
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen the left side is supposed to connect to us. */
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen hosts = array_get(&dir->dir_hosts, &count);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen for (i = 1; i < count; i++) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen unsigned int idx = (self_idx + i) % count;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (hosts[idx]->removed)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen continue;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (hosts[idx]->last_network_failure +
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_RECONNECT_RETRY_SECS > ioloop_time) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* connection failed recently, don't try retrying here */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen continue;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (hosts[idx]->last_protocol_failure +
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_PROTOCOL_FAILURE_RETRY_SECS > ioloop_time) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* the director recently sent invalid protocol data,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen don't try retrying yet */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen continue;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (director_connect_host(dir, hosts[idx]) == 0) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* success */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen return;
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen }
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen }
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (count > 1 && director_wait_for_others(dir))
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen return;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* we're the only one */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (count > 1) {
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen i_warning("director: Couldn't connect to right side, "
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen "we must be the only director left");
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->left != NULL) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* since we couldn't connect to it,
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen it must have failed recently */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_warning("director: Assuming %s is dead, disconnecting",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_get_name(dir->left));
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_connection_deinit(&dir->left,
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen "This connection is dead?");
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->ring_min_version = DIRECTOR_VERSION_MINOR;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (!dir->ring_handshaked)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_set_ring_handshaked(dir);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen else
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_set_ring_synced(dir);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen}
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainenvoid director_set_ring_handshaked(struct director *dir)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen{
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_assert(!dir->ring_handshaked);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (dir->to_handshake_warning != NULL)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen timeout_remove(&dir->to_handshake_warning);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->ring_handshake_warning_sent) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen i_warning("Directors have been connected, "
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen "continuing delayed requests");
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->ring_handshake_warning_sent = FALSE;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir_debug("Director ring handshaked");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->ring_handshaked = TRUE;
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen director_set_ring_synced(dir);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void director_reconnect_timeout(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *cur_host, *preferred_host =
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen director_get_preferred_right_host(dir);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen cur_host = dir->right == NULL ? NULL :
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen director_connection_get_host(dir->right);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (preferred_host == NULL) {
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen /* all directors have been removed, try again later */
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen } else if (cur_host != preferred_host)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen (void)director_connect_host(dir, preferred_host);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen else {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* the connection hasn't finished sync yet.
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen keep this timeout for now. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_set_ring_synced(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen i_assert(!dir->ring_synced);
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen i_assert((dir->left != NULL && dir->right != NULL) ||
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen (dir->left == NULL && dir->right == NULL));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->to_handshake_warning != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen timeout_remove(&dir->to_handshake_warning);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->ring_handshake_warning_sent) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_warning("Ring is synced, continuing delayed requests "
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen "(syncing took %d secs, hosts_hash=%u)",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen (int)(ioloop_time - dir->ring_last_sync_time),
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen mail_hosts_hash(dir->mail_hosts));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->ring_handshake_warning_sent = FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host = dir->right == NULL ? NULL :
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_get_host(dir->right);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->to_reconnect != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen timeout_remove(&dir->to_reconnect);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (host != director_get_preferred_right_host(dir)) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* try to reconnect to preferred host later */
56c69b4b17af0b5a2c71705d5edae746f00780b9Timo Sirainen dir->to_reconnect =
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen timeout_add(DIRECTOR_RECONNECT_TIMEOUT_MSECS,
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen director_reconnect_timeout, dir);
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->left != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_set_synced(dir->left, TRUE);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_set_synced(dir->right, TRUE);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->to_sync != NULL)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen timeout_remove(&dir->to_sync);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->ring_synced = TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->ring_last_sync_time = ioloop_time;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen mail_hosts_set_synced(dir->mail_hosts);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_set_state_changed(dir);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen}
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_sync_send(struct director *dir, struct director_host *host,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen uint32_t seq, unsigned int minor_version,
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen unsigned int timestamp, unsigned int hosts_hash)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen{
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen string_t *str;
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (host == dir->self_host)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen dir->last_sync_sent_ring_change_counter = dir->ring_change_counter;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen str = t_str_new(128);
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen str_printfa(str, "SYNC\t%s\t%u\t%u",
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen net_ip2addr(&host->ip), host->port, seq);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen if (minor_version > 0 &&
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen director_connection_get_minor_version(dir->right) > 0) {
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen /* only minor_version>0 supports extra parameters */
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen str_printfa(str, "\t%u\t%u\t%u", minor_version,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen timestamp, hosts_hash);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen str_append_c(str, '\n');
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_connection_send(dir->right, str_c(str));
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen /* ping our connections in case either of them are hanging.
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen if they are, we want to know it fast. */
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (dir->left != NULL)
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_connection_ping(dir->left);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_connection_ping(dir->right);
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen}
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainenbool director_resend_sync(struct director *dir)
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen{
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (!dir->ring_synced && dir->left != NULL && dir->right != NULL) {
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen /* send a new SYNC in case the previous one got dropped */
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen dir->self_host->last_sync_timestamp = ioloop_time;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_sync_send(dir, dir->self_host, dir->sync_seq,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen DIRECTOR_VERSION_MINOR, ioloop_time,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen mail_hosts_hash(dir->mail_hosts));
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (dir->to_sync != NULL)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen timeout_reset(dir->to_sync);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
7be1a5530fcb414588fbe90eaed65eff83e84737Timo Sirainen }
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen return FALSE;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen}
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainenstatic void director_sync_timeout(struct director *dir)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen{
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen i_assert(!dir->ring_synced);
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen if (director_resend_sync(dir))
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen i_error("Ring SYNC appears to have got lost, resending");
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen}
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainenvoid director_set_ring_unsynced(struct director *dir)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen{
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (dir->ring_synced) {
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen dir->ring_synced = FALSE;
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen dir->ring_last_sync_time = ioloop_time;
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen }
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (dir->to_sync == NULL) {
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen dir->to_sync = timeout_add(DIRECTOR_SYNC_TIMEOUT_MSECS,
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen director_sync_timeout, dir);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen } else {
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen timeout_reset(dir->to_sync);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen }
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen}
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainenstatic void director_sync(struct director *dir)
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen{
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen /* we're synced again when we receive this SYNC back */
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen dir->sync_seq++;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen if (dir->right == NULL && dir->left == NULL) {
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen /* we're alone. if we're already synced,
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen don't become unsynced. */
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen return;
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen }
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen director_set_ring_unsynced(dir);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (dir->sync_frozen) {
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen dir->sync_pending = TRUE;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen return;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (dir->right == NULL) {
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen i_assert(!dir->ring_synced ||
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen (dir->left == NULL && dir->right == NULL));
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen return;
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen }
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen dir_debug("Ring is desynced (seq=%u, sending SYNC to %s)",
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen dir->sync_seq, dir->right == NULL ? "(nowhere)" :
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen director_connection_get_name(dir->right));
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* send PINGs to our connections more rapidly until we've synced again.
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if the connection has actually died, we don't need to wait (and
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen delay requests) for as long to detect it */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->left != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_set_synced(dir->left, FALSE);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_set_synced(dir->right, FALSE);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync_send(dir, dir->self_host, dir->sync_seq,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen DIRECTOR_VERSION_MINOR, ioloop_time,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen mail_hosts_hash(dir->mail_hosts));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainenvoid director_sync_freeze(struct director *dir)
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen{
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen struct director_connection *const *connp;
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen i_assert(!dir->sync_frozen);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen i_assert(!dir->sync_pending);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen array_foreach(&dir->connections, connp)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_cork(*connp);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen dir->sync_frozen = TRUE;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen}
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainenvoid director_sync_thaw(struct director *dir)
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_connection *const *connp;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_assert(dir->sync_frozen);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_frozen = FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->sync_pending) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_pending = FALSE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_sync(dir);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen array_foreach(&dir->connections, connp)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_uncork(*connp);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_notify_ring_added(struct director_host *added_host,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_host *src)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *cmd;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen added_host->dir->ring_change_counter++;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen cmd = t_strdup_printf("DIRECTOR\t%s\t%u\n",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen net_ip2addr(&added_host->ip), added_host->port);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_update_send(added_host->dir, src, cmd);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_delayed_dir_remove_timeout(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *const *hosts, *host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int i, count;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen timeout_remove(&dir->to_remove_dirs);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hosts = array_get(&dir->dir_hosts, &count);
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen for (i = 0; i < count; ) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (hosts[i]->removed) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host = hosts[i];
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_host_free(&host);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hosts = array_get(&dir->dir_hosts, &count);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen } else {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid director_ring_remove(struct director_host *removed_host,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *src)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director *dir = removed_host->dir;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_connection *const *conns, *conn;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int i, count;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const char *cmd;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (removed_host->self) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* others will just disconnect us */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* mark the host as removed and fully remove it later. this delay is
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen needed, because the removal may trigger director reconnections,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen which may send the director back and we don't want to re-add it */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen removed_host->removed = TRUE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (dir->to_remove_dirs == NULL) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen dir->to_remove_dirs =
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen timeout_add(DIRECTOR_DELAYED_DIR_REMOVE_MSECS,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_delayed_dir_remove_timeout, dir);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* disconnect any connections to the host */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen conns = array_get(&dir->connections, &count);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen for (i = 0; i < count; ) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen conn = conns[i];
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (director_connection_get_host(conn) != removed_host)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen else {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_connection_deinit(&conn, "Removing from ring");
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen conns = array_get(&dir->connections, &count);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (dir->right == NULL)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_connect(dir);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cmd = t_strdup_printf("DIRECTOR-REMOVE\t%s\t%u\n",
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen net_ip2addr(&removed_host->ip),
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen removed_host->port);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_update_send_version(dir, src,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen DIRECTOR_VERSION_RING_REMOVE, cmd);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenstatic void
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainendirector_send_host(struct director *dir, struct director_host *src,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *orig_src,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct mail_host *host)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const char *host_tag = mail_host_get_tag(host);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen string_t *str;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (orig_src == NULL) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen orig_src = dir->self_host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen orig_src->last_seq++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen str = t_str_new(128);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen str_printfa(str, "HOST\t%s\t%u\t%u\t%s\t%u",
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen orig_src->last_seq,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen net_ip2addr(&host->ip), host->vhost_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->ring_min_version >= DIRECTOR_VERSION_TAGS_V2) {
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen str_append_c(str, '\t');
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str_append_tabescaped(str, host_tag);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen } else if (host_tag[0] != '\0' &&
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->ring_min_version < DIRECTOR_VERSION_TAGS_V2) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->ring_min_version < DIRECTOR_VERSION_TAGS) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("Ring has directors that don't support tags - removing host %s with tag '%s'",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen net_ip2addr(&host->ip), host_tag);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_error("Ring has directors that support mixed versions of tags - removing host %s with tag '%s'",
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen net_ip2addr(&host->ip), host_tag);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen director_remove_host(dir, NULL, NULL, host);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen return;
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (dir->ring_min_version >= DIRECTOR_VERSION_UPDOWN) {
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen str_printfa(str, "\t%c%ld\t", host->down ? 'D' : 'U',
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen (long)host->last_updown_change);
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen /* add any further version checks here - these directors ignore
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen any extra unknown arguments */
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen if (host->hostname != NULL)
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen str_append_tabescaped(str, host->hostname);
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen }
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen str_append_c(str, '\n');
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen director_update_send(dir, src, str_c(str));
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen}
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainenvoid director_resend_hosts(struct director *dir)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen{
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen struct mail_host *const *hostp;
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen array_foreach(mail_hosts_get(dir->mail_hosts), hostp)
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen director_send_host(dir, dir->self_host, NULL, *hostp);
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen}
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainenvoid director_update_host(struct director *dir, struct director_host *src,
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen struct director_host *orig_src,
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen struct mail_host *host)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen{
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen /* update state in case this is the first mail host being added */
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen director_set_state_changed(dir);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen dir_debug("Updating host %s vhost_count=%u "
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen "down=%d last_updown_change=%ld (hosts_hash=%u)",
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen net_ip2addr(&host->ip), host->vhost_count, host->down,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen (long)host->last_updown_change,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen mail_hosts_hash(dir->mail_hosts));
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen director_send_host(dir, src, orig_src, host);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen /* mark the host desynced until ring is synced again. except if we're
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen alone in the ring that never happens. */
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (dir->right != NULL || dir->left != NULL)
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen host->desynced = TRUE;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen director_sync(dir);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen}
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainenvoid director_remove_host(struct director *dir, struct director_host *src,
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen struct director_host *orig_src,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct mail_host *host)
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen{
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (src != NULL) {
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (orig_src == NULL) {
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen orig_src = dir->self_host;
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen orig_src->last_seq++;
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen }
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen director_update_send(dir, src, t_strdup_printf(
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen "HOST-REMOVE\t%s\t%u\t%u\t%s\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&orig_src->ip), orig_src->port,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen orig_src->last_seq, net_ip2addr(&host->ip)));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_directory_remove_host(dir->users, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_host_remove(host);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_flush_host(struct director *dir, struct director_host *src,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *orig_src,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct mail_host *host)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (orig_src == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src = dir->self_host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src->last_seq++;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_update_send(dir, src, t_strdup_printf(
87842f621233257b7a7945d994ba931508b34877Timo Sirainen "HOST-FLUSH\t%s\t%u\t%u\t%s\n",
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&host->ip)));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_directory_remove_host(dir->users, host);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen director_sync(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenvoid director_update_user(struct director *dir, struct director_host *src,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct user *user)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(src != NULL);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(!user->weak);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen director_update_send(dir, src, t_strdup_printf("USER\t%u\t%s\n",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen user->username_hash, net_ip2addr(&user->host->ip)));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenvoid director_update_user_weak(struct director *dir, struct director_host *src,
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen struct director_connection *src_conn,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct director_host *orig_src,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct user *user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen i_assert(src != NULL);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen i_assert(user->weak);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (orig_src == NULL) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen orig_src = dir->self_host;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen orig_src->last_seq++;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen cmd = t_strdup_printf("USER-WEAK\t%s\t%u\t%u\t%u\t%s\n",
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->username_hash, net_ip2addr(&user->host->ip));
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen if (src != dir->self_host && dir->left != NULL && dir->right != NULL &&
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_connection_get_host(dir->left) ==
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_connection_get_host(dir->right)) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* only two directors in this ring and we're forwarding
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen USER-WEAK from one director back to itself via another
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen so it sees we've received it. we can't use
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_update_send() for this, because it doesn't send
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen data back to the source. */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (dir->right == src_conn)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_connection_send(dir->left, cmd);
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen else if (dir->left == src_conn)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_connection_send(dir->right, cmd);
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen else
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen i_unreached();
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen } else {
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_update_send(dir, src, cmd);
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen }
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen}
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainenstruct director_user_kill_finish_ctx {
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen struct director *dir;
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen struct user *user;
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen};
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainenstatic void
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainendirector_user_kill_finish_delayed_to(struct director_user_kill_finish_ctx *ctx)
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen{
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen i_assert(ctx->user->kill_state == USER_KILL_STATE_DELAY);
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen ctx->user->kill_state = USER_KILL_STATE_NONE;
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen timeout_remove(&ctx->user->to_move);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ctx->dir->state_change_callback(ctx->dir);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_free(ctx);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainenstatic void
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_user_kill_finish_delayed(struct director *dir, struct user *user)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct director_user_kill_finish_ctx *ctx;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ctx = i_new(struct director_user_kill_finish_ctx, 1);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ctx->dir = dir;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi ctx->user = user;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->kill_state = USER_KILL_STATE_DELAY;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi timeout_remove(&user->to_move);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* wait for a while for the kills to finish in the backend server,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi so there are no longer any processes running for the user before we
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi start letting new in connections to the new server. */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->to_move = timeout_add(dir->set->director_user_kick_delay * 1000,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_user_kill_finish_delayed_to, ctx);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistruct director_kill_context {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct director *dir;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi unsigned int username_hash;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi bool self;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi};
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainenstatic void
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomidirector_finish_user_kill(struct director *dir, struct user *user, bool self)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_assert(user->kill_state != USER_KILL_STATE_DELAY);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen if (dir->right == NULL) {
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen /* we're alone */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_user_kill_finish_delayed(dir, user);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi } else if (self ||
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->kill_state == USER_KILL_STATE_KILLING_NOTIFY_RECEIVED) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_connection_send(dir->right, t_strdup_printf(
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi "USER-KILLED\t%u\n", user->username_hash));
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->kill_state = USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi } else {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_assert(user->kill_state == USER_KILL_STATE_KILLING);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->kill_state = USER_KILL_STATE_KILLED_WAITING_FOR_NOTIFY;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistatic void director_kill_user_callback(enum ipc_client_cmd_state state,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi const char *data, void *context)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct director_kill_context *ctx = context;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct user *user;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* this is an asynchronous notification about user being killed.
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi there are no guarantees about what might have happened to the user
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi in the mean time. */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi switch (state) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi case IPC_CLIENT_CMD_STATE_REPLY:
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* shouldn't get here. the command reply isn't finished yet. */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi return;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi case IPC_CLIENT_CMD_STATE_OK:
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi break;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi case IPC_CLIENT_CMD_STATE_ERROR:
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_error("Failed to kill user %u connections: %s",
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen ctx->username_hash, data);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* we can't really do anything but continue anyway */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi break;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user = user_directory_lookup(ctx->dir->users, ctx->username_hash);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi if (user == NULL) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* user was already freed - ignore */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi } else if (user->kill_state == USER_KILL_STATE_KILLING ||
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->kill_state == USER_KILL_STATE_KILLING_NOTIFY_RECEIVED) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* we were still waiting for the kill notification */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_finish_user_kill(ctx->dir, user, ctx->self);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi } else {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* we don't currently want to kill the user */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_free(ctx);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistatic void director_user_move_timeout(struct user *user)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_assert(user->kill_state != USER_KILL_STATE_DELAY);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_error("Finishing user %u move timed out, "
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi "its state may now be inconsistent", user->username_hash);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->kill_state = USER_KILL_STATE_NONE;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi timeout_remove(&user->to_move);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomivoid director_move_user(struct director *dir, struct director_host *src,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct director_host *orig_src,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi unsigned int username_hash, struct mail_host *host)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct user *user;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi const char *cmd;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct director_kill_context *ctx;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* 1. move this user's host, and set its "killing" flag to delay all of
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen its future connections until all directors have killed the
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen connections and notified us about it.
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen 2. tell the other directors about the move
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen 3. once user kill callback is called, tell the other directors
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi with USER-KILLED that we're done killing the user.
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen 4. when some director gets a duplicate USER-KILLED, it's
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen responsible for notifying all directors that user is completely
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen killed.
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen 5. after receiving USER-KILLED-EVERYWHERE notification,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen new connections are again allowed for the user.
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user = user_directory_lookup(dir->users, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (user == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user = user_directory_add(dir->users, username_hash,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen host, ioloop_time);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi } else {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi if (user->host == host) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi /* user is already in this host */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi return;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->host->user_count--;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->host = host;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->host->user_count++;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->timestamp = ioloop_time;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (user->kill_state == USER_KILL_STATE_NONE) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ctx = i_new(struct director_kill_context, 1);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ctx->dir = dir;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ctx->username_hash = username_hash;
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen ctx->self = src->self;
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen user->to_move = timeout_add(DIRECTOR_USER_MOVE_TIMEOUT_MSECS,
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen director_user_move_timeout, user);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->kill_state = USER_KILL_STATE_KILLING;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen cmd = t_strdup_printf("proxy\t*\tKICK-DIRECTOR-HASH\t%u",
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ipc_client_cmd(dir->ipc_proxy, cmd,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_kill_user_callback, ctx);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (orig_src == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src = dir->self_host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src->last_seq++;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_update_send(dir, src, t_strdup_printf(
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen "USER-MOVE\t%s\t%u\t%u\t%u\t%s\n",
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen user->username_hash, net_ip2addr(&user->host->ip)));
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_kick_user_callback(enum ipc_client_cmd_state state ATTR_UNUSED,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *data ATTR_UNUSED,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen void *context ATTR_UNUSED)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenvoid director_kick_user(struct director *dir, struct director_host *src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *orig_src, const char *username)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *cmd;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen cmd = t_strdup_printf("proxy\t*\tKICK\t%s", username);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen ipc_client_cmd(dir->ipc_proxy, cmd,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen director_kick_user_callback, (void *)NULL);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen if (orig_src == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src = dir->self_host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src->last_seq++;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen cmd = t_strdup_printf("USER-KICK\t%s\t%u\t%u\t%s\n",
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen username);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK, cmd);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen}
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenvoid director_kick_user_hash(struct director *dir, struct director_host *src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *orig_src,
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen unsigned int username_hash,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const struct ip_addr *except_ip)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *cmd;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen cmd = t_strdup_printf("proxy\t*\tKICK-DIRECTOR-HASH\t%u\t%s",
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen username_hash, net_ip2addr(except_ip));
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen ipc_client_cmd(dir->ipc_proxy, cmd,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen director_kick_user_callback, (void *)NULL);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (orig_src == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src = dir->self_host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src->last_seq++;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen cmd = t_strdup_printf("USER-KICK-HASH\t%s\t%u\t%u\t%u\t%s\n",
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen username_hash, net_ip2addr(except_ip));
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK, cmd);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen}
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen
488d92156e431ef201faf75910955588d0b768e3Timo Sirainenvoid director_user_killed(struct director *dir, unsigned int username_hash)
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen{
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen struct user *user;
6f8d511666b292196f305d40b9e5e8b017c27a3cTimo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user = user_directory_lookup(dir->users, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (user == NULL)
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen return;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen switch (user->kill_state) {
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen case USER_KILL_STATE_KILLING:
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen user->kill_state = USER_KILL_STATE_KILLING_NOTIFY_RECEIVED;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen break;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen case USER_KILL_STATE_KILLED_WAITING_FOR_NOTIFY:
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_finish_user_kill(dir, user, TRUE);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen case USER_KILL_STATE_NONE:
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen case USER_KILL_STATE_DELAY:
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen case USER_KILL_STATE_KILLING_NOTIFY_RECEIVED:
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen break;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen case USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE:
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen director_user_killed_everywhere(dir, dir->self_host,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen NULL, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
ffedd89747e11373c0dd3a172d3e94e0cf724fd7Timo Sirainen}
ffedd89747e11373c0dd3a172d3e94e0cf724fd7Timo Sirainen
ffedd89747e11373c0dd3a172d3e94e0cf724fd7Timo Sirainenvoid director_user_killed_everywhere(struct director *dir,
ffedd89747e11373c0dd3a172d3e94e0cf724fd7Timo Sirainen struct director_host *src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *orig_src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int username_hash)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct user *user;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user = user_directory_lookup(dir->users, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (user == NULL ||
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->kill_state != USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_user_kill_finish_delayed(dir, user);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (orig_src == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src = dir->self_host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen orig_src->last_seq++;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_update_send(dir, src, t_strdup_printf(
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen "USER-KILLED-EVERYWHERE\t%s\t%u\t%u\t%u\n",
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->username_hash));
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void director_state_callback_timeout(struct director *dir)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen timeout_remove(&dir->to_callback);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen dir->state_change_callback(dir);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenvoid director_set_state_changed(struct director *dir)
32a93320fd2b6ada5ac8027166819463c1a007b6Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen /* we may get called to here from various places. use a timeout to
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen make sure the state callback is called with a clean state. */
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (dir->to_callback == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen dir->to_callback =
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen timeout_add(0, director_state_callback_timeout, dir);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenvoid director_update_send(struct director *dir, struct director_host *src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *cmd)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_update_send_version(dir, src, 0, cmd);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenvoid director_update_send_version(struct director *dir,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int min_version, const char *cmd)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_connection *const *connp;
ac1118842c3d80285e32d2cd53bda3e95e5be217Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_assert(src != NULL);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen array_foreach(&dir->connections, connp) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (director_connection_get_host(*connp) != src &&
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_connection_get_minor_version(*connp) >= min_version)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_connection_send(*connp, cmd);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstruct director *
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_init(const struct director_settings *set,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const struct ip_addr *listen_ip, in_port_t listen_port,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_state_change_callback_t *callback)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director *dir;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir = i_new(struct director, 1);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir->set = set;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir->self_port = listen_port;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir->self_ip = *listen_ip;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir->state_change_callback = callback;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen i_array_init(&dir->dir_hosts, 16);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen i_array_init(&dir->pending_requests, 16);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen i_array_init(&dir->connections, 8);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir->users = user_directory_init(set->director_user_expire,
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen set->director_username_hash);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen dir->mail_hosts = mail_hosts_init(set->director_consistent_hashing);
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen dir->ipc_proxy = ipc_client_init(DIRECTOR_IPC_PROXY_PATH);
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen dir->ring_min_version = DIRECTOR_VERSION_MINOR;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen return dir;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen}
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainenvoid director_deinit(struct director **_dir)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen{
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen struct director *dir = *_dir;
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen struct director_host *const *hostp, *host;
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen struct director_connection *conn, *const *connp;
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen *_dir = NULL;
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen while (array_count(&dir->connections) > 0) {
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen connp = array_idx(&dir->connections, 0);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen conn = *connp;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen director_connection_deinit(&conn, "Shutting down");
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen }
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen user_directory_deinit(&dir->users);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen mail_hosts_deinit(&dir->mail_hosts);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen mail_hosts_deinit(&dir->orig_config_hosts);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen ipc_client_deinit(&dir->ipc_proxy);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (dir->to_reconnect != NULL)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen timeout_remove(&dir->to_reconnect);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (dir->to_handshake_warning != NULL)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen timeout_remove(&dir->to_handshake_warning);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (dir->to_request != NULL)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen timeout_remove(&dir->to_request);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (dir->to_sync != NULL)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen timeout_remove(&dir->to_sync);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (dir->to_remove_dirs != NULL)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen timeout_remove(&dir->to_remove_dirs);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (dir->to_callback != NULL)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen timeout_remove(&dir->to_callback);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen while (array_count(&dir->dir_hosts) > 0) {
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen hostp = array_idx(&dir->dir_hosts, 0);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen host = *hostp;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen director_host_free(&host);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen }
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen array_free(&dir->pending_requests);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen array_free(&dir->dir_hosts);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen array_free(&dir->connections);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen i_free(dir);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen}
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainenvoid dir_debug(const char *fmt, ...)
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen{
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen va_list args;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen if (!director_debug)
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen return;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen va_start(args, fmt);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen T_BEGIN {
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen i_debug("%s", t_strdup_vprintf(fmt, args));
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen } T_END;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen va_end(args);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen}
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen