refactor: timer pt 2 (#3617)

* feat: add convenience variants of TimerMaker::create()

* refactor: use libtransmission::Timer in peer-mgr

* refactor: use libtransmission::Timer in peer-msgs

* refactor: use libtransmission::Timer in tr-utp

* refactor: use libtransmission::Timer in tr-dht

* refactor: use libtransmission::Timer in port-forwarding

* refactor: use libtransmission::Timer in webseed

* refactor: use libtransmission::Timer in tr-lpd

* refactor: use libtransmission::Timer in rpc-server

* chore: remove unused function tr_timerAdd()

* chore: remove unused function tr_gettimeofday()

* fixup! chore: remove unused function tr_timerAdd()

* fixup! refactor: use libtransmission::Timer in port-forwarding
This commit is contained in:
Charles Kerr 2022-08-11 12:28:37 -05:00 committed by GitHub
parent 7c152c1db4
commit 63eab54fd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 214 additions and 340 deletions

View File

@ -181,7 +181,7 @@ jobs:
run: brew install cmake gettext libdeflate libevent libnatpmp libpsl miniupnpc ninja run: brew install cmake gettext libdeflate libevent libnatpmp libpsl miniupnpc ninja
- name: Get Dependencies (GTK) - name: Get Dependencies (GTK)
if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }} if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }}
run: brew install gtkmm3 run: brew install gtkmm3 libjpeg
- name: Get Dependencies (Qt) - name: Get Dependencies (Qt)
if: ${{ needs.what-to-make.outputs.make-qt == 'true' }} if: ${{ needs.what-to-make.outputs.make-qt == 'true' }}
run: brew install qt@5 run: brew install qt@5
@ -349,7 +349,7 @@ jobs:
run: brew install cmake gettext libdeflate libevent libnatpmp libpsl miniupnpc ninja run: brew install cmake gettext libdeflate libevent libnatpmp libpsl miniupnpc ninja
- name: Get Dependencies (GTK) - name: Get Dependencies (GTK)
if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }} if: ${{ needs.what-to-make.outputs.make-gtk == 'true' }}
run: brew install gtkmm3 run: brew install gtkmm3 libjpeg
- name: Get Dependencies (Qt) - name: Get Dependencies (Qt)
if: ${{ needs.what-to-make.outputs.make-qt == 'true' }} if: ${{ needs.what-to-make.outputs.make-qt == 'true' }}
run: brew install qt@5 run: brew install qt@5

View File

