director-test.c revision 9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen/*
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen This program accepts incoming unauthenticated IMAP connections from
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen port 14300. If the same user is connecting to multiple different local IPs,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen it logs an error (i.e. director is not working right then).
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen This program also accepts incoming director connections on port 9091 and
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen forwards them to local_ip:9090. To make this work properly, director
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen executable must be given -t 9091 parameter. The idea is that this test tool
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hooks between all director connections and can then add delays or break the
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen connections.
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen Finally, this program connects to director-admin socket where it adds
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen and removes mail hosts.
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen*/
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "lib.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "ioloop.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "istream.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "ostream.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "write-full.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "hash.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "llist.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "imap-parser.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "master-service.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "master-service-settings.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "director-settings.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include <stdlib.h>
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include <unistd.h>
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define IMAP_PORT 14300
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define DIRECTOR_IN_PORT 9091
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define DIRECTOR_OUT_PORT 9090
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define USER_TIMEOUT_MSECS (1000*60)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#define ADMIN_RANDOM_TIMEOUT_MSECS 500
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen#define DIRECTOR_CONN_MAX_DELAY_MSECS 100
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstruct host {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen int refcount;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct ip_addr ip;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen unsigned int vhost_count;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct user {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen char *username;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *host;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen time_t last_seen;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned int connections;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct timeout *to;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct imap_client {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct imap_client *prev, *next;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct io *io;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct istream *input;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct ostream *output;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct imap_parser *parser;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct user *user;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen char *username;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct director_connection {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct director_connection *prev, *next;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int in_fd, out_fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct io *in_io, *out_io;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct istream *in_input, *out_input;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct ostream *in_output, *out_output;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct timeout *to_delay;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct admin_connection {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen char *path;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int fd;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct io *io;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct istream *input;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct timeout *to_random;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct imap_client *imap_clients;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct director_connection *director_connections;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct hash_table *users;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic struct hash_table *hosts;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic ARRAY_DEFINE(hosts_array, struct host *);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct admin_connection *admin;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void imap_client_destroy(struct imap_client **client);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void director_connection_destroy(struct director_connection **conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void director_connection_timeout(struct director_connection *conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void host_unref(struct host **_host)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *host = *_host;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen *_host = NULL;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_assert(host->refcount > 0);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (--host->refcount > 0)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen return;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_free(host);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void client_username_check(struct imap_client *client)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct user *user;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *host;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct ip_addr local_ip;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (net_getsockname(client->fd, &local_ip, NULL) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("net_getsockname() failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host = hash_table_lookup(hosts, &local_ip);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (host == NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("User logging into unknown host %s",
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_ip2addr(&local_ip));
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host = i_new(struct host, 1);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host->refcount++;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host->ip = local_ip;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host->vhost_count = 100;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hash_table_insert(hosts, &host->ip, host);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen array_append(&hosts_array, &host, 1);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user = hash_table_lookup(users, client->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (user == NULL) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user = i_new(struct user, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user->username = i_strdup(client->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen hash_table_insert(users, user->username, user);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen } else if (user->host != host) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("user %s: old connection from %s, new from %s. "
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "%u old connections, last was %u secs ago",
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen user->username, net_ip2addr(&user->host->ip),
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_ip2addr(&host->ip), user->connections,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen (unsigned int)(ioloop_time - user->last_seen));
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen host_unref(&user->host);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->user = user;
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen user->host = host;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user->connections++;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user->last_seen = ioloop_time;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen user->host->refcount++;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (user->to != NULL)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen timeout_remove(&user->to);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void user_free(struct user *user)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host_unref(&user->host);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (user->to != NULL)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen timeout_remove(&user->to);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen hash_table_remove(users, user->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(user->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(user);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic int imap_client_parse_input(struct imap_client *client)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const char *tag, *cmd, *str;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const struct imap_arg *args;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int ret;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ret = imap_parser_read_args(client->parser, 0, 0, &args);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret < 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret == -2)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return 0;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (!imap_arg_get_atom(args, &tag))
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen args++;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (!imap_arg_get_atom(args, &cmd))
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen args++;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (strcasecmp(cmd, "login") == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (client->username != NULL)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (!imap_arg_get_astring(args, &str))
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_send_str(client->output,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen t_strconcat(tag, " OK Logged in.\r\n", NULL));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->username = i_strdup(str);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client_username_check(client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else if (strcasecmp(cmd, "logout") == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_send_str(client->output, t_strconcat(
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "* BYE Out.\r\n",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen tag, " OK Logged out.\r\n", NULL));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_client_destroy(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return 0;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else if (strcasecmp(cmd, "capability") == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_send_str(client->output,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen t_strconcat("* CAPABILITY IMAP4rev1\r\n",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen tag, " OK Done.\r\n", NULL));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_send_str(client->output,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen t_strconcat(tag, " BAD Not supported.\r\n", NULL));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen (void)i_stream_read_next_line(client->input); /* eat away LF */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_parser_reset(client->parser);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return 1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void imap_client_input(struct imap_client *client)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int ret;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen switch (i_stream_read(client->input)) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen case -2:
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("imap: Too much input");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_client_destroy(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen case -1:
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_client_destroy(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen default:
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen break;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen while ((ret = imap_client_parse_input(client)) > 0) ;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret < 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("imap: Invalid input");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_client_destroy(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void imap_client_create(int fd)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct imap_client *client;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client = i_new(struct imap_client, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->fd = fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->input = i_stream_create_fd(fd, 4096, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->io = io_add(fd, IO_READ, imap_client_input, client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->parser =
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_parser_create(client->input, client->output, 4096);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_send_str(client->output,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "* OK [CAPABILITY IMAP4rev1] director-test ready.\r\n");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen DLLIST_PREPEND(&imap_clients, client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void imap_client_destroy(struct imap_client **_client)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct imap_client *client = *_client;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct user *user = client->user;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen *_client = NULL;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (user != NULL) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_assert(user->connections > 0);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (--user->connections == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_assert(user->to == NULL);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user->to = timeout_add(USER_TIMEOUT_MSECS, user_free,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user->last_seen = ioloop_time;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen DLLIST_REMOVE(&imap_clients, client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_parser_destroy(&client->parser);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen io_remove(&client->io);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_stream_unref(&client->input);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_unref(&client->output);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen net_disconnect(client->fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(client->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_client_connection_destroyed(master_service);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainendirector_connection_input(struct director_connection *conn,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct istream *input, struct ostream *output)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen const unsigned char *data;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen size_t size;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (i_stream_read_data(input, &data, &size, 0) == -1) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_destroy(&conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen o_stream_send(output, data, size);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_stream_skip(input, size);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (rand() % 3 == 0 && conn->to_delay == NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->to_delay =
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen timeout_add(rand() % DIRECTOR_CONN_MAX_DELAY_MSECS,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen director_connection_timeout, conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen io_remove(&conn->in_io);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen io_remove(&conn->out_io);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void director_connection_in_input(struct director_connection *conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_input(conn, conn->in_input, conn->out_output);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void director_connection_out_input(struct director_connection *conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_input(conn, conn->out_input, conn->in_output);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void director_connection_timeout(struct director_connection *conn)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen timeout_remove(&conn->to_delay);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->in_io = io_add(conn->in_fd, IO_READ,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen director_connection_in_input, conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->out_io = io_add(conn->out_fd, IO_READ,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen director_connection_out_input, conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainendirector_connection_create(int in_fd, const struct ip_addr *local_ip)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct director_connection *conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn = i_new(struct director_connection, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->in_fd = in_fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->in_input = i_stream_create_fd(conn->in_fd, (size_t)-1, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->in_output = o_stream_create_fd(conn->in_fd, (size_t)-1, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->in_io = io_add(conn->in_fd, IO_READ,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_in_input, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->out_fd = net_connect_ip(local_ip, DIRECTOR_OUT_PORT, NULL);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->out_input = i_stream_create_fd(conn->out_fd, (size_t)-1, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->out_output = o_stream_create_fd(conn->out_fd, (size_t)-1, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->out_io = io_add(conn->out_fd, IO_READ,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_out_input, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen DLLIST_PREPEND(&director_connections, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void director_connection_destroy(struct director_connection **_conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct director_connection *conn = *_conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen DLLIST_REMOVE(&director_connections, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (conn->to_delay != NULL)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen timeout_remove(&conn->to_delay);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (conn->in_io != NULL)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen io_remove(&conn->in_io);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_stream_unref(&conn->in_input);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_unref(&conn->in_output);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen net_disconnect(conn->in_fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (conn->out_io != NULL)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen io_remove(&conn->out_io);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_stream_unref(&conn->out_input);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_unref(&conn->out_output);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen net_disconnect(conn->out_fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void client_connected(struct master_service_connection *conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct ip_addr local_ip;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned int local_port;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (net_getsockname(conn->fd, &local_ip, &local_port) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("net_getsockname() failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (local_port == IMAP_PORT)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_client_create(conn->fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen else if (local_port == DIRECTOR_IN_PORT)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_create(conn->fd, &local_ip);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen else {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("Connection to unknown port %u", local_port);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_client_connection_accept(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenadmin_send(struct admin_connection *conn, const char *data)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (write_full(i_stream_get_fd(conn->input), data, strlen(data)) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("write(%s) failed: %m", conn->path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void admin_input(struct admin_connection *conn)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen const char *line;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen while ((line = i_stream_read_next_line(conn->input)) != NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (strcmp(line, "OK") != 0)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("director-doveadm: Unexpected input: %s", line);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (conn->input->stream_errno != 0 || conn->input->eof)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_fatal("director-doveadm: Connection lost");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void admin_random_action(struct admin_connection *conn)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *const *hosts;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen unsigned int i, count;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hosts = array_get(&hosts_array, &count);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i = rand() % count;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hosts[i]->vhost_count = (rand() % 20) * 10;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin_send(conn, t_strdup_printf("HOST-SET\t%s\t%u\n",
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_ip2addr(&hosts[i]->ip), hosts[i]->vhost_count));
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct admin_connection *admin_connect(const char *path)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define DIRECTOR_ADMIN_HANDSHAKE "VERSION\tdirector-doveadm\t1\t0\n"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct admin_connection *conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const char *line;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn = i_new(struct admin_connection, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->path = i_strdup(path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->fd = net_connect_unix(path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (conn->fd == -1)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("net_connect_unix(%s) failed: %m", path);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->io = io_add(conn->fd, IO_READ, admin_input, conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->to_random = timeout_add(ADMIN_RANDOM_TIMEOUT_MSECS,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin_random_action, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_set_nonblock(conn->fd, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->input = i_stream_create_fd(conn->fd, (size_t)-1, TRUE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen admin_send(conn, DIRECTOR_ADMIN_HANDSHAKE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen line = i_stream_read_next_line(conn->input);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (line == NULL)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("%s disconnected", conn->path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (!version_string_verify(line, "director-doveadm", 1)) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("%s not a compatible director-doveadm socket",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_set_nonblock(conn->fd, TRUE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void admin_disconnect(struct admin_connection **_conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct admin_connection *conn = *_conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen *_conn = NULL;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen //timeout_remove(&conn->to_random);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_stream_destroy(&conn->input);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen io_remove(&conn->io);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen net_disconnect(conn->fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(conn->path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void admin_read_hosts(struct admin_connection *conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen const char *line;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_set_nonblock(admin->fd, FALSE);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen while ((line = i_stream_read_next_line(conn->input)) != NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (*line == '\0')
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen break;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen /* ip vhost-count user-count */
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen T_BEGIN {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen const char *const *args = t_strsplit(line, "\t");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *host;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host = i_new(struct host, 1);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (net_addr2ip(args[0], &host->ip) < 0 ||
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen str_to_uint(args[1], &host->vhost_count) < 0)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_fatal("host list broken");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hash_table_insert(hosts, &host->ip, host);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen array_append(&hosts_array, &host, 1);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen } T_END;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (line == NULL)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_fatal("Couldn't read hosts list");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_set_nonblock(admin->fd, TRUE);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void main_init(const char *admin_path)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen users = hash_table_create(default_pool, default_pool, 0,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_hash, (hash_cmp_callback_t *)strcmp);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hosts = hash_table_create(default_pool, default_pool, 0,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen (hash_callback_t *)net_ip_hash,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen (hash_cmp_callback_t *)net_ip_cmp);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_array_init(&hosts_array, 256);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin = admin_connect(admin_path);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin_send(admin, "HOST-LIST\n");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin_read_hosts(admin);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void main_deinit(void)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct hash_iterate_context *iter;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen void *key, *value;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen while (imap_clients != NULL) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct imap_client *client = imap_clients;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen imap_client_destroy(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen while (director_connections != NULL) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct director_connection *conn = director_connections;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_destroy(&conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen iter = hash_table_iterate_init(users);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen while (hash_table_iterate(iter, &key, &value)) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct user *user = value;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user_free(user);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen hash_table_iterate_deinit(&iter);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen hash_table_destroy(&users);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen iter = hash_table_iterate_init(hosts);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen while (hash_table_iterate(iter, &key, &value)) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *host = value;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host_unref(&host);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hash_table_iterate_deinit(&iter);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hash_table_destroy(&hosts);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen array_free(&hosts_array);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin_disconnect(&admin);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenint main(int argc, char *argv[])
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen const char *admin_path;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service = master_service_init("director-test", 0,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen &argc, &argv, NULL);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (master_getopt(master_service) > 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return FATAL_DEFAULT;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen admin_path = argv[optind];
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (admin_path == NULL)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_fatal("director-doveadm socket path missing");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_init_log(master_service, "director-test: ");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_init_finish(master_service);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen main_init(admin_path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_run(master_service, client_connected);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen main_deinit();
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_deinit(&master_service);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return 0;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}