fixup: unix socket implementation changes (#2707)

* Use std::unique_ptr for bindAddress

* fixup: unix socket implementation changes

Assortment of changes and comments from #2574

- actually assign variables in the tr_rpc_address union for ipv4 and
  ipv6
- use std::size() instead of std::string.length()
- add [[maybe_unused]] to bindUnixSocket() args for Windows
- fix error log for windows to to actually print a string instead of
  an enum int
- use C++ style cast for ecvonnlistener_new_bind()
- refactor rpc URL log line to only substitute a single string
- remove redundant tr_rpc+address_is_valid() check

* change TrUnixSocketPrefix to std::string_view

This allows for removing runtime overhead of strlen() in a few places.

Co-authored-by: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com>
Co-authored-by: LaserEyess <LaserEyess@users.noreply.github.com>
This commit is contained in:
LaserEyess 2022-02-27 17:05:08 -05:00 committed by GitHub
parent 2c7e167436
commit 3bc21fe8a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 65 deletions

View File

@ -58,16 +58,16 @@ using namespace std::literals;
static char constexpr MyName[] = "RPC Server";
static char constexpr TrUnixSocketPrefix[] = "unix:";
static auto constexpr TrUnixSocketPrefix = "unix:"sv;
/* The maximum size of a unix socket path is defined per-platform based on sockaddr_un.sun_path.
* On Windows the fallback is the length of the unix prefix. Subtracting one at the end is for
* double counting null terminators from sun_path and TrUnixSocketPrefix. */
#ifdef _WIN32
auto inline constexpr TrUnixAddrStrLen = size_t{ sizeof(TrUnixSocketPrefix) };
auto inline constexpr TrUnixAddrStrLen = size_t{ std::size(TrUnixSocketPrefix) };
#else
auto inline constexpr TrUnixAddrStrLen = size_t{ sizeof(((struct sockaddr_un*)nullptr)->sun_path) + sizeof(TrUnixSocketPrefix) -
1 };
auto inline constexpr TrUnixAddrStrLen = size_t{ sizeof(((struct sockaddr_un*)nullptr)->sun_path) +
std::size(TrUnixSocketPrefix) };
#endif
enum tr_rpc_address_type
@ -82,13 +82,17 @@ struct tr_rpc_address
tr_rpc_address_type type;
union
{
struct in6_addr;
struct in_addr;
struct in_addr addr4;
struct in6_addr addr6;
char unixSocketPath[TrUnixAddrStrLen];
} addr;
};
static tr_rpc_address constexpr tr_rpc_inaddr_any = { TR_RPC_AF_INET, { INADDR_ANY } };
void set_inaddr_any()
{
type = TR_RPC_AF_INET;
addr.addr4 = { INADDR_ANY };
}
};
#define MY_REALM "Transmission"
@ -96,9 +100,9 @@ static tr_rpc_address constexpr tr_rpc_inaddr_any = { TR_RPC_AF_INET, { INADDR_A
static int constexpr DeflateLevel = 6; // medium / default
static bool constexpr tr_rpc_address_is_valid(tr_rpc_address const* a)
static bool constexpr tr_rpc_address_is_valid(tr_rpc_address const& a)
{
return a != nullptr && (a->type == TR_RPC_AF_INET || a->type == TR_RPC_AF_INET6 || a->type == TR_RPC_AF_UNIX);
return a.type == TR_RPC_AF_INET || a.type == TR_RPC_AF_INET6 || a.type == TR_RPC_AF_UNIX;
}
/***
@ -588,20 +592,20 @@ static auto constexpr ServerStartRetryDelayIncrement = int{ 5 };
static auto constexpr ServerStartRetryDelayStep = int{ 3 };
static auto constexpr ServerStartRetryMaxDelay = int{ 60 };
static char const* tr_rpc_address_to_string(tr_rpc_address const* addr, char* buf, size_t buflen)
static char const* tr_rpc_address_to_string(tr_rpc_address const& addr, char* buf, size_t buflen)
{
TR_ASSERT(tr_rpc_address_is_valid(addr));
switch (addr->type)
switch (addr.type)
{
case TR_RPC_AF_INET:
return evutil_inet_ntop(AF_INET, &addr->addr, buf, buflen);
return evutil_inet_ntop(AF_INET, &addr.addr, buf, buflen);
case TR_RPC_AF_INET6:
return evutil_inet_ntop(AF_INET6, &addr->addr, buf, buflen);
return evutil_inet_ntop(AF_INET6, &addr.addr, buf, buflen);
case TR_RPC_AF_UNIX:
tr_strlcpy(buf, addr->addr.unixSocketPath, buflen);
tr_strlcpy(buf, addr.addr.unixSocketPath, buflen);
return buf;
default:
@ -611,70 +615,79 @@ static char const* tr_rpc_address_to_string(tr_rpc_address const* addr, char* bu
static std::string tr_rpc_address_with_port(tr_rpc_server const* server)
{
tr_rpc_address const* addr = server->bindAddress;
char addr_buf[TrUnixAddrStrLen];
tr_rpc_address_to_string(addr, addr_buf, sizeof(addr_buf));
tr_rpc_address_to_string(*server->bindAddress, addr_buf, sizeof(addr_buf));
std::string addr_port_str{ addr_buf };
if (addr->type != TR_RPC_AF_UNIX)
if (server->bindAddress->type != TR_RPC_AF_UNIX)
{
addr_port_str.append(":" + std::to_string(tr_rpcGetPort(server)));
}
return addr_port_str;
}
static bool tr_rpc_address_from_string(tr_rpc_address* dst, std::string_view src)
static bool tr_rpc_address_from_string(tr_rpc_address& dst, std::string_view src)
{
if (tr_strvStartsWith(src, TrUnixSocketPrefix))
{
if (src.length() >= TrUnixAddrStrLen)
if (std::size(src) >= TrUnixAddrStrLen)
{
tr_logAddNamedError(
MyName,
_("Unix socket path must be fewer than %zu characters (including \"%s\" prefix)"),
_("Unix socket path must be fewer than %zu characters (including \"%" TR_PRIsv "\" prefix)"),
TrUnixAddrStrLen - 1,
TrUnixSocketPrefix);
TR_PRIsv_ARG(TrUnixSocketPrefix));
return false;
}
dst->type = TR_RPC_AF_UNIX;
tr_strlcpy(dst->addr.unixSocketPath, std::string{ src }.c_str(), TrUnixAddrStrLen);
dst.type = TR_RPC_AF_UNIX;
tr_strlcpy(dst.addr.unixSocketPath, std::string{ src }.c_str(), TrUnixAddrStrLen);
return true;
}
if (evutil_inet_pton(AF_INET, std::string{ src }.c_str(), &dst->addr) == 1)
if (evutil_inet_pton(AF_INET, std::string{ src }.c_str(), &dst.addr) == 1)
{
dst->type = TR_RPC_AF_INET;
dst.type = TR_RPC_AF_INET;
return true;
}
if (evutil_inet_pton(AF_INET6, std::string{ src }.c_str(), &dst->addr) == 1)
if (evutil_inet_pton(AF_INET6, std::string{ src }.c_str(), &dst.addr) == 1)
{
dst->type = TR_RPC_AF_INET6;
dst.type = TR_RPC_AF_INET6;
return true;
}
return false;
}
static bool bindUnixSocket(struct event_base* base, struct evhttp* httpd, char const* path, int socket_mode)
static bool bindUnixSocket(
[[maybe_unused]] struct event_base* base,
[[maybe_unused]] struct evhttp* httpd,
[[maybe_unused]] char const* path,
[[maybe_unused]] int socket_mode)
{
#ifdef _WIN32
tr_logAddNamedError(
MyName,
_("Unix sockets are not supported on Windows. Please change \"%s\" in your configuration file."),
TR_KEY_rpc_bind_address);
tr_quark_get_string(TR_KEY_rpc_bind_address, nullptr));
return false;
#else
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
tr_strlcpy(addr.sun_path, path + strlen(TrUnixSocketPrefix), sizeof(addr.sun_path));
tr_strlcpy(addr.sun_path, path + std::size(TrUnixSocketPrefix), sizeof(addr.sun_path));
unlink(addr.sun_path);
struct evconnlistener*
lev = evconnlistener_new_bind(base, nullptr, nullptr, LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&addr, sizeof(addr));
struct evconnlistener* lev = evconnlistener_new_bind(
base,
nullptr,
nullptr,
LEV_OPT_CLOSE_ON_FREE,
-1,
reinterpret_cast<sockaddr const*>(&addr),
sizeof(addr));
if (lev == nullptr)
{
@ -797,7 +810,7 @@ static void stopServer(tr_rpc_server* server)
if (server->bindAddress->type == TR_RPC_AF_UNIX)
{
unlink(address + strlen(TrUnixSocketPrefix));
unlink(address + std::size(TrUnixSocketPrefix));
}
tr_logAddNamedDbg(MyName, "Stopped listening on %s", tr_rpc_address_with_port(server).c_str());
@ -985,7 +998,7 @@ bool tr_rpcIsPasswordEnabled(tr_rpc_server const* server)
char const* tr_rpcGetBindAddress(tr_rpc_server const* server)
{
static char addr_buf[TrUnixAddrStrLen];
return tr_rpc_address_to_string(server->bindAddress, addr_buf, sizeof(addr_buf));
return tr_rpc_address_to_string(*server->bindAddress, addr_buf, sizeof(addr_buf));
}
bool tr_rpcGetAntiBruteForceEnabled(tr_rpc_server const* server)
@ -1024,9 +1037,9 @@ static void missing_settings_key(tr_quark const q)
tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
: compressor{ libdeflate_alloc_compressor(DeflateLevel), libdeflate_free_compressor }
, bindAddress(std::make_unique<struct tr_rpc_address>())
, session{ session_in }
{
auto address = tr_rpc_address{};
auto boolVal = bool{};
auto i = int64_t{};
auto sv = std::string_view{};
@ -1183,42 +1196,28 @@ tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
if (!tr_variantDictFindStrView(settings, key, &sv))
{
missing_settings_key(key);
address = tr_rpc_inaddr_any;
bindAddress->set_inaddr_any();
}
else
else if (!tr_rpc_address_from_string(*bindAddress, sv))
{
if (!tr_rpc_address_from_string(&address, sv))
{
tr_logAddNamedError(MyName, _("%" TR_PRIsv " is not a valid address, falling back to 0.0.0.0."), TR_PRIsv_ARG(sv));
address = tr_rpc_inaddr_any;
}
else if (address.type != TR_RPC_AF_INET && address.type != TR_RPC_AF_INET6 && address.type != TR_RPC_AF_UNIX)
{
tr_logAddNamedError(
MyName,
_("%" TR_PRIsv
" is not an IPv4 address, an IPv6 address, or a unix socket path. RPC listeners must be one of the previously mentioned types. Falling back to 0.0.0.0."),
TR_PRIsv_ARG(sv));
address = tr_rpc_inaddr_any;
}
tr_logAddNamedError(
MyName,
_("%" TR_PRIsv
" is not an IPv4 address, an IPv6 address, or a unix socket path. RPC listeners must be one of the previously mentioned types. Falling back to 0.0.0.0."),
TR_PRIsv_ARG(sv));
bindAddress->set_inaddr_any();
}
if (address.type == TR_RPC_AF_UNIX)
if (bindAddress->type == TR_RPC_AF_UNIX)
{
this->isWhitelistEnabled = false;
this->isHostWhitelistEnabled = false;
}
this->bindAddress = (tr_rpc_address*)tr_memdup(&address, sizeof(tr_rpc_address));
if (this->isEnabled)
{
tr_logAddNamedInfo(
MyName,
_("Serving RPC and Web requests on %s%s"),
tr_rpc_address_with_port(this).c_str(),
this->url.c_str());
auto const rpc_uri = tr_rpc_address_with_port(this) + this->url;
tr_logAddNamedInfo(MyName, _("Serving RPC and Web requests on %s"), rpc_uri.c_str());
tr_runInEventThread(session, startServer, this);
if (this->isWhitelistEnabled)
@ -1244,7 +1243,4 @@ tr_rpc_server::~tr_rpc_server()
TR_ASSERT(tr_amInEventThread(this->session));
stopServer(this);
tr_free(this->bindAddress);
this->bindAddress = nullptr;
}

View File

@ -44,7 +44,7 @@ public:
std::string whitelistStr;
std::string url;
struct tr_rpc_address* bindAddress;
std::unique_ptr<struct tr_rpc_address> bindAddress;
struct event* start_retry_timer = nullptr;
struct evhttp* httpd = nullptr;