From 9a44eeaa2759413749dae1fc1183c29de1542304 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 8 Jul 2022 13:23:41 -0500 Subject: [PATCH] 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() --- libtransmission/announcer-http.cc | 7 +- libtransmission/blocklist.cc | 16 +- libtransmission/net.cc | 253 ++++++++---------------- libtransmission/net.h | 41 ++-- libtransmission/peer-io.cc | 14 +- libtransmission/peer-io.h | 6 +- libtransmission/peer-mgr.cc | 21 +- libtransmission/peer-mgr.h | 2 +- libtransmission/peer-msgs.cc | 85 +------- libtransmission/peer-msgs.h | 7 - libtransmission/peer-socket.h | 5 +- libtransmission/port-forwarding.cc | 7 +- libtransmission/session.cc | 87 ++++---- libtransmission/session.h | 8 +- libtransmission/tr-dht.cc | 16 +- libtransmission/tr-dht.h | 4 +- libtransmission/tr-udp.cc | 9 +- libtransmission/tr-utp.cc | 20 +- libtransmission/upnp.cc | 12 +- libtransmission/upnp.h | 4 +- libtransmission/web-utils.cc | 12 +- tests/libtransmission/blocklist-test.cc | 6 +- tests/libtransmission/peer-msgs-test.cc | 7 +- 23 files changed, 217 insertions(+), 432 deletions(-) diff --git a/libtransmission/announcer-http.cc b/libtransmission/announcer-http.cc index 9a82979bb..3932aae85 100644 --- a/libtransmission/announcer-http.cc +++ b/libtransmission/announcer-http.cc @@ -184,7 +184,7 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std:: { 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_); pex_ = {}; @@ -251,7 +251,10 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std:: } 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") { diff --git a/libtransmission/blocklist.cc b/libtransmission/blocklist.cc index ce17d43ab..7b284d7e8 100644 --- a/libtransmission/blocklist.cc +++ b/libtransmission/blocklist.cc @@ -155,9 +155,9 @@ bool BlocklistFile::parseLine1(std::string_view line, struct IPv4Range* range) { 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 { @@ -166,9 +166,9 @@ bool BlocklistFile::parseLine1(std::string_view line, struct IPv4Range* range) line = line.substr(pos + 1); // 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 { @@ -193,9 +193,9 @@ bool BlocklistFile::parseLine2(std::string_view line, struct IPv4Range* range) 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 { @@ -209,9 +209,9 @@ bool BlocklistFile::parseLine2(std::string_view line, struct IPv4Range* range) 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 { diff --git a/libtransmission/net.cc b/libtransmission/net.cc index 409af90af..9bc9d8283 100644 --- a/libtransmission/net.cc +++ b/libtransmission/net.cc @@ -61,86 +61,6 @@ std::string tr_net_strerror(int err) #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{}; - 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 **********************************************************************/ @@ -247,38 +167,36 @@ void tr_netSetCongestionControl([[maybe_unused]] tr_socket_t s, [[maybe_unused]] #endif } -bool tr_address_from_sockaddr_storage(tr_address* setme_addr, tr_port* setme_port, struct sockaddr_storage const* from) +std::optional> 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; - setme_addr->type = TR_AF_INET; - setme_addr->addr.addr4.s_addr = sin->sin_addr.s_addr; - *setme_port = tr_port::fromNetwork(sin->sin_port); - return true; + auto const* const sin = reinterpret_cast(&from); + auto tmp = tr_address{}; + tmp.type = TR_AF_INET; + tmp.addr.addr4.s_addr = sin->sin_addr.s_addr; + 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; - setme_addr->type = TR_AF_INET6; - setme_addr->addr.addr6 = sin6->sin6_addr; - *setme_port = tr_port::fromNetwork(sin6->sin6_port); - return true; + auto const* const sin6 = reinterpret_cast(&from); + auto tmp = tr_address{}; + tmp.type = TR_AF_INET6; + tmp.addr.addr6 = sin6->sin6_addr; + 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 = {}; 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(); memcpy(sockaddr, &sock4, sizeof(sock4)); 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_port = port.network(); sock6.sin6_flowinfo = 0; - sock6.sin6_addr = addr->addr.addr6; + sock6.sin6_addr = addr.addr.addr6; memcpy(sockaddr, &sock6, sizeof(sock6)); return sizeof(struct sockaddr_in6); } @@ -341,17 +259,15 @@ static tr_socket_t createSocket(tr_session* session, int domain, int type) 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 (!tr_address_is_valid_for_peers(addr, port)) + if (!addr.isValidPeerAddress(port)) { return {}; } - static auto constexpr Domains = std::array{ AF_INET, AF_INET6 }; - auto const s = createSocket(session, Domains[addr->type], SOCK_STREAM); + static auto constexpr Domains = std::array{ AF_INET, AF_INET6 }; + auto const s = createSocket(session, Domains[addr.type], SOCK_STREAM); if (s == TR_BAD_SOCKET) { 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); // set source address - tr_address const* const source_addr = tr_sessionGetPublicAddress(session, addr->type, nullptr); - TR_ASSERT(source_addr != nullptr); + auto const [source_addr, is_default_addr] = session->getPublicAddress(addr.type); struct sockaddr_storage 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( _("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("error", tr_net_strerror(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; - if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr->type == TR_AF_INET) + if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr.type == TR_AF_INET) { tr_logAddWarn(fmt::format( _("Couldn't connect socket {socket} to {address}:{port}: {error} ({error_code})"), fmt::arg("socket", s), - fmt::arg("address", addr->readable()), + fmt::arg("address", addr.readable()), fmt::arg("port", port.host()), fmt::arg("error", tr_net_strerror(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); } - char addrstr[TR_ADDRSTRLEN]; - tr_address_and_port_to_string(addrstr, sizeof(addrstr), addr, port); - tr_logAddTrace(fmt::format("New OUTGOING connection {} ({})", s, addrstr)); + tr_logAddTrace(fmt::format("New OUTGOING connection {} ({})", s, addr.readable(port))); return ret; } -struct tr_peer_socket tr_netOpenPeerUTPSocket( - tr_session* session, - tr_address const* addr, - tr_port port, - bool /*client_is_seed*/) +struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address addr, tr_port port, bool /*client_is_seed*/) { 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; 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 int const domains[NUM_TR_AF_INET_TYPES] = { AF_INET, AF_INET6 }; + static auto constexpr Domains = std::array{ AF_INET, AF_INET6 }; 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) { *errOut = sockerrno; @@ -503,7 +410,7 @@ static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool #ifdef IPV6_V6ONLY - if ((addr->type == TR_AF_INET6) && + if ((addr.type == TR_AF_INET6) && (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&optval), sizeof(optval)) == -1) && (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 ? _("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})"), - fmt::arg("address", addr->readable()), + fmt::arg("address", addr.readable()), fmt::arg("port", port.host()), fmt::arg("error", tr_net_strerror(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) { - 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 @@ -568,7 +475,7 @@ static tr_socket_t tr_netBindTCPImpl(tr_address const* addr, tr_port port, bool 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; return tr_netBindTCPImpl(addr, port, suppressMsgs, &unused); @@ -582,7 +489,7 @@ bool tr_net_hasIPv6(tr_port port) if (!alreadyDone) { 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 */ { @@ -600,11 +507,9 @@ bool tr_net_hasIPv6(tr_port port) return result; } -tr_socket_t tr_netAccept(tr_session* session, tr_socket_t listening_sockfd, tr_address* addr, tr_port* port) +std::optional> tr_netAccept(tr_session* session, tr_socket_t listening_sockfd) { TR_ASSERT(tr_isSession(session)); - TR_ASSERT(addr != nullptr); - TR_ASSERT(port != nullptr); // accept the incoming connection 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); if (sockfd == TR_BAD_SOCKET) { - return TR_BAD_SOCKET; + return {}; } // get the address and port, // make the socket unblocking, // and confirm we don't have too many peers - if (!tr_address_from_sockaddr_storage(addr, port, &sock) || evutil_make_socket_nonblocking(sockfd) == -1 || - !session->incPeerCount()) + auto const addrport = tr_address::fromSockaddrStorage(sock); + if (!addrport || evutil_make_socket_nonblocking(sockfd) == -1 || !session->incPeerCount()) { 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) @@ -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 our bound address if non-default. */ - bool is_default = false; - auto const* ipv6_bindaddr = tr_sessionGetPublicAddress(session, TR_AF_INET6, &is_default); - if (ipv6_bindaddr != nullptr && !is_default) + auto const [ipv6_bindaddr, is_default] = session->getPublicAddress(TR_AF_INET6); + if (!is_default) { /* 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; @@ -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) && - !isMartianAddr(addr); + return !std::empty(port) && tr_address_is_valid(this) && !isIPv6LinkLocalAddress(this) && !isIPv4MappedAddress(this) && + !isMartianAddr(this); } struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle) @@ -891,50 +796,53 @@ std::pair tr_port::fromCompact(uint8_t const* compact) /// tr_address -std::optional tr_address::fromString(std::string_view address_str) +std::optional tr_address::fromString(std::string_view addrstr) { + auto const addrstr_sz = tr_strbuf{ addrstr }; 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 -OutputIt tr_address::readable(OutputIt out) const +std::string_view tr_address::readable(char* out, size_t outlen, tr_port port) 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{}; - tr_address_to_string_with_buf(this, std::data(buf), std::size(buf)); - return fmt::format_to(out, FMT_STRING("{:s}"), std::data(buf)); -} - -template char* tr_address::readable(char*) const; - -std::string tr_address::readable() const -{ - auto buf = std::string{}; - buf.reserve(INET6_ADDRSTRLEN); - this->readable(std::back_inserter(buf)); - return buf; + auto const addr_sv = readable(std::data(buf), std::size(buf)); + auto const [end, size] = fmt::format_to_n(out, outlen - 1, FMT_STRING("[{:s}]:{:d}"), addr_sv, port.host()); + return { out, size }; } template OutputIt tr_address::readable(OutputIt out, tr_port port) const { - auto buf = std::array{}; - tr_address_to_string_with_buf(this, std::data(buf), std::size(buf)); - return fmt::format_to(out, FMT_STRING("[{:s}]:{:d}"), std::data(buf), port.host()); + auto addrbuf = std::array{}; + auto const addr_sv = readable(std::data(addrbuf), std::size(addrbuf), port); + return std::copy(std::begin(addr_sv), std::end(addr_sv), out); } template char* tr_address::readable(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{}; - buf.reserve(INET6_ADDRSTRLEN + 9); + buf.reserve(INET6_ADDRSTRLEN + 16); this->readable(std::back_inserter(buf), port); return buf; } @@ -966,5 +874,12 @@ std::pair tr_address::fromCompact6(uint8_t const* co 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)); } diff --git a/libtransmission/net.h b/libtransmission/net.h index ac68b6b32..62f92f759 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -66,13 +66,10 @@ enum tr_address_type { TR_AF_INET, TR_AF_INET6, - NUM_TR_AF_INET_TYPES }; struct tr_address; -[[nodiscard]] int tr_address_compare(tr_address const* a, tr_address const* b) noexcept; - /** * Literally just a port number. * @@ -152,19 +149,27 @@ private: struct tr_address { [[nodiscard]] static std::optional fromString(std::string_view str); + [[nodiscard]] static std::optional> fromSockaddrStorage(sockaddr_storage); [[nodiscard]] static std::pair fromCompact4(uint8_t const* compact) noexcept; [[nodiscard]] static std::pair fromCompact6(uint8_t const* compact) noexcept; + [[nodiscard]] bool isValidPeerAddress(tr_port) const noexcept; + // human-readable formatting - template - 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 - OutputIt readable(OutputIt out, tr_port) const; + [[nodiscard]] constexpr auto isIPv4() const noexcept + { + return type == TR_AF_INET; + } - [[nodiscard]] std::string readable() const; - [[nodiscard]] std::string readable(tr_port) const; + [[nodiscard]] constexpr auto isIPv6() const noexcept + { + return type == TR_AF_INET6; + } // comparisons @@ -196,20 +201,6 @@ struct tr_address extern tr_address const tr_inaddr_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) { 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; -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> tr_netAccept(tr_session*, tr_socket_t listening_sockfd); void tr_netSetCongestionControl(tr_socket_t s, char const* algorithm); diff --git a/libtransmission/peer-io.cc b/libtransmission/peer-io.cc index 9a3290ecd..cde0a21d6 100644 --- a/libtransmission/peer-io.cc +++ b/libtransmission/peer-io.cc @@ -560,7 +560,7 @@ static uint64 utp_callback(utp_callback_arguments* args) static tr_peerIo* tr_peerIoNew( tr_session* session, tr_bandwidth* parent, - tr_address const* addr, + tr_address addr, tr_port port, time_t current_time, tr_sha1_digest_t const* torrent_hash, @@ -580,11 +580,11 @@ static tr_peerIo* tr_peerIoNew( 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()); } - 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->bandwidth().setPeer(io); 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_session* session, tr_bandwidth* parent, - tr_address const* addr, + tr_address addr, tr_port port, time_t current_time, struct tr_peer_socket const socket) { TR_ASSERT(session != nullptr); - TR_ASSERT(tr_address_is_valid(addr)); 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_session* session, tr_bandwidth* parent, - tr_address const* addr, + tr_address addr, tr_port port, time_t current_time, tr_sha1_digest_t const& torrent_hash, @@ -653,7 +652,6 @@ tr_peerIo* tr_peerIoNewOutgoing( bool utp) { TR_ASSERT(session != nullptr); - TR_ASSERT(tr_address_is_valid(addr)); auto socket = tr_peer_socket{}; @@ -911,7 +909,7 @@ int tr_peerIoReconnect(tr_peerIo* io) io_close_socket(io); 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) { diff --git a/libtransmission/peer-io.h b/libtransmission/peer-io.h index 64659a270..beb27786b 100644 --- a/libtransmission/peer-io.h +++ b/libtransmission/peer-io.h @@ -80,7 +80,7 @@ public: tr_session* session_in, tr_sha1_digest_t const* torrent_hash, bool is_incoming, - tr_address const& addr, + tr_address addr, tr_port port, bool is_seed, time_t current_time, @@ -244,7 +244,7 @@ void tr_peerIoUtpInit(struct_utp_context* ctx); tr_peerIo* tr_peerIoNewOutgoing( tr_session* session, tr_bandwidth* parent, - struct tr_address const* addr, + tr_address addr, tr_port port, time_t current_time, tr_sha1_digest_t const& torrent_hash, @@ -254,7 +254,7 @@ tr_peerIo* tr_peerIoNewOutgoing( tr_peerIo* tr_peerIoNewIncoming( tr_session* session, tr_bandwidth* parent, - struct tr_address const* addr, + tr_address addr, tr_port port, time_t current_time, struct tr_peer_socket const socket); diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index 80fe9d41e..4fb6fe854 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -107,7 +107,7 @@ struct peer_atom return *blocklisted_; } - auto const value = tr_sessionIsAddressBlocked(session, &addr); + auto const value = session->isAddressBlocked(addr); blocklisted_ = value; return value; } @@ -1175,19 +1175,19 @@ static bool on_handshake_done(tr_handshake_result const& result) 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)); auto const lock = manager->unique_lock(); 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); } - else if (manager->incoming_handshakes.contains(*addr)) + else if (manager->incoming_handshakes.contains(addr)) { 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() */ - 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) { - if (tr_isPex(pex) && /* safeguard against corrupt data */ - !tr_sessionIsAddressBlocked(s->manager->session, &pex->addr) && - tr_address_is_valid_for_peers(&pex->addr, pex->port)) + if (tr_isPex(pex) && // safeguard against corrupt data + !s->manager->session->isAddressBlocked(pex->addr) && pex->addr.isValidPeerAddress(pex->port)) { ensureAtomExists(s, pex->addr, pex->port, pex->flags, from); ++n_used; @@ -1631,7 +1630,7 @@ namespace peer_stat_helpers 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.port = port.host(); 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( mgr->session, &mgr->session->top_bandwidth_, - &atom.addr, + atom.addr, atom.port, tr_time(), s->tor->infoHash(), diff --git a/libtransmission/peer-mgr.h b/libtransmission/peer-mgr.h index 3be2c7070..e726a898e 100644 --- a/libtransmission/peer-mgr.h +++ b/libtransmission/peer-mgr.h @@ -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); -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_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len); diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index 3809b1cf0..e750f0577 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -985,89 +985,6 @@ static void protocolSendHaveNone(tr_peerMsgsImpl* msgs) 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 **/ @@ -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)) { 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; diff --git a/libtransmission/peer-msgs.h b/libtransmission/peer-msgs.h index 4015e5a20..f349563e7 100644 --- a/libtransmission/peer-msgs.h +++ b/libtransmission/peer-msgs.h @@ -80,11 +80,4 @@ tr_peerMsgs* tr_peerMsgsNew( tr_peer_callback callback, 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); - /* @} */ diff --git a/libtransmission/peer-socket.h b/libtransmission/peer-socket.h index 71d8d71b1..829bd2c12 100644 --- a/libtransmission/peer-socket.h +++ b/libtransmission/peer-socket.h @@ -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_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); diff --git a/libtransmission/port-forwarding.cc b/libtransmission/port-forwarding.cc index 8e4f36adf..20813589b 100644 --- a/libtransmission/port-forwarding.cc +++ b/libtransmission/port-forwarding.cc @@ -96,12 +96,7 @@ static void natPulse(tr_shared* s, bool do_check) fmt::arg("private_port", session->private_peer_port.host()))); } - s->upnpStatus = tr_upnpPulse( - s->upnp, - private_peer_port, - is_enabled, - do_check, - tr_address_to_string(&session->bind_ipv4->addr)); + s->upnpStatus = tr_upnpPulse(s->upnp, private_peer_port, is_enabled, do_check, session->bind_ipv4->addr.readable()); auto const new_status = tr_sharedTraversalStatus(s); diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 7b65835a5..93dbd4203 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -147,11 +147,11 @@ std::optional tr_session::WebMediator::publicAddress() const { for (auto const type : { TR_AF_INET, TR_AF_INET6 }) { - auto is_default_value = bool{}; - tr_address const* addr = tr_sessionGetPublicAddress(session_, type, &is_default_value); - if (addr != nullptr && !is_default_value) + auto const [addr, is_default_value] = session_->getPublicAddress(type); + + 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; } -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(vsession); - auto clientAddr = tr_address{}; - auto clientPort = tr_port{}; - auto const clientSocket = tr_netAccept(session, fd, &clientAddr, &clientPort); - - if (clientSocket != TR_BAD_SOCKET) + if (auto const accepted = tr_netAccept(session, listening_sockfd); accepted) { - char addrstr[TR_ADDRSTRLEN]; - tr_address_and_port_to_string(addrstr, sizeof(addrstr), &clientAddr, clientPort); - tr_logAddTrace(fmt::format("new incoming connection {} ({})", clientSocket, addrstr)); - - tr_peerMgrAddIncoming(session->peerMgr, &clientAddr, clientPort, tr_peer_socket_tcp_create(clientSocket)); + auto const& [sock, addr, port] = *accepted; + tr_logAddTrace(fmt::format("new incoming connection {} ({})", sock, addr.readable(port))); + tr_peerMgrAddIncoming(session->peerMgr, addr, port, tr_peer_socket_tcp_create(sock)); } } @@ -258,7 +252,7 @@ static void open_incoming_peer_port(tr_session* session) { /* bind an ipv4 port to listen for incoming peers... */ 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) { @@ -270,7 +264,7 @@ static void open_incoming_peer_port(tr_session* session) if (tr_net_hasIPv6(session->private_peer_port)) { 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) { @@ -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_session::getPublicAddress(tr_address_type type) const { - char const* default_value = ""; - tr_bindinfo const* bindinfo = nullptr; - - switch (tr_af_type) - { - 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; + auto const* const bindinfo = type == TR_AF_INET6 ? bind_ipv6 : bind_ipv4; + 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; + return std::make_pair(bindinfo->addr, is_default_value); } /*** @@ -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_variantDictAddStr(d, TR_KEY_umask, fmt::format("{:#o}", s->umask)); 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_ipv6, tr_address_to_string(&s->bind_ipv6->addr)); + tr_variantDictAddStr(d, TR_KEY_bind_address_ipv4, s->bind_ipv4->addr.readable()); + 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_trash_original_torrent_files, tr_sessionGetDeleteSource(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); - if (!tr_variantDictFindStrView(settings, TR_KEY_bind_address_ipv4, &sv) || !tr_address_from_string(&b.addr, sv) || - b.addr.type != TR_AF_INET) + b.addr = tr_inaddr_any; + 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; session->bind_ipv4 = static_cast(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.type != TR_AF_INET6) + b.addr = tr_in6addr_any; + 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; @@ -2491,10 +2470,10 @@ size_t tr_blocklistSetContent(tr_session* session, char const* contentFilename) 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; - return std::any_of(std::begin(src), std::end(src), [&addr](auto& blocklist) { return blocklist->hasAddress(*addr); }); + auto const& src = blocklists; + 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) diff --git a/libtransmission/session.h b/libtransmission/session.h index f6446dd06..a6c6c9509 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -255,6 +255,10 @@ public: tr_netSetTOS(sock, peer_socket_tos_, type); } + [[nodiscard]] std::pair getPublicAddress(tr_address_type) const; + + [[nodiscard]] bool isAddressBlocked(tr_address) const noexcept; + [[nodiscard]] constexpr bool incPeerCount() noexcept { 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_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*); int tr_sessionCountTorrents(tr_session const* session); diff --git a/libtransmission/tr-dht.cc b/libtransmission/tr-dht.cc index 3382157a1..b17ddaa6e 100644 --- a/libtransmission/tr-dht.cc +++ b/libtransmission/tr-dht.cc @@ -203,7 +203,7 @@ static void dht_bootstrap(void* closure) addr.type = TR_AF_INET; memcpy(&addr.addr.addr4, &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)) @@ -213,7 +213,7 @@ static void dht_bootstrap(void* closure) addr.type = TR_AF_INET6; memcpy(&addr.addr.addr6, &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 @@ -528,9 +528,9 @@ tr_port tr_dhtPort(tr_session* ss) 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)) { @@ -545,23 +545,23 @@ bool tr_dhtAddNode(tr_session* ss, tr_address const* address, tr_port port, bool return false; } - if (address->type == TR_AF_INET) + if (address.type == TR_AF_INET) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); 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(); dht_ping_node((struct sockaddr*)&sin, sizeof(sin)); return true; } - if (address->type == TR_AF_INET6) + if (address.type == TR_AF_INET6) { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); 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(); dht_ping_node((struct sockaddr*)&sin6, sizeof(sin6)); return true; diff --git a/libtransmission/tr-dht.h b/libtransmission/tr-dht.h index fb48d0d51..e2002154b 100644 --- a/libtransmission/tr-dht.h +++ b/libtransmission/tr-dht.h @@ -10,7 +10,7 @@ #include "transmission.h" -#include "net.h" // tr_port +#include "net.h" // tr_address, tr_port enum { @@ -27,6 +27,6 @@ bool tr_dhtEnabled(tr_session const*); tr_port tr_dhtPort(tr_session*); int tr_dhtStatus(tr_session*, int af, int* setme_nodeCount); 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_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, socklen_t fromlen, void* sv); diff --git a/libtransmission/tr-udp.cc b/libtransmission/tr-udp.cc index f77288134..98e3f6cc3 100644 --- a/libtransmission/tr-udp.cc +++ b/libtransmission/tr-udp.cc @@ -290,14 +290,13 @@ void tr_udpInit(tr_session* ss) } else { - auto is_default = bool{}; - tr_address const* public_addr = tr_sessionGetPublicAddress(ss, TR_AF_INET, &is_default); + auto const [public_addr, is_default] = ss->getPublicAddress(TR_AF_INET); auto sin = sockaddr_in{}; 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(); @@ -308,7 +307,7 @@ void tr_udpInit(tr_session* ss) auto const error_code = errno; tr_logAddWarn(fmt::format( _("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_code", error_code))); tr_netCloseSocket(ss->udp_socket); diff --git a/libtransmission/tr-utp.cc b/libtransmission/tr-utp.cc index a86370eee..a402b2471 100644 --- a/libtransmission/tr-utp.cc +++ b/libtransmission/tr-utp.cc @@ -76,28 +76,28 @@ static auto constexpr UtpIntervalUs = int{ 500000 }; 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)) { utp_close(s); return; } + struct sockaddr_storage from_storage; + auto* const from = (struct sockaddr*)&from_storage; + socklen_t fromlen = sizeof(from_storage); + 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")); utp_close(s); - return; } - - tr_peerMgrAddIncoming(session->peerMgr, &addr, port, tr_peer_socket_utp_create(s)); } static void utp_send_to( diff --git a/libtransmission/upnp.cc b/libtransmission/upnp.cc index 6a3ad4587..64e784b8a 100644 --- a/libtransmission/upnp.cc +++ b/libtransmission/upnp.cc @@ -240,11 +240,9 @@ enum UPNP_IGD_INVALID = 3 }; -static auto* discoverThreadfunc(char* bindaddr) +static auto* discoverThreadfunc(std::string bindaddr) { - auto* const ret = tr_upnpDiscover(2000, bindaddr); - tr_free(bindaddr); - return ret; + return tr_upnpDiscover(2000, bindaddr.c_str()); } template @@ -253,17 +251,17 @@ static bool isFutureReady(std::future const& future) 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) { TR_ASSERT(!handle->discover_future); - auto task = std::packaged_task{ discoverThreadfunc }; + auto task = std::packaged_task{ discoverThreadfunc }; handle->discover_future = task.get_future(); 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 && diff --git a/libtransmission/upnp.h b/libtransmission/upnp.h index d575f5a55..8e04f54f7 100644 --- a/libtransmission/upnp.h +++ b/libtransmission/upnp.h @@ -18,12 +18,14 @@ #include "net.h" // tr_port +#include + struct tr_upnp; tr_upnp* tr_upnpInit(void); 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); /* @} */ diff --git a/libtransmission/web-utils.cc b/libtransmission/web-utils.cc index 7e25883fe..61c9cc328 100644 --- a/libtransmission/web-utils.cc +++ b/libtransmission/web-utils.cc @@ -33,8 +33,7 @@ using namespace std::literals; bool tr_addressIsIP(char const* str) { - tr_address tmp; - return tr_address_from_string(&tmp, str); + return tr_address::fromString(str).has_value(); } char const* tr_webGetResponseStr(long code) @@ -271,16 +270,15 @@ std::string_view getSiteName(std::string_view host) return host; } - // psl needs a zero-terminated hostname - auto const szhost = tr_urlbuf{ host }; - // is it an IP? - auto addr = tr_address{}; - if (tr_address_from_string(&addr, std::data(szhost))) + if (auto const addr = tr_address::fromString(host); addr) { return host; } + // psl needs a zero-terminated hostname + auto const szhost = tr_urlbuf{ host }; + // is it a registered name? if (isAsciiNonUpperCase(host)) { diff --git a/tests/libtransmission/blocklist-test.cc b/tests/libtransmission/blocklist-test.cc index 2065736d1..ae8386cc2 100644 --- a/tests/libtransmission/blocklist-test.cc +++ b/tests/libtransmission/blocklist-test.cc @@ -57,10 +57,10 @@ protected: #endif - bool addressIsBlocked(char const* address_str) + bool addressIsBlocked(std::string_view address_str) { - struct tr_address addr = {}; - return !tr_address_from_string(&addr, address_str) || tr_sessionIsAddressBlocked(session_, &addr); + auto const addr = tr_address::fromString(address_str); + return addr && session_->isAddressBlocked(*addr); } }; diff --git a/tests/libtransmission/peer-msgs-test.cc b/tests/libtransmission/peer-msgs-test.cc index 72ca1af58..d7389e682 100644 --- a/tests/libtransmission/peer-msgs-test.cc +++ b/tests/libtransmission/peer-msgs-test.cc @@ -14,7 +14,6 @@ TEST(PeerMsgs, placeholder) #if 0 auto infohash = tr_sha1_digest_t{}; - struct tr_address addr; tr_piece_index_t pieceCount = 1313; size_t numwant; size_t numgot; @@ -23,15 +22,15 @@ TEST(PeerMsgs, placeholder) 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; - numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, &addr); + numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, *addr); check_uint(numgot, ==, numwant); check_mem(buf, ==, pieces, numgot); numwant = 9; - numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, &addr); + numgot = tr_generateAllowedSet(buf, numwant, pieceCount, infohash, *addr); check_uint(numgot, ==, numwant); check_mem(buf, ==, pieces, numgot);