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