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(
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)
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;
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");
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)
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);