doveadm-connection.c revision 88734aa9496db13e7ce0cd5f1c03b3ddfe3effd6
/* Copyright (c) 2010-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "net.h"
#include "istream.h"
#include "ostream.h"
#include "array.h"
#include "str.h"
#include "strescape.h"
#include "llist.h"
#include "time-util.h"
#include "master-service.h"
#include "user-directory.h"
#include "mail-host.h"
#include "director.h"
#include "director-host.h"
#include "director-request.h"
#include "director-connection.h"
#include "doveadm-connection.h"
#include <unistd.h>
#define DOVEADM_PROTOCOL_VERSION_MAJOR 1
#define DOVEADM_HANDSHAKE "VERSION\tdirector-doveadm\t1\t0\n"
#define MAX_VALID_VHOST_COUNT 1000
#define DEFAULT_MAX_MOVING_USERS 100
enum doveadm_director_cmd_ret {
};
enum doveadm_director_cmd_flag {
};
typedef void
struct director_reset_cmd {
struct doveadm_connection *_conn;
struct timeval start_time;
struct director_user_iter *iter;
unsigned int max_moving_users;
unsigned int reset_count;
bool users_killed;
};
struct doveadm_connection {
int fd;
struct timeout *to_ring_sync_abort;
struct director_reset_cmd *reset_cmd;
const char **cmd_pending_args;
unsigned int cmd_pending_idx;
bool handshaked:1;
};
static struct doveadm_connection *doveadm_connections;
static struct doveadm_connection *doveadm_ring_sync_pending_connections;
static void
static enum doveadm_director_cmd_ret
const char *const *args ATTR_UNUSED)
{
(*hostp)->user_count);
(long)(*hostp)->last_updown_change);
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
const char *const *args ATTR_UNUSED)
{
struct mail_host_list *orig_hosts_list;
unsigned int i, j, orig_hosts_count, cur_hosts_count;
int ret;
NULL);
/* the hosts are sorted by IP */
for (i = j = 0; i < orig_hosts_count && j < cur_hosts_count; ) {
if (ret == 0)
i++, j++;
else if (ret > 0)
j++;
else {
i++;
}
}
for (; i < orig_hosts_count; i++)
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static void
{
}
{
if (!dir->ring_handshaked)
else if (dir->ring_synced)
else {
}
}
static void
{
struct director_connection_status status;
else if (director_connection_is_synced(conn))
else
}
static enum doveadm_director_cmd_ret
const char *const *args ATTR_UNUSED)
{
struct director_host *const *hostp;
const char *type;
struct director_connection *const *connp;
/* show each individual connection */
const struct director_host *host =
/* NOTE: for incoming connections host is initially NULL */
break;
}
}
type = "left";
type = "right";
else if (director_connection_is_incoming(*connp))
type = "in";
else
type = "out";
}
/* show the rest of the hosts that don't have any connections */
type = "removed";
type = "self";
else
type = "";
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
struct director_host *host;
i_error("doveadm sent invalid DIRECTOR-ADD parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
struct director_host *host;
i_error("doveadm sent invalid DIRECTOR-REMOVE parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
} else {
}
}
static enum doveadm_director_cmd_ret
{
unsigned int vhost_count = UINT_MAX;
tag = "";
else
}
i_error("doveadm sent invalid %s parameters",
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
if (update) {
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
"host is already being updated - try again later\n");
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
if (vhost_count != UINT_MAX)
/* NOTE: we don't support changing a tag for an existing host.
it needs to be removed first. otherwise it would be a bit ugly to
handle. */
}
static enum doveadm_director_cmd_ret
{
}
static enum doveadm_director_cmd_ret
{
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
i_error("doveadm sent invalid %s parameters: %s",
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
"host is already being updated - try again later\n");
return DOVEADM_DIRECTOR_CMD_RET_OK;
} else {
}
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
i_error("doveadm sent invalid HOST-REMOVE parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
} else {
}
}
static void
{
unsigned int total_user_count = 0;
}
i_warning("Flushed all backend hosts with %u users. This is an unsafe "
"operation and may cause the same users to end up in multiple backends.",
}
static enum doveadm_director_cmd_ret
{
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
i_error("doveadm sent invalid HOST-FLUSH parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
} else {
}
}
{
}
static bool
{
return FALSE;
}
continue;
} else {
/* there are no more available backends.
kick the user instead. */
TRUE);
}
cmd->reset_count++;
} T_END;
break;
}
i_info("Moved %u users in %u hosts in %u.%03u secs (max parallel=%u)",
if (cmd->users_killed) {
/* no more backends. we already sent kills. now remove
the users entirely from the host. */
}
}
}
static bool
{
unsigned int count;
return FALSE;
}
}
return TRUE;
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
struct director_reset_cmd *cmd;
unsigned int i = 0, count;
unsigned int max_moving_users = DEFAULT_MAX_MOVING_USERS;
max_moving_users == 0)) {
i_error("doveadm sent invalid HOST-RESET-USERS parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
i_error("doveadm sent invalid HOST-RESET-USERS ip: %s",
args[0]);
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
for (i = 0; i < count; i++) {
break;
}
if (i == count) {
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
count = i+1;
}
cmd->host_start_idx = i;
if (!director_reset_cmd_run(cmd)) {
/* we still have work to do. don't handle any more doveadm
input until we're finished. */
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
unsigned int username_hash;
username = "";
tag = "";
} else {
}
username, &username_hash)) {
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
}
/* get user's current host */
else {
}
/* get host if it wasn't in user directory */
else
/* get host with default configuration */
username_hash, tag);
else
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
{
struct director_user_iter *iter;
i_error("doveadm sent invalid USER-LIST parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
} else {
}
"%u\t%u\t%s\n",
} T_END;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
{
unsigned int username_hash;
i_error("doveadm sent invalid USER-MOVE parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
args[0], &username_hash)) {
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
} else {
/* already the correct host. reset the user's timeout. */
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
{
i_error("doveadm sent invalid USER-KICK parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
{
i_error("doveadm sent invalid USER-KICK-ALT parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
struct {
const char *name;
enum doveadm_director_cmd_ret (*cmd)
} doveadm_director_commands[] = {
{ "HOST-LIST", doveadm_cmd_host_list, 0 },
{ "HOST-LIST-REMOVED", doveadm_cmd_host_list_removed, 0 },
{ "DIRECTOR-LIST", doveadm_cmd_director_list, 0 },
{ "HOST-RESET-USERS", doveadm_cmd_host_reset_users, 0 },
{ "USER-LOOKUP", doveadm_cmd_user_lookup, 0 },
{ "USER-LIST", doveadm_cmd_user_list, 0 },
{ "USER-MOVE", doveadm_cmd_user_move, 0 },
{ "USER-KICK", doveadm_cmd_user_kick, 0 },
{ "USER-KICK-ALT", doveadm_cmd_user_kick_alt, 0 },
};
static void
{
}
static void
{
}
{
}
static enum doveadm_director_cmd_ret
const char *const *args, unsigned int i)
{
enum doveadm_director_cmd_ret ret;
if ((doveadm_director_commands[i].flags &
/* wait for ring to be synced before running the command */
conn->cmd_pending_idx = i;
}
return ret;
/* Delay sending OK until ring is synced. This way doveadm will know
whether the call actually succeeded or not. */
/* director is alone */
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
}
{
}
static enum doveadm_director_cmd_ret
{
i_error("doveadm sent empty command line");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
args++;
for (unsigned int i = 0; i < N_ELEMENTS(doveadm_director_commands); i++) {
}
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
{
const char *line;
if (!conn->handshaked) {
return;
}
i_error("doveadm not compatible with this server "
"(mixed old and new binaries?)");
return;
}
}
T_BEGIN {
} T_END;
}
}
{
}
struct doveadm_connection *
{
struct doveadm_connection *conn;
return conn;
}
{
/* finish the move even if doveadm disconnected */
}
i_error("close(doveadm connection) failed: %m");
}
static void
{
}
void doveadm_connections_deinit(void)
{
while (reset_cmds != NULL)
unsigned int pending_count = 0;
while (doveadm_ring_sync_pending_connections != NULL) {
}
if (pending_count > 0)
while (doveadm_connections != NULL) {
}
}
static void doveadm_connections_continue_reset_cmds(void)
{
while (reset_cmds != NULL) {
if (!director_reset_cmd_run(reset_cmds))
break;
}
}
void doveadm_connections_ring_synced(void)
{
while (doveadm_ring_sync_pending_connections != NULL) {
struct doveadm_connection *conn =
}
}