/* Copyright (c) 2010-2018 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>
enum doveadm_director_cmd_ret {
};
enum doveadm_director_cmd_flag {
};
typedef void
struct director_reset_cmd {
unsigned int max_moving_users;
unsigned int reset_count;
bool users_killed;
};
struct director_kick_cmd {
};
struct doveadm_connection {
int fd;
const char **cmd_pending_args;
unsigned int cmd_pending_idx;
};
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)
{
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
{
if (!director_connection_is_handshaked(conn)) {
else
} else if (director_connection_is_synced(conn))
else
}
static void
struct director_connection *conn,
const struct director_host *host,
{
const char *type;
type = "left";
type = "right";
else if (director_connection_is_incoming(conn))
type = "in";
else
type = "out";
}
static void
{
const char *type;
type = "removed";
type = "self";
else
type = "";
}
static enum doveadm_director_cmd_ret
const char *const *args ATTR_UNUSED)
{
/* first show incoming connections that have no known host yet */
}
/* show other connections and host without connections sorted by host */
continue;
}
if (!have_connections)
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
static enum doveadm_director_cmd_ret
const char *const *args)
{
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)
{
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
{
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)
{
unsigned int i = 0, count;
unsigned int 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
{
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;
}
{
}
{
return FALSE;
else
}
return TRUE;
}
static enum doveadm_director_cmd_ret
{
i_error("doveadm sent invalid USER-KICK parameters");
return DOVEADM_DIRECTOR_CMD_RET_FAIL;
}
if (!doveadm_cmd_user_kick_run(cmd)) {
if (wait) {
/* we have work to do, wait until it finishes */
} else {
/* need to remove it here */
}
}
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;
}
if (!doveadm_cmd_user_kick_run(cmd)) {
if (wait) {
/* we have work to do, wait until it finishes */
} else {
}
}
return DOVEADM_DIRECTOR_CMD_RET_OK;
}
struct {
const char *name;
} 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)
{
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 *
{
return conn;
}
{
/* finish the move even if doveadm disconnected */
}
/* finish the kick 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) {
}
}
{
break;
}
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) {
}
}