bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 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"
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen#include "strescape.h"
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen#include "time-util.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 "director-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <unistd.h>
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen#include <sys/time.h>
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen#include <sys/resource.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_INBUF_SIZE 1024
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define OUTBUF_FLUSH_THRESHOLD (1024*128)
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen/* Max time to wait for connect() to finish before aborting */
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen#define DIRECTOR_CONNECTION_CONNECT_TIMEOUT_MSECS (10*1000)
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,
5c8dec7f648cb0de2293a13265873baa640aa0cfTimo Sirainen or we'll disconnect. Use a slightly larger value than for _SEND_USERS_ so
5c8dec7f648cb0de2293a13265873baa640aa0cfTimo Sirainen that we'll get a better error if the sender decides to disconnect. */
5c8dec7f648cb0de2293a13265873baa640aa0cfTimo Sirainen#define DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS (40*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
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen/* Log a warning if PING reply or PONG response takes longer than this */
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen#define DIRECTOR_CONNECTION_PINGPONG_WARN_MSECS (5*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
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen/* If USER request doesn't have a timestamp, user isn't refreshed if it was
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen already refreshed director_user_expire/4 seconds ago. This value is the
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen hardcoded maximum for that value. */
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen#define DIRECTOR_SKIP_RECENT_REFRESH_MAX_SECS 15
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen#define DIRECTOR_RECONNECT_AFTER_WRONG_CONNECT_MSECS 1000
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
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen/* If we receive SYNCs with a timestamp this many seconds higher than the last
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen valid received SYNC timestamp, assume that we lost the director's restart
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen notification and reset the last_sync_seq */
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen#define DIRECTOR_SYNC_STALE_TIMESTAMP_RESET_SECS (60*2)
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen#define DIRECTOR_MAX_CLOCK_DIFF_WARN_SECS 1
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen/* How many USER entries to send during handshake before going back to ioloop
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen to see if there's other work to be done as well. */
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen#define DIRECTOR_HANDSHAKE_MAX_USERS_SENT_PER_FLUSH 10000
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen#define CMD_IS_USER_HANDSHAKE(minor_version, args) \
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen ((minor_version) < DIRECTOR_VERSION_HANDSHAKE_U_CMD && \
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen str_array_length(args) > 2)
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen#define DIRECTOR_OPT_CONSISTENT_HASHING "consistent-hashing"
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection {
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen int refcount;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen char *name;
7fd22d5521c8ecf84c40fbef553e70bf2553a663Timo Sirainen struct timeval created, connected_time, me_received_time;
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen struct timeval connected_user_cpu;
ee3362f3b78827a2c9a7e9ddee83f5a429c06213Timo Sirainen unsigned int minor_version;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen struct timeval last_input, last_output;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen size_t peak_bytes_buffered;
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo Sirainen struct timeval ping_sent_time;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen size_t ping_sent_buffer_size;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen struct timeval ping_sent_user_cpu;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen uoff_t ping_sent_input_offset, ping_sent_output_offset;
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo Sirainen unsigned int last_ping_msecs;
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo 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
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen struct director_user_iter *user_iter;
58a102564ba58e2713e02ab86054978eb611cb81Timo Sirainen unsigned int users_received, handshake_users_received;
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen unsigned int handshake_users_sent;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen /* set during command execution */
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen const char *cur_cmd, *const *cur_args;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool in:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool connected:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool version_received:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool me_received:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool handshake_received:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool ignore_host_events:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool handshake_sending_hosts:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool ping_waiting:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool synced:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool wrong_host:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool verifying_left:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool users_unsorted:1;
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen bool connected_user_cpu_set:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainenstatic bool director_connection_unref(struct director_connection *conn);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainenstatic void director_finish_sending_handshake(struct director_connection *conn);
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainenstatic void director_connection_disconnected(struct director_connection **conn,
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen const char *reason);
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenstatic void director_connection_reconnect(struct director_connection **conn,
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen const char *reason);
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainenstatic void
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainendirector_connection_log_disconnect(struct director_connection *conn, int err,
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen const char *errstr);
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainenstatic int director_connection_send_done(struct director_connection *conn);
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,
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen conn->cur_cmd, t_strdup_vprintf(fmt, args),
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen t_strarray_join(conn->cur_args, "\t"));
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen va_end(args);
4847d74a7442a3efabe76a8ad18dd464082d6581Timo Sirainen
34115224152b94328ffe3ec4ff4f30927c8f9aa1Timo Sirainen if (conn->host != NULL)
34115224152b94328ffe3ec4ff4f30927c8f9aa1Timo Sirainen conn->host->last_protocol_failure = ioloop_time;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen}
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainenstatic void
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainendirector_connection_append_stats(struct director_connection *conn, string_t *str)
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen{
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen int input_msecs = timeval_diff_msecs(&ioloop_timeval, &conn->last_input);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen int output_msecs = timeval_diff_msecs(&ioloop_timeval, &conn->last_output);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen int connected_msecs = timeval_diff_msecs(&ioloop_timeval, &conn->connected_time);
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen struct rusage usage;
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen str_printfa(str, "bytes in=%"PRIuUOFF_T", bytes out=%"PRIuUOFF_T,
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen conn->input->v_offset, conn->output->offset);
58a102564ba58e2713e02ab86054978eb611cb81Timo Sirainen str_printfa(str, ", %u+%u USERs received",
58a102564ba58e2713e02ab86054978eb611cb81Timo Sirainen conn->handshake_users_received, conn->users_received);
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen if (conn->handshake_users_sent > 0) {
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen str_printfa(str, ", %u USERs sent in handshake",
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen conn->handshake_users_sent);
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen }
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen if (conn->last_input.tv_sec > 0) {
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen str_printfa(str, ", last input %u.%03u s ago",
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen input_msecs/1000, input_msecs%1000);
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen }
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen if (conn->last_output.tv_sec > 0) {
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen str_printfa(str, ", last output %u.%03u s ago",
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen output_msecs/1000, output_msecs%1000);
8a513c80e95a51c29f5af5c702fbf71ecbad41f4Timo Sirainen }
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen if (conn->connected) {
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_printfa(str, ", connected %u.%03u s ago",
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen connected_msecs/1000, connected_msecs%1000);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen }
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen if (o_stream_get_buffer_used_size(conn->output) > 0) {
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_printfa(str, ", %"PRIuSIZE_T" bytes in output buffer",
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen o_stream_get_buffer_used_size(conn->output));
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen }
ef996cb0e68ea5474716058137308a98cfa0c324Timo Sirainen str_printfa(str, ", %zu peak output buffer size",
ef996cb0e68ea5474716058137308a98cfa0c324Timo Sirainen conn->peak_bytes_buffered);
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen if (conn->connected_user_cpu_set &&
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen getrusage(RUSAGE_SELF, &usage) == 0) {
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen /* this isn't measuring the CPU usage used by the connection
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen itself, but it can still be a useful measurement */
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen int diff = timeval_diff_msecs(&usage.ru_utime,
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen &conn->connected_user_cpu);
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen str_printfa(str, ", %d.%03d CPU secs since connected",
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen diff / 1000, diff % 1000);
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen }
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen}
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainendirector_connection_init_timeout(struct director_connection *conn)
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen{
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen struct timeval start_time;
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen string_t *reason = t_str_new(128);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (!conn->connected) {
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen start_time = conn->created;
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append(reason, "Connect timed out");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else if (!conn->me_received) {
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen start_time = conn->connected_time;
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append(reason, "Handshaking ME timed out");
6ccc7f584c832a3212d70952881cb0eb2d6e2cb9Timo Sirainen } else if (!conn->in) {
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen start_time = conn->me_received_time;
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append(reason, "Sending handshake timed out");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen } else {
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen start_time = conn->me_received_time;
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append(reason, "Handshaking DONE timed out");
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen }
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen int msecs = timeval_diff_msecs(&ioloop_timeval, &start_time);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_printfa(reason, " (%u.%03u secs, ", msecs/1000, msecs%1000);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen director_connection_append_stats(conn, reason);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append_c(reason, ')');
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen i_error("director(%s): %s", conn->name, str_c(reason));
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_disconnected(&conn, "Handshake timeout");
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{
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo 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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, 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,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen DIRECTOR_VERSION_MINOR, ioloop_time,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen mail_hosts_hash(dir->mail_hosts));
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
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainenstatic void director_send_delayed_syncs(struct director *dir)
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen{
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen struct director_host *const *hostp;
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen i_assert(dir->right != NULL);
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen dir_debug("director(%s): Sending delayed SYNCs", dir->right->name);
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen array_foreach(&dir->dir_hosts, hostp) {
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen if ((*hostp)->delayed_sync_seq == 0)
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen continue;
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen director_sync_send(dir, *hostp, (*hostp)->delayed_sync_seq,
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen (*hostp)->delayed_sync_minor_version,
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen (*hostp)->delayed_sync_timestamp,
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen (*hostp)->delayed_sync_hosts_hash);
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen (*hostp)->delayed_sync_seq = 0;
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen }
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen}
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo 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);
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen director_send_delayed_syncs(dir);
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,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch struct ip_addr *ip_r, in_port_t *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 }
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(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;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t 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)",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen conn->host->ip_str, conn->host->port,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&ip), port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->me_received = TRUE;
7fd22d5521c8ecf84c40fbef553e70bf2553a663Timo Sirainen conn->me_received_time = ioloop_timeval;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen if (args[2] != NULL) {
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen time_t remote_time;
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen int diff;
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen if (str_to_time(args[2], &remote_time) < 0) {
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen director_cmd_error(conn, "Invalid ME timestamp");
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen return FALSE;
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen }
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen diff = ioloop_time - remote_time;
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen if (diff > DIRECTOR_MAX_CLOCK_DIFF_WARN_SECS ||
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen (diff < 0 && -diff > DIRECTOR_MAX_CLOCK_DIFF_WARN_SECS)) {
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen i_warning("Director %s clock differs from ours by %d secs",
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen conn->name, diff);
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen }
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen }
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen timeout_remove(&conn->to_ping);
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen if (conn->in) {
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS,
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen director_connection_init_timeout, conn);
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen } else {
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_SEND_USERS_TIMEOUT_MSECS,
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen director_connection_init_timeout, conn);
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen }
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))
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_connect(dir, "Connecting to left");
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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen conn->host->ip_str,
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
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainenstatic inline bool
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainenuser_need_refresh(struct director *dir, struct user *user,
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen time_t timestamp, bool unknown_timestamp)
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen{
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen if (timestamp <= (time_t)user->timestamp) {
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen /* we already have this timestamp */
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen return FALSE;
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen }
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen if (unknown_timestamp) {
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen /* Old director sent USER command without timestamp. We don't
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen know what it is exactly, but we can assume that it's very
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen close to the current time (which timestamp parameter is
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen already set to). However, try to break USER loops here when
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen director ring latency is >1sec, but below skip_recent_secs
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen by just not refreshing the user. */
70a88f28adfd52040d483b62ef6fd164db89b015Josef 'Jeff' Sipek time_t skip_recent_secs =
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen I_MIN(dir->set->director_user_expire/4,
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen DIRECTOR_SKIP_RECENT_REFRESH_MAX_SECS);
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen if ((time_t)user->timestamp + skip_recent_secs >= timestamp)
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen return FALSE;
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen }
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen return TRUE;
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen}
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainenstatic int
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainendirector_user_refresh(struct director_connection *conn,
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen unsigned int username_hash, struct mail_host *host,
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen time_t timestamp, bool weak, bool *forced_r,
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen 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;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi struct user_directory *users = host->tag->users;
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen bool unknown_timestamp = (timestamp == (time_t)-1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen *forced_r = FALSE;
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen if (unknown_timestamp) {
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen /* Old director version sent USER without timestamp. */
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen timestamp = ioloop_time;
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen }
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen
154f91726624265fce15097eb4bbbf6e55f8c477Timo Sirainen if (timestamp + (time_t)dir->set->director_user_expire <= ioloop_time) {
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen /* Ignore this refresh entirely, regardless of whether the
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen user already exists or not. */
154f91726624265fce15097eb4bbbf6e55f8c477Timo Sirainen dir_debug("user refresh: %u has expired timestamp %"PRIdTIME_T,
154f91726624265fce15097eb4bbbf6e55f8c477Timo Sirainen username_hash, timestamp);
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen return -1;
154f91726624265fce15097eb4bbbf6e55f8c477Timo Sirainen }
154f91726624265fce15097eb4bbbf6e55f8c477Timo Sirainen
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen user = user_directory_lookup(users, username_hash);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user == NULL) {
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen *user_r = user_directory_add(users, username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host, timestamp);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen (*user_r)->weak = weak;
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen dir_debug("user refresh: %u added", username_hash);
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen return 1;
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 &&
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen !user_directory_user_is_recently_updated(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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen username_hash, host->ip_str,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->host->ip_str);
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen host = user->host;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen ret = TRUE;
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen } else if (user->host == host) {
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen /* update to the same host */
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen } else if (user_directory_user_is_near_expiring(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,
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen user->host->ip_str, host->ip_str);
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen ret = TRUE;
79ee504bdf920f01e12e28f238799bf2616489dfTimo Sirainen } else if (USER_IS_BEING_KILLED(user)) {
5c1733e9e572e242598b8b2f12a0068897caf5b7Timo Sirainen /* user is still being moved - ignore conflicting host updates
5c1733e9e572e242598b8b2f12a0068897caf5b7Timo Sirainen from other directors who don't yet know about the move. */
5c1733e9e572e242598b8b2f12a0068897caf5b7Timo Sirainen dir_debug("user refresh: %u is being moved, "
5c1733e9e572e242598b8b2f12a0068897caf5b7Timo Sirainen "preserve its host %s instead of replacing with %s",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen username_hash, user->host->ip_str, host->ip_str);
5c1733e9e572e242598b8b2f12a0068897caf5b7Timo Sirainen host = user->host;
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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen username_hash, user->host->ip_str, host->ip_str);
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 }
79ee504bdf920f01e12e28f238799bf2616489dfTimo Sirainen if (USER_IS_BEING_KILLED(user)) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (user->kill_ctx->to_move != NULL)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen str_append(str, ",moving");
ade4a0e1a8f4bc3467f4fcff9c219558fe348abfTimo Sirainen str_printfa(str, ",kill_state=%s",
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen user_kill_state_names[user->kill_ctx->kill_state]);
ade4a0e1a8f4bc3467f4fcff9c219558fe348abfTimo Sirainen }
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
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen keep track of the user for more than one host.
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen send the updated USER back to the sender as well. */
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen *forced_r = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen } else {
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* keep the host */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen host = user->host;
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen /* especially IMAP connections can take a long time to die.
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen make sure we kill off the connections in the wrong
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen backends. */
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen director_kick_user_hash(dir, dir->self_host, NULL,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen username_hash, &host->ip);
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 }
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen /* Update user's timestamp if it's higher than the current one. Note
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen that we'll preserve the original timestamp. This is important when
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen the director ring is slow and a single USER can traverse through
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen the ring more than a second. We don't want to get into a loop where
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen the same USER goes through the ring forever. */
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen if (user_need_refresh(dir, user, timestamp, unknown_timestamp)) {
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen /* NOTE: This makes the users list somewhat out-of-order.
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen It's not a big problem - most likely it's only a few seconds
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen difference. The worst that can happen is that some users
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen take up memory that should have been freed already. */
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen dir_debug("user refresh: %u refreshed timestamp from %u to %"PRIdTIME_T,
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen username_hash, user->timestamp, timestamp);
68d87d8fb8f23ffed031ddfd9c410f3c929777faTimo Sirainen user_directory_refresh(users, user);
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen user->timestamp = timestamp;
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen ret = TRUE;
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen } else {
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen dir_debug("user refresh: %u ignored timestamp %"PRIdTIME_T" (we have %u)",
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen username_hash, timestamp, user->timestamp);
4f2b533808371b3b8a8187819cd4c3d90e1ca8eeTimo Sirainen }
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;
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen return ret ? 1 : 0;
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;
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen bool weak, forced;
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';
58a102564ba58e2713e02ab86054978eb611cb81Timo Sirainen conn->handshake_users_received++;
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
70a88f28adfd52040d483b62ef6fd164db89b015Josef 'Jeff' Sipek if ((time_t)timestamp > ioloop_time) {
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen /* The other director's clock seems to be into the future
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen compared to us. Don't set any of our users' timestamps into
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen future though. It's most likely only 1 second difference. */
04c8a9554e34ad1afed9291e673cd452ee93e849Timo Sirainen timestamp = ioloop_time;
04c8a9554e34ad1afed9291e673cd452ee93e849Timo Sirainen }
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo Sirainen conn->dir->num_incoming_requests++;
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen if (director_user_refresh(conn, username_hash, host,
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen timestamp, weak, &forced, &user) < 0) {
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen /* user expired - ignore */
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen return TRUE;
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen }
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen /* Possibilities:
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen a) The user didn't exist yet, and it was added with the given
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen timestamp.
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen b) The user existed, but with an older timestamp. The timestamp
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen wasn't yet updated, so do it here below.
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen c) The user existed with a newer timestamp. This is either because
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen we already received a non-handshake USER update for this user, or
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen our director saw a login for this user. Ignore this update.
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen (We never want to change the user's timestamp to be older, because
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen that could result in directors going to a loop fighting each others
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen over a flipping timestamp.) */
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen if (user->timestamp < timestamp)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen user->timestamp = timestamp;
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen /* always sort users after handshaking to make sure the order
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen is correct */
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen conn->users_unsorted = TRUE;
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;
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen bool forced;
edaa9f5c32594e7af8c0b862cd3a0c188d55ac7bTimo Sirainen time_t timestamp = (time_t)-1;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen if (str_array_length(args) < 2 ||
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen net_addr2ip(args[1], &ip) < 0 ||
b3e36790ca9e16d022118012b46ed50f73a45046Timo Sirainen (args[2] != NULL && str_to_time(args[2], &timestamp) < 0)) {
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen director_cmd_error(conn, "Invalid parameters");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo Sirainen /* could this before it's potentially ignored */
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo Sirainen conn->dir->num_incoming_requests++;
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo Sirainen
58a102564ba58e2713e02ab86054978eb611cb81Timo Sirainen conn->users_received++;
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,
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen host, timestamp, FALSE, &forced, &user) > 0) {
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen /* user changed - forward the USER in the ring */
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen struct director_host *src_host =
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen forced ? conn->dir->self_host : conn->host;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen i_assert(!user->weak);
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen director_update_user(conn->dir, src_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;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen bool log_add = 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
e588e0b3f3119ba2cc98b338ee9868f8f0297f49Timo Sirainen timestamp, since it might be up now, but only if this
e588e0b3f3119ba2cc98b338ee9868f8f0297f49Timo Sirainen isn't part of the handshake. (if it was, reseting the
e588e0b3f3119ba2cc98b338ee9868f8f0297f49Timo Sirainen timestamp could cause us to rapidly keep trying to connect
e588e0b3f3119ba2cc98b338ee9868f8f0297f49Timo Sirainen to it) */
e588e0b3f3119ba2cc98b338ee9868f8f0297f49Timo Sirainen if (conn->handshake_received)
e588e0b3f3119ba2cc98b338ee9868f8f0297f49Timo Sirainen host->last_network_failure = 0;
88cb1595bf0ad84846b9c611a1afbca35fcfe460Timo Sirainen /* it also may have been restarted, reset its state */
88cb1595bf0ad84846b9c611a1afbca35fcfe460Timo Sirainen director_host_restarted(host);
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen } else {
c9b08dc8d71bd655e5648daf8a09ff4b728cae81Timo Sirainen /* save the director and forward it */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen host = director_host_add(conn->dir, &ip, port);
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen log_add = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
88cb1595bf0ad84846b9c611a1afbca35fcfe460Timo Sirainen /* just forward this to the entire ring until it reaches back to
88cb1595bf0ad84846b9c611a1afbca35fcfe460Timo Sirainen itself. some hosts may see this twice, but that's the only way to
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi guarantee that it gets seen by everyone. resetting the host multiple
88cb1595bf0ad84846b9c611a1afbca35fcfe460Timo Sirainen times may cause us to handle its commands multiple times, but the
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen commands can handle that. however, we need to also handle a
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen situation where the added director never comes back - we don't want
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen to send the director information in a loop forever. */
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen if (conn->dir->right != NULL &&
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen director_host_cmp_to_self(host, conn->dir->right->host,
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen conn->dir->self_host) > 0) {
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen dir_debug("Received DIRECTOR update for a host where we should be connected to. "
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen "Not forwarding it since it's probably crashed.");
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen } else {
336cdc9993838d967bbaf214a671975c2e7e5942Timo Sirainen director_notify_ring_added(host,
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen director_connection_get_host(conn), log_add);
336cdc9993838d967bbaf214a671975c2e7e5942Timo 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;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t 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
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if (remote_ring_completed != 0 && !conn->dir->ring_handshaked) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen /* clear everything we have and use only what remote sends us */
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("%s: We're joining a ring - replace all hosts",
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen conn->name);
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 }
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen } else if (remote_ring_completed == 0 && conn->dir->ring_handshaked) {
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen /* ignore whatever remote sends */
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("%s: Remote is joining our ring - "
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen "ignore all remote HOSTs", conn->name);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen conn->ignore_host_events = TRUE;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen } else {
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("%s: Merge rings' hosts", conn->name);
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen }
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen conn->handshake_sending_hosts = TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen return TRUE;
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen}
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic int
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainendirector_cmd_is_seen_full(struct director_connection *conn,
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen const char *const **_args, unsigned int *seq_r,
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen struct director_host **host_r)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *const *args = *_args;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct ip_addr ip;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch unsigned int 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 ||
009217abb57a24a4076092e8e4e165545747839eStephan Bosch net_str2port(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;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen *seq_r = seq;
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
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainenstatic int
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainendirector_cmd_is_seen(struct director_connection *conn,
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen const char *const **_args,
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen struct director_host **host_r)
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen{
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen unsigned int seq;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen return director_cmd_is_seen_full(conn, _args, &seq, host_r);
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen}
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo 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;
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen bool weak = TRUE, weak_forward = FALSE, forced;
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
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo Sirainen /* could this before it's potentially ignored */
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo Sirainen conn->dir->num_incoming_requests++;
dd19de9b6382c9a47b65df6b2396789df37a19fbTimo 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
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen if (ret == 0) {
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen /* First time we're seeing this - forward it to others also.
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen We'll want to do it even if the user was already marked as
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen weak, because otherwise if two directors mark the user weak
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen at the same time both the USER-WEAK notifications reach
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen only half the directors until they collide and neither one
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen finishes going through the whole ring marking the user
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen non-weak. */
f8c57c39abd8d987fdbc90dff5289b420017a700Timo Sirainen weak_forward = TRUE;
f8c57c39abd8d987fdbc90dff5289b420017a700Timo 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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen username_hash, dir_host->ip_str);
c6a5305674d2aa59ee52dc101ef87bbcb04f04efTimo Sirainen weak_forward = TRUE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen ret = director_user_refresh(conn, username_hash,
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen host, ioloop_time, weak, &forced, &user);
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen /* user is refreshed with ioloop_time, it can't be expired already */
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen i_assert(ret >= 0);
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen if (ret > 0 || weak_forward) {
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen /* user changed, or we've decided that we need to forward
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen the weakness notification to the rest of the ring even
0bd3eb7c8139cfb80f46dc596c5fe7cdbb1d2aeeTimo Sirainen though we already knew it. */
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen if (forced)
fb9dfa9ea15abdbf248021cfb7bf2846410116e6Timo Sirainen src_host = conn->dir->self_host;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen if (!user->weak)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen director_update_user(conn->dir, src_host, user);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen else {
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen director_update_user_weak(conn->dir, src_host, conn,
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{
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen struct director_host *src_host = conn->host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen const char *tag = "", *host_tag, *hostname = NULL;
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen unsigned int arg_count, vhost_count;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen bool update, down = FALSE;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen time_t last_updown_change = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen arg_count = str_array_length(args);
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen if (arg_count < 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 }
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen if (arg_count >= 3)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen tag = args[2];
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen if (arg_count >= 4) {
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen if ((args[3][0] != 'D' && args[3][0] != 'U') ||
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen str_to_time(args[3]+1, &last_updown_change) < 0) {
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen director_cmd_error(conn, "Invalid updown parameters");
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen return FALSE;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
c5279d575d40f7c4c6cd4b44dbf8fba55e156d90Timo Sirainen down = args[3][0] == 'D';
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen if (arg_count >= 5)
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen hostname = args[4];
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 }
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen if (tag[0] != '\0' && conn->minor_version < DIRECTOR_VERSION_TAGS_V2) {
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen director_cmd_error(conn, "Received a host tag from older director version with incompatible tagging support");
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen return FALSE;
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL) {
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen host = mail_host_add_hostname(conn->dir->mail_hosts,
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen hostname, &ip, tag);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen update = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen update = host->vhost_count != vhost_count ||
ed4a4d9b8289061627d5236da31b1a989b0fd6b1Timo Sirainen host->down != down;
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen host_tag = mail_host_get_tag(host);
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen if (strcmp(tag, host_tag) != 0) {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_error("director(%s): Host %s changed tag from '%s' to '%s'",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen conn->name, host->ip_str,
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen host_tag, tag);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen mail_host_set_tag(host, tag);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen update = TRUE;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen }
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen if (update && host->desynced) {
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen string_t *str = t_str_new(128);
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_printfa(str, "director(%s): Host %s is being updated before previous update had finished (",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen conn->name, host->ip_str);
12f8ffba02e99b53ee71cd44f9947c6a59ff9ea4Timo Sirainen if (host->down != down &&
12f8ffba02e99b53ee71cd44f9947c6a59ff9ea4Timo Sirainen host->last_updown_change > last_updown_change) {
12f8ffba02e99b53ee71cd44f9947c6a59ff9ea4Timo Sirainen /* our host has a newer change. preserve it. */
12f8ffba02e99b53ee71cd44f9947c6a59ff9ea4Timo Sirainen down = host->down;
12f8ffba02e99b53ee71cd44f9947c6a59ff9ea4Timo Sirainen }
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen if (host->down != down) {
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen if (host->down)
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_append(str, "down -> up");
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen else
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_append(str, "up -> down");
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen }
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen if (host->vhost_count != vhost_count) {
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen if (host->down != down)
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_append(str, ", ");
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_printfa(str, "vhosts %u -> %u",
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen host->vhost_count, vhost_count);
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen }
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_append(str, ") - ");
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen vhost_count = I_MIN(vhost_count, host->vhost_count);
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen last_updown_change = I_MAX(last_updown_change,
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen host->last_updown_change);
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen str_printfa(str, "setting to state=%s vhosts=%u",
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen down ? "down" : "up", vhost_count);
78a6431465ac6ee6e870352a68ea1d7a8170376aTimo Sirainen i_warning("%s", str_c(str));
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen /* make the change appear to come from us, so it
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen reaches the full ring */
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen dir_host = NULL;
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen src_host = conn->dir->self_host;
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (update) {
b3abfd0ac256ffa0cbfd74c3793eac4e83d41f78Martti Rannanjärvi const char *log_prefix = t_strdup_printf("director(%s): ",
b3abfd0ac256ffa0cbfd74c3793eac4e83d41f78Martti Rannanjärvi conn->name);
b3abfd0ac256ffa0cbfd74c3793eac4e83d41f78Martti Rannanjärvi mail_host_set_down(host, down, last_updown_change, log_prefix);
b3abfd0ac256ffa0cbfd74c3793eac4e83d41f78Martti Rannanjärvi mail_host_set_vhost_count(host, vhost_count, log_prefix);
8752573c44bcd139ae3ecc6d8e917c2c60bcb89fTimo Sirainen director_update_host(conn->dir, src_host, dir_host, host);
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen } else {
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen dir_debug("Ignoring host %s update vhost_count=%u "
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen "down=%d last_updown_change=%ld (hosts_hash=%u)",
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen net_ip2addr(&ip), vhost_count, down ? 1 : 0,
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen (long)last_updown_change,
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen mail_hosts_hash(conn->dir->mail_hosts));
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
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainenstatic bool
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainendirector_cmd_user_kick(struct director_connection *conn,
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen const char *const *args)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen{
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen struct director_host *dir_host;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen int ret;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen return ret > 0;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if (str_array_length(args) != 1) {
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen director_cmd_error(conn, "Invalid parameters");
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen return FALSE;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen }
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen director_kick_user(conn->dir, conn->host, dir_host, args[0]);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen return TRUE;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen}
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainenstatic bool
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainendirector_cmd_user_kick_alt(struct director_connection *conn,
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen const char *const *args)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen{
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen struct director_host *dir_host;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen int ret;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen return ret > 0;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (str_array_length(args) != 2) {
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen director_cmd_error(conn, "Invalid parameters");
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen return FALSE;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen }
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen director_kick_user_alt(conn->dir, conn->host, dir_host, args[0], args[1]);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen return TRUE;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen}
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainenstatic bool
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainendirector_cmd_user_kick_hash(struct director_connection *conn,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen const char *const *args)
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen{
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen struct director_host *dir_host;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen unsigned int username_hash;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen struct ip_addr except_ip;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen int ret;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen return ret > 0;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen if (str_array_length(args) != 2 ||
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen net_addr2ip(args[1], &except_ip) < 0) {
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen director_cmd_error(conn, "Invalid parameters");
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen return FALSE;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen }
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen director_kick_user_hash(conn->dir, conn->host, dir_host,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen username_hash, &except_ip);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen return TRUE;
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen}
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo 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;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen unsigned int seq, username_hash;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen int ret;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen if ((ret = director_cmd_is_seen_full(conn, &args, &seq, &dir_host)) < 0)
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen return FALSE;
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
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen if (ret > 0) {
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen i_assert(dir_host != NULL);
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen dir_debug("User %u - ignoring already seen USER-KILLED-EVERYWHERE "
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen "with seq=%u <= %s.last_seq=%u", username_hash,
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen seq, dir_host->name, dir_host->last_seq);
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen return TRUE;
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo Sirainen }
0874d7a4fa15322318c71291f0134ff7cc49bbb8Timo 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;
7fd22d5521c8ecf84c40fbef553e70bf2553a663Timo Sirainen int handshake_msecs = timeval_diff_msecs(&ioloop_timeval, &conn->connected_time);
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;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi mail_hosts_sort_users(conn->dir->mail_hosts);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen }
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
8420ca2c46d15257d43a5507e841325134fffa75Timo Sirainen str = t_str_new(128);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_printfa(str, "director(%s): Handshake finished in %u.%03u secs (",
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen conn->name, handshake_msecs/1000, handshake_msecs%1000);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen director_connection_append_stats(conn, str);
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append_c(str, ')');
7fd22d5521c8ecf84c40fbef553e70bf2553a663Timo Sirainen if (handshake_msecs >= DIRECTOR_HANDSHAKE_WARN_SECS*1000)
8420ca2c46d15257d43a5507e841325134fffa75Timo Sirainen i_warning("%s", str_c(str));
8420ca2c46d15257d43a5507e841325134fffa75Timo Sirainen else
8420ca2c46d15257d43a5507e841325134fffa75Timo Sirainen i_info("%s", str_c(str));
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",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen conn->host->ip_str,
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
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainenstatic int
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainendirector_handshake_cmd_options(struct director_connection *conn,
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen const char *const *args)
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen{
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen bool consistent_hashing = FALSE;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen unsigned int i;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen for (i = 0; args[i] != NULL; i++) {
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen if (strcmp(args[i], DIRECTOR_OPT_CONSISTENT_HASHING) == 0)
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen consistent_hashing = TRUE;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen }
00cc7eb569710722af0e0af652034b9fc22c57dfMartti Rannanjärvi if (!consistent_hashing) {
00cc7eb569710722af0e0af652034b9fc22c57dfMartti Rannanjärvi i_error("director(%s): director_consistent_hashing settings "
00cc7eb569710722af0e0af652034b9fc22c57dfMartti Rannanjärvi "differ between directors. Set "
00cc7eb569710722af0e0af652034b9fc22c57dfMartti Rannanjärvi "director_consistent_hashing=yes on old directors",
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen conn->name);
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen return -1;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen }
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen return 1;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen}
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainenstatic int
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_handle_handshake(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd, const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch unsigned int major_version;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch
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;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } else if (str_to_uint(args[1], &major_version) < 0 ||
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch str_to_uint(args[2], &conn->minor_version) < 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch i_error("director(%s): Invalid protocol version: "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "%s.%s", conn->name, args[1], args[2]);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch return -1;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } else if (major_version != DIRECTOR_VERSION_MAJOR) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Incompatible protocol version: "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "%u vs %u", conn->name, major_version,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_VERSION_MAJOR);
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen if (conn->minor_version < DIRECTOR_VERSION_TAGS_V2 &&
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen mail_hosts_have_tags(conn->dir->mail_hosts)) {
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen i_error("director(%s): Director version supports incompatible tags", conn->name);
389a9fe1636038527f7a75fb5d38361c90bd676aTimo Sirainen return -1;
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->version_received = TRUE;
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen director_finish_sending_handshake(conn);
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 }
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen if (strcmp(cmd, "OPTIONS") == 0)
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen return director_handshake_cmd_options(conn, args);
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
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen if (conn->in &&
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen (strcmp(cmd, "U") == 0 ||
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen (strcmp(cmd, "USER") == 0 &&
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen CMD_IS_USER_HANDSHAKE(conn->minor_version, 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,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen unsigned int timestamp, unsigned int hosts_hash)
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
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (hosts_hash != 0 &&
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen hosts_hash != mail_hosts_hash(conn->dir->mail_hosts)) {
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen i_error("director(%s): Hosts unexpectedly changed during SYNC reply - resending"
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen "(seq=%u, old hosts_hash=%u, new hosts_hash=%u)",
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen conn->name, seq, hosts_hash,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen mail_hosts_hash(dir->mail_hosts));
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen (void)director_resend_sync(dir);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen return FALSE;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen }
abe29107f5dce932d28a00912d2d75a01021bef1Timo 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 {
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen dir_debug("Ring is synced (%s sent seq=%u, hosts_hash=%u)",
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen conn->name, seq,
1574df6b0bc965212f1152e480e7a762cdaa8226Timo Sirainen mail_hosts_hash(dir->mail_hosts));
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen int sync_msecs =
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen timeval_diff_msecs(&ioloop_timeval, &dir->last_sync_start_time);
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen if (sync_msecs >= 0)
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen dir->last_sync_msecs = sync_msecs;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_set_ring_synced(dir);
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen } else {
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen if (seq < host->last_sync_seq &&
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen timestamp < host->last_sync_timestamp +
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen DIRECTOR_SYNC_STALE_TIMESTAMP_RESET_SECS) {
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;
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen } else if (seq < host->last_sync_seq) {
688653dfb53411a9ca66dc5647363b53e4f2c997Aki Tuomi i_warning("Last SYNC seq for %s appears to be stale, resetting "
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen "(seq=%u, timestamp=%u -> seq=%u, timestamp=%u)",
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->name, host->last_sync_seq,
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->last_sync_timestamp, seq, timestamp);
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->last_sync_seq = seq;
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->last_sync_timestamp = timestamp;
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->last_sync_seq_counter = 1;
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen } else if (seq > host->last_sync_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;
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen dir_debug("Update SYNC for %s "
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen "(seq=%u, timestamp=%u -> seq=%u, timestamp=%u)",
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->name, host->last_sync_seq,
dfbd56c81cb8fb7fe70393c4682cc99e68fe06b6Timo Sirainen host->last_sync_timestamp, 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
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (hosts_hash != 0 &&
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen hosts_hash != mail_hosts_hash(conn->dir->mail_hosts)) {
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (host->desynced_hosts_hash != hosts_hash) {
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen dir_debug("Ignore director %s stale SYNC request whose hosts don't match us "
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen "(seq=%u, remote hosts_hash=%u, my hosts_hash=%u)",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, seq, hosts_hash,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen mail_hosts_hash(dir->mail_hosts));
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen host->desynced_hosts_hash = hosts_hash;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen return FALSE;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen }
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen /* we'll get here only if we received a SYNC twice
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen with the same wrong hosts_hash. FIXME: this gets
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen triggered unnecessarily sometimes if hosts are
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen changing rapidly. */
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen i_error("director(%s): Director %s SYNC request hosts don't match us - resending hosts "
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen "(seq=%u, remote hosts_hash=%u, my hosts_hash=%u)",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen conn->name, host->ip_str, seq,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen hosts_hash, mail_hosts_hash(dir->mail_hosts));
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen director_resend_hosts(dir);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen return FALSE;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen }
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen host->desynced_hosts_hash = 0;
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,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen timestamp, hosts_hash);
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen } else {
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen dir_debug("director(%s): We have no right connection - "
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen "delay replying to SYNC until finished", conn->name);
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen host->delayed_sync_seq = seq;
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen host->delayed_sync_minor_version = minor_version;
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen host->delayed_sync_timestamp = timestamp;
67cb14c7fb54a031818228522dc7255d5cd00f0aTimo Sirainen host->delayed_sync_hosts_hash = hosts_hash;
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;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen unsigned int arg_count, seq, minor_version = 0, timestamp = ioloop_time;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen unsigned int hosts_hash = 0;
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen arg_count = str_array_length(args);
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen if (arg_count < 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 }
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen if (arg_count >= 4 && str_to_uint(args[3], &minor_version) < 0) {
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen director_cmd_error(conn, "Invalid parameters");
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen return FALSE;
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen }
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen if (arg_count >= 5 && str_to_uint(args[4], &timestamp) < 0) {
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen director_cmd_error(conn, "Invalid parameters");
dd81d88575909f2bd99eafffb13c48c3b8cf9529Timo Sirainen return FALSE;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen }
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen if (arg_count >= 6 && str_to_uint(args[5], &hosts_hash) < 0) {
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen director_cmd_error(conn, "Invalid parameters");
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen return FALSE;
abe29107f5dce932d28a00912d2d75a01021bef1Timo 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,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen minor_version, timestamp,
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen hosts_hash))
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return TRUE;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen }
fe201fb1819622ab33c51ef5a0a1f672e906b21aTimo Sirainen
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen /* If directors got disconnected while we were waiting a SYNC reply,
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen it might have gotten lost. If we've received a DIRECTOR update since
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen the last time we sent a SYNC, retry sending it here to make sure
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen it doesn't get stuck. We don't want to do this too eagerly because
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen it may trigger desynced_hosts_hash != hosts_hash mismatch, which
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen causes unnecessary error logging and hosts-resending. */
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen if ((host == NULL || !host->self) &&
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen dir->last_sync_sent_ring_change_counter != dir->ring_change_counter &&
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
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainenstatic void director_disconnect_timeout(struct director_connection *conn)
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen{
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen director_connection_deinit(&conn, "CONNECT requested");
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen}
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainenstatic void
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainendirector_reconnect_after_wrong_connect_timeout(struct director_connection *conn)
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen{
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen struct director *dir = conn->dir;
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen director_connection_deinit(&conn, "Wrong CONNECT requested");
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen if (dir->right == NULL)
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen director_connect(dir, "Reconnecting after wrong CONNECT request");
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen}
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainenstatic void
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainendirector_reconnect_after_wrong_connect(struct director_connection *conn)
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen{
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen if (conn->to_disconnect != NULL)
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen return;
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen conn->to_disconnect =
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen timeout_add_short(DIRECTOR_RECONNECT_AFTER_WRONG_CONNECT_MSECS,
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen director_reconnect_after_wrong_connect_timeout, conn);
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen}
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo 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;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen const char *right_state;
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);
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);
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen director_reconnect_after_wrong_connect(conn);
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen return TRUE;
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen }
69ea755e44ae1ec65971acc737b2641a4917a60eTimo Sirainen if (host->removed) {
69ea755e44ae1ec65971acc737b2641a4917a60eTimo Sirainen dir_debug("Ignoring CONNECT request to %s (director is removed)",
69ea755e44ae1ec65971acc737b2641a4917a60eTimo Sirainen host->name);
69ea755e44ae1ec65971acc737b2641a4917a60eTimo Sirainen director_reconnect_after_wrong_connect(conn);
69ea755e44ae1ec65971acc737b2641a4917a60eTimo Sirainen return TRUE;
69ea755e44ae1ec65971acc737b2641a4917a60eTimo Sirainen }
1055d8038122c4f4190d37d98fdff6791d1306f8Timo Sirainen
002eaedb419e67eec1b518f520eca133a6ee27dbTimo Sirainen /* reset failure timestamp so we'll actually try to connect there. */
002eaedb419e67eec1b518f520eca133a6ee27dbTimo Sirainen host->last_network_failure = 0;
002eaedb419e67eec1b518f520eca133a6ee27dbTimo Sirainen /* reset removed-flag, so we don't crash */
002eaedb419e67eec1b518f520eca133a6ee27dbTimo Sirainen host->removed = FALSE;
002eaedb419e67eec1b518f520eca133a6ee27dbTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (dir->right == NULL) {
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen right_state = "initializing right";
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen } else {
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen right_state = t_strdup_printf("replacing current right %s",
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen dir->right->name);
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen /* disconnect from right side immediately - it's not accepting
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen any further commands from us. */
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen if (conn->dir->right != conn)
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen director_connection_deinit(&conn->dir->right, "CONNECT requested");
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen else if (conn->to_disconnect == NULL) {
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen conn->to_disconnect =
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen timeout_add_short(0, director_disconnect_timeout, conn);
d8a93844f0b25be82da9c0ab79c321c110f5fb5fTimo Sirainen }
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen }
d935f94a88940e4639f685c662eadeba1e9a4914Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* connect here */
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen (void)director_connect_host(dir, host, t_strdup_printf(
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen "Received CONNECT request from %s - %s",
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen conn->name, right_state));
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
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainenstatic bool director_cmd_ping(struct director_connection *conn,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen const char *const *args)
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen{
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen time_t sent_time;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen uintmax_t send_buffer_size;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (str_array_length(args) >= 2 &&
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_to_time(args[0], &sent_time) == 0 &&
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_to_uintmax(args[1], &send_buffer_size) == 0) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen int diff_secs = ioloop_time - sent_time;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (diff_secs*1000+500 > DIRECTOR_CONNECTION_PINGPONG_WARN_MSECS) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen i_warning("director(%s): PING response took %d secs to receive "
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen "(send buffer was %ju bytes)",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->name, diff_secs, send_buffer_size);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen director_connection_send(conn,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen t_strdup_printf("PONG\t%"PRIdTIME_T"\t%zu\n",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen ioloop_time, o_stream_get_buffer_used_size(conn->output)));
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen return TRUE;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen}
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainenstatic void
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainendirector_ping_append_extra(struct director_connection *conn, string_t *str,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen time_t pong_sent_time,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen uintmax_t pong_send_buffer_size)
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen{
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen struct rusage usage;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_printfa(str, "buffer size at PING was %zu bytes", conn->ping_sent_buffer_size);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (pong_sent_time != 0) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_printfa(str, ", remote sent it %"PRIdTIME_T" secs ago",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen ioloop_time - pong_sent_time);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (pong_send_buffer_size != (uintmax_t)-1) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_printfa(str, ", remote buffer size at PONG was %ju bytes",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen pong_send_buffer_size);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (conn->ping_sent_user_cpu.tv_sec != (time_t)-1 &&
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen getrusage(RUSAGE_SELF, &usage) == 0) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen int diff = timeval_diff_msecs(&usage.ru_utime,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen &conn->ping_sent_user_cpu);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_printfa(str, ", %u.%03u CPU secs since PING was sent",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen diff/1000, diff%1000);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_printfa(str, ", %"PRIuUOFF_T" bytes input",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->input->v_offset - conn->ping_sent_input_offset);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_printfa(str, ", %"PRIuUOFF_T" bytes output",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->output->offset - conn->ping_sent_output_offset);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen}
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainenstatic bool director_cmd_pong(struct director_connection *conn,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen const char *const *args)
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen{
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen time_t sent_time;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen uintmax_t send_buffer_size;
91b0bd6e7277646032d5001822f65575be75f062Timo 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
b2117031bf2c3e35f6efad43b78caaecb6ebdad9Timo Sirainen if (str_array_length(args) < 2 ||
b2117031bf2c3e35f6efad43b78caaecb6ebdad9Timo Sirainen str_to_time(args[0], &sent_time) < 0 ||
b2117031bf2c3e35f6efad43b78caaecb6ebdad9Timo Sirainen str_to_uintmax(args[1], &send_buffer_size) < 0) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen sent_time = 0;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen send_buffer_size = (uintmax_t)-1;
b2117031bf2c3e35f6efad43b78caaecb6ebdad9Timo Sirainen }
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo Sirainen int ping_msecs = timeval_diff_msecs(&ioloop_timeval, &conn->ping_sent_time);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (ping_msecs >= 0) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (ping_msecs > DIRECTOR_CONNECTION_PINGPONG_WARN_MSECS) {
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen string_t *extra = t_str_new(128);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen director_ping_append_extra(conn, extra, sent_time, send_buffer_size);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen i_warning("director(%s): PONG response took %u.%03u secs (%s)",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->name, ping_msecs/1000, ping_msecs%1000,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen str_c(extra));
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo Sirainen conn->last_ping_msecs = ping_msecs;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen }
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo 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
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (strcmp(cmd, "PING") == 0)
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen return director_cmd_ping(conn, args);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (strcmp(cmd, "PONG") == 0)
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen return director_cmd_pong(conn, args);
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);
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if (strcmp(cmd, "USER-KICK") == 0)
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen return director_cmd_user_kick(conn, args);
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (strcmp(cmd, "USER-KICK-ALT") == 0)
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen return director_cmd_user_kick_alt(conn, args);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen if (strcmp(cmd, "USER-KICK-HASH") == 0)
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen return director_cmd_user_kick_hash(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,
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen 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
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen args = t_strsplit_tabescaped_inplace(line);
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen cmd = args[0];
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;
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen conn->cur_args = args;
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen ret = director_connection_handle_cmd(conn, cmd, args+1);
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen conn->cur_cmd = NULL;
e8d44b65aab0a6723e7906756d0825e22ee85a82Timo Sirainen conn->cur_args = NULL;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen return ret;
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen}
98d5941dc28754f32432edc38578b946ba71dd0bTimo Sirainen
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainenstatic void
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainendirector_connection_log_disconnect(struct director_connection *conn, int err,
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen const char *errstr)
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen{
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;
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen if (errstr[0] == '\0')
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen str_printfa(str, ": %m");
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen else
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen str_printfa(str, ": %s", errstr);
06fc82430569125dccb8cd20e122e77b44698c7eTimo Sirainen }
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen
00367aee8d303589e1e1b50c3b5f007ed6489a65Timo Sirainen str_append(str, " (");
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen director_connection_append_stats(conn, str);
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");
43edd1078b1ba2f094d9c53f9e7c553f971657c1Timo Sirainen if (conn->synced)
43edd1078b1ba2f094d9c53f9e7c553f971657c1Timo Sirainen str_append(str, ", synced");
1ef9754a5169dc886d15089e59b45a7017d647d7Timo Sirainen str_append_c(str, ')');
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;
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen uoff_t prev_offset;
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 */
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_log_disconnect(conn, conn->input->stream_errno,
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen i_stream_get_error(conn->input));
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_disconnected(&conn, i_stream_get_error(conn->input));
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 }
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen conn->last_input = ioloop_timeval;
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen conn->refcount++;
6cb8e7d726a7e9d157e87fb379982d52100b283fTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_sync_freeze(dir);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen prev_offset = conn->input->v_offset;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen dir->ring_traffic_input += conn->input->v_offset - prev_offset;
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen prev_offset = conn->input->v_offset;
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = director_connection_handle_line(conn, line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } T_END;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!ret) {
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen if (!director_connection_unref(conn))
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen break;
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);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen if (conn != NULL) {
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen if (director_connection_unref(conn))
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen timeout_reset(conn->to_ping);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainenstatic void director_connection_send_directors(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hostp;
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen string_t *str = t_str_new(64);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&conn->dir->dir_hosts, hostp) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if ((*hostp)->removed)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen continue;
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen str_truncate(str, 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, "DIRECTOR\t%s\t%u\n",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen (*hostp)->ip_str, (*hostp)->port);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen director_connection_send(conn, str_c(str));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8d63b0ab4dea920a4dd6a4469289950eef50a063Timo Sirainenstatic void
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainendirector_connection_send_hosts(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *const *hostp;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen bool send_updowns;
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen string_t *str = t_str_new(128);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen i_assert(conn->version_received);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen send_updowns = conn->minor_version >= DIRECTOR_VERSION_UPDOWN;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen str_printfa(str, "HOST-HAND-START\t%u\n",
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen conn->dir->ring_handshaked ? 1 : 0);
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen struct mail_host *host = *hostp;
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen const char *host_tag = mail_host_get_tag(host);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str_printfa(str, "HOST\t%s\t%u",
bd4bbe6478a97e3fab77b05257dd1397c7c090eaTimo Sirainen host->ip_str, host->vhost_count);
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen if (host_tag[0] != '\0' || send_updowns) {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str_append_c(str, '\t');
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen str_append_tabescaped(str, host_tag);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (send_updowns) {
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen str_printfa(str, "\t%c%ld\t", host->down ? 'D' : 'U',
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen (long)host->last_updown_change);
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen if (host->hostname != NULL)
9de5eb9e1ac3a07c4197a60fdefd412d6cc78eb2Timo Sirainen str_append_tabescaped(str, host->hostname);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen str_append_c(str, '\n');
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen director_connection_send(conn, str_c(str));
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen str_truncate(str, 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen str_printfa(str, "HOST-HAND-END\t%u\n",
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen conn->dir->ring_handshaked ? 1 : 0);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen director_connection_send(conn, str_c(str));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainenstatic int director_connection_send_done(struct director_connection *conn)
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen{
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen i_assert(conn->version_received);
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
00cc7eb569710722af0e0af652034b9fc22c57dfMartti Rannanjärvi if (conn->minor_version >= DIRECTOR_VERSION_OPTIONS) {
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen director_connection_send(conn,
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen "OPTIONS\t"DIRECTOR_OPT_CONSISTENT_HASHING"\n");
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen } else {
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen i_error("director(%s): Director version is too old for supporting director_consistent_hashing=yes",
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen conn->name);
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen return -1;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen }
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen director_connection_send(conn, "DONE\n");
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen return 0;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen}
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_connection_send_users(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen string_t *str = t_str_new(128);
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen char dec_buf[MAX_INT_STRLEN];
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen unsigned int sent_count = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen i_assert(conn->version_received);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen /* with new versions use "U" for sending the handshake users, because
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen otherwise their parameters may look identical and can't be
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen distinguished. */
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen if (director_connection_get_minor_version(conn) >= DIRECTOR_VERSION_HANDSHAKE_U_CMD)
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen str_append(str, "U\t");
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen else
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append(str, "USER\t");
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen size_t cmd_prefix_len = str_len(str);
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen while ((user = director_iterate_users_next(conn->user_iter)) != NULL) {
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen str_truncate(str, cmd_prefix_len);
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append(str, dec2str_buf(dec_buf, user->username_hash));
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append_c(str, '\t');
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append(str, user->host->ip_str);
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append_c(str, '\t');
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append(str, dec2str_buf(dec_buf, user->timestamp));
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen if (user->weak)
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append(str, "\tw");
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen str_append_c(str, '\n');
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen
e5ef6fa616e0b0ed1bf545b39f0d9e8dea48c970Timo Sirainen conn->handshake_users_sent++;
6b740bf2d35b25dcc607cfd16593fe912ec49812Timo Sirainen director_connection_send(conn, str_c(str));
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen if (++sent_count >= DIRECTOR_HANDSHAKE_MAX_USERS_SENT_PER_FLUSH) {
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen /* Don't send too much at once to avoid hangs */
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen timeout_reset(conn->to_ping);
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen return 0;
ad394c531ca4b7ca85f3741fa01f96c36c008c70Timo Sirainen }
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 }
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen director_iterate_users_deinit(&conn->user_iter);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen if (director_connection_send_done(conn) < 0)
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen return -1;
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;
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi mail_hosts_sort_users(conn->dir->mail_hosts);
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
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen conn->last_output = ioloop_timeval;
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen if (conn->user_iter != NULL) {
377dd19a90436b8f96902af741a3ea130bc3fe75Timo Sirainen /* still handshaking USER list */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen ret = director_connection_send_users(conn);
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen if (ret < 0) {
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen director_connection_log_disconnect(conn, conn->output->stream_errno,
1a85ac6b42b73c48143ef7b76f95c15e89d3ca4dTimo Sirainen o_stream_get_error(conn->output));
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_disconnected(&conn,
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen o_stream_get_error(conn->output));
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen } else {
b695e4700d0953031205ad4411182c4bb207605cTimo Sirainen o_stream_set_flush_pending(conn->output, TRUE);
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen }
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);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen conn->refcount = 1;
7fd22d5521c8ecf84c40fbef553e70bf2553a663Timo Sirainen conn->created = ioloop_timeval;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->fd = fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir = dir;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE);
311cf367b949f360c9a90822f06f39df31ec69e3Timo Sirainen conn->output = o_stream_create_fd(conn->fd, dir->set->director_output_buffer_size);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
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"
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen "ME\t%s\t%u\t%lld\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_VERSION_MAJOR, DIRECTOR_VERSION_MINOR,
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen net_ip2addr(&conn->dir->self_ip), conn->dir->self_port,
9054b5f92a7e5666c6beaa04916699a1408bf021Timo Sirainen (long long)time(NULL)));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainenstatic void director_connection_set_connected(struct director_connection *conn)
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainen{
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen struct rusage usage;
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainen conn->connected = TRUE;
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainen conn->connected_time = ioloop_timeval;
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen if (getrusage(RUSAGE_SELF, &usage) == 0) {
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen conn->connected_user_cpu_set = TRUE;
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen conn->connected_user_cpu = usage.ru_utime;
f534eb971e3e40087ad81dcd080c1d69424df417Timo Sirainen }
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainen}
c83e45c826c93c5122340a37a6faf99ce6078627Timo 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;
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainen director_connection_set_connected(conn);
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);
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_ME_TIMEOUT_MSECS,
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen director_connection_init_timeout, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen i_info("Incoming connection from director %s", conn->name);
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{
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));
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_disconnected(&conn, strerror(err));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
c83e45c826c93c5122340a37a6faf99ce6078627Timo Sirainen director_connection_set_connected(conn);
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);
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_ME_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);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen director_connection_send_directors(conn);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen o_stream_uncork(conn->output);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen /* send the rest of the handshake after we've received the remote's
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen version number */
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen}
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainenstatic void director_finish_sending_handshake(struct director_connection *conn)
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen{
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen if (
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen conn->in) {
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen /* only outgoing connections send hosts & users */
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen return;
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen }
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen o_stream_cork(conn->output);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen director_connection_send_hosts(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen i_assert(conn->user_iter == NULL);
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen /* Iterate only through users that aren't refreshed since the
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen iteration started. The refreshed users will already be sent as
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen regular USER updates, so they don't need to be sent again.
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen We especially don't want to send these users again, because
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen otherwise in a rapidly changing director we might never end up
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen sending all the users when they constantly keep being added to the
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen end of the list. (The iteration lists users in order from older to
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen newer.) */
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen conn->user_iter = director_iterate_users_init(conn->dir, TRUE);
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
f37684a44ce2371e04cf40ba3d26630fee4630f6Timo Sirainen if (director_connection_send_users(conn) == 0)
f37684a44ce2371e04cf40ba3d26630fee4630f6Timo Sirainen o_stream_set_flush_pending(conn->output, TRUE);
a9ade104616bbb81c34cc6f8bfde5dab0571afacTimo Sirainen
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);
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_CONNECT_TIMEOUT_MSECS,
5a530f778cc3eae05e70d13b8e5d7d501e7ba0b3Timo Sirainen director_connection_init_timeout, 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
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_assert(conn->fd != -1);
312213260e384239ac93c77951c2f1f5f3d3611eTimo 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;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0e94f6c27bffd58953b3479415532bff2bc04732Timo Sirainen if (conn->users_unsorted) {
0e94f6c27bffd58953b3479415532bff2bc04732Timo Sirainen /* Users were received, but handshake didn't finish.
0e94f6c27bffd58953b3479415532bff2bc04732Timo Sirainen Finish sorting so the users won't stay in wrong order. */
0e94f6c27bffd58953b3479415532bff2bc04732Timo Sirainen mail_hosts_sort_users(conn->dir->mail_hosts);
0e94f6c27bffd58953b3479415532bff2bc04732Timo Sirainen }
0e94f6c27bffd58953b3479415532bff2bc04732Timo Sirainen
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen if (conn->connect_request_to != NULL) {
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen director_host_unref(conn->connect_request_to);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen conn->connect_request_to = NULL;
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->user_iter != NULL)
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen director_iterate_users_deinit(&conn->user_iter);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to_disconnect);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to_pong);
f64b5bc9e73bedc63ba3c072c286542c29c69e43Timo Sirainen timeout_remove(&conn->to_ping);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&conn->io);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_stream_close(conn->input);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen o_stream_close(conn->output);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_close_fd(&conn->fd);
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen
6ffc2a3e61636ba8ad50a3be260885bb6b041a3dTimo Sirainen if (conn->in)
6ffc2a3e61636ba8ad50a3be260885bb6b041a3dTimo Sirainen master_service_client_connection_destroyed(master_service);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen director_connection_unref(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
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainenstatic bool director_connection_unref(struct director_connection *conn)
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen{
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_assert(conn->refcount > 0);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen if (--conn->refcount > 0)
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen return TRUE;
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen if (conn->host != NULL)
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen director_host_unref(conn->host);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_stream_unref(&conn->input);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen o_stream_unref(&conn->output);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_free(conn->name);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen i_free(conn);
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen return FALSE;
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen}
312213260e384239ac93c77951c2f1f5f3d3611eTimo Sirainen
ff060dcf76798701c0d1386717096062ff5cf9a8Phil Carmodystatic void director_connection_disconnected(struct director_connection **_conn,
ff060dcf76798701c0d1386717096062ff5cf9a8Phil Carmody const char *reason)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_connection *conn = *_conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director *dir = conn->dir;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
1707f8b66faf2dcd1fe2d1b07d421f9d006c9432Timo Sirainen if ((conn->connected_time.tv_sec == 0 ||
1707f8b66faf2dcd1fe2d1b07d421f9d006c9432Timo Sirainen conn->connected_time.tv_sec + 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
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_deinit(_conn, reason);
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (dir->right == NULL)
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_connect(dir, "Reconnecting after disconnection");
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)
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen director_connect(dir, "Reconnecting after error");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainenstatic void director_disconnect_write_error(struct director_connection *conn)
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen{
3a7a8b3685eb946a2153b9af92bc545800935a95Timo Sirainen struct director *dir = conn->dir;
3a7a8b3685eb946a2153b9af92bc545800935a95Timo Sirainen
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen director_connection_deinit(&conn, "write failure");
3a7a8b3685eb946a2153b9af92bc545800935a95Timo Sirainen if (dir->right == NULL)
3a7a8b3685eb946a2153b9af92bc545800935a95Timo Sirainen director_connect(dir, "Reconnecting after write failure");
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen}
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_send(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *data)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t 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) {
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen if (ret < 0) {
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen director_connection_log_disconnect(conn,
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen conn->output->stream_errno,
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen t_strdup_printf("write() failed: %s",
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen o_stream_get_error(conn->output)));
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen } else {
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen director_connection_log_disconnect(conn, EINVAL,
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen t_strdup_printf("Output buffer full at %zu",
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen o_stream_get_buffer_used_size(conn->output)));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_close(conn->output);
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen /* closing the stream when output buffer is full doesn't cause
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen disconnection itself. */
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen timeout_remove(&conn->to_disconnect);
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen conn->to_disconnect =
1511fc56b80709183cfa1201bfddd09d8a804c99Timo Sirainen timeout_add_short(0, director_disconnect_write_error, conn);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen } else {
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen conn->dir->ring_traffic_output += len;
a1febfe04b4fa4445e4f7fad371ef2b992449825Timo Sirainen conn->last_output = ioloop_timeval;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen conn->peak_bytes_buffered =
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen I_MAX(conn->peak_bytes_buffered,
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen o_stream_get_buffer_used_size(conn->output));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainendirector_connection_ping_idle_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen string_t *str = t_str_new(128);
8506e63fd90332f32d991337b48e06fd3db5b928Timo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &conn->ping_sent_time);
9224645cf699abae90fdd2cdf54247444f7acc18Timo Sirainen
1a85ac6b42b73c48143ef7b76f95c15e89d3ca4dTimo Sirainen str_printfa(str, "Ping timed out in %u.%03u secs: ",
8506e63fd90332f32d991337b48e06fd3db5b928Timo Sirainen diff/1000, diff%1000);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen director_ping_append_extra(conn, str, 0, (uintmax_t)-1);
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen director_connection_log_disconnect(conn, EINVAL, str_c(str));
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_disconnected(&conn, "Ping timeout");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainenstatic void director_connection_pong_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &conn->ping_sent_time);
1a85ac6b42b73c48143ef7b76f95c15e89d3ca4dTimo Sirainen const char *errstr;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
1a85ac6b42b73c48143ef7b76f95c15e89d3ca4dTimo Sirainen errstr = t_strdup_printf(
1a85ac6b42b73c48143ef7b76f95c15e89d3ca4dTimo Sirainen "PONG reply not received in %u.%03u secs, "
1a85ac6b42b73c48143ef7b76f95c15e89d3ca4dTimo Sirainen "although other input keeps coming",
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen diff/1000, diff%1000);
4ccb6182274da8e95e8dfb940ef9c03755381cd4Timo Sirainen director_connection_log_disconnect(conn, EINVAL, errstr);
d3ee83b4c24529fac4be5c1f30e254295e7addd9Timo Sirainen director_connection_disconnected(&conn, "Pong timeout");
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);
2adcf55dd8b0380cb2f1d2fd53accf448053d5d3Timo Sirainen conn->to_ping = timeout_add(conn->dir->set->director_ping_idle_timeout*1000,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_ping_idle_timeout, conn);
2adcf55dd8b0380cb2f1d2fd53accf448053d5d3Timo Sirainen conn->to_pong = timeout_add(conn->dir->set->director_ping_max_timeout*1000,
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen director_connection_pong_timeout, conn);
03fa2d644be0a9274e7e94fb4835cc374c539264Timo Sirainen conn->ping_waiting = TRUE;
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo Sirainen conn->ping_sent_time = ioloop_timeval;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->ping_sent_buffer_size = o_stream_get_buffer_used_size(conn->output);
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->ping_sent_input_offset = conn->input->v_offset;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->ping_sent_output_offset = conn->output->offset;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen struct rusage usage;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen if (getrusage(RUSAGE_SELF, &usage) == 0)
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->ping_sent_user_cpu = usage.ru_utime;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen else
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->ping_sent_user_cpu.tv_sec = (time_t)-1;
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen /* send it after getting the buffer size */
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen director_connection_send(conn, t_strdup_printf(
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen "PING\t%"PRIdTIME_T"\t%zu\n", ioloop_time,
91b0bd6e7277646032d5001822f65575be75f062Timo Sirainen conn->ping_sent_buffer_size));
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
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenbool director_connection_is_synced(struct director_connection *conn)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen{
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return conn->synced;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen}
ad404d294fedf792619aed432ed8de5174e9ce7cTimo 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}
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainenvoid director_connection_get_status(struct director_connection *conn,
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen struct director_connection_status *status_r)
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen{
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen i_zero(status_r);
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen status_r->bytes_read = conn->input->v_offset;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen status_r->bytes_sent = conn->output->offset;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen status_r->bytes_buffered = o_stream_get_buffer_used_size(conn->output);
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen status_r->peak_bytes_buffered = conn->peak_bytes_buffered;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen status_r->last_input = conn->last_input;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen status_r->last_output = conn->last_output;
f1551f4a50a471f0adecd92dd1f94702beeed72dTimo Sirainen status_r->last_ping_msecs = conn->last_ping_msecs;
5cdaaf2ecfed02503572935266f55123923ba00aTimo Sirainen status_r->handshake_users_sent = conn->handshake_users_sent;
5cdaaf2ecfed02503572935266f55123923ba00aTimo Sirainen status_r->handshake_users_received = conn->handshake_users_received;
56139ffc94e481ca1940ffd8d8f7166879150665Timo Sirainen}