refactor: tr_address cleanup (#3422)

* refactor: remove tr_address_compare()

* refactor: remove tr_address_to_string()

* refactor: remove NUM_TR_AF_INET_TYPES

* refactor: replace tr_sessionGetPublicAddress with tr_session::getPublicAddress()

* refactor: tr_peerIo() takes tr_address by value

* refactor: replace tr_sessionIsAddressBlocked with tr_session::isAddressBlocked()

* refactor: tr_peerMgrAddIncoming now takes tr_address by value

* refactor: replace tr_address_is_valid_for_peers() with tr_address.isValidForPeers()

* refactor: tr_netOpenPeerSocket takes tr_address by value

* refactor: remove tr_generateAllowedSet()

* refactor: setup_sockaddr takes a tr_address by value

* refactor: tr_netBindTCP() takes a tr_address by value

* refactor: tr_dhtAddNode() takes a tr_address by value

* refactor: remove tr_address_from_string()

* refactor: rename tr_address.isValidForPeers() to .isValidPeerAddress()

* refactor: replace tr_address_from_sockaddr_storage() with tr_address::fromSockaddrStorage()

* refactor: minor cleanup to tr_address::readable()
This commit is contained in:
Charles Kerr 2022-07-08 13:23:41 -05:00 committed by GitHub
parent 745adf8332
commit 9a44eeaa27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 217 additions and 432 deletions

View File

@ -184,7 +184,7 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
{ {
BasicHandler::EndDict(context); BasicHandler::EndDict(context);
if (tr_address_is_valid_for_peers(&pex_.addr, pex_.port)) if (pex_.addr.isValidPeerAddress(pex_.port))
{ {
response_.pex.push_back(pex_); response_.pex.push_back(pex_);
pex_ = {}; pex_ = {};
@ -251,7 +251,10 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
} }
else if (key == "ip") else if (key == "ip")
{ {
tr_address_from_string(&pex_.addr, value); if (auto const addr = tr_address::fromString(value))
{
pex_.addr = *addr;
}
} }
else if (key == "peer id") else if (key == "peer id")
{ {

View File

@ -155,9 +155,9 @@ bool BlocklistFile::parseLine1(std::string_view line, struct IPv4Range* range)
{ {
return false; return false;
} }
if (auto addr = tr_address{}; tr_address_from_string(&addr, line.substr(0, pos))) if (auto const addr = tr_address::fromString(line.substr(0, pos)); addr)
{ {
range->begin_ = ntohl(addr.addr.addr4.s_addr); range->begin_ = ntohl(addr->addr.addr4.s_addr);
} }
else else
{ {
@ -166,9 +166,9 @@ bool BlocklistFile::parseLine1(std::string_view line, struct IPv4Range* range)
line = line.substr(pos + 1); line = line.substr(pos + 1);
// parse the trailing 'y.y.y.y' // parse the trailing 'y.y.y.y'
if (auto addr = tr_address{}; tr_address_from_string(&addr, line)) if (auto const addr = tr_address::fromString(line); addr)
{ {
range->end_ = ntohl(addr.addr.addr4.s_addr); range->end_ = ntohl(addr->addr.addr4.s_addr);
} }
else else
{ {
@ -193,9 +193,9 @@ bool BlocklistFile::parseLine2(std::string_view line, struct IPv4Range* range)
return false; return false;
} }
if (auto addr = tr_address{}; tr_address_from_string(&addr, line.substr(0, pos))) if (auto const addr = tr_address::fromString(line.substr(0, pos)); addr)
{ {
range->begin_ = ntohl(addr.addr.addr4.s_addr); range->begin_ = ntohl(addr->addr.addr4.s_addr);
} }
else else
{ {
@ -209,9 +209,9 @@ bool BlocklistFile::parseLine2(std::string_view line, struct IPv4Range* range)
return false; return false;
} }
if (auto addr = tr_address{}; tr_address_from_string(&addr, line.substr(0, pos))) if (auto const addr = tr_address::fromString(line.substr(0, pos)); addr)
{ {
range->end_ = ntohl(addr.addr.addr4.s_addr); range->end_ = ntohl(addr->addr.addr4.s_addr);
} }
else else
{ {

View File

@ -61,86 +61,6 @@ std::string tr_net_strerror(int err)
#endif #endif
} }
char const* tr_address_and_port_to_string(char* buf, size_t buflen, tr_address const* addr, tr_port port)
{
char addr_buf[INET6_ADDRSTRLEN];
tr_address_to_string_with_buf(addr, addr_buf, sizeof(addr_buf));
*fmt::format_to_n(buf, buflen - 1, FMT_STRING("[{:s}]:{:d}"), addr_buf, port.host()).out = '\0';
return buf;
}
char const* tr_address_to_string_with_buf(tr_address const* addr, char* buf, size_t buflen)
{
TR_ASSERT(tr_address_is_valid(addr));
return addr->type == TR_AF_INET ? evutil_inet_ntop(AF_INET, &addr->addr, buf, buflen) :
evutil_inet_ntop(AF_INET6, &addr->addr, buf, buflen);
}
/*
* Non-threadsafe version of tr_address_to_string_with_buf()
* and uses a static memory area for a buffer.
* This function is suitable to be called from libTransmission's networking code,
* which is single-threaded.
*/
char const* tr_address_to_string(tr_address const* addr)
{
static char buf[INET6_ADDRSTRLEN];
return tr_address_to_string_with_buf(addr, buf, sizeof(buf));
}
bool tr_address_from_string(tr_address* dst, char const* src)
{
if (evutil_inet_pton(AF_INET, src, &dst->addr) == 1)
{
dst->type = TR_AF_INET;
return true;
}
if (evutil_inet_pton(AF_INET6, src, &dst->addr) == 1)
{
dst->type = TR_AF_INET6;
return true;
}
return false;
}
bool tr_address_from_string(tr_address* dst, std::string_view src)
{
// inet_pton() requires zero-terminated strings,
// so make a zero-terminated copy here on the stack.
auto buf = std::array<char, TR_ADDRSTRLEN>{};
if (std::size(src) >= std::size(buf))
{
// shouldn't ever be that large; malformed address
return false;
}
*std::copy(std::begin(src), std::end(src), std::begin(buf)) = '\0';
return tr_address_from_string(dst, std::data(buf));
}
/*
* Compare two tr_address structures.
* Returns:
* <0 if a < b
* >0 if a > b
* 0 if a == b
*/
int tr_address_compare(tr_address const* a, tr_address const* b) noexcept
{
// IPv6 addresses are always "greater than" IPv4
if (a->type != b->type)
{
return a->type == TR_AF_INET ? 1 : -1;
}
return a->type == TR_AF_INET ? memcmp(&a->addr.addr4, &b->addr.addr4, sizeof(a->addr.addr4)) :
memcmp(&a->addr.addr6.s6_addr, &b->addr.addr6.s6_addr, sizeof(a->addr.addr6.s6_addr));
}
/*********************************************************************** /***********************************************************************
* TCP sockets * TCP sockets
**********************************************************************/ **********************************************************************/
@ -247,38 +167,36 @@ void tr_netSetCongestionControl([[maybe_unused]] tr_socket_t s, [[maybe_unused]]
#endif #endif
} }
bool tr_address_from_sockaddr_storage(tr_address* setme_addr, tr_port* setme_port, struct sockaddr_storage const* from) std::optional<std::pair<tr_address, tr_port>> tr_address::fromSockaddrStorage(sockaddr_storage from)
{ {
if (from->ss_family == AF_INET) if (from.ss_family == AF_INET)
{ {
auto const* const sin = (struct sockaddr_in const*)from; auto const* const sin = reinterpret_cast<sockaddr_in const*>(&from);
setme_addr->type = TR_AF_INET; auto tmp = tr_address{};
setme_addr->addr.addr4.s_addr = sin->sin_addr.s_addr; tmp.type = TR_AF_INET;
*setme_port = tr_port::fromNetwork(sin->sin_port); tmp.addr.addr4.s_addr = sin->sin_addr.s_addr;
return true; return std::make_pair(tmp, tr_port::fromNetwork(sin->sin_port));
} }
if (from->ss_family == AF_INET6) if (from.ss_family == AF_INET6)
{ {
auto const* const sin6 = (struct sockaddr_in6 const*)from; auto const* const sin6 = reinterpret_cast<sockaddr_in6 const*>(&from);
setme_addr->type = TR_AF_INET6; auto tmp = tr_address{};
setme_addr->addr.addr6 = sin6->sin6_addr; tmp.type = TR_AF_INET6;
*setme_port = tr_port::fromNetwork(sin6->sin6_port); tmp.addr.addr6 = sin6->sin6_addr;
return true; return std::make_pair(tmp, tr_port::fromNetwork(sin6->sin6_port));
} }
return false; return {};
} }
static socklen_t setup_sockaddr(tr_address const* addr, tr_port port, struct sockaddr_storage* sockaddr) static socklen_t setup_sockaddr(tr_address addr, tr_port port, struct sockaddr_storage* sockaddr)
{ {
TR_ASSERT(tr_address_is_valid(addr)); if (addr.type == TR_AF_INET)
if (addr->type == TR_AF_INET)
{ {
sockaddr_in sock4 = {}; sockaddr_in sock4 = {};
sock4.sin_family = AF_INET; sock4.sin_family = AF_INET;
sock4.sin_addr.s_addr = addr->addr.addr4.s_addr; sock4.sin_addr.s_addr = addr.addr.addr4.s_addr;
sock4.sin_port = port.network(); sock4.sin_port = port.network();
memcpy(sockaddr, &sock4, sizeof(sock4)); memcpy(sockaddr, &sock4, sizeof(sock4));
return sizeof(struct sockaddr_in); return sizeof(struct sockaddr_in);
@ -288,7 +206,7 @@ static socklen_t setup_sockaddr(tr_address const* addr, tr_port port, struct soc
sock6.sin6_family = AF_INET6; sock6.sin6_family = AF_INET6;
sock6.sin6_port = port.network(); sock6.sin6_port = port.network();
sock6.sin6_flowinfo = 0; sock6.sin6_flowinfo = 0;
sock6.sin6_addr = addr->addr.addr6; sock6.sin6_addr = addr.addr.addr6;
memcpy(sockaddr, &sock6, sizeof(sock6)); memcpy(sockaddr, &sock6, sizeof(sock6));
return sizeof(struct sockaddr_in6); return sizeof(struct sockaddr_in6);
} }
@ -341,17 +259,15 @@ static tr_socket_t createSocket(tr_session* session, int domain, int type)
return sockfd; return sockfd;
} }
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool client_is_seed) struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address addr, tr_port port, bool client_is_seed)
{ {
TR_ASSERT(tr_address_is_valid(addr)); if (!addr.isValidPeerAddress(port))
if (!tr_address_is_valid_for_peers(addr, port))
{ {
return {}; return {};
} }
static auto constexpr Domains = std::array<int, NUM_TR_AF_INET_TYPES>{ AF_INET, AF_INET6 }; static auto constexpr Domains = std::array<int, 2>{ AF_INET, AF_INET6 };
auto const s = createSocket(session, Domains[addr->type], SOCK_STREAM); auto const s = createSocket(session, Domains[addr.type], SOCK_STREAM);
if (s == TR_BAD_SOCKET) if (s == TR_BAD_SOCKET)
{ {
return {}; return {};
@ -372,8 +288,7 @@ struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const
socklen_t const addrlen = setup_sockaddr(addr, port, &sock); socklen_t const addrlen = setup_sockaddr(addr, port, &sock);
// set source address // set source address
tr_address const* const source_addr = tr_sessionGetPublicAddress(session, addr->type, nullptr); auto const [source_addr, is_default_addr] = session->getPublicAddress(addr.type);
TR_ASSERT(source_addr != nullptr);
struct sockaddr_storage source_sock; struct sockaddr_storage source_sock;
socklen_t const sourcelen = setup_sockaddr(source_addr, {}, &source_sock); socklen_t const sourcelen = setup_sockaddr(source_addr, {}, &source_sock);
@ -381,7 +296,7 @@ struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const
{ {
tr_logAddWarn(fmt::format( tr_logAddWarn(fmt::format(
_("Couldn't set source address {address} on {socket}: {error} ({error_code})"), _("Couldn't set source address {address} on {socket}: {error} ({error_code})"),
fmt::arg("address", source_addr->readable()), fmt::arg("address", source_addr.readable()),
fmt::arg("socket", s), fmt::arg("socket", s),
fmt::arg("error", tr_net_strerror(sockerrno)), fmt::arg("error", tr_net_strerror(sockerrno)),
fmt::arg("error_code", sockerrno))); fmt::arg("error_code", sockerrno)));
@ -398,12 +313,12 @@ struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const
{ {
int const tmperrno = sockerrno; int const tmperrno = sockerrno;
if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr->type == TR_AF_INET) if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr.type == TR_AF_INET)
{ {
tr_logAddWarn(fmt::format( tr_logAddWarn(fmt::format(
_("Couldn't connect socket {socket} to {address}:{port}: {error} ({error_code})"), _("Couldn't connect socket {socket} to {address}:{port}: {error} ({error_code})"),
fmt::arg("socket", s), fmt::arg("socket", s),
fmt::arg("address", addr->readable()), fmt::arg("address", addr.readable()),
fmt::arg("port", port.host()), fmt::arg("port", port.host()),
fmt::arg("error", tr_net_strerror(tmperrno)), fmt::arg("error", tr_net_strerror(tmperrno)),
fmt::arg("error_code", tmperrno))); fmt::arg("error_code", tmperrno)));
@ -416,22 +331,16 @@ struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const
ret = tr_peer_socket_tcp_create(s); ret = tr_peer_socket_tcp_create(s);
} }
char addrstr[TR_ADDRSTRLEN]; tr_logAddTrace(fmt::format("New OUTGOING connection {} ({})", s, addr.readable(port)));
tr_address_and_port_to_string(addrstr, sizeof(addrstr), addr, port);
tr_logAddTrace(fmt::format("New OUTGOING connection {} ({})", s, addrstr));
return ret; return ret;
} }
struct tr_peer_socket tr_netOpenPeerUTPSocket( struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address addr, tr_port port, bool /*client_is_seed*/)
tr_session* session,
tr_address const* addr,
tr_port port,
bool /*client_is_seed*/)
{ {
auto ret = tr_peer_socket{}; auto ret = tr_peer_socket{};
if (session->utp_context != nullptr && tr_address_is_valid_for_peers(addr, port)) if (session->utp_context != nullptr && addr.isValidPeerAddress(port))
{ {
struct sockaddr_storage ss; struct sockaddr_storage ss;
socklen_t const sslen = setup_sockaddr(addr, port, &ss); socklen_t const sslen = setup_sockaddr(addr, port, &ss);
@ -476,14 +385,12 @@ void tr_netClosePeerSocket(tr_session* session, tr_peer_socket socket)
} }
} }
static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool suppressMsgs, int* errOut) static tr_socket_t tr_netBindTCPImpl(tr_address addr, tr_port port, bool suppressMsgs, int* errOut)
{ {
TR_ASSERT(tr_address_is_valid(addr)); static auto constexpr Domains = std::array<int, 2>{ AF_INET, AF_INET6 };
static int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 };
struct sockaddr_storage sock; struct sockaddr_storage sock;
auto const fd = socket(domains[addr->type], SOCK_STREAM, 0); auto const fd = socket(Domains[addr.type], SOCK_STREAM, 0);
if (fd == TR_BAD_SOCKET) if (fd == TR_BAD_SOCKET)
{ {
*errOut = sockerrno; *errOut = sockerrno;
@ -503,7 +410,7 @@ static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
if ((addr->type == TR_AF_INET6) && if ((addr.type == TR_AF_INET6) &&
(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char const*>(&optval), sizeof(optval)) == -1) && (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char const*>(&optval), sizeof(optval)) == -1) &&
(sockerrno != ENOPROTOOPT)) // if the kernel doesn't support it, ignore it (sockerrno != ENOPROTOOPT)) // if the kernel doesn't support it, ignore it
{ {
@ -526,7 +433,7 @@ static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool
err == EADDRINUSE ? err == EADDRINUSE ?
_("Couldn't bind port {port} on {address}: {error} ({error_code}) -- Is another copy of Transmission already running?") : _("Couldn't bind port {port} on {address}: {error} ({error_code}) -- Is another copy of Transmission already running?") :
_("Couldn't bind port {port} on {address}: {error} ({error_code})"), _("Couldn't bind port {port} on {address}: {error} ({error_code})"),
fmt::arg("address", addr->readable()), fmt::arg("address", addr.readable()),
fmt::arg("port", port.host()), fmt::arg("port", port.host()),
fmt::arg("error", tr_net_strerror(err)), fmt::arg("error", tr_net_strerror(err)),
fmt::arg("error_code", err))); fmt::arg("error_code", err)));
@ -539,7 +446,7 @@ static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool
if (!suppressMsgs) if (!suppressMsgs)
{ {
tr_logAddDebug(fmt::format(FMT_STRING("Bound socket {:d} to port {:d} on {:s}"), fd, port.host(), addr->readable())); tr_logAddDebug(fmt::format(FMT_STRING("Bound socket {:d} to port {:d} on {:s}"), fd, port.host(), addr.readable()));
} }
#ifdef TCP_FASTOPEN #ifdef TCP_FASTOPEN
@ -568,7 +475,7 @@ static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool
return fd; return fd;
} }
tr_socket_t tr_netBindTCP(tr_address const* addr, tr_port port, bool suppressMsgs) tr_socket_t tr_netBindTCP(tr_address addr, tr_port port, bool suppressMsgs)
{ {
int unused = 0; int unused = 0;
return tr_netBindTCPImpl(addr, port, suppressMsgs, &unused); return tr_netBindTCPImpl(addr, port, suppressMsgs, &unused);
@ -582,7 +489,7 @@ bool tr_net_hasIPv6(tr_port port)
if (!alreadyDone) if (!alreadyDone)
{ {
int err = 0; int err = 0;
auto const fd = tr_netBindTCPImpl(&tr_in6addr_any, port, true, &err); auto const fd = tr_netBindTCPImpl(tr_in6addr_any, port, true, &err);
if (fd != TR_BAD_SOCKET || err != EAFNOSUPPORT) /* we support ipv6 */ if (fd != TR_BAD_SOCKET || err != EAFNOSUPPORT) /* we support ipv6 */
{ {
@ -600,11 +507,9 @@ bool tr_net_hasIPv6(tr_port port)
return result; return result;
} }
tr_socket_t tr_netAccept(tr_session* session, tr_socket_t listening_sockfd, tr_address* addr, tr_port* port) std::optional<std::tuple<tr_socket_t, tr_address, tr_port>> tr_netAccept(tr_session* session, tr_socket_t listening_sockfd)
{ {
TR_ASSERT(tr_isSession(session)); TR_ASSERT(tr_isSession(session));
TR_ASSERT(addr != nullptr);
TR_ASSERT(port != nullptr);
// accept the incoming connection // accept the incoming connection
struct sockaddr_storage sock; struct sockaddr_storage sock;
@ -612,20 +517,21 @@ tr_socket_t tr_netAccept(tr_session* session, tr_socket_t listening_sockfd, tr_a
auto const sockfd = accept(listening_sockfd, (struct sockaddr*)&sock, &len); auto const sockfd = accept(listening_sockfd, (struct sockaddr*)&sock, &len);
if (sockfd == TR_BAD_SOCKET) if (sockfd == TR_BAD_SOCKET)
{ {
return TR_BAD_SOCKET; return {};
} }
// get the address and port, // get the address and port,
// make the socket unblocking, // make the socket unblocking,
// and confirm we don't have too many peers // and confirm we don't have too many peers
if (!tr_address_from_sockaddr_storage(addr, port, &sock) || evutil_make_socket_nonblocking(sockfd) == -1 || auto const addrport = tr_address::fromSockaddrStorage(sock);
!session->incPeerCount()) if (!addrport || evutil_make_socket_nonblocking(sockfd) == -1 || !session->incPeerCount())
{ {
tr_netCloseSocket(sockfd); tr_netCloseSocket(sockfd);
return TR_BAD_SOCKET; return {};
} }
return sockfd; auto const& [addr, port] = *addrport;
return std::make_tuple(sockfd, addr, port);
} }
void tr_netCloseSocket(tr_socket_t sockfd) void tr_netCloseSocket(tr_socket_t sockfd)
@ -800,12 +706,11 @@ unsigned char const* tr_globalIPv6(tr_session const* session)
/* We have some sort of address, now make sure that we return /* We have some sort of address, now make sure that we return
our bound address if non-default. */ our bound address if non-default. */
bool is_default = false; auto const [ipv6_bindaddr, is_default] = session->getPublicAddress(TR_AF_INET6);
auto const* ipv6_bindaddr = tr_sessionGetPublicAddress(session, TR_AF_INET6, &is_default); if (!is_default)
if (ipv6_bindaddr != nullptr && !is_default)
{ {
/* Explicitly bound. Return that address. */ /* Explicitly bound. Return that address. */
memcpy(ipv6, ipv6_bindaddr->addr.addr6.s6_addr, 16); memcpy(ipv6, ipv6_bindaddr.addr.addr6.s6_addr, 16);
} }
return ipv6; return ipv6;
@ -853,10 +758,10 @@ static bool isMartianAddr(struct tr_address const* a)
} }
} }
bool tr_address_is_valid_for_peers(tr_address const* addr, tr_port port) [[nodiscard]] bool tr_address::isValidPeerAddress(tr_port port) const noexcept
{ {
return !std::empty(port) && tr_address_is_valid(addr) && !isIPv6LinkLocalAddress(addr) && !isIPv4MappedAddress(addr) && return !std::empty(port) && tr_address_is_valid(this) && !isIPv6LinkLocalAddress(this) && !isIPv4MappedAddress(this) &&
!isMartianAddr(addr); !isMartianAddr(this);
} }
struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle) struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle)
@ -891,50 +796,53 @@ std::pair<tr_port, uint8_t const*> tr_port::fromCompact(uint8_t const* compact)
/// tr_address /// tr_address
std::optional<tr_address> tr_address::fromString(std::string_view address_str) std::optional<tr_address> tr_address::fromString(std::string_view addrstr)
{ {
auto const addrstr_sz = tr_strbuf<char, 64>{ addrstr };
auto addr = tr_address{}; auto addr = tr_address{};
if (!tr_address_from_string(&addr, address_str)) if (evutil_inet_pton(AF_INET, addrstr_sz, &addr.addr) == 1)
{ {
return {}; addr.type = TR_AF_INET;
return addr;
} }
return addr; if (evutil_inet_pton(AF_INET6, addrstr_sz, &addr.addr) == 1)
{
addr.type = TR_AF_INET6;
return addr;
}
return {};
} }
template<typename OutputIt> std::string_view tr_address::readable(char* out, size_t outlen, tr_port port) const
OutputIt tr_address::readable(OutputIt out) const
{ {
if (std::empty(port))
{
return isIPv4() ? evutil_inet_ntop(AF_INET, &addr, out, outlen) : evutil_inet_ntop(AF_INET6, &addr, out, outlen);
}
auto buf = std::array<char, INET6_ADDRSTRLEN>{}; auto buf = std::array<char, INET6_ADDRSTRLEN>{};
tr_address_to_string_with_buf(this, std::data(buf), std::size(buf)); auto const addr_sv = readable(std::data(buf), std::size(buf));
return fmt::format_to(out, FMT_STRING("{:s}"), std::data(buf)); auto const [end, size] = fmt::format_to_n(out, outlen - 1, FMT_STRING("[{:s}]:{:d}"), addr_sv, port.host());
} return { out, size };
template char* tr_address::readable<char*>(char*) const;
std::string tr_address::readable() const
{
auto buf = std::string{};
buf.reserve(INET6_ADDRSTRLEN);
this->readable(std::back_inserter(buf));
return buf;
} }
template<typename OutputIt> template<typename OutputIt>
OutputIt tr_address::readable(OutputIt out, tr_port port) const OutputIt tr_address::readable(OutputIt out, tr_port port) const
{ {
auto buf = std::array<char, INET6_ADDRSTRLEN>{}; auto addrbuf = std::array<char, TR_ADDRSTRLEN + 16>{};
tr_address_to_string_with_buf(this, std::data(buf), std::size(buf)); auto const addr_sv = readable(std::data(addrbuf), std::size(addrbuf), port);
return fmt::format_to(out, FMT_STRING("[{:s}]:{:d}"), std::data(buf), port.host()); return std::copy(std::begin(addr_sv), std::end(addr_sv), out);
} }
template char* tr_address::readable<char*>(char*, tr_port) const; template char* tr_address::readable<char*>(char*, tr_port) const;
std::string tr_address::readable(tr_port port) const [[nodiscard]] std::string tr_address::readable(tr_port port) const
{ {
auto buf = std::string{}; auto buf = std::string{};
buf.reserve(INET6_ADDRSTRLEN + 9); buf.reserve(INET6_ADDRSTRLEN + 16);
this->readable(std::back_inserter(buf), port); this->readable(std::back_inserter(buf), port);
return buf; return buf;
} }
@ -966,5 +874,12 @@ std::pair<tr_address, uint8_t const*> tr_address::fromCompact6(uint8_t const* co
int tr_address::compare(tr_address const& that) const noexcept // <=> int tr_address::compare(tr_address const& that) const noexcept // <=>
{ {
return tr_address_compare(this, &that); // IPv6 addresses are always "greater than" IPv4
if (type != that.type)
{
return type == TR_AF_INET ? 1 : -1;
}
return type == TR_AF_INET ? memcmp(&addr.addr4, &that.addr.addr4, sizeof(addr.addr4)) :
memcmp(&addr.addr6.s6_addr, &that.addr.addr6.s6_addr, sizeof(addr.addr6.s6_addr));
} }

View File

@ -66,13 +66,10 @@ enum tr_address_type
{ {
TR_AF_INET, TR_AF_INET,
TR_AF_INET6, TR_AF_INET6,
NUM_TR_AF_INET_TYPES
}; };
struct tr_address; struct tr_address;
[[nodiscard]] int tr_address_compare(tr_address const* a, tr_address const* b) noexcept;
/** /**
* Literally just a port number. * Literally just a port number.
* *
@ -152,19 +149,27 @@ private:
struct tr_address struct tr_address
{ {
[[nodiscard]] static std::optional<tr_address> fromString(std::string_view str); [[nodiscard]] static std::optional<tr_address> fromString(std::string_view str);
[[nodiscard]] static std::optional<std::pair<tr_address, tr_port>> fromSockaddrStorage(sockaddr_storage);
[[nodiscard]] static std::pair<tr_address, uint8_t const*> fromCompact4(uint8_t const* compact) noexcept; [[nodiscard]] static std::pair<tr_address, uint8_t const*> fromCompact4(uint8_t const* compact) noexcept;
[[nodiscard]] static std::pair<tr_address, uint8_t const*> fromCompact6(uint8_t const* compact) noexcept; [[nodiscard]] static std::pair<tr_address, uint8_t const*> fromCompact6(uint8_t const* compact) noexcept;
[[nodiscard]] bool isValidPeerAddress(tr_port) const noexcept;
// human-readable formatting // human-readable formatting
template<typename OutputIt> template<typename OutputIt>
OutputIt readable(OutputIt out) const; OutputIt readable(OutputIt out, tr_port port = {}) const;
std::string_view readable(char* out, size_t outlen, tr_port port = {}) const;
[[nodiscard]] std::string readable(tr_port port = {}) const;
template<typename OutputIt> [[nodiscard]] constexpr auto isIPv4() const noexcept
OutputIt readable(OutputIt out, tr_port) const; {
return type == TR_AF_INET;
}
[[nodiscard]] std::string readable() const; [[nodiscard]] constexpr auto isIPv6() const noexcept
[[nodiscard]] std::string readable(tr_port) const; {
return type == TR_AF_INET6;
}
// comparisons // comparisons
@ -196,20 +201,6 @@ struct tr_address
extern tr_address const tr_inaddr_any; extern tr_address const tr_inaddr_any;
extern tr_address const tr_in6addr_any; extern tr_address const tr_in6addr_any;
char const* tr_address_to_string(tr_address const* addr);
char const* tr_address_to_string_with_buf(tr_address const* addr, char* buf, size_t buflen);
char const* tr_address_and_port_to_string(char* buf, size_t buflen, tr_address const* addr, tr_port port);
bool tr_address_from_string(tr_address* setme, char const* string);
bool tr_address_from_string(tr_address* dst, std::string_view src);
bool tr_address_from_sockaddr_storage(tr_address* setme, tr_port* port, struct sockaddr_storage const* src);
bool tr_address_is_valid_for_peers(tr_address const* addr, tr_port port);
constexpr bool tr_address_is_valid(tr_address const* a) constexpr bool tr_address_is_valid(tr_address const* a)
{ {
return a != nullptr && (a->type == TR_AF_INET || a->type == TR_AF_INET6); return a != nullptr && (a->type == TR_AF_INET || a->type == TR_AF_INET6);
@ -221,9 +212,9 @@ constexpr bool tr_address_is_valid(tr_address const* a)
struct tr_session; struct tr_session;
tr_socket_t tr_netBindTCP(tr_address const* addr, tr_port port, bool suppressMsgs); tr_socket_t tr_netBindTCP(tr_address addr, tr_port port, bool suppressMsgs);
tr_socket_t tr_netAccept(tr_session* session, tr_socket_t bound, tr_address* setme_addr, tr_port* setme_port); std::optional<std::tuple<tr_socket_t, tr_address, tr_port>> tr_netAccept(tr_session*, tr_socket_t listening_sockfd);
void tr_netSetCongestionControl(tr_socket_t s, char const* algorithm); void tr_netSetCongestionControl(tr_socket_t s, char const* algorithm);

View File

@ -560,7 +560,7 @@ static uint64 utp_callback(utp_callback_arguments* args)
static tr_peerIo* tr_peerIoNew( static tr_peerIo* tr_peerIoNew(
tr_session* session, tr_session* session,
tr_bandwidth* parent, tr_bandwidth* parent,
tr_address const* addr, tr_address addr,
tr_port port, tr_port port,
time_t current_time, time_t current_time,
tr_sha1_digest_t const* torrent_hash, tr_sha1_digest_t const* torrent_hash,
@ -580,11 +580,11 @@ static tr_peerIo* tr_peerIoNew(
if (socket.type == TR_PEER_SOCKET_TYPE_TCP) if (socket.type == TR_PEER_SOCKET_TYPE_TCP)
{ {
session->setSocketTOS(socket.handle.tcp, addr->type); session->setSocketTOS(socket.handle.tcp, addr.type);
maybeSetCongestionAlgorithm(socket.handle.tcp, session->peerCongestionAlgorithm()); maybeSetCongestionAlgorithm(socket.handle.tcp, session->peerCongestionAlgorithm());
} }
auto* io = new tr_peerIo{ session, torrent_hash, is_incoming, *addr, port, is_seed, current_time, parent }; auto* io = new tr_peerIo{ session, torrent_hash, is_incoming, addr, port, is_seed, current_time, parent };
io->socket = socket; io->socket = socket;
io->bandwidth().setPeer(io); io->bandwidth().setPeer(io);
tr_logAddTraceIo(io, fmt::format("bandwidth is {}; its parent is {}", fmt::ptr(&io->bandwidth()), fmt::ptr(parent))); tr_logAddTraceIo(io, fmt::format("bandwidth is {}; its parent is {}", fmt::ptr(&io->bandwidth()), fmt::ptr(parent)));
@ -631,13 +631,12 @@ void tr_peerIoUtpInit([[maybe_unused]] struct_utp_context* ctx)
tr_peerIo* tr_peerIoNewIncoming( tr_peerIo* tr_peerIoNewIncoming(
tr_session* session, tr_session* session,
tr_bandwidth* parent, tr_bandwidth* parent,
tr_address const* addr, tr_address addr,
tr_port port, tr_port port,
time_t current_time, time_t current_time,
struct tr_peer_socket const socket) struct tr_peer_socket const socket)
{ {
TR_ASSERT(session != nullptr); TR_ASSERT(session != nullptr);
TR_ASSERT(tr_address_is_valid(addr));
return tr_peerIoNew(session, parent, addr, port, current_time, nullptr, true, false, socket); return tr_peerIoNew(session, parent, addr, port, current_time, nullptr, true, false, socket);
} }
@ -645,7 +644,7 @@ tr_peerIo* tr_peerIoNewIncoming(
tr_peerIo* tr_peerIoNewOutgoing( tr_peerIo* tr_peerIoNewOutgoing(
tr_session* session, tr_session* session,
tr_bandwidth* parent, tr_bandwidth* parent,
tr_address const* addr, tr_address addr,
tr_port port, tr_port port,
time_t current_time, time_t current_time,
tr_sha1_digest_t const& torrent_hash, tr_sha1_digest_t const& torrent_hash,
@ -653,7 +652,6 @@ tr_peerIo* tr_peerIoNewOutgoing(
bool utp) bool utp)
{ {
TR_ASSERT(session != nullptr); TR_ASSERT(session != nullptr);
TR_ASSERT(tr_address_is_valid(addr));
auto socket = tr_peer_socket{}; auto socket = tr_peer_socket{};
@ -911,7 +909,7 @@ int tr_peerIoReconnect(tr_peerIo* io)
io_close_socket(io); io_close_socket(io);
auto const [addr, port] = io->socketAddress(); auto const [addr, port] = io->socketAddress();
io->socket = tr_netOpenPeerSocket(session, &addr, port, io->isSeed()); io->socket = tr_netOpenPeerSocket(session, addr, port, io->isSeed());
if (io->socket.type != TR_PEER_SOCKET_TYPE_TCP) if (io->socket.type != TR_PEER_SOCKET_TYPE_TCP)
{ {

View File

@ -80,7 +80,7 @@ public:
tr_session* session_in, tr_session* session_in,
tr_sha1_digest_t const* torrent_hash, tr_sha1_digest_t const* torrent_hash,
bool is_incoming, bool is_incoming,
tr_address const& addr, tr_address addr,
tr_port port, tr_port port,
bool is_seed, bool is_seed,
time_t current_time, time_t current_time,
@ -244,7 +244,7 @@ void tr_peerIoUtpInit(struct_utp_context* ctx);
tr_peerIo* tr_peerIoNewOutgoing( tr_peerIo* tr_peerIoNewOutgoing(
tr_session* session, tr_session* session,
tr_bandwidth* parent, tr_bandwidth* parent,
struct tr_address const* addr, tr_address addr,
tr_port port, tr_port port,
time_t current_time, time_t current_time,
tr_sha1_digest_t const& torrent_hash, tr_sha1_digest_t const& torrent_hash,
@ -254,7 +254,7 @@ tr_peerIo* tr_peerIoNewOutgoing(
tr_peerIo* tr_peerIoNewIncoming( tr_peerIo* tr_peerIoNewIncoming(
tr_session* session, tr_session* session,
tr_bandwidth* parent, tr_bandwidth* parent,
struct tr_address const* addr, tr_address addr,
tr_port port, tr_port port,
time_t current_time, time_t current_time,
struct tr_peer_socket const socket); struct tr_peer_socket const socket);

View File

@ -107,7 +107,7 @@ struct peer_atom
return *blocklisted_; return *blocklisted_;
} }
auto const value = tr_sessionIsAddressBlocked(session, &addr); auto const value = session->isAddressBlocked(addr);
blocklisted_ = value; blocklisted_ = value;
return value; return value;
} }
@ -1175,19 +1175,19 @@ static bool on_handshake_done(tr_handshake_result const& result)
return success; return success;
} }
void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address const* addr, tr_port port, struct tr_peer_socket const socket) void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address addr, tr_port port, struct tr_peer_socket const socket)
{ {
TR_ASSERT(tr_isSession(manager->session)); TR_ASSERT(tr_isSession(manager->session));
auto const lock = manager->unique_lock(); auto const lock = manager->unique_lock();
tr_session* session = manager->session; tr_session* session = manager->session;
if (tr_sessionIsAddressBlocked(session, addr)) if (session->isAddressBlocked(addr))
{ {
tr_logAddTrace(fmt::format("Banned IP address '{}' tried to connect to us", tr_address_to_string(addr))); tr_logAddTrace(fmt::format("Banned IP address '{}' tried to connect to us", addr.readable()));
tr_netClosePeerSocket(session, socket); tr_netClosePeerSocket(session, socket);
} }
else if (manager->incoming_handshakes.contains(*addr)) else if (manager->incoming_handshakes.contains(addr))
{ {
tr_netClosePeerSocket(session, socket); tr_netClosePeerSocket(session, socket);
} }
@ -1198,7 +1198,7 @@ void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address const* addr, tr_port
tr_peerIoUnref(io); /* balanced by the implicit ref in tr_peerIoNewIncoming() */ tr_peerIoUnref(io); /* balanced by the implicit ref in tr_peerIoNewIncoming() */
manager->incoming_handshakes.add(*addr, handshake); manager->incoming_handshakes.add(addr, handshake);
} }
} }
@ -1224,9 +1224,8 @@ size_t tr_peerMgrAddPex(tr_torrent* tor, uint8_t from, tr_pex const* pex, size_t
for (tr_pex const* const end = pex + n_pex; pex != end; ++pex) for (tr_pex const* const end = pex + n_pex; pex != end; ++pex)
{ {
if (tr_isPex(pex) && /* safeguard against corrupt data */ if (tr_isPex(pex) && // safeguard against corrupt data
!tr_sessionIsAddressBlocked(s->manager->session, &pex->addr) && !s->manager->session->isAddressBlocked(pex->addr) && pex->addr.isValidPeerAddress(pex->port))
tr_address_is_valid_for_peers(&pex->addr, pex->port))
{ {
ensureAtomExists(s, pex->addr, pex->port, pex->flags, from); ensureAtomExists(s, pex->addr, pex->port, pex->flags, from);
++n_used; ++n_used;
@ -1631,7 +1630,7 @@ namespace peer_stat_helpers
auto const [addr, port] = peer->socketAddress(); auto const [addr, port] = peer->socketAddress();
tr_address_to_string_with_buf(&addr, stats.addr, sizeof(stats.addr)); addr.readable(stats.addr, sizeof(stats.addr));
stats.client = peer->client.c_str(); stats.client = peer->client.c_str();
stats.port = port.host(); stats.port = port.host();
stats.from = atom->fromFirst; stats.from = atom->fromFirst;
@ -2754,7 +2753,7 @@ void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, peer_atom& atom)
tr_peerIo* const io = tr_peerIoNewOutgoing( tr_peerIo* const io = tr_peerIoNewOutgoing(
mgr->session, mgr->session,
&mgr->session->top_bandwidth_, &mgr->session->top_bandwidth_,
&atom.addr, atom.addr,
atom.port, atom.port,
tr_time(), tr_time(),
s->tor->infoHash(), s->tor->infoHash(),

View File

@ -124,7 +124,7 @@ void tr_peerMgrClientSentRequests(tr_torrent* torrent, tr_peer* peer, tr_block_s
size_t tr_peerMgrCountActiveRequestsToPeer(tr_torrent const* torrent, tr_peer const* peer); size_t tr_peerMgrCountActiveRequestsToPeer(tr_torrent const* torrent, tr_peer const* peer);
void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address const* addr, tr_port port, struct tr_peer_socket const socket); void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address addr, tr_port port, struct tr_peer_socket const socket);
std::vector<tr_pex> tr_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len); std::vector<tr_pex> tr_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len);

View File

@ -985,89 +985,6 @@ static void protocolSendHaveNone(tr_peerMsgsImpl* msgs)
msgs->pokeBatchPeriod(ImmediatePriorityIntervalSecs); msgs->pokeBatchPeriod(ImmediatePriorityIntervalSecs);
} }
/**
*** ALLOWED FAST SET
*** For explanation, see http://www.bittorrent.org/beps/bep_0006.html
**/
#if 0
size_t tr_generateAllowedSet(tr_piece_index_t* setmePieces, size_t desiredSetSize, size_t pieceCount, uint8_t const* infohash,
tr_address const* addr)
{
TR_ASSERT(setmePieces != nullptr);
TR_ASSERT(desiredSetSize <= pieceCount);
TR_ASSERT(desiredSetSize != 0);
TR_ASSERT(pieceCount != 0);
TR_ASSERT(infohash != nullptr);
TR_ASSERT(addr != nullptr);
size_t setSize = 0;
if (addr->type == TR_AF_INET)
{
uint8_t w[SHA_DIGEST_LENGTH + 4];
uint8_t* walk = w;
uint8_t x[SHA_DIGEST_LENGTH];
uint32_t ui32 = ntohl(htonl(addr->addr.addr4.s_addr) & 0xffffff00); /* (1) */
memcpy(w, &ui32, sizeof(uint32_t));
walk += sizeof(uint32_t);
memcpy(walk, infohash, SHA_DIGEST_LENGTH); /* (2) */
walk += SHA_DIGEST_LENGTH;
tr_sha1(x, w, walk - w, nullptr); /* (3) */
TR_ASSERT(sizeof(w) == walk - w);
while (setSize < desiredSetSize)
{
for (int i = 0; i < 5 && setSize < desiredSetSize; ++i) /* (4) */
{
uint32_t j = i * 4; /* (5) */
uint32_t y = ntohl(*(uint32_t*)(x + j)); /* (6) */
uint32_t index = y % pieceCount; /* (7) */
bool found = false;
for (size_t k = 0; !found && k < setSize; ++k) /* (8) */
{
found = setmePieces[k] == index;
}
if (!found)
{
setmePieces[setSize++] = index; /* (9) */
}
}
tr_sha1(x, x, sizeof(x), nullptr); /* (3) */
}
}
return setSize;
}
static void updateFastSet(tr_peerMsgs*)
{
bool const fext = msgs->io->supportsFEXT();
bool const peerIsNeedy = msgs->peer->progress < 0.10;
if (fext && peerIsNeedy && !msgs->haveFastSet)
{
tr_info const* inf = &msgs->torrent->info;
size_t const numwant = std::min(MAX_FAST_SET_SIZE, inf->pieceCount);
/* build the fast set */
msgs->fastsetSize = tr_generateAllowedSet(msgs->fastset, numwant, inf->pieceCount, inf->hash, msgs->io->address());
msgs->haveFastSet = true;
/* send it to the peer */
for (size_t i = 0; i < msgs->fastsetSize; ++i)
{
protocolSendAllowedFast(msgs, msgs->fastset[i]);
}
}
}
#endif
/** /**
*** INTEREST *** INTEREST
**/ **/
@ -1902,7 +1819,7 @@ static ReadState readBtMessage(tr_peerMsgsImpl* msgs, struct evbuffer* inbuf, si
if (auto const dht_port = tr_port::fromNetwork(nport); !std::empty(dht_port)) if (auto const dht_port = tr_port::fromNetwork(nport); !std::empty(dht_port))
{ {
msgs->dht_port = dht_port; msgs->dht_port = dht_port;
tr_dhtAddNode(msgs->session, &msgs->io->address(), msgs->dht_port, false); tr_dhtAddNode(msgs->session, msgs->io->address(), msgs->dht_port, false);
} }
} }
break; break;

View File

@ -80,11 +80,4 @@ tr_peerMsgs* tr_peerMsgsNew(
tr_peer_callback callback, tr_peer_callback callback,
void* callback_data); void* callback_data);
size_t tr_generateAllowedSet(
tr_piece_index_t* setmePieces,
size_t desiredSetSize,
size_t pieceCount,
uint8_t const* infohash,
struct tr_address const* addr);
/* @} */ /* @} */