@ -5,6 +5,7 @@
#include <algorithm> #include <algorithm>
#include <cerrno> /* error codes ERANGE, ... */ #include <cerrno> /* error codes ERANGE, ... */
#include <chrono>
#include <climits> /* INT_MAX */ #include <climits> /* INT_MAX */
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
@ -18,8 +19,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <event2/event.h>
#include <fmt/format.h> #include <fmt/format.h>
#define LIBTRANSMISSION_PEER_MODULE #define LIBTRANSMISSION_PEER_MODULE
@ -48,6 +47,8 @@
#include "utils.h" #include "utils.h"
#include "webseed.h" #include "webseed.h"
using namespace std::literals;
// use for bitwise operations w/peer_atom.flags2 // use for bitwise operations w/peer_atom.flags2
static auto constexpr MyflagBanned = int{ 1 }; static auto constexpr MyflagBanned = int{ 1 };
@ -560,27 +561,17 @@ private:
bool is_endgame_ = false; bool is_endgame_ = false;
}; };
struct EventDeleter
{
void operator()(struct event* ev) const
{
event_free(ev);
}
};
using UniqueTimer = std::unique_ptr<struct event, EventDeleter>;
struct tr_peerMgr struct tr_peerMgr
{ {
explicit tr_peerMgr(tr_session* session_in) explicit tr_peerMgr(tr_session* session_in)
: session{ session_in } : session{ session_in }
, bandwidth_timer_{ evtimer_new(session->eventBase(), bandwidthPulseMarshall, this) } , bandwidth_timer_{ session->timerMaker().create([this]() { bandwidthPulse(); }) }
, rechoke_timer_{ evtimer_new(session->eventBase(), rechokePulseMarshall, this) } , rechoke_timer_{ session->timerMaker().create([this]() { rechokePulseMarshall(); }) }
, refill_upkeep_timer_{ evtimer_new(session->eventBase(), refillUpkeepMarshall, this) } , refill_upkeep_timer_{ session->timerMaker().create([this]() { refillUpkeep(); }) }
{ {
tr_timerAddMsec(*bandwidth_timer_, BandwidthPeriodMsec); bandwidth_timer_->startRepeating(BandwidthPeriod);
tr_timerAddMsec(*rechoke_timer_, RechokePeriodMsec); rechoke_timer_->startSingleShot(RechokePeriod);
tr_timerAddMsec(*refill_upkeep_timer_, RefillUpkeepPeriodMsec); refill_upkeep_timer_->startRepeating(RefillUpkeepPeriod);
} }
tr_peerMgr(tr_peerMgr&&) = delete; tr_peerMgr(tr_peerMgr&&) = delete;
@ -601,7 +592,7 @@ struct tr_peerMgr
void rechokeSoon() noexcept void rechokeSoon() noexcept
{ {
tr_timerAddMsec(*rechoke_timer_, 100); rechoke_timer_->startSingleShot(100ms);
} }
void bandwidthPulse(); void bandwidthPulse();
@ -614,34 +605,19 @@ struct tr_peerMgr
Handshakes incoming_handshakes; Handshakes incoming_handshakes;
private: private:
static void bandwidthPulseMarshall(evutil_socket_t, short /*reason*/, void* vmgr) void rechokePulseMarshall()
{ {
auto* const self = static_cast<tr_peerMgr*>(vmgr); rechokePulse();
self->bandwidthPulse(); rechoke_timer_->startSingleShot(RechokePeriod);
tr_timerAddMsec(*self->bandwidth_timer_, BandwidthPeriodMsec);
} }
static void rechokePulseMarshall(evutil_socket_t, short /*reason*/, void* vmgr) std::unique_ptr<libtransmission::Timer> const bandwidth_timer_;
{ std::unique_ptr<libtransmission::Timer> const rechoke_timer_;
auto* const self = static_cast<tr_peerMgr*>(vmgr); std::unique_ptr<libtransmission::Timer> const refill_upkeep_timer_;
self->rechokePulse();
tr_timerAddMsec(*self->rechoke_timer_, RechokePeriodMsec);
}
static void refillUpkeepMarshall(evutil_socket_t, short /*reason*/, void* vmgr) static auto constexpr BandwidthPeriod = 500ms;
{ static auto constexpr RechokePeriod = 10s;
auto* const self = static_cast<tr_peerMgr*>(vmgr); static auto constexpr RefillUpkeepPeriod = 10s;
self->refillUpkeep();
tr_timerAddMsec(*self->refill_upkeep_timer_, RefillUpkeepPeriodMsec);
}
UniqueTimer const bandwidth_timer_;
UniqueTimer const rechoke_timer_;
UniqueTimer const refill_upkeep_timer_;
static auto constexpr BandwidthPeriodMsec = int{ 500 };
static auto constexpr RechokePeriodMsec = int{ 10 * 1000 };
static auto constexpr RefillUpkeepPeriodMsec = int{ 10 * 1000 };
// how frequently to decide which peers live and die // how frequently to decide which peers live and die
static auto constexpr ReconnectPeriodMsec = int{ 500 }; static auto constexpr ReconnectPeriodMsec = int{ 500 };
@ -2579,8 +2555,9 @@ void tr_peerMgr::bandwidthPulse()
pumpAllPeers(this); pumpAllPeers(this);
/* allocate bandwidth to the peers */ /* allocate bandwidth to the peers */
session->top_bandwidth_.allocate(TR_UP, BandwidthPeriodMsec); auto const msec = std::chrono::duration_cast<std::chrono::milliseconds>(BandwidthPeriod).count();
session->top_bandwidth_.allocate(TR_DOWN, BandwidthPeriodMsec); session->top_bandwidth_.allocate(TR_UP, msec);
session->top_bandwidth_.allocate(TR_DOWN, msec);
/* torrent upkeep */ /* torrent upkeep */
for (auto* const tor : session->torrents()) for (auto* const tor : session->torrents())

View File

@ -4,7 +4,9 @@
// License text can be found in the licenses/ folder. // License text can be found in the licenses/ folder.
#include <algorithm> #include <algorithm>
#include <array>
#include <cerrno> #include <cerrno>
#include <chrono>
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#include <iterator> #include <iterator>
@ -15,7 +17,6 @@
#include <event2/buffer.h> #include <event2/buffer.h>
#include <event2/bufferevent.h> #include <event2/bufferevent.h>
#include <event2/event.h>
#include <fmt/format.h> #include <fmt/format.h>
@ -43,6 +44,8 @@
#define EBADMSG EINVAL #define EBADMSG EINVAL
#endif #endif
using namespace std::literals;
/** /**
*** ***
**/ **/
@ -113,9 +116,6 @@ auto constexpr Reject = int{ 2 };
} // namespace MetadataMsgType } // namespace MetadataMsgType
// seconds between sendPex() calls
static auto constexpr PexIntervalSecs = int{ 90 };
static auto constexpr MinChokePeriodSec = int{ 10 }; static auto constexpr MinChokePeriodSec = int{ 10 };
// idle seconds before we send a keepalive // idle seconds before we send a keepalive
@ -203,7 +203,6 @@ static void cancelAllRequestsToClient(tr_peerMsgsImpl* msgs);
static void didWrite(tr_peerIo* io, size_t bytesWritten, bool wasPieceData, void* vmsgs); static void didWrite(tr_peerIo* io, size_t bytesWritten, bool wasPieceData, void* vmsgs);
static void gotError(tr_peerIo* io, short what, void* vmsgs); static void gotError(tr_peerIo* io, short what, void* vmsgs);
static void peerPulse(void* vmsgs); static void peerPulse(void* vmsgs);
static void pexPulse(evutil_socket_t fd, short what, void* vmsgs);
static void protocolSendCancel(tr_peerMsgsImpl* msgs, struct peer_request const& req); static void protocolSendCancel(tr_peerMsgsImpl* msgs, struct peer_request const& req);
static void protocolSendChoke(tr_peerMsgsImpl* msgs, bool choke); static void protocolSendChoke(tr_peerMsgsImpl* msgs, bool choke);
static void protocolSendHave(tr_peerMsgsImpl* msgs, tr_piece_index_t index); static void protocolSendHave(tr_peerMsgsImpl* msgs, tr_piece_index_t index);
@ -212,17 +211,6 @@ static void sendInterest(tr_peerMsgsImpl* msgs, bool b);
static void sendLtepHandshake(tr_peerMsgsImpl* msgs); static void sendLtepHandshake(tr_peerMsgsImpl* msgs);
static void tellPeerWhatWeHave(tr_peerMsgsImpl* msgs); static void tellPeerWhatWeHave(tr_peerMsgsImpl* msgs);
static void updateDesiredRequestCount(tr_peerMsgsImpl* msgs); static void updateDesiredRequestCount(tr_peerMsgsImpl* msgs);
//zzz
struct EventDeleter
{
void operator()(struct event* ev) const
{
event_free(ev);
}
};
using UniqueTimer = std::unique_ptr<struct event, EventDeleter>;
#define myLogMacro(msgs, level, text) \ #define myLogMacro(msgs, level, text) \
do \ do \
@ -270,8 +258,8 @@ public:
{ {
if (torrent->allowsPex()) if (torrent->allowsPex())
{ {
pex_timer.reset(evtimer_new(torrent->session->eventBase(), pexPulse, this)); pex_timer_ = torrent->session->timerMaker().create([this]() { sendPex(); });
tr_timerAdd(*pex_timer, PexIntervalSecs, 0); pex_timer_->startRepeating(SendPexInterval);
} }
if (io->supportsUTP()) if (io->supportsUTP())
@ -671,6 +659,8 @@ public:
return RequestLimit{ max_blocks, max_blocks }; return RequestLimit{ max_blocks, max_blocks };
} }
void sendPex();
private: private:
[[nodiscard]] size_t maxAvailableReqs() const [[nodiscard]] size_t maxAvailableReqs() const
{ {
@ -856,17 +846,20 @@ public:
supplied a reqq argument, it's stored here. */ supplied a reqq argument, it's stored here. */
std::optional<size_t> reqq; std::optional<size_t> reqq;
UniqueTimer pex_timer; std::unique_ptr<libtransmission::Timer> pex_timer_;
tr_bitfield have_; tr_bitfield have_;
private: private:
bool is_active_[2] = { false, false }; std::array<bool, 2> is_active_ = { false, false };
tr_peer_callback const callback_; tr_peer_callback const callback_;
void* const callbackData_; void* const callbackData_;
mutable std::optional<float> percent_done_; mutable std::optional<float> percent_done_;
// seconds between periodic sendPex() calls
static auto constexpr SendPexInterval = 90s;
}; };
tr_peerMsgs* tr_peerMsgsNew(tr_torrent* torrent, peer_atom* atom, tr_peerIo* io, tr_peer_callback callback, void* callback_data) tr_peerMsgs* tr_peerMsgsNew(tr_torrent* torrent, peer_atom* atom, tr_peerIo* io, tr_peer_callback callback, void* callback_data)
@ -1461,8 +1454,6 @@ static void parseUtPex(tr_peerMsgsImpl* msgs, uint32_t msglen, struct evbuffer*
} }
} }
static void sendPex(tr_peerMsgsImpl* msgs);
static void parseLtep(tr_peerMsgsImpl* msgs, uint32_t msglen, struct evbuffer* inbuf) static void parseLtep(tr_peerMsgsImpl* msgs, uint32_t msglen, struct evbuffer* inbuf)
{ {
TR_ASSERT(msglen > 0); TR_ASSERT(msglen > 0);
@ -1479,7 +1470,7 @@ static void parseLtep(tr_peerMsgsImpl* msgs, uint32_t msglen, struct evbuffer* i
if (msgs->io->supportsLTEP()) if (msgs->io->supportsLTEP())
{ {
sendLtepHandshake(msgs); sendLtepHandshake(msgs);
sendPex(msgs); msgs->sendPex();
} }
} }
else if (ltep_msgid == UT_PEX_ID) else if (ltep_msgid == UT_PEX_ID)
@ -2453,31 +2444,31 @@ static void tellPeerWhatWeHave(tr_peerMsgsImpl* msgs)
} }
} }
static void sendPex(tr_peerMsgsImpl* msgs) void tr_peerMsgsImpl::sendPex()
{ {
// only send pex if both the torrent and peer support it // only send pex if both the torrent and peer support it
if (!msgs->peerSupportsPex || !msgs->torrent->allowsPex()) if (!this->peerSupportsPex || !this->torrent->allowsPex())
{ {
return; return;
} }
auto& old = msgs->pex; auto& old4 = this->pex;
auto pex = tr_peerMgrGetPeers(msgs->torrent, TR_AF_INET, TR_PEERS_CONNECTED, MaxPexPeerCount); auto new4 = tr_peerMgrGetPeers(this->torrent, TR_AF_INET, TR_PEERS_CONNECTED, MaxPexPeerCount);
auto added = std::vector<tr_pex>{}; auto added = std::vector<tr_pex>{};
added.reserve(std::size(pex)); added.reserve(std::size(new4));
std::set_difference(std::begin(pex), std::end(pex), std::begin(old), std::end(old), std::back_inserter(added)); std::set_difference(std::begin(new4), std::end(new4), std::begin(old4), std::end(old4), std::back_inserter(added));
auto dropped = std::vector<tr_pex>{}; auto dropped = std::vector<tr_pex>{};
dropped.reserve(std::size(old)); dropped.reserve(std::size(old4));
std::set_difference(std::begin(old), std::end(old), std::begin(pex), std::end(pex), std::back_inserter(dropped)); std::set_difference(std::begin(old4), std::end(old4), std::begin(new4), std::end(new4), std::back_inserter(dropped));
auto& old6 = msgs->pex6; auto& old6 = this->pex6;
auto pex6 = tr_peerMgrGetPeers(msgs->torrent, TR_AF_INET6, TR_PEERS_CONNECTED, MaxPexPeerCount); auto new6 = tr_peerMgrGetPeers(this->torrent, TR_AF_INET6, TR_PEERS_CONNECTED, MaxPexPeerCount);
auto added6 = std::vector<tr_pex>{}; auto added6 = std::vector<tr_pex>{};
added6.reserve(std::size(pex6)); added6.reserve(std::size(new6));
std::set_difference(std::begin(pex6), std::end(pex6), std::begin(old6), std::end(old6), std::back_inserter(added6)); std::set_difference(std::begin(new6), std::end(new6), std::begin(old6), std::end(old6), std::back_inserter(added6));
auto dropped6 = std::vector<tr_pex>{}; auto dropped6 = std::vector<tr_pex>{};
dropped6.reserve(std::size(old6)); dropped6.reserve(std::size(old6));
std::set_difference(std::begin(old6), std::end(old6), std::begin(pex6), std::end(pex6), std::back_inserter(dropped6)); std::set_difference(std::begin(old6), std::end(old6), std::begin(new6), std::end(new6), std::back_inserter(dropped6));
// Some peers give us error messages if we send // Some peers give us error messages if we send
// more than this many peers in a single pex message. // more than this many peers in a single pex message.
@ -2490,13 +2481,13 @@ static void sendPex(tr_peerMsgsImpl* msgs)
dropped6.resize(std::min(std::size(dropped6), MaxPexDropped)); dropped6.resize(std::min(std::size(dropped6), MaxPexDropped));
logtrace( logtrace(
msgs, this,
fmt::format( fmt::format(
FMT_STRING("pex: old peer count {:d}+{:d}, new peer count {:d}+{:d}, added {:d}+{:d}, dropped {:d}+{:d}"), FMT_STRING("pex: old peer count {:d}+{:d}, new peer count {:d}+{:d}, added {:d}+{:d}, dropped {:d}+{:d}"),
std::size(old), std::size(old4),
std::size(old6), std::size(old6),
std::size(pex), std::size(new4),
std::size(pex6), std::size(new6),
std::size(added), std::size(added),
std::size(added6), std::size(added6),
std::size(dropped), std::size(dropped),
@ -2508,11 +2499,11 @@ static void sendPex(tr_peerMsgsImpl* msgs)
return; return;
} }
evbuffer* const out = msgs->outMessages; evbuffer* const out = this->outMessages;
// update msgs // update msgs
std::swap(old, pex); std::swap(old4, new4);
std::swap(old6, pex6); std::swap(old6, new6);
// build the pex payload // build the pex payload
auto val = tr_variant{}; auto val = tr_variant{};
@ -2622,22 +2613,12 @@ static void sendPex(tr_peerMsgsImpl* msgs)
auto* const payload = tr_variantToBuf(&val, TR_VARIANT_FMT_BENC); auto* const payload = tr_variantToBuf(&val, TR_VARIANT_FMT_BENC);
evbuffer_add_uint32(out, 2 * sizeof(uint8_t) + evbuffer_get_length(payload)); evbuffer_add_uint32(out, 2 * sizeof(uint8_t) + evbuffer_get_length(payload));
evbuffer_add_uint8(out, BtPeerMsgs::Ltep); evbuffer_add_uint8(out, BtPeerMsgs::Ltep);
evbuffer_add_uint8(out, msgs->ut_pex_id); evbuffer_add_uint8(out, this->ut_pex_id);
evbuffer_add_buffer(out, payload); evbuffer_add_buffer(out, payload);
msgs->pokeBatchPeriod(HighPriorityIntervalSecs); this->pokeBatchPeriod(HighPriorityIntervalSecs);
logtrace(msgs, fmt::format(FMT_STRING("sending a pex message; outMessage size is now {:d}"), evbuffer_get_length(out))); logtrace(this, fmt::format(FMT_STRING("sending a pex message; outMessage size is now {:d}"), evbuffer_get_length(out)));
msgs->dbgOutMessageLen(); this->dbgOutMessageLen();
evbuffer_free(payload); evbuffer_free(payload);
tr_variantFree(&val); tr_variantFree(&val);
} }
static void pexPulse(evutil_socket_t /*fd*/, short /*what*/, void* vmsgs)
{
auto* msgs = static_cast<tr_peerMsgsImpl*>(vmsgs);
sendPex(msgs);
TR_ASSERT(msgs->pex_timer);
tr_timerAdd(*msgs->pex_timer, PexIntervalSecs, 0);
}

View File

@ -4,10 +4,7 @@
// License text can be found in the licenses/ folder. // License text can be found in the licenses/ folder.
#include <algorithm> #include <algorithm>
#include <chrono>
#include <sys/types.h>
#include <event2/event.h>
#include <fmt/core.h> #include <fmt/core.h>
@ -21,22 +18,30 @@
#include "torrent.h" #include "torrent.h"
#include "tr-assert.h" #include "tr-assert.h"
#include "upnp.h" #include "upnp.h"
#include "utils.h" #include "utils.h" // for _()
using namespace std::literals;
struct tr_shared struct tr_shared
{ {
bool isEnabled; tr_shared(tr_session* session_in)
bool isShuttingDown; : session{ session_in }
bool doPortCheck; {
}
tr_port_forwarding natpmpStatus; tr_session* const session = nullptr;
tr_port_forwarding upnpStatus;
tr_upnp* upnp; bool isEnabled = false;
tr_natpmp* natpmp; bool isShuttingDown = false;
tr_session* session; bool doPortCheck = false;
struct event* timer; tr_port_forwarding natpmpStatus = TR_PORT_UNMAPPED;
tr_port_forwarding upnpStatus = TR_PORT_UNMAPPED;
tr_upnp* upnp = nullptr;
tr_natpmp* natpmp = nullptr;
std::unique_ptr<libtransmission::Timer> timer;
}; };
/*** /***
@ -109,51 +114,56 @@ static void natPulse(tr_shared* s, bool do_check)
} }
} }
static void set_evtimer_from_status(tr_shared* s) static void restartTimer(tr_shared* s)
{ {
int sec = 0; auto& timer = s->timer;
int msec = 0; if (!timer)
{
return;
}
/* when to wake up again */ // when to wake up again
switch (tr_sharedTraversalStatus(s)) switch (tr_sharedTraversalStatus(s))
{ {
case TR_PORT_MAPPED: case TR_PORT_MAPPED:
/* if we're mapped, everything is fine... check back at renew_time // if we're mapped, everything is fine... check back at `renew_time`
* to renew the port forwarding if it's expired */ // to renew the port forwarding if it's expired
s->doPortCheck = true; s->doPortCheck = true;
sec = std::max(0, int(s->natpmp->renew_time - tr_time())); if (auto const now = tr_time(); s->natpmp->renew_time > now)
{
timer->startSingleShot(std::chrono::seconds{ s->natpmp->renew_time - now });
}
else // ???
{
timer->startSingleShot(1min);
}
break; break;
case TR_PORT_ERROR: case TR_PORT_ERROR:
/* some kind of an error. wait 60 seconds and retry */ // some kind of an error. wait a minute and retry
sec = 60; timer->startSingleShot(1min);
break; break;
default: default:
/* in progress. pulse frequently. */ // in progress. pulse frequently.
msec = 333000; timer->startSingleShot(333ms);
break; break;
} }
if (s->timer != nullptr)
{
tr_timerAdd(*s->timer, sec, msec);
}
} }
static void onTimer(evutil_socket_t /*fd*/, short /*what*/, void* vshared) static void onTimer(void* vshared)
{ {
auto* s = static_cast<tr_shared*>(vshared); auto* s = static_cast<tr_shared*>(vshared);
TR_ASSERT(s != nullptr); TR_ASSERT(s != nullptr);
TR_ASSERT(s->timer != nullptr); TR_ASSERT(s->timer);
/* do something */ /* do something */
natPulse(s, s->doPortCheck); natPulse(s, s->doPortCheck);
s->doPortCheck = false; s->doPortCheck = false;
/* set up the timer for the next pulse */ /* set up the timer for the next pulse */
set_evtimer_from_status(s); restartTimer(s);
} }
/*** /***
@ -162,34 +172,12 @@ static void onTimer(evutil_socket_t /*fd*/, short /*what*/, void* vshared)
tr_shared* tr_sharedInit(tr_session* session) tr_shared* tr_sharedInit(tr_session* session)
{ {
auto* const s = tr_new0(tr_shared, 1); return new tr_shared{ session };
s->session = session;
s->isEnabled = false;
s->upnpStatus = TR_PORT_UNMAPPED;
s->natpmpStatus = TR_PORT_UNMAPPED;
#if 0
if (isEnabled)
{
s->timer = tr_new0(struct event, 1);
evtimer_set(s->timer, onTimer, s);
tr_timerAdd(s->timer, 0, 333000);
}
#endif
return s;
} }
static void stop_timer(tr_shared* s) static void stop_timer(tr_shared* s)
{ {
if (s->timer != nullptr) s->timer.reset();
{
event_free(s->timer);
s->timer = nullptr;
}
} }
static void stop_forwarding(tr_shared* s) static void stop_forwarding(tr_shared* s)
@ -210,18 +198,18 @@ static void stop_forwarding(tr_shared* s)
void tr_sharedClose(tr_session* session) void tr_sharedClose(tr_session* session)
{ {
tr_shared* s = session->shared; tr_shared* shared = session->shared;
s->isShuttingDown = true; shared->isShuttingDown = true;
stop_forwarding(s); stop_forwarding(shared);
s->session->shared = nullptr; shared->session->shared = nullptr;
tr_free(s); delete shared;
} }
static void start_timer(tr_shared* s) static void start_timer(tr_shared* s)
{ {
s->timer = evtimer_new(s->session->eventBase(), onTimer, s); s->timer = s->session->timerMaker().create(onTimer, s);
set_evtimer_from_status(s); restartTimer(s);
} }
void tr_sharedTraversalEnable(tr_shared* s, bool is_enable) void tr_sharedTraversalEnable(tr_shared* s, bool is_enable)

