]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
director: Handle CONNECT commands (properly).
authorTimo Sirainen <tss@iki.fi>
Thu, 17 Jun 2010 18:16:09 +0000 (19:16 +0100)
committerTimo Sirainen <tss@iki.fi>
Thu, 17 Jun 2010 18:16:09 +0000 (19:16 +0100)
--HG--
branch : HEAD

src/director/director-connection.c
src/director/director-host.c
src/director/director-host.h

index 9528cc2b96fe59277f033d7eb149749f622ed703..6d07b77cb8ab73724efcfad560466fa37e7bbba4 100644 (file)
@@ -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");
index 2c3ca9d87ed2797be074642dda14a3fcb79d71d6..451570f58c741b6635dd17b2ebe0b71994e5abbc 100644 (file)
@@ -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)
index fb9015ccfae41893a25b75321f65845885cdd426..2b8f84b2927e238f7c995ca4166a15bbe951983f 100644 (file)
@@ -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);