refactor: misc-use-anonymous-namespace pt. 5 (#4552)

This commit is contained in:
Charles Kerr 2023-01-07 16:55:00 -06:00 committed by GitHub
parent cb10255ef1
commit d9278bd167
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 454 additions and 512 deletions

View File

@ -18,10 +18,6 @@
#include "tr-assert.h"
#include "utils.h" // tr_time_msec()
/***
****
***/
tr_bytes_per_second_t tr_bandwidth::getSpeedBytesPerSecond(RateControl& r, unsigned int interval_msec, uint64_t now)
{
if (now == 0)
@ -77,20 +73,20 @@ void tr_bandwidth::notifyBandwidthConsumedBytes(uint64_t const now, RateControl*
r->cache_time_ = 0;
}
/***
****
***/
// ---
tr_bandwidth::tr_bandwidth(tr_bandwidth* parent)
{
this->setParent(parent);
}
/***
****
***/
// ---
static void remove_child(std::vector<tr_bandwidth*>& v, tr_bandwidth* remove_me) noexcept
namespace
{
namespace deparent_helpers
{
void remove_child(std::vector<tr_bandwidth*>& v, tr_bandwidth* remove_me) noexcept
{
// the list isn't sorted -- so instead of erase()ing `it`,
// do the cheaper option of overwriting it with the final item
@ -100,9 +96,13 @@ static void remove_child(std::vector<tr_bandwidth*>& v, tr_bandwidth* remove_me)
v.resize(v.size() - 1);
}
}
} // namespace deparent_helpers
} // namespace
void tr_bandwidth::deparent() noexcept
{
using namespace deparent_helpers;
if (parent_ == nullptr)
{
return;
@ -131,9 +131,7 @@ void tr_bandwidth::setParent(tr_bandwidth* new_parent)
}
}
/***
****
***/
// ---
void tr_bandwidth::allocateBandwidth(
tr_priority_t parent_priority,
@ -259,9 +257,7 @@ void tr_bandwidth::allocate(unsigned int period_msec)
}
}
/***
****
***/
// ---
size_t tr_bandwidth::clamp(uint64_t now, tr_direction dir, size_t byte_count) const
{
@ -347,9 +343,7 @@ void tr_bandwidth::notifyBandwidthConsumed(tr_direction dir, size_t byte_count,
}
}
/***
****
***/
// ---
tr_bandwidth_limits tr_bandwidth::getLimits() const
{

View File

@ -168,6 +168,18 @@ public:
return did_change;
}
[[nodiscard]] bool is_maxed_out(tr_direction dir, uint64_t now_msec) const noexcept
{
if (!isLimited(dir))
{
return false;
}
auto const got = getPieceSpeedBytesPerSecond(now_msec, dir);
auto const want = getDesiredSpeedBytesPerSecond(dir);
return got >= want;
}
/**
* @brief Get the desired speed for the bandwidth subtree.
* @see tr_bandwidth::setDesiredSpeed

View File

@ -1097,9 +1097,10 @@ std::string tr_sys_dir_get_current(tr_error** error)
}
}
namespace
{
#ifndef HAVE_MKDIRP
static bool tr_mkdirp_(std::string_view path, int permissions, tr_error** error)
[[nodiscard]] bool tr_mkdirp_(std::string_view path, int permissions, tr_error** error)
{
auto walk = path.find_first_not_of('/'); // walk past the root
auto subpath = tr_pathbuf{};
@ -1128,8 +1129,8 @@ static bool tr_mkdirp_(std::string_view path, int permissions, tr_error** error)
return true;
}
#endif
} // namespace
bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error** error)
{

View File

@ -211,6 +211,13 @@ public:
// requests that have been made but haven't been fulfilled yet
[[nodiscard]] virtual size_t activeReqCount(tr_direction) const noexcept = 0;
[[nodiscard]] tr_bytes_per_second_t get_piece_speed_bytes_per_second(uint64_t now, tr_direction direction) const
{
auto bytes_per_second = tr_bytes_per_second_t{};
isTransferringPieces(now, direction, &bytes_per_second);
return bytes_per_second;
}
virtual void requestBlocks(tr_block_span_t const* block_spans, size_t n_spans) = 0;
struct RequestLimit

View File

@ -43,6 +43,33 @@
#define tr_logAddDebugIo(io, msg) tr_logAddDebug(msg, (io)->display_name())
#define tr_logAddTraceIo(io, msg) tr_logAddTrace(msg, (io)->display_name())
namespace
{
// Helps us to ignore errors that say "try again later"
// since that's what peer-io does by default anyway.
[[nodiscard]] auto constexpr canRetryFromError(int error_code) noexcept
{
return error_code == 0 || error_code == EAGAIN || error_code == EINTR || error_code == EINPROGRESS;
}
size_t get_desired_output_buffer_size(tr_peerIo const* io, uint64_t now)
{
// this is all kind of arbitrary, but what seems to work well is
// being large enough to hold the next 20 seconds' worth of input,
// or a few blocks, whichever is bigger. OK to tweak this as needed.
static auto constexpr PeriodSecs = 15U;
// the 3 is an arbitrary number of blocks;
// the .5 is to leave room for protocol messages
static auto constexpr Floor = static_cast<size_t>(tr_block_info::BlockSize * 3.5);
auto const current_speed_bytes_per_second = io->get_piece_speed_bytes_per_second(now, TR_UP);
return std::max(Floor, current_speed_bytes_per_second * PeriodSecs);
}
} // namespace
// ---
tr_peerIo::tr_peerIo(
tr_session* session,
tr_sha1_digest_t const* info_hash,
@ -213,15 +240,6 @@ bool tr_peerIo::reconnect()
// ---
// Helps us to ignore errors that say "try again later"
// since that's what peer-io does by default anyway.
[[nodiscard]] static auto constexpr canRetryFromError(int error_code) noexcept
{
return error_code == 0 || error_code == EAGAIN || error_code == EINTR || error_code == EINPROGRESS;
}
// ---
void tr_peerIo::did_write_wrapper(size_t bytes_transferred)
{
auto const keep_alive = shared_from_this();
@ -549,21 +567,6 @@ size_t tr_peerIo::flush_outgoing_protocol_msgs()
// ---
static size_t get_desired_output_buffer_size(tr_peerIo const* io, uint64_t now)
{
// this is all kind of arbitrary, but what seems to work well is
// being large enough to hold the next 20 seconds' worth of input,
// or a few blocks, whichever is bigger. OK to tweak this as needed.
static auto constexpr PeriodSecs = 15U;
// the 3 is an arbitrary number of blocks;
// the .5 is to leave room for protocol messages
static auto constexpr Floor = static_cast<size_t>(tr_block_info::BlockSize * 3.5);
auto const current_speed_bytes_per_second = io->get_piece_speed_bytes_per_second(now, TR_UP);
return std::max(Floor, current_speed_bytes_per_second * PeriodSecs);
}
size_t tr_peerIo::get_write_buffer_space(uint64_t now) const noexcept
{
size_t const desired_len = get_desired_output_buffer_size(this, now);

View File

@ -60,11 +60,7 @@ static auto constexpr MyflagUnreachable = int{ 2 };
static auto constexpr CancelHistorySec = int{ 60 };
/**
***
**/
static bool tr_peerMgrPeerIsSeed(tr_torrent const* tor, tr_address const& addr);
// ---
class HandshakeMediator final : public tr_handshake::Mediator
{
@ -118,11 +114,7 @@ public:
}
}
[[nodiscard]] bool is_peer_known_seed(tr_torrent_id_t tor_id, tr_address const& addr) const override
{
auto const* const tor = session_.torrents().get(tor_id);
return tor != nullptr && tr_peerMgrPeerIsSeed(tor, addr);
}
[[nodiscard]] bool is_peer_known_seed(tr_torrent_id_t tor_id, tr_address const& addr) const override;
[[nodiscard]] libtransmission::TimerMaker& timer_maker() override
{
@ -312,12 +304,15 @@ using Handshakes = std::map<tr_address, tr_handshake>;
#define tr_logAddDebugSwarm(swarm, msg) tr_logAddDebugTor((swarm)->tor, msg)
#define tr_logAddTraceSwarm(swarm, msg) tr_logAddTraceTor((swarm)->tor, msg)
static void peerCallbackFunc(tr_peer* /*peer*/, tr_peer_event const& /*e*/, void* /*vs*/);
/** @brief Opaque, per-torrent data structure for peer connection information */
class tr_swarm
{
public:
[[nodiscard]] auto unique_lock() const
{
return tor->unique_lock();
}
tr_swarm(tr_peerMgr* manager_in, tr_torrent* tor_in) noexcept
: manager{ manager_in }
, tor{ tor_in }
@ -325,6 +320,21 @@ public:
rebuildWebseeds();
}
tr_swarm(tr_swarm&&) = delete;
tr_swarm(tr_swarm const&) = delete;
tr_swarm& operator=(tr_swarm&&) = delete;
tr_swarm& operator=(tr_swarm const&) = delete;
~tr_swarm()
{
auto const lock = unique_lock();
TR_ASSERT(!is_running);
TR_ASSERT(std::empty(outgoing_handshakes));
TR_ASSERT(std::empty(peers));
}
[[nodiscard]] bool peer_is_in_use(peer_atom const& atom) const;
void cancelOldRequests()
{
auto const now = tr_time();
@ -345,11 +355,6 @@ public:
}
}
[[nodiscard]] auto unique_lock() const
{
return tor->unique_lock();
}
[[nodiscard]] uint16_t countActiveWebseeds(uint64_t now) const noexcept
{
if (!tor->isRunning || tor->isDone())
@ -445,7 +450,7 @@ public:
webseeds.reserve(n);
for (size_t i = 0; i < n; ++i)
{
webseeds.emplace_back(tr_webseedNew(tor, tor->webseed(i), peerCallbackFunc, this));
webseeds.emplace_back(tr_webseedNew(tor, tor->webseed(i), &tr_swarm::peerCallbackFunc, this));
}
webseeds.shrink_to_fit();
@ -467,14 +472,161 @@ public:
pool_is_all_seeds_.reset();
}
[[nodiscard]] peer_atom* get_existing_atom(tr_address const& addr)
[[nodiscard]] peer_atom* get_existing_atom(tr_address const& addr) noexcept
{
auto const test = [&addr](auto const& atom)
auto const iter = std::find_if(
std::begin(pool),
std::end(pool),
[&addr](auto const& atom) { return atom.addr == addr; });
return iter != std::end(pool) ? &*iter : nullptr;
}
[[nodiscard]] peer_atom const* get_existing_atom(tr_address const& addr) const noexcept
{
auto const iter = std::find_if(
std::begin(pool),
std::end(pool),
[&addr](auto const& atom) { return atom.addr == addr; });
return iter != std::end(pool) ? &*iter : nullptr;
}
[[nodiscard]] bool peer_is_a_seed(tr_address const& addr) const noexcept
{
auto const* const atom = get_existing_atom(addr);
return atom != nullptr && atom->isSeed();
}
peer_atom* ensure_atom_exists(tr_address const& addr, tr_port const port, uint8_t const flags, uint8_t const from)
{
TR_ASSERT(addr.is_valid());
TR_ASSERT(from < TR_PEER_FROM__MAX);
peer_atom* atom = get_existing_atom(addr);
if (atom == nullptr)
{
return atom.addr == addr;
};
auto const it = std::find_if(std::begin(pool), std::end(pool), test);
return it != std::end(pool) ? &*it : nullptr;
atom = &pool.emplace_back(addr, port, flags, from);
}
else
{
atom->fromBest = std::min(atom->fromBest, from);
atom->flags |= flags;
}
markAllSeedsFlagDirty();
return atom;
}
void mark_atom_as_seed(peer_atom& atom)
{
tr_logAddTraceSwarm(this, fmt::format("marking peer {} as a seed", atom.display_name()));
atom.flags |= ADDED_F_SEED_FLAG;
markAllSeedsFlagDirty();
}
static void peerCallbackFunc(tr_peer* peer, tr_peer_event const& event, void* vs)
{
TR_ASSERT(peer != nullptr);
auto* s = static_cast<tr_swarm*>(vs);
auto const lock = s->unique_lock();
switch (event.type)
{
case tr_peer_event::Type::ClientSentPieceData:
{
auto const now = tr_time();
auto* const tor = s->tor;
tor->uploadedCur += event.length;
tr_announcerAddBytes(tor, TR_ANN_UP, event.length);
tor->setDateActive(now);
tor->setDirty();
tor->session->addUploaded(event.length);
if (peer->atom != nullptr)
{
peer->atom->piece_data_time = now;
}
break;
}
case tr_peer_event::Type::ClientGotPieceData:
{
auto const now = tr_time();
auto* const tor = s->tor;
tor->downloadedCur += event.length;
tor->setDateActive(now);
tor->setDirty();
tor->session->addDownloaded(event.length);
if (peer->atom != nullptr)
{
peer->atom->piece_data_time = now;
}
break;
}
case tr_peer_event::Type::ClientGotHave:
case tr_peer_event::Type::ClientGotHaveAll:
case tr_peer_event::Type::ClientGotHaveNone:
case tr_peer_event::Type::ClientGotBitfield:
/* TODO: if we don't need these, should these events be removed? */
/* noop */
break;
case tr_peer_event::Type::ClientGotRej:
s->active_requests.remove(s->tor->pieceLoc(event.pieceIndex, event.offset).block, peer);
break;
case tr_peer_event::Type::ClientGotChoke:
s->active_requests.remove(peer);
break;
case tr_peer_event::Type::ClientGotPort:
if (peer->atom != nullptr)
{
peer->atom->port = event.port;
}
break;
case tr_peer_event::Type::ClientGotSuggest:
case tr_peer_event::Type::ClientGotAllowedFast:
// not currently supported
break;
case tr_peer_event::Type::ClientGotBlock:
{
auto* const tor = s->tor;
auto const loc = tor->pieceLoc(event.pieceIndex, event.offset);
s->cancelAllRequestsForBlock(loc.block, peer);
peer->blocks_sent_to_client.add(tr_time(), 1);
tr_torrentGotBlock(tor, loc.block);
break;
}
case tr_peer_event::Type::Error:
if (event.err == ERANGE || event.err == EMSGSIZE || event.err == ENOTCONN)
{
/* some protocol error from the peer */
peer->do_purge = true;
tr_logAddDebugSwarm(
s,
fmt::format(
"setting {} do_purge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error",
peer->display_name()));
}
else
{
tr_logAddDebugSwarm(s, fmt::format("unhandled error: {}", tr_strerror(event.err)));
}
break;
}
}
Handshakes outgoing_handshakes;
@ -607,13 +759,6 @@ private:
*** tr_peer virtual functions
**/
tr_bytes_per_second_t tr_peerGetPieceSpeedBytesPerSecond(tr_peer const* peer, uint64_t now, tr_direction direction)
{
tr_bytes_per_second_t bytes_per_second = 0;
peer->isTransferringPieces(now, direction, &bytes_per_second);
return bytes_per_second;
}
tr_peer::tr_peer(tr_torrent const* tor, peer_atom* atom_in)
: session{ tor->session }
, swarm{ tor->swarm }
@ -635,29 +780,7 @@ tr_peer::~tr_peer()
}
}
/**
***
**/
static bool peerIsInUse(tr_swarm const* swarm, struct peer_atom const* atom)
{
return atom->is_connected || swarm->outgoing_handshakes.count(atom->addr) != 0U ||
swarm->manager->incoming_handshakes.count(atom->addr) != 0U;
}
static void swarmFree(tr_swarm* s)
{
TR_ASSERT(s != nullptr);
auto const lock = s->unique_lock();
TR_ASSERT(!s->is_running);
TR_ASSERT(std::empty(s->outgoing_handshakes));
TR_ASSERT(s->peerCount() == 0);
s->stats = {};
delete s;
}
// ---
tr_peerMgr* tr_peerMgrNew(tr_session* session)
{
@ -669,9 +792,7 @@ void tr_peerMgrFree(tr_peerMgr* manager)
delete manager;
}
/***
****
***/
// ---
void tr_peerMgrOnBlocklistChanged(tr_peerMgr* mgr)
{
@ -686,26 +807,7 @@ void tr_peerMgrOnBlocklistChanged(tr_peerMgr* mgr)
}
}
/***
****
***/
static void atomSetSeed(tr_swarm* swarm, peer_atom& atom)
{
tr_logAddTraceSwarm(swarm, fmt::format("marking peer {} as a seed", atom.display_name()));
atom.flags |= ADDED_F_SEED_FLAG;
swarm->markAllSeedsFlagDirty();
}
static bool tr_peerMgrPeerIsSeed(tr_torrent const* tor, tr_address const& addr)
{
if (auto const* atom = tor->swarm->get_existing_atom(addr); atom != nullptr)
{
return atom->isSeed();
}
return false;
}
// ---
void tr_peerMgrSetUtpSupported(tr_torrent* tor, tr_address const& addr)
{
@ -848,61 +950,6 @@ void tr_peerMgr::refillUpkeep() const
}
}
static void peerSuggestedPiece(
tr_swarm const* /*s*/,
tr_peer const* /*peer*/,
tr_piece_index_t /*pieceIndex*/,
bool /*isFastAllowed*/)
{
#if 0
TR_ASSERT(t != nullptr);
TR_ASSERT(peer != nullptr);
TR_ASSERT(peer->msgs != nullptr);
/* is this a valid piece? */
if (pieceIndex >= t->tor->pieceCount())
{
return;
}
/* don't ask for it if we've already got it */
if (t->tor->hasPiece(pieceIndex))
{
return;
}
/* don't ask for it if they don't have it */
if (!peer->have.readBit(pieceIndex))
{
return;
}
/* don't ask for it if we're choked and it's not fast */
if (!isFastAllowed && peer->clientIsChoked)
{
return;
}
/* request the blocks that we don't have in this piece */
{
tr_torrent const* tor = t->tor;
auto const [begin, end] = tor->blockSpanForPiece(pieceIndex);
for (tr_block_index_t b = begin; b < end; ++b)
{
if (tor->hasBlock(b))
{
uint32_t const offset = getBlockOffsetInPiece(tor, b);
uint32_t const length = tor->blockSize(b);
tr_peerMsgsAddRequest(peer->msgs, pieceIndex, offset, length);
incrementPieceRequests(t, pieceIndex);
}
}
}
#endif
}
void tr_peerMgrPieceCompleted(tr_torrent* tor, tr_piece_index_t p)
{
bool piece_came_from_peers = false;
@ -927,141 +974,11 @@ void tr_peerMgrPieceCompleted(tr_torrent* tor, tr_piece_index_t p)
tor->set_needs_completeness_check();
}
static void peerCallbackFunc(tr_peer* peer, tr_peer_event const& event, void* vs)
namespace
{
TR_ASSERT(peer != nullptr);
auto* s = static_cast<tr_swarm*>(vs);
auto const lock = s->unique_lock();
switch (event.type)
{
case tr_peer_event::Type::ClientSentPieceData:
{
auto const now = tr_time();
auto* const tor = s->tor;
tor->uploadedCur += event.length;
tr_announcerAddBytes(tor, TR_ANN_UP, event.length);
tor->setDateActive(now);
tor->setDirty();
tor->session->addUploaded(event.length);
if (peer->atom != nullptr)
{
peer->atom->piece_data_time = now;
}
break;
}
case tr_peer_event::Type::ClientGotPieceData:
{
auto const now = tr_time();
auto* const tor = s->tor;
tor->downloadedCur += event.length;
tor->setDateActive(now);
tor->setDirty();
tor->session->addDownloaded(event.length);
if (peer->atom != nullptr)
{
peer->atom->piece_data_time = now;
}
break;
}
case tr_peer_event::Type::ClientGotHave:
case tr_peer_event::Type::ClientGotHaveAll:
case tr_peer_event::Type::ClientGotHaveNone:
case tr_peer_event::Type::ClientGotBitfield:
/* TODO: if we don't need these, should these events be removed? */
/* noop */
break;
case tr_peer_event::Type::ClientGotRej:
s->active_requests.remove(s->tor->pieceLoc(event.pieceIndex, event.offset).block, peer);
break;
case tr_peer_event::Type::ClientGotChoke:
s->active_requests.remove(peer);
break;
case tr_peer_event::Type::ClientGotPort:
if (peer->atom != nullptr)
{
peer->atom->port = event.port;
}
break;
case tr_peer_event::Type::ClientGotSuggest:
peerSuggestedPiece(s, peer, event.pieceIndex, false);
break;
case tr_peer_event::Type::ClientGotAllowedFast:
peerSuggestedPiece(s, peer, event.pieceIndex, true);
break;
case tr_peer_event::Type::ClientGotBlock:
{
auto* const tor = s->tor;
auto const loc = tor->pieceLoc(event.pieceIndex, event.offset);
s->cancelAllRequestsForBlock(loc.block, peer);
peer->blocks_sent_to_client.add(tr_time(), 1);
tr_torrentGotBlock(tor, loc.block);
break;
}
case tr_peer_event::Type::Error:
if (event.err == ERANGE || event.err == EMSGSIZE || event.err == ENOTCONN)
{
/* some protocol error from the peer */
peer->do_purge = true;
tr_logAddDebugSwarm(
s,
fmt::format(
"setting {} do_purge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error",
peer->display_name()));
}
else
{
tr_logAddDebugSwarm(s, fmt::format("unhandled error: {}", tr_strerror(event.err)));
}
break;
}
}
static struct peer_atom* ensureAtomExists(
tr_swarm* s,
tr_address const& addr,
tr_port const port,
uint8_t const flags,
uint8_t const from)
namespace handshake_helpers
{
TR_ASSERT(addr.is_valid());
TR_ASSERT(from < TR_PEER_FROM__MAX);
struct peer_atom* a = s->get_existing_atom(addr);
if (a == nullptr)
{
a = &s->pool.emplace_back(addr, port, flags, from);
}
else
{
a->fromBest = std::min(a->fromBest, from);
a->flags |= flags;
}
s->markAllSeedsFlagDirty();
return a;
}
static void createBitTorrentPeer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, struct peer_atom* atom, tr_quark client)
void create_bit_torrent_peer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io, struct peer_atom* atom, tr_quark client)
{
TR_ASSERT(atom != nullptr);
TR_ASSERT(tr_isTorrent(tor));
@ -1069,7 +986,7 @@ static void createBitTorrentPeer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io,
tr_swarm* swarm = tor->swarm;
auto* peer = tr_peerMsgsNew(tor, atom, std::move(io), peerCallbackFunc, swarm);
auto* peer = tr_peerMsgsNew(tor, atom, std::move(io), &tr_swarm::peerCallbackFunc, swarm);
peer->client = client;
atom->is_connected = true;
@ -1088,7 +1005,7 @@ static void createBitTorrentPeer(tr_torrent* tor, std::shared_ptr<tr_peerIo> io,
}
/* FIXME: this is kind of a mess. */
static bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& result)
[[nodiscard]] bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& result)
{
TR_ASSERT(result.io != nullptr);
@ -1135,7 +1052,7 @@ static bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& r
}
else /* looking good */
{
struct peer_atom* atom = ensureAtomExists(s, addr, port, 0, TR_PEER_FROM_INCOMING);
struct peer_atom* atom = s->ensure_atom_exists(addr, port, 0, TR_PEER_FROM_INCOMING);
atom->time = tr_time();
atom->piece_data_time = 0;
@ -1177,7 +1094,7 @@ static bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& r
}
result.io->set_bandwidth(&s->tor->bandwidth_);
createBitTorrentPeer(s->tor, result.io, atom, client);
create_bit_torrent_peer(s->tor, result.io, atom, client);
success = true;
}
@ -1185,9 +1102,13 @@ static bool on_handshake_done(tr_peerMgr* manager, tr_handshake::Result const& r
return success;
}
} // namespace handshake_helpers
} // namespace
void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_peer_socket&& socket)
{
using namespace handshake_helpers;
TR_ASSERT(manager->session != nullptr);
auto const lock = manager->unique_lock();
@ -1222,7 +1143,7 @@ void tr_peerMgrSetSwarmIsAllSeeds(tr_torrent* tor)
for (auto& atom : swarm->pool)
{
atomSetSeed(swarm, atom);
swarm->mark_atom_as_seed(atom);
}
swarm->markAllSeedsFlagDirty();
@ -1239,7 +1160,7 @@ size_t tr_peerMgrAddPex(tr_torrent* tor, uint8_t from, tr_pex const* pex, size_t
if (tr_isPex(pex) && /* safeguard against corrupt data */
!s->manager->session->addressIsBlocked(pex->addr) && pex->is_valid_for_peers())
{
ensureAtomExists(s, pex->addr, pex->port, pex->flags, from);
s->ensure_atom_exists(pex->addr, pex->port, pex->flags, from);
++n_used;
}
}
@ -1295,9 +1216,7 @@ std::vector<tr_pex> tr_pex::from_compact_ipv6(
return pex;
}
/**
***
**/
// ---
void tr_peerMgrGotBadPiece(tr_torrent* tor, tr_piece_index_t piece_index)
{
@ -1366,7 +1285,7 @@ struct CompareAtomsByUsefulness
return false;
}
if (peerIsInUse(tor->swarm, &atom))
if (tor->swarm->peer_is_in_use(atom))
{
return true;
}
@ -1483,28 +1402,31 @@ void tr_peerMgrRemoveTorrent(tr_torrent* tor)
auto const lock = tor->unique_lock();
tor->swarm->stop();
swarmFree(tor->swarm);
delete tor->swarm;
tor->swarm = nullptr;
}
void tr_peerMgrOnTorrentGotMetainfo(tr_torrent* tor)
{
auto* const swarm = tor->swarm;
/* the webseed list may have changed... */
tor->swarm->rebuildWebseeds();
swarm->rebuildWebseeds();
/* some peer_msgs' progress fields may not be accurate if we
didn't have the metadata before now... so refresh them all... */
for (auto* peer : tor->swarm->peers)
for (auto* peer : swarm->peers)
{
peer->onTorrentGotMetainfo();
if (peer->isSeed())
{
atomSetSeed(tor->swarm, *peer->atom);
swarm->mark_atom_as_seed(*peer->atom);
}
}
/* update the bittorrent peers' willingness... */
for (auto* peer : tor->swarm->peers)
for (auto* peer : swarm->peers)
{
peer->update_active(TR_UP);
peer->update_active(TR_DOWN);
@ -1640,8 +1562,8 @@ namespace peer_stat_helpers
stats.progress = peer->percentDone();
stats.isUTP = peer->is_utp_connection();
stats.isEncrypted = peer->is_encrypted();
stats.rateToPeer_KBps = tr_toSpeedKBps(tr_peerGetPieceSpeedBytesPerSecond(peer, now_msec, TR_CLIENT_TO_PEER));
stats.rateToClient_KBps = tr_toSpeedKBps(tr_peerGetPieceSpeedBytesPerSecond(peer, now_msec, TR_PEER_TO_CLIENT));
stats.rateToPeer_KBps = tr_toSpeedKBps(peer->get_piece_speed_bytes_per_second(now_msec, TR_CLIENT_TO_PEER));
stats.rateToClient_KBps = tr_toSpeedKBps(peer->get_piece_speed_bytes_per_second(now_msec, TR_PEER_TO_CLIENT));
stats.peerIsChoked = peer->is_peer_choked();
stats.peerIsInterested = peer->is_peer_interested();
stats.clientIsChoked = peer->is_client_choked();
@ -1989,21 +1911,7 @@ void rechokeDownloads(tr_swarm* s)
} // namespace rechoke_downloads_helpers
/**
***
**/
[[nodiscard]] static inline bool isBandwidthMaxedOut(tr_bandwidth const& b, uint64_t const now_msec, tr_direction dir)
{
if (!b.isLimited(dir))
{
return false;
}
auto const got = b.getPieceSpeedBytesPerSecond(now_msec, dir);
auto const want = b.getDesiredSpeedBytesPerSecond(dir);
return got >= want;
}
// ---
namespace rechoke_uploads_helpers
{
@ -2060,19 +1968,19 @@ struct ChokeData
{
if (tor->isDone())
{
return tr_peerGetPieceSpeedBytesPerSecond(peer, now, TR_CLIENT_TO_PEER);
return peer->get_piece_speed_bytes_per_second(now, TR_CLIENT_TO_PEER);
}
/* downloading a private torrent... take upload speed into account
* because there may only be a small window of opportunity to share */
if (tor->isPrivate())
{
return tr_peerGetPieceSpeedBytesPerSecond(peer, now, TR_PEER_TO_CLIENT) +
tr_peerGetPieceSpeedBytesPerSecond(peer, now, TR_CLIENT_TO_PEER);
return peer->get_piece_speed_bytes_per_second(now, TR_PEER_TO_CLIENT) +
peer->get_piece_speed_bytes_per_second(now, TR_CLIENT_TO_PEER);
}
/* downloading a public torrent */
return tr_peerGetPieceSpeedBytesPerSecond(peer, now, TR_PEER_TO_CLIENT);
return peer->get_piece_speed_bytes_per_second(now, TR_PEER_TO_CLIENT);
}
// an optimistically unchoked peer is immune from rechoking
@ -2091,7 +1999,7 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
choked.reserve(peer_count);
auto const* const session = s->manager->session;
bool const choke_all = !s->tor->clientCanUpload();
bool const is_maxed_out = isBandwidthMaxedOut(s->tor->bandwidth_, now, TR_UP);
bool const is_maxed_out = s->tor->bandwidth_.is_maxed_out(TR_UP, now);
/* an optimistic unchoke peer's "optimistic"
* state lasts for N calls to rechokeUploads(). */
@ -2509,11 +2417,13 @@ void tr_peerMgr::bandwidthPulse()
reconnectPulse();
}
/***
****
****
****
***/
// ---
bool tr_swarm::peer_is_in_use(peer_atom const& atom) const
{
return atom.is_connected || outgoing_handshakes.count(atom.addr) != 0U ||
manager->incoming_handshakes.count(atom.addr) != 0U;
}
namespace connect_helpers
{
@ -2536,7 +2446,7 @@ namespace
}
// not if we've already got a connection to them...
if (peerIsInUse(tor->swarm, &atom))
if (tor->swarm->peer_is_in_use(atom))
{
return false;
}
@ -2683,7 +2593,7 @@ struct peer_candidate
}
/* if we've already got enough speed in this torrent... */
if (seeding && isBandwidthMaxedOut(tor->bandwidth_, now_msec, TR_UP))
if (seeding && tor->bandwidth_.is_maxed_out(TR_UP, now_msec))
{
continue;
}
@ -2713,7 +2623,9 @@ struct peer_candidate
void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, peer_atom& atom)
{
time_t const now = tr_time();
using namespace handshake_helpers;
auto const now = tr_time();
bool utp = mgr->session->allowsUTP() && !atom.utp_failed;
if (atom.fromFirst == TR_PEER_FROM_PEX)
@ -2777,3 +2689,11 @@ void tr_peerMgr::makeNewPeerConnections(size_t max)
initiateConnection(this, candidate.tor->swarm, *candidate.atom);
}
}
// ---
bool HandshakeMediator::is_peer_known_seed(tr_torrent_id_t tor_id, tr_address const& addr) const
{
auto const* const tor = session_.torrents().get(tor_id);
return tor != nullptr && tor->swarm != nullptr && tor->swarm->peer_is_a_seed(addr);
}

