director-connection.c revision 9d2575d99e43d08898c44d861f1a2e1377043c1e
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2010-2013 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen/*
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen Handshaking:
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen Incoming director connections send:
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen VERSION
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen ME
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen <wait for DONE from remote handshake>
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen DONE
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen <make this connection our "left" connection, potentially disconnecting
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen another one>
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen Outgoing director connections send:
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen VERSION
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen ME
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen [0..n] DIRECTOR
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen HOST-HAND-START
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen [0..n] HOST
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen HOST-HAND-END
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen [0..n] USER
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen <possibly other non-handshake commands between USERs>
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen DONE
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen <wait for DONE from remote>
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen <make this connection our "right" connection, potentially disconnecting
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen another one>
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen*/
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "array.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ostream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "str.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 MAX_INBUF_SIZE 1024
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_OUTBUF_SIZE (1024*1024*10)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define OUTBUF_FLUSH_THRESHOLD (1024*128)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen/* Max idling time before "ME" command must have been received,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen or we'll disconnect. */
fe7f9298fb789717d26dc4cb6317a9d376acd8fcTimo Sirainen#define DIRECTOR_CONNECTION_ME_TIMEOUT_MSECS (10*1000)
3574bab52a67dfe1291f6306e707c6199e777043Timo Sirainen/* Max time to wait for USERs in handshake to be sent. With a lot of users the
3574bab52a67dfe1291f6306e707c6199e777043Timo Sirainen kernel may quickly eat up everything we send, while the receiver is busy
3574bab52a67dfe1291f6306e707c6199e777043Timo Sirainen parsing the data. */
5a5b39ce7c6ba6d6ff2218ae1679e0485bf43b47Timo Sirainen#define DIRECTOR_CONNECTION_SEND_USERS_TIMEOUT_MSECS (30*1000)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen/* Max idling time before "DONE" command must have been received,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen or we'll disconnect. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen#define DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS (30*1000)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen/* How long to wait for PONG for an idling connection */
fe7f9298fb789717d26dc4cb6317a9d376acd8fcTimo Sirainen#define DIRECTOR_CONNECTION_PING_IDLE_TIMEOUT_MSECS (10*1000)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen/* Maximum time to wait for PONG reply */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen#define DIRECTOR_CONNECTION_PONG_TIMEOUT_MSECS (60*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 */
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen#define DIRECTOR_CONNECTION_PING_SYNC_INTERVAL_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 */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen#define DIRECTOR_SUCCESS_MIN_CONNECT_SECS 40
9a656df90290a5fef45b3a1191ae75864f17602dTimo Sirainen#define DIRECTOR_WAIT_DISCONNECT_SECS 10
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen#define DIRECTOR_HANDSHAKE_WARN_SECS 29
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen#define DIRECTOR_HANDSHAKE_BYTES_LOG_MIN_SECS (60*30)
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen#define DIRECTOR_MAX_SYNC_SEQ_DUPLICATES 4
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen#if DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS <= DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen# error DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS is too low
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen#endif
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen#if DIRECTOR_CONNECTION_PONG_TIMEOUT_MSECS <= DIRECTOR_CONNECTION_PING_IDLE_TIMEOUT_MSECS
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen# error DIRECTOR_CONNECTION_PONG_TIMEOUT_MSECS is too low
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen#endif
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen#define CMD_IS_USER_HANDHAKE(args) \
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen (str_array_length(args) > 2)
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen char *name;
4bc4042782c465636eff2c713bc85f5a1d773d91Timo Sirainen time_t created;
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen unsigned int minor_version;
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;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen /* this is set only for wrong connections: */
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen struct director_host *connect_request_to;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct io *io;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct istream *input;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output;
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen struct timeout *to_disconnect, *to_ping, *to_pong;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *user_iter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen /* set during command execution */
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen const char *cur_cmd, *cur_line;
98d5941dc28754f32432edc38578b946ba71dd0bTimo 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;
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen unsigned int synced:1;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen unsigned int wrong_host:1;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen unsigned int verifying_left:1;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen unsigned int users_unsorted:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void director_connection_disconnected(struct director_connection **conn);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenstatic void director_connection_reconnect(struct director_connection **conn,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen const char *reason);
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainenstatic void
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainendirector_connection_log_disconnect(struct director_connection *conn, int err);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainenstatic void ATTR_FORMAT(2, 3)
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainendirector_cmd_error(struct director_connection *conn, const char *fmt, ...)
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen{
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen va_list args;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen va_start(args, fmt);
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen i_error("director(%s): Command %s: %s (input: %s)", conn->name,
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen conn->cur_cmd, t_strdup_vprintf(fmt, args), conn->cur_line);
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen va_end(args);
4847d74a7442a3efabe76a8ad18dd464082d6581Timo Sirainen
4847d74a7442a3efabe76a8ad18dd464082d6581Timo Sirainen conn->host->last_protocol_failure = ioloop_time;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen}
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainendirector_connection_init_timeout(struct director_connection *conn)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen unsigned int secs = ioloop_time - conn->created;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (!conn->connected) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("director(%s): Connect timed out (%u secs)",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->name, secs);
cc22ca265b5b355c4a029155e074f36b5baf2e60Timo Sirainen } else if (conn->io == NULL) {
cc22ca265b5b355c4a029155e074f36b5baf2e60Timo Sirainen i_error("director(%s): Sending handshake (%u secs)",
cc22ca265b5b355c4a029155e074f36b5baf2e60Timo Sirainen conn->name, secs);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (!conn->me_received) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("director(%s): Handshaking ME timed out (%u secs)",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->name, secs);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("director(%s): Handshaking DONE timed out (%u secs)",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->name, secs);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_disconnected(&conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainendirector_connection_set_ping_timeout(struct director_connection *conn)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen unsigned int msecs;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen msecs = conn->synced || !conn->handshake_received ?
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen DIRECTOR_CONNECTION_PING_INTERVAL_MSECS :
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen DIRECTOR_CONNECTION_PING_SYNC_INTERVAL_MSECS;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen timeout_remove(&conn->to_ping);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->to_ping = timeout_add(msecs, director_connection_ping, conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainenstatic void director_connection_wait_timeout(struct director_connection *conn)
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen{
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainen director_connection_log_disconnect(conn, ETIMEDOUT);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&conn,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "Timeout waiting for disconnect after CONNECT");
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen}
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_connection_send_connect(struct director_connection *conn,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_host *host)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen const char *connect_str;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen if (conn->to_disconnect != NULL)
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen return;
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen net_ip2addr(&host->ip), host->port);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_send(conn, connect_str);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen o_stream_uncork(conn->output);
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen /* wait for a while for the remote to disconnect, so it will hopefully
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen see our CONNECT command. we'll also log the warning later to avoid
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen multiple log lines about it. */
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen conn->connect_request_to = host;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_host_ref(conn->connect_request_to);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen conn->to_disconnect =
9a656df90290a5fef45b3a1191ae75864f17602dTimo Sirainen timeout_add(DIRECTOR_WAIT_DISCONNECT_SECS*1000,
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen director_connection_wait_timeout, conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_connection_assigned(struct director_connection *conn)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director *dir = conn->dir;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (dir->left != NULL && dir->right != NULL) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* we're connected to both directors. see if the ring is
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen finished by sending a SYNC. if we get it back, it's done. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->sync_seq++;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_set_ring_unsynced(dir);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_sync_send(dir, dir->self_host, dir->sync_seq,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen DIRECTOR_VERSION_MINOR, ioloop_time);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_set_ping_timeout(conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic bool director_connection_assign_left(struct director_connection *conn)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director *dir = conn->dir;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_assert(conn->in);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_assert(dir->left != conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* make sure this is the correct incoming connection */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (conn->host->self) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("Connection from self, dropping");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return FALSE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (dir->left == NULL) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* no conflicts yet */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (dir->left->host == conn->host) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_warning("Replacing left director connection %s with %s",
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen dir->left->host->name, conn->host->name);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&dir->left, t_strdup_printf(
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "Replacing with %s", conn->host->name));
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (dir->left->verifying_left) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* we're waiting to verify if our current left is still
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen working. if we don't receive a PONG, the current left
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen gets disconnected and a new left gets assigned. if we do
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen receive a PONG, we'll wait until the current left
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen disconnects us and then reassign the new left. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (director_host_cmp_to_self(dir->left->host, conn->host,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->self_host) < 0) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* the old connection is the correct one.
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen refer the client there (FIXME: do we ever get here?) */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_send_connect(conn, dir->left->host);
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* this new connection is the correct one, but wait until the
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen old connection gets disconnected before using this one.
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen that guarantees that the director inserting itself into
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen the ring has finished handshaking its left side, so the
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen switch will be fast. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->left = conn;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_free(conn->name);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->name = i_strdup_printf("%s/left", conn->host->name);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_assigned(conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_assign_left(struct director *dir)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_connection *conn, *const *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen array_foreach(&dir->connections, connp) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn = *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen if (conn->in && conn->handshake_received &&
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen conn->to_disconnect == NULL && conn != dir->left) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* either use this or disconnect it */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (!director_connection_assign_left(conn)) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* we don't want this */
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&conn,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "Unwanted incoming connection");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_assign_left(dir);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen break;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic bool director_has_outgoing_connections(struct director *dir)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_connection *const *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen array_foreach(&dir->connections, connp) {
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen if (!(*connp)->in && (*connp)->to_disconnect == NULL)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return FALSE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic bool director_connection_assign_right(struct director_connection *conn)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director *dir = conn->dir;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_assert(!conn->in);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (dir->right != NULL) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* see if we should disconnect or keep the existing
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen connection. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (director_host_cmp_to_self(conn->host, dir->right->host,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->self_host) <= 0) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* the old connection is the correct one */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_warning("Aborting incorrect outgoing connection to %s "
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen "(already connected to correct one: %s)",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->host->name, dir->right->host->name);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->wrong_host = TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return FALSE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_warning("Replacing right director connection %s with %s",
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen dir->right->host->name, conn->host->name);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&dir->right, t_strdup_printf(
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "Replacing with %s", conn->host->name));
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->right = conn;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_free(conn->name);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->name = i_strdup_printf("%s/right", conn->host->name);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_assigned(conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo 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{
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen if (args[0] == NULL || args[1] == NULL) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Missing IP+port parameters");
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen return FALSE;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_addr2ip(args[0], ip_r) < 0) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid IP address: %s", args[0]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_to_uint(args[1], port_r) < 0) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid port: %s", 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 const char *connect_str;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen time_t next_comm_attempt;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (conn->me_received) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen director_cmd_error(conn, "Duplicate ME");
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return FALSE;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen }
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 conn->me_received = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen timeout_remove(&conn->to_ping);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_init_timeout, conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* Incoming connection:
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen a) we don't have an established ring yet. make sure we're connecting
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen to our right side (which might become our left side).
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen b) it's our current "left" connection. the previous connection
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen is most likely dead.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen c) we have an existing ring. tell our current "left" to connect to
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen it with CONNECT command.
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen d) the incoming connection doesn't belong to us at all, refer it
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen elsewhere with CONNECT. however, before disconnecting it verify
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen first that our left side is actually still functional.
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_assert(conn->host == NULL);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->host = director_host_get(dir, &ip, port);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* the host shouldn't be removed at this point, but if for some
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen reason it is we don't want to crash */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen conn->host->removed = FALSE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_host_ref(conn->host);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* make sure we don't keep old sequence values across restarts */
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen director_host_restarted(conn->host);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen next_comm_attempt = conn->host->last_protocol_failure +
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen DIRECTOR_PROTOCOL_FAILURE_RETRY_SECS;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (next_comm_attempt > ioloop_time) {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* the director recently sent invalid protocol data,
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen don't try retrying yet */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen i_error("director(%s): Remote sent invalid protocol data recently, "
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen "waiting %u secs before allowing further communication",
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen conn->name, (unsigned int)(next_comm_attempt-ioloop_time));
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen return FALSE;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen } else if (dir->left == NULL) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* a) - just in case the left is also our right side reset
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen its failed state, so we can connect to it */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen conn->host->last_network_failure = 0;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (!director_has_outgoing_connections(dir))
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connect(dir);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (dir->left->host == conn->host) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* b) */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_assert(dir->left != conn);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(&dir->left,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "Replacing with new incoming connection");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (director_host_cmp_to_self(conn->host, dir->left->host,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->self_host) < 0) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* c) */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen net_ip2addr(&conn->host->ip),
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->host->port);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_send(dir->left, connect_str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* d) */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen dir->left->verifying_left = TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_ping(dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainendirector_user_refresh(struct director_connection *conn,
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen unsigned int username_hash, struct mail_host *host,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen time_t timestamp, bool weak, struct user **user_r)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen bool ret = FALSE, unset_weak_user = 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);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen (*user_r)->weak = weak;
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("user refresh: %u added", username_hash);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (user->weak) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (!weak) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* removing user's weakness */
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("user refresh: %u weakness removed",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen username_hash);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen unset_weak_user = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->weak = FALSE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen ret = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen } else {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* weak user marked again as weak */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen } else if (weak &&
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen !user_directory_user_is_recently_updated(dir->users, user)) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* mark the user as weak */
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("user refresh: %u set weak", username_hash);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->weak = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen ret = TRUE;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen } else if (weak) {
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen dir_debug("user refresh: %u weak update to %s ignored, "
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen "we recently changed it to %s",
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen username_hash, net_ip2addr(&host->ip),
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen net_ip2addr(&user->host->ip));
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen host = user->host;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen ret = TRUE;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen } else if (user->host == host) {
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen /* update to the same host */
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen } else if (user_directory_user_is_near_expiring(dir->users, user)) {
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen /* host conflict for a user that is already near expiring. we can
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen assume that the other director had already dropped this user
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen and we should have as well. use the new host. */
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen dir_debug("user refresh: %u is nearly expired, "
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen "replacing host %s with %s", username_hash,
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen net_ip2addr(&user->host->ip), net_ip2addr(&host->ip));
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen ret = TRUE;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen } else {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* non-weak user received a non-weak update with
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen conflicting host. this shouldn't happen. */
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen string_t *str = t_str_new(128);
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen str_printfa(str, "User hash %u "
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen "is being redirected to two hosts: %s and %s",
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen username_hash, net_ip2addr(&user->host->ip),
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen net_ip2addr(&host->ip));
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen str_printfa(str, " (old_ts=%ld", (long)user->timestamp);
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen if (!conn->handshake_received) {
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen str_printfa(str, ",handshaking,recv_ts=%ld",
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen (long)timestamp);
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen }
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen if (user->to_move != NULL)
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen str_append(str, ",moving");
b37fabed279030d2989e8dcb25acdad3ad406433Timo Sirainen if (user->kill_state != USER_KILL_STATE_NONE)
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen str_printfa(str, ",kill_state=%d", user->kill_state);
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen str_append_c(str, ')');
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen i_error("%s", str_c(str));
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 */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen } else {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* keep the host */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen host = user->host;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (user->host != host) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->host->user_count--;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->host = host;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->host->user_count++;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen ret = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen if (timestamp == ioloop_time && (time_t)user->timestamp != timestamp) {
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen user_directory_refresh(dir->users, user);
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen ret = TRUE;
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen }
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("user refresh: %u refreshed timeout to %ld",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen username_hash, (long)user->timestamp);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (unset_weak_user) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* user is no longer weak. handle pending requests for
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen this user if there are any */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_set_state_changed(conn->dir);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo 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;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen bool weak;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo 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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen weak = args[3] != NULL && args[3][0] == 'w';
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
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)director_user_refresh(conn, username_hash, host,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen timestamp, weak, &user);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen if (user->timestamp < timestamp) {
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen conn->users_unsorted = TRUE;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen user->timestamp = timestamp;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic bool
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainendirector_cmd_user(struct director_connection *conn,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen 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
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen /* NOTE: if more parameters are added, update also
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen CMD_IS_USER_HANDHAKE() macro */
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen if (director_user_refresh(conn, username_hash,
32a93320fd2b6ada5ac8027166819463c1a007b6Timo Sirainen host, ioloop_time, FALSE, &user)) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen i_assert(!user->weak);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_update_user(conn->dir, conn->host, user);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
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;
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen bool forward = FALSE;
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) {
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen if (host == conn->dir->self_host) {
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen /* ignore updates to ourself */
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen return TRUE;
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (host->removed) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* ignore re-adds of removed directors */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return TRUE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* already have this. just reset its last_network_failure
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen timestamp, since it might be up now. */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen host->last_network_failure = 0;
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen if (host->last_seq != 0) {
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen /* it also may have been restarted, reset last_seq */
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen director_host_restarted(host);
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen forward = TRUE;
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen }
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen } else {
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen /* save the director and forward it */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host = director_host_add(conn->dir, &ip, port);
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen forward = TRUE;
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen }
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen if (forward) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_notify_ring_added(host,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_connection_get_host(conn));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstatic bool director_cmd_director_remove(struct director_connection *conn,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const char *const *args)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct director_host *host;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct ip_addr ip;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int port;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return FALSE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host = director_host_lookup(conn->dir, &ip, port);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (host != NULL && !host->removed)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_ring_remove(host, director_connection_get_host(conn));
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return TRUE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo 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
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen if (args[0] == NULL ||
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen str_to_uint(args[0], &remote_ring_completed) < 0) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return -1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *_args = args + 3;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host = director_host_lookup(conn->dir, &ip, port);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (host == NULL || host->removed) {
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 {
c1b9c4531186c6a7cd92d2c353273a834f8ee66fTimo Sirainen *host_r = host;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (seq <= host->last_seq) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* already seen this */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen host->last_seq = seq;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenstatic bool
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainendirector_cmd_user_weak(struct director_connection *conn,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen const char *const *args)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen{
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct director_host *dir_host;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct ip_addr ip;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen unsigned int username_hash;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct mail_host *host;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct user *user;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct director_host *src_host = conn->host;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen bool weak = TRUE, weak_forward = FALSE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen int ret;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
d3211a8014c08677e1c1bbd84e98ad51b5744448Timo Sirainen /* note that unlike other commands we don't want to just ignore
d3211a8014c08677e1c1bbd84e98ad51b5744448Timo Sirainen duplicate commands */
d3211a8014c08677e1c1bbd84e98ad51b5744448Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) < 0)
38eee54ced2034a4772958f96a737bd368d5e5e0Timo Sirainen return FALSE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (str_array_length(args) != 2 ||
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen net_addr2ip(args[1], &ip) < 0) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return FALSE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (host == NULL) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* we probably just removed this host. */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen if (ret == 0)
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen ;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen else if (dir_host == conn->dir->self_host) {
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen /* We originated this USER-WEAK request. The entire ring has seen
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen it and there weren't any conflicts. Make the user non-weak. */
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen dir_debug("user refresh: %u Our USER-WEAK seen by the entire ring",
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen username_hash);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen src_host = conn->dir->self_host;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen weak = FALSE;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen } else {
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen /* The original USER-WEAK sender will send a new non-weak USER
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen update saying what really happened. We'll still need to forward
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen this around the ring to the origin so it also knows it has
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen travelled through the ring. */
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen dir_debug("user refresh: %u Remote USER-WEAK from %s seen by the entire ring, ignoring",
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen username_hash, net_ip2addr(&dir_host->ip));
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen weak_forward = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (director_user_refresh(conn, username_hash,
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen host, ioloop_time, weak, &user) ||
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen weak_forward) {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (!user->weak)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_update_user(conn->dir, src_host, user);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen else {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_update_user_weak(conn->dir, src_host,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen dir_host, user);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen}
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic bool ATTR_NULL(3)
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
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
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic bool director_handshake_cmd_done(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir = conn->dir;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen unsigned int handshake_secs = time(NULL) - conn->created;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen string_t *str;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen if (conn->users_unsorted && conn->user_iter == NULL) {
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen /* we sent our user list before receiving remote's */
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen conn->users_unsorted = FALSE;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen user_directory_sort(conn->dir->users);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen }
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (handshake_secs >= DIRECTOR_HANDSHAKE_WARN_SECS || director_debug) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str = t_str_new(128);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_printfa(str, "director(%s): Handshake took %u secs, "
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "bytes in=%"PRIuUOFF_T" out=%"PRIuUOFF_T,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen conn->name, handshake_secs, conn->input->v_offset,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen conn->output->offset);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (handshake_secs >= DIRECTOR_HANDSHAKE_WARN_SECS)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_warning("%s", str_c(str));
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen else
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_debug("%s", str_c(str));
3a12bf3abc30af91cc141b74d2ab3b7d209f75bcTimo Sirainen }
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* the host is up now, make sure we can connect to it immediately
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if needed */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen conn->host->last_network_failure = 0;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
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
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* tell the "right" director about the "left" one */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_update_send(dir, director_connection_get_host(conn),
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen t_strdup_printf("DIRECTOR\t%s\t%u\n",
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen net_ip2addr(&conn->host->ip),
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->host->port));
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* this is our "left" side. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return director_connection_assign_left(conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* handshaked to "right" side. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return director_connection_assign_right(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainenstatic int
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_handle_handshake(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd, const char *const *args)
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);
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
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);
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen conn->minor_version = atoi(args[2]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->version_received = TRUE;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return 1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->version_received) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Incompatible protocol");
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (strcmp(cmd, "ME") == 0)
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return director_cmd_me(conn, args) ? 1 : -1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (!conn->me_received) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen director_cmd_error(conn, "Expecting ME command first");
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen /* incoming connections get a HOST list */
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (conn->handshake_sending_hosts) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (strcmp(cmd, "HOST") == 0)
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return director_cmd_host_handshake(conn, args) ? 1 : -1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (strcmp(cmd, "HOST-HAND-END") == 0) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen conn->ignore_host_events = FALSE;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen conn->handshake_sending_hosts = FALSE;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return 1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen director_cmd_error(conn, "Unexpected command during host list");
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (strcmp(cmd, "HOST-HAND-START") == 0) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (!conn->in) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen director_cmd_error(conn,
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen "Host list is only for incoming connections");
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return director_cmd_host_hand_start(conn, args) ? 1 : -1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (conn->in && strcmp(cmd, "USER") == 0 && CMD_IS_USER_HANDHAKE(args))
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return director_handshake_cmd_user(conn, args) ? 1 : -1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* both get DONE */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (strcmp(cmd, "DONE") == 0)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return director_handshake_cmd_done(conn) ? 1 : -1;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainenstatic bool
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainendirector_connection_sync_host(struct director_connection *conn,
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct director_host *host,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen uint32_t seq, unsigned int minor_version,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen unsigned int timestamp)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen if (minor_version > DIRECTOR_VERSION_MINOR) {
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen /* we're not up to date */
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen minor_version = DIRECTOR_VERSION_MINOR;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen }
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->self) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (dir->sync_seq != seq) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* stale SYNC event */
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen /* sync_seq increases when we get disconnected, so we must be
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen successfully connected to both directions */
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen i_assert(dir->left != NULL && dir->right != NULL);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen dir->ring_min_version = minor_version;
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 {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Ring is synced (%s sent seq=%u)",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen conn->name, seq);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_set_ring_synced(dir);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen } else {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if (seq < host->last_sync_seq) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen /* stale SYNC event */
9d2575d99e43d08898c44d861f1a2e1377043c1eTimo Sirainen dir_debug("Ignore stale SYNC event for %s "
9d2575d99e43d08898c44d861f1a2e1377043c1eTimo Sirainen "(seq %u < %u, timestamp=%u)",
9d2575d99e43d08898c44d861f1a2e1377043c1eTimo Sirainen host->name, seq, host->last_sync_seq,
9d2575d99e43d08898c44d861f1a2e1377043c1eTimo Sirainen timestamp);
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return FALSE;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen } else if (host->last_sync_seq != seq ||
fe30a45e565f7b803be8fb6abb31584daa219701Timo Sirainen timestamp > host->last_sync_timestamp) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen host->last_sync_seq = seq;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen host->last_sync_timestamp = timestamp;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen host->last_sync_seq_counter = 1;
7e656f6f504c93f91af8b6eb290da1a52c11d01bTimo Sirainen dir_debug("Update SYNC for %s (seq=%u, timestamp=%u)",
7e656f6f504c93f91af8b6eb290da1a52c11d01bTimo Sirainen host->name, seq, timestamp);
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen } else if (++host->last_sync_seq_counter >
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen DIRECTOR_MAX_SYNC_SEQ_DUPLICATES) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen /* we've received this too many times already */
7e656f6f504c93f91af8b6eb290da1a52c11d01bTimo Sirainen dir_debug("Ignore duplicate #%u SYNC event for %s "
7e656f6f504c93f91af8b6eb290da1a52c11d01bTimo Sirainen "(seq=%u, timestamp %u <= %u)",
9d2575d99e43d08898c44d861f1a2e1377043c1eTimo Sirainen host->last_sync_seq_counter, host->name, seq,
7e656f6f504c93f91af8b6eb290da1a52c11d01bTimo Sirainen timestamp, host->last_sync_timestamp);
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return FALSE;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if (dir->right != NULL) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen /* forward it to the connection on right */
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen director_sync_send(dir, host, seq, minor_version,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen timestamp);
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return TRUE;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainenstatic bool director_connection_sync(struct director_connection *conn,
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen const char *const *args)
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen{
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct director *dir = conn->dir;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct director_host *host;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen struct ip_addr ip;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen unsigned int port, seq, minor_version = 0, timestamp = ioloop_time;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo 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) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen return FALSE;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if (args[3] != NULL) {
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen minor_version = atoi(args[3]);
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if (args[4] != NULL && str_to_uint(args[4], &timestamp) < 0) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen director_cmd_error(conn, "Invalid parameters");
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return FALSE;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo 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);
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen if (host != NULL) {
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if (!director_connection_sync_host(conn, host, seq,
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen minor_version, timestamp))
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return TRUE;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen }
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if ((host == NULL || !host->self) &&
61b0eeb704039e9837ef3dc7d133096851517d0fTimo Sirainen (time_t)dir->self_host->last_sync_timestamp != ioloop_time)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)director_resend_sync(dir);
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)) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return FALSE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen host = director_host_get(conn->dir, &ip, port);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* reset failure timestamp so we'll actually try to connect there. */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen host->last_network_failure = 0;
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 */
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Ignoring CONNECT request to %s (current right is %s)",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen host->name, dir->right->name);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return TRUE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (dir->right == NULL) {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Received CONNECT request to %s, "
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen "initializing right", host->name);
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen } else {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Received CONNECT request to %s, "
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen "replacing current right %s",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen host->name, dir->right->name);
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen }
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* connect here */
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen (void)director_connect_host(dir, host);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return TRUE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen}
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_disconnect_wrong_lefts(struct director *dir)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct director_connection *const *connp, *conn;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen array_foreach(&dir->connections, connp) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn = *connp;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (conn->in && conn != dir->left && conn->me_received &&
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen conn->to_disconnect == NULL &&
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_host_cmp_to_self(dir->left->host, conn->host,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen dir->self_host) < 0)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_send_connect(conn, dir->left->host);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen}
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo 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 conn->ping_waiting = FALSE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen timeout_remove(&conn->to_pong);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (conn->verifying_left) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->verifying_left = FALSE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (conn == conn->dir->left) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* our left side is functional. tell all the wrong
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen incoming connections to connect to it instead. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_disconnect_wrong_lefts(conn->dir);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_set_ping_timeout(conn);
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen return TRUE;
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen}
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainendirector_connection_handle_cmd(struct director_connection *conn,
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen const char *cmd, const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen int ret;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen if (!conn->handshake_received) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen ret = director_connection_handle_handshake(conn, cmd, args);
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (ret > 0)
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return TRUE;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (ret < 0) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen /* invalid commands during handshake,
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen we probably don't want to reconnect here */
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return FALSE;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen /* allow also other commands during handshake */
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (strcmp(cmd, "PING") == 0) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_send(conn, "PONG\n");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return TRUE;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (strcmp(cmd, "PONG") == 0)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return director_cmd_pong(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "USER") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_user(conn, args);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (strcmp(cmd, "USER-WEAK") == 0)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return director_cmd_user_weak(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);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (strcmp(cmd, "DIRECTOR-REMOVE") == 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return director_cmd_director_remove(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "SYNC") == 0)
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen return director_connection_sync(conn, args);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen if (strcmp(cmd, "CONNECT") == 0)
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return director_cmd_connect(conn, args);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (strcmp(cmd, "QUIT") == 0) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_warning("Director %s disconnected us with reason: %s",
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen conn->name, t_strarray_join(args, " "));
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen return FALSE;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Unknown command %s", cmd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainenstatic bool
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainendirector_connection_handle_line(struct director_connection *conn,
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen const char *line)
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen{
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen const char *cmd, *const *args;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen bool ret;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("input: %s: %s", conn->name, line);
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen args = t_strsplit_tab(line);
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen cmd = args[0]; args++;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen if (cmd == NULL) {
4847d74a7442a3efabe76a8ad18dd464082d6581Timo Sirainen director_cmd_error(conn, "Received empty line");
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen return FALSE;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen }
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen conn->cur_cmd = cmd;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen conn->cur_line = line;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen ret = director_connection_handle_cmd(conn, cmd, args);
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen conn->cur_cmd = NULL;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen conn->cur_line = NULL;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen return ret;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen}
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenstatic void
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainendirector_connection_log_disconnect(struct director_connection *conn, int err)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen{
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen unsigned int secs = ioloop_time - conn->created;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen string_t *str = t_str_new(128);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_assert(conn->connected);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (conn->connect_request_to != NULL) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_warning("Director %s tried to connect to us, "
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "should use %s instead",
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen conn->name, conn->connect_request_to->name);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen return;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen }
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_printfa(str, "Director %s disconnected: ", conn->name);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_append(str, "Connection closed");
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainen if (err != 0 && err != EPIPE) {
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainen errno = err;
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_printfa(str, ": %m");
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainen }
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_printfa(str, " (connected %u secs, "
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "in=%"PRIuUOFF_T" out=%"PRIuUOFF_T,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen secs, conn->input->v_offset, conn->output->offset);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (!conn->me_received)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_append(str, ", handshake ME not received");
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen else if (!conn->handshake_received)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen str_append(str, ", handshake DONE not received");
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen i_error("%s", str_c(str));
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen}
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo 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 switch (i_stream_read(conn->input)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case 0:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -1:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* disconnected */
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainen director_connection_log_disconnect(conn, conn->input->stream_errno);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -2:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* buffer full */
4847d74a7442a3efabe76a8ad18dd464082d6581Timo Sirainen director_cmd_error(conn, "Director sent us more than %d bytes",
4847d74a7442a3efabe76a8ad18dd464082d6581Timo Sirainen MAX_INBUF_SIZE);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_reconnect(&conn, "Too long input line");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen if (conn->to_disconnect != NULL) {
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen /* just read everything the remote sends, and wait for it
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen to disconnect. we mainly just want the remote to read the
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen CONNECT we sent it. */
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen i_stream_skip(conn->input, i_stream_get_data_size(conn->input));
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen return;
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen }
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo 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) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_reconnect(&conn, t_strdup_printf(
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "Invalid input: %s", line));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync_thaw(dir);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen if (conn != NULL)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen timeout_reset(conn->to_ping);
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) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if ((*hostp)->removed)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen continue;
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 while ((user = user_directory_iter_next(conn->user_iter)) != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen string_t *str = t_str_new(128);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen str_printfa(str, "USER\t%u\t%s\t%u",
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->username_hash,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen net_ip2addr(&user->host->ip),
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user->timestamp);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (user->weak)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen str_append(str, "\tw");
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen str_append_c(str, '\n');
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_connection_send(conn, str_c(str));
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 */
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen timeout_reset(conn->to_ping);
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
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen if (conn->users_unsorted && conn->handshake_received) {
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen /* we received remote's list of users before sending ours */
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen conn->users_unsorted = FALSE;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen user_directory_sort(conn->dir->users);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen }
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = o_stream_flush(conn->output);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen timeout_reset(conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_connection_output(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen int ret;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (conn->user_iter != NULL) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen /* still handshaking USER list */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen o_stream_cork(conn->output);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen ret = director_connection_send_users(conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen o_stream_uncork(conn->output);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (ret < 0)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_disconnected(&conn);
b695e4700d0953031205ad4411182c4bb207605cTimo Sirainen else
b695e4700d0953031205ad4411182c4bb207605cTimo Sirainen o_stream_set_flush_pending(conn->output, TRUE);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen return ret;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen }
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return o_stream_flush(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo 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);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_ME_TIMEOUT_MSECS,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_init_timeout, conn);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen array_append(&dir->connections, &conn, 1);
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) {
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;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen o_stream_set_flush_callback(conn->output,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_output, conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen io_remove(&conn->io);
a70216512b55a4f6d633defcead6fcb081b03c16Timo Sirainen conn->io = io_add(conn->fd, IO_READ, director_connection_input, conn);
a70216512b55a4f6d633defcead6fcb081b03c16Timo Sirainen
3574bab52a67dfe1291f6306e707c6199e777043Timo Sirainen timeout_remove(&conn->to_ping);
3574bab52a67dfe1291f6306e707c6199e777043Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_SEND_USERS_TIMEOUT_MSECS,
3574bab52a67dfe1291f6306e707c6199e777043Timo Sirainen director_connection_init_timeout, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen o_stream_cork(conn->output);
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);
f37684a44ce2371e04cf40ba3d26630fee4630f6Timo Sirainen if (director_connection_send_users(conn) == 0)
f37684a44ce2371e04cf40ba3d26630fee4630f6Timo Sirainen o_stream_set_flush_pending(conn->output, TRUE);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen o_stream_uncork(conn->output);
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
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_assert(!host->removed);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* make sure we don't keep old sequence values across restarts */
ce28adabf2c47d3af9ef197787cdb5139424c69cTimo Sirainen director_host_restarted(host);
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;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_host_ref(host);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->io = io_add(conn->fd, IO_WRITE,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_connected, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenvoid director_connection_deinit(struct director_connection **_conn,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen const char *remote_reason)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen struct director_connection *const *conns, *conn = *_conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director *dir = conn->dir;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen unsigned int i, count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_conn = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (conn->host != NULL) {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("Disconnecting from %s: %s",
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen conn->host->name, remote_reason);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen }
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (*remote_reason != '\0' &&
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen conn->minor_version >= DIRECTOR_VERSION_QUIT) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen o_stream_send_str(conn->output, t_strdup_printf(
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen "QUIT\t%s\n", remote_reason));
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen }
4e43828ef88183a0750a8a374b6ba4ecf227c58fTimo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen conns = array_get(&dir->connections, &count);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen for (i = 0; i < count; i++) {
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen if (conns[i] == conn) {
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen array_delete(&dir->connections, i, 1);
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen break;
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen }
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen }
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen i_assert(i < count);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (dir->left == conn) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->left = NULL;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen /* if there is already another handshaked incoming connection,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen use it as the new "left" */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_assign_left(dir);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right == conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dir->right = NULL;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (conn->host != NULL)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen director_host_unref(conn->host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen if (conn->connect_request_to != NULL)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_host_unref(conn->connect_request_to);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->user_iter != NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen user_directory_iter_deinit(&conn->user_iter);
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen if (conn->to_disconnect != NULL)
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen timeout_remove(&conn->to_disconnect);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (conn->to_pong != NULL)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen timeout_remove(&conn->to_pong);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo 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
93cc8cf70b8df74972268d4b9ce25e9cb98ca40cTimo Sirainen if (conn->created + DIRECTOR_SUCCESS_MIN_CONNECT_SECS > ioloop_time &&
93cc8cf70b8df74972268d4b9ce25e9cb98ca40cTimo Sirainen conn->host != NULL) {
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen /* connection didn't exist for very long, assume it has a
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen network problem */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen conn->host->last_network_failure = ioloop_time;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen }
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(_conn, "");
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (dir->right == NULL)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen director_connect(dir);
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen}
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenstatic void director_connection_reconnect(struct director_connection **_conn,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen const char *reason)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen{
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen struct director_connection *conn = *_conn;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen struct director *dir = conn->dir;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_connection_deinit(_conn, reason);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (dir->right == NULL)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connect(dir);
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
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (director_debug) T_BEGIN {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen const char *const *lines = t_strsplit(data, "\n");
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen for (; lines[1] != NULL; lines++)
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("output: %s: %s", conn->name, *lines);
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen } T_END;
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 }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainendirector_connection_ping_idle_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("director(%s): Ping timed out, disconnecting", conn->name);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_connection_pong_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("director(%s): PONG reply not received although other "
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen "input keeps coming, disconnecting", conn->name);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_disconnected(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenvoid director_connection_ping(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen if (conn->ping_waiting)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen timeout_remove(&conn->to_ping);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_PING_IDLE_TIMEOUT_MSECS,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_ping_idle_timeout, conn);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen conn->to_pong = timeout_add(DIRECTOR_CONNECTION_PONG_TIMEOUT_MSECS,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_pong_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
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainenbool director_connection_is_handshaked(struct director_connection *conn)
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen{
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return conn->handshake_received;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen}
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainenbool director_connection_is_incoming(struct director_connection *conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
caae18c876f81e261350e4957471efa453c0ea9fTimo Sirainen return conn->in;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainenunsigned int
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainendirector_connection_get_minor_version(struct director_connection *conn)
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen{
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen return conn->minor_version;
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen}
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo 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
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainenvoid director_connection_set_synced(struct director_connection *conn,
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen bool synced)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen if (conn->synced == synced)
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen return;
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen conn->synced = synced;
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen /* switch ping timeout, unless we're already waiting for PONG */
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen if (conn->ping_waiting)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen director_connection_set_ping_timeout(conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}