commit fc3bfa4: [Project] Start C API implementation

Vsevolod Stakhov vsevolod at rspamd.com
Sat Oct 22 14:56:03 UTC 2022


Author: Vsevolod Stakhov
Date: 2022-10-22 14:55:52 +0100
URL: https://github.com/rspamd/rspamd/commit/fc3bfa4f62f6296e7ada58a74e0eaefa1c5a737b

[Project] Start C API implementation

---
 src/libserver/hyperscan_tools.cxx | 75 +++++++++++++++++++++++++++++++++++++--
 src/libserver/hyperscan_tools.h   | 54 ++++++++++++++++++++++++++++
 2 files changed, 127 insertions(+), 2 deletions(-)

diff --git a/src/libserver/hyperscan_tools.cxx b/src/libserver/hyperscan_tools.cxx
index 1272aa452..309f821dd 100644
--- a/src/libserver/hyperscan_tools.cxx
+++ b/src/libserver/hyperscan_tools.cxx
@@ -25,6 +25,7 @@
 #include "hs.h"
 #include "logger.h"
 #include "worker_util.h"
+#include "hyperscan_tools.h"
 
 #include <glob.h> /* for glob */
 #include <unistd.h> /* for unlink */
@@ -35,7 +36,10 @@
         "hyperscan", "", \
         RSPAMD_LOG_FUNC, \
         __VA_ARGS__)
-
+#define msg_err_hyperscan(...)   rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
+        "hyperscan", "", \
+        RSPAMD_LOG_FUNC, \
+        __VA_ARGS__)
 #define msg_debug_hyperscan(...)  rspamd_conditional_debug_fast (NULL, NULL, \
         rspamd_hyperscan_log_id, "hyperscan", "", \
         RSPAMD_LOG_FUNC, \
@@ -45,6 +49,12 @@ INIT_LOG_MODULE_PUBLIC(hyperscan)
 
 namespace rspamd::util {
 
+/*
+ * A singleton class that is responsible for deletion of the outdated hyperscan files
+ * One issue is that it must know about HS files in all workers, which is a problem
+ * TODO: we need to export hyperscan caches from all workers to a single place where
+ * we can clean them up (probably, to the main process)
+ */
 class hs_known_files_cache {
 private:
 	// These fields are filled when we add new known cache files
@@ -136,7 +146,7 @@ public:
  * This is a higher level representation of the cached hyperscan file
  */
 struct hs_shared_database {
-	hs_database_t *db; /**< internal database (might be in a shared memory) */
+	hs_database_t *db = nullptr; /**< internal database (might be in a shared memory) */
 	std::optional<raii_mmaped_file> maybe_map;
 
 	~hs_shared_database() {
@@ -148,6 +158,16 @@ struct hs_shared_database {
 
 	explicit hs_shared_database(raii_mmaped_file &&map, hs_database_t *db) : db(db), maybe_map(std::move(map)) {}
 	explicit hs_shared_database(hs_database_t *db) : db(db), maybe_map(std::nullopt) {}
+	hs_shared_database(const hs_shared_database &other) = delete;
+	hs_shared_database() = default;
+	hs_shared_database(hs_shared_database &&other) noexcept {
+		*this = std::move(other);
+	}
+	hs_shared_database& operator=(hs_shared_database &&other) noexcept {
+		std::swap(db, other.db);
+		std::swap(maybe_map, other.maybe_map);
+		return *this;
+	}
 };
 
 static auto
@@ -286,5 +306,56 @@ auto load_cached_hs_file(const char *fname) -> tl::expected<hs_shared_database,
 }
 } // namespace rspamd::util
 
+/* C API */
+
+#define CXX_DB_FROM_C(obj) (reinterpret_cast<rspamd::util::hs_shared_database *>(obj))
+#define C_DB_FROM_CXX(obj) (reinterpret_cast<rspamd_hyperscan_t *>(obj))
+
+rspamd_hyperscan_t *
+rspamd_maybe_load_hyperscan(const char *filename)
+{
+	auto maybe_db = rspamd::util::load_cached_hs_file(filename);
+
+	if (maybe_db.has_value()) {
+		auto *ndb = new rspamd::util::hs_shared_database;
+		*ndb = std::move(maybe_db.value());
+		return C_DB_FROM_CXX(ndb);
+	}
+	else {
+		auto error = maybe_db.error();
+
+		switch(error.category) {
+		case rspamd::util::error_category::CRITICAL:
+			msg_err_hyperscan("critical error when trying to load cached hyperscan: %s",
+				error.error_message.data());
+			break;
+		case rspamd::util::error_category::IMPORTANT:
+			msg_info_hyperscan("error when trying to load cached hyperscan: %s",
+				error.error_message.data());
+			break;
+		default:
+			msg_debug_hyperscan("error when trying to load cached hyperscan: %s",
+				error.error_message.data());
+			break;
+		}
+	}
+
+	return nullptr;
+}
+
+hs_database_t*
+rspamd_hyperscan_get_database(rspamd_hyperscan_t *db)
+{
+	auto *real_db = CXX_DB_FROM_C(db);
+	return real_db->db;
+}
+
+void
+rspamd_hyperscan_free(rspamd_hyperscan_t *db)
+{
+	auto *real_db = CXX_DB_FROM_C(db);
+
+	delete real_db;
+}
 
 #endif // WITH_HYPERSCAN
\ No newline at end of file
diff --git a/src/libserver/hyperscan_tools.h b/src/libserver/hyperscan_tools.h
new file mode 100644
index 000000000..31139e6af
--- /dev/null
+++ b/src/libserver/hyperscan_tools.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright 2022 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 "config.h"
+
+#ifndef RSPAMD_HYPERSCAN_TOOLS_H
+#define RSPAMD_HYPERSCAN_TOOLS_H
+
+#ifdef WITH_HYPERSCAN
+
+#include "hs.h"
+
+G_BEGIN_DECLS
+
+/**
+ * Opaque structure that represents hyperscan (maybe shared/cached database)
+ */
+typedef struct rspamd_hyperscan_s rspamd_hyperscan_t;
+
+/**
+ * Maybe load or mmap shared a hyperscan from a file
+ * @param filename
+ * @return cached database if available
+ */
+rspamd_hyperscan_t *rspamd_hyperscan_maybe_load(const char *filename);
+/**
+ * Get the internal database
+ * @param db
+ * @return
+ */
+hs_database_t* rspamd_hyperscan_get_database(rspamd_hyperscan_t *db);
+/**
+ * Free the database
+ * @param db
+ */
+void rspamd_hyperscan_free(rspamd_hyperscan_t *db);
+
+G_END_DECLS
+
+#endif
+
+#endif


More information about the Commits mailing list