View File

@ -35,10 +35,9 @@ struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle);
struct tr_peer_socket tr_peer_socket_utp_create(struct UTPSocket* const handle); struct tr_peer_socket tr_peer_socket_utp_create(struct UTPSocket* const handle);
struct tr_session; struct tr_session;
struct tr_address;
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed); struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address addr, tr_port port, bool clientIsSeed);
struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed); struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address addr, tr_port port, bool clientIsSeed);
void tr_netClosePeerSocket(tr_session* session, tr_peer_socket socket); void tr_netClosePeerSocket(tr_session* session, tr_peer_socket socket);

View File

@ -96,12 +96,7 @@ static void natPulse(tr_shared* s, bool do_check)
fmt::arg("private_port", session->private_peer_port.host()))); fmt::arg("private_port", session->private_peer_port.host())));
} }
s->upnpStatus = tr_upnpPulse( s->upnpStatus = tr_upnpPulse(s->upnp, private_peer_port, is_enabled, do_check, session->bind_ipv4->addr.readable());
s->upnp,
private_peer_port,
is_enabled,
do_check,
tr_address_to_string(&session->bind_ipv4->addr));
auto const new_status = tr_sharedTraversalStatus(s); auto const new_status = tr_sharedTraversalStatus(s);

