refactor: remove tr_new, tr_free pt. 1 (#3626)

* refactor: tr_torrentGetMetadataPiece() returns an optional vector

* refactor: use tr_pathbuf in create_temp_path()

* refactor: use tr_pathbuf in win32 create_temp_path()

* refactor: use std::vector in isPeerInteresting()

* refactor: remove tr_new0 from tr_peerMgrPeerStats()

* refactor: remove tr_new0 from rechokeUploads()

* refactor: silence clang nullptr dereference warning

* refactor: make tr_natpmp a C++ class

* refactor: use std::string in tr_log_message
This commit is contained in:
Charles Kerr 2022-08-11 19:59:58 -05:00 committed by GitHub
parent e781ee1773
commit 7c5862a5f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 239 additions and 268 deletions

View File

@ -396,8 +396,7 @@ static void pumpLogMessages(tr_sys_file_t file)
for (tr_log_message const* l = list; l != nullptr; l = l->next) for (tr_log_message const* l = list; l != nullptr; l = l->next)
{ {
auto const name = std::string_view{ l->name != nullptr ? l->name : "" }; printMessage(file, l->level, l->name, l->message, l->file, l->line);
printMessage(file, l->level, name, l->message, l->file, l->line);
} }
if (file != TR_BAD_SYS_FILE) if (file != TR_BAD_SYS_FILE)

View File

@ -208,13 +208,7 @@ void MessageLogWindow::Impl::doSave(Gtk::Window& parent, Glib::ustring const& fi
auto const it = level_names_.find(node->level); auto const it = level_names_.find(node->level);
auto const* const level_str = it != std::end(level_names_) ? it->second : "???"; auto const* const level_str = it != std::end(level_names_) ? it->second : "???";
fprintf( fprintf(fp, "%s\t%s\t%s\t%s\n", date.c_str(), level_str, node->name.c_str(), node->message.c_str());
fp,
"%s\t%s\t%s\t%s\n",
date.c_str(),
level_str,
node->name != nullptr ? node->name : "",
node->message != nullptr ? node->message : "");
} }
fclose(fp); fclose(fp);
@ -356,7 +350,7 @@ tr_log_message* addMessages(Glib::RefPtr<Gtk::ListStore> const& store, tr_log_me
for (i = head; i != nullptr && i->next != nullptr; i = i->next) for (i = head; i != nullptr && i->next != nullptr; i = i->next)
{ {
char const* name = i->name != nullptr ? i->name : default_name.c_str(); char const* name = !std::empty(i->name) ? i->name.c_str() : default_name.c_str();
auto const row = *store->prepend(); auto const row = *store->prepend();
row[message_log_cols.tr_msg] = i; row[message_log_cols.tr_msg] = i;
@ -369,9 +363,9 @@ tr_log_message* addMessages(Glib::RefPtr<Gtk::ListStore> const& store, tr_log_me
{ {
auto gstr = gtr_sprintf("%s:%d %s", i->file, i->line, i->message); auto gstr = gtr_sprintf("%s:%d %s", i->file, i->line, i->message);
if (i->name != nullptr) if (!std::empty(i->name))
{ {
gstr += gtr_sprintf(" (%s)", i->name); gstr += gtr_sprintf(" (%s)", i->name.c_str());
} }
g_warning("%s", gstr.c_str()); g_warning("%s", gstr.c_str());

View File

@ -59,7 +59,7 @@
#include "log.h" #include "log.h"
#include "tr-assert.h" #include "tr-assert.h"
#include "tr-strbuf.h" #include "tr-strbuf.h"
#include "utils.h" #include "utils.h" // for _(), tr_strerror()
#ifndef O_LARGEFILE #ifndef O_LARGEFILE
#define O_LARGEFILE 0 #define O_LARGEFILE 0
@ -192,10 +192,10 @@ static bool create_path_require_dir(char const* path, tr_error** error)
static bool create_path(char const* path_in, int permissions, tr_error** error) static bool create_path(char const* path_in, int permissions, tr_error** error)
{ {
/* make a temporary copy of path */ /* make a temporary copy of path */
char* const path = tr_strdup(path_in); auto path = tr_pathbuf{ path_in };
/* walk past the root */ /* walk past the root */
char* p = path; char* p = std::data(path);
while (*p == TR_PATH_DELIMITER) while (*p == TR_PATH_DELIMITER)
{ {
@ -283,7 +283,6 @@ CLEANUP:
TR_ASSERT(my_error == nullptr); TR_ASSERT(my_error == nullptr);
tr_free(path);
return ret; return ret;
} }

View File

@ -15,6 +15,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "transmission.h" #include "transmission.h"
#include "crypto-utils.h" /* tr_rand_int() */ #include "crypto-utils.h" /* tr_rand_int() */
#include "error.h" #include "error.h"
#include "file.h" #include "file.h"
@ -298,8 +299,8 @@ static void create_temp_path(
TR_ASSERT(path_template != nullptr); TR_ASSERT(path_template != nullptr);
TR_ASSERT(callback != nullptr); TR_ASSERT(callback != nullptr);
char* path = tr_strdup(path_template); auto path = std::string{ path_template };
size_t path_size = strlen(path); auto path_size = std::size(path);
TR_ASSERT(path_size > 0); TR_ASSERT(path_size > 0);
@ -320,7 +321,7 @@ static void create_temp_path(
tr_error_clear(&my_error); tr_error_clear(&my_error);
(*callback)(path, callback_param, &my_error); (*callback)(path.c_str(), callback_param, &my_error);
if (my_error == nullptr) if (my_error == nullptr)
{ {
@ -334,10 +335,8 @@ static void create_temp_path(
} }
else else
{ {
memcpy(path_template, path, path_size); std::copy_n(std::begin(path), path_size, path_template);
} }
tr_free(path);
} }
bool tr_sys_path_exists(char const* path, tr_error** error) bool tr_sys_path_exists(char const* path, tr_error** error)

View File

@ -133,13 +133,13 @@ void logAddImpl(
if (tr_logGetQueueEnabled()) if (tr_logGetQueueEnabled())
{ {
auto* const newmsg = tr_new0(tr_log_message, 1); auto* const newmsg = new tr_log_message{};
newmsg->level = level; newmsg->level = level;
newmsg->when = tr_time(); newmsg->when = tr_time();
newmsg->message = tr_strvDup(msg); newmsg->message = msg;
newmsg->file = file; newmsg->file = file;
newmsg->line = line; newmsg->line = line;
newmsg->name = tr_strvDup(name); newmsg->name = name;
*log_state.queue_tail_ = newmsg; *log_state.queue_tail_ = newmsg;
log_state.queue_tail_ = &newmsg->next; log_state.queue_tail_ = &newmsg->next;
@ -221,9 +221,7 @@ void tr_logFreeQueue(tr_log_message* freeme)
while (freeme != nullptr) while (freeme != nullptr)
{ {
auto* const next = freeme->next; auto* const next = freeme->next;
tr_free(freeme->message); delete freeme;
tr_free(freeme->name);
tr_free(freeme);
freeme = next; freeme = next;
} }
} }

View File

@ -8,6 +8,7 @@
#include <cstddef> #include <cstddef>
#include <ctime> #include <ctime>
#include <optional> #include <optional>
#include <string>
#include <string_view> #include <string_view>
/// ///
@ -50,17 +51,17 @@ struct tr_log_message
tr_log_level level; tr_log_level level;
// location in the source code // location in the source code
char const* file; std::string_view file;
int line; size_t line;
// when the message was generated // when the message was generated
time_t when; time_t when;
// torrent name or code module name associated with the message // torrent name or code module name associated with the message
char* name; std::string name;
// the message // the message
char* message; std::string message;
// linked list of messages // linked list of messages
struct tr_log_message* next; struct tr_log_message* next;

View File

@ -21,13 +21,6 @@
#include "port-forwarding.h" #include "port-forwarding.h"
#include "utils.h" #include "utils.h"
static auto constexpr LifetimeSecs = uint32_t{ 3600 };
static auto constexpr CommandWaitSecs = time_t{ 8 };
/**
***
**/
static void logVal(char const* func, int ret) static void logVal(char const* func, int ret)
{ {
if (ret == NATPMP_TRYAGAIN) if (ret == NATPMP_TRYAGAIN)
@ -51,57 +44,33 @@ static void logVal(char const* func, int ret)
} }
} }
struct tr_natpmp* tr_natpmpInit() bool tr_natpmp::canSendCommand() const
{ {
auto* const nat = tr_new0(struct tr_natpmp, 1); return tr_time() >= command_time_;
nat->state = TR_NATPMP_DISCOVER;
nat->public_port.clear();
nat->private_port.clear();
nat->natpmp.s = TR_BAD_SOCKET; /* socket */
return nat;
} }
void tr_natpmpClose(tr_natpmp* nat) void tr_natpmp::setCommandTime()
{ {
if (nat != nullptr) command_time_ = tr_time() + CommandWaitSecs;
}
tr_port_forwarding tr_natpmp::pulse(tr_port private_port, bool is_enabled, tr_port* public_port, tr_port* real_private_port)
{
if (is_enabled && state_ == TR_NATPMP_DISCOVER)
{ {
closenatpmp(&nat->natpmp); int val = initnatpmp(&natpmp_, 0, 0);
tr_free(nat);
}
}
static bool canSendCommand(struct tr_natpmp const* nat)
{
return tr_time() >= nat->command_time;
}
static void setCommandTime(struct tr_natpmp* nat)
{
nat->command_time = tr_time() + CommandWaitSecs;
}
tr_port_forwarding tr_natpmpPulse(
struct tr_natpmp* nat,
tr_port private_port,
bool is_enabled,
tr_port* public_port,
tr_port* real_private_port)
{
if (is_enabled && nat->state == TR_NATPMP_DISCOVER)
{
int val = initnatpmp(&nat->natpmp, 0, 0);
logVal("initnatpmp", val); logVal("initnatpmp", val);
val = sendpublicaddressrequest(&nat->natpmp); val = sendpublicaddressrequest(&natpmp_);
logVal("sendpublicaddressrequest", val); logVal("sendpublicaddressrequest", val);
nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_PUB; state_ = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_PUB;
nat->has_discovered = true; has_discovered_ = true;
setCommandTime(nat); setCommandTime();
} }
if (nat->state == TR_NATPMP_RECV_PUB && canSendCommand(nat)) if (state_ == TR_NATPMP_RECV_PUB && canSendCommand())
{ {
natpmpresp_t response; natpmpresp_t response;
int const val = readnatpmpresponseorretry(&nat->natpmp, &response); int const val = readnatpmpresponseorretry(&natpmp_, &response);
logVal("readnatpmpresponseorretry", val); logVal("readnatpmpresponseorretry", val);
if (val >= 0) if (val >= 0)
@ -109,37 +78,31 @@ tr_port_forwarding tr_natpmpPulse(
char str[128]; char str[128];
evutil_inet_ntop(AF_INET, &response.pnu.publicaddress.addr, str, sizeof(str)); evutil_inet_ntop(AF_INET, &response.pnu.publicaddress.addr, str, sizeof(str));
tr_logAddInfo(fmt::format(_("Found public address '{address}'"), fmt::arg("address", str))); tr_logAddInfo(fmt::format(_("Found public address '{address}'"), fmt::arg("address", str)));
nat->state = TR_NATPMP_IDLE; state_ = TR_NATPMP_IDLE;
} }
else if (val != NATPMP_TRYAGAIN) else if (val != NATPMP_TRYAGAIN)
{ {
nat->state = TR_NATPMP_ERR; state_ = TR_NATPMP_ERR;
} }
} }
if ((nat->state == TR_NATPMP_IDLE || nat->state == TR_NATPMP_ERR) && (nat->is_mapped) && if ((state_ == TR_NATPMP_IDLE || state_ == TR_NATPMP_ERR) && is_mapped_ && (!is_enabled || private_port_ != private_port))
(!is_enabled || nat->private_port != private_port))
{ {
nat->state = TR_NATPMP_SEND_UNMAP; state_ = TR_NATPMP_SEND_UNMAP;
} }
if (nat->state == TR_NATPMP_SEND_UNMAP && canSendCommand(nat)) if (state_ == TR_NATPMP_SEND_UNMAP && canSendCommand())
{ {
int const val = sendnewportmappingrequest( int const val = sendnewportmappingrequest(&natpmp_, NATPMP_PROTOCOL_TCP, private_port_.host(), public_port_.host(), 0);
&nat->natpmp,
NATPMP_PROTOCOL_TCP,
nat->private_port.host(),
nat->public_port.host(),
0);
logVal("sendnewportmappingrequest", val); logVal("sendnewportmappingrequest", val);
nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_UNMAP; state_ = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_UNMAP;
setCommandTime(nat); setCommandTime();
} }
if (nat->state == TR_NATPMP_RECV_UNMAP) if (state_ == TR_NATPMP_RECV_UNMAP)
{ {
natpmpresp_t resp; natpmpresp_t resp;
int const val = readnatpmpresponseorretry(&nat->natpmp, &resp); int const val = readnatpmpresponseorretry(&natpmp_, &resp);
logVal("readnatpmpresponseorretry", val); logVal("readnatpmpresponseorretry", val);
if (val >= 0) if (val >= 0)
@ -148,72 +111,72 @@ tr_port_forwarding tr_natpmpPulse(
tr_logAddInfo(fmt::format(_("Port {port} is no longer forwarded"), fmt::arg("port", unmapped_port.host()))); tr_logAddInfo(fmt::format(_("Port {port} is no longer forwarded"), fmt::arg("port", unmapped_port.host())));
if (nat->private_port == unmapped_port) if (private_port_ == unmapped_port)
{ {
nat->private_port.clear(); private_port_.clear();
nat->public_port.clear(); public_port_.clear();
nat->state = TR_NATPMP_IDLE; state_ = TR_NATPMP_IDLE;
nat->is_mapped = false; is_mapped_ = false;
} }
} }
else if (val != NATPMP_TRYAGAIN) else if (val != NATPMP_TRYAGAIN)
{ {
nat->state = TR_NATPMP_ERR; state_ = TR_NATPMP_ERR;
} }
} }
if (nat->state == TR_NATPMP_IDLE) if (state_ == TR_NATPMP_IDLE)
{ {
if (is_enabled && !nat->is_mapped && nat->has_discovered) if (is_enabled && !is_mapped_ && has_discovered_)
{ {
nat->state = TR_NATPMP_SEND_MAP; state_ = TR_NATPMP_SEND_MAP;
} }
else if (nat->is_mapped && tr_time() >= nat->renew_time) else if (is_mapped_ && tr_time() >= renew_time_)
{ {
nat->state = TR_NATPMP_SEND_MAP; state_ = TR_NATPMP_SEND_MAP;
} }
} }
if (nat->state == TR_NATPMP_SEND_MAP && canSendCommand(nat)) if (state_ == TR_NATPMP_SEND_MAP && canSendCommand())
{ {
int const val = sendnewportmappingrequest( int const val = sendnewportmappingrequest(
&nat->natpmp, &natpmp_,
NATPMP_PROTOCOL_TCP, NATPMP_PROTOCOL_TCP,
private_port.host(), private_port.host(),
private_port.host(), private_port.host(),
LifetimeSecs); LifetimeSecs);
logVal("sendnewportmappingrequest", val); logVal("sendnewportmappingrequest", val);
nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_MAP; state_ = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_MAP;
setCommandTime(nat); setCommandTime();
} }
if (nat->state == TR_NATPMP_RECV_MAP) if (state_ == TR_NATPMP_RECV_MAP)
{ {
natpmpresp_t resp; natpmpresp_t resp;
int const val = readnatpmpresponseorretry(&nat->natpmp, &resp); int const val = readnatpmpresponseorretry(&natpmp_, &resp);
logVal("readnatpmpresponseorretry", val); logVal("readnatpmpresponseorretry", val);
if (val >= 0) if (val >= 0)
{ {
nat->state = TR_NATPMP_IDLE; state_ = TR_NATPMP_IDLE;
nat->is_mapped = true; is_mapped_ = true;
nat->renew_time = tr_time() + (resp.pnu.newportmapping.lifetime / 2); renew_time_ = tr_time() + (resp.pnu.newportmapping.lifetime / 2);
nat->private_port = tr_port::fromHost(resp.pnu.newportmapping.privateport); private_port_ = tr_port::fromHost(resp.pnu.newportmapping.privateport);
nat->public_port = tr_port::fromHost(resp.pnu.newportmapping.mappedpublicport); public_port_ = tr_port::fromHost(resp.pnu.newportmapping.mappedpublicport);
tr_logAddInfo(fmt::format(_("Port {port} forwarded successfully"), fmt::arg("port", nat->private_port.host()))); tr_logAddInfo(fmt::format(_("Port {port} forwarded successfully"), fmt::arg("port", private_port_.host())));
} }
else if (val != NATPMP_TRYAGAIN) else if (val != NATPMP_TRYAGAIN)
{ {
nat->state = TR_NATPMP_ERR; state_ = TR_NATPMP_ERR;
} }
} }
switch (nat->state) switch (state_)
{ {
case TR_NATPMP_IDLE: case TR_NATPMP_IDLE:
*public_port = nat->public_port; *public_port = public_port_;
*real_private_port = nat->private_port; *real_private_port = private_port_;
return nat->is_mapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED; return is_mapped_ ? TR_PORT_MAPPED : TR_PORT_UNMAPPED;
case TR_NATPMP_DISCOVER: case TR_NATPMP_DISCOVER:
return TR_PORT_UNMAPPED; return TR_PORT_UNMAPPED;

View File

@ -9,46 +9,62 @@
#error only libtransmission should #include this header. #error only libtransmission should #include this header.
#endif #endif
/**
* @addtogroup port_forwarding Port Forwarding
* @{
*/
#include <ctime> // time_t #include <ctime> // time_t
#include "transmission.h" // tr_port_forwarding
#include "natpmp.h" #include "natpmp.h"
#include "net.h" // tr_port #include "net.h" // tr_port
enum tr_natpmp_state class tr_natpmp
{ {
TR_NATPMP_IDLE, public:
TR_NATPMP_ERR, tr_natpmp()
TR_NATPMP_DISCOVER, {
TR_NATPMP_RECV_PUB, natpmp_.s = TR_BAD_SOCKET; /* socket */
TR_NATPMP_SEND_MAP, }
TR_NATPMP_RECV_MAP,
TR_NATPMP_SEND_UNMAP, ~tr_natpmp()
TR_NATPMP_RECV_UNMAP {
closenatpmp(&natpmp_);
}
[[nodiscard]] constexpr auto renewTime() const noexcept
{
return renew_time_;
}
tr_port_forwarding pulse(tr_port port, bool is_enabled, tr_port* public_port, tr_port* real_private_port);
private:
enum tr_natpmp_state
{
TR_NATPMP_IDLE,
TR_NATPMP_ERR,
TR_NATPMP_DISCOVER,
TR_NATPMP_RECV_PUB,
TR_NATPMP_SEND_MAP,
TR_NATPMP_RECV_MAP,
TR_NATPMP_SEND_UNMAP,
TR_NATPMP_RECV_UNMAP
};
static constexpr auto LifetimeSecs = uint32_t{ 3600 };
static constexpr auto CommandWaitSecs = time_t{ 8 };
[[nodiscard]] bool canSendCommand() const;
void setCommandTime();
natpmp_t natpmp_;
tr_port public_port_ = {};
tr_port private_port_ = {};
time_t renew_time_ = 0;
time_t command_time_ = 0;
tr_natpmp_state state_ = TR_NATPMP_DISCOVER;
bool has_discovered_ = false;
bool is_mapped_ = false;
}; };
struct tr_natpmp
{
bool has_discovered;
bool is_mapped;
tr_port public_port;
tr_port private_port;
time_t renew_time;
time_t command_time;
tr_natpmp_state state;
natpmp_t natpmp;
};
tr_natpmp* tr_natpmpInit(void);
void tr_natpmpClose(tr_natpmp*);
tr_port_forwarding tr_natpmpPulse(tr_natpmp*, tr_port port, bool is_enabled, tr_port* public_port, tr_port* real_private_port);
/* @} */

View File

@ -1795,7 +1795,7 @@ tr_peer_stat* tr_peerMgrPeerStats(tr_torrent const* tor, int* setme_count)
TR_ASSERT(tor->swarm->manager != nullptr); TR_ASSERT(tor->swarm->manager != nullptr);
auto const n = tor->swarm->peerCount(); auto const n = tor->swarm->peerCount();
auto* const ret = tr_new0(tr_peer_stat, n); auto* const ret = new tr_peer_stat[n];
auto const now = tr_time(); auto const now = tr_time();
auto const now_msec = tr_time_msec(); auto const now_msec = tr_time_msec();
@ -1826,7 +1826,7 @@ namespace
/* does this peer have any pieces that we want? */ /* does this peer have any pieces that we want? */
[[nodiscard]] bool isPeerInteresting( [[nodiscard]] bool isPeerInteresting(
tr_torrent* const tor, tr_torrent* const tor,
bool const* const piece_is_interesting, std::vector<bool> const& piece_is_interesting,
tr_peerMsgs const* const peer) tr_peerMsgs const* const peer)
{ {
/* these cases should have already been handled by the calling code... */ /* these cases should have already been handled by the calling code... */
@ -1990,7 +1990,8 @@ void rechokeDownloads(tr_swarm* s)
int const n = tor->pieceCount(); int const n = tor->pieceCount();
/* build a bitfield of interesting pieces... */ /* build a bitfield of interesting pieces... */
auto* const piece_is_interesting = tr_new(bool, n); auto piece_is_interesting = std::vector<bool>{};
piece_is_interesting.resize(n);
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
@ -2034,8 +2035,6 @@ void rechokeDownloads(tr_swarm* s)
rechoke.emplace_back(peer, rechoke_state, salter()); rechoke.emplace_back(peer, rechoke_state, salter());
} }
} }
tr_free(piece_is_interesting);
} }
std::sort(std::begin(rechoke), std::end(rechoke)); std::sort(std::begin(rechoke), std::end(rechoke));
@ -2075,12 +2074,22 @@ namespace
struct ChokeData struct ChokeData
{ {
bool isInterested; ChokeData(tr_peerMsgs* msgs_in, int rate_in, uint8_t salt_in, bool is_interested_in, bool was_choked_in, bool is_choked_in)
bool wasChoked; : msgs{ msgs_in }
bool isChoked; , rate{ rate_in }
, salt{ salt_in }
, is_interested{ is_interested_in }
, was_choked{ was_choked_in }
, is_choked{ is_choked_in }
{
}
tr_peerMsgs* msgs;
int rate; int rate;
uint8_t salt; uint8_t salt;
tr_peerMsgs* msgs; bool is_interested;
bool was_choked;
bool is_choked;
[[nodiscard]] constexpr auto compare(ChokeData const& that) const noexcept // <=> [[nodiscard]] constexpr auto compare(ChokeData const& that) const noexcept // <=>
{ {
@ -2089,9 +2098,9 @@ struct ChokeData
return this->rate > that.rate ? -1 : 1; return this->rate > that.rate ? -1 : 1;
} }
if (this->wasChoked != that.wasChoked) // prefer unchoked if (this->was_choked != that.was_choked) // prefer unchoked
{ {
return this->wasChoked ? 1 : -1; return this->was_choked ? 1 : -1;
} }
if (this->salt != that.salt) // random order if (this->salt != that.salt) // random order
@ -2146,7 +2155,8 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
auto const peerCount = s->peerCount(); auto const peerCount = s->peerCount();
auto& peers = s->peers; auto& peers = s->peers;
auto* const choke = tr_new0(struct ChokeData, peerCount); auto choked = std::vector<ChokeData>{};
choked.reserve(peerCount);
auto const* const session = s->manager->session; auto const* const session = s->manager->session;
bool const chokeAll = !s->tor->clientCanUpload(); bool const chokeAll = !s->tor->clientCanUpload();
bool const isMaxedOut = isBandwidthMaxedOut(s->tor->bandwidth_, now, TR_UP); bool const isMaxedOut = isBandwidthMaxedOut(s->tor->bandwidth_, now, TR_UP);
@ -2162,8 +2172,6 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
s->optimistic = nullptr; s->optimistic = nullptr;
} }
int size = 0;
/* sort the peers by preference and rate */ /* sort the peers by preference and rate */
auto salter = tr_salt_shaker{}; auto salter = tr_salt_shaker{};
for (auto* const peer : peers) for (auto* const peer : peers)
@ -2180,17 +2188,17 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
} }
else if (peer != s->optimistic) else if (peer != s->optimistic)
{ {
struct ChokeData* n = &choke[size++]; choked.emplace_back(
n->msgs = peer; peer,
n->isInterested = peer->is_peer_interested(); getRateBps(s->tor, peer, now),
n->wasChoked = peer->is_peer_choked(); salter(),
n->rate = getRateBps(s->tor, peer, now); peer->is_peer_interested(),
n->salt = salter(); peer->is_peer_choked(),
n->isChoked = true; true);
} }
} }
std::sort(choke, choke + size); std::sort(std::begin(choked), std::end(choked));
/** /**
* Reciprocation and number of uploads capping is managed by unchoking * Reciprocation and number of uploads capping is managed by unchoking
@ -2207,57 +2215,57 @@ void rechokeUploads(tr_swarm* s, uint64_t const now)
* *
* If our bandwidth is maxed out, don't unchoke any more peers. * If our bandwidth is maxed out, don't unchoke any more peers.
*/ */
int checkedChokeCount = 0; auto checked_choke_count = size_t{ 0U };
int unchokedInterested = 0; auto unchoked_interested = size_t{ 0U };
for (int i = 0; i < size && unchokedInterested < session->uploadSlotsPerTorrent; ++i) for (auto& item : choked)
{ {
choke[i].isChoked = isMaxedOut ? choke[i].wasChoked : false; if (unchoked_interested >= session->upload_slots_per_torrent)
++checkedChokeCount;
if (choke[i].isInterested)
{ {
++unchokedInterested; break;
}
item.is_choked = isMaxedOut ? item.was_choked : false;
++checked_choke_count;
if (item.is_interested)
{
++unchoked_interested;
} }
} }
/* optimistic unchoke */ /* optimistic unchoke */
if (s->optimistic == nullptr && !isMaxedOut && checkedChokeCount < size) if (s->optimistic == nullptr && !isMaxedOut && checked_choke_count < std::size(choked))
{ {
auto randPool = std::vector<ChokeData*>{}; auto rand_pool = std::vector<ChokeData*>{};
for (int i = checkedChokeCount; i < size; ++i) for (auto i = checked_choke_count, n = std::size(choked); i < n; ++i)
{ {
if (choke[i].isInterested) if (choked[i].is_interested)
{ {
tr_peerMsgs const* msgs = choke[i].msgs; int const x = isNew(choked[i].msgs) ? 3 : 1;
int const x = isNew(msgs) ? 3 : 1;
for (int y = 0; y < x; ++y) for (int y = 0; y < x; ++y)
{ {
randPool.push_back(&choke[i]); rand_pool.push_back(&choked[i]);
} }
} }
} }
auto const n = std::size(randPool); if (auto const n = std::size(rand_pool); n != 0)
if (n != 0)
{ {
auto* c = randPool[tr_rand_int_weak(n)]; auto* c = rand_pool[tr_rand_int_weak(n)];
c->isChoked = false; c->is_choked = false;
s->optimistic = c->msgs; s->optimistic = c->msgs;
s->optimistic_unchoke_time_scaler = OptimisticUnchokeMultiplier; s->optimistic_unchoke_time_scaler = OptimisticUnchokeMultiplier;
} }
} }
for (int i = 0; i < size; ++i) for (auto& item : choked)
{ {
choke[i].msgs->set_choke(choke[i].isChoked); item.msgs->set_choke(item.is_choked);
} }
/* cleanup */
tr_free(choke);
} }
} // namespace rechoke_uploads_helpers } // namespace rechoke_uploads_helpers

