summaryrefslogtreecommitdiffstats
path: root/src/libserver/symcache/symcache_c.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/libserver/symcache/symcache_c.cxx')
-rw-r--r--src/libserver/symcache/symcache_c.cxx715
1 files changed, 715 insertions, 0 deletions
diff --git a/src/libserver/symcache/symcache_c.cxx b/src/libserver/symcache/symcache_c.cxx
new file mode 100644
index 0000000..6a7e41c
--- /dev/null
+++ b/src/libserver/symcache/symcache_c.cxx
@@ -0,0 +1,715 @@
+/*
+ * Copyright 2023 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "symcache_internal.hxx"
+#include "symcache_periodic.hxx"
+#include "symcache_item.hxx"
+#include "symcache_runtime.hxx"
+
+/**
+ * C API for symcache
+ */
+
+#define C_API_SYMCACHE(ptr) (reinterpret_cast<rspamd::symcache::symcache *>(ptr))
+#define C_API_SYMCACHE_RUNTIME(ptr) (reinterpret_cast<rspamd::symcache::symcache_runtime *>(ptr))
+#define C_API_SYMCACHE_ITEM(ptr) (reinterpret_cast<rspamd::symcache::cache_item *>(ptr))
+#define C_API_SYMCACHE_DYN_ITEM(ptr) (reinterpret_cast<rspamd::symcache::cache_dynamic_item *>(ptr))
+
+void rspamd_symcache_destroy(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ delete real_cache;
+}
+
+struct rspamd_symcache *
+rspamd_symcache_new(struct rspamd_config *cfg)
+{
+ auto *ncache = new rspamd::symcache::symcache(cfg);
+
+ return (struct rspamd_symcache *) ncache;
+}
+
+gboolean
+rspamd_symcache_init(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ return real_cache->init();
+}
+
+void rspamd_symcache_save(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->save_items();
+}
+
+gint rspamd_symcache_add_symbol(struct rspamd_symcache *cache,
+ const gchar *name,
+ gint priority,
+ symbol_func_t func,
+ gpointer user_data,
+ int type,
+ gint parent)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ /* Legacy stuff */
+ if (name == nullptr) {
+ name = "";
+ }
+
+ if (parent == -1) {
+ return real_cache->add_symbol_with_callback(name, priority, func, user_data, type);
+ }
+ else {
+ return real_cache->add_virtual_symbol(name, parent, type);
+ }
+}
+
+bool rspamd_symcache_add_symbol_augmentation(struct rspamd_symcache *cache,
+ int sym_id,
+ const char *augmentation,
+ const char *value)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ auto log_tag = [&]() { return real_cache->log_tag(); };
+
+ if (augmentation == nullptr) {
+ msg_err_cache("null augmentation is not allowed for item %d", sym_id);
+ return false;
+ }
+
+
+ auto *item = real_cache->get_item_by_id_mut(sym_id, false);
+
+ if (item == nullptr) {
+ msg_err_cache("item %d is not found", sym_id);
+ return false;
+ }
+
+ /* Handle empty or absent strings equally */
+ if (value == nullptr || value[0] == '\0') {
+ return item->add_augmentation(*real_cache, augmentation, std::nullopt);
+ }
+
+ return item->add_augmentation(*real_cache, augmentation, value);
+}
+
+void rspamd_symcache_set_peak_callback(struct rspamd_symcache *cache, gint cbref)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->set_peak_cb(cbref);
+}
+
+gboolean
+rspamd_symcache_add_condition_delayed(struct rspamd_symcache *cache,
+ const gchar *sym, lua_State *L, gint cbref)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->add_delayed_condition(sym, cbref);
+
+ return TRUE;
+}
+
+gint rspamd_symcache_find_symbol(struct rspamd_symcache *cache,
+ const gchar *name)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ /* Legacy stuff but used */
+ if (name == nullptr) {
+ return -1;
+ }
+
+ auto sym_maybe = real_cache->get_item_by_name(name, false);
+
+ if (sym_maybe != nullptr) {
+ return sym_maybe->id;
+ }
+
+ return -1;
+}
+
+gboolean
+rspamd_symcache_stat_symbol(struct rspamd_symcache *cache,
+ const gchar *name,
+ gdouble *frequency,
+ gdouble *freq_stddev,
+ gdouble *tm,
+ guint *nhits)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto sym_maybe = real_cache->get_item_by_name(name, false);
+
+ if (sym_maybe != nullptr) {
+ *frequency = sym_maybe->st->avg_frequency;
+ *freq_stddev = sqrt(sym_maybe->st->stddev_frequency);
+ *tm = sym_maybe->st->time_counter.mean;
+
+ if (nhits) {
+ *nhits = sym_maybe->st->hits;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+guint rspamd_symcache_stats_symbols_count(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ return real_cache->get_stats_symbols_count();
+}
+
+guint64
+rspamd_symcache_get_cksum(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ return real_cache->get_cksum();
+}
+
+gboolean
+rspamd_symcache_validate(struct rspamd_symcache *cache,
+ struct rspamd_config *cfg,
+ gboolean strict)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ return real_cache->validate(strict);
+}
+
+ucl_object_t *
+rspamd_symcache_counters(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ return real_cache->counters();
+}
+
+void *
+rspamd_symcache_start_refresh(struct rspamd_symcache *cache,
+ struct ev_loop *ev_base, struct rspamd_worker *w)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ return new rspamd::symcache::cache_refresh_cbdata{real_cache, ev_base, w};
+}
+
+void rspamd_symcache_inc_frequency(struct rspamd_symcache *cache, struct rspamd_symcache_item *item,
+ const char *sym_name)
+{
+ auto *real_item = C_API_SYMCACHE_ITEM(item);
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (real_item) {
+ real_item->inc_frequency(sym_name, *real_cache);
+ }
+}
+
+void rspamd_symcache_add_delayed_dependency(struct rspamd_symcache *cache,
+ const gchar *from, const gchar *to)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ real_cache->add_delayed_dependency(from, to);
+}
+
+const gchar *
+rspamd_symcache_get_parent(struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto *sym = real_cache->get_item_by_name(symbol, false);
+
+ if (sym && sym->is_virtual()) {
+ auto *parent = sym->get_parent(*real_cache);
+
+ if (parent) {
+ return parent->get_name().c_str();
+ }
+ }
+
+ return nullptr;
+}
+
+const gchar *
+rspamd_symcache_item_name(struct rspamd_symcache_item *item)
+{
+ auto *real_item = C_API_SYMCACHE_ITEM(item);
+
+ if (real_item == nullptr) {
+ return nullptr;
+ }
+
+ return real_item->get_name().c_str();
+}
+
+gint rspamd_symcache_item_flags(struct rspamd_symcache_item *item)
+{
+ auto *real_item = C_API_SYMCACHE_ITEM(item);
+
+ if (real_item == nullptr) {
+ return 0;
+ }
+
+ return real_item->get_flags();
+}
+
+
+const gchar *
+rspamd_symcache_dyn_item_name(struct rspamd_task *task,
+ struct rspamd_symcache_dynamic_item *dyn_item)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_dyn_item = C_API_SYMCACHE_DYN_ITEM(dyn_item);
+
+ if (cache_runtime == nullptr || real_dyn_item == nullptr) {
+ return nullptr;
+ }
+
+ auto static_item = cache_runtime->get_item_by_dynamic_item(real_dyn_item);
+
+ return static_item->get_name().c_str();
+}
+
+gint rspamd_symcache_item_flags(struct rspamd_task *task,
+ struct rspamd_symcache_dynamic_item *dyn_item)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_dyn_item = C_API_SYMCACHE_DYN_ITEM(dyn_item);
+
+ if (cache_runtime == nullptr || real_dyn_item == nullptr) {
+ return 0;
+ }
+
+ auto static_item = cache_runtime->get_item_by_dynamic_item(real_dyn_item);
+
+ return static_item->get_flags();
+}
+
+guint rspamd_symcache_get_symbol_flags(struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto *sym = real_cache->get_item_by_name(symbol, false);
+
+ if (sym) {
+ return sym->get_flags();
+ }
+
+ return 0;
+}
+
+const struct rspamd_symcache_item_stat *
+rspamd_symcache_item_stat(struct rspamd_symcache_item *item)
+{
+ auto *real_item = C_API_SYMCACHE_ITEM(item);
+ return real_item->st;
+}
+
+void rspamd_symcache_get_symbol_details(struct rspamd_symcache *cache,
+ const gchar *symbol,
+ ucl_object_t *this_sym_ucl)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto *sym = real_cache->get_item_by_name(symbol, false);
+
+ if (sym) {
+ ucl_object_insert_key(this_sym_ucl,
+ ucl_object_fromstring(sym->get_type_str()),
+ "type", strlen("type"), false);
+ }
+}
+
+void rspamd_symcache_foreach(struct rspamd_symcache *cache,
+ void (*func)(struct rspamd_symcache_item *item, gpointer /* userdata */),
+ gpointer ud)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->symbols_foreach([&](const rspamd::symcache::cache_item *item) {
+ func((struct rspamd_symcache_item *) item, ud);
+ });
+}
+
+void rspamd_symcache_process_settings_elt(struct rspamd_symcache *cache,
+ struct rspamd_config_settings_elt *elt)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->process_settings_elt(elt);
+}
+
+bool rspamd_symcache_set_allowed_settings_ids(struct rspamd_symcache *cache,
+ const gchar *symbol,
+ const guint32 *ids,
+ guint nids)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto *item = real_cache->get_item_by_name_mut(symbol, false);
+
+ if (item == nullptr) {
+ return false;
+ }
+
+ item->allowed_ids.set_ids(ids, nids);
+ return true;
+}
+
+bool rspamd_symcache_set_forbidden_settings_ids(struct rspamd_symcache *cache,
+ const gchar *symbol,
+ const guint32 *ids,
+ guint nids)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto *item = real_cache->get_item_by_name_mut(symbol, false);
+
+ if (item == nullptr) {
+ return false;
+ }
+
+ item->forbidden_ids.set_ids(ids, nids);
+ return true;
+}
+
+const guint32 *
+rspamd_symcache_get_allowed_settings_ids(struct rspamd_symcache *cache,
+ const gchar *symbol,
+ guint *nids)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ const auto *item = real_cache->get_item_by_name(symbol, false);
+ return item->allowed_ids.get_ids(*nids);
+}
+
+const guint32 *
+rspamd_symcache_get_forbidden_settings_ids(struct rspamd_symcache *cache,
+ const gchar *symbol,
+ guint *nids)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ const auto *item = real_cache->get_item_by_name(symbol, false);
+ return item->forbidden_ids.get_ids(*nids);
+}
+
+void rspamd_symcache_disable_all_symbols(struct rspamd_task *task,
+ struct rspamd_symcache *_cache,
+ guint skip_mask)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+
+ cache_runtime->disable_all_symbols(skip_mask);
+}
+
+gboolean
+rspamd_symcache_disable_symbol(struct rspamd_task *task,
+ struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (cache_runtime == nullptr) {
+ return FALSE;
+ }
+
+ return cache_runtime->disable_symbol(task, *real_cache, symbol);
+}
+
+gboolean
+rspamd_symcache_enable_symbol(struct rspamd_task *task,
+ struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (cache_runtime == nullptr) {
+ return FALSE;
+ }
+
+ return cache_runtime->enable_symbol(task, *real_cache, symbol);
+}
+
+void rspamd_symcache_disable_symbol_static(struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->disable_symbol_delayed(symbol);
+}
+
+void rspamd_symcache_enable_symbol_static(struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ real_cache->enable_symbol_delayed(symbol);
+}
+
+/* A real structure to match C results without extra copying */
+struct rspamd_symcache_real_timeout_result {
+ struct rspamd_symcache_timeout_result c_api_result;
+ std::vector<std::pair<double, const rspamd::symcache::cache_item *>> elts;
+};
+
+struct rspamd_symcache_timeout_result *
+rspamd_symcache_get_max_timeout(struct rspamd_symcache *cache)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ auto *res = new rspamd_symcache_real_timeout_result;
+
+ res->c_api_result.max_timeout = real_cache->get_max_timeout(res->elts);
+ res->c_api_result.items = reinterpret_cast<struct rspamd_symcache_timeout_item *>(res->elts.data());
+ res->c_api_result.nitems = res->elts.size();
+
+ return &res->c_api_result;
+}
+
+void rspamd_symcache_timeout_result_free(struct rspamd_symcache_timeout_result *res)
+{
+ auto *real_result = reinterpret_cast<rspamd_symcache_real_timeout_result *>(res);
+ delete real_result;
+}
+
+gboolean
+rspamd_symcache_is_checked(struct rspamd_task *task,
+ struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (cache_runtime == nullptr) {
+ return FALSE;
+ }
+
+ return cache_runtime->is_symbol_checked(*real_cache, symbol);
+}
+
+gboolean
+rspamd_symcache_process_settings(struct rspamd_task *task,
+ struct rspamd_symcache *cache)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (cache_runtime == nullptr) {
+ return FALSE;
+ }
+
+ return cache_runtime->process_settings(task, *real_cache);
+}
+
+gboolean
+rspamd_symcache_is_item_allowed(struct rspamd_task *task,
+ struct rspamd_symcache_item *item,
+ gboolean exec_only)
+{
+ auto *real_item = C_API_SYMCACHE_ITEM(item);
+
+ if (real_item == nullptr) {
+ return TRUE;
+ }
+
+ return real_item->is_allowed(task, exec_only);
+}
+
+gboolean
+rspamd_symcache_is_symbol_enabled(struct rspamd_task *task,
+ struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (!cache_runtime) {
+ return TRUE;
+ }
+
+ return cache_runtime->is_symbol_enabled(task, *real_cache, symbol);
+}
+
+struct rspamd_symcache_dynamic_item *
+rspamd_symcache_get_cur_item(struct rspamd_task *task)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+
+ if (!cache_runtime) {
+ return nullptr;
+ }
+
+ return (struct rspamd_symcache_dynamic_item *) cache_runtime->get_cur_item();
+}
+
+struct rspamd_symcache_dynamic_item *
+rspamd_symcache_set_cur_item(struct rspamd_task *task, struct rspamd_symcache_dynamic_item *item)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_dyn_item = C_API_SYMCACHE_DYN_ITEM(item);
+
+ if (!cache_runtime || !real_dyn_item) {
+ return nullptr;
+ }
+
+ return (struct rspamd_symcache_dynamic_item *) cache_runtime->set_cur_item(real_dyn_item);
+}
+
+void rspamd_symcache_enable_profile(struct rspamd_task *task)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ if (!cache_runtime) {
+ return;
+ }
+
+ cache_runtime->set_profile_mode(true);
+}
+
+guint rspamd_symcache_item_async_inc_full(struct rspamd_task *task,
+ struct rspamd_symcache_dynamic_item *item,
+ const gchar *subsystem,
+ const gchar *loc)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_dyn_item = C_API_SYMCACHE_DYN_ITEM(item);
+
+ auto *static_item = cache_runtime->get_item_by_dynamic_item(real_dyn_item);
+ msg_debug_cache_task("increase async events counter for %s(%d) = %d + 1; "
+ "subsystem %s (%s)",
+ static_item->symbol.c_str(), static_item->id,
+ real_dyn_item->async_events, subsystem, loc);
+
+ return ++real_dyn_item->async_events;
+}
+
+guint rspamd_symcache_item_async_dec_full(struct rspamd_task *task,
+ struct rspamd_symcache_dynamic_item *item,
+ const gchar *subsystem,
+ const gchar *loc)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_dyn_item = C_API_SYMCACHE_DYN_ITEM(item);
+
+ auto *static_item = cache_runtime->get_item_by_dynamic_item(real_dyn_item);
+ msg_debug_cache_task("decrease async events counter for %s(%d) = %d - 1; "
+ "subsystem %s (%s)",
+ static_item->symbol.c_str(), static_item->id,
+ real_dyn_item->async_events, subsystem, loc);
+
+ if (G_UNLIKELY(real_dyn_item->async_events == 0)) {
+ msg_err_cache_task("INTERNAL ERROR: trying decrease async events counter for %s(%d) that is already zero; "
+ "subsystem %s (%s)",
+ static_item->symbol.c_str(), static_item->id,
+ real_dyn_item->async_events, subsystem, loc);
+ g_abort();
+ g_assert_not_reached();
+ }
+
+ return --real_dyn_item->async_events;
+}
+
+gboolean
+rspamd_symcache_item_async_dec_check_full(struct rspamd_task *task,
+ struct rspamd_symcache_dynamic_item *item,
+ const gchar *subsystem,
+ const gchar *loc)
+{
+ if (rspamd_symcache_item_async_dec_full(task, item, subsystem, loc) == 0) {
+ rspamd_symcache_finalize_item(task, item);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+struct rspamd_abstract_callback_data *
+rspamd_symcache_get_cbdata(struct rspamd_symcache *cache,
+ const gchar *symbol)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ auto *item = real_cache->get_item_by_name(symbol, true);
+
+ if (item) {
+ return (struct rspamd_abstract_callback_data *) item->get_cbdata();
+ }
+
+ return nullptr;
+}
+
+void rspamd_symcache_composites_foreach(struct rspamd_task *task,
+ struct rspamd_symcache *cache,
+ GHFunc func,
+ gpointer fd)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+
+ real_cache->composites_foreach([&](const auto *item) {
+ auto *dyn_item = cache_runtime->get_dynamic_item(item->id);
+
+ if (dyn_item && !dyn_item->started) {
+ auto *old_item = cache_runtime->set_cur_item(dyn_item);
+ func((void *) item->get_name().c_str(), item->get_cbdata(), fd);
+ dyn_item->finished = true;
+ cache_runtime->set_cur_item(old_item);
+ }
+ });
+
+ cache_runtime->set_cur_item(nullptr);
+}
+
+gboolean
+rspamd_symcache_process_symbols(struct rspamd_task *task,
+ struct rspamd_symcache *cache,
+ guint stage)
+{
+ auto *real_cache = C_API_SYMCACHE(cache);
+
+ if (task->symcache_runtime == nullptr) {
+ task->symcache_runtime = rspamd::symcache::symcache_runtime::create(task, *real_cache);
+ }
+
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ return cache_runtime->process_symbols(task, *real_cache, stage);
+}
+
+void rspamd_symcache_finalize_item(struct rspamd_task *task,
+ struct rspamd_symcache_dynamic_item *item)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ auto *real_dyn_item = C_API_SYMCACHE_DYN_ITEM(item);
+
+ cache_runtime->finalize_item(task, real_dyn_item);
+}
+
+void rspamd_symcache_runtime_destroy(struct rspamd_task *task)
+{
+ auto *cache_runtime = C_API_SYMCACHE_RUNTIME(task->symcache_runtime);
+ cache_runtime->savepoint_dtor();
+} \ No newline at end of file