From 08bf899d704bf4c7f5f4a53514aa22cc6429bd28 Mon Sep 17 00:00:00 2001 From: zhupengfei Date: Sat, 9 Feb 2019 17:49:50 +0800 Subject: [PATCH 1/2] service/soc_u: Implement getaddrinfo and getnameinfo --- src/core/hle/service/soc_u.cpp | 131 ++++++++++++++++++++++++++++++++- src/core/hle/service/soc_u.h | 2 + 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index c0995f192..68929f95a 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -51,6 +51,14 @@ #define closesocket(x) close(x) #endif +// Some platforms seem to have these defined, they conflict with our function names +#ifdef GetAddrInfo +#undef GetAddrInfo +#endif +#ifdef GetNameInfo +#undef GetNameInfo +#endif + namespace Service::SOC { const s32 SOCKET_ERROR_VALUE = -1; @@ -320,6 +328,36 @@ union CTRSockAddr { } }; +struct CTRAddrInfo { + s32 ai_flags; + s32 ai_family; + s32 ai_socktype; + s32 ai_protocol; + s32 ai_addrlen; + char ai_canonname[256]; + CTRSockAddr ai_addr; + + /// Converts a platform-specific addrinfo to a 3ds addrinfo. + static CTRAddrInfo FromPlatform(const addrinfo& addr) { + CTRAddrInfo ctr_addr; + std::memset(&ctr_addr, 0, sizeof(ctr_addr)); + + ctr_addr.ai_flags = addr.ai_flags; + ctr_addr.ai_family = addr.ai_family; + ctr_addr.ai_socktype = addr.ai_socktype; + ctr_addr.ai_protocol = addr.ai_protocol; + if (addr.ai_canonname) + std::strncpy(ctr_addr.ai_canonname, addr.ai_canonname, sizeof(ctr_addr.ai_canonname)); + + ctr_addr.ai_addr = CTRSockAddr::FromPlatform(*addr.ai_addr); + ctr_addr.ai_addrlen = ctr_addr.ai_addr.raw.len; + + return ctr_addr; + } +}; + +static_assert(sizeof(CTRAddrInfo) == 0x130, "Size of CTRAddrInfo is not correct"); + void SOC_U::CleanupSockets() { for (auto sock : open_sockets) closesocket(sock.second.socket_fd); @@ -858,6 +896,95 @@ void SOC_U::SetSockOpt(Kernel::HLERequestContext& ctx) { rb.Push(err); } +void SOC_U::GetAddrInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0F, 4, 6); + u32 node_length = rp.Pop(); + u32 service_length = rp.Pop(); + u32 hints_size = rp.Pop(); + u32 out_size = rp.Pop(); + auto node = rp.PopStaticBuffer(); + auto service = rp.PopStaticBuffer(); + auto hints_buff = rp.PopStaticBuffer(); + + const char* node_data = node_length > 0 ? reinterpret_cast(node.data()) : nullptr; + const char* service_data = + service_length > 0 ? reinterpret_cast(service.data()) : nullptr; + + s32 ret = -1; + addrinfo* out = nullptr; + if (hints_size > 0) { + CTRAddrInfo ctr_hints; + std::memcpy(&ctr_hints, hints_buff.data(), hints_size); + // Only certain fields are meaningful in hints, copy them manually + addrinfo hints = {}; + hints.ai_flags = ctr_hints.ai_flags; + hints.ai_family = ctr_hints.ai_family; + hints.ai_socktype = ctr_hints.ai_socktype; + hints.ai_protocol = ctr_hints.ai_protocol; + ret = getaddrinfo(node_data, service_data, &hints, &out); + } else { + ret = getaddrinfo(node_data, service_data, nullptr, &out); + } + + std::vector out_buff(out_size); + u32 count = 0; + + if (ret == SOCKET_ERROR_VALUE) { + ret = TranslateError(GET_ERRNO); + out_buff.resize(0); + } else { + std::size_t pos = 0; + addrinfo* cur = out; + while (cur != nullptr) { + if (pos <= out_size - sizeof(CTRAddrInfo)) { + // According to 3dbrew, this function fills whatever it can and does not error even + // if the buffer is not big enough. However the count returned is always correct. + CTRAddrInfo ctr_addr = CTRAddrInfo::FromPlatform(*cur); + std::memcpy(out_buff.data() + pos, &ctr_addr, sizeof(ctr_addr)); + } + cur = cur->ai_next; + count++; + } + if (out != nullptr) + freeaddrinfo(out); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); + rb.Push(RESULT_SUCCESS); + rb.Push(ret); + rb.Push(count); + rb.PushStaticBuffer(out_buff, 0); +} + +void SOC_U::GetNameInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x10, 4, 2); + u32 socklen = rp.Pop(); + u32 hostlen = rp.Pop(); + u32 servlen = rp.Pop(); + int flags = static_cast(rp.Pop()); + auto sa_buff = rp.PopStaticBuffer(); + + CTRSockAddr ctr_sa; + std::memcpy(&ctr_sa, sa_buff.data(), socklen); + sockaddr sa = CTRSockAddr::ToPlatform(ctr_sa); + + std::vector host(hostlen); + std::vector serv(servlen); + char* host_data = hostlen > 0 ? reinterpret_cast(host.data()) : nullptr; + char* serv_data = servlen > 0 ? reinterpret_cast(serv.data()) : nullptr; + + s32 ret = getnameinfo(&sa, sizeof(sa), host_data, hostlen, serv_data, servlen, flags); + if (ret == SOCKET_ERROR_VALUE) { + ret = TranslateError(GET_ERRNO); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 4); + rb.Push(RESULT_SUCCESS); + rb.Push(ret); + rb.PushStaticBuffer(host, 0); + rb.PushStaticBuffer(serv, 1); +} + SOC_U::SOC_U() : ServiceFramework("soc:U") { static const FunctionInfo functions[] = { {0x00010044, &SOC_U::InitializeSockets, "InitializeSockets"}, @@ -874,8 +1001,8 @@ SOC_U::SOC_U() : ServiceFramework("soc:U") { {0x000C0082, &SOC_U::Shutdown, "Shutdown"}, {0x000D0082, nullptr, "GetHostByName"}, {0x000E00C2, nullptr, "GetHostByAddr"}, - {0x000F0106, nullptr, "GetAddrInfo"}, - {0x00100102, nullptr, "GetNameInfo"}, + {0x000F0106, &SOC_U::GetAddrInfo, "GetAddrInfo"}, + {0x00100102, &SOC_U::GetNameInfo, "GetNameInfo"}, {0x00110102, &SOC_U::GetSockOpt, "GetSockOpt"}, {0x00120104, &SOC_U::SetSockOpt, "SetSockOpt"}, {0x001300C2, &SOC_U::Fcntl, "Fcntl"}, diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h index cb650c82c..5ba89d8d8 100644 --- a/src/core/hle/service/soc_u.h +++ b/src/core/hle/service/soc_u.h @@ -44,6 +44,8 @@ private: void ShutdownSockets(Kernel::HLERequestContext& ctx); void GetSockOpt(Kernel::HLERequestContext& ctx); void SetSockOpt(Kernel::HLERequestContext& ctx); + void GetAddrInfo(Kernel::HLERequestContext& ctx); + void GetNameInfo(Kernel::HLERequestContext& ctx); /// Close all open sockets void CleanupSockets(); From 1995e8ff32d6591bb4143d78633bbace60a7214d Mon Sep 17 00:00:00 2001 From: zhupengfei Date: Sun, 10 Feb 2019 18:49:18 +0800 Subject: [PATCH 2/2] service/soc_u: address review comments --- src/core/hle/service/soc_u.cpp | 32 ++++++++++++-------------------- src/core/hle/service/soc_u.h | 7 +++++-- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 68929f95a..5ebe55356 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scope_exit.h" +#include "common/swap.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/shared_memory.h" @@ -51,14 +52,6 @@ #define closesocket(x) close(x) #endif -// Some platforms seem to have these defined, they conflict with our function names -#ifdef GetAddrInfo -#undef GetAddrInfo -#endif -#ifdef GetNameInfo -#undef GetNameInfo -#endif - namespace Service::SOC { const s32 SOCKET_ERROR_VALUE = -1; @@ -329,18 +322,17 @@ union CTRSockAddr { }; struct CTRAddrInfo { - s32 ai_flags; - s32 ai_family; - s32 ai_socktype; - s32 ai_protocol; - s32 ai_addrlen; + s32_le ai_flags; + s32_le ai_family; + s32_le ai_socktype; + s32_le ai_protocol; + s32_le ai_addrlen; char ai_canonname[256]; CTRSockAddr ai_addr; /// Converts a platform-specific addrinfo to a 3ds addrinfo. static CTRAddrInfo FromPlatform(const addrinfo& addr) { - CTRAddrInfo ctr_addr; - std::memset(&ctr_addr, 0, sizeof(ctr_addr)); + CTRAddrInfo ctr_addr{}; ctr_addr.ai_flags = addr.ai_flags; ctr_addr.ai_family = addr.ai_family; @@ -896,7 +888,7 @@ void SOC_U::SetSockOpt(Kernel::HLERequestContext& ctx) { rb.Push(err); } -void SOC_U::GetAddrInfo(Kernel::HLERequestContext& ctx) { +void SOC_U::GetAddrInfoImpl(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0F, 4, 6); u32 node_length = rp.Pop(); u32 service_length = rp.Pop(); @@ -956,12 +948,12 @@ void SOC_U::GetAddrInfo(Kernel::HLERequestContext& ctx) { rb.PushStaticBuffer(out_buff, 0); } -void SOC_U::GetNameInfo(Kernel::HLERequestContext& ctx) { +void SOC_U::GetNameInfoImpl(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x10, 4, 2); u32 socklen = rp.Pop(); u32 hostlen = rp.Pop(); u32 servlen = rp.Pop(); - int flags = static_cast(rp.Pop()); + s32 flags = rp.Pop(); auto sa_buff = rp.PopStaticBuffer(); CTRSockAddr ctr_sa; @@ -1001,8 +993,8 @@ SOC_U::SOC_U() : ServiceFramework("soc:U") { {0x000C0082, &SOC_U::Shutdown, "Shutdown"}, {0x000D0082, nullptr, "GetHostByName"}, {0x000E00C2, nullptr, "GetHostByAddr"}, - {0x000F0106, &SOC_U::GetAddrInfo, "GetAddrInfo"}, - {0x00100102, &SOC_U::GetNameInfo, "GetNameInfo"}, + {0x000F0106, &SOC_U::GetAddrInfoImpl, "GetAddrInfo"}, + {0x00100102, &SOC_U::GetNameInfoImpl, "GetNameInfo"}, {0x00110102, &SOC_U::GetSockOpt, "GetSockOpt"}, {0x00120104, &SOC_U::SetSockOpt, "SetSockOpt"}, {0x001300C2, &SOC_U::Fcntl, "Fcntl"}, diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h index 5ba89d8d8..273aac49c 100644 --- a/src/core/hle/service/soc_u.h +++ b/src/core/hle/service/soc_u.h @@ -44,8 +44,11 @@ private: void ShutdownSockets(Kernel::HLERequestContext& ctx); void GetSockOpt(Kernel::HLERequestContext& ctx); void SetSockOpt(Kernel::HLERequestContext& ctx); - void GetAddrInfo(Kernel::HLERequestContext& ctx); - void GetNameInfo(Kernel::HLERequestContext& ctx); + + // Some platforms seem to have GetAddrInfo and GetNameInfo defined as macros, + // so we have to use a different name here. + void GetAddrInfoImpl(Kernel::HLERequestContext& ctx); + void GetNameInfoImpl(Kernel::HLERequestContext& ctx); /// Close all open sockets void CleanupSockets();