director-connection.c revision fe201fb1819622ab33c51ef5a0a1f672e906b21a
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2010-2011 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 "network.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ostream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "str.h"
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen#include "llist.h"
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen#include "master-service.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-request.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "user-directory.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <stdlib.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <unistd.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_VERSION_NAME "director"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_VERSION_MAJOR 1
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_VERSION_MINOR 0
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_INBUF_SIZE 1024
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_OUTBUF_SIZE (1024*1024*10)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define OUTBUF_FLUSH_THRESHOLD (1024*128)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen/* Max idling time while connecting/handshaking before disconnecting */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen#define DIRECTOR_CONNECTION_INIT_TIMEOUT_MSECS (2*1000)
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen/* How long to wait for PONG after PING request */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS (2*1000)
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen/* How long to wait to send PING when connection is idle */
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen#define DIRECTOR_CONNECTION_PING_INTERVAL_MSECS (15*1000)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen/* How long to wait before sending PING while waiting for SYNC reply */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen#define DIRECTOR_CONNECTION_SYNC_TIMEOUT_MSECS 1000
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen/* If outgoing director connection exists for less than this many seconds,
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen mark the host as failed so we won't try to reconnect to it immediately */
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen#define DIRECTOR_SUCCESS_MIN_CONNECT_SECS 10
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_connection *prev, *next;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen char *name;
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen time_t created;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* for incoming connections the director host isn't known until
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ME-line is received */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct io *io;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct istream *input;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct timeout *to, *to_ping;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *user_iter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int in:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int connected:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int version_received:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int me_received:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int handshake_received:1;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen unsigned int ignore_host_events:1;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen unsigned int handshake_sending_hosts:1;
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen unsigned int ping_waiting:1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen unsigned int sync_ping:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_ping(struct director_connection *conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void director_connection_disconnected(struct director_connection **conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_args_parse_ip_port(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr *ip_r, unsigned int *port_r)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_addr2ip(args[0], ip_r) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Command has invalid IP address: %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[0]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_to_uint(args[1], port_r) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Command has invalid port: %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[1]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool director_cmd_me(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *connect_str;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in && (!net_ip_compare(&conn->host->ip, &ip) ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host->port != port)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("Remote director thinks it's someone else "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "(connected to %s:%u, remote says it's %s:%u)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&conn->host->ip), conn->host->port,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&ip), port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_get(dir, &ip, port);
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen /* the host is up now, make sure we can connect to it immediately
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen if needed */
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen host->last_failed = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->me_received = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_free(conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->name = i_strdup_printf("%s/left", host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host = host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* make sure we don't keep old sequence values across restarts */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host->last_seq = 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&host->ip), host->port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* make sure this is the correct incoming connection */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->self) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* probably we're trying to find our own ip. it's no */
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_error("Connection from self, dropping");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (dir->left == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* no conflicts yet */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (dir->left->host == host) {
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_warning("Dropping existing connection %s "
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen "in favor of its new connection %s",
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen dir->left->host->name, host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (director_host_cmp_to_self(dir->left->host, host,
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen dir->self_host) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* the old connection is the correct one.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen refer the client there. */
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_warning("Director connection %s tried to connect to "
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen "us, should use %s instead",
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen host->name, dir->left->host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, t_strdup_printf(
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "CONNECT\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&dir->left->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->left->host->port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* also make sure that the connection is alive */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_ping(dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* this new connection is the correct one. disconnect the old
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen one, but before that tell it to connect to the new one.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen that message might not reach it, so also send the same
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen message to right side. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_warning("Replacing director connection %s with %s",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->left->host->name, host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->left, connect_str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)o_stream_flush(dir->left->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->left = conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* tell the ring's right side to connect to this new director. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->right != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->left->host != dir->right->host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->right, connect_str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else {
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen /* there are only two directors, and we already have
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen a connection to this server. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen /* there are only two directors. connect to the other one. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)director_connect_host(dir, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_user_refresh(struct director *dir, unsigned int username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host, time_t timestamp,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user **user_r)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool ret = FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user = user_directory_lookup(dir->users, username_hash);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *user_r = user_directory_add(dir->users, username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host, timestamp);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
dc1bc1685e4a0d58ae7bacaecc282d0ebde2d7daTimo Sirainen if (timestamp == ioloop_time && (time_t)user->timestamp != timestamp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_directory_refresh(dir->users, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user->host != host) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("User hash %u is being redirected to two hosts: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "%s and %s", username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&user->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&host->ip));
36a687c1ed3ce55520bdf28cd2fa1f653360068dTimo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen /* we want all the directors to redirect the user to same
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen server, but we don't want two directors fighting over which
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen server it belongs to, so always use the lower IP address */
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (net_ip_cmp(&user->host->ip, &host->ip) > 0) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen /* change the host. we'll also need to remove the user
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen from the old host's user_count, because we can't
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen keep track of the user for more than one host */
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen user->host->user_count--;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen user->host = host;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen user->host->user_count++;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *user_r = user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_handshake_cmd_user(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int username_hash, timestamp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 3 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[1], &ip) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[2], &timestamp) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid USER handshake args",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): USER used unknown host %s in handshake",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[1]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_user_refresh(conn->dir, username_hash, host, timestamp, &user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic bool
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_cmd_user(struct director_connection *conn, const char *const *args)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen unsigned int username_hash;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct ip_addr ip;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct mail_host *host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct user *user;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (str_array_length(args) != 2 ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen net_addr2ip(args[1], &ip) < 0) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("director(%s): Invalid USER args", conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (host == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* we probably just removed this host. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (director_user_refresh(conn->dir, username_hash,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host, ioloop_time, &user))
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_update_user(conn->dir, conn->host, user);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool director_cmd_director(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_lookup(conn->dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host != NULL) {
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen /* already have this. just reset its last_failed timestamp,
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen since it might be up now. */
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen host->last_failed = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* save the director and forward it */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_host_add(conn->dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn->dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strdup_printf("DIRECTOR\t%s\t%u\n", net_ip2addr(&ip), port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainenstatic bool
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainendirector_cmd_host_hand_start(struct director_connection *conn,
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen const char *const *args)
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen{
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen const ARRAY_TYPE(mail_host) *hosts;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen struct mail_host *const *hostp;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen unsigned int remote_ring_completed;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen if (args == NULL || str_to_uint(args[0], &remote_ring_completed) < 0) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen i_error("director(%s): Invalid HOST-HAND-START args",
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen conn->name);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen return FALSE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen if (remote_ring_completed && !conn->dir->ring_handshaked) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen /* clear everything we have and use only what remote sends us */
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen hosts = mail_hosts_get(conn->dir->mail_hosts);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen while (array_count(hosts) > 0) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen hostp = array_idx(hosts, 0);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_remove_host(conn->dir, NULL, NULL, *hostp);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen } else if (!remote_ring_completed && conn->dir->ring_handshaked) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen /* ignore whatever remote sends */
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen conn->ignore_host_events = TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen conn->handshake_sending_hosts = TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen return TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen}
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic int
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_cmd_is_seen(struct director_connection *conn,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *const **_args,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host **host_r)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *const *args = *_args;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct ip_addr ip;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen unsigned int port, seq;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (str_array_length(args) < 3 ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen net_addr2ip(args[0], &ip) < 0 ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen str_to_uint(args[1], &port) < 0 ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen str_to_uint(args[2], &seq) < 0) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_error("director(%s): Command is missing parameters: %s",
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen conn->name, t_strarray_join(args, " "));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return -1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *_args = args + 3;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host = director_host_lookup(conn->dir, &ip, port);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (host == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* director is already gone, but we can't be sure if this
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen command was sent everywhere. re-send it as if it was from
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen ourself. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *host_r = NULL;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (seq <= host->last_seq) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* already seen this */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *host_r = host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host->last_seq = seq;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_cmd_host_int(struct director_connection *conn, const char *const *args,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *dir_host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int vhost_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool update;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 2 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[0], &ip) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[1], &vhost_count) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid HOST args", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen if (conn->ignore_host_events) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen /* remote is sending hosts in a handshake, but it doesn't have
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen a completed ring and we do. */
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen i_assert(conn->handshake_sending_hosts);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen return TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL) {
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_add_ip(conn->dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen update = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen update = host->vhost_count != vhost_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (update) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen mail_host_set_vhost_count(conn->dir->mail_hosts,
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen host, vhost_count);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_update_host(conn->dir, conn->host, dir_host, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic bool
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_cmd_host_handshake(struct director_connection *conn,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *const *args)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_cmd_host_int(conn, args, NULL);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic bool
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_cmd_host(struct director_connection *conn, const char *const *args)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *dir_host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen int ret;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return ret > 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_cmd_host_int(conn, args, dir_host);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_cmd_host_remove(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *dir_host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen int ret;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return ret > 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 1 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[0], &ip) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid HOST-REMOVE args", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_remove_host(conn->dir, conn->host, dir_host, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenstatic bool
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainendirector_cmd_host_flush(struct director_connection *conn,
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen const char *const *args)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *dir_host;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct mail_host *host;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct ip_addr ip;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen int ret;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return ret > 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
33e39c33202b1557532baeb2497550bfb32c4491Timo Sirainen if (str_array_length(args) != 1 ||
33e39c33202b1557532baeb2497550bfb32c4491Timo Sirainen net_addr2ip(args[0], &ip) < 0) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_error("director(%s): Invalid HOST-FLUSH args", conn->name);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return FALSE;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (host != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_flush_host(conn->dir, conn->host, dir_host, host);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return TRUE;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic bool
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_cmd_user_move(struct director_connection *conn,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *const *args)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *dir_host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct mail_host *host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct ip_addr ip;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int username_hash;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen int ret;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return ret > 0;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (str_array_length(args) != 2 ||
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen net_addr2ip(args[1], &ip) < 0) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_error("director(%s): Invalid USER-MOVE args", conn->name);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return FALSE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (host != NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_move_user(conn->dir, conn->host, dir_host,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen username_hash, host);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return TRUE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic bool
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_cmd_user_killed(struct director_connection *conn,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *const *args)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int username_hash;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (str_array_length(args) != 1 ||
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen str_to_uint(args[0], &username_hash) < 0) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_error("director(%s): Invalid USER-KILLED args", conn->name);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return FALSE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_user_killed(conn->dir, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return TRUE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic bool
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendirector_cmd_user_killed_everywhere(struct director_connection *conn,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *const *args)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct director_host *dir_host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int username_hash;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen int ret;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return ret > 0;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (str_array_length(args) != 1 ||
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen str_to_uint(args[0], &username_hash) < 0) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_error("director(%s): Invalid USER-KILLED-EVERYWHERE args",
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen conn->name);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return FALSE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_user_killed_everywhere(conn->dir, conn->host,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen dir_host, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return TRUE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_handshake_cmd_done(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen if (dir->debug)
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen i_debug("Handshaked to %s", conn->host->name);
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen conn->host->last_failed = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->handshake_received = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->in) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* handshaked to left side. tell it we've received the
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen whole handshake. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, "DONE\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* tell the right director about the left one */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->right != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strdup_printf("DIRECTOR\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&conn->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host->port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (dir->left != NULL && dir->right != NULL &&
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen dir->left->handshake_received && dir->right->handshake_received) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* we're connected to both directors. see if the ring is
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen finished by sending a SYNC. if we get it back, it's done. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_seq++;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen director_set_ring_unsynced(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strdup_printf("SYNC\t%s\t%u\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&dir->self_ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_port, dir->sync_seq));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->to_ping != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen timeout_remove(&conn->to_ping);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_PING_INTERVAL_MSECS,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_ping, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_handle_handshake(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd, const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* both incoming and outgoing connections get VERSION and ME */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "VERSION") == 0 && str_array_length(args) >= 3) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(args[0], DIRECTOR_VERSION_NAME) != 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Wrong protocol in socket "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "(%s vs %s)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[0], DIRECTOR_VERSION_NAME);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (atoi(args[1]) != DIRECTOR_VERSION_MAJOR) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Incompatible protocol version: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "%u vs %u", conn->name, atoi(args[1]),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_VERSION_MAJOR);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->version_received = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->version_received) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Incompatible protocol", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "ME") == 0 && !conn->me_received &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_array_length(args) == 2)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_me(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* only outgoing connections get a CONNECT reference */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in && strcmp(cmd, "CONNECT") == 0 &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_array_length(args) == 2) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* remote wants us to connect elsewhere */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir->right = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_get(conn->dir, &ip, port);
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen /* reset failure timestamp so we'll actually try to
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen connect there. */
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainen host->last_failed = 0;
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen if (conn->dir->debug)
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_debug("Received CONNECT reference to %s", host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)director_connect_host(conn->dir, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* only incoming connections get DIRECTOR and HOST lists */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->in && strcmp(cmd, "DIRECTOR") == 0 && conn->me_received)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_director(conn, args);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (strcmp(cmd, "HOST") == 0) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen /* allow hosts from all connections always,
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen this could be an host update */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->handshake_sending_hosts)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_cmd_host_handshake(conn, args);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen else
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_cmd_host(conn, args);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (conn->handshake_sending_hosts &&
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen strcmp(cmd, "HOST-HAND-END") == 0) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen conn->ignore_host_events = FALSE;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen conn->handshake_sending_hosts = FALSE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen return TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (conn->in && strcmp(cmd, "HOST-HAND-START") == 0 &&
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen conn->me_received)
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen return director_cmd_host_hand_start(conn, args);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* only incoming connections get a full USER list, but outgoing
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen connections can also receive USER updates during handshake and
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen it wouldn't be safe to ignore them. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (strcmp(cmd, "USER") == 0 && conn->me_received) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->in)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_handshake_cmd_user(conn, args);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen else
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_cmd_user(conn, args);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* both get DONE */
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (strcmp(cmd, "DONE") == 0 && !conn->handshake_received &&
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen !conn->handshake_sending_hosts) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_handshake_cmd_done(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("director(%s): Invalid handshake command: %s "
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen "(in=%d me_received=%d)", conn->name, cmd,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->in, conn->me_received);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainenstatic void
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainendirector_connection_sync_host(struct director_connection *conn,
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct director_host *host,
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen uint32_t seq, const char *line)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->self) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (dir->sync_seq != seq) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* stale SYNC event */
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (!dir->ring_handshaked) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen /* the ring is handshaked */
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen director_set_ring_handshaked(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else if (dir->ring_synced) {
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen /* duplicate SYNC (which was sent just in case the
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen previous one got lost) */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->debug) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_debug("Ring is synced (%s sent seq=%u)",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->name, seq);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_set_ring_synced(dir);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen } else {
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen /* forward it to the connection on right */
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen if (dir->right != NULL) {
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen director_connection_send(dir->right,
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen t_strconcat(line, "\n", NULL));
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainenstatic bool director_connection_sync(struct director_connection *conn,
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen const char *const *args, const char *line)
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen{
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct director *dir = conn->dir;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct director_host *host;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct ip_addr ip;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen unsigned int port, seq;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen if (str_array_length(args) != 3 ||
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen !director_args_parse_ip_port(conn, args, &ip, &port) ||
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen str_to_uint(args[2], &seq) < 0) {
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen i_error("director(%s): Invalid SYNC args", conn->name);
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen return FALSE;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen }
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen /* find the originating director. if we don't see it, it was already
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen removed and we can ignore this sync. */
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen host = director_host_lookup(dir, &ip, port);
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen if (host != NULL)
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen director_connection_sync_host(conn, host, seq, line);
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen if (!dir->ring_synced && dir->left != NULL && dir->right != NULL &&
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen (host == NULL || !host->self)) {
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen /* send a new SYNC in case the previous one got dropped */
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen director_connection_send(dir->right,
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen t_strdup_printf("SYNC\t%s\t%u\t%u\n",
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen net_ip2addr(&dir->self_ip),
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen dir->self_port, dir->sync_seq));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainenstatic bool director_cmd_connect(struct director_connection *conn,
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen const char *const *args)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen{
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen struct director *dir = conn->dir;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen struct director_host *host;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen struct ip_addr ip;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen unsigned int port;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (str_array_length(args) != 2 ||
ef44f827db33c2f8181d110802db1aebcd15120bTimo Sirainen !director_args_parse_ip_port(conn, args, &ip, &port)) {
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen i_error("director(%s): Invalid CONNECT args", conn->name);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return FALSE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen host = director_host_lookup(dir, &ip, port);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (host == NULL) {
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen i_error("Received CONNECT request to unknown host %s:%u",
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen net_ip2addr(&ip), port);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return TRUE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen /* remote suggests us to connect elsewhere */
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (dir->right != NULL &&
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen director_host_cmp_to_self(host, dir->right->host,
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen dir->self_host) <= 0) {
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen /* the old connection is the correct one */
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen if (dir->debug) {
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen i_debug("Ignoring CONNECT request to %s "
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen "(current right is %s)",
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen host->name, dir->right->name);
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return TRUE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen if (dir->debug) {
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen if (dir->right == NULL) {
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen i_debug("Received CONNECT request to %s, "
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen "initializing right", host->name);
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen } else {
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen i_debug("Received CONNECT request to %s, "
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen "replacing current right %s",
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen host->name, dir->right->name);
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen }
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen }
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* connect here */
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen (void)director_connect_host(dir, host);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return TRUE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen}
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainenstatic bool director_cmd_pong(struct director_connection *conn)
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen{
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen if (!conn->ping_waiting)
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen return TRUE;
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen conn->ping_waiting = FALSE;
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen timeout_remove(&conn->to_ping);
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_PING_INTERVAL_MSECS,
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen director_connection_ping, conn);
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen return TRUE;
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen}
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_handle_line(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *line)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd, *const *args;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen args = t_strsplit(line, "\t");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cmd = args[0]; args++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (cmd == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Received empty line", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* ping/pong is always handled */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (strcmp(cmd, "PING") == 0) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_send(conn, "PONG\n");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (strcmp(cmd, "PONG") == 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return director_cmd_pong(conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen if (!conn->handshake_received) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen if (!director_connection_handle_handshake(conn, cmd, args)) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen /* invalid commands during handshake,
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen we probably don't want to reconnect here */
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen if (conn->dir->debug) {
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_debug("director(%s): Handshaking failed",
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen conn->host->name);
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (conn->host != NULL)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen conn->host->last_failed = ioloop_time;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return FALSE;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return TRUE;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "USER") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_user(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "HOST") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_host(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "HOST-REMOVE") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_host_remove(conn, args);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (strcmp(cmd, "HOST-FLUSH") == 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return director_cmd_host_flush(conn, args);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (strcmp(cmd, "USER-MOVE") == 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return director_cmd_user_move(conn, args);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (strcmp(cmd, "USER-KILLED") == 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return director_cmd_user_killed(conn, args);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (strcmp(cmd, "USER-KILLED-EVERYWHERE") == 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return director_cmd_user_killed_everywhere(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "DIRECTOR") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_director(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "SYNC") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_connection_sync(conn, args, line);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (strcmp(cmd, "CONNECT") == 0)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return director_cmd_connect(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Unknown command (in this state): %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, cmd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_input(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen char *line;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to_ping != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_reset(conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen switch (i_stream_read(conn->input)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case 0:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -1:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* disconnected */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("Director %s disconnected%s", conn->name,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->handshake_received ? "" :
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen " before handshake finished");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -2:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* buffer full */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("BUG: Director %s sent us more than %d bytes",
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->name, MAX_INBUF_SIZE);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync_freeze(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = director_connection_handle_line(conn, line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } T_END;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!ret) {
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen if (dir->debug) {
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_debug("director(%s): Invalid input, disconnecting",
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen conn->name);
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync_thaw(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_send_directors(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen string_t *str)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&conn->dir->dir_hosts, hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, "DIRECTOR\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainenstatic void
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainendirector_connection_send_hosts(struct director_connection *conn, string_t *str)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen str_printfa(str, "HOST-HAND-START\t%u\n", conn->dir->ring_handshaked);
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, "HOST\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen str_printfa(str, "HOST-HAND-END\t%u\n", conn->dir->ring_handshaked);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_connection_send_users(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_cork(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((user = user_directory_iter_next(conn->user_iter)) != NULL) {
0ed263dafb47a89257b778ff2211ac44cec86848Timo Sirainen if (!user_directory_user_has_connections(conn->dir->users,
0ed263dafb47a89257b778ff2211ac44cec86848Timo Sirainen user)) {
0ed263dafb47a89257b778ff2211ac44cec86848Timo Sirainen /* user is already expired */
0ed263dafb47a89257b778ff2211ac44cec86848Timo Sirainen continue;
0ed263dafb47a89257b778ff2211ac44cec86848Timo Sirainen }
0ed263dafb47a89257b778ff2211ac44cec86848Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *line;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen line = t_strdup_printf("USER\t%u\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&user->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->timestamp);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } T_END;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (o_stream_get_buffer_used_size(conn->output) >= OUTBUF_FLUSH_THRESHOLD) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((ret = o_stream_flush(conn->output)) <= 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* continue later */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_directory_iter_deinit(&conn->user_iter);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, "DONE\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(conn->io == NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(conn->fd, IO_READ, director_connection_input, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = o_stream_flush(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_uncork(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_connection_output(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->user_iter != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_connection_send_users(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return o_stream_flush(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_connection_init_timeout(struct director_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->host != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->host->last_failed = ioloop_time;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (!conn->connected)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("director(%s): Connect timed out", conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen else
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("director(%s): Handshaking timed out", conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic struct director_connection *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_init_common(struct director *dir, int fd)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn = i_new(struct director_connection, 1);
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen conn->created = ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->fd = fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir = dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_set_flush_callback(conn->output,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_output, conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_INIT_TIMEOUT_MSECS,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_init_timeout, conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen DLLIST_PREPEND(&dir->connections, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_send_handshake(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, t_strdup_printf(
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "VERSION\t"DIRECTOR_VERSION_NAME"\t%u\t%u\n"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "ME\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_VERSION_MAJOR, DIRECTOR_VERSION_MINOR,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&conn->dir->self_ip), conn->dir->self_port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection *
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_connection_init_in(struct director *dir, int fd,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const struct ip_addr *ip)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn = director_connection_init_common(dir, fd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->in = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->connected = TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->name = i_strdup_printf("%s/in", net_ip2addr(ip));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(conn->fd, IO_READ, director_connection_input, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_handshake(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_connected(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen string_t *str = t_str_new(1024);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int err;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((err = net_geterror(conn->fd)) != 0) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen conn->host->last_failed = ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): connect() failed: %s", conn->name,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen strerror(err));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->connected = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right != NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* see if we should disconnect or keep the existing
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen connection. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (director_host_cmp_to_self(conn->host, dir->right->host,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->self_host) <= 0) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* the old connection is the correct one */
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_warning("Aborting incorrect outgoing connection to %s "
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen "(already connected to correct one: %s)",
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen conn->host->name, dir->right->host->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_deinit(&conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_warning("Replacing director connection %s with %s",
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen dir->right->host->name, conn->host->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_deinit(&dir->right);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->right = conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_free(conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->name = i_strdup_printf("%s/right", conn->host->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen io_remove(&conn->io);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_handshake(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_directors(conn, str);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen director_connection_send_hosts(conn, str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, str_c(str));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen conn->user_iter = user_directory_iter_init(dir->users);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)director_connection_send_users(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_init_out(struct director *dir, int fd,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* make sure we don't keep old sequence values across restarts */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host->last_seq = 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn = director_connection_init_common(dir, fd);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->name = i_strdup_printf("%s/out", host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host = host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* use IO_READ instead of IO_WRITE, so that we don't assign
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->right until remote has actually sent some data */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->io = io_add(conn->fd, IO_READ,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_connected, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_deinit(struct director_connection **_conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn = *_conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_conn = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen if (dir->debug && conn->host != NULL)
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen i_debug("Disconnecting from %s", conn->host->name);
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen if (conn->host != NULL && !conn->in &&
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen conn->created + DIRECTOR_SUCCESS_MIN_CONNECT_SECS > ioloop_time)
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen conn->host->last_failed = ioloop_time;
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen DLLIST_REMOVE(&dir->connections, conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->left == conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->left = NULL;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right == conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->right = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->user_iter != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen user_directory_iter_deinit(&conn->user_iter);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_remove(&conn->to);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to_ping != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_remove(&conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->io != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen io_remove(&conn->io);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_stream_unref(&conn->input);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_unref(&conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (close(conn->fd) < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("close(director connection) failed: %m");
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen
6ffc2a3e61636ba8ad50a3be260885bb6b041a3dTimo Sirainen if (conn->in)
6ffc2a3e61636ba8ad50a3be260885bb6b041a3dTimo Sirainen master_service_client_connection_destroyed(master_service);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_free(conn->name);
6ffc2a3e61636ba8ad50a3be260885bb6b041a3dTimo Sirainen i_free(conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->left == NULL || dir->right == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* we aren't synced until we're again connected to a ring */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->sync_seq++;
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen director_set_ring_unsynced(dir);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_connection_disconnected(struct director_connection **_conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_connection *conn = *_conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director *dir = conn->dir;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_deinit(_conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right == NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connect(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_send(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *data)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int len = strlen(data);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen off_t ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->output->closed || !conn->connected)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = o_stream_send(conn->output, data, len);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret != (off_t)len) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): write() failed: %m", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Output buffer full, "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "disconnecting", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_close(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->to = timeout_add(0, director_connection_timeout, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_send_except(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *skip_host,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *data)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->host != skip_host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, data);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_ping_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Ping timed out, disconnecting", conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_ping(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->sync_ping = FALSE;
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen if (conn->ping_waiting)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->to_ping != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen timeout_remove(&conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_ping_timeout, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, "PING\n");
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen conn->ping_waiting = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainenconst char *director_connection_get_name(struct director_connection *conn)
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen{
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen return conn->name;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct director_host *
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_connection_get_host(struct director_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return conn->host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstruct director_connection *
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_connection_find_outgoing(struct director *dir,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_host *host)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_connection *conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen for (conn = dir->connections; conn != NULL; conn = conn->next) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->host == host && !conn->in)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return NULL;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_connection_cork(struct director_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen o_stream_cork(conn->output);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_connection_uncork(struct director_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen o_stream_uncork(conn->output);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenvoid director_connection_wait_sync(struct director_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* switch to faster ping timeout. avoid reseting the timeout if it's
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen already fast. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->ping_waiting || conn->sync_ping)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->to_ping != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen timeout_remove(&conn->to_ping);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_SYNC_TIMEOUT_MSECS,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_ping, conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->sync_ping = TRUE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
23e1e4033d311a50253259de8866525980b23227Timo Sirainen
23e1e4033d311a50253259de8866525980b23227Timo Sirainenvoid director_connections_deinit(struct director *dir)
23e1e4033d311a50253259de8866525980b23227Timo Sirainen{
23e1e4033d311a50253259de8866525980b23227Timo Sirainen struct director_connection *conn;
23e1e4033d311a50253259de8866525980b23227Timo Sirainen
23e1e4033d311a50253259de8866525980b23227Timo Sirainen while (dir->connections != NULL) {
23e1e4033d311a50253259de8866525980b23227Timo Sirainen conn = dir->connections;
23e1e4033d311a50253259de8866525980b23227Timo Sirainen dir->connections = conn->next;
23e1e4033d311a50253259de8866525980b23227Timo Sirainen director_connection_deinit(&conn);
23e1e4033d311a50253259de8866525980b23227Timo Sirainen }
23e1e4033d311a50253259de8866525980b23227Timo Sirainen}