director.c revision 002f2544421891472dc9aeb79d3abdde6a8ed4c8
/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "str.h"
#include "ipc-client.h"
#include "user-directory.h"
#include "mail-host.h"
#include "director-host.h"
#include "director-connection.h"
#include "director.h"
#define DIRECTOR_IPC_PROXY_PATH "ipc"
#define DIRECTOR_RECONNECT_RETRY_SECS 60
{
return FALSE;
return FALSE;
return TRUE;
}
{
struct director_host *const *hosts;
unsigned int i, count;
for (i = 0; i < count; i++) {
return;
}
}
i_fatal("director_servers doesn't list ourself");
}
{
return;
if (!director_is_self_ip_set(dir))
i_fatal("director_servers doesn't list ourself (%s:%u)",
}
}
{
struct director_host *const *hosts;
unsigned int i, count;
for (i = 0; i < count; i++) {
return i;
}
i_unreached();
}
static bool
struct director_host *host)
{
struct director_connection *const *connp;
return TRUE;
}
return FALSE;
}
{
unsigned int port;
int fd;
return 0;
i_debug("Connecting to %s:%u",
}
if (fd == -1) {
return -1;
}
/* Reset timestamp so that director_connect() won't skip this host
while we're still trying to connect to it */
host->last_network_failure = 0;
return 0;
}
static struct director_host *
{
struct director_host *const *hosts;
if (count == 1) {
/* self */
return NULL;
}
}
{
struct director_host *const *hosts;
/* try to connect to first working server on our right side.
the left side is supposed to connect to us. */
for (i = 1; i < count; i++) {
/* connection failed recently, don't try retrying here */
continue;
}
/* the director recently sent invalid protocol data,
don't try retrying yet */
continue;
}
break;
}
if (i == count) {
/* we're the only one */
i_debug("director: Couldn't connect to right side, "
"we must be the only director left");
}
/* since we couldn't connect to it,
it must have failed recently */
}
if (!dir->ring_handshaked)
else
}
}
{
if (dir->ring_handshake_warning_sent) {
i_warning("Directors have been connected, "
"continuing delayed requests");
}
i_debug("Director ring handshaked");
}
{
if (preferred_host == NULL) {
/* all directors have been removed, try again later */
} else if (cur_host != preferred_host)
else {
/* the connection hasn't finished sync yet.
keep this timeout for now. */
}
}
{
struct director_host *host;
if (dir->ring_handshake_warning_sent) {
i_warning("Ring is synced, continuing delayed requests");
}
/* try to reconnect to preferred host later */
dir->to_reconnect =
}
} else {
}
}
{
if (minor_version > 0 &&
/* only minor_version>0 supports this parameter */
}
/* ping our connections in case either of them are hanging.
if they are, we want to know it fast. */
}
{
/* send a new SYNC in case the previous one got dropped */
return TRUE;
}
return FALSE;
}
{
if (director_resend_sync(dir))
i_error("Ring SYNC appears to have got lost, resending");
}
{
if (dir->ring_synced) {
}
} else {
}
}
{
/* we're synced again when we receive this SYNC back */
if (dir->sync_frozen) {
return;
}
return;
}
i_debug("Ring is desynced (seq=%u, sending SYNC to %s)",
}
/* send PINGs to our connections more rapidly until we've synced again.
if the connection has actually died, we don't need to wait (and
delay requests) for as long to detect it */
}
{
struct director_connection *const *connp;
}
{
struct director_connection *const *connp;
if (dir->sync_pending) {
}
}
struct director_host *orig_src,
{
/* update state in case this is the first mail host being added */
}
"HOST\t%s\t%u\t%u\t%s\t%u\n",
}
struct director_host *orig_src,
{
}
"HOST-REMOVE\t%s\t%u\t%u\t%s\n",
}
}
struct director_host *orig_src,
{
}
"HOST-FLUSH\t%s\t%u\t%u\t%s\n",
}
{
}
struct director_host *orig_src,
{
}
"USER-WEAK\t%s\t%u\t%u\t%u\t%s\n",
}
struct director_user_kill_finish_ctx {
};
static void
{
}
static void
{
struct director_user_kill_finish_ctx *ctx;
}
struct director_kill_context {
unsigned int username_hash;
bool self;
};
static void
{
/* we're alone */
} else if (self ||
} else {
}
}
{
switch (state) {
return;
case IPC_CLIENT_CMD_STATE_OK:
break;
i_error("Failed to kill user %u connections: %s",
/* we can't really do anything but continue anyway */
break;
}
return;
}
{
i_error("Finishing user %u move timed out, "
}
struct director_host *orig_src,
{
const char *cmd;
struct director_kill_context *ctx;
/* 1. move this user's host, and set its "killing" flag to delay all of
its future connections until all directors have killed the
connections and notified us about it.
2. tell the other directors about the move
3. once user kill callback is called, tell the other directors
with USER-KILLED that we're done killing the user.
4. when some director gets a duplicate USER-KILLED, it's
responsible for notifying all directors that user is completely
killed.
5. after receiving USER-KILLED-EVERYWHERE notification,
new connections are again allowed for the user.
*/
host, ioloop_time);
} else {
/* user is already in this host */
return;
}
}
}
}
"USER-MOVE\t%s\t%u\t%u\t%u\t%s\n",
}
{
return;
switch (user->kill_state) {
case USER_KILL_STATE_KILLING:
break;
break;
case USER_KILL_STATE_NONE:
case USER_KILL_STATE_DELAY:
break;
break;
}
}
struct director_host *src,
struct director_host *orig_src,
unsigned int username_hash)
{
return;
}
"USER-KILLED-EVERYWHERE\t%s\t%u\t%u\t%u\n",
user->username_hash));
}
{
}
const char *cmd)
{
struct director_connection *const *connp;
}
}
struct director *
{
return dir;
}
{
struct director_host *const *hostp;
}
}