dovecot-2.0: director: Added initial testing framework and some ...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jun 17 21:18:40 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/659bb1a26da4
changeset: 11572:659bb1a26da4
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jun 17 19:18:34 2010 +0100
description:
director: Added initial testing framework and some debugging output.

diffstat:

 .hgignore                          |    1 +
 src/director/Makefile.am           |    9 +
 src/director/director-connection.c |   14 +
 src/director/director-test.c       |  457 +++++++++++++++++++++++++++++++++++++++++
 src/director/director.c            |   10 +-
 src/director/director.h            |    3 +
 src/director/main.c                |   37 ++-
 7 files changed, 524 insertions(+), 7 deletions(-)

diffs (truncated from 651 to 300 lines):

diff -r 75d5e31ea8cc -r 659bb1a26da4 .hgignore
--- a/.hgignore	Thu Jun 17 19:16:09 2010 +0100
+++ b/.hgignore	Thu Jun 17 19:18:34 2010 +0100
@@ -62,6 +62,7 @@
 src/lda/dovecot-lda
 src/dict/dict
 src/director/director
+src/director/director-test
 src/dns/dns-client
 src/doveadm/doveadm
 src/dsync/dsync
diff -r 75d5e31ea8cc -r 659bb1a26da4 src/director/Makefile.am
--- a/src/director/Makefile.am	Thu Jun 17 19:16:09 2010 +0100
+++ b/src/director/Makefile.am	Thu Jun 17 19:18:34 2010 +0100
@@ -5,6 +5,7 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-auth \
+	-I$(top_srcdir)/src/lib-imap \
 	-I$(top_srcdir)/src/lib-settings \
 	-I$(top_srcdir)/src/lib-master \
 	-DPKG_RUNDIR=\""$(rundir)"\"
@@ -38,3 +39,11 @@
 	mail-host.h \
 	notify-connection.h \
 	user-directory.h
+
+noinst_PROGRAMS = director-test
+
+director_test_LDADD = $(LIBDOVECOT)
+director_test_DEPENDENCIES = $(LIBDOVECOT_DEPS)
+
+director_test_SOURCES = \
+	director-test.c
diff -r 75d5e31ea8cc -r 659bb1a26da4 src/director/director-connection.c
--- a/src/director/director-connection.c	Thu Jun 17 19:16:09 2010 +0100
+++ b/src/director/director-connection.c	Thu Jun 17 19:18:34 2010 +0100
@@ -527,10 +527,19 @@
 	}
 
 	/* remote suggests us to connect elsewhere */
+	if (dir->debug) {
+		i_debug("Received CONNECT request to %s, "
+			"current right is %s", host->name,
+			dir->right == NULL ? "<none>" :
+			dir->right->name);
+	}
+
 	if (dir->right != NULL &&
 	    director_host_cmp_to_self(host, dir->right->host,
 				      dir->self_host) <= 0) {
 		/* the old connection is the correct one */
+		if (dir->debug)
+			i_debug("Ignoring CONNECT");
 		return TRUE;
 	}
 
@@ -783,6 +792,11 @@
 
 	*_conn = NULL;
 
+	if (conn->dir->debug && conn->host != NULL) {
+		i_debug("Director %s:%u disconnected",
+			net_ip2addr(&conn->host->ip), conn->host->port);
+	}
+
 	if (conn->dir->left == conn)
 		conn->dir->left = NULL;
 	if (conn->dir->right == conn)