View File

@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cerrno> #include <cerrno>
#include <chrono>
#include <cstring> /* memcpy */ #include <cstring> /* memcpy */
#include <ctime> #include <ctime>
#include <string> #include <string>
@ -19,7 +20,6 @@
#endif #endif
#include <event2/buffer.h> #include <event2/buffer.h>
#include <event2/event.h>
#include <event2/http.h> #include <event2/http.h>
#include <event2/http_struct.h> /* TODO: eventually remove this */ #include <event2/http_struct.h> /* TODO: eventually remove this */
#include <event2/listener.h> #include <event2/listener.h>
@ -549,9 +549,8 @@ static void handle_request(struct evhttp_request* req, void* arg)
} }
static auto constexpr ServerStartRetryCount = int{ 10 }; static auto constexpr ServerStartRetryCount = int{ 10 };
static auto constexpr ServerStartRetryDelayIncrement = int{ 5 }; static auto constexpr ServerStartRetryDelayIncrement = 5s;
static auto constexpr ServerStartRetryDelayStep = int{ 3 }; static auto constexpr ServerStartRetryMaxDelay = 60s;
static auto constexpr ServerStartRetryMaxDelay = int{ 60 };
static char const* tr_rpc_address_to_string(tr_rpc_address const& addr, char* buf, size_t buflen) static char const* tr_rpc_address_to_string(tr_rpc_address const& addr, char* buf, size_t buflen)
{ {
@ -664,35 +663,22 @@ static bool bindUnixSocket(
static void startServer(tr_rpc_server* server); static void startServer(tr_rpc_server* server);
static void rpc_server_on_start_retry(evutil_socket_t /*fd*/, short /*type*/, void* context) static auto rpc_server_start_retry(tr_rpc_server* server)
{ {
startServer(static_cast<tr_rpc_server*>(context)); if (!server->start_retry_timer)
}
static int rpc_server_start_retry(tr_rpc_server* server)
{
int retry_delay = (server->start_retry_counter / ServerStartRetryDelayStep + 1) * ServerStartRetryDelayIncrement;
retry_delay = std::min(retry_delay, int{ ServerStartRetryMaxDelay });
if (server->start_retry_timer == nullptr)
{ {
server->start_retry_timer = evtimer_new(server->session->eventBase(), rpc_server_on_start_retry, server); server->start_retry_timer = server->session->timerMaker().create([server]() { startServer(server); });
} }
tr_timerAdd(*server->start_retry_timer, retry_delay, 0);
++server->start_retry_counter; ++server->start_retry_counter;
auto const interval = std::min(ServerStartRetryDelayIncrement * server->start_retry_counter, ServerStartRetryMaxDelay);
return retry_delay; server->start_retry_timer->startSingleShot(std::chrono::duration_cast<std::chrono::milliseconds>(interval));
return interval;
} }
static void rpc_server_start_retry_cancel(tr_rpc_server* server) static void rpc_server_start_retry_cancel(tr_rpc_server* server)
{ {
if (server->start_retry_timer != nullptr) server->start_retry_timer.reset();
{
event_free(server->start_retry_timer);
server->start_retry_timer = nullptr;
}
server->start_retry_counter = 0; server->start_retry_counter = 0;
} }
@ -723,9 +709,9 @@ static void startServer(tr_rpc_server* server)
if (server->start_retry_counter < ServerStartRetryCount) if (server->start_retry_counter < ServerStartRetryCount)
{ {
int const retry_delay = rpc_server_start_retry(server); auto const retry_delay = rpc_server_start_retry(server);
auto const seconds = std::chrono::duration_cast<std::chrono::seconds>(retry_delay).count();
tr_logAddDebug(fmt::format("Couldn't bind to {}, retrying in {} seconds", addr_port_str, retry_delay)); tr_logAddDebug(fmt::format("Couldn't bind to {}, retrying in {} seconds", addr_port_str, seconds));
return; return;
} }

View File

@ -17,6 +17,7 @@
#include "transmission.h" #include "transmission.h"
#include "net.h" #include "net.h"
#include "timer.h"
struct event; struct event;
struct evhttp; struct evhttp;
@ -130,7 +131,7 @@ public:
std::unique_ptr<struct tr_rpc_address> bindAddress; std::unique_ptr<struct tr_rpc_address> bindAddress;
struct event* start_retry_timer = nullptr; std::unique_ptr<libtransmission::Timer> start_retry_timer;
struct evhttp* httpd = nullptr; struct evhttp* httpd = nullptr;
tr_session* const session; tr_session* const session;

View File

@ -678,17 +678,15 @@ static void onNowTimer(void* vsession)
} }
} }
// set the timer to kick again right after the next second // set the timer to kick again right after (10ms after) the next second
auto const tv = tr_gettimeofday(); auto const now = std::chrono::system_clock::now();
int constexpr Min = 100; auto const target_time = std::chrono::time_point_cast<std::chrono::seconds>(now) + 1s + 10ms;
int constexpr Max = 999999; auto target_interval = target_time - now;
auto const next_second_occurs_in_usec = std::chrono::microseconds{ std::clamp(int(1000000 - tv.tv_usec), Min, Max) }; if (target_interval < 100ms)
auto next_second_occurs_in_msec = std::chrono::duration_cast<std::chrono::milliseconds>(next_second_occurs_in_usec);
if (next_second_occurs_in_msec < 100ms)
{ {
next_second_occurs_in_msec += 1s; target_interval += 1s;
} }
session->now_timer_->setInterval(next_second_occurs_in_msec); session->now_timer_->setInterval(std::chrono::duration_cast<std::chrono::milliseconds>(target_interval));
} }
static void loadBlocklists(tr_session* session); static void loadBlocklists(tr_session* session);

