director-connection.c revision dc1bc1685e4a0d58ae7bacaecc282d0ebde2d7da
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "array.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "network.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ostream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "str.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-request.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "user-directory.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <stdlib.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <unistd.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_VERSION_NAME "director"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_VERSION_MAJOR 1
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_VERSION_MINOR 0
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_INBUF_SIZE 1024
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_OUTBUF_SIZE (1024*1024*10)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define OUTBUF_FLUSH_THRESHOLD (1024*128)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS (2*1000)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *name;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* for incoming connections the director host isn't known until
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ME-line is received */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct io *io;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct istream *input;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct timeout *to, *to_ping;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *user_iter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int in:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int connected:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int version_received:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int me_received:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int handshake_received:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_ping(struct director_connection *conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_args_parse_ip_port(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr *ip_r, unsigned int *port_r)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_addr2ip(args[0], ip_r) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Command has invalid IP address: %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[0]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_to_uint(args[1], port_r) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Command has invalid port: %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[1]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool director_cmd_me(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *connect_str;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in && (!net_ip_compare(&conn->host->ip, &ip) ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host->port != port)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("Remote director thinks it's someone else "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "(connected to %s:%u, remote says it's %s:%u)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&conn->host->ip), conn->host->port,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&ip), port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_get(dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->me_received = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host = host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&host->ip), host->port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* make sure this is the correct incoming connection */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->self) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* probably we're trying to find our own ip. it's no */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Connection from self, dropping",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (dir->left == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* no conflicts yet */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (dir->left->host == host) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_warning("director(%s): Dropping existing connection "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "in favor of its new connection", host->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (director_host_cmp_to_self(dir->left->host, host,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_host) > 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* the old connection is the correct one.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen refer the client there. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, t_strdup_printf(
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "CONNECT\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&dir->left->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->left->host->port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* also make sure that the connection is alive */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_ping(dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* this new connection is the correct one. disconnect the old
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen one, but before that tell it to connect to the new one.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen that message might not reach it, so also send the same
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen message to right side. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->left, connect_str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)o_stream_flush(dir->left->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&dir->left);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->left = conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* tell the ring's right side to connect to this new director. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->right != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->left->host != dir->right->host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->right, connect_str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* there are only two directors */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* looks like we're the right side. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)director_connect_host(dir, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_user_refresh(struct director *dir, unsigned int username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host, time_t timestamp,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user **user_r)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool ret = FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user = user_directory_lookup(dir->users, username_hash);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *user_r = user_directory_add(dir->users, username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host, timestamp);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
dc1bc1685e4a0d58ae7bacaecc282d0ebde2d7daTimo Sirainen if (timestamp == ioloop_time && (time_t)user->timestamp != timestamp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_directory_refresh(dir->users, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user->host != host) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("User hash %u is being redirected to two hosts: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "%s and %s", username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&user->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&host->ip));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->host = host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *user_r = user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_handshake_cmd_user(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int username_hash, timestamp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 3 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[1], &ip) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[2], &timestamp) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid USER handshake args",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = mail_host_lookup(&ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): USER used unknown host %s in handshake",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[1]);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_user_refresh(conn->dir, username_hash, host, timestamp, &user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool director_cmd_director(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_lookup(conn->dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* already have this, skip */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* save the director and forward it */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_host_add(conn->dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn->dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strdup_printf("DIRECTOR\t%s\t%u\n", net_ip2addr(&ip), port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_cmd_host(struct director_connection *conn, const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int vhost_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool update;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 2 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[0], &ip) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[1], &vhost_count) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid HOST args", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = mail_host_lookup(&ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = mail_host_add_ip(&ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen update = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen update = host->vhost_count != vhost_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (update) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* FIXME: 1) shouldn't be unconditional, 2) if we're not
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen handshaking, we should do SYNC before making it visible */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host->vhost_count = vhost_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_update_host(conn->dir, conn->host, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_cmd_host_remove(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 1 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[0], &ip) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid HOST-REMOVE args", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = mail_host_lookup(&ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_remove_host(conn->dir, conn->host, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_handshake_cmd_done(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo 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
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* tell the right director about the left one */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->right != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strdup_printf("DIRECTOR\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&conn->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host->port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dir->left != NULL && dir->right != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* we're connected to both directors. see if the ring is
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen finished by sending a SYNC. if we get it back, it's done. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->sync_seq = ++dir->self_host->last_seq;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strdup_printf("SYNC\t%s\t%u\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&dir->self_ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->self_port, dir->sync_seq));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_handle_handshake(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd, const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* both incoming and outgoing connections get VERSION and ME */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "VERSION") == 0 && str_array_length(args) >= 3) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(args[0], DIRECTOR_VERSION_NAME) != 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Wrong protocol in socket "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "(%s vs %s)",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, args[0], DIRECTOR_VERSION_NAME);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (atoi(args[1]) != DIRECTOR_VERSION_MAJOR) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Incompatible protocol version: "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "%u vs %u", conn->name, atoi(args[1]),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_VERSION_MAJOR);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->version_received = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->version_received) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Incompatible protocol", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "ME") == 0 && !conn->me_received &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_array_length(args) == 2)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_me(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* only outgoing connections get a CONNECT reference */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->in && strcmp(cmd, "CONNECT") == 0 &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_array_length(args) == 2) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* remote wants us to connect elsewhere */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!director_args_parse_ip_port(conn, args, &ip, &port))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir->right = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_get(conn->dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)director_connect_host(conn->dir, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* only incoming connections get DIRECTOR and HOST lists */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->in && strcmp(cmd, "DIRECTOR") == 0 && conn->me_received)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_director(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->in && strcmp(cmd, "HOST") == 0 && conn->me_received)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_host(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* only incoming connections get a USER list */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->in && strcmp(cmd, "USER") == 0 && conn->me_received)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_handshake_cmd_user(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* both get DONE */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "DONE") == 0 && !conn->handshake_received) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_handshake_cmd_done(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen i_error("director(%s): Invalid handshake command: %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, cmd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_cmd_user(struct director_connection *conn, const char *const *args)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int username_hash;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 2 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[0], &username_hash) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[1], &ip) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid USER args", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = mail_host_lookup(&ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* we probably just removed this host. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (director_user_refresh(conn->dir, username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host, ioloop_time, &user))
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_update_user(conn->dir, conn->host, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool director_connection_sync(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args, const char *line)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int port, seq;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (str_array_length(args) != 3 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_args_parse_ip_port(conn, args, &ip, &port) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_to_uint(args[2], &seq) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Invalid SYNC args", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* find the originating director. if we don't see it, it was already
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen removed and we can ignore this sync. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen host = director_host_lookup(conn->dir, &ip, port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host->self) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->dir->sync_seq != seq) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* stale SYNC event */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->dir->ring_handshaked)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* the ring is handshaked */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir->ring_handshaked = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_set_state_changed(conn->dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* forward it to the connection on right */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->dir->right != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn->dir->right,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen t_strconcat(line, "\n", NULL));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_handle_line(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *line)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *cmd, *const *args;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen args = t_strsplit(line, "\t");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cmd = args[0]; args++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (cmd == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Received empty line", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen if (!conn->handshake_received) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen if (!director_connection_handle_handshake(conn, cmd, args)) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen /* invalid commands during handshake,
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen we probably don't want to reconnect here */
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen conn->host->last_failed = ioloop_time;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return FALSE;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen return TRUE;
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "USER") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_user(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "HOST") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_host(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "HOST-REMOVE") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_host_remove(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "DIRECTOR") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_cmd_director(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "SYNC") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_connection_sync(conn, args, line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "PING") == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, "PONG\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(cmd, "PONG") == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to_ping != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_remove(&conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Unknown command (in this state): %s",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name, cmd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_input(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen char *line;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to_ping != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_reset(conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen switch (i_stream_read(conn->input)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case 0:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -1:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* disconnected */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case -2:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* buffer full */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("BUG: Director sent us more than %d bytes",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MAX_INBUF_SIZE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = director_connection_handle_line(conn, line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } T_END;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!ret) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_send_directors(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen string_t *str)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&conn->dir->dir_hosts, hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, "DIRECTOR\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->port);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_send_hosts(string_t *str)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(mail_hosts_get(), hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, "HOST\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_connection_send_users(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_cork(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((user = user_directory_iter_next(conn->user_iter)) != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen T_BEGIN {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *line;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen line = t_strdup_printf("USER\t%u\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&user->host->ip),
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->timestamp);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } T_END;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (o_stream_get_buffer_used_size(conn->output) >= OUTBUF_FLUSH_THRESHOLD) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((ret = o_stream_flush(conn->output)) <= 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* continue later */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_directory_iter_deinit(&conn->user_iter);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, "DONE\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(conn->io == NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(conn->fd, IO_READ, director_connection_input, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = o_stream_flush(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_uncork(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int director_connection_output(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->user_iter != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return director_connection_send_users(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return o_stream_flush(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
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);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->fd = fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir = dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_set_flush_callback(conn->output,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_output, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_send_handshake(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, t_strdup_printf(
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "VERSION\t"DIRECTOR_VERSION_NAME"\t%u\t%u\n"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "ME\t%s\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DIRECTOR_VERSION_MAJOR, DIRECTOR_VERSION_MINOR,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&conn->dir->self_ip), conn->dir->self_port));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_init_in(struct director *dir, int fd)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn = director_connection_init_common(dir, fd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->in = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->connected = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name = "<incoming>";
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(conn->fd, IO_READ, director_connection_input, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_handshake(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_connected(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen string_t *str = t_str_new(1024);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int err;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((err = net_geterror(conn->fd)) != 0) {
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen conn->host->last_failed = ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): connect() failed: %s", conn->name,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen strerror(err));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&conn);
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen /* try connecting to next server */
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen director_connect(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->connected = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen io_remove(&conn->io);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_handshake(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_directors(conn, str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send_hosts(str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, str_c(str));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainen conn->user_iter = user_directory_iter_init(dir->users);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (void)director_connection_send_users(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct director_connection *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendirector_connection_init_out(struct director *dir, int fd,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn = director_connection_init_common(dir, fd);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->name = host->name;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->host = host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(conn->fd, IO_WRITE,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_connected, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_deinit(struct director_connection **_conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_connection *conn = *_conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_conn = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->dir->left == conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir->left = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->dir->right == conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir->right = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_remove(&conn->to);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to_ping != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen timeout_remove(&conn->to_ping);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->io != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen io_remove(&conn->io);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_stream_unref(&conn->input);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_unref(&conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (close(conn->fd) < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("close(director connection) failed: %m");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_send(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *data)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int len = strlen(data);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen off_t ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->output->closed || !conn->connected)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = o_stream_send(conn->output, data, len);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret != (off_t)len) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): write() failed: %m", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Output buffer full, "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "disconnecting", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_close(conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->to = timeout_add(0, director_connection_timeout, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid director_connection_send_except(struct director_connection *conn,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *skip_host,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *data)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->host != skip_host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, data);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_ping_timeout(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("director(%s): Ping timed out, disconnecting", conn->name);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void director_connection_ping(struct director_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->to_ping != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->to_ping = timeout_add(DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_ping_timeout, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_connection_send(conn, "PING\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}