diff -r 75d5e31ea8cc -r 659bb1a26da4 src/director/director-test.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/director/director-test.c	Thu Jun 17 19:18:34 2010 +0100
@@ -0,0 +1,457 @@
+/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
+
+/*
+   This program accepts incoming unauthenticated IMAP connections from
+   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.
+
+   Finally, this program connects to director-admin socket where it adds
+   and removes mail hosts.
+*/
+
+#include "lib.h"
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "write-full.h"
+#include "hash.h"
+#include "llist.h"
+#include "imap-parser.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "director-settings.h"
+
+#define IMAP_PORT 14300
+#define DIRECTOR_IN_PORT 9091
+#define DIRECTOR_OUT_PORT 9090
+#define USER_TIMEOUT_MSECS (1000*60)
+
+struct user {
+	char *username;
+	struct ip_addr local_ip;
+
+	time_t last_seen;
+	unsigned int connections;
+
+	struct timeout *to;
+};
+
+struct imap_client {
+	struct imap_client *prev, *next;
+
+	int fd;
+	struct io *io;
+	struct istream *input;
+	struct ostream *output;
+	struct imap_parser *parser;
+	struct user *user;
+
+	char *username;
+};
+
+struct director_connection {
+	struct director_connection *prev, *next;
+
+	int in_fd, out_fd;
+	struct io *in_io, *out_io;
+	struct istream *in_input, *out_input;
+	struct ostream *in_output, *out_output;
+};
+
+struct admin_connection {
+	char *path;
+	int fd;
+	struct istream *input;
+};
+
+static struct imap_client *imap_clients;
+static struct director_connection *director_connections;
+static struct hash_table *users;
+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 client_username_check(struct imap_client *client)
+{
+	struct user *user;
+	struct ip_addr local_ip;
+
+	if (net_getsockname(client->fd, &local_ip, NULL) < 0)
+		i_fatal("net_getsockname() failed: %m");
+
+	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;
+		hash_table_insert(users, user->username, user);
+	} else if (!net_ip_compare(&user->local_ip, &local_ip)) {
+		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,
+			(unsigned int)(ioloop_time - user->last_seen));
+		return;
+	}
+	client->user = user;
+	user->connections++;
+	user->last_seen = ioloop_time;
+
+	if (user->to != NULL)
+		timeout_remove(&user->to);
+}
+
+static void user_free(struct user *user)
+{
+	if (user->to != NULL)
+		timeout_remove(&user->to);
+	hash_table_remove(users, user->username);
+	i_free(user->username);
+	i_free(user);
+}
+
+static int imap_client_parse_input(struct imap_client *client)
+{
+	const char *tag, *cmd, *str;
+	const struct imap_arg *args;
+	int ret;
+
+	ret = imap_parser_read_args(client->parser, 0, 0, &args);
+	if (ret < 0) {
+		if (ret == -2)
+			return 0;
+		return -1;
+	}
+
+	if (!imap_arg_get_atom(args, &tag))
+		return -1;
+	args++;
+
+	if (!imap_arg_get_atom(args, &cmd))
+		return -1;
+	args++;
+
+	if (strcasecmp(cmd, "login") == 0) {
+		if (client->username != NULL)
+			return -1;
+
+		if (!imap_arg_get_astring(args, &str))
+			return -1;
+
+		o_stream_send_str(client->output,
+			t_strconcat(tag, " OK Logged in.\r\n", NULL));
+		client->username = i_strdup(str);
+		client_username_check(client);
+	} else if (strcasecmp(cmd, "logout") == 0) {
+		o_stream_send_str(client->output, t_strconcat(
+			"* BYE Out.\r\n",
+			tag, " OK Logged out.\r\n", NULL));
+		imap_client_destroy(&client);
+		return 0;
+	} else if (strcasecmp(cmd, "capability") == 0) {
+		o_stream_send_str(client->output,
+			t_strconcat("* CAPABILITY IMAP4rev1\r\n",
+				    tag, " OK Done.\r\n", NULL));
+	} else {
+		o_stream_send_str(client->output,
+			t_strconcat(tag, " BAD Not supported.\r\n", NULL));
+	}
+
+	(void)i_stream_read_next_line(client->input); /* eat away LF */
+	imap_parser_reset(client->parser);
+	return 1;
+}
+
+static void imap_client_input(struct imap_client *client)
+{
+	int ret;
+
+	switch (i_stream_read(client->input)) {
+	case -2:
+		i_error("imap: Too much input");
+		imap_client_destroy(&client);
+		return;
+	case -1:
+		imap_client_destroy(&client);
+		return;
+	default:
+		break;
+	}
+
+	while ((ret = imap_client_parse_input(client)) > 0) ;
+	if (ret < 0) {
+		i_error("imap: Invalid input");
+		imap_client_destroy(&client);
+	}
+}
+
+static void imap_client_create(int fd)
+{
+	struct imap_client *client;
+
+	client = i_new(struct imap_client, 1);
+	client->fd = fd;
+	client->input = i_stream_create_fd(fd, 4096, FALSE);
+	client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+	client->io = io_add(fd, IO_READ, imap_client_input, client);
+	client->parser =
+		imap_parser_create(client->input, client->output, 4096);
+	o_stream_send_str(client->output,
+		"* OK [CAPABILITY IMAP4rev1] director-test ready.\r\n");
+	DLLIST_PREPEND(&imap_clients, client);
+}
+
+static void imap_client_destroy(struct imap_client **_client)
+{
+	struct imap_client *client = *_client;
+	struct user *user = client->user;
+
+	*_client = NULL;
+
+	if (user != NULL) {
+		i_assert(user->connections > 0);
+		if (--user->connections == 0) {
+			i_assert(user->to == NULL);
+			user->to = timeout_add(USER_TIMEOUT_MSECS, user_free,
+					       user);
+		}
+		user->last_seen = ioloop_time;
+	}
+


More information about the dovecot-cvs mailing list