Implement GetAddrInfo and GetNameInfo

This commit is contained in:
Ryan Loebs 2016-04-19 23:09:34 -07:00
parent 32dfd4b4fe
commit f20a096d8c

View File

@ -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"},