View File

@ -2225,9 +2225,7 @@ static size_t fillOutputBuffer(tr_peerMsgsImpl* msgs, time_t now)
{ {
auto ok = bool{ false }; auto ok = bool{ false };
auto dataLen = size_t{}; if (auto const piece_data = tr_torrentGetMetadataPiece(msgs->torrent, piece); piece_data)
if (auto* data = static_cast<char*>(tr_torrentGetMetadataPiece(msgs->torrent, piece, &dataLen)); data != nullptr)
{ {
auto* const out = msgs->outMessages; auto* const out = msgs->outMessages;
@ -2240,17 +2238,16 @@ static size_t fillOutputBuffer(tr_peerMsgsImpl* msgs, time_t now)
evbuffer* const payload = tr_variantToBuf(&tmp, TR_VARIANT_FMT_BENC); evbuffer* const payload = tr_variantToBuf(&tmp, TR_VARIANT_FMT_BENC);
/* write it out as a LTEP message to our outMessages buffer */ /* write it out as a LTEP message to our outMessages buffer */
evbuffer_add_uint32(out, 2 * sizeof(uint8_t) + evbuffer_get_length(payload) + dataLen); evbuffer_add_uint32(out, 2 * sizeof(uint8_t) + evbuffer_get_length(payload) + std::size(*piece_data));
evbuffer_add_uint8(out, BtPeerMsgs::Ltep); evbuffer_add_uint8(out, BtPeerMsgs::Ltep);
evbuffer_add_uint8(out, msgs->ut_metadata_id); evbuffer_add_uint8(out, msgs->ut_metadata_id);
evbuffer_add_buffer(out, payload); evbuffer_add_buffer(out, payload);
evbuffer_add(out, data, dataLen); evbuffer_add(out, std::data(*piece_data), std::size(*piece_data));
msgs->pokeBatchPeriod(HighPriorityIntervalSecs); msgs->pokeBatchPeriod(HighPriorityIntervalSecs);
msgs->dbgOutMessageLen(); msgs->dbgOutMessageLen();
evbuffer_free(payload); evbuffer_free(payload);
tr_variantFree(&tmp); tr_variantFree(&tmp);
tr_free(data);
ok = true; ok = true;
} }

View File

@ -24,12 +24,12 @@ using namespace std::literals;
struct tr_shared struct tr_shared
{ {
tr_shared(tr_session* session_in) tr_shared(tr_session& session_in)
: session{ session_in } : session{ session_in }
{ {
} }
tr_session* const session = nullptr; tr_session& session;
bool isEnabled = false; bool isEnabled = false;
bool isShuttingDown = false; bool isShuttingDown = false;
@ -39,7 +39,7 @@ struct tr_shared
tr_port_forwarding upnpStatus = TR_PORT_UNMAPPED; tr_port_forwarding upnpStatus = TR_PORT_UNMAPPED;
tr_upnp* upnp = nullptr; tr_upnp* upnp = nullptr;
tr_natpmp* natpmp = nullptr; std::unique_ptr<tr_natpmp> natpmp;
std::unique_ptr<libtransmission::Timer> timer; std::unique_ptr<libtransmission::Timer> timer;
}; };
@ -71,13 +71,13 @@ static char const* getNatStateStr(int state)
static void natPulse(tr_shared* s, bool do_check) static void natPulse(tr_shared* s, bool do_check)
{ {
auto* session = s->session; auto& session = s->session;
tr_port const private_peer_port = session->private_peer_port; tr_port const private_peer_port = session.private_peer_port;
bool const is_enabled = s->isEnabled && !s->isShuttingDown; bool const is_enabled = s->isEnabled && !s->isShuttingDown;
if (s->natpmp == nullptr) if (!s->natpmp)
{ {
s->natpmp = tr_natpmpInit(); s->natpmp = std::make_unique<tr_natpmp>();
} }
if (s->upnp == nullptr) if (s->upnp == nullptr)
@ -89,19 +89,19 @@ static void natPulse(tr_shared* s, bool do_check)
auto public_peer_port = tr_port{}; auto public_peer_port = tr_port{};
auto received_private_port = tr_port{}; auto received_private_port = tr_port{};
s->natpmpStatus = tr_natpmpPulse(s->natpmp, private_peer_port, is_enabled, &public_peer_port, &received_private_port); s->natpmpStatus = s->natpmp->pulse(private_peer_port, is_enabled, &public_peer_port, &received_private_port);
if (s->natpmpStatus == TR_PORT_MAPPED) if (s->natpmpStatus == TR_PORT_MAPPED)
{ {
session->public_peer_port = public_peer_port; session.public_peer_port = public_peer_port;
session->private_peer_port = received_private_port; session.private_peer_port = received_private_port;
tr_logAddInfo(fmt::format( tr_logAddInfo(fmt::format(
_("Mapped private port {private_port} to public port {public_port}"), _("Mapped private port {private_port} to public port {public_port}"),
fmt::arg("public_port", session->public_peer_port.host()), fmt::arg("public_port", session.public_peer_port.host()),
fmt::arg("private_port", session->private_peer_port.host()))); fmt::arg("private_port", session.private_peer_port.host())));
} }
s->upnpStatus = tr_upnpPulse(s->upnp, private_peer_port, is_enabled, do_check, session->bind_ipv4.readable()); s->upnpStatus = tr_upnpPulse(s->upnp, private_peer_port, is_enabled, do_check, session.bind_ipv4.readable());
auto const new_status = tr_sharedTraversalStatus(s); auto const new_status = tr_sharedTraversalStatus(s);
@ -129,9 +129,9 @@ static void restartTimer(tr_shared* s)
// 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;
if (auto const now = tr_time(); s->natpmp->renew_time > now) if (auto const now = tr_time(); s->natpmp->renewTime() > now)
{ {
timer->startSingleShot(std::chrono::seconds{ s->natpmp->renew_time - now }); timer->startSingleShot(std::chrono::seconds{ s->natpmp->renewTime() - now });
} }
else // ??? else // ???
{ {
@ -170,7 +170,7 @@ static void onTimer(void* vshared)
**** ****
***/ ***/
tr_shared* tr_sharedInit(tr_session* session) tr_shared* tr_sharedInit(tr_session& session)
{ {
return new tr_shared{ session }; return new tr_shared{ session };
} }
@ -185,8 +185,7 @@ static void stop_forwarding(tr_shared* s)
tr_logAddTrace("stopped"); tr_logAddTrace("stopped");
natPulse(s, false); natPulse(s, false);
tr_natpmpClose(s->natpmp); s->natpmp.reset();
s->natpmp = nullptr;
s->natpmpStatus = TR_PORT_UNMAPPED; s->natpmpStatus = TR_PORT_UNMAPPED;
tr_upnpClose(s->upnp); tr_upnpClose(s->upnp);
@ -196,19 +195,19 @@ static void stop_forwarding(tr_shared* s)
stop_timer(s); stop_timer(s);
} }
void tr_sharedClose(tr_session* session) void tr_sharedClose(tr_session& session)
{ {
tr_shared* shared = session->shared; tr_shared* shared = session.shared;
shared->isShuttingDown = true; shared->isShuttingDown = true;
stop_forwarding(shared); stop_forwarding(shared);
shared->session->shared = nullptr; shared->session.shared = nullptr;
delete shared; delete shared;
} }
static void start_timer(tr_shared* s) static void start_timer(tr_shared* s)
{ {
s->timer = s->session->timerMaker().create(onTimer, s); s->timer = s->session.timerMaker().create(onTimer, s);
restartTimer(s); restartTimer(s);
} }
@ -226,9 +225,9 @@ void tr_sharedTraversalEnable(tr_shared* s, bool is_enable)
} }
} }
void tr_sharedPortChanged(tr_session* session) void tr_sharedPortChanged(tr_session& session)
{ {
tr_shared* s = session->shared; auto* const s = session.shared;
if (s->isEnabled) if (s->isEnabled)
{ {

View File

@ -15,11 +15,11 @@ struct tr_bindsockets;
struct tr_session; struct tr_session;
struct tr_shared; struct tr_shared;
tr_shared* tr_sharedInit(tr_session*); tr_shared* tr_sharedInit(tr_session&);
void tr_sharedClose(tr_session*); void tr_sharedClose(tr_session&);
void tr_sharedPortChanged(tr_session*); void tr_sharedPortChanged(tr_session&);
void tr_sharedTraversalEnable(tr_shared*, bool is_enabled); void tr_sharedTraversalEnable(tr_shared*, bool is_enabled);

View File

@ -458,7 +458,7 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* setme_dictionary)
tr_variantDictAddInt(d, TR_KEY_speed_limit_up, tr_sessionGetSpeedLimit_KBps(s, TR_UP)); tr_variantDictAddInt(d, TR_KEY_speed_limit_up, tr_sessionGetSpeedLimit_KBps(s, TR_UP));
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, tr_sessionIsSpeedLimited(s, TR_UP)); tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, tr_sessionIsSpeedLimited(s, TR_UP));
tr_variantDictAddStr(d, TR_KEY_umask, fmt::format("{:#o}", s->umask)); tr_variantDictAddStr(d, TR_KEY_umask, fmt::format("{:#o}", s->umask));
tr_variantDictAddInt(d, TR_KEY_upload_slots_per_torrent, s->uploadSlotsPerTorrent); tr_variantDictAddInt(d, TR_KEY_upload_slots_per_torrent, s->upload_slots_per_torrent);
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, s->bind_ipv4.readable()); tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, s->bind_ipv4.readable());
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, s->bind_ipv6.readable()); tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, s->bind_ipv6.readable());
tr_variantDictAddBool(d, TR_KEY_start_added_torrents, !tr_sessionGetPaused(s)); tr_variantDictAddBool(d, TR_KEY_start_added_torrents, !tr_sessionGetPaused(s));
@ -722,7 +722,7 @@ static void tr_sessionInitImpl(init_data* data)
session->peerMgr = tr_peerMgrNew(session); session->peerMgr = tr_peerMgrNew(session);
session->shared = tr_sharedInit(session); session->shared = tr_sharedInit(*session);
/** /**
*** Blocklist *** Blocklist
@ -1016,7 +1016,7 @@ static void sessionSetImpl(struct init_data* const data)
if (tr_variantDictFindInt(settings, TR_KEY_upload_slots_per_torrent, &i)) if (tr_variantDictFindInt(settings, TR_KEY_upload_slots_per_torrent, &i))
{ {
session->uploadSlotsPerTorrent = i; session->upload_slots_per_torrent = i;
} }
if (tr_variantDictFindInt(settings, TR_KEY_speed_limit_up, &i)) if (tr_variantDictFindInt(settings, TR_KEY_speed_limit_up, &i))
@ -1254,7 +1254,7 @@ static void peerPortChanged(tr_session* const session)
close_incoming_peer_port(session); close_incoming_peer_port(session);
open_incoming_peer_port(session); open_incoming_peer_port(session);
tr_sharedPortChanged(session); tr_sharedPortChanged(*session);
for (auto* const tor : session->torrents()) for (auto* const tor : session->torrents())
{ {
@ -1855,7 +1855,7 @@ static void sessionCloseImplStart(tr_session* session)
session->now_timer_.reset(); session->now_timer_.reset();
tr_verifyClose(session); tr_verifyClose(session);
tr_sharedClose(session); tr_sharedClose(*session);
close_incoming_peer_port(session); close_incoming_peer_port(session);
session->rpc_server_.reset(); session->rpc_server_.reset();

View File

@ -507,7 +507,7 @@ public:
uint16_t peerLimit = 200; uint16_t peerLimit = 200;
uint16_t peerLimitPerTorrent = 50; uint16_t peerLimitPerTorrent = 50;
int uploadSlotsPerTorrent = 0; uint16_t upload_slots_per_torrent = 0;
/* The UDP sockets used for the DHT and uTP. */ /* The UDP sockets used for the DHT and uTP. */
tr_port udp_port; tr_port udp_port;

