Modernize blocklist.cc: Rename, move members inside struct (#2010)

* Modernize blocklist.cc to C++

* Modernize blocklist.cc: Renamed BlocklistFile struct and moved IPv4 range struct inside it

 Modernize bandwidth.cc: Review notes; Promote container of blocklists in session to vec of unique_ptrs
This commit is contained in:
Dmytro Lytovchenko 2022-05-15 18:32:22 +02:00 committed by GitHub
parent 25ef121d71
commit aa502f9312
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 229 additions and 232 deletions

View File

@ -3,9 +3,9 @@
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#include <algorithm>
#include <cerrno>
#include <cstdio>
#include <cstdlib> /* bsearch(), qsort() */
#include <cstring>
#include <string_view>
@ -18,48 +18,31 @@
#include "file.h"
#include "log.h"
#include "net.h"
#include "tr-assert.h"
#include "utils.h"
/***
**** PRIVATE
***/
struct tr_ipv4_range
void BlocklistFile::close()
{
uint32_t begin;
uint32_t end;
};
struct tr_blocklistFile
{
bool isEnabled;
tr_sys_file_t fd;
size_t ruleCount;
uint64_t byteCount;
char* filename;
struct tr_ipv4_range* rules;
};
static void blocklistClose(tr_blocklistFile* b)
{
if (b->rules != nullptr)
if (rules_ != nullptr)
{
tr_sys_file_unmap(b->rules, b->byteCount);
tr_sys_file_close(b->fd);
b->rules = nullptr;
b->ruleCount = 0;
b->byteCount = 0;
b->fd = TR_BAD_SYS_FILE;
tr_sys_file_unmap(rules_, byte_count_);
tr_sys_file_close(fd_);
rules_ = nullptr;
rule_count_ = 0;
byte_count_ = 0;
fd_ = TR_BAD_SYS_FILE;
}
}
static void blocklistLoad(tr_blocklistFile* b)
void BlocklistFile::load()
{
blocklistClose(b);
close();
auto info = tr_sys_path_info{};
if (!tr_sys_path_get_info(b->filename, 0, &info))
if (!tr_sys_path_get_info(getFilename(), 0, &info))
{
return;
}
@ -71,24 +54,24 @@ static void blocklistLoad(tr_blocklistFile* b)
}
tr_error* error = nullptr;
auto const fd = tr_sys_file_open(b->filename, TR_SYS_FILE_READ, 0, &error);
auto const fd = tr_sys_file_open(getFilename(), TR_SYS_FILE_READ, 0, &error);
if (fd == TR_BAD_SYS_FILE)
{
tr_logAddWarn(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", b->filename),
fmt::arg("path", getFilename()),
fmt::arg("error", error->message),
fmt::arg("error_code", error->code)));
tr_error_free(error);
return;
}
b->rules = static_cast<struct tr_ipv4_range*>(tr_sys_file_map_for_reading(fd, 0, byteCount, &error));
if (b->rules == nullptr)
rules_ = static_cast<struct IPv4Range*>(tr_sys_file_map_for_reading(fd, 0, byteCount, &error));
if (rules_ == nullptr)
{
tr_logAddWarn(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", b->filename),
fmt::arg("path", getFilename()),
fmt::arg("error", error->message),
fmt::arg("error_code", error->code)));
tr_sys_file_close(fd);
@ -96,108 +79,57 @@ static void blocklistLoad(tr_blocklistFile* b)
return;
}
b->fd = fd;
b->byteCount = byteCount;
b->ruleCount = byteCount / sizeof(struct tr_ipv4_range);
fd_ = fd;
byte_count_ = byteCount;
rule_count_ = byteCount / sizeof(IPv4Range);
tr_logAddInfo(fmt::format(
ngettext("Blocklist '{path}' has {count} entry", "Blocklist '{path}' has {count} entries", b->ruleCount),
fmt::arg("path", tr_sys_path_basename(b->filename)),
fmt::arg("count", b->ruleCount)));
ngettext("Blocklist '{path}' has {count} entry", "Blocklist '{path}' has {count} entries", rule_count_),
fmt::arg("path", tr_sys_path_basename(getFilename())),
fmt::arg("count", rule_count_)));
}
static void blocklistEnsureLoaded(tr_blocklistFile* b)
void BlocklistFile::ensureLoaded()
{
if (b->rules == nullptr)
if (rules_ == nullptr)
{
blocklistLoad(b);
load();
}
}
static int compareAddressToRange(void const* va, void const* vb)
{
auto const* a = static_cast<uint32_t const*>(va);
auto const* b = static_cast<struct tr_ipv4_range const*>(vb);
if (*a < b->begin)
{
return -1;
}
if (*a > b->end)
{
return 1;
}
return 0;
}
static void blocklistDelete(tr_blocklistFile* b)
{
blocklistClose(b);
tr_sys_path_remove(b->filename);
}
// TODO: unused
//static void blocklistDelete(tr_blocklistFile* b)
//{
// blocklistClose(b);
// tr_sys_path_remove(b->filename, nullptr);
//}
/***
**** PACKAGE-VISIBLE
***/
tr_blocklistFile* tr_blocklistFileNew(char const* filename, bool isEnabled)
bool BlocklistFile::hasAddress(tr_address const& addr)
{
auto* const b = tr_new0(tr_blocklistFile, 1);
b->fd = TR_BAD_SYS_FILE;
b->filename = tr_strdup(filename);
b->isEnabled = isEnabled;
TR_ASSERT(tr_address_is_valid(&addr));
return b;
}
char const* tr_blocklistFileGetFilename(tr_blocklistFile const* b)
{
return b->filename;
}
void tr_blocklistFileFree(tr_blocklistFile* b)
{
blocklistClose(b);
tr_free(b->filename);
tr_free(b);
}
size_t tr_blocklistFileGetRuleCount(tr_blocklistFile const* b)
{
blocklistEnsureLoaded((tr_blocklistFile*)b);
return b->ruleCount;
}
void tr_blocklistFileSetEnabled(tr_blocklistFile* b, bool isEnabled)
{
TR_ASSERT(b != nullptr);
b->isEnabled = isEnabled;
}
bool tr_blocklistFileHasAddress(tr_blocklistFile* b, tr_address const* addr)
{
TR_ASSERT(tr_address_is_valid(addr));
if (!b->isEnabled || addr->type == TR_AF_INET6)
if (!is_enabled_ || addr.type == TR_AF_INET6)
{
return false;
}
blocklistEnsureLoaded(b);
ensureLoaded();
if (b->rules == nullptr || b->ruleCount == 0)
if (rules_ == nullptr || rule_count_ == 0)
{
return false;
}
auto const needle = ntohl(addr->addr.addr4.s_addr);
auto const needle = ntohl(addr.addr.addr4.s_addr);
auto const* range = static_cast<struct tr_ipv4_range const*>(
bsearch(&needle, b->rules, b->ruleCount, sizeof(struct tr_ipv4_range), compareAddressToRange));
// std::binary_search works differently and requires a less-than comparison
// and two arguments of the same type. std::bsearch is the right choice.
auto const* range = static_cast<IPv4Range const*>(
std::bsearch(&needle, rules_, rule_count_, sizeof(IPv4Range), IPv4Range::compareAddressToRange));
return range != nullptr;
}
@ -207,7 +139,7 @@ bool tr_blocklistFileHasAddress(tr_blocklistFile* b, tr_address const* addr)
* http://wiki.phoenixlabs.org/wiki/P2P_Format
* https://en.wikipedia.org/wiki/PeerGuardian#P2P_plaintext_format
*/
static bool parseLine1(std::string_view line, struct tr_ipv4_range* range)
bool BlocklistFile::parseLine1(std::string_view line, struct IPv4Range* range)
{
// remove leading "comment:"
auto pos = line.find(':');
@ -225,7 +157,7 @@ static bool parseLine1(std::string_view line, struct tr_ipv4_range* range)
}
if (auto addr = tr_address{}; tr_address_from_string(&addr, line.substr(0, pos)))
{
range->begin = ntohl(addr.addr.addr4.s_addr);
range->begin_ = ntohl(addr.addr.addr4.s_addr);
}
else
{
@ -236,7 +168,7 @@ static bool parseLine1(std::string_view line, struct tr_ipv4_range* range)
// parse the trailing 'y.y.y.y'
if (auto addr = tr_address{}; tr_address_from_string(&addr, line))
{
range->end = ntohl(addr.addr.addr4.s_addr);
range->end_ = ntohl(addr.addr.addr4.s_addr);
}
else
{
@ -250,7 +182,7 @@ static bool parseLine1(std::string_view line, struct tr_ipv4_range* range)
* DAT / eMule format: "000.000.000.000 - 000.255.255.255 , 000 , invalid ip"a
* https://sourceforge.net/p/peerguardian/wiki/dev-blocklist-format-dat/
*/
static bool parseLine2(std::string_view line, struct tr_ipv4_range* range)
bool BlocklistFile::parseLine2(std::string_view line, struct IPv4Range* range)
{
static auto constexpr Delim1 = std::string_view{ " - " };
static auto constexpr Delim2 = std::string_view{ " , " };
@ -263,7 +195,7 @@ static bool parseLine2(std::string_view line, struct tr_ipv4_range* range)
if (auto addr = tr_address{}; tr_address_from_string(&addr, line.substr(0, pos)))
{
range->begin = ntohl(addr.addr.addr4.s_addr);
range->begin_ = ntohl(addr.addr.addr4.s_addr);
}
else
{
@ -279,7 +211,7 @@ static bool parseLine2(std::string_view line, struct tr_ipv4_range* range)
if (auto addr = tr_address{}; tr_address_from_string(&addr, line.substr(0, pos)))
{
range->end = ntohl(addr.addr.addr4.s_addr);
range->end_ = ntohl(addr.addr.addr4.s_addr);
}
else
{
@ -293,7 +225,7 @@ static bool parseLine2(std::string_view line, struct tr_ipv4_range* range)
* CIDR notation: "0.0.0.0/8", IPv4 only
* https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation
*/
static bool parseLine3(char const* line, struct tr_ipv4_range* range)
bool BlocklistFile::parseLine3(char const* line, IPv4Range* range)
{
unsigned int ip[4];
unsigned int pflen = 0;
@ -315,48 +247,30 @@ static bool parseLine3(char const* line, struct tr_ipv4_range* range)
ip_u = ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3];
/* fill the non-prefix bits the way we need it */
range->begin = ip_u & mask;
range->end = ip_u | (~mask);
range->begin_ = ip_u & mask;
range->end_ = ip_u | (~mask);
return true;
}
static bool parseLine(char const* line, struct tr_ipv4_range* range)
bool BlocklistFile::parseLine(char const* line, IPv4Range* range)
{
return parseLine1(line, range) || parseLine2(line, range) || parseLine3(line, range);
}
static int compareAddressRangesByFirstAddress(void const* va, void const* vb)
bool BlocklistFile::compareAddressRangesByFirstAddress(IPv4Range const& a, IPv4Range const& b)
{
auto const* a = static_cast<struct tr_ipv4_range const*>(va);
auto const* b = static_cast<struct tr_ipv4_range const*>(vb);
if (a->begin < b->begin)
{
return -1;
}
if (a->begin > b->begin)
{
return 1;
}
return 0;
return a.begin_ < b.begin_;
}
int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename)
size_t BlocklistFile::setContent(char const* filename)
{
int inCount = 0;
char line[2048];
// TODO: should be a vector
struct tr_ipv4_range* ranges = nullptr;
size_t ranges_alloc = 0;
size_t ranges_count = 0;
tr_error* error = nullptr;
if (filename == nullptr)
{
blocklistDelete(b);
return 0;
}
@ -372,14 +286,18 @@ int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename)
return 0;
}
blocklistClose(b);
close();
auto const out = tr_sys_file_open(b->filename, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0666, &error);
auto const out = tr_sys_file_open(
getFilename(),
TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE,
0666,
&error);
if (out == TR_BAD_SYS_FILE)
{
tr_logAddWarn(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", b->filename),
fmt::arg("path", getFilename()),
fmt::arg("error", error->message),
fmt::arg("error_code", error->code)));
tr_error_free(error);
@ -388,9 +306,10 @@ int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename)
}
/* load the rules into memory */
std::vector<IPv4Range> ranges;
while (tr_sys_file_read_line(in, line, sizeof(line)))
{
struct tr_ipv4_range range;
IPv4Range range = {};
++inCount;
@ -401,60 +320,41 @@ int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename)
continue;
}
if (ranges_alloc == ranges_count)
{
ranges_alloc += 4096; /* arbitrary */
ranges = tr_renew(struct tr_ipv4_range, ranges, ranges_alloc);
}
ranges[ranges_count++] = range;
ranges.push_back(range);
}
if (ranges_count > 0) /* sort and merge */
if (!std::empty(ranges)) // sort and merge
{
struct tr_ipv4_range* keep = ranges;
size_t keep = 0; // index in ranges
/* sort */
qsort(ranges, ranges_count, sizeof(struct tr_ipv4_range), compareAddressRangesByFirstAddress);
std::sort(std::begin(ranges), std::end(ranges), BlocklistFile::compareAddressRangesByFirstAddress);
/* merge */
for (size_t i = 1; i < ranges_count; ++i)
// merge
for (auto const& r : ranges)
{
struct tr_ipv4_range const* r = &ranges[i];
if (keep->end < r->begin)
if (ranges[keep].end_ < r.begin_)
{
*++keep = *r;
ranges[++keep] = r;
}
else if (keep->end < r->end)
else if (ranges[keep].end_ < r.end_)
{
keep->end = r->end;
ranges[keep].end_ = r.end_;
}
}
ranges_count = keep + 1 - ranges;
TR_ASSERT_MSG(keep + 1 <= std::size(ranges), "Can shrink `ranges` or leave intact, but not grow");
ranges.resize(keep + 1);
#ifdef TR_ENABLE_ASSERTS
/* sanity checks: make sure the rules are sorted in ascending order and don't overlap */
for (size_t i = 0; i < ranges_count; ++i)
{
TR_ASSERT(ranges[i].begin <= ranges[i].end);
}
for (size_t i = 1; i < ranges_count; ++i)
{
TR_ASSERT(ranges[i - 1].end < ranges[i].begin);
}
assertValidRules(ranges);
#endif
}
if (!tr_sys_file_write(out, ranges, sizeof(struct tr_ipv4_range) * ranges_count, nullptr, &error))
if (!tr_sys_file_write(out, ranges.data(), sizeof(IPv4Range) * std::size(ranges), nullptr, &error))
{
tr_logAddWarn(fmt::format(
_("Couldn't save '{path}': {error} ({error_code})"),
fmt::arg("path", b->filename),
fmt::arg("path", getFilename()),
fmt::arg("error", error->message),
fmt::arg("error_code", error->code)));
tr_error_free(error);
@ -462,16 +362,30 @@ int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename)
else
{
tr_logAddInfo(fmt::format(
ngettext("Blocklist '{path}' has {count} entry", "Blocklist '{path}' has {count} entries", b->ruleCount),
fmt::arg("path", tr_sys_path_basename(b->filename)),
fmt::arg("count", b->ruleCount)));
ngettext("Blocklist '{path}' has {count} entry", "Blocklist '{path}' has {count} entries", rule_count_),
fmt::arg("path", tr_sys_path_basename(getFilename())),
fmt::arg("count", rule_count_)));
}
tr_free(ranges);
tr_sys_file_close(out);
tr_sys_file_close(in);
blocklistLoad(b);
load();
return ranges_count;
return std::size(ranges);
}
#ifdef TR_ENABLE_ASSERTS
void BlocklistFile::assertValidRules(std::vector<IPv4Range>& ranges)
{
for (auto const& r : ranges)
{
TR_ASSERT(r.begin_ <= r.end_);
}
for (size_t i = 1; i < std::size(ranges); ++i)
{
TR_ASSERT(ranges[i - 1].end_ < ranges[i].begin_);
}
}
#endif

