diff options
-rw-r--r-- | src/libserver/hyperscan_tools.cxx | 29 | ||||
-rw-r--r-- | src/libserver/symcache/symcache_impl.cxx | 9 | ||||
-rw-r--r-- | src/libutil/cxx/error.hxx | 100 | ||||
-rw-r--r-- | src/libutil/cxx/file_util.cxx | 52 | ||||
-rw-r--r-- | src/libutil/cxx/file_util.hxx | 25 |
5 files changed, 162 insertions, 53 deletions
diff --git a/src/libserver/hyperscan_tools.cxx b/src/libserver/hyperscan_tools.cxx index a2acc0c18..1272aa452 100644 --- a/src/libserver/hyperscan_tools.cxx +++ b/src/libserver/hyperscan_tools.cxx @@ -21,6 +21,7 @@ #include "contrib/ankerl/svector.h" #include "fmt/core.h" #include "libutil/cxx/file_util.hxx" +#include "libutil/cxx/error.hxx" #include "hs.h" #include "logger.h" #include "worker_util.h" @@ -150,35 +151,35 @@ struct hs_shared_database { }; static auto -hs_shared_from_unserialized(raii_mmaped_file &&map) -> tl::expected<hs_shared_database, std::string> +hs_shared_from_unserialized(raii_mmaped_file &&map) -> tl::expected<hs_shared_database, error> { auto ptr = map.get_map(); - return tl::expected<hs_shared_database, std::string>{tl::in_place, std::move(map), (hs_database_t *)ptr}; + return tl::expected<hs_shared_database, error>{tl::in_place, std::move(map), (hs_database_t *)ptr}; } static auto -hs_shared_from_serialized(raii_mmaped_file &&map) -> tl::expected<hs_shared_database, std::string> +hs_shared_from_serialized(raii_mmaped_file &&map) -> tl::expected<hs_shared_database, error> { hs_database_t *target = nullptr; if (auto ret = hs_deserialize_database((const char *)map.get_map(), map.get_size(), &target); ret != HS_SUCCESS) { - return tl::make_unexpected("cannot deserialize database"); + return tl::make_unexpected(error {"cannot deserialize database", ret}); } - return tl::expected<hs_shared_database, std::string>{tl::in_place, target}; + return tl::expected<hs_shared_database, error>{tl::in_place, target}; } -auto load_cached_hs_file(const char *fname) -> tl::expected<hs_shared_database, std::string> +auto load_cached_hs_file(const char *fname) -> tl::expected<hs_shared_database, error> { auto &hs_cache = hs_known_files_cache::get(); return raii_mmaped_file::mmap_shared(fname, O_RDONLY, PROT_READ) - .and_then([&]<class T>(T &&cached_serialized) -> tl::expected<hs_shared_database, std::string> { + .and_then([&]<class T>(T &&cached_serialized) -> tl::expected<hs_shared_database, error> { #if defined(HS_MAJOR) && defined(HS_MINOR) && HS_MAJOR >= 5 && HS_MINOR >= 4 auto unserialized_fname = fmt::format("{}.unser", fname); auto unserialized_file = raii_locked_file::create(unserialized_fname.c_str(), O_CREAT | O_RDWR | O_EXCL, 00644) - .and_then([&](auto &&new_file_locked) -> tl::expected<raii_file, std::string> { + .and_then([&](auto &&new_file_locked) -> tl::expected<raii_file, error> { auto tmpfile_pattern = fmt::format("{}{}hsmp-XXXXXXXXXXXXXXXXXX", cached_serialized.get_file().get_dir(), G_DIR_SEPARATOR); auto tmpfile = raii_locked_file::mkstemp(tmpfile_pattern.data(), O_CREAT | O_RDWR | O_EXCL, @@ -199,7 +200,7 @@ auto load_cached_hs_file(const char *fname) -> tl::expected<hs_shared_database, void *buf; posix_memalign(&buf, 16, unserialized_size); if (buf == NULL) { - return tl::make_unexpected("Cannot allocate memory"); + return tl::make_unexpected(error {"Cannot allocate memory", errno, error_category::CRITICAL }); } // Store owned string @@ -207,14 +208,14 @@ auto load_cached_hs_file(const char *fname) -> tl::expected<hs_shared_database, if (auto ret = hs_deserialize_database_at((const char *)cached_serialized.get_map(), cached_serialized.get_size(), (hs_database_t *) buf); ret != HS_SUCCESS) { - return tl::make_unexpected( - fmt::format("cannot deserialize hyperscan database: {}", ret)); + return tl::make_unexpected(error { + fmt::format("cannot deserialize hyperscan database: {}", ret), ret }); } else { if (write(tmpfile_checked.get_fd(), buf, unserialized_size) == -1) { free(buf); - return tl::make_unexpected(fmt::format("cannot write to {}: {}", - tmpfile_name, ::strerror(errno))); + return tl::make_unexpected(error { fmt::format("cannot write to {}: {}", + tmpfile_name, ::strerror(errno)), errno, error_category::CRITICAL }); } else { free(buf); @@ -247,7 +248,7 @@ auto load_cached_hs_file(const char *fname) -> tl::expected<hs_shared_database, return raii_file::open(unserialized_fname.c_str(), O_RDONLY); }; }) - .or_else([&](auto unused) -> tl::expected<raii_file, std::string> { + .or_else([&](auto unused) -> tl::expected<raii_file, error> { // Cannot create file, so try to open it in RO mode return raii_file::open(unserialized_fname.c_str(), O_RDONLY); }); diff --git a/src/libserver/symcache/symcache_impl.cxx b/src/libserver/symcache/symcache_impl.cxx index c29b9d6d4..4208d4882 100644 --- a/src/libserver/symcache/symcache_impl.cxx +++ b/src/libserver/symcache/symcache_impl.cxx @@ -232,7 +232,12 @@ auto symcache::load_items() -> bool O_RDONLY, PROT_READ); if (!cached_map.has_value()) { - msg_info_cache("%s", cached_map.error().c_str()); + if (cached_map.error().category == util::error_category::CRITICAL) { + msg_err_cache("%s", cached_map.error().error_message.data()); + } + else { + msg_info_cache("%s", cached_map.error().error_message.data()); + } return false; } @@ -369,7 +374,7 @@ bool symcache::save_items() const return false; } - msg_err_cache("%s", file_sink.error().c_str()); + msg_err_cache("%s", file_sink.error().error_message.data()); return false; } diff --git a/src/libutil/cxx/error.hxx b/src/libutil/cxx/error.hxx new file mode 100644 index 000000000..65fa76f3b --- /dev/null +++ b/src/libutil/cxx/error.hxx @@ -0,0 +1,100 @@ +/*- + * 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. + */ + +#ifndef RSPAMD_ERROR_HXX +#define RSPAMD_ERROR_HXX +#pragma once + +#include "config.h" +#include <string> +#include <string_view> +#include <cstdint> +#include <optional> + +/*** + * This unit is used to represent Rspamd C++ errors in a way to interoperate + * with C code if needed and avoid allocations for static strings + */ +namespace rspamd::util { + +enum class error_category : std::uint8_t { + INFORMAL, + IMPORTANT, + CRITICAL +}; + +struct error { +public: + /** + * Construct from a static string, this string must live long enough to outlive this object + * @param msg + * @param code + * @param category + */ + error(const char *msg, int code, error_category category = error_category::INFORMAL) : + error_message(msg), error_code(code), category(category) {} + /** + * Construct error from a temporary string taking membership + * @param msg + * @param code + * @param category + */ + error(std::string &&msg, int code, error_category category = error_category::INFORMAL) + : error_code(code), category(category) { + static_storage = std::move(msg); + error_message = static_storage.value(); + } + /** + * Construct error from another string copying it into own storage + * @param msg + * @param code + * @param category + */ + error(const std::string &msg, int code, error_category category = error_category::INFORMAL) + : error_code(code), category(category) { + static_storage = msg; + error_message = static_storage.value(); + } + + /** + * Convert into GError + * @return + */ + auto into_g_error() const -> GError * { + return g_error_new(g_quark_from_static_string("rspamd"), error_code, "%s", + error_message.data()); + } + + /** + * Convenience alias for the `into_g_error` + * @param err + */ + auto into_g_error_set(GError **err) const -> void { + if (err && *err == nullptr) { + *err = into_g_error(); + } + } +public: + std::string_view error_message; + int error_code; + error_category category; +private: + std::optional<std::string> static_storage; +}; + +} // namespace rspamd::util + +#endif //RSPAMD_ERROR_HXX diff --git a/src/libutil/cxx/file_util.cxx b/src/libutil/cxx/file_util.cxx index 10a91a251..d0860b77b 100644 --- a/src/libutil/cxx/file_util.cxx +++ b/src/libutil/cxx/file_util.cxx @@ -24,7 +24,7 @@ namespace rspamd::util { -auto raii_file::open(const char *fname, int flags) -> tl::expected<raii_file, std::string> +auto raii_file::open(const char *fname, int flags) -> tl::expected<raii_file, error> { int oflags = flags; #ifdef O_CLOEXEC @@ -32,25 +32,25 @@ auto raii_file::open(const char *fname, int flags) -> tl::expected<raii_file, st #endif if (fname == nullptr) { - return tl::make_unexpected("cannot open file; filename is nullptr"); + return tl::make_unexpected(error {"cannot open file; filename is nullptr", EINVAL, error_category::CRITICAL}); } auto fd = ::open(fname, oflags); if (fd == -1) { - return tl::make_unexpected(fmt::format("cannot open file {}: {}", fname, ::strerror(errno))); + return tl::make_unexpected(error{fmt::format("cannot open file {}: {}", fname, ::strerror(errno)), errno}); } auto ret = raii_file{fname, fd, false}; if (fstat(ret.fd, &ret.st) == -1) { - return tl::make_unexpected(fmt::format("cannot stat file {}: {}", fname, ::strerror(errno))); + return tl::make_unexpected(error {fmt::format("cannot stat file {}: {}", fname, ::strerror(errno)), errno}); } return ret; } -auto raii_file::create(const char *fname, int flags, int perms) -> tl::expected<raii_file, std::string> +auto raii_file::create(const char *fname, int flags, int perms) -> tl::expected<raii_file, error> { int oflags = flags; #ifdef O_CLOEXEC @@ -58,57 +58,58 @@ auto raii_file::create(const char *fname, int flags, int perms) -> tl::expected< #endif if (fname == nullptr) { - return tl::make_unexpected("cannot open file; filename is nullptr"); + return tl::make_unexpected(error {"cannot open file; filename is nullptr", EINVAL, error_category::CRITICAL}); } auto fd = ::open(fname, oflags, perms); if (fd == -1) { - return tl::make_unexpected(fmt::format("cannot create file {}: {}", fname, ::strerror(errno))); + return tl::make_unexpected(error{fmt::format("cannot create file {}: {}", fname, ::strerror(errno)), errno}); } auto ret = raii_file{fname, fd, false}; if (fstat(ret.fd, &ret.st) == -1) { - return tl::make_unexpected(fmt::format("cannot stat file {}: {}", fname, ::strerror(errno))); + return tl::make_unexpected(error{fmt::format("cannot stat file {}: {}", fname, ::strerror(errno)), errno}); } return ret; } -auto raii_file::create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, std::string> +auto raii_file::create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, error> { int oflags = flags; #ifdef O_CLOEXEC oflags |= O_CLOEXEC | O_CREAT | O_EXCL; #endif if (fname == nullptr) { - return tl::make_unexpected("cannot open file; filename is nullptr"); + return tl::make_unexpected(error {"cannot open file; filename is nullptr", EINVAL, error_category::CRITICAL}); } auto fd = ::open(fname, oflags, perms); if (fd == -1) { - return tl::make_unexpected(fmt::format("cannot create file {}: {}", fname, ::strerror(errno))); + return tl::make_unexpected(error {fmt::format("cannot create file {}: {}", fname, ::strerror(errno)), errno}); } auto ret = raii_file{fname, fd, true}; if (fstat(ret.fd, &ret.st) == -1) { - return tl::make_unexpected(fmt::format("cannot stat file {}: {}", fname, ::strerror(errno))); + return tl::make_unexpected(error {fmt::format("cannot stat file {}: {}", fname, ::strerror(errno)), errno}); } return ret; } -auto raii_file::mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, std::string> +auto raii_file::mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, error> { int oflags = flags; #ifdef O_CLOEXEC oflags |= O_CLOEXEC | O_CREAT | O_EXCL; #endif if (pattern == nullptr) { - return tl::make_unexpected("cannot open file; pattern is nullptr"); + return tl::make_unexpected(error {"cannot open file; pattern is nullptr", EINVAL, error_category::CRITICAL}); + } std::string mutable_pattern = pattern; @@ -116,14 +117,14 @@ auto raii_file::mkstemp(const char *pattern, int flags, int perms) -> tl::expect auto fd = g_mkstemp_full(mutable_pattern.data(), oflags, perms); if (fd == -1) { - return tl::make_unexpected(fmt::format("cannot create file {}: {}", pattern, ::strerror(errno))); + return tl::make_unexpected(error {fmt::format("cannot create file {}: {}", pattern, ::strerror(errno)), errno}); } auto ret = raii_file{mutable_pattern.c_str(), fd, true}; if (fstat(ret.fd, &ret.st) == -1) { - return tl::make_unexpected(fmt::format("cannot stat file {}: {}", - mutable_pattern.c_str(), ::strerror(errno))); + return tl::make_unexpected(error { fmt::format("cannot stat file {}: {}", + mutable_pattern, ::strerror(errno)), errno} ); } return ret; @@ -152,10 +153,11 @@ raii_locked_file::~raii_locked_file() noexcept } } -auto raii_locked_file::lock_raii_file(raii_file &&unlocked) -> tl::expected<raii_locked_file, std::string> +auto raii_locked_file::lock_raii_file(raii_file &&unlocked) -> tl::expected<raii_locked_file, error> { if (!rspamd_file_lock(unlocked.get_fd(), TRUE)) { - return tl::make_unexpected(fmt::format("cannot lock file {}: {}", unlocked.get_name(), ::strerror(errno))); + return tl::make_unexpected( + error { fmt::format("cannot lock file {}: {}", unlocked.get_name(), ::strerror(errno)), errno}); } return raii_locked_file{std::move(unlocked)}; @@ -175,7 +177,7 @@ raii_mmaped_file::raii_mmaped_file(raii_file &&_file, void *_map) } auto raii_mmaped_file::mmap_shared(raii_file &&file, - int flags) -> tl::expected<raii_mmaped_file, std::string> + int flags) -> tl::expected<raii_mmaped_file, error> { void *map; @@ -184,8 +186,8 @@ auto raii_mmaped_file::mmap_shared(raii_file &&file, map = mmap(NULL, file.get_stat().st_size, flags, MAP_SHARED, file.get_fd(), 0); if (map == MAP_FAILED) { - return tl::make_unexpected(fmt::format("cannot mmap file at fd: {}: {}", - file.get_fd(), ::strerror(errno))); + return tl::make_unexpected(error { fmt::format("cannot mmap file at fd: {}: {}", + file.get_fd(), ::strerror(errno)), errno }); } @@ -193,7 +195,7 @@ auto raii_mmaped_file::mmap_shared(raii_file &&file, } auto raii_mmaped_file::mmap_shared(const char *fname, int open_flags, - int mmap_flags) -> tl::expected<raii_mmaped_file, std::string> + int mmap_flags) -> tl::expected<raii_mmaped_file, error> { auto file = raii_file::open(fname, open_flags); @@ -218,10 +220,10 @@ raii_mmaped_file::raii_mmaped_file(raii_mmaped_file &&other) noexcept } auto raii_file_sink::create(const char *fname, int flags, int perms, - const char *suffix) -> tl::expected<raii_file_sink, std::string> + const char *suffix) -> tl::expected<raii_file_sink, error> { if (!fname || !suffix) { - return tl::make_unexpected("cannot create file sink: bad input arguments"); + return tl::make_unexpected(error {"cannot open file; filename is nullptr", EINVAL, error_category::CRITICAL}); } auto tmp_fname = fmt::format("{}.{}", fname, suffix); diff --git a/src/libutil/cxx/file_util.hxx b/src/libutil/cxx/file_util.hxx index c66fd17ef..097ce03a7 100644 --- a/src/libutil/cxx/file_util.hxx +++ b/src/libutil/cxx/file_util.hxx @@ -19,6 +19,7 @@ #include "config.h" #include "contrib/expected/expected.hpp" +#include "libutil/cxx/error.hxx" #include <string> #include <sys/stat.h> @@ -31,10 +32,10 @@ struct raii_file { public: virtual ~raii_file() noexcept; - static auto open(const char *fname, int flags) -> tl::expected<raii_file, std::string>; - static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_file, std::string>; - static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, std::string>; - static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, std::string>; + static auto open(const char *fname, int flags) -> tl::expected<raii_file, error>; + static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_file, error>; + static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, error>; + static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, error>; auto get_fd() const -> int { return fd; @@ -135,28 +136,28 @@ struct raii_locked_file final : public raii_file { public: ~raii_locked_file() noexcept override; - static auto open(const char *fname, int flags) -> tl::expected<raii_locked_file, std::string> { + static auto open(const char *fname, int flags) -> tl::expected<raii_locked_file, error> { auto locked = raii_file::open(fname, flags).and_then([]<class T>(T &&file) { return lock_raii_file(std::forward<T>(file)); }); return locked; } - static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, std::string> { + static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, error> { auto locked = raii_file::create(fname, flags, perms).and_then([]<class T>(T &&file) { return lock_raii_file(std::forward<T>(file)); }); return locked; } - static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, std::string> { + static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, error> { auto locked = raii_file::create_temp(fname, flags, perms).and_then([]<class T>(T &&file) { return lock_raii_file(std::forward<T>(file)); }); return locked; } - static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_locked_file, std::string> { + static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_locked_file, error> { auto locked = raii_file::mkstemp(pattern, flags, perms).and_then([]<class T>(T &&file) { return lock_raii_file(std::forward<T>(file)); }); @@ -185,7 +186,7 @@ public: raii_locked_file() = delete; raii_locked_file(const raii_locked_file &other) = delete; private: - static auto lock_raii_file(raii_file &&unlocked) -> tl::expected<raii_locked_file, std::string>; + static auto lock_raii_file(raii_file &&unlocked) -> tl::expected<raii_locked_file, error>; raii_locked_file(raii_file &&other) noexcept : raii_file(std::move(other)) {} explicit raii_locked_file(const char *fname, int fd, bool temp) : raii_file(fname, fd, temp) {} }; @@ -195,8 +196,8 @@ private: */ struct raii_mmaped_file final { ~raii_mmaped_file(); - static auto mmap_shared(raii_file &&file, int flags) -> tl::expected<raii_mmaped_file, std::string>; - static auto mmap_shared(const char *fname, int open_flags, int mmap_flags) -> tl::expected<raii_mmaped_file, std::string>; + static auto mmap_shared(raii_file &&file, int flags) -> tl::expected<raii_mmaped_file, error>; + static auto mmap_shared(const char *fname, int open_flags, int mmap_flags) -> tl::expected<raii_mmaped_file, error>; // Returns a constant pointer to the underlying map auto get_map() const -> void* {return map;} auto get_file() const -> const raii_file& { return file; } @@ -235,7 +236,7 @@ private: */ struct raii_file_sink final { static auto create(const char *fname, int flags, int perms, const char *suffix = "new") - -> tl::expected<raii_file_sink, std::string>; + -> tl::expected<raii_file_sink, error>; auto write_output() -> bool; ~raii_file_sink(); auto get_fd() const -> int |