dovecot-2.0: director-test improvements.

dovecot at dovecot.org dovecot at dovecot.org
Fri Jun 18 18:28:55 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/6aa749b789ef
changeset: 11580:6aa749b789ef
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Jun 18 16:28:49 2010 +0100
description:
director-test improvements.

diffstat:

 src/director/director-test.c |  235 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 173 insertions(+), 62 deletions(-)

diffs (truncated from 413 to 300 lines):

diff -r 61708c33154d -r 6aa749b789ef src/director/director-test.c
--- a/src/director/director-test.c	Fri Jun 18 16:28:36 2010 +0100
+++ b/src/director/director-test.c	Fri Jun 18 16:28:49 2010 +0100
@@ -5,11 +5,11 @@
    port 14300. If the same user is connecting to multiple different local IPs,
    it logs an error (i.e. director is not working right then).
 
-   This program also accepts incoming director connections on port 9090 and
-   forwards them to local_ip:9091. So all directors think the others are
-   listening on port 9091, while in reality all of them are on 9090.
-   The idea is that this test tool hooks between all director connections and
-   can then add delays or break the connections.
+   This program also accepts incoming director connections on port 9091 and
+   forwards them to local_ip:9090. To make this work properly, director
+   executable must be given -t 9091 parameter. The idea is that this test tool
+   hooks between all director connections and can then add delays or break the
+   connections.
 
    Finally, this program connects to director-admin socket where it adds
    and removes mail hosts.
@@ -27,14 +27,26 @@
 #include "master-service-settings.h"
 #include "director-settings.h"
 
+#include <stdlib.h>
+#include <unistd.h>
+
 #define IMAP_PORT 14300
 #define DIRECTOR_IN_PORT 9091
 #define DIRECTOR_OUT_PORT 9090
 #define USER_TIMEOUT_MSECS (1000*60)
+#define ADMIN_RANDOM_TIMEOUT_MSECS 500
+#define DIRECTOR_CONN_MAX_DELAY_MSECS 1000
+
+struct host {
+	int refcount;
+
+	struct ip_addr ip;
+	unsigned int vhost_count;
+};
 
 struct user {
 	char *username;
-	struct ip_addr local_ip;
+	struct host *host;
 
 	time_t last_seen;
 	unsigned int connections;
@@ -62,47 +74,80 @@
 	struct io *in_io, *out_io;
 	struct istream *in_input, *out_input;
 	struct ostream *in_output, *out_output;
+	struct timeout *to_delay;
 };
 
 struct admin_connection {
 	char *path;
 	int fd;
+	struct io *io;
 	struct istream *input;
+	struct timeout *to_random;
 };
 
 static struct imap_client *imap_clients;
 static struct director_connection *director_connections;
 static struct hash_table *users;
+static struct hash_table *hosts;
+static ARRAY_DEFINE(hosts_array, struct host *);
 static struct admin_connection *admin;
 
 static void imap_client_destroy(struct imap_client **client);
