/* Current version of fuzzy hash file format */
#define CURRENT_FUZZY_VERSION 1
+#define INVALID_NODE_TIME (guint64)-1
+
/* Init functions */
gpointer init_fuzzy (struct config_file *cfg);
void start_fuzzy (struct rspamd_worker *worker);
gint fd;
u_char *pos;
socklen_t salen;
+ guint64 time;
union {
struct sockaddr ss;
struct sockaddr_storage sa;
for (i = 0; i < expired_num; i ++) {
#ifdef WITH_JUDY
- PPvoid_t pvalue;
- gpointer data;
-
if (ctx->use_judy) {
node = (struct rspamd_fuzzy_node *)to_expire[i];
+ if (node->time != INVALID_NODE_TIME) {
+ server_stat->fuzzy_hashes_expired ++;
+ }
+ server_stat->fuzzy_hashes --;
JudySLDel (&jtree, node->h.hash_pipe, PJE0);
bloom_del (bf, node->h.hash_pipe);
g_slice_free1 (sizeof (struct rspamd_fuzzy_node), node);
-
- pvalue = JudySLGet (jtree, node->h.hash_pipe, PJE0);
- if (pvalue) {
- data = *pvalue;
- JudySLDel (&jtree, node->h.hash_pipe, PJE0);
- g_slice_free1 (sizeof (struct rspamd_fuzzy_node), data);
- server_stat->fuzzy_hashes_expired ++;
- server_stat->fuzzy_hashes --;
- }
}
else {
#endif
head = hashes[node->h.block_size % BUCKETS];
g_queue_delete_link (head, cur);
bloom_del (bf, node->h.hash_pipe);
- server_stat->fuzzy_hashes_expired++;
+ if (node->time != INVALID_NODE_TIME) {
+ server_stat->fuzzy_hashes_expired ++;
+ }
server_stat->fuzzy_hashes--;
g_slice_free1 (sizeof(struct rspamd_fuzzy_node), node);
#ifdef WITH_JUDY
pvalue = JudySLFirst (jtree, indexbuf, PJE0);
while (pvalue) {
node = *((struct rspamd_fuzzy_node **)pvalue);
- if (now - node->time > expire) {
+ if (node->time == INVALID_NODE_TIME || now - node->time > expire) {
if (nodes_expired == NULL) {
nodes_expired = g_malloc (max_expired * sizeof (gpointer));
}
}
static inline struct rspamd_fuzzy_node *
-check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value, struct rspamd_fuzzy_storage_ctx *ctx)
+check_hash_node (GQueue *hash, fuzzy_hash_t *s, gint update_value,
+ guint64 time, struct rspamd_fuzzy_storage_ctx *ctx)
{
GList *cur;
struct rspamd_fuzzy_node *h;
pvalue = JudySLGet (jtree, s->hash_pipe, PJE0);
if (pvalue != NULL) {
h = *((struct rspamd_fuzzy_node **)pvalue);
- /* Also check block size */
- if (h->h.block_size== s->block_size) {
+
+ if (h->time == INVALID_NODE_TIME) {
+ /* Node is expired */
+ return NULL;
+ }
+ else if (update_value == 0 && time - h->time > ctx->expire) {
+ h->time = INVALID_NODE_TIME;
+ server_stat->fuzzy_hashes_expired ++;
+ return NULL;
+ }
+ else if (h->h.block_size== s->block_size) {
msg_info ("fuzzy hash was found in judy tree");
if (update_value) {
h->value += update_value;
h = cur->data;
if ((prob = fuzzy_compare_hashes (&h->h, s)) > LEV_LIMIT) {
msg_info ("fuzzy hash was found, probability %d%%", prob);
- if (update_value) {
+ if (h->time == INVALID_NODE_TIME) {
+ return NULL;
+ }
+ else if (update_value) {
msg_info ("new hash weight: %d", h->value);
h->value += update_value;
}
+ else if (time - h->time > ctx->expire) {
+ h->time = INVALID_NODE_TIME;
+ server_stat->fuzzy_hashes_expired ++;
+ return NULL;
+ }
return h;
}
cur = g_list_next (cur);
h = cur->data;
if ((prob = fuzzy_compare_hashes (&h->h, s)) > LEV_LIMIT) {
msg_info ("fuzzy hash was found, probability %d%%", prob);
- if (update_value) {
- h->value += update_value;
+ if (h->time == INVALID_NODE_TIME) {
+ return NULL;
+ }
+ else if (update_value) {
msg_info ("new hash weight: %d", h->value);
+ h->value += update_value;
+ }
+ else if (time - h->time > ctx->expire) {
+ h->time = INVALID_NODE_TIME;
+ server_stat->fuzzy_hashes_expired ++;
+ return NULL;
}
if (h->value > (gint)ctx->frequent_score) {
g_queue_unlink (hash, cur);
}
static gint
-process_check_command (struct fuzzy_cmd *cmd, gint *flag, struct rspamd_fuzzy_storage_ctx *ctx)
+process_check_command (struct fuzzy_cmd *cmd, gint *flag, guint64 time, struct rspamd_fuzzy_storage_ctx *ctx)
{
fuzzy_hash_t s;
struct rspamd_fuzzy_node *h;
s.block_size = cmd->blocksize;
rspamd_rwlock_reader_lock (ctx->tree_lock);
- h = check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, 0, ctx);
+ h = check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, 0, time, ctx);
rspamd_rwlock_reader_unlock (ctx->tree_lock);
if (h == NULL) {
}
static gboolean
-update_hash (struct fuzzy_cmd *cmd, struct rspamd_fuzzy_storage_ctx *ctx)
+update_hash (struct fuzzy_cmd *cmd, guint64 time, struct rspamd_fuzzy_storage_ctx *ctx)
{
fuzzy_hash_t s;
- gboolean r;
+ struct rspamd_fuzzy_node *n;
memcpy (s.hash_pipe, cmd->hash, sizeof (s.hash_pipe));
s.block_size = cmd->blocksize;
mods ++;
rspamd_rwlock_writer_lock (ctx->tree_lock);
- r = check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, cmd->value, ctx) != NULL;
+ n = check_hash_node (hashes[cmd->blocksize % BUCKETS], &s, cmd->value, time, ctx);
rspamd_rwlock_writer_unlock (ctx->tree_lock);
- return r;
+ if (n != NULL) {
+ n->time = time;
+ return TRUE;
+ }
+ return FALSE;
}
static gboolean
-process_write_command (struct fuzzy_cmd *cmd, struct rspamd_fuzzy_storage_ctx *ctx)
+process_write_command (struct fuzzy_cmd *cmd, guint64 time, struct rspamd_fuzzy_storage_ctx *ctx)
{
struct rspamd_fuzzy_node *h;
#ifdef WITH_JUDY
#endif
if (bloom_check (bf, cmd->hash)) {
- if (update_hash (cmd, ctx)) {
+ if (update_hash (cmd, time, ctx)) {
return TRUE;
}
}
h = g_slice_alloc (sizeof (struct rspamd_fuzzy_node));
memcpy (&h->h.hash_pipe, &cmd->hash, sizeof (cmd->hash));
h->h.block_size = cmd->blocksize;
- h->time = (guint64) time (NULL);
+ h->time = time;
h->value = cmd->value;
h->flag = cmd->flag;
#ifdef WITH_JUDY
}
static gboolean
-process_delete_command (struct fuzzy_cmd *cmd, struct rspamd_fuzzy_storage_ctx *ctx)
+process_delete_command (struct fuzzy_cmd *cmd, guint64 time, struct rspamd_fuzzy_storage_ctx *ctx)
{
fuzzy_hash_t s;
gboolean res = FALSE;
#define CMD_PROCESS(x) \
do { \
-if (process_##x##_command (&session->cmd, session->worker->ctx)) { \
+if (process_##x##_command (&session->cmd, session->time, session->worker->ctx)) { \
if (sendto (session->fd, "OK" CRLF, sizeof ("OK" CRLF) - 1, 0, &session->client_addr.ss, session->salen) == -1) { \
msg_err ("error while writing reply: %s", strerror (errno)); \
} \
switch (session->cmd.cmd) {
case FUZZY_CHECK:
- r = process_check_command (&session->cmd, &flag, session->worker->ctx);
+ r = process_check_command (&session->cmd, &flag, session->time, session->worker->ctx);
if (r != 0) {
r = rspamd_snprintf (buf, sizeof (buf), "OK %d %d" CRLF, r, flag);
if (sendto (session->fd, buf, r, 0,
session.pos = (u_char *) & session.cmd;
session.salen = sizeof (session.client_addr);
session.ctx = worker->ctx;
+ session.time = (guint64)time (NULL);
/* Got some data */
if (what == EV_READ) {