View File

@ -9,19 +9,117 @@
#error only libtransmission should #include this header.
#endif
#include <string>
#include <string_view>
#include <vector>
#include "file.h" // for tr_sys_file_t
#include "tr-assert.h"
#include "tr-macros.h"
struct tr_address;
struct tr_blocklistFile;
tr_blocklistFile* tr_blocklistFileNew(char const* filename, bool isEnabled);
struct BlocklistFile
{
public:
// Prevent moving to protect the fd_ from accidental destruction
BlocklistFile(BlocklistFile&&) = delete;
BlocklistFile(BlocklistFile const&) = delete;
BlocklistFile& operator=(BlocklistFile const&) = delete;
BlocklistFile& operator=(BlocklistFile&&) = delete;
char const* tr_blocklistFileGetFilename(tr_blocklistFile const* b);
BlocklistFile(char const* filename, bool isEnabled)
: is_enabled_(isEnabled)
, filename_(filename)
{
}
size_t tr_blocklistFileGetRuleCount(tr_blocklistFile const* b);
~BlocklistFile()
{
close();
}
void tr_blocklistFileFree(tr_blocklistFile* b);
[[nodiscard]] bool exists() const
{
return tr_sys_path_exists(getFilename(), nullptr);
}
void tr_blocklistFileSetEnabled(tr_blocklistFile* b, bool isEnabled);
[[nodiscard]] char const* getFilename() const
{
return filename_.c_str();
}
bool tr_blocklistFileHasAddress(tr_blocklistFile* b, struct tr_address const* addr);
// TODO: This function should be const, but cannot be const due to it calling ensureLoaded()
size_t getRuleCount()
{
ensureLoaded();
int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename);
return rule_count_;
}
[[nodiscard]] constexpr bool isEnabled() const
{
return is_enabled_;
}
void setEnabled(bool isEnabled)
{
is_enabled_ = isEnabled;
}
bool hasAddress(tr_address const& addr);
/// @brief Read the file of ranges, sort and merge, write to our own file, and reload from it
size_t setContent(char const* filename);
private:
struct IPv4Range
{
uint32_t begin_ = 0;
uint32_t end_ = 0;
/// @brief Used for std::bsearch of an IPv4 address
static int compareAddressToRange(void const* va, void const* vb)
{
auto const* a = reinterpret_cast<uint32_t const*>(va);
auto const* b = reinterpret_cast<IPv4Range const*>(vb);
if (*a < b->begin_)
{
return -1;
}
if (*a > b->end_)
{
return 1;
}
return 0;
}
};
void ensureLoaded();
void load();
void close();
static bool parseLine(char const* line, IPv4Range* range);
static bool compareAddressRangesByFirstAddress(IPv4Range const& a, IPv4Range const& b);
static bool parseLine1(std::string_view line, struct IPv4Range* range);
static bool parseLine2(std::string_view line, struct IPv4Range* range);
static bool parseLine3(char const* line, IPv4Range* range);
#ifdef TR_ENABLE_ASSERTS
/// @brief Sanity checks: make sure the rules are sorted in ascending order and don't overlap
void assertValidRules(std::vector<IPv4Range>& ranges);
#endif
bool is_enabled_;
tr_sys_file_t fd_{ TR_BAD_SYS_FILE };
size_t rule_count_ = 0;
uint64_t byte_count_ = 0;
std::string const filename_;
/// @brief Not a container, memory mapped file
IPv4Range* rules_ = nullptr;
};