View File

@ -216,11 +216,6 @@ void tr_peerMgrOnBlocklistChanged(tr_peerMgr* mgr);
[[nodiscard]] tr_webseed_view tr_peerMgrWebseed(tr_torrent const* tor, size_t i);
[[nodiscard]] tr_bytes_per_second_t tr_peerGetPieceSpeedBytesPerSecond(
tr_peer const* peer,
uint64_t now,
tr_direction direction);
void tr_peerMgrClearInterest(tr_torrent* tor);
void tr_peerMgrGotBadPiece(tr_torrent* tor, tr_piece_index_t piece_index);

View File

@ -549,7 +549,7 @@ private:
// Get the rate limit we should use.
// TODO: this needs to consider all the other peers as well...
uint64_t const now = tr_time_msec();
auto rate_bytes_per_second = tr_peerGetPieceSpeedBytesPerSecond(this, now, TR_PEER_TO_CLIENT);
auto rate_bytes_per_second = get_piece_speed_bytes_per_second(now, TR_PEER_TO_CLIENT);
if (torrent->usesSpeedLimit(TR_PEER_TO_CLIENT))
{
rate_bytes_per_second = std::min(rate_bytes_per_second, torrent->speedLimitBps(TR_PEER_TO_CLIENT));

View File

@ -24,7 +24,9 @@
#include "port-forwarding.h"
#include "utils.h"
static void logVal(char const* func, int ret)
namespace
{
void log_val(char const* func, int ret)
{
if (ret == NATPMP_TRYAGAIN)
{
@ -46,6 +48,7 @@ static void logVal(char const* func, int ret)
tr_strerror(errno)));
}
}
} // namespace
bool tr_natpmp::canSendCommand() const
{
@ -62,9 +65,9 @@ tr_natpmp::PulseResult tr_natpmp::pulse(tr_port local_port, bool is_enabled)
if (is_enabled && state_ == State::Discover)
{
int val = initnatpmp(&natpmp_, 0, 0);
logVal("initnatpmp", val);
log_val("initnatpmp", val);
val = sendpublicaddressrequest(&natpmp_);
logVal("sendpublicaddressrequest", val);
log_val("sendpublicaddressrequest", val);
state_ = val < 0 ? State::Err : State::RecvPub;
has_discovered_ = true;
setCommandTime();
@ -74,7 +77,7 @@ tr_natpmp::PulseResult tr_natpmp::pulse(tr_port local_port, bool is_enabled)
{
natpmpresp_t response;
auto const val = readnatpmpresponseorretry(&natpmp_, &response);
logVal("readnatpmpresponseorretry", val);
log_val("readnatpmpresponseorretry", val);
if (val >= 0)
{
@ -102,7 +105,7 @@ tr_natpmp::PulseResult tr_natpmp::pulse(tr_port local_port, bool is_enabled)
local_port_.host(),
advertised_port_.host(),
0);
logVal("sendnewportmappingrequest", val);
log_val("sendnewportmappingrequest", val);
state_ = val < 0 ? State::Err : State::RecvUnmap;
setCommandTime();
}
@ -111,7 +114,7 @@ tr_natpmp::PulseResult tr_natpmp::pulse(tr_port local_port, bool is_enabled)
{
auto resp = natpmpresp_t{};
auto const val = readnatpmpresponseorretry(&natpmp_, &resp);
logVal("readnatpmpresponseorretry", val);
log_val("readnatpmpresponseorretry", val);
if (val >= 0)
{
@ -153,7 +156,7 @@ tr_natpmp::PulseResult tr_natpmp::pulse(tr_port local_port, bool is_enabled)
local_port.host(),
local_port.host(),
LifetimeSecs);
logVal("sendnewportmappingrequest", val);
log_val("sendnewportmappingrequest", val);
state_ = val < 0 ? State::Err : State::RecvMap;
setCommandTime();
}
@ -162,7 +165,7 @@ tr_natpmp::PulseResult tr_natpmp::pulse(tr_port local_port, bool is_enabled)
{
auto resp = natpmpresp_t{};
auto const val = readnatpmpresponseorretry(&natpmp_, &resp);
logVal("readnatpmpresponseorretry", val);
log_val("readnatpmpresponseorretry", val);
if (val >= 0)
{

View File

@ -64,8 +64,6 @@
using namespace std::literals;
static auto constexpr SaveIntervalSecs = 360s;
namespace
{
namespace bandwidth_group_helpers
@ -144,6 +142,19 @@ int bandwidthGroupWrite(tr_session const* session, std::string_view config_dir)
}
} // namespace bandwidth_group_helpers
void update_bandwidth(tr_session* session, tr_direction dir)
{
if (auto const limit_bytes_per_second = session->activeSpeedLimitBps(dir); limit_bytes_per_second)
{
session->top_bandwidth_.setLimited(dir, *limit_bytes_per_second > 0U);
session->top_bandwidth_.setDesiredSpeedBytesPerSecond(dir, *limit_bytes_per_second);
}
else
{
session->top_bandwidth_.setLimited(dir, false);
}
}
} // namespace
tr_port tr_session::randomPort() const
@ -438,9 +449,27 @@ tr_session::PublicAddressResult tr_session::publicAddress(tr_address_type type)
return {};
}
/***
****
***/
// ---
namespace
{
namespace settings_helpers
{
void get_settings_filename(tr_pathbuf& setme, char const* config_dir, char const* appname)
{
if (!tr_str_is_empty(config_dir))
{
setme.assign(std::string_view{ config_dir }, "/settings.json"sv);
return;
}
auto const default_config_dir = tr_getDefaultConfigDir(appname);
setme.assign(std::string_view{ default_config_dir }, "/settings.json"sv);
}
} // namespace settings_helpers
} // namespace
void tr_sessionGetDefaultSettings(tr_variant* setme_dictionary)
{
@ -459,20 +488,10 @@ void tr_sessionGetSettings(tr_session const* session, tr_variant* setme_dictiona
tr_variantDictAddInt(setme_dictionary, TR_KEY_message_level, tr_logGetLevel());
}
static void getSettingsFilename(tr_pathbuf& setme, char const* config_dir, char const* appname)
{
if (!tr_str_is_empty(config_dir))
{
setme.assign(std::string_view{ config_dir }, "/settings.json"sv);
return;
}
auto const default_config_dir = tr_getDefaultConfigDir(appname);
setme.assign(std::string_view{ default_config_dir }, "/settings.json"sv);
}
bool tr_sessionLoadSettings(tr_variant* dict, char const* config_dir, char const* app_name)
{
using namespace settings_helpers;
TR_ASSERT(tr_variantIsDict(dict));
/* initializing the defaults: caller may have passed in some app-level defaults.
@ -486,7 +505,7 @@ bool tr_sessionLoadSettings(tr_variant* dict, char const* config_dir, char const
/* file settings override the defaults */
auto success = bool{};
auto filename = tr_pathbuf{};
getSettingsFilename(filename, config_dir, app_name);
get_settings_filename(filename, config_dir, app_name);
if (!tr_sys_path_exists(filename))
{
success = true;
@ -546,9 +565,7 @@ void tr_sessionSaveSettings(tr_session* session, char const* config_dir, tr_vari
bandwidthGroupWrite(session, config_dir);
}
/***
****
***/
// ---
struct tr_session::init_data
{
@ -648,8 +665,6 @@ void tr_session::initImpl(init_data& data)
data.done_cv.notify_one();
}
static void updateBandwidth(tr_session* session, tr_direction dir);
void tr_session::setSettings(tr_variant* settings_dict, bool force)
{
TR_ASSERT(amInSessionThread());
@ -779,8 +794,8 @@ void tr_session::setSettings(tr_session_settings&& settings_in, bool force)
// We need to update bandwidth if speed settings changed.
// It's a harmless call, so just call it instead of checking for settings changes
updateBandwidth(this, TR_UP);
updateBandwidth(this, TR_DOWN);
update_bandwidth(this, TR_UP);
update_bandwidth(this, TR_DOWN);
}
void tr_sessionSet(tr_session* session, tr_variant* settings)
@ -1018,19 +1033,6 @@ std::optional<tr_bytes_per_second_t> tr_session::activeSpeedLimitBps(tr_directio
return {};
}
static void updateBandwidth(tr_session* session, tr_direction dir)
{
if (auto const limit_bytes_per_second = session->activeSpeedLimitBps(dir); limit_bytes_per_second)
{
session->top_bandwidth_.setLimited(dir, *limit_bytes_per_second > 0U);
session->top_bandwidth_.setDesiredSpeedBytesPerSecond(dir, *limit_bytes_per_second);
}
else
{
session->top_bandwidth_.setLimited(dir, false);
}
}
time_t tr_session::AltSpeedMediator::time()
{
return tr_time();
@ -1040,8 +1042,8 @@ void tr_session::AltSpeedMediator::isActiveChanged(bool is_active, tr_session_al
{
auto const in_session_thread = [session = &session_, is_active, reason]()
{
updateBandwidth(session, TR_UP);
updateBandwidth(session, TR_DOWN);
update_bandwidth(session, TR_UP);
update_bandwidth(session, TR_DOWN);
if (session->alt_speed_active_changed_func_ != nullptr)
{
@ -1074,7 +1076,7 @@ void tr_sessionSetSpeedLimit_KBps(tr_session* session, tr_direction dir, tr_kilo
session->settings_.speed_limit_up = limit;
}
updateBandwidth(session, dir);
update_bandwidth(session, dir);
}
tr_kilobytes_per_second_t tr_sessionGetSpeedLimit_KBps(tr_session const* session, tr_direction dir)
@ -1099,7 +1101,7 @@ void tr_sessionLimitSpeed(tr_session* session, tr_direction dir, bool limited)
session->settings_.speed_limit_up_enabled = limited;
}
updateBandwidth(session, dir);
update_bandwidth(session, dir);
}
bool tr_sessionIsSpeedLimited(tr_session const* session, tr_direction dir)
@ -1120,7 +1122,7 @@ void tr_sessionSetAltSpeed_KBps(tr_session* session, tr_direction dir, tr_kiloby
TR_ASSERT(tr_isDirection(dir));
session->alt_speeds_.setLimitKBps(dir, limit);
updateBandwidth(session, dir);
update_bandwidth(session, dir);
}
tr_kilobytes_per_second_t tr_sessionGetAltSpeed_KBps(tr_session const* session, tr_direction dir)
@ -1238,9 +1240,7 @@ uint16_t tr_sessionGetPeerLimitPerTorrent(tr_session const* session)
return session->peerLimitPerTorrent();
}
/***
****
***/
// ---
void tr_sessionSetPaused(tr_session* session, bool is_paused)
{
@ -1263,18 +1263,12 @@ void tr_sessionSetDeleteSource(tr_session* session, bool delete_source)
session->settings_.should_delete_source_torrents = delete_source;
}
/***
****
***/
static tr_kilobytes_per_second_t tr_sessionGetRawSpeed_Bps(tr_session const* session, tr_direction dir)
{
return session != nullptr ? session->top_bandwidth_.getRawSpeedBytesPerSecond(0, dir) : 0;
}
// ---
double tr_sessionGetRawSpeed_KBps(tr_session const* session, tr_direction dir)
{
return tr_toSpeedKBps(tr_sessionGetRawSpeed_Bps(session, dir));
auto const bps = session != nullptr ? session->top_bandwidth_.getRawSpeedBytesPerSecond(0, dir) : 0;
return tr_toSpeedKBps(bps);
}
void tr_session::closeImplPart1(std::promise<void>* closed_promise, std::chrono::time_point<std::chrono::steady_clock> deadline)
@ -1370,7 +1364,11 @@ void tr_sessionClose(tr_session* session, size_t timeout_secs)
delete session;
}
static void sessionLoadTorrents(tr_session* session, tr_ctor* ctor, std::promise<size_t>* loaded_promise)
namespace
{
namespace load_torrents_helpers
{
void session_load_torrents(tr_session* session, tr_ctor* ctor, std::promise<size_t>* loaded_promise)
{
auto const& dirname = session->torrentDir();
auto const info = tr_sys_path_get_info(dirname);
@ -1414,13 +1412,17 @@ static void sessionLoadTorrents(tr_session* session, tr_ctor* ctor, std::promise
loaded_promise->set_value(n_torrents);
}
} // namespace load_torrents_helpers
} // namespace
size_t tr_sessionLoadTorrents(tr_session* session, tr_ctor* ctor)
{
using namespace load_torrents_helpers;
auto loaded_promise = std::promise<size_t>{};
auto loaded_future = loaded_promise.get_future();
session->runInSessionThread(sessionLoadTorrents, session, ctor, &loaded_promise);
session->runInSessionThread(session_load_torrents, session, ctor, &loaded_promise);
loaded_future.wait();
auto const n_torrents = loaded_future.get();
@ -2129,6 +2131,7 @@ void tr_sessionClearStats(tr_session* session)
namespace
{
auto constexpr SaveIntervalSecs = 360s;
auto makeResumeDir(std::string_view config_dir)
{

View File

@ -62,9 +62,7 @@ struct tr_ctor
}
};
/***
****
***/
// ---
bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_error** error)
{
@ -128,9 +126,7 @@ bool tr_ctorSaveContents(tr_ctor const* ctor, std::string_view filename, tr_erro
return tr_saveFile(filename, ctor->contents, error);
}
/***
****
***/
// ---
void tr_ctorSetFilePriorities(tr_ctor* ctor, tr_file_index_t const* files, tr_file_index_t file_count, tr_priority_t priority)
{
@ -169,9 +165,7 @@ void tr_ctorInitTorrentWanted(tr_ctor const* ctor, tr_torrent* tor)
tor->initFilesWanted(std::data(ctor->wanted), std::size(ctor->wanted), true);
}
/***
****
***/
// ---
void tr_ctorSetDeleteSource(tr_ctor* ctor, bool delete_source)
{
@ -194,9 +188,7 @@ bool tr_ctorGetDeleteSource(tr_ctor const* ctor, bool* setme)
return true;
}
/***
****
***/
// ---
void tr_ctorSetPaused(tr_ctor* ctor, tr_ctorMode mode, bool paused)
{
@ -308,21 +300,16 @@ tr_session* tr_ctorGetSession(tr_ctor const* ctor)
return const_cast<tr_session*>(ctor->session);
}
/***
****
***/
static bool isPriority(int i)
{
return i == TR_PRI_LOW || i == TR_PRI_NORMAL || i == TR_PRI_HIGH;
}
// ---
void tr_ctorSetBandwidthPriority(tr_ctor* ctor, tr_priority_t priority)
{
if (isPriority(priority))
if (priority != TR_PRI_LOW && priority != TR_PRI_NORMAL && priority != TR_PRI_HIGH)
{
ctor->priority = priority;
return;
}
ctor->priority = priority;
}
tr_priority_t tr_ctorGetBandwidthPriority(tr_ctor const* ctor)
@ -330,9 +317,7 @@ tr_priority_t tr_ctorGetBandwidthPriority(tr_ctor const* ctor)
return ctor->priority;
}
/***
****
***/
// ---
void tr_ctorSetLabels(tr_ctor* ctor, tr_quark const* labels, size_t n_labels)
{
@ -344,9 +329,7 @@ tr_torrent::labels_t const& tr_ctorGetLabels(tr_ctor const* ctor)
return ctor->labels;
}
/***
****
***/
// ---
tr_ctor* tr_ctorNew(tr_session const* session)
{

View File

@ -28,13 +28,6 @@
#include "utils.h"
#include "variant.h"
/***
****
***/
/* don't ask for the same metadata piece more than this often */
static auto constexpr MinRepeatIntervalSecs = int{ 3 };
struct metadata_node
{
time_t requested_at = 0U;
@ -51,7 +44,12 @@ struct tr_incomplete_metadata
int piece_count = 0;
};
static auto create_all_needed(int n_pieces)
namespace
{
// don't ask for the same metadata piece more than this often
auto constexpr MinRepeatIntervalSecs = int{ 3 };
auto create_all_needed(int n_pieces)
{
auto ret = std::deque<metadata_node>{};
@ -64,6 +62,7 @@ static auto create_all_needed(int n_pieces)
return ret;
}
} // namespace
bool tr_torrentSetMetadataSizeHint(tr_torrent* tor, int64_t size)
{
@ -151,14 +150,54 @@ std::optional<std::vector<std::byte>> tr_torrentGetMetadataPiece(tr_torrent cons
return buf;
}
static size_t getPieceLength(struct tr_incomplete_metadata const* m, int piece)
bool tr_torrentUseMetainfoFromFile(
tr_torrent* tor,
tr_torrent_metainfo const* metainfo,
char const* filename_in,
tr_error** error)
{
// add .torrent file
if (!tr_sys_path_copy(filename_in, tor->torrentFile(), error))
{
return false;
}
// remove .magnet file
tr_sys_path_remove(tor->magnetFile());
// tor should keep this metainfo
tor->setMetainfo(*metainfo);
if (tor->incompleteMetadata != nullptr)
{
delete tor->incompleteMetadata;
tor->incompleteMetadata = nullptr;
}
tor->isStopping = true;
tor->magnetVerify = true;
if (tor->session->shouldPauseAddedTorrents())
{
tor->startAfterVerify = false;
}
tor->markEdited();
return true;
}
// ---
namespace
{
namespace set_metadata_piece_helpers
{
[[nodiscard]] constexpr size_t get_piece_length(struct tr_incomplete_metadata const* m, int piece)
{
return piece + 1 == m->piece_count ? // last piece
std::size(m->metadata) - (piece * METADATA_PIECE_SIZE) :
METADATA_PIECE_SIZE;
}
static void tr_buildMetainfoExceptInfoDict(tr_torrent_metainfo const& tm, tr_variant* top)
void build_metainfo_except_info_dict(tr_torrent_metainfo const& tm, tr_variant* top)
{
tr_variantInitDict(top, 6);
@ -216,41 +255,7 @@ static void tr_buildMetainfoExceptInfoDict(tr_torrent_metainfo const& tm, tr_var
}
}
bool tr_torrentUseMetainfoFromFile(
tr_torrent* tor,
tr_torrent_metainfo const* metainfo,
char const* filename_in,
tr_error** error)
{
// add .torrent file
if (!tr_sys_path_copy(filename_in, tor->torrentFile(), error))
{
return false;
}
// remove .magnet file
tr_sys_path_remove(tor->magnetFile());
// tor should keep this metainfo
tor->setMetainfo(*metainfo);
if (tor->incompleteMetadata != nullptr)
{
delete tor->incompleteMetadata;
tor->incompleteMetadata = nullptr;
}
tor->isStopping = true;
tor->magnetVerify = true;
if (tor->session->shouldPauseAddedTorrents())
{
tor->startAfterVerify = false;
}
tor->markEdited();
return true;
}
static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_error** error)
bool use_new_metainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_error** error)
{
// test the info_dict checksum
if (tr_sha1::digest(m->metadata) != tor->infoHash())
@ -267,7 +272,7 @@ static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_
// yay we have an info dict. Let's make a torrent file
auto top_v = tr_variant{};
tr_buildMetainfoExceptInfoDict(tor->metainfo_, &top_v);
build_metainfo_except_info_dict(tor->metainfo_, &top_v);
tr_variantMergeDicts(tr_variantDictAddDict(&top_v, TR_KEY_info, 0), &info_dict_v);
auto const benc = tr_variantToStr(&top_v, TR_VARIANT_FMT_BENC);
tr_variantClear(&top_v);
@ -295,10 +300,10 @@ static bool useNewMetainfo(tr_torrent* tor, tr_incomplete_metadata const* m, tr_
return true;
}
static void onHaveAllMetainfo(tr_torrent* tor, tr_incomplete_metadata* m)
void on_have_all_metainfo(tr_torrent* tor, tr_incomplete_metadata* m)
{
tr_error* error = nullptr;
if (useNewMetainfo(tor, m, &error))
if (use_new_metainfo(tor, m, &error))
{
delete tor->incompleteMetadata;
tor->incompleteMetadata = nullptr;
@ -329,9 +334,13 @@ static void onHaveAllMetainfo(tr_torrent* tor, tr_incomplete_metadata* m)
tr_error_clear(&error);
}
}
} // namespace set_metadata_piece_helpers
} // namespace
void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, size_t len)
{
using namespace set_metadata_piece_helpers;
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(data != nullptr);
@ -351,7 +360,7 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, si
}
// sanity test: is `len` the right size?
if (getPieceLength(m, piece) != len)
if (get_piece_length(m, piece) != len)
{
return;
}
@ -377,10 +386,12 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, si
if (std::empty(needed))
{
tr_logAddDebugTor(tor, fmt::format("metainfo piece {} was the last one", piece));
onHaveAllMetainfo(tor, m);
on_have_all_metainfo(tor, m);
}
}
// ---
std::optional<int> tr_torrentGetNextMetadataRequest(tr_torrent* tor, time_t now)
{
TR_ASSERT(tr_isTorrent(tor));

View File

@ -122,9 +122,19 @@ public:
/// SPEED LIMIT
[[nodiscard]] constexpr auto& bandwidth() noexcept
{
return bandwidth_;
}
[[nodiscard]] constexpr auto const& bandwidth() const noexcept
{
return bandwidth_;
}
constexpr void setSpeedLimitBps(tr_direction dir, tr_bytes_per_second_t bytes_per_second)
{
if (bandwidth_.setDesiredSpeedBytesPerSecond(dir, bytes_per_second))
if (bandwidth().setDesiredSpeedBytesPerSecond(dir, bytes_per_second))
{
setDirty();
}
@ -132,7 +142,7 @@ public:
constexpr void useSpeedLimit(tr_direction dir, bool do_use)
{
if (bandwidth_.setLimited(dir, do_use))
if (bandwidth().setLimited(dir, do_use))
{
setDirty();
}
@ -140,17 +150,17 @@ public:
[[nodiscard]] constexpr auto speedLimitBps(tr_direction dir) const
{
return bandwidth_.getDesiredSpeedBytesPerSecond(dir);
return bandwidth().getDesiredSpeedBytesPerSecond(dir);
}
[[nodiscard]] constexpr auto usesSessionLimits() const noexcept
{
return bandwidth_.areParentLimitsHonored(TR_UP);
return bandwidth().areParentLimitsHonored(TR_UP);
}
[[nodiscard]] constexpr auto usesSpeedLimit(tr_direction dir) const noexcept
{
return bandwidth_.isLimited(dir);
return bandwidth().isLimited(dir);
}
/// BLOCK INFO
@ -673,7 +683,7 @@ public:
[[nodiscard]] constexpr auto getPriority() const noexcept
{
return bandwidth_.getPriority();
return bandwidth().getPriority();
}
[[nodiscard]] constexpr auto const& bandwidthGroup() const noexcept