refactor: tr_globalIPv6() returns a std::optional<in6_addr> (#3836)

This commit is contained in:
Charles Kerr
2022-09-21 23:59:31 -05:00
committed by GitHub
parent dd12fd010a
commit 228efa16e3
7 changed files with 43 additions and 62 deletions

View File

@@ -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,

View File

@@ -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));

View File

@@ -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;
}
/***

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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
{