penalty.c revision 7e7cdca78e6a67757188406c8de9db42fcd17881
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen/* Copyright (C) 2009 Dovecot authors, see the included COPYING file */
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#include "lib.h"
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#include "ioloop.h"
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#include "hash.h"
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#include "llist.h"
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#include "penalty.h"
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#include <time.h>
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen#define PENALTY_DEFAULT_EXPIRE_SECS (60*60)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenstruct penalty_rec {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen /* ordered by last_update */
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct penalty_rec *prev, *next;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen char *ident;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen unsigned int penalty;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen time_t last_update;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen};
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenstruct penalty {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen /* ident => penalty_rec */
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct hash_table *hash;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct penalty_rec *oldest, *newest;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen unsigned int expire_secs;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct timeout *to;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen};
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenstruct penalty *penalty_init(void)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct penalty *penalty;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty = i_new(struct penalty, 1);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty->hash =
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen hash_table_create(default_pool, default_pool, 0,
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen str_hash, (hash_cmp_callback_t *)strcmp);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty->expire_secs = PENALTY_DEFAULT_EXPIRE_SECS;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen return penalty;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenstatic void penalty_rec_free(struct penalty *penalty, struct penalty_rec *rec)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen i_free(rec->ident);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen i_free(rec);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenvoid penalty_deinit(struct penalty **_penalty)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct penalty *penalty = *_penalty;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen *_penalty = NULL;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen while (penalty->oldest != NULL)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty_rec_free(penalty, penalty->oldest);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen hash_table_destroy(&penalty->hash);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen if (penalty->to != NULL)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen timeout_remove(&penalty->to);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen i_free(penalty);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenvoid penalty_set_expire_secs(struct penalty *penalty, unsigned int expire_secs)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty->expire_secs = expire_secs;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenunsigned int penalty_get(struct penalty *penalty, const char *ident,
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen time_t *last_update_r)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct penalty_rec *rec;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen rec = hash_table_lookup(penalty->hash, ident);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen if (rec == NULL) {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen *last_update_r = 0;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen return 0;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen } else {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen *last_update_r = rec->last_update;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen return rec->penalty;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen }
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenstatic void penalty_timeout(struct penalty *penalty)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen time_t expire_time;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen expire_time = ioloop_time - penalty->expire_secs;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen while (penalty->oldest != NULL &&
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty->oldest->last_update <= expire_time) {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen hash_table_remove(penalty->hash, penalty->oldest->ident);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty_rec_free(penalty, penalty->oldest);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen }
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen timeout_remove(&penalty->to);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen if (penalty->oldest != NULL) {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen unsigned int diff = penalty->oldest->last_update - expire_time;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty->to = timeout_add(diff * 1000,
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty_timeout, penalty);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen }
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainenvoid penalty_set(struct penalty *penalty, const char *ident,
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen unsigned int value)
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen{
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen struct penalty_rec *rec;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen rec = hash_table_lookup(penalty->hash, ident);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen if (rec == NULL) {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen rec = i_new(struct penalty_rec, 1);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen rec->ident = i_strdup(ident);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen hash_table_insert(penalty->hash, rec->ident, rec);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen } else {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen }
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen rec->penalty = value;
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen rec->last_update = time(NULL);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen DLLIST2_APPEND(&penalty->oldest, &penalty->newest, rec);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen if (penalty->to == NULL) {
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty->to = timeout_add(penalty->expire_secs * 1000,
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen penalty_timeout, penalty);
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen }
7e7cdca78e6a67757188406c8de9db42fcd17881Timo Sirainen}