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