mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 12:55:45 +00:00
revert [android] Snapdragon 865 patches (#23) Co-authored-by: Aleksandr Popovich <alekpopo@pm.me> Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/23 Reverted due to heavy performance hits on Android with higher specifications, will be adjusted to be included in a specific build for older A6XX devices, as 855, 860, 865, 870, meanwhile it does fix critical issues with certain games crashing due to memory and VRAM usage, hits performance on SoC that can do it without this special flags.
363 lines
13 KiB
C++
363 lines
13 KiB
C++
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <string_view>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "common/string_util.h"
|
|
#include "common/swap.h"
|
|
#include "core/core.h"
|
|
#include "core/hle/service/ipc_helpers.h"
|
|
#include "core/hle/service/sockets/sfdnsres.h"
|
|
#include "core/hle/service/sockets/sockets.h"
|
|
#include "core/hle/service/sockets/sockets_translate.h"
|
|
#include "core/internal_network/network.h"
|
|
#include "core/memory.h"
|
|
|
|
namespace Service::Sockets {
|
|
|
|
SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "SetDnsAddressesPrivateRequest"},
|
|
{1, nullptr, "GetDnsAddressPrivateRequest"},
|
|
{2, &SFDNSRES::GetHostByNameRequest, "GetHostByNameRequest"},
|
|
{3, nullptr, "GetHostByAddrRequest"},
|
|
{4, nullptr, "GetHostStringErrorRequest"},
|
|
{5, &SFDNSRES::GetGaiStringErrorRequest, "GetGaiStringErrorRequest"},
|
|
{6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"},
|
|
{7, nullptr, "GetNameInfoRequest"},
|
|
{8, nullptr, "RequestCancelHandleRequest"},
|
|
{9, nullptr, "CancelRequest"},
|
|
{10, &SFDNSRES::GetHostByNameRequestWithOptions, "GetHostByNameRequestWithOptions"},
|
|
{11, nullptr, "GetHostByAddrRequestWithOptions"},
|
|
{12, &SFDNSRES::GetAddrInfoRequestWithOptions, "GetAddrInfoRequestWithOptions"},
|
|
{13, nullptr, "GetNameInfoRequestWithOptions"},
|
|
{14, &SFDNSRES::ResolverSetOptionRequest, "ResolverSetOptionRequest"},
|
|
{15, nullptr, "ResolverGetOptionRequest"},
|
|
};
|
|
RegisterHandlers(functions);
|
|
}
|
|
|
|
SFDNSRES::~SFDNSRES() = default;
|
|
|
|
enum class NetDbError : s32 {
|
|
Internal = -1,
|
|
Success = 0,
|
|
HostNotFound = 1,
|
|
TryAgain = 2,
|
|
NoRecovery = 3,
|
|
NoData = 4,
|
|
};
|
|
|
|
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
|
// These combinations have been verified on console (but are not
|
|
// exhaustive).
|
|
switch (result) {
|
|
case GetAddrInfoError::SUCCESS:
|
|
return NetDbError::Success;
|
|
case GetAddrInfoError::AGAIN:
|
|
return NetDbError::TryAgain;
|
|
case GetAddrInfoError::NODATA:
|
|
return NetDbError::HostNotFound;
|
|
case GetAddrInfoError::SERVICE:
|
|
return NetDbError::Success;
|
|
default:
|
|
return NetDbError::HostNotFound;
|
|
}
|
|
}
|
|
|
|
static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
|
|
// These combinations have been verified on console (but are not
|
|
// exhaustive).
|
|
switch (result) {
|
|
case GetAddrInfoError::SUCCESS:
|
|
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
|
|
// some reason, but that doesn't seem useful to implement.
|
|
return Errno::SUCCESS;
|
|
case GetAddrInfoError::AGAIN:
|
|
return Errno::SUCCESS;
|
|
case GetAddrInfoError::NODATA:
|
|
return Errno::SUCCESS;
|
|
case GetAddrInfoError::SERVICE:
|
|
return Errno::INVAL;
|
|
default:
|
|
return Errno::SUCCESS;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static void Append(std::vector<u8>& vec, T t) {
|
|
const size_t offset = vec.size();
|
|
vec.resize(offset + sizeof(T));
|
|
std::memcpy(vec.data() + offset, &t, sizeof(T));
|
|
}
|
|
|
|
static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
|
|
const size_t offset = vec.size();
|
|
vec.resize(offset + str.size() + 1);
|
|
std::memmove(vec.data() + offset, str.data(), str.size());
|
|
}
|
|
|
|
// We implement gethostbyname using the host's getaddrinfo rather than the
|
|
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
|
|
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
|
|
// doesn't implement h_errno.
|
|
static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
|
|
std::string_view host) {
|
|
|
|
std::vector<u8> data;
|
|
// h_name: use the input hostname (append nul-terminated)
|
|
AppendNulTerminated(data, host);
|
|
// h_aliases: leave empty
|
|
|
|
Append<u32_be>(data, 0); // count of h_aliases
|
|
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
|
|
Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
|
|
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
|
|
// h_addr_list:
|
|
size_t count = vec.size();
|
|
ASSERT(count <= UINT32_MAX);
|
|
Append<u32_be>(data, static_cast<uint32_t>(count));
|
|
for (const Network::AddrInfo& addrinfo : vec) {
|
|
// On the Switch, this is passed through htonl despite already being
|
|
// big-endian, so it ends up as little-endian.
|
|
Append<u32_le>(data, Network::IPv4AddressToInteger(addrinfo.addr.ip));
|
|
|
|
LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host,
|
|
Network::IPv4AddressToString(addrinfo.addr.ip));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
|
struct InputParameters {
|
|
u8 use_nsd_resolve;
|
|
u32 cancel_handle;
|
|
u64 process_id;
|
|
};
|
|
static_assert(sizeof(InputParameters) == 0x10);
|
|
|
|
IPC::RequestParser rp{ctx};
|
|
const auto parameters = rp.PopRaw<InputParameters>();
|
|
|
|
LOG_WARNING(
|
|
Service,
|
|
"called with ignored parameters: use_nsd_resolve={}, cancel_handle={}, process_id={}",
|
|
parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
|
|
|
|
const auto host_buffer = ctx.ReadBuffer(0);
|
|
const std::string host = Common::StringFromBuffer(host_buffer);
|
|
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
|
|
|
|
// Prevent resolution of Nintendo servers
|
|
if (host.find("srv.nintendo.net") != std::string::npos) {
|
|
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
|
return {0, GetAddrInfoError::AGAIN};
|
|
}
|
|
|
|
auto res = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
|
if (!res.has_value()) {
|
|
return {0, Translate(res.error())};
|
|
}
|
|
|
|
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(res.value(), host);
|
|
const u32 data_size = static_cast<u32>(data.size());
|
|
ctx.WriteBuffer(data, 0);
|
|
|
|
return {data_size, GetAddrInfoError::SUCCESS};
|
|
}
|
|
|
|
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
|
auto [data_size, emu_gai_err] = GetHostByNameRequestImpl(ctx);
|
|
|
|
struct OutputParameters {
|
|
NetDbError netdb_error;
|
|
Errno bsd_errno;
|
|
u32 data_size;
|
|
};
|
|
static_assert(sizeof(OutputParameters) == 0xc);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 5};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(OutputParameters{
|
|
.netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
|
|
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
|
|
.data_size = data_size,
|
|
});
|
|
}
|
|
|
|
void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
|
auto [data_size, emu_gai_err] = GetHostByNameRequestImpl(ctx);
|
|
|
|
struct OutputParameters {
|
|
u32 data_size;
|
|
NetDbError netdb_error;
|
|
Errno bsd_errno;
|
|
};
|
|
static_assert(sizeof(OutputParameters) == 0xc);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 5};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(OutputParameters{
|
|
.data_size = data_size,
|
|
.netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
|
|
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
|
|
});
|
|
}
|
|
|
|
static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
|
|
std::string_view host) {
|
|
// Adapted from
|
|
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
|
|
std::vector<u8> data;
|
|
|
|
for (const Network::AddrInfo& addrinfo : vec) {
|
|
// serialized addrinfo:
|
|
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
|
Append<u32_be>(data, 0); // ai_flags
|
|
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
|
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
|
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
|
Append<u32_be>(data, sizeof(SockAddrIn)); // ai_addrlen
|
|
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
|
|
|
// ai_addr:
|
|
Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
|
|
// On the Switch, the following fields are passed through htonl despite
|
|
// already being big-endian, so they end up as little-endian.
|
|
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
|
|
Append<u32_le>(data, Network::IPv4AddressToInteger(addrinfo.addr.ip)); // sin_addr
|
|
data.resize(data.size() + 8, 0); // sin_zero
|
|
|
|
if (addrinfo.canon_name.has_value()) {
|
|
AppendNulTerminated(data, *addrinfo.canon_name);
|
|
} else {
|
|
data.push_back(0);
|
|
}
|
|
|
|
LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host,
|
|
Network::IPv4AddressToString(addrinfo.addr.ip));
|
|
}
|
|
|
|
data.resize(data.size() + 4, 0); // 4-byte sentinel value
|
|
|
|
return data;
|
|
}
|
|
|
|
static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
|
struct InputParameters {
|
|
u8 use_nsd_resolve;
|
|
u32 cancel_handle;
|
|
u64 process_id;
|
|
};
|
|
static_assert(sizeof(InputParameters) == 0x10);
|
|
|
|
IPC::RequestParser rp{ctx};
|
|
const auto parameters = rp.PopRaw<InputParameters>();
|
|
|
|
LOG_WARNING(
|
|
Service,
|
|
"called with ignored parameters: use_nsd_resolve={}, cancel_handle={}, process_id={}",
|
|
parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
|
|
|
|
// TODO: If use_nsd_resolve is true, pass the name through NSD::Resolve
|
|
// before looking up.
|
|
|
|
const auto host_buffer = ctx.ReadBuffer(0);
|
|
const std::string host = Common::StringFromBuffer(host_buffer);
|
|
|
|
// Prevent resolution of Nintendo servers
|
|
if (host.find("srv.nintendo.net") != std::string::npos) {
|
|
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
|
return {0, GetAddrInfoError::AGAIN};
|
|
}
|
|
|
|
std::optional<std::string> service = std::nullopt;
|
|
if (ctx.CanReadBuffer(1)) {
|
|
const std::span<const u8> service_buffer = ctx.ReadBuffer(1);
|
|
service = Common::StringFromBuffer(service_buffer);
|
|
}
|
|
|
|
// Serialized hints are also passed in a buffer, but are ignored for now.
|
|
|
|
auto res = Network::GetAddressInfo(host, service);
|
|
if (!res.has_value()) {
|
|
return {0, Translate(res.error())};
|
|
}
|
|
|
|
const std::vector<u8> data = SerializeAddrInfo(res.value(), host);
|
|
const u32 data_size = static_cast<u32>(data.size());
|
|
ctx.WriteBuffer(data, 0);
|
|
|
|
return {data_size, GetAddrInfoError::SUCCESS};
|
|
}
|
|
|
|
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
|
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
|
|
|
struct OutputParameters {
|
|
Errno bsd_errno;
|
|
GetAddrInfoError gai_error;
|
|
u32 data_size;
|
|
};
|
|
static_assert(sizeof(OutputParameters) == 0xc);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 5};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(OutputParameters{
|
|
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
|
|
.gai_error = emu_gai_err,
|
|
.data_size = data_size,
|
|
});
|
|
}
|
|
|
|
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
|
|
struct InputParameters {
|
|
GetAddrInfoError gai_errno;
|
|
};
|
|
IPC::RequestParser rp{ctx};
|
|
auto input = rp.PopRaw<InputParameters>();
|
|
|
|
const std::string result = Translate(input.gai_errno);
|
|
ctx.WriteBuffer(result);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
|
|
// Additional options are ignored
|
|
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
|
|
|
struct OutputParameters {
|
|
u32 data_size;
|
|
GetAddrInfoError gai_error;
|
|
NetDbError netdb_error;
|
|
Errno bsd_errno;
|
|
};
|
|
static_assert(sizeof(OutputParameters) == 0x10);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 6};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(OutputParameters{
|
|
.data_size = data_size,
|
|
.gai_error = emu_gai_err,
|
|
.netdb_error = GetAddrInfoErrorToNetDbError(emu_gai_err),
|
|
.bsd_errno = GetAddrInfoErrorToErrno(emu_gai_err),
|
|
});
|
|
}
|
|
|
|
void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service, "(STUBBED) called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
|
|
rb.Push(ResultSuccess);
|
|
rb.Push<s32>(0); // bsd errno
|
|
}
|
|
|
|
} // namespace Service::Sockets
|