View File

@ -1455,8 +1455,8 @@ static void onBlocklistFetched(tr_web::FetchResponse const& web_response)
}
// feed it to the session and give the client a response
int const rule_count = tr_blocklistSetContent(session, filename);
tr_variantDictAddInt(data->args_out, TR_KEY_blocklist_size, rule_count);
size_t const rule_count = tr_blocklistSetContent(session, filename);
tr_variantDictAddInt(data->args_out, TR_KEY_blocklist_size, static_cast<int64_t>(rule_count));
tr_sys_path_remove(filename);
tr_idle_function_done(data, SuccessResult);
}

View File

@ -2374,14 +2374,11 @@ static void loadBlocklists(tr_session* session)
if (!tr_sys_path_get_info(binname, 0, &binname_info)) /* create it */
{
tr_blocklistFile* b = tr_blocklistFileNew(binname, isEnabled);
if (auto const n = tr_blocklistFileSetContent(b, path); n > 0)
BlocklistFile b(binname, isEnabled);
if (auto const n = b.setContent(path); n > 0)
{
load = binname;
}
tr_blocklistFileFree(b);
}
else if (
tr_sys_path_get_info(path, 0, &path_info) &&
@ -2390,9 +2387,10 @@ static void loadBlocklists(tr_session* session)
auto const old = tr_pathbuf{ binname, ".old"sv };
tr_sys_path_remove(old);
tr_sys_path_rename(binname, old);
auto* const b = tr_blocklistFileNew(binname, isEnabled);
if (tr_blocklistFileSetContent(b, path) > 0)
BlocklistFile b(binname, isEnabled);
if (b.setContent(path) > 0)
{
tr_sys_path_remove(old);
}
@ -2401,8 +2399,6 @@ static void loadBlocklists(tr_session* session)
tr_sys_path_remove(binname);
tr_sys_path_rename(old, binname);
}
tr_blocklistFileFree(b);
}
}
@ -2417,7 +2413,7 @@ static void loadBlocklists(tr_session* session)
std::begin(loadme),
std::end(loadme),
std::back_inserter(session->blocklists),
[&isEnabled](auto const& path) { return tr_blocklistFileNew(path.c_str(), isEnabled); });
[&isEnabled](auto const& path) { return std::make_unique<BlocklistFile>(path.c_str(), isEnabled); });
/* cleanup */
tr_sys_dir_close(odir);
@ -2425,9 +2421,7 @@ static void loadBlocklists(tr_session* session)
static void closeBlocklists(tr_session* session)
{
auto& src = session->blocklists;
std::for_each(std::begin(src), std::end(src), [](auto* b) { tr_blocklistFileFree(b); });
src.clear();
session->blocklists.clear();
}
void tr_sessionReloadBlocklists(tr_session* session)
@ -2442,12 +2436,8 @@ size_t tr_blocklistGetRuleCount(tr_session const* session)
{
TR_ASSERT(tr_isSession(session));
auto const& src = session->blocklists;
return std::accumulate(
std::begin(src),
std::end(src),
0,
[](size_t sum, auto const* cur) { return sum + tr_blocklistFileGetRuleCount(cur); });
auto& src = session->blocklists;
return std::accumulate(std::begin(src), std::end(src), 0, [](int sum, auto& cur) { return sum + cur->getRuleCount(); });
}
bool tr_blocklistIsEnabled(tr_session const* session)
@ -2461,10 +2451,7 @@ void tr_session::useBlocklist(bool enabled)
{
this->blocklist_enabled_ = enabled;
std::for_each(
std::begin(blocklists),
std::end(blocklists),
[enabled](auto* blocklist) { tr_blocklistFileSetEnabled(blocklist, enabled); });
std::for_each(std::begin(blocklists), std::end(blocklists), [enabled](auto& blocklist) { blocklist->setEnabled(enabled); });
}
void tr_blocklistSetEnabled(tr_session* session, bool enabled)
@ -2481,41 +2468,39 @@ bool tr_blocklistExists(tr_session const* session)
return !std::empty(session->blocklists);
}
int tr_blocklistSetContent(tr_session* session, char const* contentFilename)
size_t tr_blocklistSetContent(tr_session* session, char const* contentFilename)
{
auto const lock = session->unique_lock();
// find (or add) the default blocklist
tr_blocklistFile* b = nullptr;
auto& src = session->blocklists;
char const* const name = DEFAULT_BLOCKLIST_FILENAME;
auto const it = std::find_if(
std::begin(src),
std::end(src),
[&name](auto const* blocklist) { return tr_strvEndsWith(tr_blocklistFileGetFilename(blocklist), name); });
[&name](auto const& blocklist) { return tr_strvEndsWith(blocklist->getFilename(), name); });
BlocklistFile* b = nullptr;
if (it == std::end(src))
{
b = tr_blocklistFileNew(tr_pathbuf{ session->config_dir, "/blocklists/"sv, name }, session->useBlocklist());
src.push_back(b);
auto path = tr_pathbuf{ session->config_dir, "/blocklists/"sv, name };
src.push_back(std::make_unique<BlocklistFile>(path, session->useBlocklist()));
b = std::rbegin(src)->get();
}
else
{
b = *it;
b = it->get();
}
// set the default blocklist's content
int const ruleCount = tr_blocklistFileSetContent(b, contentFilename);
int const ruleCount = b->setContent(contentFilename);
return ruleCount;
}
bool tr_sessionIsAddressBlocked(tr_session const* session, tr_address const* addr)
{
auto const& src = session->blocklists;
return std::any_of(
std::begin(src),
std::end(src),
[&addr](auto* blocklist) { return tr_blocklistFileHasAddress(blocklist, addr); });
return std::any_of(std::begin(src), std::end(src), [&addr](auto& blocklist) { return blocklist->hasAddress(*addr); });
}
void tr_blocklistSetURL(tr_session* session, char const* url)

View File

@ -53,7 +53,7 @@ struct tr_address;
struct tr_announcer;
struct tr_announcer_udp;
struct tr_bindsockets;
struct tr_blocklistFile;
struct BlocklistFile;
struct tr_cache;
struct tr_fdInfo;
@ -438,7 +438,7 @@ public:
std::string resume_dir;
std::string torrent_dir;
std::vector<tr_blocklistFile*> blocklists;
std::vector<std::unique_ptr<BlocklistFile>> blocklists;
struct tr_peerMgr* peerMgr;
struct tr_shared* shared;

View File

@ -752,7 +752,7 @@ bool tr_sessionIsScriptEnabled(tr_session const*, TrScript);
*
* Passing nullptr for a filename will clear the blocklist.
*/
int tr_blocklistSetContent(tr_session* session, char const* filename);
size_t tr_blocklistSetContent(tr_session* session, char const* filename);
size_t tr_blocklistGetRuleCount(tr_session const* session);