From: Timo Sirainen Date: Thu, 17 Jun 2010 18:16:09 +0000 (+0100) Subject: director: Handle CONNECT commands (properly). X-Git-Tag: 2.0.rc1~147 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1055d8038122c4f4190d37d98fdff6791d1306f8;p=thirdparty%2Fdovecot%2Fcore.git director: Handle CONNECT commands (properly). --HG-- branch : HEAD --- diff --git a/src/director/director-connection.c b/src/director/director-connection.c index 9528cc2b96..6d07b77cb8 100644 --- a/src/director/director-connection.c +++ b/src/director/director-connection.c @@ -114,7 +114,7 @@ static bool director_cmd_me(struct director_connection *conn, director_connection_deinit(&dir->left); } else { if (director_host_cmp_to_self(dir->left->host, host, - dir->self_host) > 0) { + dir->self_host) < 0) { /* the old connection is the correct one. refer the client there. */ director_connection_send(conn, t_strdup_printf( @@ -505,6 +505,43 @@ static bool director_connection_sync(struct director_connection *conn, return TRUE; } +static bool director_cmd_connect(struct director_connection *conn, + const char *const *args) +{ + struct director *dir = conn->dir; + struct director_host *host; + struct ip_addr ip; + unsigned int port; + + if (str_array_length(args) != 2 || + director_args_parse_ip_port(conn, args, &ip, &port) < 0) { + i_error("director(%s): Invalid CONNECT args", conn->name); + return FALSE; + } + + host = director_host_lookup(dir, &ip, port); + if (host == NULL) { + i_error("Received CONNECT request to unknown host %s:%u", + net_ip2addr(&ip), port); + return TRUE; + } + + /* remote suggests us to connect elsewhere */ + if (dir->right != NULL && + director_host_cmp_to_self(host, dir->right->host, + dir->self_host) <= 0) { + /* the old connection is the correct one */ + return TRUE; + } + + /* connect here, disconnect old one */ + if (dir->right != NULL) + director_connection_deinit(&dir->right); + + (void)director_connect_host(dir, host); + return TRUE; +} + static bool director_connection_handle_line(struct director_connection *conn, const char *line) @@ -521,7 +558,8 @@ director_connection_handle_line(struct director_connection *conn, if (!director_connection_handle_handshake(conn, cmd, args)) { /* invalid commands during handshake, we probably don't want to reconnect here */ - conn->host->last_failed = ioloop_time; + if (conn->host != NULL) + conn->host->last_failed = ioloop_time; return FALSE; } return TRUE; @@ -539,6 +577,8 @@ director_connection_handle_line(struct director_connection *conn, return director_cmd_director(conn, args); if (strcmp(cmd, "SYNC") == 0) return director_connection_sync(conn, args, line); + if (strcmp(cmd, "CONNECT") == 0) + return director_cmd_connect(conn, args); if (strcmp(cmd, "PING") == 0) { director_connection_send(conn, "PONG\n"); diff --git a/src/director/director-host.c b/src/director/director-host.c index 2c3ca9d87e..451570f58c 100644 --- a/src/director/director-host.c +++ b/src/director/director-host.c @@ -89,10 +89,21 @@ int director_host_cmp_to_self(const struct director_host *b1, const struct director_host *b2, const struct director_host *self) { - if (director_host_cmp(b1, self) < 0) - return director_host_cmp(b1, b2); - else - return director_host_cmp(b2, b1); + int ret; + + if ((ret = director_host_cmp(b1, b2)) >= 0) + return ret == 0 ? 0 : -director_host_cmp_to_self(b2, b1, self); + + /* order -> return: + self, b1, b2 -> b2 + b1, self, b2 -> b1 + b1, b2, self -> b2 + */ + if (director_host_cmp(self, b1) < 0) + return 1; /* self, b1, b2 */ + if (director_host_cmp(self, b2) < 0) + return -1; /* b1, self, b2 */ + return 1; /* b1, b2, self */ } static void director_host_add_string(struct director *dir, const char *host) diff --git a/src/director/director-host.h b/src/director/director-host.h index fb9015ccfa..2b8f84b292 100644 --- a/src/director/director-host.h +++ b/src/director/director-host.h @@ -38,8 +38,10 @@ director_host_lookup(struct director *dir, const struct ip_addr *ip, struct director_host * director_host_lookup_ip(struct director *dir, const struct ip_addr *ip); -/* Returns -1 if b1 is more on our left side than b2, 1 if b2 is, - 0 if they equal. */ +/* Returns 0 if b1 equals b2. + -1 if b1 is closer to our left side than b2 or + -1 if b2 is closer to our right side than b1 + 1 vice versa */ int director_host_cmp_to_self(const struct director_host *b1, const struct director_host *b2, const struct director_host *self);