penalty.c revision 8825740187b8aaca9c39c4fd6a0b79d480eb143f
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "lib.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "ioloop.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "hash.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "str.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "strescape.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "llist.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "ostream.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include "penalty.h"
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#include <time.h>
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#define PENALTY_DEFAULT_EXPIRE_SECS (60*60)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#define PENALTY_CHECKSUM_SAVE_COUNT
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#define CHECKSUM_VALUE_COUNT 2
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#define CHECKSUM_VALUE_PTR_COUNT 10
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose#define LAST_UPDATE_BITS 15
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestruct penalty_rec {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* ordered by last_update */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty_rec *prev, *next;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose char *ident;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int last_penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int penalty:16;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int last_update:LAST_UPDATE_BITS; /* last_penalty + n */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int checksum_is_pointer:1;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* we use value up to two different checksums.
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose after that switch to pointer. */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose union {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int value[CHECKSUM_VALUE_COUNT];
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int *value_ptr;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose } checksum;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose};
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestruct penalty {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* ident => penalty_rec */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct hash_table *hash;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty_rec *oldest, *newest;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int expire_secs;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct timeout *to;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose};
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestruct penalty *penalty_init(void)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty *penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty = i_new(struct penalty, 1);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty->hash =
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose hash_table_create(default_pool, default_pool, 0,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose str_hash, (hash_cmp_callback_t *)strcmp);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty->expire_secs = PENALTY_DEFAULT_EXPIRE_SECS;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic void penalty_rec_free(struct penalty *penalty, struct penalty_rec *rec)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec->checksum_is_pointer)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_free(rec->checksum.value_ptr);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_free(rec->ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_free(rec);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosevoid penalty_deinit(struct penalty **_penalty)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty *penalty = *_penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose *_penalty = NULL;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose while (penalty->oldest != NULL)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty_rec_free(penalty, penalty->oldest);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose hash_table_destroy(&penalty->hash);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (penalty->to != NULL)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose timeout_remove(&penalty->to);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_free(penalty);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosevoid penalty_set_expire_secs(struct penalty *penalty, unsigned int expire_secs)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty->expire_secs = expire_secs;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic bool
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosepenalty_bump_checksum(struct penalty_rec *rec, unsigned int checksum)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int *checksums;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int i, count;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (!rec->checksum_is_pointer) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose checksums = rec->checksum.value;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose count = CHECKSUM_VALUE_COUNT;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose } else {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose checksums = rec->checksum.value_ptr;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose count = CHECKSUM_VALUE_PTR_COUNT;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose for (i = 0; i < count; i++) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (checksums[i] == checksum) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (i > 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose memcpy(checksums + 1, checksums,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose sizeof(checksums[0]) * i);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose checksums[0] = checksum;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return TRUE;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return FALSE;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic void penalty_add_checksum(struct penalty_rec *rec, unsigned int checksum)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int *checksums;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_assert(checksum != 0);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (!rec->checksum_is_pointer) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec->checksum.value[CHECKSUM_VALUE_COUNT-1] == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose memcpy(rec->checksum.value + 1, rec->checksum.value,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose sizeof(rec->checksum.value[0]) *
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose (CHECKSUM_VALUE_COUNT-1));
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->checksum.value[0] = checksum;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* switch to using a pointer */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose checksums = i_new(unsigned int, CHECKSUM_VALUE_PTR_COUNT);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose memcpy(checksums, rec->checksum.value,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose sizeof(checksums[0]) * CHECKSUM_VALUE_COUNT);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->checksum.value_ptr = checksums;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->checksum_is_pointer = TRUE;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose memcpy(rec->checksum.value_ptr + 1, rec->checksum.value_ptr,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose sizeof(rec->checksum.value_ptr[0]) *
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose (CHECKSUM_VALUE_PTR_COUNT-1));
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->checksum.value_ptr[0] = checksum;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Boseunsigned int penalty_get(struct penalty *penalty, const char *ident,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose time_t *last_penalty_r)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty_rec *rec;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec = hash_table_lookup(penalty->hash, ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec == NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose *last_penalty_r = 0;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return 0;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose *last_penalty_r = rec->last_penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return rec->penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic void penalty_timeout(struct penalty *penalty)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty_rec *rec;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose time_t expire_time;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose expire_time = ioloop_time - penalty->expire_secs;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose while (penalty->oldest != NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec = penalty->oldest;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec->last_penalty + rec->last_update > expire_time)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose break;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose hash_table_remove(penalty->hash, rec->ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty_rec_free(penalty, rec);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose timeout_remove(&penalty->to);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec = penalty->oldest;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec != NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int diff;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose diff = rec->last_penalty + rec->last_update - expire_time;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty->to = timeout_add(diff * 1000,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty_timeout, penalty);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosevoid penalty_inc(struct penalty *penalty, const char *ident,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int checksum, unsigned int value)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty_rec *rec;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose time_t diff;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_assert(value > 0 || checksum == 0);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose i_assert(value <= INT_MAX);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec = hash_table_lookup(penalty->hash, ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec == NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec = i_new(struct penalty_rec, 1);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->ident = i_strdup(ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose hash_table_insert(penalty->hash, rec->ident, rec);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose } else {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose DLLIST2_REMOVE(&penalty->oldest, &penalty->newest, rec);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (checksum == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->penalty = value;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->last_penalty = ioloop_time;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose } else {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (penalty_bump_checksum(rec, checksum))
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->penalty = value - 1;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose else {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty_add_checksum(rec, checksum);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->penalty = value;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->last_penalty = ioloop_time;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose diff = ioloop_time - rec->last_penalty;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (diff >= (1 << LAST_UPDATE_BITS)) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->last_update = (1 << LAST_UPDATE_BITS) - 1;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->last_penalty = ioloop_time - rec->last_update;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose } else {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->last_update = diff;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose DLLIST2_APPEND(&penalty->oldest, &penalty->newest, rec);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (penalty->to == NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty->to = timeout_add(penalty->expire_secs * 1000,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose penalty_timeout, penalty);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosebool penalty_has_checksum(struct penalty *penalty, const char *ident,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int checksum)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct penalty_rec *rec;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const unsigned int *checksums;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose unsigned int i, count;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec = hash_table_lookup(penalty->hash, ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (rec == NULL)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return FALSE;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (!rec->checksum_is_pointer) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose checksums = rec->checksum.value;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose count = CHECKSUM_VALUE_COUNT;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose } else {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose checksums = rec->checksum.value_ptr;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose count = CHECKSUM_VALUE_PTR_COUNT;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose for (i = 0; i < count; i++) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (checksums[i] == checksum)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return TRUE;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return FALSE;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosevoid penalty_dump(struct penalty *penalty, struct ostream *output)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose{
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const struct penalty_rec *rec;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose string_t *str = t_str_new(256);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose for (rec = penalty->oldest; rec != NULL; rec = rec->next) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose str_truncate(str, 0);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose str_tabescape_write(str, rec->ident);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose str_printfa(str, "\t%u\t%u\t%u\n",
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->penalty, rec->last_penalty,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose rec->last_penalty + rec->last_update);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (o_stream_send(output, str_data(str), str_len(str)) < 0)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose break;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose }
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose (void)o_stream_send(output, "\n", 1);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose}
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose