refactor: misc-use-anonymous-namespace pt. 5 (#4552)
This commit is contained in:
parent
cb10255ef1
commit
d9278bd167
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue