mirror of
https://github.com/transmission/transmission.git
synced 2025-12-24 20:35:36 +00:00
refactor: tr_globalIPv6() returns a std::optional<in6_addr> (#3836)
This commit is contained in:
@@ -12,6 +12,7 @@ Checks: >
|
||||
cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
cppcoreguidelines-init-variables,
|
||||
cppcoreguidelines-interfaces-global-init,
|
||||
cppcoreguidelines-no-malloc,
|
||||
cppcoreguidelines-prefer-member-initializer,
|
||||
cppcoreguidelines-slicing,
|
||||
cppcoreguidelines-special-member-functions,
|
||||
|
||||
@@ -113,10 +113,10 @@ static std::string format_ipv4_url_arg(tr_address const& ipv4_address)
|
||||
return "&ipv4="s + readable.data();
|
||||
}
|
||||
|
||||
static std::string format_ipv6_url_arg(unsigned char const* ipv6_address)
|
||||
static std::string format_ipv6_url_arg(in6_addr const addr)
|
||||
{
|
||||
std::array<char, INET6_ADDRSTRLEN> readable;
|
||||
evutil_inet_ntop(AF_INET6, ipv6_address, readable.data(), readable.size());
|
||||
evutil_inet_ntop(AF_INET6, &addr, std::data(readable), std::size(readable));
|
||||
|
||||
auto arg = "&ipv6="s;
|
||||
tr_urlPercentEncode(std::back_inserter(arg), readable.data());
|
||||
@@ -436,7 +436,7 @@ void tr_tracker_http_announce(
|
||||
session->web->fetch(std::move(opt));
|
||||
};
|
||||
|
||||
auto ipv6 = tr_globalIPv6(session);
|
||||
auto const ipv6 = tr_globalIPv6(session);
|
||||
|
||||
/*
|
||||
* Before Curl 7.77.0, if we explicitly choose the IP version we want
|
||||
@@ -451,13 +451,13 @@ void tr_tracker_http_announce(
|
||||
{
|
||||
options.url += format_ip_arg(session->announceIP());
|
||||
}
|
||||
else if (ipv6 != nullptr)
|
||||
else if (ipv6)
|
||||
{
|
||||
if (auto public_ipv4 = session->externalIP(); public_ipv4.has_value())
|
||||
{
|
||||
options.url += format_ipv4_url_arg(*public_ipv4);
|
||||
}
|
||||
options.url += format_ipv6_url_arg(ipv6);
|
||||
options.url += format_ipv6_url_arg(*ipv6);
|
||||
}
|
||||
|
||||
d->requests_sent_count = 1;
|
||||
@@ -465,7 +465,7 @@ void tr_tracker_http_announce(
|
||||
}
|
||||
else
|
||||
{
|
||||
if (session->useAnnounceIP() || ipv6 == nullptr)
|
||||
if (session->useAnnounceIP() || !ipv6)
|
||||
{
|
||||
if (session->useAnnounceIP())
|
||||
{
|
||||
@@ -481,7 +481,7 @@ void tr_tracker_http_announce(
|
||||
// First try to send the announce via IPv4:
|
||||
auto ipv4_options = options;
|
||||
// Set the "&ipv6=" argument
|
||||
ipv4_options.url += format_ipv6_url_arg(ipv6);
|
||||
ipv4_options.url += format_ipv6_url_arg(*ipv6);
|
||||
// Set protocol to IPv4
|
||||
ipv4_options.ip_proto = tr_web::FetchOptions::IPProtocol::V4;
|
||||
do_make_request("IPv4"sv, std::move(ipv4_options));
|
||||
|
||||
@@ -709,44 +709,43 @@ static int tr_globalAddress(int af, void* addr, int* addr_len)
|
||||
}
|
||||
|
||||
/* Return our global IPv6 address, with caching. */
|
||||
unsigned char const* tr_globalIPv6(tr_session const* session)
|
||||
std::optional<in6_addr> tr_globalIPv6(tr_session const* session)
|
||||
{
|
||||
static auto ipv6 = std::array<unsigned char, 16>{};
|
||||
static auto ipv6 = in6_addr{};
|
||||
static time_t last_time = 0;
|
||||
static bool have_ipv6 = false;
|
||||
|
||||
/* Re-check every half hour */
|
||||
if (auto const now = tr_time(); last_time < now - 1800)
|
||||
{
|
||||
int addrlen = 16;
|
||||
int const rc = tr_globalAddress(AF_INET6, std::data(ipv6), &addrlen);
|
||||
have_ipv6 = rc >= 0 && addrlen == 16;
|
||||
int addrlen = sizeof(ipv6);
|
||||
int const rc = tr_globalAddress(AF_INET6, &ipv6, &addrlen);
|
||||
have_ipv6 = rc >= 0 && addrlen == sizeof(ipv6);
|
||||
last_time = now;
|
||||
}
|
||||
|
||||
if (!have_ipv6)
|
||||
{
|
||||
return nullptr; /* No IPv6 address at all. */
|
||||
return {}; // no IPv6 address at all
|
||||
}
|
||||
|
||||
/* Return the default address.
|
||||
* This is useful for checking for connectivity in general. */
|
||||
// Return the default address.
|
||||
// This is useful for checking for connectivity in general.
|
||||
if (session == nullptr)
|
||||
{
|
||||
return std::data(ipv6);
|
||||
return ipv6;
|
||||
}
|
||||
|
||||
/* We have some sort of address, now make sure that we return
|
||||
our bound address if non-default. */
|
||||
|
||||
// We have some sort of address.
|
||||
// Now make sure that we return our bound address if non-default.
|
||||
auto const [ipv6_bindaddr, is_default] = session->publicAddress(TR_AF_INET6);
|
||||
if (!is_default)
|
||||
{
|
||||
/* Explicitly bound. Return that address. */
|
||||
memcpy(std::data(ipv6), ipv6_bindaddr.addr.addr6.s6_addr, 16);
|
||||
// return this explicitly-bound address
|
||||
ipv6 = ipv6_bindaddr.addr.addr6;
|
||||
}
|
||||
|
||||
return std::data(ipv6);
|
||||
return ipv6;
|
||||
}
|
||||
|
||||
/***
|
||||
|
||||
@@ -246,4 +246,4 @@ void tr_netSetTOS(tr_socket_t sock, int tos, tr_address_type type);
|
||||
*/
|
||||
[[nodiscard]] std::string tr_net_strerror(int err);
|
||||
|
||||
unsigned char const* tr_globalIPv6(tr_session const* session);
|
||||
[[nodiscard]] std::optional<in6_addr> tr_globalIPv6(tr_session const* session);
|
||||
|
||||
@@ -284,7 +284,7 @@ public:
|
||||
if (tr_dhtEnabled(torrent->session) && io->supportsDHT())
|
||||
{
|
||||
/* Only send PORT over IPv6 when the IPv6 DHT is running (BEP-32). */
|
||||
if (io->address().isIPv4() || tr_globalIPv6(nullptr) != nullptr)
|
||||
if (io->address().isIPv4() || tr_globalIPv6(nullptr).has_value())
|
||||
{
|
||||
protocolSendPort(this, tr_dhtPort(torrent->session));
|
||||
}
|
||||
@@ -915,7 +915,7 @@ static void cancelAllRequestsToClient(tr_peerMsgsImpl* msgs)
|
||||
static void sendLtepHandshake(tr_peerMsgsImpl* msgs)
|
||||
{
|
||||
evbuffer* const out = msgs->outMessages;
|
||||
unsigned char const* ipv6 = tr_globalIPv6(msgs->io->session);
|
||||
auto const ipv6 = tr_globalIPv6(msgs->io->session);
|
||||
static tr_quark version_quark = 0;
|
||||
|
||||
if (msgs->clientSentLtepHandshake)
|
||||
@@ -953,9 +953,9 @@ static void sendLtepHandshake(tr_peerMsgsImpl* msgs)
|
||||
tr_variantInitDict(&val, 8);
|
||||
tr_variantDictAddBool(&val, TR_KEY_e, msgs->session->encryptionMode() != TR_CLEAR_PREFERRED);
|
||||
|
||||
if (ipv6 != nullptr)
|
||||
if (ipv6.has_value())
|
||||
{
|
||||
tr_variantDictAddRaw(&val, TR_KEY_ipv6, ipv6, 16);
|
||||
tr_variantDictAddRaw(&val, TR_KEY_ipv6, &*ipv6, sizeof(*ipv6));
|
||||
}
|
||||
|
||||
// http://bittorrent.org/beps/bep_0009.html
|
||||
|
||||
@@ -516,7 +516,7 @@ public:
|
||||
tr_session& session_;
|
||||
struct event* udp_event_ = nullptr;
|
||||
struct event* udp6_event_ = nullptr;
|
||||
unsigned char* udp6_bound_ = nullptr;
|
||||
std::optional<in6_addr> udp6_bound_;
|
||||
tr_socket_t udp_socket_ = TR_BAD_SOCKET;
|
||||
tr_socket_t udp6_socket_ = TR_BAD_SOCKET;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring> /* memcmp(), memcpy(), memset() */
|
||||
#include <cstdlib> /* malloc(), free() */
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h> /* dup2() */
|
||||
@@ -111,24 +110,19 @@ void tr_session::tr_udp_core::set_socket_buffers()
|
||||
void tr_session::tr_udp_core::rebind_ipv6(bool force)
|
||||
{
|
||||
struct sockaddr_in6 sin6;
|
||||
unsigned char const* ipv6 = tr_globalIPv6(&session_);
|
||||
auto const ipv6 = tr_globalIPv6(&session_);
|
||||
int rc = -1;
|
||||
int one = 1;
|
||||
|
||||
/* We currently have no way to enable or disable IPv6 after initialisation.
|
||||
No way to fix that without some surgery to the DHT code itself. */
|
||||
if (ipv6 == nullptr || (!force && udp6_socket_ == TR_BAD_SOCKET))
|
||||
if (!ipv6 || (!force && udp6_socket_ == TR_BAD_SOCKET))
|
||||
{
|
||||
if (udp6_bound_ != nullptr)
|
||||
{
|
||||
free(udp6_bound_);
|
||||
udp6_bound_ = nullptr;
|
||||
}
|
||||
|
||||
udp6_bound_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (udp6_bound_ != nullptr && memcmp(ipv6, udp6_bound_, 16) == 0)
|
||||
if (udp6_bound_ && memcmp(&*udp6_bound_, &*ipv6, sizeof(*ipv6)) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -149,9 +143,9 @@ void tr_session::tr_udp_core::rebind_ipv6(bool force)
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
|
||||
if (ipv6 != nullptr)
|
||||
if (ipv6)
|
||||
{
|
||||
memcpy(&sin6.sin6_addr, ipv6, 16);
|
||||
sin6.sin6_addr = *ipv6;
|
||||
}
|
||||
|
||||
sin6.sin6_port = udp_port_.network();
|
||||
@@ -180,16 +174,7 @@ void tr_session::tr_udp_core::rebind_ipv6(bool force)
|
||||
tr_netCloseSocket(s);
|
||||
}
|
||||
|
||||
if (udp6_bound_ == nullptr)
|
||||
{
|
||||
udp6_bound_ = static_cast<unsigned char*>(malloc(16));
|
||||
}
|
||||
|
||||
if (udp6_bound_ != nullptr)
|
||||
{
|
||||
memcpy(udp6_bound_, ipv6, 16);
|
||||
}
|
||||
|
||||
udp6_bound_ = ipv6;
|
||||
return;
|
||||
|
||||
FAIL:
|
||||
@@ -197,7 +182,7 @@ FAIL:
|
||||
set things up so that we try again next time. */
|
||||
auto const error_code = errno;
|
||||
auto ipv6_readable = std::array<char, INET6_ADDRSTRLEN>{};
|
||||
evutil_inet_ntop(AF_INET6, ipv6, std::data(ipv6_readable), std::size(ipv6_readable));
|
||||
evutil_inet_ntop(AF_INET6, &*ipv6, std::data(ipv6_readable), std::size(ipv6_readable));
|
||||
tr_logAddWarn(fmt::format(
|
||||
_("Couldn't rebind IPv6 socket {address}: {error} ({error_code})"),
|
||||
fmt::arg("address", std::data(ipv6_readable)),
|
||||
@@ -209,11 +194,7 @@ FAIL:
|
||||
tr_netCloseSocket(s);
|
||||
}
|
||||
|
||||
if (udp6_bound_ != nullptr)
|
||||
{
|
||||
free(udp6_bound_);
|
||||
udp6_bound_ = nullptr;
|
||||
}
|
||||
udp6_bound_.reset();
|
||||
}
|
||||
|
||||
static void event_callback(evutil_socket_t s, [[maybe_unused]] short type, void* vsession)
|
||||
@@ -319,7 +300,7 @@ tr_session::tr_udp_core::tr_udp_core(tr_session& session)
|
||||
|
||||
// IPV6
|
||||
|
||||
if (tr_globalIPv6(nullptr) != nullptr)
|
||||
if (tr_globalIPv6(nullptr).has_value())
|
||||
{
|
||||
rebind_ipv6(true);
|
||||
}
|
||||
@@ -380,11 +361,7 @@ tr_session::tr_udp_core::~tr_udp_core()
|
||||
udp6_event_ = nullptr;
|
||||
}
|
||||
|
||||
if (udp6_bound_ != nullptr)
|
||||
{
|
||||
free(udp6_bound_);
|
||||
udp6_bound_ = nullptr;
|
||||
}
|
||||
udp6_bound_.reset();
|
||||
}
|
||||
|
||||
void tr_session::tr_udp_core::sendto(void const* buf, size_t buflen, struct sockaddr const* to, socklen_t const tolen) const
|
||||
@@ -397,7 +374,9 @@ void tr_session::tr_udp_core::sendto(void const* buf, size_t buflen, struct sock
|
||||
if (udp_socket_ != TR_BAD_SOCKET)
|
||||
{
|
||||
if (::sendto(udp_socket_, static_cast<char const*>(buf), buflen, 0, to, tolen) == -1)
|
||||
{
|
||||
error = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -418,7 +397,9 @@ void tr_session::tr_udp_core::sendto(void const* buf, size_t buflen, struct sock
|
||||
if (udp6_socket_ != TR_BAD_SOCKET)
|
||||
{
|
||||
if (::sendto(udp6_socket_, static_cast<char const*>(buf), buflen, 0, to, tolen) == -1)
|
||||
{
|
||||
error = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user