View File

@ -518,7 +518,7 @@ public:
struct event* udp6_event = nullptr; struct event* udp6_event = nullptr;
struct struct_utp_context* utp_context = nullptr; struct struct_utp_context* utp_context = nullptr;
struct event* utp_timer = nullptr; std::unique_ptr<libtransmission::Timer> utp_timer;
/* The open port on the local machine for incoming peer requests */ /* The open port on the local machine for incoming peer requests */
tr_port private_peer_port; tr_port private_peer_port;

View File

@ -62,6 +62,20 @@ class TimerMaker
public: public:
virtual ~TimerMaker() = default; virtual ~TimerMaker() = default;
[[nodiscard]] virtual std::unique_ptr<Timer> create() = 0; [[nodiscard]] virtual std::unique_ptr<Timer> create() = 0;
[[nodiscard]] virtual std::unique_ptr<Timer> create(std::function<void()> callback)
{
auto timer = create();
timer->setCallback(std::move(callback));
return timer;
}
[[nodiscard]] virtual std::unique_ptr<Timer> create(Timer::CStyleCallback callback, void* user_data)
{
auto timer = create();
timer->setCallback(callback, user_data);
return timer;
}
}; };
} // namespace libtransmission } // namespace libtransmission

View File

@ -4,6 +4,7 @@
#include <algorithm> #include <algorithm>
#include <cerrno> #include <cerrno>
#include <chrono>
#include <csignal> /* sig_atomic_t */ #include <csignal> /* sig_atomic_t */
#include <cstdio> #include <cstdio>
#include <cstring> /* memcpy(), memset() */ #include <cstring> /* memcpy(), memset() */
@ -20,7 +21,7 @@
#undef gai_strerror #undef gai_strerror
#define gai_strerror gai_strerrorA #define gai_strerror gai_strerrorA
#else #else
#include <sys/time.h> #include <sys/time.h> // for `struct timezone`
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> /* socket(), bind() */ #include <sys/socket.h> /* socket(), bind() */
#include <netdb.h> #include <netdb.h>
@ -29,8 +30,6 @@
#include <dht/dht.h> #include <dht/dht.h>
#include <event2/event.h>
#include <fmt/format.h> #include <fmt/format.h>
#include "transmission.h" #include "transmission.h"
@ -51,12 +50,10 @@
using namespace std::literals; using namespace std::literals;
static struct event* dht_timer = nullptr; static std::unique_ptr<libtransmission::Timer> dht_timer;
static unsigned char myid[20]; static unsigned char myid[20];
static tr_session* session_ = nullptr; static tr_session* session_ = nullptr;
static void timer_callback(evutil_socket_t s, short type, void* session);
static bool bootstrap_done(tr_session* session, int af) static bool bootstrap_done(tr_session* session, int af)
{ {
if (af == 0) if (af == 0)
@ -325,8 +322,12 @@ int tr_dhtInit(tr_session* ss)
std::thread(dht_bootstrap, session_, nodes, nodes6).detach(); std::thread(dht_bootstrap, session_, nodes, nodes6).detach();
dht_timer = evtimer_new(session_->eventBase(), timer_callback, session_); dht_timer = session_->timerMaker().create([]() { tr_dhtCallback(nullptr, 0, nullptr, 0, session_); });
tr_timerAdd(*dht_timer, 0, tr_rand_int_weak(1000000)); auto const random_percent = tr_rand_int_weak(1000) / 1000.0;
static auto constexpr MinInterval = 10ms;
static auto constexpr MaxInterval = 1s;
auto interval = MinInterval + random_percent * (MaxInterval - MinInterval);
dht_timer->startSingleShot(std::chrono::duration_cast<std::chrono::milliseconds>(interval));
tr_logAddDebug("DHT initialized"); tr_logAddDebug("DHT initialized");
@ -342,11 +343,7 @@ void tr_dhtUninit(tr_session* ss)
tr_logAddTrace("Uninitializing DHT"); tr_logAddTrace("Uninitializing DHT");
if (dht_timer != nullptr) dht_timer.reset();
{
event_free(dht_timer);
dht_timer = nullptr;
}
/* Since we only save known good nodes, avoid erasing older data if we /* Since we only save known good nodes, avoid erasing older data if we
don't know enough nodes. */ don't know enough nodes. */
@ -715,12 +712,11 @@ void tr_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, sockl
/* Being slightly late is fine, /* Being slightly late is fine,
and has the added benefit of adding some jitter. */ and has the added benefit of adding some jitter. */
tr_timerAdd(*dht_timer, (int)tosleep, tr_rand_int_weak(1000000)); auto const random_percent = tr_rand_int_weak(1000) / 1000.0;
} auto const min_interval = std::chrono::seconds{ tosleep };
auto const max_interval = std::chrono::seconds{ tosleep + 1 };
static void timer_callback(evutil_socket_t /*s*/, short /*type*/, void* session) auto const interval = min_interval + random_percent * (max_interval - min_interval);
{ dht_timer->startSingleShot(std::chrono::duration_cast<std::chrono::milliseconds>(interval));
tr_dhtCallback(nullptr, 0, nullptr, 0, session);
} }
/* This function should return true when a node is blacklisted. We do /* This function should return true when a node is blacklisted. We do
@ -759,10 +755,19 @@ int dht_sendto(int sockfd, void const* buf, int len, int flags, struct sockaddr
#if defined(_WIN32) && !defined(__MINGW32__) #if defined(_WIN32) && !defined(__MINGW32__)
extern "C" int dht_gettimeofday(struct timeval* tv, [[maybe_unused]] timezone* tz) /***
****
***/
extern "C" int dht_gettimeofday(struct timeval* tv, [[maybe_unused]] struct timezone* tz)
{ {
TR_ASSERT(tz == nullptr); TR_ASSERT(tz == nullptr);
*tv = tr_gettimeofday();
auto const d = std::chrono::system_clock::now().time_since_epoch();
auto const s = std::chrono::duration_cast<std::chrono::seconds>(d);
tv->tv_sec = s.count();
tv->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(d - s).count();
return 0; return 0;
} }