View File

@ -107,50 +107,45 @@ bool tr_torrentSetMetadataSizeHint(tr_torrent* tor, int64_t size)
return true; return true;
} }
void* tr_torrentGetMetadataPiece(tr_torrent const* tor, int piece, size_t* len) std::optional<std::vector<std::byte>> tr_torrentGetMetadataPiece(tr_torrent const* tor, int piece)
{ {
TR_ASSERT(tr_isTorrent(tor)); TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(piece >= 0); TR_ASSERT(piece >= 0);
TR_ASSERT(len != nullptr);
if (!tor->hasMetainfo()) if (!tor->hasMetainfo())
{ {
return nullptr; return {};
} }
auto const fd = tr_sys_file_open(tor->torrentFile(), TR_SYS_FILE_READ, 0); auto const fd = tr_sys_file_open(tor->torrentFile(), TR_SYS_FILE_READ, 0);
if (fd == TR_BAD_SYS_FILE) if (fd == TR_BAD_SYS_FILE)
{ {
return nullptr; return {};
} }
auto const info_dict_size = tor->infoDictSize(); auto const info_dict_size = tor->infoDictSize();
TR_ASSERT(info_dict_size > 0); TR_ASSERT(info_dict_size > 0);
char* ret = nullptr;
if (size_t const o = piece * METADATA_PIECE_SIZE; tr_sys_file_seek(fd, tor->infoDictOffset() + o, TR_SEEK_SET, nullptr)) if (size_t const o = piece * METADATA_PIECE_SIZE; tr_sys_file_seek(fd, tor->infoDictOffset() + o, TR_SEEK_SET, nullptr))
{ {
size_t const l = o + METADATA_PIECE_SIZE <= info_dict_size ? METADATA_PIECE_SIZE : info_dict_size - o; size_t const piece_len = o + METADATA_PIECE_SIZE <= info_dict_size ? METADATA_PIECE_SIZE : info_dict_size - o;
if (0 < l && l <= METADATA_PIECE_SIZE) if (piece_len <= METADATA_PIECE_SIZE)
{ {
auto* buf = tr_new(char, l); auto buf = std::vector<std::byte>{};
buf.resize(piece_len);
if (auto n = uint64_t{}; tr_sys_file_read(fd, buf, l, &n) && n == l) if (auto n_read = uint64_t{};
tr_sys_file_read(fd, std::data(buf), std::size(buf), &n_read) && n_read == std::size(buf))
{ {
*len = l; tr_sys_file_close(fd);
ret = buf; return buf;
buf = nullptr;
} }
tr_free(buf);
} }
} }
tr_sys_file_close(fd); tr_sys_file_close(fd);
return {};
TR_ASSERT(ret == nullptr || *len > 0);
return ret;
} }
static int getPieceLength(struct tr_incomplete_metadata const* m, int piece) static int getPieceLength(struct tr_incomplete_metadata const* m, int piece)