-static void director_connection_destroy(struct director_connection **_conn);
+static void director_connection_destroy(struct director_connection **conn);
+static void director_connection_timeout(struct director_connection *conn);
+
+static void host_unref(struct host **_host)
+{
+	struct host *host = *_host;
+
+	*_host = NULL;
+
+	i_assert(host->refcount > 0);
+	if (--host->refcount > 0)
+		return;
+
+	i_free(host);
+}
 
 static void client_username_check(struct imap_client *client)
 {
 	struct user *user;
+	struct host *host;
 	struct ip_addr local_ip;
 
 	if (net_getsockname(client->fd, &local_ip, NULL) < 0)
 		i_fatal("net_getsockname() failed: %m");
 
+	host = hash_table_lookup(hosts, &local_ip);
+	if (host == NULL) {
+		i_error("User logging into unknown host %s",
+			net_ip2addr(&local_ip));
+		host = i_new(struct host, 1);
+		host->refcount++;
+		host->ip = local_ip;
+		host->vhost_count = 100;
+		hash_table_insert(hosts, &host->ip, host);
+		array_append(&hosts_array, &host, 1);
+	}
+
 	user = hash_table_lookup(users, client->username);
 	if (user == NULL) {
 		user = i_new(struct user, 1);
 		user->username = i_strdup(client->username);
-		user->local_ip = local_ip;
+		user->host = host;
 		hash_table_insert(users, user->username, user);
-	} else if (!net_ip_compare(&user->local_ip, &local_ip)) {
+	} else if (user->host != host) {
 		i_error("user %s: old connection from %s, new from %s. "
 			"%u old connections, last was %u secs ago",
-			user->username, net_ip2addr(&user->local_ip),
-			net_ip2addr(&local_ip), user->connections,
+			user->username, net_ip2addr(&user->host->ip),
+			net_ip2addr(&host->ip), user->connections,
 			(unsigned int)(ioloop_time - user->last_seen));
 		return;
 	}
 	client->user = user;
 	user->connections++;
 	user->last_seen = ioloop_time;
+	user->host->refcount++;
 
 	if (user->to != NULL)
 		timeout_remove(&user->to);
@@ -110,6 +155,7 @@
 
 static void user_free(struct user *user)
 {
+	host_unref(&user->host);
 	if (user->to != NULL)
 		timeout_remove(&user->to);
 	hash_table_remove(users, user->username);
@@ -237,53 +283,28 @@
 	master_service_client_connection_destroyed(master_service);
 }
 
-static const char *director_line_update_port(const char *line)
-{
-	const char *p, *prefix, *suffix;
-	unsigned int i = 0;
-
-	/* <cmd> \t IP \t <port> [\t more] */
-	for (p = line;; p++) {
-		if (*p == '\0') {
-			i_error("director: Invalid input: %s", line);
-			return line;
-		}
-		if (*p == '\t') {
-			if (++i == 2)
-				break;
-		}
-	}
-	prefix = t_strdup_until(line, ++p);
-	suffix = strchr(p, '\t');
-	return t_strdup_printf("%s%u%s", prefix, DIRECTOR_OUT_PORT,
-			       suffix != NULL ? suffix : "");
-}
-
 static void
 director_connection_input(struct director_connection *conn,
 			  struct istream *input, struct ostream *output)
 {
-	const char *line;
+	const unsigned char *data;
+	size_t size;
 
-	o_stream_cork(output);
-	while ((line = i_stream_read_next_line(input)) != NULL) {
-#if 0
-		if (strncmp(line, "ME\t", 3) == 0 ||
-		    strncmp(line, "DIRECTOR\t", 9) == 0 ||
-		    strncmp(line, "SYNC\t", 5) == 0) {
-			const char *orig = line;
-
-			line = director_line_update_port(line);
-		}
-#endif
-		o_stream_send_str(output, line);
-		o_stream_send(output, "\n", 1);
-	}
-	o_stream_uncork(output);
-	if (input->stream_errno != 0 || input->eof) {
+	if (i_stream_read_data(input, &data, &size, 0) == -1) {
 		director_connection_destroy(&conn);
 		return;
 	}
+
+	o_stream_send(output, data, size);
+	i_stream_skip(input, size);
+
+	if (rand() % 3 == 0 && conn->to_delay == NULL) {
+		conn->to_delay =
+			timeout_add(rand() % DIRECTOR_CONN_MAX_DELAY_MSECS,
+				    director_connection_timeout, conn);
+		io_remove(&conn->in_io);
+		io_remove(&conn->out_io);
+	}
 }
 
 static void director_connection_in_input(struct director_connection *conn)
@@ -296,6 +317,18 @@
 	director_connection_input(conn, conn->out_input, conn->in_output);
 }
 
+static void director_connection_timeout(struct director_connection *conn)
+{
+	timeout_remove(&conn->to_delay);
+	conn->in_io = io_add(conn->in_fd, IO_READ,
+			     director_connection_in_input, conn);
+	conn->out_io = io_add(conn->out_fd, IO_READ,
+			      director_connection_out_input, conn);
+
+	director_connection_in_input(conn);
+	director_connection_out_input(conn);
+}
+
 static void
 director_connection_create(int in_fd, const struct ip_addr *local_ip)
 {
@@ -323,12 +356,17 @@
 
 	DLLIST_REMOVE(&director_connections, conn);
 
-	io_remove(&conn->in_io);
+	if (conn->to_delay != NULL)
+		timeout_remove(&conn->to_delay);
+
+	if (conn->in_io != NULL)
+		io_remove(&conn->in_io);
 	i_stream_unref(&conn->in_input);
 	o_stream_unref(&conn->in_output);
 	net_disconnect(conn->in_fd);
 
-	io_remove(&conn->out_io);
+	if (conn->out_io != NULL)
+		io_remove(&conn->out_io);
 	i_stream_unref(&conn->out_input);
 	o_stream_unref(&conn->out_output);
 	net_disconnect(conn->out_fd);
@@ -362,6 +400,32 @@
 		i_fatal("write(%s) failed: %m", conn->path);
 }
 
+static void admin_input(struct admin_connection *conn)
+{
+	const char *line;
+
+	while ((line = i_stream_read_next_line(conn->input)) != NULL) {
+		if (strcmp(line, "OK") != 0)
+			i_error("director-doveadm: Unexpected input: %s", line);
+	}
+	if (conn->input->stream_errno != 0 || conn->input->eof)
+		i_fatal("director-doveadm: Connection lost");
+}
+
+static void admin_random_action(struct admin_connection *conn)
+{
+	struct host *const *hosts;
+	unsigned int i, count;
+
+	hosts = array_get(&hosts_array, &count);
+	i = rand() % count;
+
+	hosts[i]->vhost_count = (rand() % 20) * 10;
+
+	admin_send(conn, t_strdup_printf("HOST-SET\t%s\t%u\n",
+		net_ip2addr(&hosts[i]->ip), hosts[i]->vhost_count));
+}
+
 static struct admin_connection *admin_connect(const char *path)
 {
 #define DIRECTOR_ADMIN_HANDSHAKE "VERSION\tdirector-doveadm\t1\t0\n"
@@ -373,8 +437,11 @@
 	conn->fd = net_connect_unix(path);
 	if (conn->fd == -1)
 		i_fatal("net_connect_unix(%s) failed: %m", path);
+	conn->io = io_add(conn->fd, IO_READ, admin_input, conn);
+	conn->to_random = timeout_add(ADMIN_RANDOM_TIMEOUT_MSECS,
+				      admin_random_action, conn);
+
 	net_set_nonblock(conn->fd, FALSE);
-
 	conn->input = i_stream_create_fd(conn->fd, (size_t)-1, TRUE);
 	admin_send(conn, DIRECTOR_ADMIN_HANDSHAKE);
 
@@ -385,6 +452,7 @@
 		i_fatal("%s not a compatible director-doveadm socket",
 			conn->path);
 	}
+	net_set_nonblock(conn->fd, TRUE);


More information about the dovecot-cvs mailing list