dovecot-2.0: director: Lots of fixes. It should be pretty stable...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Jun 24 22:29:34 EEST 2010
details: http://hg.dovecot.org/dovecot-2.0/rev/a07aa85f68c9
changeset: 11629:a07aa85f68c9
user: Timo Sirainen <tss at iki.fi>
date: Thu Jun 24 20:29:27 2010 +0100
description:
director: Lots of fixes. It should be pretty stable now.
diffstat:
src/director/auth-connection.c | 18 +-
src/director/auth-connection.h | 2 +-
src/director/director-connection.c | 375 +++++++++++++++++++++++++++++++----------
src/director/director-connection.h | 12 +-
src/director/director-host.h | 11 +-
src/director/director-request.c | 32 ++-
src/director/director-test.c | 42 ++++-
src/director/director-test.sh | 11 +-
src/director/director.c | 166 +++++++++++++++++-
src/director/director.h | 23 +-
src/director/doveadm-connection.c | 14 +-
src/director/main.c | 4 +-
12 files changed, 563 insertions(+), 147 deletions(-)
diffs (truncated from 1420 to 300 lines):
diff -r 7885030184ab -r a07aa85f68c9 src/director/auth-connection.c
--- a/src/director/auth-connection.c Thu Jun 24 16:27:20 2010 +0100
+++ b/src/director/auth-connection.c Thu Jun 24 20:29:27 2010 +0100
@@ -27,6 +27,8 @@
static struct auth_connection *auth_connections;
+static void auth_connection_disconnected(struct auth_connection **conn);
+
static void auth_connection_input(struct auth_connection *conn)
{
char *line;
@@ -36,13 +38,13 @@
return;
case -1:
/* disconnected */
- auth_connection_deinit(&conn);
+ auth_connection_disconnected(&conn);
return;
case -2:
/* buffer full */
i_error("BUG: Auth server sent us more than %d bytes",
(int)AUTH_CLIENT_MAX_LINE_LENGTH);
- auth_connection_deinit(&conn);
+ auth_connection_disconnected(&conn);
return;
}
@@ -103,12 +105,20 @@
if (close(conn->fd) < 0)
i_error("close(auth connection) failed: %m");
- conn->callback(NULL, conn->context);
}
i_free(conn->path);
i_free(conn);
}
+static void auth_connection_disconnected(struct auth_connection **_conn)
+{
+ struct auth_connection *conn = *_conn;
+
+ *_conn = NULL;
+ /* notify callback. it should deinit this connection */
+ conn->callback(NULL, conn->context);
+}
+
void auth_connection_send(struct auth_connection *conn,
const void *data, size_t size)
{
@@ -122,6 +132,6 @@
while (auth_connections != NULL) {
struct auth_connection *conn = auth_connections;
- auth_connection_deinit(&conn);
+ auth_connection_disconnected(&conn);
}
}
diff -r 7885030184ab -r a07aa85f68c9 src/director/auth-connection.h
--- a/src/director/auth-connection.h Thu Jun 24 16:27:20 2010 +0100
+++ b/src/director/auth-connection.h Thu Jun 24 20:29:27 2010 +0100
@@ -2,7 +2,7 @@
#define AUTH_CONNECTION_H
/* Called for each input line. This is also called with line=NULL if
- connection gets disonnected. */
+ connection gets disconnected. */
typedef void auth_input_callback(const char *line, void *context);
struct auth_connection *auth_connection_init(const char *path);
diff -r 7885030184ab -r a07aa85f68c9 src/director/director-connection.c
--- a/src/director/director-connection.c Thu Jun 24 16:27:20 2010 +0100
+++ b/src/director/director-connection.c Thu Jun 24 20:29:27 2010 +0100
@@ -7,6 +7,7 @@
#include "istream.h"
#include "ostream.h"
#include "str.h"
+#include "llist.h"
#include "master-service.h"
#include "mail-host.h"
#include "director.h"
@@ -25,14 +26,20 @@
#define MAX_INBUF_SIZE 1024
#define MAX_OUTBUF_SIZE (1024*1024*10)
#define OUTBUF_FLUSH_THRESHOLD (1024*128)
+/* Max idling time while connecting/handshaking before disconnecting */
+#define DIRECTOR_CONNECTION_INIT_TIMEOUT_MSECS (2*1000)
/* How long to wait for PONG after PING request */
#define DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS (2*1000)
/* How long to wait to send PING when connection is idle */
#define DIRECTOR_CONNECTION_PING_INTERVAL_MSECS (15*1000)
+/* How long to wait before sending PING while waiting for SYNC reply */
+#define DIRECTOR_CONNECTION_SYNC_TIMEOUT_MSECS 1000
struct director_connection {
+ struct director_connection *prev, *next;
+
struct director *dir;
- const char *name;
+ char *name;
/* for incoming connections the director host isn't known until
ME-line is received */
@@ -54,9 +61,11 @@
unsigned int ignore_host_events:1;
unsigned int handshake_sending_hosts:1;
unsigned int ping_waiting:1;
+ unsigned int sync_ping:1;
};
static void director_connection_ping(struct director_connection *conn);
+static void director_connection_disconnected(struct director_connection **conn);
static bool
director_args_parse_ip_port(struct director_connection *conn,
@@ -102,7 +111,12 @@
if (!conn->in)
return TRUE;
+ i_free(conn->name);
+ conn->name = i_strdup_printf("%s/left", host->name);
conn->host = host;
+ /* make sure we don't keep old sequence values across restarts */
+ host->last_seq = 0;
+
connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
net_ip2addr(&host->ip), host->port);
/* make sure this is the correct incoming connection */
@@ -135,6 +149,8 @@
one, but before that tell it to connect to the new one.
that message might not reach it, so also send the same
message to right side. */
+ i_warning("Replacing director connection %s with %s",
+ dir->left->host->name, host->name);
director_connection_send(dir->left, connect_str);
(void)o_stream_flush(dir->left->output);
director_connection_deinit(&dir->left);
@@ -227,6 +243,33 @@
return TRUE;
}
+static bool
+director_cmd_user(struct director_connection *conn, const char *const *args)
+{
+ unsigned int username_hash;
+ struct ip_addr ip;
+ struct mail_host *host;
+ struct user *user;
+
+ if (str_array_length(args) != 2 ||
+ str_to_uint(args[0], &username_hash) < 0 ||
+ net_addr2ip(args[1], &ip) < 0) {
+ i_error("director(%s): Invalid USER args", conn->name);
+ return FALSE;
+ }
+
+ host = mail_host_lookup(conn->dir->mail_hosts, &ip);
+ if (host == NULL) {
+ /* we probably just removed this host. */
+ return TRUE;
+ }
+
+ if (director_user_refresh(conn->dir, username_hash,
+ host, ioloop_time, &user))
+ director_update_user(conn->dir, conn->host, user);
+ return TRUE;
+}
+
static bool director_cmd_director(struct director_connection *conn,
const char *const *args)
{
@@ -269,7 +312,7 @@
hosts = mail_hosts_get(conn->dir->mail_hosts);
while (array_count(hosts) > 0) {
hostp = array_idx(hosts, 0);
- director_remove_host(conn->dir, conn->host, *hostp);
+ director_remove_host(conn->dir, NULL, NULL, *hostp);
}
} else if (!remote_ring_completed && conn->dir->ring_handshaked) {
/* ignore whatever remote sends */
@@ -279,8 +322,46 @@
return TRUE;
}
+static int
+director_cmd_is_seen(struct director_connection *conn,
+ const char *const **_args,
+ struct director_host **host_r)
+{
+ const char *const *args = *_args;
+ struct ip_addr ip;
+ unsigned int port, seq;
+ struct director_host *host;
+
+ if (str_array_length(args) < 3 ||
+ net_addr2ip(args[0], &ip) < 0 ||
+ str_to_uint(args[1], &port) < 0 ||
+ str_to_uint(args[2], &seq) < 0) {
+ i_error("director(%s): Command is missing parameters",
+ conn->name);
+ return -1;
+ }
+ *_args = args + 3;
+
+ host = director_host_lookup(conn->dir, &ip, port);
+ if (host == NULL) {
+ /* director is already gone, but we can't be sure if this
+ command was sent everywhere. re-send it as if it was from
+ ourself. */
+ *host_r = NULL;
+ } else {
+ if (seq <= host->last_seq) {
+ /* already seen this */
+ return 1;
+ }
+ *host_r = host;
+ host->last_seq = seq;
+ }
+ return 0;
+}
+
static bool
-director_cmd_host(struct director_connection *conn, const char *const *args)
+director_cmd_host_int(struct director_connection *conn, const char *const *args,
+ struct director_host *dir_host)
{
struct mail_host *host;
struct ip_addr ip;
@@ -311,17 +392,40 @@
if (update) {
mail_host_set_vhost_count(conn->dir->mail_hosts,
host, vhost_count);
- director_update_host(conn->dir, conn->host, host);
+ director_update_host(conn->dir, conn->host, dir_host, host);
}
return TRUE;
}
static bool
+director_cmd_host_handshake(struct director_connection *conn,
+ const char *const *args)
+{
+ return director_cmd_host_int(conn, args, NULL);
+}
+
+static bool
+director_cmd_host(struct director_connection *conn, const char *const *args)
+{
+ struct director_host *dir_host;
+ int ret;
+
+ if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+ return ret > 0;
+ return director_cmd_host_int(conn, args, dir_host);
+}
+
+static bool
director_cmd_host_remove(struct director_connection *conn,
const char *const *args)
{
+ struct director_host *dir_host;
struct mail_host *host;
struct ip_addr ip;
+ int ret;
+
+ if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+ return ret > 0;
if (str_array_length(args) != 1 ||
net_addr2ip(args[0], &ip) < 0) {
@@ -331,7 +435,7 @@
host = mail_host_lookup(conn->dir->mail_hosts, &ip);
if (host != NULL)
- director_remove_host(conn->dir, conn->host, host);
+ director_remove_host(conn->dir, conn->host, dir_host, host);
return TRUE;
}
@@ -339,18 +443,25 @@
director_cmd_host_flush(struct director_connection *conn,
const char *const *args)
{
+ struct director_host *dir_host;
struct mail_host *host;
struct ip_addr ip;
+ unsigned int seq;
+ int ret;
- if (str_array_length(args) != 1 ||
- net_addr2ip(args[0], &ip) < 0) {
+ if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+ return ret > 0;
+
+ if (str_array_length(args) != 2 ||
+ net_addr2ip(args[0], &ip) < 0 ||
+ str_to_uint(args[1], &seq) < 0) {
i_error("director(%s): Invalid HOST-FLUSH args", conn->name);
return FALSE;
}
More information about the dovecot-cvs
mailing list