View File

@ -4,6 +4,7 @@
#include <algorithm> #include <algorithm>
#include <cerrno> #include <cerrno>
#include <chrono>
#include <csignal> /* sig_atomic_t */ #include <csignal> /* sig_atomic_t */
#include <cstring> /* strlen(), strncpy(), strstr(), memset() */ #include <cstring> /* strlen(), strncpy(), strstr(), memset() */
#include <type_traits> #include <type_traits>
@ -49,9 +50,9 @@ static auto constexpr SIZEOF_HASH_STRING = TR_SHA1_DIGEST_STRLEN;
static void event_callback(evutil_socket_t, short /*type*/, void* /*unused*/); static void event_callback(evutil_socket_t, short /*type*/, void* /*unused*/);
static auto constexpr UpkeepIntervalSecs = int{ 5 }; static auto constexpr UpkeepInterval = 5s;
static struct event* upkeep_timer = nullptr; static std::unique_ptr<libtransmission::Timer> upkeep_timer;
static tr_socket_t lpd_socket; /**<separate multicast receive socket */ static tr_socket_t lpd_socket; /**<separate multicast receive socket */
static tr_socket_t lpd_socket2; /**<and multicast send socket */ static tr_socket_t lpd_socket2; /**<and multicast send socket */
@ -229,7 +230,7 @@ static bool lpd_extractParam(char const* const str, char const* const name, int
/** /**
* @} */ * @} */
static void on_upkeep_timer(evutil_socket_t, short /*unused*/, void* /*unused*/); static void on_upkeep_timer();
/** /**
* @brief Initializes Local Peer Discovery for this node * @brief Initializes Local Peer Discovery for this node
@ -357,8 +358,8 @@ int tr_lpdInit(tr_session* ss, tr_address* /*tr_addr*/)
lpd_event = event_new(ss->eventBase(), lpd_socket, EV_READ | EV_PERSIST, event_callback, nullptr); lpd_event = event_new(ss->eventBase(), lpd_socket, EV_READ | EV_PERSIST, event_callback, nullptr);
event_add(lpd_event, nullptr); event_add(lpd_event, nullptr);
upkeep_timer = evtimer_new(ss->eventBase(), on_upkeep_timer, ss); upkeep_timer = ss->timerMaker().create([]() { on_upkeep_timer(); });
tr_timerAdd(*upkeep_timer, UpkeepIntervalSecs, 0); upkeep_timer->startRepeating(UpkeepInterval);
tr_logAddDebug("Local Peer Discovery initialised"); tr_logAddDebug("Local Peer Discovery initialised");
@ -393,8 +394,7 @@ void tr_lpdUninit(tr_session* ss)
event_free(lpd_event); event_free(lpd_event);
lpd_event = nullptr; lpd_event = nullptr;
evtimer_del(upkeep_timer); upkeep_timer.reset();
upkeep_timer = nullptr;
/* just shut down, we won't remember any former nodes */ /* just shut down, we won't remember any former nodes */
evutil_closesocket(lpd_socket); evutil_closesocket(lpd_socket);
@ -616,11 +616,11 @@ static int tr_lpdAnnounceMore(time_t const now, int const interval)
return announcesSent; return announcesSent;
} }
static void on_upkeep_timer(evutil_socket_t /*s*/, short /*type*/, void* /*user_data*/) static void on_upkeep_timer()
{ {
time_t const now = tr_time(); time_t const now = tr_time();
tr_lpdAnnounceMore(now, UpkeepIntervalSecs); auto const seconds = std::chrono::duration_cast<std::chrono::seconds>(UpkeepInterval).count();
tr_timerAdd(*upkeep_timer, UpkeepIntervalSecs, 0); tr_lpdAnnounceMore(now, seconds);
} }
/** /**

View File

@ -3,8 +3,7 @@
// License text can be found in the licenses/ folder. // License text can be found in the licenses/ folder.
#include <cstdint> #include <cstdint>
#include <chrono>
#include <event2/event.h>
#include <fmt/core.h> #include <fmt/core.h>
#include <fmt/format.h> #include <fmt/format.h>
@ -23,6 +22,8 @@
#include "tr-utp.h" #include "tr-utp.h"
#include "utils.h" #include "utils.h"
using namespace std::literals;
#ifndef WITH_UTP #ifndef WITH_UTP
void utp_close(UTPSocket* socket) void utp_close(UTPSocket* socket)
@ -72,7 +73,7 @@ void tr_utpClose(tr_session* /*session*/)
#else #else
/* Greg says 50ms works for them. */ /* Greg says 50ms works for them. */
static auto constexpr UtpIntervalUs = int{ 500000 }; static auto constexpr UtpInterval = 50ms;
static void utp_on_accept(tr_session* const session, UTPSocket* const s) static void utp_on_accept(tr_session* const session, UTPSocket* const s)
{ {
@ -155,15 +156,17 @@ static uint64 utp_callback(utp_callback_arguments* args)
return 0; return 0;
} }
static void reset_timer(tr_session* ss) static void reset_timer(tr_session* session)
{ {
int sec = 0; auto interval = std::chrono::milliseconds{};
int usec = 0; auto const random_percent = tr_rand_int_weak(1000) / 1000.0;
if (tr_sessionIsUTPEnabled(ss)) if (tr_sessionIsUTPEnabled(session))
{ {
sec = 0; static auto constexpr MinInterval = UtpInterval * 0.5;
usec = UtpIntervalUs / 2 + tr_rand_int_weak(UtpIntervalUs); static auto constexpr MaxInterval = UtpInterval * 1.5;
auto const target = MinInterval + random_percent * (MaxInterval - MinInterval);
interval = std::chrono::duration_cast<std::chrono::milliseconds>(target);
} }
else else
{ {
@ -172,14 +175,16 @@ static void reset_timer(tr_session* ss)
gracefully and so on. However, since we're not particularly gracefully and so on. However, since we're not particularly
interested in that happening in a timely manner, we might as interested in that happening in a timely manner, we might as
well use a large timeout. */ well use a large timeout. */
sec = 2; static auto constexpr MinInterval = 2s;
usec = tr_rand_int_weak(1000000); static auto constexpr MaxInterval = 3s;
auto const target = MinInterval + random_percent * (MaxInterval - MinInterval);
interval = std::chrono::duration_cast<std::chrono::milliseconds>(target);
} }
tr_timerAdd(*ss->utp_timer, sec, usec); session->utp_timer->startSingleShot(interval);
} }
static void timer_callback(evutil_socket_t /*s*/, short /*type*/, void* vsession) static void timer_callback(void* vsession)
{ {
auto* session = static_cast<tr_session*>(vsession); auto* session = static_cast<tr_session*>(vsession);
@ -226,15 +231,9 @@ void tr_utpInit(tr_session* session)
bool tr_utpPacket(unsigned char const* buf, size_t buflen, struct sockaddr const* from, socklen_t fromlen, tr_session* ss) bool tr_utpPacket(unsigned char const* buf, size_t buflen, struct sockaddr const* from, socklen_t fromlen, tr_session* ss)
{ {
if (!ss->isClosed && ss->utp_timer == nullptr) if (!ss->isClosed && !ss->utp_timer)
{ {
ss->utp_timer = evtimer_new(ss->eventBase(), timer_callback, ss); ss->utp_timer = ss->timerMaker().create(timer_callback, ss);
if (ss->utp_timer == nullptr)
{
return false;
}
reset_timer(ss); reset_timer(ss);
} }
@ -248,11 +247,7 @@ bool tr_utpPacket(unsigned char const* buf, size_t buflen, struct sockaddr const
void tr_utpClose(tr_session* session) void tr_utpClose(tr_session* session)
{ {
if (session->utp_timer != nullptr) session->utp_timer.reset();
{
evtimer_del(session->utp_timer);
session->utp_timer = nullptr;
}
if (session->utp_context != nullptr) if (session->utp_context != nullptr)
{ {

View File

@ -36,8 +36,6 @@
#define UTF_CPP_CPLUSPLUS 201703L #define UTF_CPP_CPLUSPLUS 201703L
#include <utf8.h> #include <utf8.h>
#include <event2/event.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <fast_float/fast_float.h> #include <fast_float/fast_float.h>
@ -64,20 +62,6 @@ time_t __tr_current_time = 0;
**** ****
***/ ***/
struct timeval tr_gettimeofday()
{
auto const d = std::chrono::system_clock::now().time_since_epoch();
auto const s = std::chrono::duration_cast<std::chrono::seconds>(d);
auto ret = timeval{};
ret.tv_sec = s.count();
ret.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(d - s).count();
return ret;
}
/***
****
***/
void* tr_malloc(size_t size) void* tr_malloc(size_t size)
{ {
return size != 0 ? malloc(size) : nullptr; return size != 0 ? malloc(size) : nullptr;
@ -108,30 +92,6 @@ void tr_free(void* p)
} }
} }
/***
****
***/
void tr_timerAdd(struct event& timer, int seconds, int microseconds)
{
auto tv = timeval{};
tv.tv_sec = seconds;
tv.tv_usec = microseconds;
TR_ASSERT(tv.tv_sec >= 0);
TR_ASSERT(tv.tv_usec >= 0);
TR_ASSERT(tv.tv_usec < 1000000);
evtimer_add(&timer, &tv);
}
void tr_timerAddMsec(struct event& timer, int milliseconds)
{
int const seconds = milliseconds / 1000;
int const usec = (milliseconds % 1000) * 1000;
tr_timerAdd(timer, seconds, usec);
}
/** /**
*** ***
**/ **/
@ -311,8 +271,7 @@ std::string_view tr_strvStrip(std::string_view str)
uint64_t tr_time_msec() uint64_t tr_time_msec()
{ {
auto const tv = tr_gettimeofday(); return std::chrono::system_clock::now().time_since_epoch() / 1ms;
return uint64_t(tv.tv_sec) * 1000 + (tv.tv_usec / 1000);
} }
void tr_wait_msec(long int delay_milliseconds) void tr_wait_msec(long int delay_milliseconds)

View File

@ -88,21 +88,6 @@ constexpr auto tr_saveFile(std::string_view filename, ContiguousRange const& x,
*/ */
tr_disk_space tr_dirSpace(std::string_view directory); tr_disk_space tr_dirSpace(std::string_view directory);
/**
* @brief Convenience wrapper around timer_add() to have a timer wake up in a number of seconds and microseconds
* @param timer the timer to set
* @param seconds seconds to wait
* @param microseconds microseconds to wait
*/
void tr_timerAdd(struct event& timer, int seconds, int microseconds);
/**
* @brief Convenience wrapper around timer_add() to have a timer wake up in a number of milliseconds
* @param timer the timer to set
* @param milliseconds milliseconds to wait
*/
void tr_timerAddMsec(struct event& timer, int milliseconds);
/** @brief return the current date in milliseconds */ /** @brief return the current date in milliseconds */
uint64_t tr_time_msec(); uint64_t tr_time_msec();
@ -300,9 +285,6 @@ std::string& tr_strvUtf8Clean(std::string_view cleanme, std::string& setme);
*/ */
[[nodiscard]] std::string tr_strratio(double ratio, char const* infinity); [[nodiscard]] std::string tr_strratio(double ratio, char const* infinity);
/** @brief Portability wrapper for gettimeofday(), with tz argument dropped */
struct timeval tr_gettimeofday();
/** /**
* @brief move a file * @brief move a file
* @return `True` on success, `false` otherwise (with `error` set accordingly). * @return `True` on success, `false` otherwise (with `error` set accordingly).

View File

@ -4,6 +4,7 @@
// License text can be found in the licenses/ folder. // License text can be found in the licenses/ folder.
#include <algorithm> #include <algorithm>
#include <chrono>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <numeric> // std::accumulate() #include <numeric> // std::accumulate()
@ -13,7 +14,6 @@
#include <vector> #include <vector>
#include <event2/buffer.h> #include <event2/buffer.h>
#include <event2/event.h>
#include <fmt/format.h> #include <fmt/format.h>
@ -164,9 +164,9 @@ public:
, callback{ callback_in } , callback{ callback_in }
, callback_data{ callback_data_in } , callback_data{ callback_data_in }
, bandwidth_(&tor->bandwidth_) , bandwidth_(&tor->bandwidth_)
, pulse_timer(evtimer_new(session->eventBase(), &tr_webseed::onTimer, this), event_free) , idle_timer(session->timerMaker().create([this]() { on_idle(this); }))
{ {
startTimer(); idle_timer->startRepeating(IdleTimerInterval);
} }
tr_webseed(tr_webseed&&) = delete; tr_webseed(tr_webseed&&) = delete;
@ -338,21 +338,9 @@ private:
publish(&e); publish(&e);
} }
void startTimer()
{
tr_timerAddMsec(*pulse_timer, IdleTimerMsec);
}
static void onTimer(evutil_socket_t /*fd*/, short /*what*/, void* vwebseed)
{
auto* const webseed = static_cast<tr_webseed*>(vwebseed);
on_idle(webseed);
webseed->startTimer();
}
tr_bandwidth bandwidth_; tr_bandwidth bandwidth_;
std::shared_ptr<event> const pulse_timer; std::unique_ptr<libtransmission::Timer> idle_timer;
static int constexpr IdleTimerMsec = 2000; static auto constexpr IdleTimerInterval = 2s;
}; };
/*** /***