bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 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"
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen#include "strescape.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 <unistd.h>
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define IMAP_PORT 14300
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define DIRECTOR_IN_PORT 9091
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define DIRECTOR_OUT_PORT 9090
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen#define USER_TIMEOUT_MSECS (1000*10) /* FIXME: this should be based on director_user_expire */
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#define ADMIN_RANDOM_TIMEOUT_MSECS 500
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen#define DIRECTOR_CONN_MAX_DELAY_MSECS 100
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen#define DIRECTOR_DISCONNECT_TIMEOUT_SECS 10
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;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen bool pending_command;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct imap_client *imap_clients;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct director_connection *director_connections;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainenstatic HASH_TABLE(char *, struct user *) users;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainenstatic HASH_TABLE(struct ip_addr *, struct host *) hosts;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(struct host *) hosts_array;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic struct admin_connection *admin;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic struct timeout *to_disconnect;
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);
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen host->refcount = 1;
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
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&user->to);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void user_free(struct user *user)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host_unref(&user->host);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek 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
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_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) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_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) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(client->output,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen t_strconcat("* CAPABILITY IMAP4rev1\r\n",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen tag, " OK Done.\r\n", NULL));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_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;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->input = i_stream_create_fd(fd, 4096);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->output = o_stream_create_fd(fd, (size_t)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
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);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_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);
428fb4dc39c6e9b2eb36216c396dad6096a65f8fTimo Sirainen imap_parser_unref(&client->parser);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen io_remove(&client->io);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_stream_destroy(&client->input);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_destroy(&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
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody if (i_stream_read_more(input, &data, &size) == -1) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_destroy(&conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, data, size);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_stream_skip(input, size);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek if (i_rand_limit(3) == 0 && conn->to_delay == NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->to_delay =
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek timeout_add(i_rand_limit(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
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainendirector_connection_create(int in_fd, const struct ip_addr *local_ip,
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen const struct ip_addr *remote_ip)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct director_connection *conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen int out_fd;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen out_fd = net_connect_ip(local_ip, DIRECTOR_OUT_PORT, remote_ip);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (out_fd == -1) {
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&in_fd);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn = i_new(struct director_connection, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->in_fd = in_fd;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->in_input = i_stream_create_fd(conn->in_fd, (size_t)-1);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->in_output = o_stream_create_fd(conn->in_fd, (size_t)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->in_output, TRUE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->in_io = io_add(conn->in_fd, IO_READ,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen director_connection_in_input, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->out_fd = out_fd;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->out_input = i_stream_create_fd(conn->out_fd, (size_t)-1);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->out_output = o_stream_create_fd(conn->out_fd, (size_t)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->out_output, TRUE);
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
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to_delay);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek 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
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek 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{
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen struct ip_addr local_ip, remote_ip;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t local_port;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (net_getsockname(conn->fd, &local_ip, &local_port) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_fatal("net_getsockname() failed: %m");
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen if (net_getpeername(conn->fd, &remote_ip, NULL) < 0)
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo 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)
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen director_connection_create(conn->fd, &local_ip, &remote_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);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->pending_command = FALSE;
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
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (conn->pending_command)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen hosts = array_get(&hosts_array, &count);
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek i = i_rand_limit(count);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek hosts[i]->vhost_count = i_rand_limit(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));
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen conn->pending_command = TRUE;
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);
4b335788eb41dec2de5f78459d96387fcc710010Timo Sirainen conn->to_random = timeout_add_short(ADMIN_RANDOM_TIMEOUT_MSECS,
4b335788eb41dec2de5f78459d96387fcc710010Timo Sirainen admin_random_action, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen net_set_nonblock(conn->fd, FALSE);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->input = i_stream_create_fd(conn->fd, (size_t)-1);
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;
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek 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 {
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen const char *const *args = t_strsplit_tabescaped(line);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct host *host;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host = i_new(struct host, 1);
c9b3bbfb605ca19fbd39d083984241b2419e9fe1Timo Sirainen host->refcount = 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
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(1)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainendirector_connection_disconnect_timeout(void *context ATTR_UNUSED)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct director_connection *conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen unsigned int i, count = 0;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen for (conn = director_connections; conn != NULL; conn = conn->next)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen count++;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (count != 0) {
62461eb609e1d852e027cf4e07d30d51288678a2Aki Tuomi i = 0; count = i_rand() % count;
6c961309a97ee0c86b85fa336f5f51662bd3d515Timo Sirainen for (conn = director_connections; i < count; conn = conn->next) {
6c961309a97ee0c86b85fa336f5f51662bd3d515Timo Sirainen i_assert(conn != NULL);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i++;
6c961309a97ee0c86b85fa336f5f51662bd3d515Timo Sirainen }
c1b9c4531186c6a7cd92d2c353273a834f8ee66fTimo Sirainen i_assert(conn != NULL);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_connection_destroy(&conn);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic void main_init(const char *admin_path)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&users, default_pool, 0, str_hash, strcmp);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&hosts, default_pool, 0, net_ip_hash, 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);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen to_disconnect =
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek timeout_add(1000 * i_rand_minmax(5, 5 + DIRECTOR_DISCONNECT_TIMEOUT_SECS - 1),
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek director_connection_disconnect_timeout, NULL);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void main_deinit(void)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen char *username;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct ip_addr *ip;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct user *user;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct host *host;
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
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen timeout_remove(&to_disconnect);
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);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, users, &username, &user))
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen user_free(user);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen hash_table_iterate_deinit(&iter);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen hash_table_destroy(&users);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen iter = hash_table_iterate_init(hosts);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen while (hash_table_iterate(iter, hosts, &ip, &host))
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen host_unref(&host);
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,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen &argc, &argv, "");
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
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen main_init(admin_path);
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen master_service_init_finish(master_service);
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}