refactor: add tr_address::fromSockaddr() (#3964)

* refactor: remove TR_DISCARD_ALIGN

* refactor: add tr_address::fromSockaddr()
This commit is contained in:
Charles Kerr 2022-10-14 01:20:39 -05:00 committed by GitHub
parent 9ccaffb044
commit 572e1bb50f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 79 additions and 49 deletions

View File

@ -48,11 +48,11 @@ static void tau_sockaddr_setport(struct sockaddr* sa, tr_port port)
{
if (sa->sa_family == AF_INET)
{
TR_DISCARD_ALIGN(sa, struct sockaddr_in*)->sin_port = port.network();
reinterpret_cast<sockaddr_in*>(sa)->sin_port = port.network();
}
else if (sa->sa_family == AF_INET6)
{
TR_DISCARD_ALIGN(sa, struct sockaddr_in6*)->sin6_port = port.network();
reinterpret_cast<sockaddr_in6*>(sa)->sin6_port = port.network();
}
}

View File

@ -186,27 +186,32 @@ 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<std::pair<tr_address, tr_port>> tr_address::fromSockaddr(struct sockaddr const* from)
{
if (from->ss_family == AF_INET)
if (from == nullptr)
{
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;
return {};
}
if (from->ss_family == AF_INET6)
if (from->sa_family == AF_INET)
{
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 sin = reinterpret_cast<struct sockaddr_in const*>(from);
auto addr = tr_address{};
addr.type = TR_AF_INET;
addr.addr.addr4 = sin->sin_addr;
return std::make_pair(addr, tr_port::fromNetwork(sin->sin_port));
}
return false;
if (from->sa_family == AF_INET6)
{
auto const* const sin6 = reinterpret_cast<struct sockaddr_in6 const*>(from);
auto addr = tr_address{};
addr.type = TR_AF_INET6;
addr.addr.addr6 = sin6->sin6_addr;
return std::make_pair(addr, tr_port::fromNetwork(sin6->sin6_port));
}
return {};
}
std::pair<sockaddr_storage, socklen_t> tr_address::toSockaddr(tr_port port) const noexcept
@ -216,7 +221,7 @@ std::pair<sockaddr_storage, socklen_t> tr_address::toSockaddr(tr_port port) cons
if (isIPv4())
{
auto* const ss4 = reinterpret_cast<sockaddr_in*>(&ss);
ss4->sin_addr.s_addr = addr.addr4.s_addr;
ss4->sin_addr = addr.addr4;
ss4->sin_family = AF_INET;
ss4->sin_port = port.network();
return { ss, sizeof(sockaddr_in) };
@ -533,11 +538,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<std::tuple<tr_address, tr_port, tr_socket_t>> tr_netAccept(tr_session* session, tr_socket_t listening_sockfd)
{
TR_ASSERT(session != nullptr);
TR_ASSERT(addr != nullptr);
TR_ASSERT(port != nullptr);
// accept the incoming connection
auto sock = sockaddr_storage{};
@ -545,20 +548,20 @@ 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::fromSockaddr(reinterpret_cast<struct sockaddr*>(&sock));
if (!addrport || evutil_make_socket_nonblocking(sockfd) == -1 || !session->incPeerCount())
{
tr_netCloseSocket(sockfd);
return TR_BAD_SOCKET;
return {};
}
return sockfd;
return std::make_tuple(addrport->first, addrport->second, sockfd);
}
void tr_netCloseSocket(tr_socket_t sockfd)

View File

@ -153,6 +153,7 @@ private:
struct tr_address
{
[[nodiscard]] static std::optional<tr_address> fromString(std::string_view address_sv);
[[nodiscard]] static std::optional<std::pair<tr_address, tr_port>> fromSockaddr(struct sockaddr const*);
[[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;
@ -206,8 +207,6 @@ struct tr_address
extern tr_address const tr_inaddr_any;
extern tr_address const tr_in6addr_any;
bool tr_address_from_sockaddr_storage(tr_address* setme, tr_port* port, struct sockaddr_storage const* from);
bool tr_address_is_valid_for_peers(tr_address const* addr, tr_port port);
constexpr bool tr_address_is_valid(tr_address const* a)
@ -223,7 +222,9 @@ struct tr_session;
tr_socket_t tr_netBindTCP(tr_address const* addr, tr_port port, bool suppress_msgs);
tr_socket_t tr_netAccept(tr_session* session, tr_socket_t listening_sockfd, tr_address* setme_addr, tr_port* setme_port);
[[nodiscard]] std::optional<std::tuple<tr_address, tr_port, tr_socket_t>> tr_netAccept(
tr_session* session,
tr_socket_t listening_sockfd);
void tr_netSetCongestionControl(tr_socket_t s, char const* algorithm);

View File

@ -287,15 +287,11 @@ static void acceptIncomingPeer(evutil_socket_t fd, short /*what*/, void* vsessio
{
auto* session = static_cast<tr_session*>(vsession);
auto client_addr = tr_address{};
auto client_port = tr_port{};
auto const client_socket = tr_netAccept(session, fd, &client_addr, &client_port);
if (client_socket != TR_BAD_SOCKET)
if (auto const incoming_info = tr_netAccept(session, fd); incoming_info)
{
tr_logAddTrace(fmt::format("new incoming connection {} ({})", client_socket, client_addr.readable(client_port)));
session->addIncoming(client_addr, client_port, tr_peer_socket_tcp_create(client_socket));
auto const [addr, port, sock] = *incoming_info;
tr_logAddTrace(fmt::format("new incoming connection {} ({})", sock, addr.readable(port)));
session->addIncoming(addr, port, tr_peer_socket_tcp_create(sock));
}
}

View File

@ -60,9 +60,6 @@
#define TR_PATH_DELIMITER '/'
/* Only use this macro to suppress false-positive alignment warnings */
#define TR_DISCARD_ALIGN(ptr, type) ((type)(void*)(ptr))
#define TR_INET6_ADDRSTRLEN 46
#define TR_ADDRSTRLEN 64

View File

@ -76,30 +76,30 @@ void tr_utpClose(tr_session* /*session*/)
/* Greg says 50ms works for them. */
static auto constexpr UtpInterval = 50ms;
static void utp_on_accept(tr_session* const session, UTPSocket* const s)
static void utp_on_accept(tr_session* const session, UTPSocket* const utp_sock)
{
auto from_storage = sockaddr_storage{};
auto* const from = (struct sockaddr*)&from_storage;
socklen_t fromlen = sizeof(from_storage);
auto addr = tr_address{};
auto port = tr_port{};
if (!session->allowsUTP())
{
utp_close(s);
utp_close(utp_sock);
return;
}
utp_getpeername(s, from, &fromlen);
utp_getpeername(utp_sock, from, &fromlen);
if (!tr_address_from_sockaddr_storage(&addr, &port, &from_storage))
if (auto addrport = tr_address::fromSockaddr(reinterpret_cast<struct sockaddr*>(&from_storage)); addrport)
{
auto const [addr, port] = *addrport;
session->addIncoming(addr, port, tr_peer_socket_utp_create(utp_sock));
}
else
{
tr_logAddWarn(_("Unknown socket family"));
utp_close(s);
return;
utp_close(utp_sock);
}
session->addIncoming(addr, port, tr_peer_socket_utp_create(s));
}
static void utp_send_to(

View File

@ -21,6 +21,7 @@ add_executable(libtransmission-test
magnet-metainfo-test.cc
makemeta-test.cc
move-test.cc
net-test.cc
open-files-test.cc
peer-mgr-active-requests-test.cc
peer-mgr-wishlist-test.cc

View File

@ -0,0 +1,32 @@
// This file Copyright (C) 2013-2022 Mnemosyne LLC.
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#include "transmission.h"
#include "net.h"
#include "test-fixtures.h"
using NetTest = ::testing::Test;
using namespace std::literals;
TEST_F(NetTest, conversionsIPv4)
{
auto constexpr port = tr_port::fromHost(80);
auto constexpr addrstr = "127.0.0.1"sv;
auto addr = tr_address::fromString(addrstr);
EXPECT_TRUE(addr);
EXPECT_EQ(addrstr, addr->readable());
auto [ss, sslen] = addr->toSockaddr(port);
EXPECT_EQ(AF_INET, ss.ss_family);
EXPECT_EQ(port.network(), reinterpret_cast<sockaddr_in const*>(&ss)->sin_port);
auto addrport = tr_address::fromSockaddr(reinterpret_cast<sockaddr const*>(&ss));
EXPECT_TRUE(addrport);
EXPECT_EQ(addr, addrport->first);
EXPECT_EQ(port, addrport->second);
}