bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 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 "log-throttle.h"
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#include "ipc-client.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "program-client.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "var-expand.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "istream.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "ostream.h"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#include "iostream-temp.h"
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen#include "mail-user-hash.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "user-directory.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#define DIRECTOR_IPC_PROXY_PATH "ipc"
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi#define DIRECTOR_DNS_SOCKET_PATH "dns-client"
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen#define DIRECTOR_RECONNECT_RETRY_SECS 60
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen#define DIRECTOR_RECONNECT_TIMEOUT_MSECS (30*1000)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#define DIRECTOR_USER_MOVE_TIMEOUT_MSECS (30*1000)
4865df74dad010a65ab63734b3ca1349ce38dc57Timo Sirainen#define DIRECTOR_SYNC_TIMEOUT_MSECS (5*1000)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen#define DIRECTOR_RING_MIN_WAIT_SECS 20
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen#define DIRECTOR_QUICK_RECONNECT_TIMEOUT_MSECS 1000
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen#define DIRECTOR_DELAYED_DIR_REMOVE_MSECS (1000*30)
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainenbool director_debug;
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenconst char *user_kill_state_names[USER_KILL_STATE_DELAY+1] = {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "none",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "killing",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "notify-received",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "waiting-for-notify",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "waiting-for-everyone",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "flushing",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen "delay",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen};
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenstatic struct log_throttle *user_move_throttle;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenstatic struct log_throttle *user_kill_fail_throttle;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
eb5809d0666810ff5ba9da188e1e4e2092ee0eeaTimo Sirainenstatic void director_hosts_purge_removed(struct director *dir);
eb5809d0666810ff5ba9da188e1e4e2092ee0eeaTimo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenstatic const struct log_throttle_settings director_log_throttle_settings = {
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen .throttle_at_max_per_interval = 100,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen .unthrottle_at_max_per_interval = 2,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen};
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistatic void
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomidirector_user_kill_finish_delayed(struct director *dir, struct user *user,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi bool skip_delay);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool director_is_self_ip_set(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
db623deb12c3566618faba5a35a44ceed83c3dc0Martti Rannanjärvi if (net_ip_compare(&dir->self_ip, &net_ip4_any))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
db623deb12c3566618faba5a35a44ceed83c3dc0Martti Rannanjärvi if (net_ip_compare(&dir->self_ip, &net_ip6_any))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_find_self_ip(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hosts;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hosts = array_get(&dir->dir_hosts, &count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 0; i < count; i++) {
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen if (net_try_bind(&hosts[i]->ip) == 0) {
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen dir->self_ip = hosts[i]->ip;
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen return;
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen i_fatal("director_servers doesn't list ourself");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainenvoid director_find_self(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->self_host != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
34a45b80c8ed18861c6e343fe40adbe360fc6badTimo Sirainen if (!director_is_self_ip_set(dir))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_find_self_ip(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_host = director_host_lookup(dir, &dir->self_ip,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->self_host == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_fatal("director_servers doesn't list ourself (%s:%u)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&dir->self_ip), dir->self_port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_host->self = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic unsigned int director_find_self_idx(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo 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
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainenstatic bool
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainendirector_has_outgoing_connection(struct director *dir,
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen struct director_host *host)
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen{
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen struct director_connection *const *connp;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen array_foreach(&dir->connections, connp) {
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen if (director_connection_get_host(*connp) == host &&
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen !director_connection_is_incoming(*connp))
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen return TRUE;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen }
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen return FALSE;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen}
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainenstatic void
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainendirector_log_connect(struct director *dir, struct director_host *host,
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen const char *reason)
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen{
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen string_t *str = t_str_new(128);
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen if (host->last_network_failure > 0) {
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen str_printfa(str, ", last network failure %ds ago",
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen (int)(ioloop_time - host->last_network_failure));
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen }
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen if (host->last_protocol_failure > 0) {
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen str_printfa(str, ", last protocol failure %ds ago",
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen (int)(ioloop_time - host->last_protocol_failure));
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen }
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen i_info("Connecting to %s:%u (as %s%s): %s",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host->port,
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen net_ip2addr(&dir->self_ip), str_c(str), reason);
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen}
e9d302dceba09ceefa0aaddf7eafafd760cd1736Timo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainenint director_connect_host(struct director *dir, struct director_host *host,
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen const char *reason)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen if (director_has_outgoing_connection(dir, host))
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_log_connect(dir, host, reason);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen port = dir->test_port != 0 ? dir->test_port : host->port;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen fd = net_connect_ip(&host->ip, port, &dir->self_ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (fd == -1) {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen host->last_network_failure = ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("connect(%s) failed: %m", host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen /* Reset timestamp so that director_connect() won't skip this host
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen while we're still trying to connect to it */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen host->last_network_failure = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)director_connection_init_out(dir, fd, host);
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic struct director_host *
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_get_preferred_right_host(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *const *hosts, *host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int i, count, self_idx;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen hosts = array_get(&dir->dir_hosts, &count);
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen if (count == 1) {
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen /* self */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return NULL;
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen self_idx = director_find_self_idx(dir);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen for (i = 0; i < count; i++) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host = hosts[(self_idx + i + 1) % count];
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (!host->removed)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* self, with some removed hosts */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return NULL;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainenstatic void director_quick_reconnect_retry(struct director *dir)
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen{
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_connect(dir, "Alone in director ring - trying to connect to others");
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen}
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainenstatic bool director_wait_for_others(struct director *dir)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen{
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen struct director_host *const *hostp;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* don't assume we're alone until we've attempted to connect
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen to others for a while */
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->ring_first_alone != 0 &&
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen ioloop_time - dir->ring_first_alone > DIRECTOR_RING_MIN_WAIT_SECS)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen return FALSE;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->ring_first_alone == 0)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->ring_first_alone = ioloop_time;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* reset all failures and try again */
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen array_foreach(&dir->dir_hosts, hostp) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen (*hostp)->last_network_failure = 0;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen (*hostp)->last_protocol_failure = 0;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen }
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_reconnect);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->to_reconnect = timeout_add(DIRECTOR_QUICK_RECONNECT_TIMEOUT_MSECS,
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_quick_reconnect_retry, dir);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen return TRUE;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen}
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainenvoid director_connect(struct director *dir, const char *reason)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hosts;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, count, self_idx;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen self_idx = director_find_self_idx(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* try to connect to first working server on our right side.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen the left side is supposed to connect to us. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hosts = array_get(&dir->dir_hosts, &count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 1; i < count; i++) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int idx = (self_idx + i) % count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (hosts[idx]->removed)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen continue;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (hosts[idx]->last_network_failure +
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen DIRECTOR_RECONNECT_RETRY_SECS > ioloop_time) {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* connection failed recently, don't try retrying here */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen continue;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen }
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (hosts[idx]->last_protocol_failure +
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen DIRECTOR_PROTOCOL_FAILURE_RETRY_SECS > ioloop_time) {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* the director recently sent invalid protocol data,
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen don't try retrying yet */
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen continue;
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen }
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen if (director_connect_host(dir, hosts[idx], reason) == 0) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* success */
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (count > 1 && director_wait_for_others(dir))
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen return;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* we're the only one */
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (count > 1) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen i_warning("director: Couldn't connect to right side, "
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen "we must be the only director left");
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen if (dir->left != NULL) {
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen /* since we couldn't connect to it,
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen it must have failed recently */
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_warning("director: Assuming %s is dead, disconnecting",
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_get_name(dir->left));
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&dir->left,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo 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);
aa7e573b32f014d8736333fe271ea606c5709f82Timo Sirainen else if (!dir->ring_synced)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_set_ring_synced(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainenvoid director_set_ring_handshaked(struct director *dir)
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(!dir->ring_handshaked);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_handshake_warning);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen if (dir->ring_handshake_warning_sent) {
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen i_warning("Directors have been connected, "
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen "continuing delayed requests");
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen dir->ring_handshake_warning_sent = FALSE;
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen }
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Director ring handshaked");
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen dir->ring_handshaked = TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_set_ring_synced(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void director_reconnect_timeout(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *cur_host, *preferred_host =
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_get_preferred_right_host(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen cur_host = dir->right == NULL ? NULL :
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_get_host(dir->right);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen if (preferred_host == NULL) {
42401be443f96c91a20fc976d66ca626fa6e14ecTimo Sirainen /* all directors have been removed, try again later */
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen } else if (cur_host != preferred_host) {
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen (void)director_connect_host(dir, preferred_host,
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen "Reconnect attempt to preferred director");
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo 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
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(!dir->ring_synced);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert((dir->left != NULL && dir->right != NULL) ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen (dir->left == NULL && dir->right == NULL));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_handshake_warning);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->ring_handshake_warning_sent) {
56c69b4b17af0b5a2c71705d5edae746f00780b9Timo Sirainen i_warning("Ring is synced, continuing delayed requests "
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen "(syncing took %d secs, hosts_hash=%u)",
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen (int)(ioloop_time - dir->ring_last_sync_time),
1574df6b0bc965212f1152e480e7a762cdaa8226Timo 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);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_reconnect);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (host != director_get_preferred_right_host(dir)) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* try to reconnect to preferred host later */
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen dir->to_reconnect =
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen timeout_add(DIRECTOR_RECONNECT_TIMEOUT_MSECS,
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen director_reconnect_timeout, dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen if (dir->left != NULL)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_set_synced(dir->left, TRUE);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen if (dir->right != NULL)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_set_synced(dir->right, TRUE);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_sync);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen dir->ring_synced = TRUE;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen dir->ring_last_sync_time = ioloop_time;
eb5809d0666810ff5ba9da188e1e4e2092ee0eeaTimo Sirainen /* If there are any director hosts still marked as "removed", we can
eb5809d0666810ff5ba9da188e1e4e2092ee0eeaTimo Sirainen safely remove those now. The entire director cluster knows about the
eb5809d0666810ff5ba9da188e1e4e2092ee0eeaTimo Sirainen removal now. */
eb5809d0666810ff5ba9da188e1e4e2092ee0eeaTimo Sirainen director_hosts_purge_removed(dir);
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen mail_hosts_set_synced(dir->mail_hosts);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen director_set_state_changed(dir);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen}
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainenvoid director_sync_send(struct director *dir, struct director_host *host,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen uint32_t seq, unsigned int minor_version,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen unsigned int timestamp, unsigned int hosts_hash)
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen{
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen string_t *str;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen if (host == dir->self_host) {
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen dir->last_sync_sent_ring_change_counter = dir->ring_change_counter;
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen dir->last_sync_start_time = ioloop_timeval;
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen }
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen str = t_str_new(128);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen str_printfa(str, "SYNC\t%s\t%u\t%u",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host->port, seq);
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen if (minor_version > 0 &&
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen director_connection_get_minor_version(dir->right) > 0) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen /* only minor_version>0 supports extra parameters */
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen str_printfa(str, "\t%u\t%u\t%u", minor_version,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen timestamp, hosts_hash);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen }
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen str_append_c(str, '\n');
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_connection_send(dir->right, str_c(str));
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* ping our connections in case either of them are hanging.
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if they are, we want to know it fast. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (dir->left != NULL)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_ping(dir->left);
7be1a5530fcb414588fbe90eaed65eff83e84737Timo Sirainen director_connection_ping(dir->right);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen}
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainenstatic bool
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainendirector_has_any_outgoing_connections(struct director *dir)
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen{
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen struct director_connection *const *connp;
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen array_foreach(&dir->connections, connp) {
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen if (!director_connection_is_incoming(*connp))
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen return TRUE;
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen }
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen return FALSE;
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen}
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainenbool director_resend_sync(struct director *dir)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen{
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen if (dir->ring_synced) {
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen /* everything ok, no need to do anything */
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen return FALSE;
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen }
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen if (dir->right == NULL) {
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen /* right side connection is missing. make sure we're not
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen hanging due to some bug. */
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen if (dir->to_reconnect == NULL &&
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen !director_has_any_outgoing_connections(dir)) {
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen i_warning("Right side connection is unexpectedly lost, reconnecting");
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen director_connect(dir, "Right side connection lost");
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen }
d5967394396acaa4aaa249ea973423aa5b9c38edTimo Sirainen } else if (dir->left != NULL) {
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen /* send a new SYNC in case the previous one got dropped */
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen dir->self_host->last_sync_timestamp = ioloop_time;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_sync_send(dir, dir->self_host, dir->sync_seq,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen DIRECTOR_VERSION_MINOR, ioloop_time,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen mail_hosts_hash(dir->mail_hosts));
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (dir->to_sync != NULL)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen timeout_reset(dir->to_sync);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen return TRUE;
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen }
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen return FALSE;
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen}
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainenstatic void director_sync_timeout(struct director *dir)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen{
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen i_assert(!dir->ring_synced);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (director_resend_sync(dir))
3a7a0c35c9f827f86fb437e640287f3a467ef692Timo Sirainen i_error("Ring SYNC seq=%u appears to have got lost, resending", dir->sync_seq);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen}
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainenvoid director_set_ring_unsynced(struct director *dir)
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen{
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen if (dir->ring_synced) {
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen dir->ring_synced = FALSE;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen dir->ring_last_sync_time = ioloop_time;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo 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 }
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen}
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainenstatic void director_sync(struct director *dir)
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen{
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen /* we're synced again when we receive this SYNC back */
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen dir->sync_seq++;
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen if (dir->right == NULL && dir->left == NULL) {
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen /* we're alone. if we're already synced,
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen don't become unsynced. */
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen return;
c88275be7fcb92b10f412cecdd6c2ceaae17917eTimo Sirainen }
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen director_set_ring_unsynced(dir);
002f2544421891472dc9aeb79d3abdde6a8ed4c8Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->sync_frozen) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_pending = TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(!dir->ring_synced ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen (dir->left == NULL && dir->right == NULL));
465fb89a877b778f68734f6cc36db9ce2a4a0a71Timo Sirainen dir_debug("Ring is desynced (seq=%u, no right connection)",
465fb89a877b778f68734f6cc36db9ce2a4a0a71Timo Sirainen dir->sync_seq);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Ring is desynced (seq=%u, sending SYNC to %s)",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir->sync_seq, dir->right == NULL ? "(nowhere)" :
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen director_connection_get_name(dir->right));
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen /* send PINGs to our connections more rapidly until we've synced again.
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen if the connection has actually died, we don't need to wait (and
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen delay requests) for as long to detect it */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->left != NULL)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_set_synced(dir->left, FALSE);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_set_synced(dir->right, FALSE);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen director_sync_send(dir, dir->self_host, dir->sync_seq,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen DIRECTOR_VERSION_MINOR, ioloop_time,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen mail_hosts_hash(dir->mail_hosts));
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen}
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_sync_freeze(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_connection *const *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(!dir->sync_frozen);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(!dir->sync_pending);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen array_foreach(&dir->connections, connp)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_cork(*connp);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_frozen = TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_sync_thaw(struct director *dir)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_connection *const *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(dir->sync_frozen);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_frozen = FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->sync_pending) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_pending = FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen array_foreach(&dir->connections, connp)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_uncork(*connp);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid director_notify_ring_added(struct director_host *added_host,
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen struct director_host *src, bool log)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const char *cmd;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen if (log) {
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen i_info("Adding director %s to ring (requested by %s)",
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen added_host->name, src->name);
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen }
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen added_host->dir->ring_change_counter++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cmd = t_strdup_printf("DIRECTOR\t%s\t%u\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen added_host->ip_str, added_host->port);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_update_send(added_host->dir, src, cmd);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
de69258ceb035b1e08301dc70e257bef341dea85Timo Sirainenstatic void director_hosts_purge_removed(struct director *dir)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo 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);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo 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
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen i_info("Removing director %s from ring (requested by %s)",
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen removed_host->name, src->name);
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen if (removed_host->self && !src->self) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* others will just disconnect us */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen if (!removed_host->self) {
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen /* mark the host as removed and fully remove it later. this
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen delay is needed, because the removal may trigger director
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen reconnections, which may send the director back and we don't
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen want to re-add it */
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen removed_host->removed = TRUE;
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen if (dir->to_remove_dirs == NULL) {
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen dir->to_remove_dirs =
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen timeout_add(DIRECTOR_DELAYED_DIR_REMOVE_MSECS,
de69258ceb035b1e08301dc70e257bef341dea85Timo Sirainen director_hosts_purge_removed, dir);
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
83b9d8afc2776ebf61ddb77b85241f2591ef7f7bTimo Sirainen /* if our left or ride side gets removed, notify them first
83b9d8afc2776ebf61ddb77b85241f2591ef7f7bTimo Sirainen before disconnecting. */
83b9d8afc2776ebf61ddb77b85241f2591ef7f7bTimo Sirainen cmd = t_strdup_printf("DIRECTOR-REMOVE\t%s\t%u\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen removed_host->ip_str, removed_host->port);
83b9d8afc2776ebf61ddb77b85241f2591ef7f7bTimo Sirainen director_update_send_version(dir, src,
83b9d8afc2776ebf61ddb77b85241f2591ef7f7bTimo Sirainen DIRECTOR_VERSION_RING_REMOVE, cmd);
83b9d8afc2776ebf61ddb77b85241f2591ef7f7bTimo 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];
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen if (director_connection_get_host(conn) != removed_host ||
b0421c7397be2146988ee3afb5dcc491c01206ccTimo Sirainen removed_host->self)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen else {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo 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)
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_connect(dir, "Reconnecting after director was removed");
30089b563dd385f9b18835af2c5a47de2b560660Timo Sirainen director_sync(dir);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainenstatic void
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainendirector_send_host(struct director *dir, struct director_host *src,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct director_host *orig_src,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct mail_host *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen const char *host_tag = mail_host_get_tag(host);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen string_t *str;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (orig_src == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src = dir->self_host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src->last_seq++;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str = t_str_new(128);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str_printfa(str, "HOST\t%s\t%u\t%u\t%s\t%u",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host->vhost_count);
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen if (dir->ring_min_version >= DIRECTOR_VERSION_TAGS_V2) {
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen str_append_c(str, '\t');
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen str_append_tabescaped(str, host_tag);
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen } else if (host_tag[0] != '\0' &&
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen dir->ring_min_version < DIRECTOR_VERSION_TAGS_V2) {
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen if (dir->ring_min_version < DIRECTOR_VERSION_TAGS) {
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen i_error("Ring has directors that don't support tags - removing host %s with tag '%s'",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host_tag);
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen } else {
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen i_error("Ring has directors that support mixed versions of tags - removing host %s with tag '%s'",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host_tag);
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen director_remove_host(dir, NULL, NULL, host);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen return;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (dir->ring_min_version >= DIRECTOR_VERSION_UPDOWN) {
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen str_printfa(str, "\t%c%ld\t", host->down ? 'D' : 'U',
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen (long)host->last_updown_change);
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen /* add any further version checks here - these directors ignore
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen any extra unknown arguments */
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen if (host->hostname != NULL)
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen str_append_tabescaped(str, host->hostname);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str_append_c(str, '\n');
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen director_update_send(dir, src, str_c(str));
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen}
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainenvoid director_resend_hosts(struct director *dir)
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen{
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct mail_host *const *hostp;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen array_foreach(mail_hosts_get(dir->mail_hosts), hostp)
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen director_send_host(dir, dir->self_host, NULL, *hostp);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen}
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainenvoid director_update_host(struct director *dir, struct director_host *src,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct director_host *orig_src,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct mail_host *host)
abe29107f5dce932d28a00912d2d75a01021bef1Timo 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)",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host->vhost_count, host->down ? 1 : 0,
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);
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen /* mark the host desynced until ring is synced again. except if we're
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen alone in the ring that never happens. */
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen if (dir->right != NULL || dir->left != NULL)
a93c909cfa1139226891d198dc6f7a7c98509b49Timo Sirainen host->desynced = TRUE;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen director_sync(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_remove_host(struct director *dir, struct director_host *src,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *orig_src,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct user_directory *users = host->tag->users;
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (src != NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (orig_src == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src = dir->self_host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src->last_seq++;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_update_send(dir, src, t_strdup_printf(
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen "HOST-REMOVE\t%s\t%u\t%u\t%s\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->last_seq, host->ip_str));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen user_directory_remove_host(users, host);
87842f621233257b7a7945d994ba931508b34877Timo Sirainen mail_host_remove(host);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen director_sync(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenvoid director_flush_host(struct director *dir, struct director_host *src,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *orig_src,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct mail_host *host)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct user_directory *users = host->tag->users;
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (orig_src == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src = dir->self_host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen orig_src->last_seq++;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen director_update_send(dir, src, t_strdup_printf(
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen "HOST-FLUSH\t%s\t%u\t%u\t%s\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str));
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen user_directory_remove_host(users, host);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen director_sync(dir);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_update_user(struct director *dir, struct director_host *src,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen struct director_connection *const *connp;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen i_assert(src != NULL);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen i_assert(!user->weak);
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen array_foreach(&dir->connections, connp) {
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen if (director_connection_get_host(*connp) == src)
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen continue;
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen if (director_connection_get_minor_version(*connp) >= DIRECTOR_VERSION_USER_TIMESTAMP) {
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen director_connection_send(*connp, t_strdup_printf(
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen "USER\t%u\t%s\t%u\n", user->username_hash, user->host->ip_str,
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen user->timestamp));
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen } else {
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen director_connection_send(*connp, t_strdup_printf(
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen "USER\t%u\t%s\n", user->username_hash, user->host->ip_str));
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen }
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen}
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenvoid director_update_user_weak(struct director *dir, struct director_host *src,
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen struct director_connection *src_conn,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct director_host *orig_src,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct user *user)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen{
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen const char *cmd;
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo 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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->username_hash, user->host->ip_str);
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen if (src != dir->self_host && dir->left != NULL && dir->right != NULL &&
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_connection_get_host(dir->left) ==
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_connection_get_host(dir->right)) {
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen /* only two directors in this ring and we're forwarding
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen USER-WEAK from one director back to itself via another
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen so it sees we've received it. we can't use
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_update_send() for this, because it doesn't send
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen data back to the source. */
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen if (dir->right == src_conn)
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_connection_send(dir->left, cmd);
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen else if (dir->left == src_conn)
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo 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 }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistatic void
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainendirector_flush_user_continue(int result, struct director_kill_context *ctx)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct director *dir = ctx->dir;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->callback_pending = FALSE;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct user *user = user_directory_lookup(ctx->tag->users,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi ctx->username_hash);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi if (result == 0) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct istream *is = iostream_temp_finish(&ctx->reply, (size_t)-1);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi char *data;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_stream_set_return_partial_line(is, TRUE);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi data = i_stream_read_next_line(is);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_error("%s: Failed to flush user hash %u in host %s: %s",
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi ctx->socket_path,
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen ctx->username_hash,
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen net_ip2addr(&ctx->host_ip),
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi data == NULL ? "(no output to stdout)" : data);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi while((data = i_stream_read_next_line(is)) != NULL) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_error("%s: Failed to flush user hash %u in host %s: %s",
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi ctx->socket_path,
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen ctx->username_hash,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen net_ip2addr(&ctx->host_ip), data);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_stream_unref(&is);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi } else {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi o_stream_unref(&ctx->reply);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi program_client_destroy(&ctx->pclient);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (!DIRECTOR_KILL_CONTEXT_IS_VALID(user, ctx)) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* user was already freed - ignore */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen dir_debug("User %u freed while flushing, result=%d",
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->username_hash, result);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(ctx->to_move == NULL);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_free(ctx);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen } else {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* ctx is freed later via user->kill_ctx */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen dir_debug("Flushing user %u finished, result=%d",
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->username_hash, result);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen director_user_kill_finish_delayed(dir, user, result == 1);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomistatic void
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomidirector_flush_user(struct director *dir, struct user *user)
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct director_kill_context *ctx = user->kill_ctx;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct var_expand_table tab[] = {
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen { 'i', user->host->ip_str, "ip" },
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi { 'h', user->host->hostname, "host" },
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi { '\0', NULL, NULL }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi };
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *error;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
6af8cc0573832465c621bcd91634e15461e8bf58Timo Sirainen /* Execute flush script, if set. Only the director that started the
6af8cc0573832465c621bcd91634e15461e8bf58Timo Sirainen user moving will call the flush script. Having each director do it
6af8cc0573832465c621bcd91634e15461e8bf58Timo Sirainen would be redundant since they're all supposed to be performing the
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen same flush task to the same backend.
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen Flushing is also not triggered if we're moving a user that we just
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen created due to the user move. This means that the user doesn't have
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen an old host, so we couldn't really even perform any flushing on the
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen backend. */
6af8cc0573832465c621bcd91634e15461e8bf58Timo Sirainen if (*dir->set->director_flush_socket == '\0' ||
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen ctx->old_host_ip.family == 0 ||
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen !ctx->kill_is_self_initiated) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_user_kill_finish_delayed(dir, user, FALSE);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi return;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
9faac59f664d4003d1412278ac8db4aad1c2067cTimo Sirainen ctx->host_ip = user->host->ip;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi string_t *s_sock = str_new(default_pool, 32);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (var_expand(s_sock, dir->set->director_flush_socket, tab, &error) <= 0) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen i_error("Failed to expand director_flush_socket=%s: %s",
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen dir->set->director_flush_socket, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen director_user_kill_finish_delayed(dir, user, FALSE);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi ctx->socket_path = str_free_without_data(&s_sock);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi struct program_client_settings set = {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi .client_connect_timeout_msecs = 10000,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi .dns_client_socket_path = DIRECTOR_DNS_SOCKET_PATH,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi };
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi restrict_access_init(&set.restrict_set);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen const char *const args[] = {
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen "FLUSH",
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen t_strdup_printf("%u", user->username_hash),
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen net_ip2addr(&ctx->old_host_ip),
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->host->ip_str,
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen ctx->old_host_down ? "down" : "up",
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen dec2str(ctx->old_host_vhost_count),
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen NULL
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen };
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->kill_state = USER_KILL_STATE_FLUSHING;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("Flushing user %u via %s", user->username_hash,
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen ctx->socket_path);
f9c76559302e6485f59ab0e6050b76fd6d268feeTimo Sirainen
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi if ((program_client_create(ctx->socket_path, args, &set, FALSE,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi &ctx->pclient, &error)) != 0) {
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi i_error("%s: Failed to flush user hash %u in host %s: %s",
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi ctx->socket_path,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi user->username_hash,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->host->ip_str,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi error);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_flush_user_continue(0, ctx);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi return;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi ctx->reply =
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi iostream_temp_create_named("/tmp", 0,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi t_strdup_printf("flush response from %s",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->host->ip_str));
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi o_stream_set_no_error_handling(ctx->reply, TRUE);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi program_client_set_output(ctx->pclient, ctx->reply);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->callback_pending = TRUE;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi program_client_run_async(ctx->pclient, director_flush_user_continue, ctx);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi}
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainenstatic void director_user_move_finished(struct director *dir)
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen{
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen i_assert(dir->users_moving_count > 0);
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen dir->users_moving_count--;
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen director_set_state_changed(dir);
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen}
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenstatic void director_user_move_free(struct user *user)
3751234328db786e53680f4df21a4d10b446e252Timo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct director *dir = user->kill_ctx->dir;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct director_kill_context *kill_ctx = user->kill_ctx;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(kill_ctx != NULL);
3751234328db786e53680f4df21a4d10b446e252Timo Sirainen
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("User %u move finished at state=%s", user->username_hash,
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user_kill_state_names[kill_ctx->kill_state]);
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&kill_ctx->to_move);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_free(kill_ctx->socket_path);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_free(kill_ctx);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user->kill_ctx = NULL;
3751234328db786e53680f4df21a4d10b446e252Timo Sirainen
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen director_user_move_finished(dir);
3751234328db786e53680f4df21a4d10b446e252Timo Sirainen}
3751234328db786e53680f4df21a4d10b446e252Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainendirector_user_kill_finish_delayed_to(struct user *user)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(user->kill_ctx != NULL);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(user->kill_ctx->kill_state == USER_KILL_STATE_DELAY);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen director_user_move_free(user);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomidirector_user_kill_finish_delayed(struct director *dir, struct user *user,
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi bool skip_delay)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi if (skip_delay) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user->kill_ctx->kill_state = USER_KILL_STATE_NONE;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen director_user_move_free(user);
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi return;
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi }
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user->kill_ctx->kill_state = USER_KILL_STATE_DELAY;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen /* wait for a while for the kills to finish in the backend server,
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen so there are no longer any processes running for the user before we
3e10cd470988298dc2b37f548ad03da4d7c11ffaTimo Sirainen start letting new in connections to the new server. */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen timeout_remove(&user->kill_ctx->to_move);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user->kill_ctx->to_move =
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen timeout_add(dir->set->director_user_kick_delay * 1000,
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen director_user_kill_finish_delayed_to, user);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_finish_user_kill(struct director *dir, struct user *user, bool self)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct director_kill_context *kill_ctx = user->kill_ctx;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(kill_ctx != NULL);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(kill_ctx->kill_state != USER_KILL_STATE_FLUSHING);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(kill_ctx->kill_state != USER_KILL_STATE_DELAY);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen dir_debug("User %u kill finished - %sstate=%s", user->username_hash,
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen self ? "we started it " : "",
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen user_kill_state_names[kill_ctx->kill_state]);
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (dir->right == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen /* we're alone */
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_flush_user(dir, user);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen } else if (self ||
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen kill_ctx->kill_state == USER_KILL_STATE_KILLING_NOTIFY_RECEIVED) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_connection_send(dir->right, t_strdup_printf(
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen "USER-KILLED\t%u\n", user->username_hash));
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen kill_ctx->kill_state = USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen } else {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(kill_ctx->kill_state == USER_KILL_STATE_KILLING);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen kill_ctx->kill_state = USER_KILL_STATE_KILLED_WAITING_FOR_NOTIFY;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenstatic void director_user_kill_fail_throttled(unsigned int new_events_count,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen void *context ATTR_UNUSED)
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen{
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen i_error("Failed to kill %u users' connections", new_events_count);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen}
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void director_kill_user_callback(enum ipc_client_cmd_state state,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *data, void *context)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_kill_context *ctx = context;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct user *user;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen /* this is an asynchronous notification about user being killed.
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen there are no guarantees about what might have happened to the user
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen in the mean time. */
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen switch (state) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case IPC_CLIENT_CMD_STATE_REPLY:
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen /* shouldn't get here. the command reply isn't finished yet. */
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainen i_error("login process sent unexpected reply to kick: %s", data);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case IPC_CLIENT_CMD_STATE_OK:
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case IPC_CLIENT_CMD_STATE_ERROR:
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen if (log_throttle_accept(user_kill_fail_throttle)) {
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen i_error("Failed to kill user %u connections: %s",
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen ctx->username_hash, data);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen /* we can't really do anything but continue anyway */
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen i_assert(ctx->dir->users_kicking_count > 0);
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen ctx->dir->users_kicking_count--;
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi if (ctx->dir->kick_callback != NULL)
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi ctx->dir->kick_callback(ctx->dir);
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->callback_pending = FALSE;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi user = user_directory_lookup(ctx->tag->users, ctx->username_hash);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (!DIRECTOR_KILL_CONTEXT_IS_VALID(user, ctx)) {
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen /* user was already freed - ignore */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(ctx->to_move == NULL);
34642ccff3ad4906cd365d0cb3deaa1e4f16610bTimo Sirainen director_user_move_finished(ctx->dir);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_free(ctx);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen } else {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(ctx->kill_state == USER_KILL_STATE_KILLING ||
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen ctx->kill_state == USER_KILL_STATE_KILLING_NOTIFY_RECEIVED);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen /* we were still waiting for the kill notification */
778a9861ee39eb23ec443a03cde832e3e31d7d37Timo Sirainen director_finish_user_kill(ctx->dir, user, ctx->kill_is_self_initiated);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenstatic void director_user_move_throttled(unsigned int new_events_count,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen void *context ATTR_UNUSED)
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen{
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen i_error("%u users' move timed out, their state may now be inconsistent",
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen new_events_count);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen}
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic void director_user_move_timeout(struct user *user)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(user->kill_ctx != NULL);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_assert(user->kill_ctx->kill_state != USER_KILL_STATE_DELAY);
488d92156e431ef201faf75910955588d0b768e3Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen if (log_throttle_accept(user_move_throttle)) {
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen i_error("Finishing user %u move timed out, "
3c89b4794ac52cc229b2b1dcec2324b490539c30Timo Sirainen "its state may now be inconsistent (state=%s)",
3c89b4794ac52cc229b2b1dcec2324b490539c30Timo Sirainen user->username_hash,
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user_kill_state_names[user->kill_ctx->kill_state]);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen }
6ce2e6f7aba7b36649b9d9d599bf59f8519c48d8Timo Sirainen if (user->kill_ctx->kill_state == USER_KILL_STATE_FLUSHING) {
6ce2e6f7aba7b36649b9d9d599bf59f8519c48d8Timo Sirainen o_stream_unref(&user->kill_ctx->reply);
6ce2e6f7aba7b36649b9d9d599bf59f8519c48d8Timo Sirainen program_client_destroy(&user->kill_ctx->pclient);
6ce2e6f7aba7b36649b9d9d599bf59f8519c48d8Timo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen director_user_move_free(user);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
f5d82a4b87a9b17894e1869cfe8b1a90afbced59Timo Sirainenvoid director_kill_user(struct director *dir, struct director_host *src,
f5d82a4b87a9b17894e1869cfe8b1a90afbced59Timo Sirainen struct user *user, struct mail_tag *tag,
ce8d63810932f48176304ed08cd8b7652c4a8addTimo Sirainen struct mail_host *old_host, bool forced_kick)
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen{
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen struct director_kill_context *ctx;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen const char *cmd;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen if (USER_IS_BEING_KILLED(user)) {
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen /* User is being moved again before the previous move
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen finished. We'll just continue wherever we left off
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen earlier. */
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen dir_debug("User %u move restarted - previous kill_state=%s",
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen user->username_hash,
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen user_kill_state_names[user->kill_ctx->kill_state]);
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen return;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen }
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen user->kill_ctx = ctx = i_new(struct director_kill_context, 1);
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen ctx->dir = dir;
078d7671f59bfcedc010b0b9192639c7d87f3e58Timo Sirainen ctx->tag = tag;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen ctx->username_hash = user->username_hash;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen ctx->kill_is_self_initiated = src->self;
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen if (old_host != NULL) {
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen ctx->old_host_ip = old_host->ip;
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen ctx->old_host_down = old_host->down;
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen ctx->old_host_vhost_count = old_host->vhost_count;
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen }
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen dir->users_moving_count++;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen ctx->to_move = timeout_add(DIRECTOR_USER_MOVE_TIMEOUT_MSECS,
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen director_user_move_timeout, user);
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen ctx->kill_state = USER_KILL_STATE_KILLING;
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen
ce8d63810932f48176304ed08cd8b7652c4a8addTimo Sirainen if ((old_host != NULL && old_host != user->host) || forced_kick) {
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen cmd = t_strdup_printf("proxy\t*\tKICK-DIRECTOR-HASH\t%u",
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen user->username_hash);
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen ctx->callback_pending = TRUE;
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen dir->users_kicking_count++;
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen ipc_client_cmd(dir->ipc_proxy, cmd,
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen director_kill_user_callback, ctx);
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen } else {
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen /* a) we didn't even know about the user before now.
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen don't bother performing a local kick, since it wouldn't
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen kick anything.
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen b) our host was already correct. notify others that we have
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen killed the user, but don't really do it. */
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen director_finish_user_kill(ctx->dir, user,
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen ctx->kill_is_self_initiated);
aad23ef1531748997776e50a5272a2fc8e022f04Timo Sirainen }
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen}
3404b66f3fda78955be9b6891ce5f5d6e13ef97aTimo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenvoid director_move_user(struct director *dir, struct director_host *src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *orig_src,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int username_hash, struct mail_host *host)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct user_directory *users = host->tag->users;
3638fd7bb3d9b900894eed0bb6296a9c2294c8f6Timo Sirainen struct mail_host *old_host = NULL;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct user *user;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen /* 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
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen with USER-KILLED that we're done killing the user.
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
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.
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen */
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen user = user_directory_lookup(users, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (user == NULL) {
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen dir_debug("User %u move started: User was nonexistent",
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen username_hash);
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen user = user_directory_add(users, username_hash,
32a93320fd2b6ada5ac8027166819463c1a007b6Timo Sirainen host, ioloop_time);
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen } else if (user->host == host) {
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen /* User is already in the wanted host, but another director
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen didn't think so. We'll need to finish the move without
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen killing any of our connections. */
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen old_host = user->host;
47f09f848021d147ab0cc7d75c4f138b40dbff8cTimo Sirainen user->timestamp = ioloop_time;
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen dir_debug("User %u move forwarded: host is already %s",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen username_hash, host->ip_str);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen } else {
7a380e77afc69a81725d410cd67082a37cf140d2Timo Sirainen /* user is looked up via the new host's tag, so if it's found
7a380e77afc69a81725d410cd67082a37cf140d2Timo Sirainen the old tag has to be the same. */
7a380e77afc69a81725d410cd67082a37cf140d2Timo Sirainen i_assert(user->host->tag == host->tag);
7a380e77afc69a81725d410cd67082a37cf140d2Timo Sirainen
3638fd7bb3d9b900894eed0bb6296a9c2294c8f6Timo Sirainen old_host = user->host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->host->user_count--;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->host = host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->host->user_count++;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user->timestamp = ioloop_time;
edaf7b320f860428b5cd3a0847dc0f7689816129Timo Sirainen dir_debug("User %u move started: host %s -> %s",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen username_hash, old_host->ip_str,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str);
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(
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen "USER-MOVE\t%s\t%u\t%u\t%u\t%s\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->username_hash, user->host->ip_str));
3638fd7bb3d9b900894eed0bb6296a9c2294c8f6Timo Sirainen /* kill the user only after sending the USER-MOVE, because the kill
3638fd7bb3d9b900894eed0bb6296a9c2294c8f6Timo Sirainen may finish instantly. */
ce8d63810932f48176304ed08cd8b7652c4a8addTimo Sirainen director_kill_user(dir, src, user, host->tag, old_host, FALSE);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainenstatic void
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainendirector_kick_user_callback(enum ipc_client_cmd_state state,
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen const char *data, void *context)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen{
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen struct director *dir = context;
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainen if (state == IPC_CLIENT_CMD_STATE_REPLY) {
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainen /* shouldn't get here. the command reply isn't finished yet. */
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainen i_error("login process sent unexpected reply to kick: %s", data);
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen return;
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainen }
6f20cb5225ddc5ec76f4c9bf6505d959270624deTimo Sirainen
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen i_assert(dir->users_kicking_count > 0);
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen dir->users_kicking_count--;
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi if (dir->kick_callback != NULL)
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi dir->kick_callback(dir);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen}
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainenvoid director_kick_user(struct director *dir, struct director_host *src,
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen struct director_host *orig_src, const char *username)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen{
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen string_t *cmd = t_str_new(64);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen str_append(cmd, "proxy\t*\tKICK\t");
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen str_append_tabescaped(cmd, username);
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen dir->users_kicking_count++;
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen ipc_client_cmd(dir->ipc_proxy, str_c(cmd),
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen director_kick_user_callback, dir);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if (orig_src == NULL) {
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen orig_src = dir->self_host;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen orig_src->last_seq++;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen }
6460420c3843322b3e725d83288a098cbd0edee2Timo Sirainen str_truncate(cmd, 0);
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen str_printfa(cmd, "USER-KICK\t%s\t%u\t%u\t",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq);
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen str_append_tabescaped(cmd, username);
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen str_append_c(cmd, '\n');
4a4fdb14788aec22dab8f1b91e9523233e5548dcTimo Sirainen director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK, str_c(cmd));
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen}
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainenvoid director_kick_user_alt(struct director *dir, struct director_host *src,
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen struct director_host *orig_src,
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen const char *field, const char *value)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen{
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen string_t *cmd = t_str_new(64);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append(cmd, "proxy\t*\tKICK-ALT\t");
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_tabescaped(cmd, field);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_c(cmd, '\t');
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_tabescaped(cmd, value);
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen dir->users_kicking_count++;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen ipc_client_cmd(dir->ipc_proxy, str_c(cmd),
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen director_kick_user_callback, dir);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (orig_src == NULL) {
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen orig_src = dir->self_host;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen orig_src->last_seq++;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen }
6460420c3843322b3e725d83288a098cbd0edee2Timo Sirainen str_truncate(cmd, 0);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_printfa(cmd, "USER-KICK-ALT\t%s\t%u\t%u\t",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_tabescaped(cmd, field);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_c(cmd, '\t');
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_tabescaped(cmd, value);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen str_append_c(cmd, '\n');
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK_ALT, str_c(cmd));
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen}
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainenvoid director_kick_user_hash(struct director *dir, struct director_host *src,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen struct director_host *orig_src,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen unsigned int username_hash,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen const struct ip_addr *except_ip)
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen{
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen const char *cmd;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen cmd = t_strdup_printf("proxy\t*\tKICK-DIRECTOR-HASH\t%u\t%s",
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen username_hash, net_ip2addr(except_ip));
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen dir->users_kicking_count++;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen ipc_client_cmd(dir->ipc_proxy, cmd,
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen director_kick_user_callback, dir);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen if (orig_src == NULL) {
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen orig_src = dir->self_host;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen orig_src->last_seq++;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen }
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen cmd = t_strdup_printf("USER-KICK-HASH\t%s\t%u\t%u\t%u\t%s\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen username_hash, net_ip2addr(except_ip));
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen director_update_send_version(dir, src, DIRECTOR_VERSION_USER_KICK, cmd);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen}
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainenstatic void
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainendirector_send_user_killed_everywhere(struct director *dir,
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen struct director_host *src,
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen struct director_host *orig_src,
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen unsigned int username_hash)
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen{
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen if (orig_src == NULL) {
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen orig_src = dir->self_host;
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen orig_src->last_seq++;
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen }
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen director_update_send(dir, src, t_strdup_printf(
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen "USER-KILLED-EVERYWHERE\t%s\t%u\t%u\t%u\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen orig_src->ip_str, orig_src->port, orig_src->last_seq,
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen username_hash));
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen}
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomistatic void
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomidirector_user_tag_killed(struct director *dir, struct mail_tag *tag,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi unsigned int username_hash)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct user *user;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi user = user_directory_lookup(tag->users, username_hash);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (user == NULL || !USER_IS_BEING_KILLED(user))
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen switch (user->kill_ctx->kill_state) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case USER_KILL_STATE_KILLING:
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user->kill_ctx->kill_state = USER_KILL_STATE_KILLING_NOTIFY_RECEIVED;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case USER_KILL_STATE_KILLED_WAITING_FOR_NOTIFY:
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_finish_user_kill(dir, user, TRUE);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen case USER_KILL_STATE_KILLING_NOTIFY_RECEIVED:
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen dir_debug("User %u kill_state=%s - ignoring USER-KILLED",
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen username_hash, user_kill_state_names[user->kill_ctx->kill_state]);
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case USER_KILL_STATE_NONE:
f9c76559302e6485f59ab0e6050b76fd6d268feeTimo Sirainen case USER_KILL_STATE_FLUSHING:
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case USER_KILL_STATE_DELAY:
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen /* move restarted. state=none can also happen if USER-MOVE was
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen sent while we were still moving. send back
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen USER-KILLED-EVERYWHERE to avoid hangs. */
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen director_send_user_killed_everywhere(dir, dir->self_host, NULL,
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen case USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE:
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_user_killed_everywhere(dir, dir->self_host,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen NULL, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen break;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomivoid director_user_killed(struct director *dir, unsigned int username_hash)
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct mail_tag *const *tagp;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi array_foreach(mail_hosts_get_tags(dir->mail_hosts), tagp)
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi director_user_tag_killed(dir, *tagp, username_hash);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi}
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomistatic void
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomidirector_user_tag_killed_everywhere(struct director *dir,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct mail_tag *tag,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct director_host *src,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct director_host *orig_src,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi unsigned int username_hash)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct user *user;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi user = user_directory_lookup(tag->users, username_hash);
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen if (user == NULL) {
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("User %u no longer exists - ignoring USER-KILLED-EVERYWHERE",
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (!USER_IS_BEING_KILLED(user)) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen dir_debug("User %u is no longer being killed - ignoring USER-KILLED-EVERYWHERE",
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen username_hash);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen return;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (user->kill_ctx->kill_state != USER_KILL_STATE_KILLED_WAITING_FOR_EVERYONE) {
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("User %u kill_state=%s - ignoring USER-KILLED-EVERYWHERE",
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen username_hash, user_kill_state_names[user->kill_ctx->kill_state]);
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen return;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
cf7857bce68a33cdabe88bb15568e21921eb5ac7Aki Tuomi director_flush_user(dir, user);
fd882f791279d0bb0cbf15ccec75cff9f6b399ccTimo Sirainen director_send_user_killed_everywhere(dir, src, orig_src, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomivoid director_user_killed_everywhere(struct director *dir,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct director_host *src,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct director_host *orig_src,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi unsigned int username_hash)
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct mail_tag *const *tagp;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi array_foreach(mail_hosts_get_tags(dir->mail_hosts), tagp) {
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi director_user_tag_killed_everywhere(dir, *tagp, src, orig_src,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi username_hash);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi }
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi}
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainenstatic void director_state_callback_timeout(struct director *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen timeout_remove(&dir->to_callback);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->state_change_callback(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainenvoid director_set_state_changed(struct director *dir)
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen{
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen /* we may get called to here from various places. use a timeout to
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen make sure the state callback is called with a clean state. */
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen if (dir->to_callback == NULL) {
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen dir->to_callback =
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen timeout_add(0, director_state_callback_timeout, dir);
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen }
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen}
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_update_send(struct director *dir, struct director_host *src,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_update_send_version(dir, src, 0, cmd);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenvoid director_update_send_version(struct director *dir,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *src,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int min_version, const char *cmd)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_connection *const *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(src != NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen array_foreach(&dir->connections, connp) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (director_connection_get_host(*connp) != src &&
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_connection_get_minor_version(*connp) >= min_version)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_send(*connp, cmd);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenstatic void director_user_freed(struct user *user)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (user->kill_ctx != NULL) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* director_user_expire is very short. user expired before
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen moving the user finished or timed out. */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (user->kill_ctx->callback_pending) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* kill_ctx is used as a callback parameter.
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen only remove the timeout and finish the free later. */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&user->kill_ctx->to_move);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen } else {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen director_user_move_free(user);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen}
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_init(const struct director_settings *set,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch const struct ip_addr *listen_ip, in_port_t listen_port,
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi director_state_change_callback_t *callback,
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi director_kick_callback_t *kick_callback)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir = i_new(struct director, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->set = set;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_port = listen_port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_ip = *listen_ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->state_change_callback = callback;
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi dir->kick_callback = kick_callback;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_array_init(&dir->dir_hosts, 16);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_array_init(&dir->pending_requests, 16);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen i_array_init(&dir->connections, 8);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi dir->mail_hosts = mail_hosts_init(set->director_user_expire,
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi director_user_freed);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
fb35b9f2c80954da842c20d5128b5e506835d93eTimo Sirainen dir->ipc_proxy = ipc_client_init(DIRECTOR_IPC_PROXY_PATH);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen dir->ring_min_version = DIRECTOR_VERSION_MINOR;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_deinit(struct director **_dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir = *_dir;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *const *hostp, *host;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen struct director_connection *conn, *const *connp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_dir = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen while (array_count(&dir->connections) > 0) {
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen connp = array_idx(&dir->connections, 0);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen conn = *connp;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&conn, "Shutting down");
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen }
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen mail_hosts_deinit(&dir->mail_hosts);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen mail_hosts_deinit(&dir->orig_config_hosts);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ipc_client_deinit(&dir->ipc_proxy);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_reconnect);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_handshake_warning);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_request);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_sync);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_remove_dirs);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&dir->to_callback);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen while (array_count(&dir->dir_hosts) > 0) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen hostp = array_idx(&dir->dir_hosts, 0);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host = *hostp;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_host_free(&host);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_free(&dir->pending_requests);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_free(&dir->dir_hosts);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen array_free(&dir->connections);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainenvoid dir_debug(const char *fmt, ...)
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen{
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen va_list args;
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (!director_debug)
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen return;
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen va_start(args, fmt);
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen T_BEGIN {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen i_debug("%s", t_strdup_vprintf(fmt, args));
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen } T_END;
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen va_end(args);
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen}
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainenstruct director_user_iter {
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct director *dir;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi unsigned int tag_idx;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen struct user_directory_iter *user_iter;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen bool iter_until_current_tail;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen};
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainenstruct director_user_iter *
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainendirector_iterate_users_init(struct director *dir, bool iter_until_current_tail)
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen{
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen struct director_user_iter *iter = i_new(struct director_user_iter, 1);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi iter->dir = dir;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen iter->iter_until_current_tail = iter_until_current_tail;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen return iter;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen}
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainenstruct user *director_iterate_users_next(struct director_user_iter *iter)
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi const ARRAY_TYPE(mail_tag) *tags;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct user *user;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi i_assert(iter != NULL);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi if (iter->user_iter == NULL) {
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi tags = mail_hosts_get_tags(iter->dir->mail_hosts);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi if (iter->tag_idx >= array_count(tags))
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi return NULL;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct mail_tag *const *tagp = array_idx(tags, iter->tag_idx);
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen iter->user_iter = user_directory_iter_init((*tagp)->users,
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen iter->iter_until_current_tail);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi }
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi user = user_directory_iter_next(iter->user_iter);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi if (user == NULL) {
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi user_directory_iter_deinit(&iter->user_iter);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi iter->tag_idx++;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi return director_iterate_users_next(iter);
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi } else
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi return user;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen}
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainenvoid director_iterate_users_deinit(struct director_user_iter **_iter)
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen{
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi i_assert(_iter != NULL && *_iter != NULL);
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen struct director_user_iter *iter = *_iter;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen *_iter = NULL;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi if (iter->user_iter != NULL)
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi user_directory_iter_deinit(&iter->user_iter);
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen i_free(iter);
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen}
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainenbool
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainendirector_get_username_hash(struct director *dir, const char *username,
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen unsigned int *hash_r)
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen{
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen const char *error;
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen if (mail_user_hash(username, dir->set->director_username_hash, hash_r,
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen &error))
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen return TRUE;
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen i_error("Failed to expand director_user_expire=%s: %s",
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen dir->set->director_username_hash, error);
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen return FALSE;
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen}
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenvoid directors_init(void)
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen{
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen user_move_throttle =
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen log_throttle_init(&director_log_throttle_settings,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen director_user_move_throttled, NULL);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen user_kill_fail_throttle =
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen log_throttle_init(&director_log_throttle_settings,
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen director_user_kill_fail_throttled, NULL);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen}
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainenvoid directors_deinit(void)
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen{
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen log_throttle_deinit(&user_move_throttle);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen log_throttle_deinit(&user_kill_fail_throttle);
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen}