ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "lib.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "ioloop.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "array.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "str.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "mail-host.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "director.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#include "director-request.h"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#define DIRECTOR_REQUEST_TIMEOUT_SECS 30
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#define RING_NOCONN_WARNING_DELAY_MSECS (2*1000)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhenum director_request_delay_reason {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh REQUEST_DELAY_NONE = 0,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh REQUEST_DELAY_RINGNOTHANDSHAKED,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh REQUEST_DELAY_RINGNOTSYNCED,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh REQUEST_DELAY_NOHOSTS,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh REQUEST_DELAY_WEAK,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh REQUEST_DELAY_KILL
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh};
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic const char *delay_reason_strings[] = {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "unknown",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "ring not handshaked",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "ring not synced",
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh "no hosts",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "weak user",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "kill waiting"
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh};
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstruct director_request {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh struct director *dir;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh time_t create_time;
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh unsigned int username_hash;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh enum director_request_delay_reason delay_reason;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh char *username_tag;
3996e391054a1c02ab62e1541ae21a8204bd5d0aAmitKumar
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh director_request_callback *callback;
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh void *context;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh};
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic void director_request_free(struct director_request *request)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik{
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh i_free(request->username_tag);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh i_free(request);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik}
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic const char *
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikdirector_request_get_timeout_error(struct director_request *request,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh struct user *user, string_t *str)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik{
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik unsigned int secs;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_truncate(str, 0);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh str_printfa(str, "Timeout because %s - queued for %u secs (",
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh delay_reason_strings[request->delay_reason],
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh (unsigned int)(ioloop_time - request->create_time));
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (request->dir->ring_last_sync_time == 0)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_append(str, "Ring has never been synced");
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik else {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik secs = ioloop_time - request->dir->ring_last_sync_time;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (request->dir->ring_synced)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh str_printfa(str, "Ring synced for %u secs", secs);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh else
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh str_printfa(str, "Ring not synced for %u secs", secs);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh }
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (user != NULL) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (user->weak)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_append(str, ", weak user");
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_printfa(str, ", user refreshed %u secs ago",
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik (unsigned int)(ioloop_time - user->timestamp));
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik }
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_printfa(str, ", hash=%u", request->username_hash);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (request->username_tag != NULL)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_printfa(str, ", tag=%s", request->username_tag);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik str_append_c(str, ')');
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik return str_c(str);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik}
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic void director_request_timeout(struct director *dir)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik{
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek struct director_request **requestp, *request;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik struct user *user;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik const char *errormsg;
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek string_t *str = t_str_new(128);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik while (array_count(&dir->pending_requests) > 0) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik requestp = array_idx_modifiable(&dir->pending_requests, 0);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request = *requestp;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (request->create_time +
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik DIRECTOR_REQUEST_TIMEOUT_SECS > ioloop_time)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik break;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik const char *tag_name = request->username_tag == NULL ? "" :
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek request->username_tag;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik struct mail_tag *tag = mail_tag_find(dir->mail_hosts, tag_name);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user = tag == NULL ? NULL :
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user_directory_lookup(tag->users, request->username_hash);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik errormsg = director_request_get_timeout_error(request,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user, str);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (user != NULL &&
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->delay_reason == REQUEST_DELAY_WEAK) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /* weakness appears to have gotten stuck. this is a
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik bug, but try to fix it for future requests by
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik removing the weakness. */
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek user->weak = FALSE;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik }
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik i_assert(dir->requests_delayed_count > 0);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik dir->requests_delayed_count--;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik array_delete(&dir->pending_requests, 0, 1);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik T_BEGIN {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->callback(NULL, NULL, errormsg, request->context);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik } T_END;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik director_request_free(request);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik }
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh if (array_count(&dir->pending_requests) == 0 && dir->to_request != NULL)
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh timeout_remove(&dir->to_request);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik}
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikvoid director_request(struct director *dir, const char *username,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik const char *tag,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik director_request_callback *callback, void *context)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik{
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik struct director_request *request;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik unsigned int username_hash;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (!director_get_username_hash(dir, username,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik &username_hash)) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik callback(NULL, NULL, "Failed to expand director_username_hash", context);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik return;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik }
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik dir->num_requests++;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek request = i_new(struct director_request, 1);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->dir = dir;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->create_time = ioloop_time;
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek request->username_hash = username_hash;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->username_tag = tag[0] == '\0' ? NULL : i_strdup(tag);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->callback = callback;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->context = context;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (director_request_continue(request))
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik return;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /* need to queue it */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (dir->to_request == NULL) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik dir->to_request =
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik timeout_add(DIRECTOR_REQUEST_TIMEOUT_SECS * 1000,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik director_request_timeout, dir);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik }
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik array_append(&dir->pending_requests, &request, 1);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik}
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic void ring_noconn_warning(struct director *dir)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh{
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (!dir->ring_handshaked) {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh i_warning("Delaying all requests "
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh "until all directors have connected");
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh } else {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh i_warning("Delaying new user requests until ring is synced");
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh }
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir->ring_handshake_warning_sent = TRUE;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik timeout_remove(&dir->to_handshake_warning);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh}
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic void ring_log_delayed_warning(struct director *dir)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh{
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (dir->ring_handshake_warning_sent ||
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir->to_handshake_warning != NULL)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh return;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir->to_handshake_warning = timeout_add(RING_NOCONN_WARNING_DELAY_MSECS,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh ring_noconn_warning, dir);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh}
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic bool
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhdirector_request_existing(struct director_request *request, struct user *user)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh{
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh struct director *dir = request->dir;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh struct mail_host *host;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (USER_IS_BEING_KILLED(user)) {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* delay processing this user's connections until
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh its existing connections have been killed */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->delay_reason = REQUEST_DELAY_KILL;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir_debug("request: %u waiting for kill to finish",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh user->username_hash);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh return FALSE;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh }
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (dir->right == NULL && dir->ring_synced) {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* looks like all the other directors have died. we can do
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh whatever we want without breaking anything. remove the
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user's weakness just in case it was set to TRUE when we
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik had more directors. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik user->weak = FALSE;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik return TRUE;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik }
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (user->weak) {
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* wait for user to become non-weak */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->delay_reason = REQUEST_DELAY_WEAK;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir_debug("request: %u waiting for weakness",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->username_hash);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh return FALSE;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh }
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (!user_directory_user_is_near_expiring(user->host->tag->users, user))
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh return TRUE;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* user is close to being expired. another director may have
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh already expired it. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh user->host->tag->name);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik if (!dir->ring_synced) {
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /* try again later once ring is synced */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik request->delay_reason = REQUEST_DELAY_RINGNOTSYNCED;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dir_debug("request: %u waiting for sync for making weak",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh request->username_hash);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh return FALSE;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh }
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek if (user->host == host) {
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek /* doesn't matter, other directors would
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek assign the user the same way regardless */
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek dir_debug("request: %u would be weak, but host doesn't change", request->username_hash);
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek return TRUE;
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek }
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek /* We have to worry about two separate timepoints in here:
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh a) some directors think the user isn't expiring, and
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh others think the user is near expiring
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek b) some directors think the user is near expiring, and
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh others think the user has already expired
What we don't have to worry about is:
!c) some directors think the user isn't expiring, and
others think the user has already expired
If !c) happens, the user might get redirected to different backends.
We'll use a large enough timeout between a) and b) states, so that
!c) should never happen.
So what we'll do here is:
1. Send a USER-WEAK notification to all directors with the new host.
2. Each director receiving USER-WEAK refreshes the user's timestamp
and host, but marks the user as being weak.
3. Once USER-WEAK has reached all directors, a real USER update is
sent, which removes the weak-flag.
4. If a director ever receives a USER update for a weak user, the
USER update overrides the host and removes the weak-flag.
5. Director doesn't let any weak user log in, until the weak-flag
gets removed.
*/
if (dir->ring_min_version < DIRECTOR_VERSION_WEAK_USERS) {
/* weak users not supported by ring currently */
return TRUE;
} else {
user->weak = TRUE;
director_update_user_weak(dir, dir->self_host, NULL, NULL, user);
request->delay_reason = REQUEST_DELAY_WEAK;
dir_debug("request: %u set to weak", request->username_hash);
return FALSE;
}
}
static bool director_request_continue_real(struct director_request *request)
{
struct director *dir = request->dir;
struct mail_host *host;
struct user *user;
const char *tag;
struct mail_tag *mail_tag;
if (!dir->ring_handshaked) {
/* delay requests until ring handshaking is complete */
dir_debug("request: %u waiting for handshake",
request->username_hash);
ring_log_delayed_warning(dir);
request->delay_reason = REQUEST_DELAY_RINGNOTHANDSHAKED;
return FALSE;
}
tag = request->username_tag == NULL ? "" : request->username_tag;
mail_tag = mail_tag_find(dir->mail_hosts, tag);
user = mail_tag == NULL ? NULL :
user_directory_lookup(mail_tag->users, request->username_hash);
if (user != NULL) {
i_assert(user->host->tag == mail_tag);
if (!director_request_existing(request, user))
return FALSE;
user_directory_refresh(mail_tag->users, user);
dir_debug("request: %u refreshed timeout to %u",
request->username_hash, user->timestamp);
} else {
if (!dir->ring_synced) {
/* delay adding new users until ring is again synced */
ring_log_delayed_warning(dir);
request->delay_reason = REQUEST_DELAY_RINGNOTSYNCED;
dir_debug("request: %u waiting for sync for adding",
request->username_hash);
return FALSE;
}
host = mail_host_get_by_hash(dir->mail_hosts,
request->username_hash, tag);
if (host == NULL) {
/* all hosts have been removed */
request->delay_reason = REQUEST_DELAY_NOHOSTS;
dir_debug("request: %u waiting for hosts",
request->username_hash);
return FALSE;
}
user = user_directory_add(host->tag->users,
request->username_hash,
host, ioloop_time);
dir_debug("request: %u added timeout to %u (hosts_hash=%u)",
request->username_hash, user->timestamp,
mail_hosts_hash(dir->mail_hosts));
}
i_assert(!user->weak);
director_update_user(dir, dir->self_host, user);
T_BEGIN {
request->callback(user->host, user->host->hostname,
NULL, request->context);
} T_END;
director_request_free(request);
return TRUE;
}
bool director_request_continue(struct director_request *request)
{
if (request->delay_reason != REQUEST_DELAY_NONE) {
i_assert(request->dir->requests_delayed_count > 0);
request->dir->requests_delayed_count--;
}
if (!director_request_continue_real(request)) {
i_assert(request->delay_reason != REQUEST_DELAY_NONE);
request->dir->requests_delayed_count++;
return FALSE;
}
return TRUE;
}