diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index d3e5d4bca..c40e99b8c 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -323,6 +323,80 @@ union CTRSockAddr { } }; +// CTR's addrinfo struct +struct CTRAddrInfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + u32 ai_canonname; //char* + u32 ai_addr; //CTRSockAddr* + u32 ai_next; //CTRAddrInfo* + + static addrinfo ToPlatform(CTRAddrInfo const& ctr_info) { + addrinfo result; + result.ai_flags = ctr_info.ai_flags; + result.ai_family = ctr_info.ai_family; + result.ai_socktype = ctr_info.ai_socktype; + result.ai_protocol = ctr_info.ai_protocol; + result.ai_addrlen = ctr_info.ai_addrlen; + if(ctr_info.ai_canonname != 0) { + result.ai_canonname = ::strdup(reinterpret_cast(Memory::GetPointer(ctr_info.ai_canonname))); + } else { + result.ai_canonname = nullptr; + } + + CTRSockAddr* addr = reinterpret_cast(Memory::GetPointer(ctr_info.ai_addr)); + if(addr != nullptr) { + result.ai_addr = new sockaddr(); + sockaddr plat_addr = CTRSockAddr::ToPlatform(*addr); + ::memcpy(result.ai_addr, &plat_addr, sizeof(sockaddr)); + } else { + result.ai_addr = nullptr; + } + + return result; + } + + static void FreePlatform(addrinfo const& info) { + if(info.ai_canonname != nullptr) { + delete info.ai_canonname; + } + if(info.ai_addr != nullptr) { + delete info.ai_addr; + } + } +}; + +// Special addrinfo buffer format struct with specific sizes for each entry +struct CTRAddrInfoBuffer { + s32 ai_flags; + s32 ai_family; + s32 ai_socktype; + s32 ai_protocol; + u32 ai_addrlen; + char ai_canonname[256]; + sockaddr_storage ai_addr; + + static void FromAddrInfo(addrinfo const& info, CTRAddrInfoBuffer *buffer) { + buffer->ai_flags = info.ai_flags; + buffer->ai_family = info.ai_family; + buffer->ai_socktype = info.ai_socktype; + buffer->ai_protocol = info.ai_protocol; + buffer->ai_addrlen = info.ai_addrlen; + + size_t min_length = 0; + if(info.ai_canonname != nullptr) { + size_t info_name_len = ::strlen(info.ai_canonname); + min_length = info_name_len < 256 ? info_name_len : 256; + } + + ::strncpy(buffer->ai_canonname, info.ai_canonname, min_length); + ::memcpy(&buffer->ai_addr, info.ai_addr, sizeof(sockaddr_storage)); + } +}; + /// Holds info about the currently open sockets static std::unordered_map open_sockets; @@ -818,6 +892,67 @@ static void SetSockOpt(Service::Interface* self) { cmd_buffer[2] = err; } +static void GetAddrInfo(Service::Interface* self) { + u32* cmd_buffer = Kernel::GetCommandBuffer(); + u32 buffer_len = cmd_buffer[4]; // count * sizeof(CTRAddrInfoBuffer) + u32 max_count = buffer_len / sizeof(CTRAddrInfoBuffer); + + char* node = reinterpret_cast(Memory::GetPointer(cmd_buffer[6])); + char* service = reinterpret_cast(Memory::GetPointer(cmd_buffer[8])); + CTRAddrInfo* hints = reinterpret_cast(Memory::GetPointer(cmd_buffer[10])); + CTRAddrInfoBuffer* buffer = reinterpret_cast(Memory::GetPointer(cmd_buffer[0x104 >> 2])); + + int ret; + int err = 0; + int count = 0; + + addrinfo* results; + addrinfo* res; + addrinfo plat_hints = CTRAddrInfo::ToPlatform(*hints); + + ret = ::getaddrinfo(node, service, &plat_hints, &results); + + CTRAddrInfo::FreePlatform(plat_hints); + + if(ret == SOCKET_ERROR_VALUE) { + err = TranslateError(GET_ERRNO); + } else { + res = results; + while(res != nullptr && count < max_count) { + CTRAddrInfoBuffer::FromAddrInfo(*res, buffer + (count++)); + res = res->ai_next; + } + freeaddrinfo(results); + } + + cmd_buffer[0] = IPC::MakeHeader(0x0F, 4, 6); + cmd_buffer[1] = ret; + cmd_buffer[2] = err; + cmd_buffer[3] = count; +} + +static void GetNameInfo(Service::Interface* self) { + u32* cmd_buffer = Kernel::GetCommandBuffer(); + u32 tmpaddr_len = cmd_buffer[1]; + u32 hostlen = cmd_buffer[2]; + u32 servlen = cmd_buffer[3]; + u32 flags = cmd_buffer[4]; + + CTRSockAddr* tmpaddr = reinterpret_cast(Memory::GetPointer(cmd_buffer[6])); + char* host = reinterpret_cast(Memory::GetPointer(cmd_buffer[0x104 >> 2])); + char* serv = reinterpret_cast(Memory::GetPointer(cmd_buffer[0x10C >> 2])); + + int ret; + int err = 0; + + sockaddr addr = CTRSockAddr::ToPlatform(*tmpaddr); + ::getnameinfo(&addr, tmpaddr_len, host, hostlen, serv, servlen, flags); + + cmd_buffer[0] = IPC::MakeHeader(0x10, 4, 2); + cmd_buffer[1] = ret; + cmd_buffer[2] = err; +} + const Interface::FunctionInfo FunctionTable[] = { {0x00010044, InitializeSockets, "InitializeSockets"}, {0x000200C2, Socket, "Socket"}, @@ -833,8 +968,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000C0082, Shutdown, "Shutdown"}, {0x000D0082, nullptr, "GetHostByName"}, {0x000E00C2, nullptr, "GetHostByAddr"}, - {0x000F0106, nullptr, "GetAddrInfo"}, - {0x00100102, nullptr, "GetNameInfo"}, + {0x000F0106, GetAddrInfo, "GetAddrInfo"}, + {0x00100102, GetNameInfo, "GetNameInfo"}, {0x00110102, GetSockOpt, "GetSockOpt"}, {0x00120104, SetSockOpt, "SetSockOpt"}, {0x001300C2, Fcntl, "Fcntl"},