summaryrefslogtreecommitdiffstats
path: root/src/libserver/symbols_cache.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2014-04-21 16:25:51 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2014-04-21 16:25:51 +0100
commit61555065f3d1c8badcc9573691232f1b6e42988c (patch)
tree563d5b7cb8c468530f7e79c4da0a75267b1184e1 /src/libserver/symbols_cache.c
parentad5bf825b7f33bc10311673991f0cc888e69c0b1 (diff)
downloadrspamd-61555065f3d1c8badcc9573691232f1b6e42988c.tar.gz
rspamd-61555065f3d1c8badcc9573691232f1b6e42988c.zip
Rework project structure, remove trash files.
Diffstat (limited to 'src/libserver/symbols_cache.c')
-rw-r--r--src/libserver/symbols_cache.c1055
1 files changed, 1055 insertions, 0 deletions
diff --git a/src/libserver/symbols_cache.c b/src/libserver/symbols_cache.c
new file mode 100644
index 000000000..dfca57c66
--- /dev/null
+++ b/src/libserver/symbols_cache.c
@@ -0,0 +1,1055 @@
+/*
+ * Copyright (c) 2009-2012, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "util.h"
+#include "main.h"
+#include "message.h"
+#include "symbols_cache.h"
+#include "cfg_file.h"
+
+#define WEIGHT_MULT 4.0
+#define FREQUENCY_MULT 10.0
+#define TIME_MULT -1.0
+
+/* After which number of messages try to resort cache */
+#define MAX_USES 100
+/*
+ * Symbols cache utility functions
+ */
+
+#define MIN_CACHE 17
+
+static guint64 total_frequency = 0;
+static guint32 nsymbols = 0;
+
+gint
+cache_cmp (const void *p1, const void *p2)
+{
+ const struct cache_item *i1 = p1, *i2 = p2;
+
+ return strcmp (i1->s->symbol, i2->s->symbol);
+}
+
+gint
+cache_logic_cmp (const void *p1, const void *p2)
+{
+ const struct cache_item *i1 = p1, *i2 = p2;
+ double w1, w2;
+ double weight1, weight2;
+ double f1 = 0, f2 = 0;
+
+ if (i1->priority == 0 && i2->priority == 0) {
+ if (total_frequency > 0) {
+ f1 = ((double)i1->s->frequency * nsymbols) / (double)total_frequency;
+ f2 = ((double)i2->s->frequency * nsymbols) / (double)total_frequency;
+ }
+ weight1 = i1->metric_weight == 0 ? i1->s->weight : i1->metric_weight;
+ weight2 = i2->metric_weight == 0 ? i2->s->weight : i2->metric_weight;
+ w1 = abs (weight1) * WEIGHT_MULT + f1 * FREQUENCY_MULT + i1->s->avg_time * TIME_MULT;
+ w2 = abs (weight2) * WEIGHT_MULT + f2 * FREQUENCY_MULT + i2->s->avg_time * TIME_MULT;
+ }
+ else {
+ /* Strict sorting */
+ w1 = abs (i1->priority);
+ w2 = abs (i2->priority);
+ }
+
+ return (gint)w2 - w1;
+}
+
+static GChecksum *
+get_mem_cksum (struct symbols_cache *cache)
+{
+ GChecksum *result;
+ GList *cur, *l;
+ struct cache_item *item;
+
+ result = g_checksum_new (G_CHECKSUM_SHA1);
+
+ l = g_list_copy (cache->negative_items);
+ l = g_list_sort (l, cache_cmp);
+ cur = g_list_first (l);
+ while (cur) {
+ item = cur->data;
+ if (item->s->symbol[0] != '\0') {
+ g_checksum_update (result, item->s->symbol, strlen (item->s->symbol));
+ }
+ cur = g_list_next (cur);
+ }
+ g_list_free (l);
+
+
+ l = g_list_copy (cache->static_items);
+ l = g_list_sort (l, cache_cmp);
+ cur = g_list_first (l);
+ while (cur) {
+ item = cur->data;
+ if (item->s->symbol[0] != '\0') {
+ g_checksum_update (result, item->s->symbol, strlen (item->s->symbol));
+ }
+ total_frequency += item->s->frequency;
+ cur = g_list_next (cur);
+ }
+ g_list_free (l);
+
+ return result;
+}
+
+/* Sort items in logical order */
+static void
+post_cache_init (struct symbols_cache *cache)
+{
+ GList *cur;
+ struct cache_item *item;
+
+ total_frequency = 0;
+ nsymbols = cache->used_items;
+ cur = g_list_first (cache->negative_items);
+ while (cur) {
+ item = cur->data;
+ total_frequency += item->s->frequency;
+ cur = g_list_next (cur);
+ }
+ cur = g_list_first (cache->static_items);
+ while (cur) {
+ item = cur->data;
+ total_frequency += item->s->frequency;
+ cur = g_list_next (cur);
+ }
+
+ cache->negative_items = g_list_sort (cache->negative_items, cache_logic_cmp);
+ cache->static_items = g_list_sort (cache->static_items, cache_logic_cmp);
+}
+
+/* Unmap cache file */
+static void
+unmap_cache_file (gpointer arg)
+{
+ struct symbols_cache *cache = arg;
+
+ /* A bit ugly usage */
+ munmap (cache->map, cache->used_items * sizeof (struct saved_cache_item));
+}
+
+static gboolean
+mmap_cache_file (struct symbols_cache *cache, gint fd, rspamd_mempool_t *pool)
+{
+ guint8 *map;
+ gint i;
+ GList *cur;
+ struct cache_item *item;
+
+ if (cache->used_items > 0) {
+ map = mmap (NULL, cache->used_items * sizeof (struct saved_cache_item), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) {
+ msg_err ("cannot mmap cache file: %d, %s", errno, strerror (errno));
+ close (fd);
+ return FALSE;
+ }
+ /* Close descriptor as it would never be used */
+ close (fd);
+ cache->map = map;
+ /* Now free old values for saved cache items and fill them with mmapped ones */
+ i = 0;
+ cur = g_list_first (cache->negative_items);
+ while (cur) {
+ item = cur->data;
+ item->s = (struct saved_cache_item *)(map + i * sizeof (struct saved_cache_item));
+ cur = g_list_next (cur);
+ i ++;
+ }
+ cur = g_list_first (cache->static_items);
+ while (cur) {
+ item = cur->data;
+ item->s = (struct saved_cache_item *)(map + i * sizeof (struct saved_cache_item));
+ cur = g_list_next (cur);
+ i ++;
+ }
+
+ post_cache_init (cache);
+ }
+
+ return TRUE;
+}
+
+/* Fd must be opened for writing, after creating file is mmapped */
+static gboolean
+create_cache_file (struct symbols_cache *cache, const gchar *filename, gint fd, rspamd_mempool_t *pool)
+{
+ GChecksum *cksum;
+ u_char *digest;
+ gsize cklen;
+ GList *cur;
+ struct cache_item *item;
+
+ /* Calculate checksum */
+ cksum = get_mem_cksum (cache);
+ if (cksum == NULL) {
+ msg_err ("cannot calculate checksum for symbols");
+ close (fd);
+ return FALSE;
+ }
+
+ cklen = g_checksum_type_get_length (G_CHECKSUM_SHA1);
+ digest = g_malloc (cklen);
+
+ g_checksum_get_digest (cksum, digest, &cklen);
+ /* Now write data to file */
+ cur = g_list_first (cache->negative_items);
+ while (cur) {
+ item = cur->data;
+ if (write (fd, item->s, sizeof (struct saved_cache_item)) == -1) {
+ msg_err ("cannot write to file %d, %s", errno, strerror (errno));
+ close (fd);
+ g_checksum_free (cksum);
+ g_free (digest);
+ return FALSE;
+ }
+ cur = g_list_next (cur);
+ }
+ cur = g_list_first (cache->static_items);
+ while (cur) {
+ item = cur->data;
+ if (write (fd, item->s, sizeof (struct saved_cache_item)) == -1) {
+ msg_err ("cannot write to file %d, %s", errno, strerror (errno));
+ close (fd);
+ g_checksum_free (cksum);
+ g_free (digest);
+ return FALSE;
+ }
+ cur = g_list_next (cur);
+ }
+ /* Write checksum */
+ if (write (fd, digest, cklen) == -1) {
+ msg_err ("cannot write to file %d, %s", errno, strerror (errno));
+ close (fd);
+ g_checksum_free (cksum);
+ g_free (digest);
+ return FALSE;
+ }
+
+ close (fd);
+ g_checksum_free (cksum);
+ g_free (digest);
+ /* Reopen for reading */
+ if ((fd = open (filename, O_RDWR)) == -1) {
+ msg_info ("cannot open file %s, error %d, %s", errno, strerror (errno));
+ return FALSE;
+ }
+
+ return mmap_cache_file (cache, fd, pool);
+}
+
+enum rspamd_symbol_type {
+ SYMBOL_TYPE_NORMAL,
+ SYMBOL_TYPE_VIRTUAL,
+ SYMBOL_TYPE_CALLBACK
+};
+
+static void
+register_symbol_common (struct symbols_cache **cache, const gchar *name, double weight, gint priority,
+ symbol_func_t func, gpointer user_data, enum rspamd_symbol_type type)
+{
+ struct cache_item *item = NULL;
+ struct symbols_cache *pcache = *cache;
+ GList **target;
+ double *w;
+
+ if (*cache == NULL) {
+ pcache = g_new0 (struct symbols_cache, 1);
+ *cache = pcache;
+ pcache->static_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
+ pcache->items_by_symbol = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
+ }
+
+ item = rspamd_mempool_alloc0 (pcache->static_pool, sizeof (struct cache_item));
+ item->s = rspamd_mempool_alloc0 (pcache->static_pool, sizeof (struct saved_cache_item));
+ rspamd_strlcpy (item->s->symbol, name, sizeof (item->s->symbol));
+ item->func = func;
+ item->user_data = user_data;
+ item->priority = priority;
+
+ switch (type) {
+ case SYMBOL_TYPE_NORMAL:
+ break;
+ case SYMBOL_TYPE_VIRTUAL:
+ item->is_virtual = TRUE;
+ break;
+ case SYMBOL_TYPE_CALLBACK:
+ item->is_callback = TRUE;
+ break;
+ }
+
+ /* Handle weight using default metric */
+ if (pcache->cfg && pcache->cfg->default_metric && (w = g_hash_table_lookup (pcache->cfg->default_metric->symbols, name)) != NULL) {
+ item->s->weight = weight * (*w);
+ }
+ else {
+ item->s->weight = weight;
+ }
+
+ /* If we have undefined priority determine list according to weight */
+ if (priority == 0) {
+ if (item->s->weight > 0) {
+ target = &(*cache)->static_items;
+ }
+ else {
+ target = &(*cache)->negative_items;
+ }
+ }
+ else {
+ /* Items with more priority are called before items with less priority */
+ if (priority < 0) {
+ target = &(*cache)->negative_items;
+ }
+ else {
+ target = &(*cache)->static_items;
+ }
+ }
+
+ pcache->used_items++;
+ g_hash_table_insert (pcache->items_by_symbol, item->s->symbol, item);
+ msg_debug ("used items: %d, added symbol: %s", (*cache)->used_items, name);
+ set_counter (item->s->symbol, 0);
+
+ *target = g_list_prepend (*target, item);
+}
+
+void
+register_symbol (struct symbols_cache **cache, const gchar *name, double weight,
+ symbol_func_t func, gpointer user_data)
+{
+ register_symbol_common (cache, name, weight, 0, func, user_data, SYMBOL_TYPE_NORMAL);
+}
+
+void
+register_virtual_symbol (struct symbols_cache **cache, const gchar *name, double weight)
+{
+ register_symbol_common (cache, name, weight, 0, NULL, NULL, SYMBOL_TYPE_VIRTUAL);
+}
+
+void
+register_callback_symbol (struct symbols_cache **cache, const gchar *name, double weight,
+ symbol_func_t func, gpointer user_data)
+{
+ register_symbol_common (cache, name, weight, 0, func, user_data, SYMBOL_TYPE_CALLBACK);
+}
+
+void
+register_callback_symbol_priority (struct symbols_cache **cache, const gchar *name, double weight, gint priority,
+ symbol_func_t func, gpointer user_data)
+{
+ register_symbol_common (cache, name, weight, priority, func, user_data, SYMBOL_TYPE_CALLBACK);
+}
+
+void
+register_dynamic_symbol (rspamd_mempool_t *dynamic_pool, struct symbols_cache **cache,
+ const gchar *name, double weight, symbol_func_t func,
+ gpointer user_data, GList *networks)
+{
+ struct cache_item *item = NULL;
+ struct symbols_cache *pcache = *cache;
+ GList *t, *cur;
+ uintptr_t r;
+ double *w;
+ guint32 mask = 0xFFFFFFFF;
+ struct dynamic_map_item *it;
+ gint rr;
+
+ if (*cache == NULL) {
+ pcache = g_new0 (struct symbols_cache, 1);
+ *cache = pcache;
+ pcache->static_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
+ }
+
+ item = rspamd_mempool_alloc0 (dynamic_pool, sizeof (struct cache_item));
+ item->s = rspamd_mempool_alloc (dynamic_pool, sizeof (struct saved_cache_item));
+ rspamd_strlcpy (item->s->symbol, name, sizeof (item->s->symbol));
+ item->func = func;
+ item->user_data = user_data;
+ /* Handle weight using default metric */
+ if (pcache->cfg && pcache->cfg->default_metric && (w = g_hash_table_lookup (pcache->cfg->default_metric->symbols, name)) != NULL) {
+ item->s->weight = weight * (*w);
+ }
+ else {
+ item->s->weight = weight;
+ }
+ item->is_dynamic = TRUE;
+ item->priority = 0;
+
+ pcache->used_items++;
+ msg_debug ("used items: %d, added symbol: %s", (*cache)->used_items, name);
+ set_counter (item->s->symbol, 0);
+
+ g_hash_table_insert (pcache->items_by_symbol, item->s->symbol, item);
+
+ if (networks == NULL) {
+ pcache->dynamic_items = g_list_prepend (pcache->dynamic_items, item);
+ }
+ else {
+ if (pcache->dynamic_map == NULL) {
+ pcache->dynamic_map = radix_tree_create ();
+ pcache->negative_dynamic_map = radix_tree_create ();
+ }
+ cur = networks;
+ while (cur) {
+ it = cur->data;
+ mask = mask << (32 - it->mask);
+ r = ntohl (it->addr.s_addr & mask);
+ if (it->negative) {
+ /* For negatve items insert into list and into negative cache map */
+ if ((r = radix32tree_find (pcache->negative_dynamic_map, r)) != RADIX_NO_VALUE) {
+ t = (GList *)((gpointer)r);
+ t = g_list_prepend (t, item);
+ /* Replace pointers in radix tree and in destructor function */
+ rspamd_mempool_replace_destructor (dynamic_pool, (rspamd_mempool_destruct_t)g_list_free, (gpointer)r, t);
+ rr = radix32tree_replace (pcache->negative_dynamic_map, ntohl (it->addr.s_addr), mask, (uintptr_t)t);
+ if (rr == -1) {
+ msg_warn ("cannot replace ip to tree: %s, mask %X", inet_ntoa (it->addr), mask);
+ }
+ }
+ else {
+ t = g_list_prepend (NULL, item);
+ rspamd_mempool_add_destructor (dynamic_pool, (rspamd_mempool_destruct_t)g_list_free, t);
+ rr = radix32tree_insert (pcache->negative_dynamic_map, ntohl (it->addr.s_addr), mask, (uintptr_t)t);
+ if (rr == -1) {
+ msg_warn ("cannot insert ip to tree: %s, mask %X", inet_ntoa (it->addr), mask);
+ }
+ else if (rr == 1) {
+ msg_warn ("ip %s, mask %X, value already exists", inet_ntoa (it->addr), mask);
+ }
+ }
+ /* Insert into list */
+ pcache->dynamic_items = g_list_prepend (pcache->dynamic_items, item);
+ }
+ else {
+ if ((r = radix32tree_find (pcache->dynamic_map, r)) != RADIX_NO_VALUE) {
+ t = (GList *)((gpointer)r);
+ t = g_list_prepend (t, item);
+ /* Replace pointers in radix tree and in destructor function */
+ rspamd_mempool_replace_destructor (dynamic_pool, (rspamd_mempool_destruct_t)g_list_free, (gpointer)r, t);
+ rr = radix32tree_replace (pcache->dynamic_map, ntohl (it->addr.s_addr), mask, (uintptr_t)t);
+ if (rr == -1) {
+ msg_warn ("cannot replace ip to tree: %s, mask %X", inet_ntoa (it->addr), mask);
+ }
+ }
+ else {
+ t = g_list_prepend (NULL, item);
+ rspamd_mempool_add_destructor (dynamic_pool, (rspamd_mempool_destruct_t)g_list_free, t);
+ rr = radix32tree_insert (pcache->dynamic_map, ntohl (it->addr.s_addr), mask, (uintptr_t)t);
+ if (rr == -1) {
+ msg_warn ("cannot insert ip to tree: %s, mask %X", inet_ntoa (it->addr), mask);
+ }
+ else if (rr == 1) {
+ msg_warn ("ip %s, mask %X, value already exists", inet_ntoa (it->addr), mask);
+ }
+ }
+ }
+ cur = g_list_next (cur);
+ }
+ }
+}
+
+void
+remove_dynamic_rules (struct symbols_cache *cache)
+{
+ if (cache->dynamic_items) {
+ g_list_free (cache->dynamic_items);
+ cache->dynamic_items = NULL;
+ }
+
+ if (cache->dynamic_map) {
+ radix_tree_free (cache->dynamic_map);
+ cache->dynamic_map = NULL;
+ }
+ if (cache->negative_dynamic_map) {
+ radix_tree_free (cache->negative_dynamic_map);
+ cache->negative_dynamic_map = NULL;
+ }
+}
+
+static void
+free_cache (gpointer arg)
+{
+ struct symbols_cache *cache = arg;
+
+ if (cache->map != NULL) {
+ unmap_cache_file (cache);
+ }
+
+ if (cache->static_items) {
+ g_list_free (cache->static_items);
+ }
+ if (cache->negative_items) {
+ g_list_free (cache->negative_items);
+ }
+ if (cache->dynamic_items) {
+ g_list_free (cache->dynamic_items);
+ }
+ if (cache->dynamic_map) {
+ radix_tree_free (cache->dynamic_map);
+ }
+ if (cache->negative_dynamic_map) {
+ radix_tree_free (cache->negative_dynamic_map);
+ }
+ g_hash_table_destroy (cache->items_by_symbol);
+ rspamd_mempool_delete (cache->static_pool);
+
+ g_free (cache);
+}
+
+gboolean
+init_symbols_cache (rspamd_mempool_t * pool, struct symbols_cache *cache, struct config_file *cfg,
+ const gchar *filename, gboolean ignore_checksum)
+{
+ struct stat st;
+ gint fd;
+ GChecksum *cksum;
+ u_char *mem_sum, *file_sum;
+ gsize cklen;
+ gboolean res;
+
+ if (cache == NULL) {
+ return FALSE;
+ }
+
+ /* Init locking */
+ cache->lock = rspamd_mempool_get_rwlock (pool);
+
+ cache->cfg = cfg;
+
+ /* Just in-memory cache */
+ if (filename == NULL) {
+ post_cache_init (cache);
+ return TRUE;
+ }
+
+ /* First of all try to stat file */
+ if (stat (filename, &st) == -1) {
+ /* Check errno */
+ if (errno == ENOENT) {
+ /* Try to create file */
+ if ((fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1) {
+ msg_info ("cannot create file %s, error %d, %s", filename, errno, strerror (errno));
+ return FALSE;
+ }
+ else {
+ return create_cache_file (cache, filename, fd, pool);
+ }
+ }
+ else {
+ msg_info ("cannot stat file %s, error %d, %s", filename, errno, strerror (errno));
+ return FALSE;
+ }
+ }
+ else {
+ if ((fd = open (filename, O_RDWR)) == -1) {
+ msg_info ("cannot open file %s, error %d, %s", filename, errno, strerror (errno));
+ return FALSE;
+ }
+ }
+
+ if (!ignore_checksum) {
+ /* Calculate checksum */
+ cksum = get_mem_cksum (cache);
+ if (cksum == NULL) {
+ msg_err ("cannot calculate checksum for symbols");
+ close (fd);
+ return FALSE;
+ }
+
+ cklen = g_checksum_type_get_length (G_CHECKSUM_SHA1);
+ mem_sum = g_malloc (cklen);
+
+ g_checksum_get_digest (cksum, mem_sum, &cklen);
+ /* Now try to read file sum */
+ if (lseek (fd, -(cklen), SEEK_END) == -1) {
+ if (errno == EINVAL) {
+ /* Try to create file */
+ msg_info ("recreate cache file");
+ if ((fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1) {
+ msg_info ("cannot create file %s, error %d, %s", filename, errno, strerror (errno));
+ return FALSE;
+ }
+ else {
+ return create_cache_file (cache, filename, fd, pool);
+ }
+ }
+ close (fd);
+ g_free (mem_sum);
+ g_checksum_free (cksum);
+ msg_err ("cannot seek to read checksum, %d, %s", errno, strerror (errno));
+ return FALSE;
+ }
+ file_sum = g_malloc (cklen);
+ if (read (fd, file_sum, cklen) == -1) {
+ close (fd);
+ g_free (mem_sum);
+ g_free (file_sum);
+ g_checksum_free (cksum);
+ msg_err ("cannot read checksum, %d, %s", errno, strerror (errno));
+ return FALSE;
+ }
+
+ if (memcmp (file_sum, mem_sum, cklen) != 0) {
+ close (fd);
+ g_free (mem_sum);
+ g_free (file_sum);
+ g_checksum_free (cksum);
+ msg_info ("checksum mismatch, recreating file");
+ /* Reopen with rw permissions */
+ if ((fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1) {
+ msg_info ("cannot create file %s, error %d, %s", filename, errno, strerror (errno));
+ return FALSE;
+ }
+ else {
+ return create_cache_file (cache, filename, fd, pool);
+ }
+ }
+
+ g_free (mem_sum);
+ g_free (file_sum);
+ g_checksum_free (cksum);
+ }
+ /* MMap cache file and copy saved_cache structures */
+ res = mmap_cache_file (cache, fd, pool);
+
+ rspamd_mempool_add_destructor (pool, (rspamd_mempool_destruct_t)free_cache, cache);
+
+ return res;
+}
+
+static GList *
+check_dynamic_item (struct rspamd_task *task, struct symbols_cache *cache)
+{
+#ifdef HAVE_INET_PTON
+ /* TODO: radix doesn't support ipv6 addrs */
+ return NULL;
+#else
+ GList *res = NULL;
+ uintptr_t r;
+ if (cache->dynamic_map != NULL && task->from_addr.s_addr != INADDR_NONE) {
+ if ((r = radix32tree_find (cache->dynamic_map, ntohl (task->from_addr.s_addr))) != RADIX_NO_VALUE) {
+ res = (GList *)((gpointer)r);
+ return res;
+ }
+ else {
+ return NULL;
+ }
+ }
+ return res;
+#endif
+}
+
+static gboolean
+check_negative_dynamic_item (struct rspamd_task *task, struct symbols_cache *cache, struct cache_item *item)
+{
+
+#ifdef HAVE_INET_PTON
+ /* TODO: radix doesn't support ipv6 addrs */
+ return FALSE;
+#else
+ GList *res = NULL;
+ uintptr_t r;
+
+ if (cache->negative_dynamic_map != NULL && task->from_addr.s_addr != INADDR_NONE) {
+ if ((r = radix32tree_find (cache->negative_dynamic_map, ntohl (task->from_addr.s_addr))) != RADIX_NO_VALUE) {
+ res = (GList *)((gpointer)r);
+ while (res) {
+ if (res->data == (gpointer)item) {
+ return TRUE;
+ }
+ res = g_list_next (res);
+ }
+ }
+ }
+ return FALSE;
+#endif
+
+}
+
+static gboolean
+check_debug_symbol (struct config_file *cfg, const gchar *symbol)
+{
+ GList *cur;
+
+ cur = cfg->debug_symbols;
+ while (cur) {
+ if (strcmp (symbol, (const gchar *)cur->data) == 0) {
+ return TRUE;
+ }
+ cur = g_list_next (cur);
+ }
+
+ return FALSE;
+}
+
+static void
+rspamd_symbols_cache_metric_cb (gpointer k, gpointer v, gpointer ud)
+{
+ struct symbols_cache *cache = (struct symbols_cache *)ud;
+ GList *cur;
+ const gchar *sym = k;
+ gdouble weight = *(gdouble *)v;
+ struct cache_item *item;
+
+ cur = cache->negative_items;
+ while (cur) {
+ item = cur->data;
+ if (strcmp (item->s->symbol, sym) == 0) {
+ item->metric_weight = weight;
+ return;
+ }
+ cur = g_list_next (cur);
+ }
+ cur = cache->static_items;
+ while (cur) {
+ item = cur->data;
+ if (strcmp (item->s->symbol, sym) == 0) {
+ item->metric_weight = weight;
+ return;
+ }
+ cur = g_list_next (cur);
+ }
+}
+
+gboolean
+validate_cache (struct symbols_cache *cache, struct config_file *cfg, gboolean strict)
+{
+ struct cache_item *item;
+ GList *cur, *p, *metric_symbols;
+ gboolean res;
+
+ if (cache == NULL) {
+ msg_err ("empty cache is invalid");
+ return FALSE;
+ }
+
+ /* Check each symbol in a cache and find its weight definition */
+ cur = cache->negative_items;
+ while (cur) {
+ item = cur->data;
+ if (!item->is_callback) {
+ if (g_hash_table_lookup (cfg->metrics_symbols, item->s->symbol) == NULL) {
+ if (strict) {
+ msg_warn ("no weight registered for symbol %s", item->s->symbol);
+ return FALSE;
+ }
+ else {
+ msg_info ("no weight registered for symbol %s", item->s->symbol);
+ }
+ }
+ }
+ cur = g_list_next (cur);
+ }
+ cur = cache->static_items;
+ while (cur) {
+ item = cur->data;
+ if (!item->is_callback) {
+ if (g_hash_table_lookup (cfg->metrics_symbols, item->s->symbol) == NULL) {
+ if (strict) {
+ msg_warn ("no weight registered for symbol %s", item->s->symbol);
+ return FALSE;
+ }
+ else {
+ msg_info ("no weight registered for symbol %s", item->s->symbol);
+ }
+ }
+ }
+ cur = g_list_next (cur);
+ }
+#ifndef GLIB_HASH_COMPAT
+ /* Now check each metric item and find corresponding symbol in a cache */
+ metric_symbols = g_hash_table_get_keys (cfg->metrics_symbols);
+ cur = metric_symbols;
+ while (cur) {
+ res = FALSE;
+ p = cache->negative_items;
+ while (p) {
+ item = p->data;
+ if (strcmp (item->s->symbol, cur->data) == 0) {
+ res = TRUE;
+ break;
+ }
+ p = g_list_next (p);
+ }
+ if (!res) {
+ p = cache->static_items;
+ while (p) {
+ item = p->data;
+ if (strcmp (item->s->symbol, cur->data) == 0) {
+ res = TRUE;
+ break;
+ }
+ p = g_list_next (p);
+ }
+ }
+ if (!res) {
+ msg_warn ("symbol '%s' is registered in metric but not found in cache", cur->data);
+ if (strict) {
+ return FALSE;
+ }
+ }
+ cur = g_list_next (cur);
+ }
+ g_list_free (metric_symbols);
+#endif /* GLIB_COMPAT */
+
+ /* Now adjust symbol weights according to default metric */
+ if (cfg->default_metric != NULL) {
+ g_hash_table_foreach (cfg->default_metric->symbols, rspamd_symbols_cache_metric_cb, cache);
+ /* Resort caches */
+ cache->negative_items = g_list_sort (cache->negative_items, cache_logic_cmp);
+ cache->static_items = g_list_sort (cache->static_items, cache_logic_cmp);
+ }
+
+ return TRUE;
+}
+
+struct symbol_callback_data {
+ enum {
+ CACHE_STATE_NEGATIVE,
+ CACHE_STATE_DYNAMIC_MAP,
+ CACHE_STATE_DYNAMIC,
+ CACHE_STATE_STATIC
+ } state;
+ struct cache_item *saved_item;
+ GList *list_pointer;
+};
+
+gboolean
+call_symbol_callback (struct rspamd_task * task, struct symbols_cache * cache, gpointer *save)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts1, ts2;
+#else
+ struct timeval tv1, tv2;
+#endif
+ guint64 diff;
+ struct cache_item *item = NULL;
+ struct symbol_callback_data *s = *save;
+
+ if (s == NULL) {
+ if (cache == NULL) {
+ return FALSE;
+ }
+ if (cache->uses++ >= MAX_USES) {
+ msg_info ("resort symbols cache");
+ rspamd_mempool_wlock_rwlock (cache->lock);
+ cache->uses = 0;
+ /* Resort while having write lock */
+ post_cache_init (cache);
+ rspamd_mempool_wunlock_rwlock (cache->lock);
+ }
+ s = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct symbol_callback_data));
+ *save = s;
+ if (cache->negative_items != NULL) {
+ s->list_pointer = g_list_first (cache->negative_items);
+ s->saved_item = s->list_pointer->data;
+ s->state = CACHE_STATE_NEGATIVE;
+ }
+ else if ((s->list_pointer = check_dynamic_item (task, cache)) || cache->dynamic_items != NULL) {
+ if (s->list_pointer == NULL) {
+ s->list_pointer = g_list_first (cache->dynamic_items);
+ s->saved_item = s->list_pointer->data;
+ s->state = CACHE_STATE_DYNAMIC;
+ }
+ else {
+ s->saved_item = s->list_pointer->data;
+ s->state = CACHE_STATE_DYNAMIC_MAP;
+ }
+ }
+ else {
+ s->state = CACHE_STATE_STATIC;
+ s->list_pointer = g_list_first (cache->static_items);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ item = s->saved_item;
+ }
+ else {
+ if (cache == NULL) {
+ return FALSE;
+ }
+ switch (s->state) {
+ case CACHE_STATE_NEGATIVE:
+ s->list_pointer = g_list_next (s->list_pointer);
+ if (s->list_pointer == NULL) {
+ if ((s->list_pointer = check_dynamic_item (task, cache)) || cache->dynamic_items != NULL) {
+ if (s->list_pointer == NULL) {
+ s->list_pointer = g_list_first (cache->dynamic_items);
+ s->saved_item = s->list_pointer->data;
+ s->state = CACHE_STATE_DYNAMIC;
+ }
+ else {
+ s->saved_item = s->list_pointer->data;
+ s->state = CACHE_STATE_DYNAMIC_MAP;
+ }
+ }
+ else {
+ s->state = CACHE_STATE_STATIC;
+ s->list_pointer = g_list_first (cache->static_items);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ }
+ else {
+ s->saved_item = s->list_pointer->data;
+ }
+ item = s->saved_item;
+ break;
+ case CACHE_STATE_DYNAMIC_MAP:
+ s->list_pointer = g_list_next (s->list_pointer);
+ if (s->list_pointer == NULL) {
+ s->list_pointer = g_list_first (cache->dynamic_items);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ s->state = CACHE_STATE_DYNAMIC;
+ }
+ else {
+ s->state = CACHE_STATE_STATIC;
+ s->list_pointer = g_list_first (cache->static_items);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ }
+ else {
+ s->saved_item = s->list_pointer->data;
+ }
+ item = s->saved_item;
+ break;
+ case CACHE_STATE_DYNAMIC:
+ s->list_pointer = g_list_next (s->list_pointer);
+ if (s->list_pointer == NULL) {
+ s->state = CACHE_STATE_STATIC;
+ s->list_pointer = g_list_first (cache->static_items);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ else {
+ s->saved_item = s->list_pointer->data;
+ /* Skip items that are in negative map */
+ while (s->list_pointer != NULL && check_negative_dynamic_item (task, cache, s->saved_item)) {
+ s->list_pointer = g_list_next (s->list_pointer);
+ if (s->list_pointer != NULL) {
+ s->saved_item = s->list_pointer->data;
+ }
+ }
+ if (s->list_pointer == NULL) {
+ s->state = CACHE_STATE_STATIC;
+ s->list_pointer = g_list_first (cache->static_items);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ }
+ item = s->saved_item;
+ break;
+ case CACHE_STATE_STATIC:
+ /* Next pointer */
+ s->list_pointer = g_list_next (s->list_pointer);
+ if (s->list_pointer) {
+ s->saved_item = s->list_pointer->data;
+ }
+ else {
+ return FALSE;
+ }
+ item = s->saved_item;
+ break;
+ }
+ }
+ if (!item) {
+ return FALSE;
+ }
+ if (!item->is_virtual) {
+#ifdef HAVE_CLOCK_GETTIME
+# ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
+ clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts1);
+# elif defined(HAVE_CLOCK_VIRTUAL)
+ clock_gettime (CLOCK_VIRTUAL, &ts1);
+# else
+ clock_gettime (CLOCK_REALTIME, &ts1);
+# endif
+#else
+ if (gettimeofday (&tv1, NULL) == -1) {
+ msg_warn ("gettimeofday failed: %s", strerror (errno));
+ }
+#endif
+ if (G_UNLIKELY (check_debug_symbol (task->cfg, item->s->symbol))) {
+ rspamd_log_debug (rspamd_main->logger);
+ item->func (task, item->user_data);
+ rspamd_log_nodebug (rspamd_main->logger);
+ }
+ else {
+ item->func (task, item->user_data);
+ }
+
+
+#ifdef HAVE_CLOCK_GETTIME
+# ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
+ clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts2);
+# elif defined(HAVE_CLOCK_VIRTUAL)
+ clock_gettime (CLOCK_VIRTUAL, &ts2);
+# else
+ clock_gettime (CLOCK_REALTIME, &ts2);
+# endif
+#else
+ if (gettimeofday (&tv2, NULL) == -1) {
+ msg_warn ("gettimeofday failed: %s", strerror (errno));
+ }
+#endif
+
+#ifdef HAVE_CLOCK_GETTIME
+ diff = (ts2.tv_sec - ts1.tv_sec) * 1000000 + (ts2.tv_nsec - ts1.tv_nsec) / 1000;
+#else
+ diff = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
+#endif
+ item->s->avg_time = set_counter (item->s->symbol, diff);
+ }
+
+ s->saved_item = item;
+
+ return TRUE;
+
+}
r-logging-28 Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
path: root/settings/l10n/ro.php
blob: f5227f15e266a8b242735bab5fa67bd712d8307b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102