mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 13:10:14 +00:00
Implement GetAddrInfo and GetNameInfo
This commit is contained in:
parent
32dfd4b4fe
commit
f20a096d8c
@ -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<char *>(Memory::GetPointer(ctr_info.ai_canonname)));
|
||||
} else {
|
||||
result.ai_canonname = nullptr;
|
||||
}
|
||||
|
||||
CTRSockAddr* addr = reinterpret_cast<CTRSockAddr *>(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<u32, SocketHolder> 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<char *>(Memory::GetPointer(cmd_buffer[6]));
|
||||
char* service = reinterpret_cast<char *>(Memory::GetPointer(cmd_buffer[8]));
|
||||
CTRAddrInfo* hints = reinterpret_cast<CTRAddrInfo *>(Memory::GetPointer(cmd_buffer[10]));
|
||||
CTRAddrInfoBuffer* buffer = reinterpret_cast<CTRAddrInfoBuffer *>(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<CTRSockAddr *>(Memory::GetPointer(cmd_buffer[6]));
|
||||
char* host = reinterpret_cast<char *>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
|
||||
char* serv = reinterpret_cast<char *>(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"},
|
||||
|
Loading…
Reference in New Issue
Block a user