Skip to content

Commit

Permalink
[Project] Start C API implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
vstakhov committed Oct 22, 2022
1 parent 272503b commit fc3bfa4
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 2 deletions.
75 changes: 73 additions & 2 deletions src/libserver/hyperscan_tools.cxx
Expand Up @@ -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 */
Expand All @@ -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, \
Expand All @@ -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
Expand Down Expand Up @@ -136,7 +146,7 @@ class hs_known_files_cache {
* 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() {
Expand All @@ -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
Expand Down Expand Up @@ -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
54 changes: 54 additions & 0 deletions 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

0 comments on commit fc3bfa4

Please sign in to comment.