dovecot-2.1: director: Avoid infinite SYNC loops if the originat...
dovecot at dovecot.org
dovecot at dovecot.org
Mon Jul 29 23:21:50 EEST 2013
details: http://hg.dovecot.org/dovecot-2.1/rev/c9d7586d01ae
changeset: 14988:c9d7586d01ae
user: Timo Sirainen <tss at iki.fi>
date: Mon Jul 29 23:21:38 2013 +0300
description:
director: Avoid infinite SYNC loops if the originating director goes away for a long time.
diffstat:
src/director/director-connection.c | 51 +++++++++++++++++++++++++++++--------
src/director/director-host.h | 3 ++
src/director/director.c | 12 +++++---
src/director/director.h | 3 +-
4 files changed, 51 insertions(+), 18 deletions(-)
diffs (184 lines):
diff -r 77213cdc8d7f -r c9d7586d01ae src/director/director-connection.c
--- a/src/director/director-connection.c Mon Jul 29 22:48:36 2013 +0300
+++ b/src/director/director-connection.c Mon Jul 29 23:21:38 2013 +0300
@@ -73,6 +73,7 @@
#define DIRECTOR_WAIT_DISCONNECT_SECS 10
#define DIRECTOR_HANDSHAKE_WARN_SECS 29
#define DIRECTOR_HANDSHAKE_BYTES_LOG_MIN_SECS (60*30)
+#define DIRECTOR_MAX_SYNC_SEQ_DUPLICATES 4
#if DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS <= DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS
# error DIRECTOR_CONNECTION_DONE_TIMEOUT_MSECS is too low
@@ -217,7 +218,7 @@
dir->sync_seq++;
director_set_ring_unsynced(dir);
director_sync_send(dir, dir->self_host, dir->sync_seq,
- DIRECTOR_VERSION_MINOR);
+ DIRECTOR_VERSION_MINOR, ioloop_time);
}
director_connection_set_ping_timeout(conn);
}
@@ -1084,10 +1085,11 @@
return 0;
}
-static void
+static bool
director_connection_sync_host(struct director_connection *conn,
struct director_host *host,
- uint32_t seq, unsigned int minor_version)
+ uint32_t seq, unsigned int minor_version,
+ unsigned int timestamp)
{
struct director *dir = conn->dir;
@@ -1099,7 +1101,7 @@
if (host->self) {
if (dir->sync_seq != seq) {
/* stale SYNC event */
- return;
+ return FALSE;
}
/* sync_seq increases when we get disconnected, so we must be
successfully connected to both directions */
@@ -1117,10 +1119,28 @@
conn->name, seq);
director_set_ring_synced(dir);
}
- } else if (dir->right != NULL) {
- /* forward it to the connection on right */
- director_sync_send(dir, host, seq, minor_version);
+ } else {
+ if (seq < host->last_sync_seq) {
+ /* stale SYNC event */
+ return FALSE;
+ } else if (host->last_sync_seq != seq ||
+ timestamp < host->last_sync_timestamp) {
+ host->last_sync_seq = seq;
+ host->last_sync_timestamp = timestamp;
+ host->last_sync_seq_counter = 1;
+ } else if (++host->last_sync_seq_counter >
+ DIRECTOR_MAX_SYNC_SEQ_DUPLICATES) {
+ /* we've received this too many times already */
+ return FALSE;
+ }
+
+ if (dir->right != NULL) {
+ /* forward it to the connection on right */
+ director_sync_send(dir, host, seq, minor_version,
+ timestamp);
+ }
}
+ return TRUE;
}
static bool director_connection_sync(struct director_connection *conn,
@@ -1129,7 +1149,7 @@
struct director *dir = conn->dir;
struct director_host *host;
struct ip_addr ip;
- unsigned int port, seq, minor_version = 0;
+ unsigned int port, seq, minor_version = 0, timestamp = ioloop_time;
if (str_array_length(args) < 3 ||
!director_args_parse_ip_port(conn, args, &ip, &port) ||
@@ -1137,18 +1157,25 @@
director_cmd_error(conn, "Invalid parameters");
return FALSE;
}
- if (args[3] != NULL)
+ if (args[3] != NULL) {
minor_version = atoi(args[3]);
+ if (args[4] != NULL && str_to_uint(args[4], ×tamp) < 0) {
+ director_cmd_error(conn, "Invalid parameters");
+ return FALSE;
+ }
+ }
/* find the originating director. if we don't see it, it was already
removed and we can ignore this sync. */
host = director_host_lookup(dir, &ip, port);
if (host != NULL) {
- director_connection_sync_host(conn, host, seq,
- minor_version);
+ if (!director_connection_sync_host(conn, host, seq,
+ minor_version, timestamp))
+ return TRUE;
}
- if (host == NULL || !host->self)
+ if ((host == NULL || !host->self) &&
+ dir->self_host->last_sync_timestamp != ioloop_time)
director_resend_sync(dir);
return TRUE;
}
diff -r 77213cdc8d7f -r c9d7586d01ae src/director/director-host.h
--- a/src/director/director-host.h Mon Jul 29 22:48:36 2013 +0300
+++ b/src/director/director-host.h Mon Jul 29 23:21:38 2013 +0300
@@ -20,6 +20,9 @@
it can be ignored (or: it must be ignored to avoid potential command
loops) */
unsigned int last_seq;
+ /* use these to avoid infinitely sending SYNCs for directors that
+ aren't connected in the ring. */
+ unsigned int last_sync_seq, last_sync_seq_counter, last_sync_timestamp;
/* Last time host was detected to be down */
time_t last_network_failure;
time_t last_protocol_failure;
diff -r 77213cdc8d7f -r c9d7586d01ae src/director/director.c
--- a/src/director/director.c Mon Jul 29 22:48:36 2013 +0300
+++ b/src/director/director.c Mon Jul 29 23:21:38 2013 +0300
@@ -302,7 +302,8 @@
}
void director_sync_send(struct director *dir, struct director_host *host,
- uint32_t seq, unsigned int minor_version)
+ uint32_t seq, unsigned int minor_version,
+ unsigned int timestamp)
{
string_t *str;
@@ -311,8 +312,8 @@
net_ip2addr(&host->ip), host->port, seq);
if (minor_version > 0 &&
director_connection_get_minor_version(dir->right) > 0) {
- /* only minor_version>0 supports this parameter */
- str_printfa(str, "\t%u", minor_version);
+ /* only minor_version>0 supports extra parameters */
+ str_printfa(str, "\t%u\t%u", minor_version, timestamp);
}
str_append_c(str, '\n');
director_connection_send(dir->right, str_c(str));
@@ -329,8 +330,9 @@
{
if (!dir->ring_synced && dir->left != NULL && dir->right != NULL) {
/* send a new SYNC in case the previous one got dropped */
+ dir->self_host->last_sync_timestamp = ioloop_time;
director_sync_send(dir, dir->self_host, dir->sync_seq,
- DIRECTOR_VERSION_MINOR);
+ DIRECTOR_VERSION_MINOR, ioloop_time);
if (dir->to_sync != NULL)
timeout_reset(dir->to_sync);
return TRUE;
@@ -393,7 +395,7 @@
director_connection_set_synced(dir->left, FALSE);
director_connection_set_synced(dir->right, FALSE);
director_sync_send(dir, dir->self_host, dir->sync_seq,
- DIRECTOR_VERSION_MINOR);
+ DIRECTOR_VERSION_MINOR, ioloop_time);
}
void director_sync_freeze(struct director *dir)
diff -r 77213cdc8d7f -r c9d7586d01ae src/director/director.h
--- a/src/director/director.h Mon Jul 29 22:48:36 2013 +0300
+++ b/src/director/director.h Mon Jul 29 23:21:38 2013 +0300
@@ -103,7 +103,8 @@
void director_set_ring_unsynced(struct director *dir);
void director_set_state_changed(struct director *dir);
void director_sync_send(struct director *dir, struct director_host *host,
- uint32_t seq, unsigned int minor_version);
+ uint32_t seq, unsigned int minor_version,
+ unsigned int timestamp);
bool director_resend_sync(struct director *dir);
void director_notify_ring_added(struct director_host *added_host,
More information about the dovecot-cvs
mailing list