View File

@ -9,9 +9,11 @@
#error only libtransmission should #include this header. #error only libtransmission should #include this header.
#endif #endif
#include <cstdint> // int64_t
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // int64_t
#include <ctime> // time_t #include <ctime> // time_t
#include <optional>
#include <vector>
#include "transmission.h" #include "transmission.h"
@ -21,7 +23,7 @@ struct tr_torrent_metainfo;
// defined by BEP #9 // defined by BEP #9
inline constexpr int METADATA_PIECE_SIZE = 1024 * 16; inline constexpr int METADATA_PIECE_SIZE = 1024 * 16;
void* tr_torrentGetMetadataPiece(tr_torrent const* tor, int piece, size_t* len); std::optional<std::vector<std::byte>> tr_torrentGetMetadataPiece(tr_torrent const* tor, int piece);
void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, int len); void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, int len);

View File

@ -1264,7 +1264,7 @@ tr_peer_stat* tr_torrentPeers(tr_torrent const* tor, int* peerCount)
void tr_torrentPeersFree(tr_peer_stat* peers, int /*peerCount*/) void tr_torrentPeersFree(tr_peer_stat* peers, int /*peerCount*/)
{ {
tr_free(peers); delete[] peers;
} }
void tr_torrentAvailability(tr_torrent const* tor, int8_t* tab, int size) void tr_torrentAvailability(tr_torrent const* tor, int8_t* tab, int size)