View File

@ -147,11 +147,11 @@ std::optional<std::string> tr_session::WebMediator::publicAddress() const
{ {
for (auto const type : { TR_AF_INET, TR_AF_INET6 }) for (auto const type : { TR_AF_INET, TR_AF_INET6 })
{ {
auto is_default_value = bool{}; auto const [addr, is_default_value] = session_->getPublicAddress(type);
tr_address const* addr = tr_sessionGetPublicAddress(session_, type, &is_default_value);
if (addr != nullptr && !is_default_value) if (!is_default_value)
{ {
return addr->readable(); return addr.readable();
} }
} }
@ -236,21 +236,15 @@ static void free_incoming_peer_port(tr_session* session)
session->bind_ipv6 = nullptr; session->bind_ipv6 = nullptr;
} }
static void accept_incoming_peer(evutil_socket_t fd, short /*what*/, void* vsession) static void accept_incoming_peer(evutil_socket_t listening_sockfd, short /*what*/, void* vsession)
{ {
auto* session = static_cast<tr_session*>(vsession); auto* session = static_cast<tr_session*>(vsession);
auto clientAddr = tr_address{}; if (auto const accepted = tr_netAccept(session, listening_sockfd); accepted)
auto clientPort = tr_port{};
auto const clientSocket = tr_netAccept(session, fd, &clientAddr, &clientPort);
if (clientSocket != TR_BAD_SOCKET)
{ {
char addrstr[TR_ADDRSTRLEN]; auto const& [sock, addr, port] = *accepted;
tr_address_and_port_to_string(addrstr, sizeof(addrstr), &clientAddr, clientPort); tr_logAddTrace(fmt::format("new incoming connection {} ({})", sock, addr.readable(port)));
tr_logAddTrace(fmt::format("new incoming connection {} ({})", clientSocket, addrstr)); tr_peerMgrAddIncoming(session->peerMgr, addr, port, tr_peer_socket_tcp_create(sock));
tr_peerMgrAddIncoming(session->peerMgr, &clientAddr, clientPort, tr_peer_socket_tcp_create(clientSocket));
} }
} }
@ -258,7 +252,7 @@ static void open_incoming_peer_port(tr_session* session)
{ {
/* bind an ipv4 port to listen for incoming peers... */ /* bind an ipv4 port to listen for incoming peers... */
auto* b = session->bind_ipv4; auto* b = session->bind_ipv4;
b->socket = tr_netBindTCP(&b->addr, session->private_peer_port, false); b->socket = tr_netBindTCP(b->addr, session->private_peer_port, false);
if (b->socket != TR_BAD_SOCKET) if (b->socket != TR_BAD_SOCKET)
{ {
@ -270,7 +264,7 @@ static void open_incoming_peer_port(tr_session* session)
if (tr_net_hasIPv6(session->private_peer_port)) if (tr_net_hasIPv6(session->private_peer_port))
{ {
b = session->bind_ipv6; b = session->bind_ipv6;
b->socket = tr_netBindTCP(&b->addr, session->private_peer_port, false); b->socket = tr_netBindTCP(b->addr, session->private_peer_port, false);
if (b->socket != TR_BAD_SOCKET) if (b->socket != TR_BAD_SOCKET)
{ {
@ -280,33 +274,12 @@ static void open_incoming_peer_port(tr_session* session)
} }
} }
tr_address const* tr_sessionGetPublicAddress(tr_session const* session, int tr_af_type, bool* is_default_value) std::pair<tr_address, bool> tr_session::getPublicAddress(tr_address_type type) const
{ {
char const* default_value = ""; auto const* const bindinfo = type == TR_AF_INET6 ? bind_ipv6 : bind_ipv4;
tr_bindinfo const* bindinfo = nullptr; char const* const default_value = type == TR_AF_INET6 ? TR_DEFAULT_BIND_ADDRESS_IPV6 : TR_DEFAULT_BIND_ADDRESS_IPV4;
auto const is_default_value = bindinfo->addr.readable() == default_value;
switch (tr_af_type) return std::make_pair(bindinfo->addr, is_default_value);
{
case TR_AF_INET:
bindinfo = session->bind_ipv4;
default_value = TR_DEFAULT_BIND_ADDRESS_IPV4;
break;
case TR_AF_INET6:
bindinfo = session->bind_ipv6;
default_value = TR_DEFAULT_BIND_ADDRESS_IPV6;
break;
default:
break;
}
if (is_default_value != nullptr && bindinfo != nullptr)
{
*is_default_value = bindinfo->addr.readable() == default_value;
}
return bindinfo != nullptr ? &bindinfo->addr : nullptr;
} }
/*** /***
@ -464,8 +437,8 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* d)
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->uploadSlotsPerTorrent);
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, tr_address_to_string(&s->bind_ipv4->addr)); tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, s->bind_ipv4->addr.readable());
tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, tr_address_to_string(&s->bind_ipv6->addr)); tr_variantDictAddStr(d, TR_KEY_bind_address_ipv6, s->bind_ipv6->addr.readable());
tr_variantDictAddBool(d, TR_KEY_start_added_torrents, !tr_sessionGetPaused(s)); tr_variantDictAddBool(d, TR_KEY_start_added_torrents, !tr_sessionGetPaused(s));
tr_variantDictAddBool(d, TR_KEY_trash_original_torrent_files, tr_sessionGetDeleteSource(s)); tr_variantDictAddBool(d, TR_KEY_trash_original_torrent_files, tr_sessionGetDeleteSource(s));
tr_variantDictAddInt(d, TR_KEY_anti_brute_force_threshold, tr_sessionGetAntiBruteForceThreshold(s)); tr_variantDictAddInt(d, TR_KEY_anti_brute_force_threshold, tr_sessionGetAntiBruteForceThreshold(s));
@ -958,19 +931,25 @@ static void sessionSetImpl(struct init_data* const data)
free_incoming_peer_port(session); free_incoming_peer_port(session);
if (!tr_variantDictFindStrView(settings, TR_KEY_bind_address_ipv4, &sv) || !tr_address_from_string(&b.addr, sv) || b.addr = tr_inaddr_any;
b.addr.type != TR_AF_INET) if (tr_variantDictFindStrView(settings, TR_KEY_bind_address_ipv4, &sv))
{ {
b.addr = tr_inaddr_any; if (auto const addr = tr_address::fromString(sv); addr && addr->isIPv4())
{
b.addr = *addr;
}
} }
b.socket = TR_BAD_SOCKET; b.socket = TR_BAD_SOCKET;
session->bind_ipv4 = static_cast<struct tr_bindinfo*>(tr_memdup(&b, sizeof(struct tr_bindinfo))); session->bind_ipv4 = static_cast<struct tr_bindinfo*>(tr_memdup(&b, sizeof(struct tr_bindinfo)));
if (!tr_variantDictFindStrView(settings, TR_KEY_bind_address_ipv6, &sv) || !tr_address_from_string(&b.addr, sv) || b.addr = tr_in6addr_any;
b.addr.type != TR_AF_INET6) if (tr_variantDictFindStrView(settings, TR_KEY_bind_address_ipv6, &sv))
{ {
b.addr = tr_in6addr_any; if (auto const addr = tr_address::fromString(sv); addr && addr->isIPv6())
{
b.addr = *addr;
}
} }
b.socket = TR_BAD_SOCKET; b.socket = TR_BAD_SOCKET;
@ -2491,10 +2470,10 @@ size_t tr_blocklistSetContent(tr_session* session, char const* contentFilename)
return ruleCount; return ruleCount;
} }
bool tr_sessionIsAddressBlocked(tr_session const* session, tr_address const* addr) [[nodiscard]] bool tr_session::isAddressBlocked(tr_address addr) const noexcept
{ {
auto const& src = session->blocklists; auto const& src = blocklists;
return std::any_of(std::begin(src), std::end(src), [&addr](auto& blocklist) { return blocklist->hasAddress(*addr); }); return std::any_of(std::begin(src), std::end(src), [&addr](auto& blocklist) { return blocklist->hasAddress(addr); });
} }
void tr_blocklistSetURL(tr_session* session, char const* url) void tr_blocklistSetURL(tr_session* session, char const* url)

View File

@ -255,6 +255,10 @@ public:
tr_netSetTOS(sock, peer_socket_tos_, type); tr_netSetTOS(sock, peer_socket_tos_, type);
} }
[[nodiscard]] std::pair<tr_address, bool /*is default value*/> getPublicAddress(tr_address_type) const;
[[nodiscard]] bool isAddressBlocked(tr_address) const noexcept;
[[nodiscard]] constexpr bool incPeerCount() noexcept [[nodiscard]] constexpr bool incPeerCount() noexcept
{ {
if (this->peerCount >= this->peerLimit) if (this->peerCount >= this->peerLimit)
@ -469,10 +473,6 @@ bool tr_sessionAllowsDHT(tr_session const* session);
bool tr_sessionAllowsLPD(tr_session const* session); bool tr_sessionAllowsLPD(tr_session const* session);
bool tr_sessionIsAddressBlocked(tr_session const* session, struct tr_address const* addr);
struct tr_address const* tr_sessionGetPublicAddress(tr_session const* session, int tr_af_type, bool* is_default_value);
struct tr_bindsockets* tr_sessionGetBindSockets(tr_session*); struct tr_bindsockets* tr_sessionGetBindSockets(tr_session*);
int tr_sessionCountTorrents(tr_session const* session); int tr_sessionCountTorrents(tr_session const* session);

View File

@ -203,7 +203,7 @@ static void dht_bootstrap(void* closure)
addr.type = TR_AF_INET; addr.type = TR_AF_INET;
memcpy(&addr.addr.addr4, &cl->nodes[i * 6], 4); memcpy(&addr.addr.addr4, &cl->nodes[i * 6], 4);
auto const [port, out] = tr_port::fromCompact(&cl->nodes[i * 6 + 4]); auto const [port, out] = tr_port::fromCompact(&cl->nodes[i * 6 + 4]);
tr_dhtAddNode(cl->session, &addr, port, true); tr_dhtAddNode(cl->session, addr, port, true);
} }
if (i < num6 && !bootstrap_done(cl->session, AF_INET6)) if (i < num6 && !bootstrap_done(cl->session, AF_INET6))
@ -213,7 +213,7 @@ static void dht_bootstrap(void* closure)
addr.type = TR_AF_INET6; addr.type = TR_AF_INET6;
memcpy(&addr.addr.addr6, &cl->nodes6[i * 18], 16); memcpy(&addr.addr.addr6, &cl->nodes6[i * 18], 16);
auto const [port, out] = tr_port::fromCompact(&cl->nodes6[i * 18 + 16]); auto const [port, out] = tr_port::fromCompact(&cl->nodes6[i * 18 + 16]);
tr_dhtAddNode(cl->session, &addr, port, true); tr_dhtAddNode(cl->session, addr, port, true);
} }
/* Our DHT code is able to take up to 9 nodes in a row without /* Our DHT code is able to take up to 9 nodes in a row without
@ -528,9 +528,9 @@ tr_port tr_dhtPort(tr_session* ss)
return tr_dhtEnabled(ss) ? ss->udp_port : tr_port{}; return tr_dhtEnabled(ss) ? ss->udp_port : tr_port{};
} }
bool tr_dhtAddNode(tr_session* ss, tr_address const* address, tr_port port, bool bootstrap) bool tr_dhtAddNode(tr_session* ss, tr_address address, tr_port port, bool bootstrap)
{ {
int af = address->type == TR_AF_INET ? AF_INET : AF_INET6; int af = address.type == TR_AF_INET ? AF_INET : AF_INET6;
if (!tr_dhtEnabled(ss)) if (!tr_dhtEnabled(ss))
{ {
@ -545,23 +545,23 @@ bool tr_dhtAddNode(tr_session* ss, tr_address const* address, tr_port port, bool
return false; return false;
} }
if (address->type == TR_AF_INET) if (address.type == TR_AF_INET)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, &address->addr.addr4, 4); memcpy(&sin.sin_addr, &address.addr.addr4, 4);
sin.sin_port = port.network(); sin.sin_port = port.network();
dht_ping_node((struct sockaddr*)&sin, sizeof(sin)); dht_ping_node((struct sockaddr*)&sin, sizeof(sin));
return true; return true;
} }
if (address->type == TR_AF_INET6) if (address.type == TR_AF_INET6)
{ {
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6)); memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6; sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, &address->addr.addr6, 16); memcpy(&sin6.sin6_addr, &address.addr.addr6, 16);
sin6.sin6_port = port.network(); sin6.sin6_port = port.network();
dht_ping_node((struct sockaddr*)&sin6, sizeof(sin6)); dht_ping_node((struct sockaddr*)&sin6, sizeof(sin6));
return true; return true;

View File

@ -10,7 +10,7 @@
#include "transmission.h" #include "transmission.h"
#include "net.h" // tr_port #include "net.h" // tr_address, tr_port
enum enum
{ {
@ -27,6 +27,6 @@ bool tr_dhtEnabled(tr_session const*);
tr_port tr_dhtPort(tr_session*); tr_port tr_dhtPort(tr_session*);
int tr_dhtStatus(tr_session*, int af, int* setme_nodeCount); int tr_dhtStatus(tr_session*, int af, int* setme_nodeCount);
char const* tr_dhtPrintableStatus(int status); char const* tr_dhtPrintableStatus(int status);
bool tr_dhtAddNode(tr_session*, tr_address const*, tr_port, bool bootstrap); bool tr_dhtAddNode(tr_session*, tr_address, tr_port, bool bootstrap);
void tr_dhtUpkeep(tr_session*); void tr_dhtUpkeep(tr_session*);
void tr_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, socklen_t fromlen, void* sv); void tr_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, socklen_t fromlen, void* sv);

View File

@ -290,14 +290,13 @@ void tr_udpInit(tr_session* ss)
} }
else else
{ {
auto is_default = bool{}; auto const [public_addr, is_default] = ss->getPublicAddress(TR_AF_INET);
tr_address const* public_addr = tr_sessionGetPublicAddress(ss, TR_AF_INET, &is_default);
auto sin = sockaddr_in{}; auto sin = sockaddr_in{};
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
if (public_addr != nullptr && !is_default) if (!is_default)
{ {
memcpy(&sin.sin_addr, &public_addr->addr.addr4, sizeof(struct in_addr)); memcpy(&sin.sin_addr, &public_addr.addr.addr4, sizeof(struct in_addr));
} }
sin.sin_port = ss->udp_port.network(); sin.sin_port = ss->udp_port.network();
@ -308,7 +307,7 @@ void tr_udpInit(tr_session* ss)
auto const error_code = errno; auto const error_code = errno;
tr_logAddWarn(fmt::format( tr_logAddWarn(fmt::format(
_("Couldn't bind IPv4 socket {address}: {error} ({error_code})"), _("Couldn't bind IPv4 socket {address}: {error} ({error_code})"),
fmt::arg("address", public_addr != nullptr ? public_addr->readable(ss->udp_port) : "?"), fmt::arg("address", public_addr.readable(ss->udp_port)),
fmt::arg("error", tr_strerror(error_code)), fmt::arg("error", tr_strerror(error_code)),
fmt::arg("error_code", error_code))); fmt::arg("error_code", error_code)));
tr_netCloseSocket(ss->udp_socket); tr_netCloseSocket(ss->udp_socket);

View File

@ -76,28 +76,28 @@ static auto constexpr UtpIntervalUs = int{ 500000 };
static void utp_on_accept(tr_session* const session, UTPSocket* const s) static void utp_on_accept(tr_session* const session, UTPSocket* const s)
{ {
struct sockaddr_storage from_storage;
auto* const from = (struct sockaddr*)&from_storage;
socklen_t fromlen = sizeof(from_storage);
tr_address addr;
tr_port port;
if (!tr_sessionIsUTPEnabled(session)) if (!tr_sessionIsUTPEnabled(session))
{ {
utp_close(s); utp_close(s);
return; return;
} }
struct sockaddr_storage from_storage;
auto* const from = (struct sockaddr*)&from_storage;
socklen_t fromlen = sizeof(from_storage);
utp_getpeername(s, from, &fromlen); utp_getpeername(s, from, &fromlen);
if (!tr_address_from_sockaddr_storage(&addr, &port, &from_storage)) if (auto const addrport = tr_address::fromSockaddrStorage(from_storage); addrport)
{
auto const& [addr, port] = *addrport;
tr_peerMgrAddIncoming(session->peerMgr, addr, port, tr_peer_socket_utp_create(s));
}
else
{ {
tr_logAddWarn(_("Unknown socket family")); tr_logAddWarn(_("Unknown socket family"));
utp_close(s); utp_close(s);
return;
} }
tr_peerMgrAddIncoming(session->peerMgr, &addr, port, tr_peer_socket_utp_create(s));
} }
static void utp_send_to( static void utp_send_to(

View File

@ -240,11 +240,9 @@ enum
UPNP_IGD_INVALID = 3 UPNP_IGD_INVALID = 3
}; };
static auto* discoverThreadfunc(char* bindaddr) static auto* discoverThreadfunc(std::string bindaddr)
{ {
auto* const ret = tr_upnpDiscover(2000, bindaddr); return tr_upnpDiscover(2000, bindaddr.c_str());
tr_free(bindaddr);
return ret;
} }
template<typename T> template<typename T>
@ -253,17 +251,17 @@ static bool isFutureReady(std::future<T> const& future)
return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready; return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
} }
tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool isEnabled, bool doPortCheck, char const* bindaddr) tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool isEnabled, bool doPortCheck, std::string bindaddr)
{ {
if (isEnabled && handle->state == UpnpState::WILL_DISCOVER) if (isEnabled && handle->state == UpnpState::WILL_DISCOVER)
{ {
TR_ASSERT(!handle->discover_future); TR_ASSERT(!handle->discover_future);
auto task = std::packaged_task<UPNPDev*(char*)>{ discoverThreadfunc }; auto task = std::packaged_task<UPNPDev*(std::string)>{ discoverThreadfunc };
handle->discover_future = task.get_future(); handle->discover_future = task.get_future();
handle->state = UpnpState::DISCOVERING; handle->state = UpnpState::DISCOVERING;
std::thread(std::move(task), tr_strdup(bindaddr)).detach(); std::thread(std::move(task), std::move(bindaddr)).detach();
} }
if (isEnabled && handle->state == UpnpState::DISCOVERING && handle->discover_future && if (isEnabled && handle->state == UpnpState::DISCOVERING && handle->discover_future &&

View File

@ -18,12 +18,14 @@
#include "net.h" // tr_port #include "net.h" // tr_port
#include <string>
struct tr_upnp; struct tr_upnp;
tr_upnp* tr_upnpInit(void); tr_upnp* tr_upnpInit(void);
void tr_upnpClose(tr_upnp*); void tr_upnpClose(tr_upnp*);
tr_port_forwarding tr_upnpPulse(tr_upnp*, tr_port port, bool isEnabled, bool doPortCheck, char const*); tr_port_forwarding tr_upnpPulse(tr_upnp*, tr_port port, bool isEnabled, bool doPortCheck, std::string addr);
/* @} */ /* @} */

View File

@ -33,8 +33,7 @@ using namespace std::literals;
bool tr_addressIsIP(char const* str) bool tr_addressIsIP(char const* str)
{ {
tr_address tmp; return tr_address::fromString(str).has_value();
return tr_address_from_string(&tmp, str);
} }
char const* tr_webGetResponseStr(long code) char const* tr_webGetResponseStr(long code)
@ -271,16 +270,15 @@ std::string_view getSiteName(std::string_view host)
return host; return host;
} }
// psl needs a zero-terminated hostname
auto const szhost = tr_urlbuf{ host };
// is it an IP? // is it an IP?
auto addr = tr_address{}; if (auto const addr = tr_address::fromString(host); addr)
if (tr_address_from_string(&addr, std::data(szhost)))
{ {
return host; return host;
} }
// psl needs a zero-terminated hostname
auto const szhost = tr_urlbuf{ host };
// is it a registered name? // is it a registered name?
if (isAsciiNonUpperCase(host)) if (isAsciiNonUpperCase(host))
{ {

View File

@ -57,10 +57,10 @@ protected:
#endif #endif
bool addressIsBlocked(char const* address_str) bool addressIsBlocked(std::string_view address_str)
{ {
struct tr_address addr = {}; auto const addr = tr_address::fromString(address_str);
return !tr_address_from_string(&addr, address_str) || tr_sessionIsAddressBlocked(session_, &addr); return addr && session_->isAddressBlocked(*addr);
} }
}; };

View File

@ -14,7 +14,6 @@ TEST(PeerMsgs, placeholder)
#if 0 #if 0
auto infohash = tr_sha1_digest_t{}; auto infohash = tr_sha1_digest_t{};
struct tr_address addr;
tr_piece_index_t pieceCount = 1313; tr_piece_index_t pieceCount = 1313;
size_t numwant; size_t numwant;
size_t numgot; size_t numgot;
@ -23,15 +22,15 @@ TEST(PeerMsgs, placeholder)
memset(std::data(infohash), 0xaa, std::size(infohash)); memset(std::data(infohash), 0xaa, std::size(infohash));
tr_address_from_string(&addr, "80.4.4.200"); auto const addr = tr_address::fromString("80.4.4.200");
numwant = 7; numwant = 7;
numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, &addr); numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, *addr);
check_uint(numgot, ==, numwant); check_uint(numgot, ==, numwant);
check_mem(buf, ==, pieces, numgot); check_mem(buf, ==, pieces, numgot);
numwant = 9; numwant = 9;
numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, &addr); numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, *addr);
check_uint(numgot, ==, numwant); check_uint(numgot, ==, numwant);
check_mem(buf, ==, pieces, numgot); check_mem(buf, ==, pieces, numgot);