View File

@ -252,12 +252,13 @@
for (tr_log_message* currentMessage = messages; currentMessage != NULL; currentMessage = currentMessage->next) for (tr_log_message* currentMessage = messages; currentMessage != NULL; currentMessage = currentMessage->next)
{ {
NSString* name = currentMessage->name != NULL ? @(currentMessage->name) : NSProcessInfo.processInfo.processName; NSString* name = !std::empty(currentMessage->name) ? @(currentMessage->name.c_str()) : NSProcessInfo.processInfo.processName;
NSString* file = [(@(currentMessage->file)).lastPathComponent stringByAppendingFormat:@":%d", currentMessage->line]; auto const file_string = std::string{ currentMessage->file };
NSString* file = [(@(file_string.c_str())).lastPathComponent stringByAppendingFormat:@":%d", currentMessage->line];
NSDictionary* message = @{ NSDictionary* message = @{
@"Message" : @(currentMessage->message), @"Message" : @(currentMessage->message.c_str()),
@"Date" : [NSDate dateWithTimeIntervalSince1970:currentMessage->when], @"Date" : [NSDate dateWithTimeIntervalSince1970:currentMessage->when],
@"Index" : @(currentIndex++), //more accurate when sorting by date @"Index" : @(currentIndex++), //more accurate when sorting by date
@"Level" : @(currentMessage->level), @"Level" : @(currentMessage->level),