diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index d2a9f50fc6..a2741b1005 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -148,9 +148,11 @@ set(SRCS ActionReplay.cpp IOS/FS/FS.cpp IOS/Network/Config.cpp IOS/Network/ICMPLin.cpp - IOS/Network/Socket.cpp + IOS/Network/MACUtils.cpp IOS/Network/Net.cpp + IOS/Network/Socket.cpp IOS/Network/SSL.cpp + IOS/Network/IP/Top.cpp IOS/Network/KD/NetKDRequest.cpp IOS/Network/KD/NetKDTime.cpp IOS/Network/KD/NWC24Config.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index d91d0c3ad7..6632ee88b1 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -180,9 +180,11 @@ - + + + @@ -420,9 +422,11 @@ - + + + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 5b84d0e0df..7dc92cbd83 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -127,6 +127,9 @@ {ab9cdd90-54d7-4f42-9248-d7903ce52cc8} + + {f20fc3ea-846b-4629-b86c-fd7860f73ee9} + {165768ae-ee50-4789-8051-5c5b7023fa4b} @@ -758,6 +761,9 @@ IOS + + IOS\Network + IOS\Network @@ -767,6 +773,9 @@ IOS\Network + + IOS\Network\IP + IOS\Network\KD @@ -1353,6 +1362,9 @@ IOS\Network + + IOS\Network + IOS\Network @@ -1362,6 +1374,9 @@ IOS\Network + + IOS\Network\IP + IOS\Network\KD diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index 2b5c7bebd2..0fe641006f 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -44,6 +44,7 @@ #include "Core/IOS/FS/FS.h" #include "Core/IOS/FS/FileIO.h" #include "Core/IOS/MIOS.h" +#include "Core/IOS/Network/IP/Top.h" #include "Core/IOS/Network/KD/NetKDRequest.h" #include "Core/IOS/Network/KD/NetKDTime.h" #include "Core/IOS/Network/Net.h" diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp new file mode 100644 index 0000000000..b1335a3899 --- /dev/null +++ b/Source/Core/Core/IOS/Network/IP/Top.cpp @@ -0,0 +1,958 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/IOS/Network/IP/Top.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#endif + +#include "Common/Assert.h" +#include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" +#include "Common/Network.h" +#include "Common/StringUtil.h" + +#include "Core/Core.h" +#include "Core/HW/Memmap.h" +#include "Core/IOS/Network/ICMP.h" +#include "Core/IOS/Network/MACUtils.h" +#include "Core/IOS/Network/Socket.h" + +#ifdef _WIN32 +#include +#include + +#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) + +#elif defined(__linux__) or defined(__APPLE__) +#include +#include + +typedef struct pollfd pollfd_t; +#else +#include +#include +#include +#include +#endif + +// WSAPoll doesn't support POLLPRI and POLLWRBAND flags +#ifdef _WIN32 +#define UNSUPPORTED_WSAPOLL POLLPRI | POLLWRBAND +#else +#define UNSUPPORTED_WSAPOLL 0 +#endif + +namespace IOS +{ +namespace HLE +{ +namespace Device +{ +NetIPTop::NetIPTop(u32 device_id, const std::string& device_name) : Device(device_id, device_name) +{ +#ifdef _WIN32 + int ret = WSAStartup(MAKEWORD(2, 2), &InitData); + INFO_LOG(IOS_NET, "WSAStartup: %d", ret); +#endif +} + +NetIPTop::~NetIPTop() +{ +#ifdef _WIN32 + WSACleanup(); +#endif +} + +static int inet_pton(const char* src, unsigned char* dst) +{ + int saw_digit, octets; + char ch; + unsigned char tmp[4], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') + { + if (ch >= '0' && ch <= '9') + { + unsigned int newt = (*tp * 10) + (ch - '0'); + + if (newt > 255) + return 0; + *tp = newt; + if (!saw_digit) + { + if (++octets > 4) + return 0; + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return 0; + *++tp = 0; + saw_digit = 0; + } + else + { + return 0; + } + } + if (octets < 4) + return 0; + memcpy(dst, tmp, 4); + return 1; +} + +// Maps SOCKOPT level from native to Wii +static unsigned int opt_level_mapping[][2] = {{SOL_SOCKET, 0xFFFF}}; + +// Maps SOCKOPT optname from native to Wii +static unsigned int opt_name_mapping[][2] = { + {SO_REUSEADDR, 0x4}, {SO_SNDBUF, 0x1001}, {SO_RCVBUF, 0x1002}, {SO_ERROR, 0x1009}}; + +IPCCommandResult NetIPTop::IOCtl(const IOCtlRequest& request) +{ + if (Core::g_want_determinism) + { + return GetDefaultReply(IPC_EACCES); + } + + s32 return_value = 0; + switch (request.request) + { + case IOCTL_SO_STARTUP: + { + request.Log(GetDeviceName(), LogTypes::IOS_WC24); + break; + } + case IOCTL_SO_SOCKET: + { + u32 af = Memory::Read_U32(request.buffer_in); + u32 type = Memory::Read_U32(request.buffer_in + 4); + u32 prot = Memory::Read_U32(request.buffer_in + 8); + + WiiSockMan& sm = WiiSockMan::GetInstance(); + return_value = sm.NewSocket(af, type, prot); + INFO_LOG(IOS_NET, "IOCTL_SO_SOCKET " + "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + return_value, af, type, prot, request.buffer_in, request.buffer_in_size, + request.buffer_out, request.buffer_out_size); + break; + } + case IOCTL_SO_ICMPSOCKET: + { + u32 pf = Memory::Read_U32(request.buffer_in); + + WiiSockMan& sm = WiiSockMan::GetInstance(); + return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP); + INFO_LOG(IOS_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, return_value); + break; + } + case IOCTL_SO_CLOSE: + case IOCTL_SO_ICMPCLOSE: + { + u32 fd = Memory::Read_U32(request.buffer_in); + WiiSockMan& sm = WiiSockMan::GetInstance(); + return_value = sm.DeleteSocket(fd); + INFO_LOG(IOS_NET, "%s(%x) %x", + request.request == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", fd, + return_value); + break; + } + case IOCTL_SO_ACCEPT: + case IOCTL_SO_BIND: + case IOCTL_SO_CONNECT: + case IOCTL_SO_FCNTL: + { + u32 fd = Memory::Read_U32(request.buffer_in); + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(fd, request, static_cast(request.request)); + return GetNoReply(); + } + ///////////////////////////////////////////////////////////// + // TODO: Tidy all below // + ///////////////////////////////////////////////////////////// + case IOCTL_SO_SHUTDOWN: + { + request.Log(GetDeviceName(), LogTypes::IOS_WC24); + + u32 fd = Memory::Read_U32(request.buffer_in); + u32 how = Memory::Read_U32(request.buffer_in + 4); + int ret = shutdown(fd, how); + return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false); + break; + } + case IOCTL_SO_LISTEN: + { + u32 fd = Memory::Read_U32(request.buffer_in); + u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04); + u32 ret = listen(fd, BACKLOG); + return_value = WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false); + request.Log(GetDeviceName(), LogTypes::IOS_WC24); + break; + } + case IOCTL_SO_GETSOCKOPT: + { + u32 fd = Memory::Read_U32(request.buffer_out); + u32 level = Memory::Read_U32(request.buffer_out + 4); + u32 optname = Memory::Read_U32(request.buffer_out + 8); + + request.Log(GetDeviceName(), LogTypes::IOS_WC24); + + // Do the level/optname translation + int nat_level = -1, nat_optname = -1; + + for (auto& map : opt_level_mapping) + if (level == map[1]) + nat_level = map[0]; + + for (auto& map : opt_name_mapping) + if (optname == map[1]) + nat_optname = map[0]; + + u8 optval[20]; + u32 optlen = 4; + + int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen); + return_value = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false); + + Memory::Write_U32(optlen, request.buffer_out + 0xC); + Memory::CopyToEmu(request.buffer_out + 0x10, optval, optlen); + + if (optname == SO_ERROR) + { + s32 last_error = WiiSockMan::GetInstance().GetLastNetError(); + + Memory::Write_U32(sizeof(s32), request.buffer_out + 0xC); + Memory::Write_U32(last_error, request.buffer_out + 0x10); + } + break; + } + + case IOCTL_SO_SETSOCKOPT: + { + u32 fd = Memory::Read_U32(request.buffer_in); + u32 level = Memory::Read_U32(request.buffer_in + 4); + u32 optname = Memory::Read_U32(request.buffer_in + 8); + u32 optlen = Memory::Read_U32(request.buffer_in + 0xc); + u8 optval[20]; + optlen = std::min(optlen, (u32)sizeof(optval)); + Memory::CopyFromEmu(optval, request.buffer_in + 0x10, optlen); + + INFO_LOG(IOS_NET, "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)" + "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " + "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx", + fd, level, optname, optlen, request.buffer_in, request.buffer_in_size, + request.buffer_out, request.buffer_out_size, optval[0], optval[1], optval[2], + optval[3], optval[4], optval[5], optval[6], optval[7], optval[8], optval[9], + optval[10], optval[11], optval[12], optval[13], optval[14], optval[15], optval[16], + optval[17], optval[18], optval[19]); + + // TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is , + // 0x2001 is most likely tcpnodelay + if (level == 6 && (optname == 0x2005 || optname == 0x2001)) + { + return_value = 0; + break; + } + + // Do the level/optname translation + int nat_level = -1, nat_optname = -1; + + for (auto& map : opt_level_mapping) + if (level == map[1]) + nat_level = map[0]; + + for (auto& map : opt_name_mapping) + if (optname == map[1]) + nat_optname = map[0]; + + if (nat_level == -1 || nat_optname == -1) + { + INFO_LOG(IOS_NET, "SO_SETSOCKOPT: unknown level %d or optname %d", level, optname); + + // Default to the given level/optname. They match on Windows... + nat_level = level; + nat_optname = optname; + } + + int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen); + return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false); + break; + } + case IOCTL_SO_GETSOCKNAME: + { + u32 fd = Memory::Read_U32(request.buffer_in); + + request.Log(GetDeviceName(), LogTypes::IOS_WC24); + + sockaddr sa; + socklen_t sa_len; + sa_len = sizeof(sa); + int ret = getsockname(fd, &sa, &sa_len); + + if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) + WARN_LOG(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating"); + + if (request.buffer_out_size > 0) + Memory::Write_U8(request.buffer_out_size, request.buffer_out); + if (request.buffer_out_size > 1) + Memory::Write_U8(sa.sa_family & 0xFF, request.buffer_out + 1); + if (request.buffer_out_size > 2) + Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data, + std::min(sizeof(sa.sa_data), request.buffer_out_size - 2)); + return_value = ret; + break; + } + case IOCTL_SO_GETPEERNAME: + { + u32 fd = Memory::Read_U32(request.buffer_in); + + sockaddr sa; + socklen_t sa_len; + sa_len = sizeof(sa); + + int ret = getpeername(fd, &sa, &sa_len); + + if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) + WARN_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating"); + + if (request.buffer_out_size > 0) + Memory::Write_U8(request.buffer_out_size, request.buffer_out); + if (request.buffer_out_size > 1) + Memory::Write_U8(AF_INET, request.buffer_out + 1); + if (request.buffer_out_size > 2) + Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data, + std::min(sizeof(sa.sa_data), request.buffer_out_size - 2)); + + INFO_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME(%x)", fd); + + return_value = ret; + break; + } + + case IOCTL_SO_GETHOSTID: + { + request.Log(GetDeviceName(), LogTypes::IOS_WC24); + +#ifdef _WIN32 + DWORD forwardTableSize, ipTableSize, result; + DWORD ifIndex = -1; + std::unique_ptr forwardTable; + std::unique_ptr ipTable; + + forwardTableSize = 0; + if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) + { + forwardTable = + std::unique_ptr((PMIB_IPFORWARDTABLE) operator new(forwardTableSize)); + } + + ipTableSize = 0; + if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) + { + ipTable = std::unique_ptr((PMIB_IPADDRTABLE) operator new(ipTableSize)); + } + + // find the interface IP used for the default route and use that + result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); + while (result == NO_ERROR || + result == ERROR_MORE_DATA) // can return ERROR_MORE_DATA on XP even after the first call + { + for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i) + { + if (forwardTable->table[i].dwForwardDest == 0) + { + ifIndex = forwardTable->table[i].dwForwardIfIndex; + break; + } + } + + if (result == NO_ERROR || ifIndex != -1) + break; + + result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); + } + + if (ifIndex != -1 && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR) + { + for (DWORD i = 0; i < ipTable->dwNumEntries; ++i) + { + if (ipTable->table[i].dwIndex == ifIndex) + { + return_value = Common::swap32(ipTable->table[i].dwAddr); + break; + } + } + } +#endif + + // default placeholder, in case of failure + if (return_value == 0) + return_value = 192 << 24 | 168 << 16 | 1 << 8 | 150; + break; + } + + case IOCTL_SO_INETATON: + { + std::string hostname = Memory::GetString(request.buffer_in); + struct hostent* remoteHost = gethostbyname(hostname.c_str()); + + if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr || + remoteHost->h_addr_list[0] == nullptr) + { + INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = -1 " + "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None", + hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, + request.buffer_out_size); + return_value = 0; + } + else + { + Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), request.buffer_out); + INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = 0 " + "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X", + hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, + request.buffer_out_size, Common::swap32(*(u32*)remoteHost->h_addr_list[0])); + return_value = 1; + } + break; + } + + case IOCTL_SO_INETPTON: + { + std::string address = Memory::GetString(request.buffer_in); + INFO_LOG(IOS_NET, "IOCTL_SO_INETPTON " + "(Translating: %s)", + address.c_str()); + return_value = inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4)); + break; + } + + case IOCTL_SO_INETNTOP: + { + // u32 af = Memory::Read_U32(BufferIn); + // u32 validAddress = Memory::Read_U32(request.buffer_in + 4); + // u32 src = Memory::Read_U32(request.buffer_in + 8); + char ip_s[16]; + sprintf(ip_s, "%i.%i.%i.%i", Memory::Read_U8(request.buffer_in + 8), + Memory::Read_U8(request.buffer_in + 8 + 1), Memory::Read_U8(request.buffer_in + 8 + 2), + Memory::Read_U8(request.buffer_in + 8 + 3)); + INFO_LOG(IOS_NET, "IOCTL_SO_INETNTOP %s", ip_s); + Memory::CopyToEmu(request.buffer_out, (u8*)ip_s, strlen(ip_s)); + break; + } + + case IOCTL_SO_POLL: + { + // Map Wii/native poll events types + struct + { + int native; + int wii; + } mapping[] = { + {POLLRDNORM, 0x0001}, {POLLRDBAND, 0x0002}, {POLLPRI, 0x0004}, {POLLWRNORM, 0x0008}, + {POLLWRBAND, 0x0010}, {POLLERR, 0x0020}, {POLLHUP, 0x0040}, {POLLNVAL, 0x0080}, + }; + + u32 unknown = Memory::Read_U32(request.buffer_in); + u32 timeout = Memory::Read_U32(request.buffer_in + 4); + + int nfds = request.buffer_out_size / 0xc; + if (nfds == 0) + ERROR_LOG(IOS_NET, "Hidden POLL"); + + std::vector ufds(nfds); + + for (int i = 0; i < nfds; ++i) + { + ufds[i].fd = Memory::Read_U32(request.buffer_out + 0xc * i); // fd + int events = Memory::Read_U32(request.buffer_out + 0xc * i + 4); // events + ufds[i].revents = Memory::Read_U32(request.buffer_out + 0xc * i + 8); // revents + + // Translate Wii to native events + int unhandled_events = events; + ufds[i].events = 0; + for (auto& map : mapping) + { + if (events & map.wii) + ufds[i].events |= map.native; + unhandled_events &= ~map.wii; + } + DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL(%d) " + "Sock: %08x, Unknown: %08x, Events: %08x, " + "NativeEvents: %08x", + i, ufds[i].fd, unknown, events, ufds[i].events); + + // Do not pass return-only events to the native poll + ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL); + + if (unhandled_events) + ERROR_LOG(IOS_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); + } + + int ret = poll(ufds.data(), nfds, timeout); + ret = WiiSockMan::GetNetErrorCode(ret, "SO_POLL", false); + + for (int i = 0; i < nfds; ++i) + { + // Translate native to Wii events + int revents = 0; + for (auto& map : mapping) + { + if (ufds[i].revents & map.native) + revents |= map.wii; + } + + // No need to change fd or events as they are input only. + // Memory::Write_U32(ufds[i].fd, request.buffer_out + 0xc*i); //fd + // Memory::Write_U32(events, request.buffer_out + 0xc*i + 4); //events + Memory::Write_U32(revents, request.buffer_out + 0xc * i + 8); // revents + + DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL socket %d wevents %08X events %08X revents %08X", i, + revents, ufds[i].events, ufds[i].revents); + } + + return_value = ret; + break; + } + + case IOCTL_SO_GETHOSTBYNAME: + { + if (request.buffer_out_size != 0x460) + { + ERROR_LOG(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME"); + return_value = -1; + break; + } + + std::string hostname = Memory::GetString(request.buffer_in); + hostent* remoteHost = gethostbyname(hostname.c_str()); + + INFO_LOG(IOS_NET, "IOCTL_SO_GETHOSTBYNAME " + "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, + request.buffer_out_size); + + if (remoteHost) + { + for (int i = 0; remoteHost->h_aliases[i]; ++i) + { + DEBUG_LOG(IOS_NET, "alias%i:%s", i, remoteHost->h_aliases[i]); + } + + for (int i = 0; remoteHost->h_addr_list[i]; ++i) + { + u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i])); + std::string ip_s = StringFromFormat("%i.%i.%i.%i", ip >> 24, (ip >> 16) & 0xff, + (ip >> 8) & 0xff, ip & 0xff); + DEBUG_LOG(IOS_NET, "addr%i:%s", i, ip_s.c_str()); + } + + // Host name; located immediately after struct + static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10; + static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110; + // Limit host name length to avoid buffer overflow. + u32 name_length = (u32)strlen(remoteHost->h_name) + 1; + if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE)) + { + ERROR_LOG(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME"); + return_value = -1; + break; + } + Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name, + name_length); + Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, request.buffer_out); + + // IP address list; located at offset 0x110. + u32 num_ip_addr = 0; + while (remoteHost->h_addr_list[num_ip_addr]) + num_ip_addr++; + // Limit number of IP addresses to avoid buffer overflow. + // (0x460 - 0x340) / sizeof(pointer) == 72 + static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71; + num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES); + for (u32 i = 0; i < num_ip_addr; ++i) + { + u32 addr = request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4; + Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr); + } + + // List of pointers to IP addresses; located at offset 0x340. + // This must be exact: PPC code to convert the struct hardcodes + // this offset. + static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340; + Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET, + request.buffer_out + 12); + for (u32 i = 0; i < num_ip_addr; ++i) + { + u32 addr = request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4; + Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr); + } + Memory::Write_U32(0, request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4); + + // Aliases - empty. (Hardware doesn't return anything.) + Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4, + request.buffer_out + 4); + + // Returned struct must be ipv4. + _assert_msg_(IOS_NET, + remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), + "returned host info is not IPv4"); + Memory::Write_U16(AF_INET, request.buffer_out + 8); + Memory::Write_U16(sizeof(u32), request.buffer_out + 10); + + return_value = 0; + } + else + { + return_value = -1; + } + + break; + } + + case IOCTL_SO_ICMPCANCEL: + ERROR_LOG(IOS_NET, "IOCTL_SO_ICMPCANCEL"); + + default: + request.DumpUnknown(GetDeviceName(), LogTypes::IOS_NET); + } + + return GetDefaultReply(return_value); +} + +IPCCommandResult NetIPTop::IOCtlV(const IOCtlVRequest& request) +{ + s32 return_value = 0; + + u32 param = 0, param2 = 0, param3, param4, param5 = 0; + switch (request.request) + { + case IOCTLV_SO_GETINTERFACEOPT: + { + param = Memory::Read_U32(request.in_vectors[0].address); + param2 = Memory::Read_U32(request.in_vectors[0].address + 4); + param3 = Memory::Read_U32(request.io_vectors[0].address); + param4 = Memory::Read_U32(request.io_vectors[1].address); + if (request.io_vectors[0].size >= 8) + { + param5 = Memory::Read_U32(request.io_vectors[0].address + 4); + } + + INFO_LOG(IOS_NET, "IOCTLV_SO_GETINTERFACEOPT(%08X, %08X, %X, %X, %X) " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i) ", + param, param2, param3, param4, param5, request.in_vectors[0].address, + request.in_vectors[0].size, + request.in_vectors.size() > 1 ? request.in_vectors[1].address : 0, + request.in_vectors.size() > 1 ? request.in_vectors[1].size : 0); + + switch (param2) + { + case 0xb003: // dns server table + { + u32 address = 0; +#ifdef _WIN32 + if (!Core::g_want_determinism) + { + PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + for (i = 0; i < 5; ++i) + { + RetVal = GetAdaptersAddresses(AF_INET, 0, nullptr, AdapterAddresses, &OutBufferLength); + + if (RetVal != ERROR_BUFFER_OVERFLOW) + { + break; + } + + if (AdapterAddresses != nullptr) + { + FREE(AdapterAddresses); + } + + AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength); + if (AdapterAddresses == nullptr) + { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) + { + unsigned long dwBestIfIndex = 0; + IPAddr dwDestAddr = (IPAddr)0x08080808; + // If successful, output some information from the data we received + PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; + if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR) + { + while (AdapterList) + { + if (AdapterList->IfIndex == dwBestIfIndex && AdapterList->FirstDnsServerAddress && + AdapterList->OperStatus == IfOperStatusUp) + { + INFO_LOG(IOS_NET, "Name of valid interface: %S", AdapterList->FriendlyName); + INFO_LOG(IOS_NET, "DNS: %u.%u.%u.%u", + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2], + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3], + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4], + (unsigned char) + AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]); + address = Common::swap32( + *(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2])); + break; + } + AdapterList = AdapterList->Next; + } + } + } + if (AdapterAddresses != nullptr) + { + FREE(AdapterAddresses); + } + } +#endif + if (address == 0) + address = 0x08080808; + + Memory::Write_U32(address, request.io_vectors[0].address); + Memory::Write_U32(0x08080404, request.io_vectors[0].address + 4); + break; + } + case 0x1003: // error + Memory::Write_U32(0, request.io_vectors[0].address); + break; + + case 0x1004: // mac address + u8 address[Common::MAC_ADDRESS_SIZE]; + IOS::Net::GetMACAddress(address); + Memory::CopyToEmu(request.io_vectors[0].address, address, sizeof(address)); + break; + + case 0x1005: // link state + Memory::Write_U32(1, request.io_vectors[0].address); + break; + + case 0x4002: // ip addr number + Memory::Write_U32(1, request.io_vectors[0].address); + break; + + case 0x4003: // ip addr table + Memory::Write_U32(0xC, request.io_vectors[1].address); + Memory::Write_U32(10 << 24 | 1 << 8 | 30, request.io_vectors[0].address); + Memory::Write_U32(255 << 24 | 255 << 16 | 255 << 8 | 0, request.io_vectors[0].address + 4); + Memory::Write_U32(10 << 24 | 0 << 16 | 255 << 8 | 255, request.io_vectors[0].address + 8); + break; + + default: + ERROR_LOG(IOS_NET, "Unknown param2: %08X", param2); + break; + } + break; + } + case IOCTLV_SO_SENDTO: + { + u32 fd = Memory::Read_U32(request.in_vectors[1].address); + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(fd, request, IOCTLV_SO_SENDTO); + return GetNoReply(); + break; + } + case IOCTLV_SO_RECVFROM: + { + u32 fd = Memory::Read_U32(request.in_vectors[0].address); + WiiSockMan& sm = WiiSockMan::GetInstance(); + sm.DoSock(fd, request, IOCTLV_SO_RECVFROM); + return GetNoReply(); + break; + } + case IOCTLV_SO_GETADDRINFO: + { + addrinfo hints; + + if (request.in_vectors.size() > 2 && request.in_vectors[2].size) + { + hints.ai_flags = Memory::Read_U32(request.in_vectors[2].address); + hints.ai_family = Memory::Read_U32(request.in_vectors[2].address + 0x4); + hints.ai_socktype = Memory::Read_U32(request.in_vectors[2].address + 0x8); + hints.ai_protocol = Memory::Read_U32(request.in_vectors[2].address + 0xC); + hints.ai_addrlen = Memory::Read_U32(request.in_vectors[2].address + 0x10); + hints.ai_canonname = nullptr; + hints.ai_addr = nullptr; + hints.ai_next = nullptr; + } + + // getaddrinfo allows a null pointer for the nodeName or serviceName strings + // So we have to do a bit of juggling here. + std::string nodeNameStr; + const char* pNodeName = nullptr; + if (request.in_vectors.size() > 0 && request.in_vectors[0].size > 0) + { + nodeNameStr = Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size); + pNodeName = nodeNameStr.c_str(); + } + + std::string serviceNameStr; + const char* pServiceName = nullptr; + if (request.in_vectors.size() > 1 && request.in_vectors[1].size > 0) + { + serviceNameStr = Memory::GetString(request.in_vectors[1].address, request.in_vectors[1].size); + pServiceName = serviceNameStr.c_str(); + } + + addrinfo* result = nullptr; + int ret = getaddrinfo( + pNodeName, pServiceName, + (request.in_vectors.size() > 2 && request.in_vectors[2].size) ? &hints : nullptr, &result); + u32 addr = request.io_vectors[0].address; + u32 sockoffset = addr + 0x460; + if (ret == 0) + { + for (addrinfo* result_iter = result; result_iter != nullptr; + result_iter = result_iter->ai_next) + { + Memory::Write_U32(result_iter->ai_flags, addr); + Memory::Write_U32(result_iter->ai_family, addr + 0x04); + Memory::Write_U32(result_iter->ai_socktype, addr + 0x08); + Memory::Write_U32(result_iter->ai_protocol, addr + 0x0C); + Memory::Write_U32((u32)result_iter->ai_addrlen, addr + 0x10); + // what to do? where to put? the buffer of 0x834 doesn't allow space for this + Memory::Write_U32(/*result->ai_cannonname*/ 0, addr + 0x14); + + if (result_iter->ai_addr) + { + Memory::Write_U32(sockoffset, addr + 0x18); + Memory::Write_U16(((result_iter->ai_addr->sa_family & 0xFF) << 8) | + (result_iter->ai_addrlen & 0xFF), + sockoffset); + Memory::CopyToEmu(sockoffset + 0x2, result_iter->ai_addr->sa_data, + sizeof(result_iter->ai_addr->sa_data)); + sockoffset += 0x1C; + } + else + { + Memory::Write_U32(0, addr + 0x18); + } + + if (result_iter->ai_next) + { + Memory::Write_U32(addr + sizeof(addrinfo), addr + 0x1C); + } + else + { + Memory::Write_U32(0, addr + 0x1C); + } + + addr += sizeof(addrinfo); + } + + freeaddrinfo(result); + } + else + { + // Host not found + ret = -305; + } + + request.Dump(GetDeviceName(), LogTypes::IOS_NET, LogTypes::LINFO); + return_value = ret; + break; + } + case IOCTLV_SO_ICMPPING: + { + struct + { + u8 length; + u8 addr_family; + u16 icmp_id; + u32 ip; + } ip_info; + + u32 fd = Memory::Read_U32(request.in_vectors[0].address); + u32 num_ip = Memory::Read_U32(request.in_vectors[0].address + 4); + u64 timeout = Memory::Read_U64(request.in_vectors[0].address + 8); + + if (num_ip != 1) + { + INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip); + } + + ip_info.length = Memory::Read_U8(request.in_vectors[0].address + 16); + ip_info.addr_family = Memory::Read_U8(request.in_vectors[0].address + 17); + ip_info.icmp_id = Memory::Read_U16(request.in_vectors[0].address + 18); + ip_info.ip = Memory::Read_U32(request.in_vectors[0].address + 20); + + if (ip_info.length != 8 || ip_info.addr_family != AF_INET) + { + INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING strange IPInfo:\n" + "length %x addr_family %x", + ip_info.length, ip_info.addr_family); + } + + INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip); + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = Common::swap32(ip_info.ip); + memset(addr.sin_zero, 0, 8); + + u8 data[0x20]; + memset(data, 0, sizeof(data)); + s32 icmp_length = sizeof(data); + + if (request.in_vectors.size() > 1 && request.in_vectors[1].size == sizeof(data)) + Memory::CopyFromEmu(data, request.in_vectors[1].address, request.in_vectors[1].size); + else + { + // TODO sequence number is incremented either statically, by + // port, or by socket. Doesn't seem to matter, so we just leave + // it 0 + ((u16*)data)[0] = Common::swap16(ip_info.icmp_id); + icmp_length = 22; + } + + int ret = icmp_echo_req(fd, &addr, data, icmp_length); + if (ret == icmp_length) + { + ret = icmp_echo_rep(fd, &addr, (u32)timeout, icmp_length); + } + + // TODO proper error codes + return_value = 0; + break; + } + default: + request.DumpUnknown(GetDeviceName(), LogTypes::IOS_NET); + } + + return GetDefaultReply(return_value); +} + +void NetIPTop::Update() +{ + WiiSockMan::GetInstance().Update(); +} +} // namespace Device +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/Network/IP/Top.h b/Source/Core/Core/IOS/Network/IP/Top.h new file mode 100644 index 0000000000..43b48d1821 --- /dev/null +++ b/Source/Core/Core/IOS/Network/IP/Top.h @@ -0,0 +1,79 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "Common/CommonTypes.h" +#include "Core/IOS/Device.h" + +#ifdef _WIN32 +#include +#endif + +namespace IOS +{ +namespace HLE +{ +enum NET_IOCTL +{ + IOCTL_SO_ACCEPT = 1, + IOCTL_SO_BIND, + IOCTL_SO_CLOSE, + IOCTL_SO_CONNECT, + IOCTL_SO_FCNTL, + IOCTL_SO_GETPEERNAME, + IOCTL_SO_GETSOCKNAME, + IOCTL_SO_GETSOCKOPT, + IOCTL_SO_SETSOCKOPT, + IOCTL_SO_LISTEN, + IOCTL_SO_POLL, + IOCTLV_SO_RECVFROM, + IOCTLV_SO_SENDTO, + IOCTL_SO_SHUTDOWN, + IOCTL_SO_SOCKET, + IOCTL_SO_GETHOSTID, + IOCTL_SO_GETHOSTBYNAME, + IOCTL_SO_GETHOSTBYADDR, + IOCTLV_SO_GETNAMEINFO, + IOCTL_SO_UNK14, + IOCTL_SO_INETATON, + IOCTL_SO_INETPTON, + IOCTL_SO_INETNTOP, + IOCTLV_SO_GETADDRINFO, + IOCTL_SO_SOCKATMARK, + IOCTLV_SO_UNK1A, + IOCTLV_SO_UNK1B, + IOCTLV_SO_GETINTERFACEOPT, + IOCTLV_SO_SETINTERFACEOPT, + IOCTL_SO_SETINTERFACE, + IOCTL_SO_STARTUP, + IOCTL_SO_ICMPSOCKET = 0x30, + IOCTLV_SO_ICMPPING, + IOCTL_SO_ICMPCANCEL, + IOCTL_SO_ICMPCLOSE +}; + +namespace Device +{ +class NetIPTop : public Device +{ +public: + NetIPTop(u32 device_id, const std::string& device_name); + virtual ~NetIPTop(); + + IPCCommandResult IOCtl(const IOCtlRequest& request) override; + IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; + + void Update() override; + +private: +#ifdef _WIN32 + WSADATA InitData; +#endif +}; +} // namespace Device +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/Network/MACUtils.cpp b/Source/Core/Core/IOS/Network/MACUtils.cpp new file mode 100644 index 0000000000..fabc58ec74 --- /dev/null +++ b/Source/Core/Core/IOS/Network/MACUtils.cpp @@ -0,0 +1,50 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/IOS/Network/MACUtils.h" + +#include + +#include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" +#include "Common/Network.h" + +#include "Core/ConfigManager.h" +#include "Core/Core.h" + +namespace IOS +{ +namespace Net +{ +static void SaveMACAddress(const u8* mac) +{ + SConfig::GetInstance().m_WirelessMac = Common::MacAddressToString(mac); + SConfig::GetInstance().SaveSettings(); +} + +void GetMACAddress(u8* mac) +{ + // Parse MAC address from config, and generate a new one if it doesn't + // exist or can't be parsed. + std::string wireless_mac = SConfig::GetInstance().m_WirelessMac; + + if (Core::g_want_determinism) + wireless_mac = "12:34:56:78:9a:bc"; + + if (!Common::StringToMacAddress(wireless_mac, mac)) + { + Common::GenerateMacAddress(Common::MACConsumer::IOS, mac); + SaveMACAddress(mac); + if (!wireless_mac.empty()) + { + ERROR_LOG(IOS_NET, "The MAC provided (%s) is invalid. We have " + "generated another one for you.", + Common::MacAddressToString(mac).c_str()); + } + } + + INFO_LOG(IOS_NET, "Using MAC address: %s", Common::MacAddressToString(mac).c_str()); +} +} // namespace Net +} // namespace IOS diff --git a/Source/Core/Core/IOS/Network/MACUtils.h b/Source/Core/Core/IOS/Network/MACUtils.h new file mode 100644 index 0000000000..7cc055d6fb --- /dev/null +++ b/Source/Core/Core/IOS/Network/MACUtils.h @@ -0,0 +1,15 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/CommonTypes.h" + +namespace IOS +{ +namespace Net +{ +void GetMACAddress(u8* mac); +} // namespace Net +} // namespace IOS diff --git a/Source/Core/Core/IOS/Network/Net.cpp b/Source/Core/Core/IOS/Network/Net.cpp index f080079b12..392e00d5b7 100644 --- a/Source/Core/Core/IOS/Network/Net.cpp +++ b/Source/Core/Core/IOS/Network/Net.cpp @@ -4,93 +4,26 @@ #include "Core/IOS/Network/Net.h" -#include -#include #include -#include #include -#include #include -#include #include -#ifndef _WIN32 -#include -#include -#endif -#include "Common/Assert.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/Network.h" -#include "Common/StringUtil.h" -#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/Memmap.h" -#include "Core/IOS/Network/ICMP.h" +#include "Core/IOS/Network/MACUtils.h" #include "Core/IOS/Network/Socket.h" -#ifdef _WIN32 -#include -#include - -#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) -#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) - -#elif defined(__linux__) or defined(__APPLE__) -#include -#include - -typedef struct pollfd pollfd_t; -#else -#include -#include -#include -#include -#endif - -// WSAPoll doesn't support POLLPRI and POLLWRBAND flags -#ifdef _WIN32 -#define UNSUPPORTED_WSAPOLL POLLPRI | POLLWRBAND -#else -#define UNSUPPORTED_WSAPOLL 0 -#endif - namespace IOS { namespace HLE { namespace Device { -static void SaveMacAddress(u8* mac) -{ - SConfig::GetInstance().m_WirelessMac = Common::MacAddressToString(mac); - SConfig::GetInstance().SaveSettings(); -} - -static void GetMacAddress(u8* mac) -{ - // Parse MAC address from config, and generate a new one if it doesn't - // exist or can't be parsed. - std::string wireless_mac = SConfig::GetInstance().m_WirelessMac; - - if (Core::g_want_determinism) - wireless_mac = "12:34:56:78:9a:bc"; - - if (!Common::StringToMacAddress(wireless_mac, mac)) - { - Common::GenerateMacAddress(Common::MACConsumer::IOS, mac); - SaveMacAddress(mac); - if (!wireless_mac.empty()) - { - ERROR_LOG(IOS_NET, "The MAC provided (%s) is invalid. We have " - "generated another one for you.", - Common::MacAddressToString(mac).c_str()); - } - } - INFO_LOG(IOS_NET, "Using MAC address: %s", Common::MacAddressToString(mac).c_str()); -} - // ********************************************************************************** // Handle /dev/net/ncd/manage requests NetNCDManage::NetNCDManage(u32 device_id, const std::string& device_name) @@ -146,7 +79,7 @@ IPCCommandResult NetNCDManage::IOCtlV(const IOCtlVRequest& request) INFO_LOG(IOS_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETWIRELESSMACADDRESS"); u8 address[Common::MAC_ADDRESS_SIZE]; - GetMacAddress(address); + IOS::Net::GetMACAddress(address); Memory::CopyToEmu(request.io_vectors.at(1).address, address, sizeof(address)); break; @@ -215,7 +148,7 @@ IPCCommandResult NetWDCommand::IOCtlV(const IOCtlVRequest& request) info->ntr_allowed_channels = Common::swap16(0xfffe); u8 address[Common::MAC_ADDRESS_SIZE]; - GetMacAddress(address); + IOS::Net::GetMACAddress(address); memcpy(info->mac, address, sizeof(info->mac)); } break; @@ -242,901 +175,6 @@ IPCCommandResult NetWDCommand::IOCtlV(const IOCtlVRequest& request) return GetDefaultReply(return_value); } - -// ********************************************************************************** -// Handle /dev/net/ip/top requests -NetIPTop::NetIPTop(u32 device_id, const std::string& device_name) : Device(device_id, device_name) -{ -#ifdef _WIN32 - int ret = WSAStartup(MAKEWORD(2, 2), &InitData); - INFO_LOG(IOS_NET, "WSAStartup: %d", ret); -#endif -} - -NetIPTop::~NetIPTop() -{ -#ifdef _WIN32 - WSACleanup(); -#endif -} - -static int inet_pton(const char* src, unsigned char* dst) -{ - int saw_digit, octets; - char ch; - unsigned char tmp[4], *tp; - - saw_digit = 0; - octets = 0; - *(tp = tmp) = 0; - while ((ch = *src++) != '\0') - { - if (ch >= '0' && ch <= '9') - { - unsigned int newt = (*tp * 10) + (ch - '0'); - - if (newt > 255) - return 0; - *tp = newt; - if (!saw_digit) - { - if (++octets > 4) - return 0; - saw_digit = 1; - } - } - else if (ch == '.' && saw_digit) - { - if (octets == 4) - return 0; - *++tp = 0; - saw_digit = 0; - } - else - { - return 0; - } - } - if (octets < 4) - return 0; - memcpy(dst, tmp, 4); - return 1; -} - -// Maps SOCKOPT level from native to Wii -static unsigned int opt_level_mapping[][2] = {{SOL_SOCKET, 0xFFFF}}; - -// Maps SOCKOPT optname from native to Wii -static unsigned int opt_name_mapping[][2] = { - {SO_REUSEADDR, 0x4}, {SO_SNDBUF, 0x1001}, {SO_RCVBUF, 0x1002}, {SO_ERROR, 0x1009}}; - -IPCCommandResult NetIPTop::IOCtl(const IOCtlRequest& request) -{ - if (Core::g_want_determinism) - { - return GetDefaultReply(IPC_EACCES); - } - - s32 return_value = 0; - switch (request.request) - { - case IOCTL_SO_STARTUP: - { - request.Log(GetDeviceName(), LogTypes::IOS_WC24); - break; - } - case IOCTL_SO_SOCKET: - { - u32 af = Memory::Read_U32(request.buffer_in); - u32 type = Memory::Read_U32(request.buffer_in + 4); - u32 prot = Memory::Read_U32(request.buffer_in + 8); - - WiiSockMan& sm = WiiSockMan::GetInstance(); - return_value = sm.NewSocket(af, type, prot); - INFO_LOG(IOS_NET, "IOCTL_SO_SOCKET " - "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - return_value, af, type, prot, request.buffer_in, request.buffer_in_size, - request.buffer_out, request.buffer_out_size); - break; - } - case IOCTL_SO_ICMPSOCKET: - { - u32 pf = Memory::Read_U32(request.buffer_in); - - WiiSockMan& sm = WiiSockMan::GetInstance(); - return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP); - INFO_LOG(IOS_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, return_value); - break; - } - case IOCTL_SO_CLOSE: - case IOCTL_SO_ICMPCLOSE: - { - u32 fd = Memory::Read_U32(request.buffer_in); - WiiSockMan& sm = WiiSockMan::GetInstance(); - return_value = sm.DeleteSocket(fd); - INFO_LOG(IOS_NET, "%s(%x) %x", - request.request == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", fd, - return_value); - break; - } - case IOCTL_SO_ACCEPT: - case IOCTL_SO_BIND: - case IOCTL_SO_CONNECT: - case IOCTL_SO_FCNTL: - { - u32 fd = Memory::Read_U32(request.buffer_in); - WiiSockMan& sm = WiiSockMan::GetInstance(); - sm.DoSock(fd, request, static_cast(request.request)); - return GetNoReply(); - } - ///////////////////////////////////////////////////////////// - // TODO: Tidy all below // - ///////////////////////////////////////////////////////////// - case IOCTL_SO_SHUTDOWN: - { - request.Log(GetDeviceName(), LogTypes::IOS_WC24); - - u32 fd = Memory::Read_U32(request.buffer_in); - u32 how = Memory::Read_U32(request.buffer_in + 4); - int ret = shutdown(fd, how); - return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false); - break; - } - case IOCTL_SO_LISTEN: - { - u32 fd = Memory::Read_U32(request.buffer_in); - u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04); - u32 ret = listen(fd, BACKLOG); - return_value = WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false); - request.Log(GetDeviceName(), LogTypes::IOS_WC24); - break; - } - case IOCTL_SO_GETSOCKOPT: - { - u32 fd = Memory::Read_U32(request.buffer_out); - u32 level = Memory::Read_U32(request.buffer_out + 4); - u32 optname = Memory::Read_U32(request.buffer_out + 8); - - request.Log(GetDeviceName(), LogTypes::IOS_WC24); - - // Do the level/optname translation - int nat_level = -1, nat_optname = -1; - - for (auto& map : opt_level_mapping) - if (level == map[1]) - nat_level = map[0]; - - for (auto& map : opt_name_mapping) - if (optname == map[1]) - nat_optname = map[0]; - - u8 optval[20]; - u32 optlen = 4; - - int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen); - return_value = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false); - - Memory::Write_U32(optlen, request.buffer_out + 0xC); - Memory::CopyToEmu(request.buffer_out + 0x10, optval, optlen); - - if (optname == SO_ERROR) - { - s32 last_error = WiiSockMan::GetInstance().GetLastNetError(); - - Memory::Write_U32(sizeof(s32), request.buffer_out + 0xC); - Memory::Write_U32(last_error, request.buffer_out + 0x10); - } - break; - } - - case IOCTL_SO_SETSOCKOPT: - { - u32 fd = Memory::Read_U32(request.buffer_in); - u32 level = Memory::Read_U32(request.buffer_in + 4); - u32 optname = Memory::Read_U32(request.buffer_in + 8); - u32 optlen = Memory::Read_U32(request.buffer_in + 0xc); - u8 optval[20]; - optlen = std::min(optlen, (u32)sizeof(optval)); - Memory::CopyFromEmu(optval, request.buffer_in + 0x10, optlen); - - INFO_LOG(IOS_NET, "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)" - "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx", - fd, level, optname, optlen, request.buffer_in, request.buffer_in_size, - request.buffer_out, request.buffer_out_size, optval[0], optval[1], optval[2], - optval[3], optval[4], optval[5], optval[6], optval[7], optval[8], optval[9], - optval[10], optval[11], optval[12], optval[13], optval[14], optval[15], optval[16], - optval[17], optval[18], optval[19]); - - // TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is , - // 0x2001 is most likely tcpnodelay - if (level == 6 && (optname == 0x2005 || optname == 0x2001)) - { - return_value = 0; - break; - } - - // Do the level/optname translation - int nat_level = -1, nat_optname = -1; - - for (auto& map : opt_level_mapping) - if (level == map[1]) - nat_level = map[0]; - - for (auto& map : opt_name_mapping) - if (optname == map[1]) - nat_optname = map[0]; - - if (nat_level == -1 || nat_optname == -1) - { - INFO_LOG(IOS_NET, "SO_SETSOCKOPT: unknown level %d or optname %d", level, optname); - - // Default to the given level/optname. They match on Windows... - nat_level = level; - nat_optname = optname; - } - - int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen); - return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false); - break; - } - case IOCTL_SO_GETSOCKNAME: - { - u32 fd = Memory::Read_U32(request.buffer_in); - - request.Log(GetDeviceName(), LogTypes::IOS_WC24); - - sockaddr sa; - socklen_t sa_len; - sa_len = sizeof(sa); - int ret = getsockname(fd, &sa, &sa_len); - - if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) - WARN_LOG(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating"); - - if (request.buffer_out_size > 0) - Memory::Write_U8(request.buffer_out_size, request.buffer_out); - if (request.buffer_out_size > 1) - Memory::Write_U8(sa.sa_family & 0xFF, request.buffer_out + 1); - if (request.buffer_out_size > 2) - Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data, - std::min(sizeof(sa.sa_data), request.buffer_out_size - 2)); - return_value = ret; - break; - } - case IOCTL_SO_GETPEERNAME: - { - u32 fd = Memory::Read_U32(request.buffer_in); - - sockaddr sa; - socklen_t sa_len; - sa_len = sizeof(sa); - - int ret = getpeername(fd, &sa, &sa_len); - - if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) - WARN_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating"); - - if (request.buffer_out_size > 0) - Memory::Write_U8(request.buffer_out_size, request.buffer_out); - if (request.buffer_out_size > 1) - Memory::Write_U8(AF_INET, request.buffer_out + 1); - if (request.buffer_out_size > 2) - Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data, - std::min(sizeof(sa.sa_data), request.buffer_out_size - 2)); - - INFO_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME(%x)", fd); - - return_value = ret; - break; - } - - case IOCTL_SO_GETHOSTID: - { - request.Log(GetDeviceName(), LogTypes::IOS_WC24); - -#ifdef _WIN32 - DWORD forwardTableSize, ipTableSize, result; - DWORD ifIndex = -1; - std::unique_ptr forwardTable; - std::unique_ptr ipTable; - - forwardTableSize = 0; - if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) - { - forwardTable = - std::unique_ptr((PMIB_IPFORWARDTABLE) operator new(forwardTableSize)); - } - - ipTableSize = 0; - if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) - { - ipTable = std::unique_ptr((PMIB_IPADDRTABLE) operator new(ipTableSize)); - } - - // find the interface IP used for the default route and use that - result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); - while (result == NO_ERROR || - result == ERROR_MORE_DATA) // can return ERROR_MORE_DATA on XP even after the first call - { - for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i) - { - if (forwardTable->table[i].dwForwardDest == 0) - { - ifIndex = forwardTable->table[i].dwForwardIfIndex; - break; - } - } - - if (result == NO_ERROR || ifIndex != -1) - break; - - result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); - } - - if (ifIndex != -1 && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR) - { - for (DWORD i = 0; i < ipTable->dwNumEntries; ++i) - { - if (ipTable->table[i].dwIndex == ifIndex) - { - return_value = Common::swap32(ipTable->table[i].dwAddr); - break; - } - } - } -#endif - - // default placeholder, in case of failure - if (return_value == 0) - return_value = 192 << 24 | 168 << 16 | 1 << 8 | 150; - break; - } - - case IOCTL_SO_INETATON: - { - std::string hostname = Memory::GetString(request.buffer_in); - struct hostent* remoteHost = gethostbyname(hostname.c_str()); - - if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr || - remoteHost->h_addr_list[0] == nullptr) - { - INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = -1 " - "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None", - hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, - request.buffer_out_size); - return_value = 0; - } - else - { - Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), request.buffer_out); - INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = 0 " - "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X", - hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, - request.buffer_out_size, Common::swap32(*(u32*)remoteHost->h_addr_list[0])); - return_value = 1; - } - break; - } - - case IOCTL_SO_INETPTON: - { - std::string address = Memory::GetString(request.buffer_in); - INFO_LOG(IOS_NET, "IOCTL_SO_INETPTON " - "(Translating: %s)", - address.c_str()); - return_value = inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4)); - break; - } - - case IOCTL_SO_INETNTOP: - { - // u32 af = Memory::Read_U32(BufferIn); - // u32 validAddress = Memory::Read_U32(request.buffer_in + 4); - // u32 src = Memory::Read_U32(request.buffer_in + 8); - char ip_s[16]; - sprintf(ip_s, "%i.%i.%i.%i", Memory::Read_U8(request.buffer_in + 8), - Memory::Read_U8(request.buffer_in + 8 + 1), Memory::Read_U8(request.buffer_in + 8 + 2), - Memory::Read_U8(request.buffer_in + 8 + 3)); - INFO_LOG(IOS_NET, "IOCTL_SO_INETNTOP %s", ip_s); - Memory::CopyToEmu(request.buffer_out, (u8*)ip_s, strlen(ip_s)); - break; - } - - case IOCTL_SO_POLL: - { - // Map Wii/native poll events types - struct - { - int native; - int wii; - } mapping[] = { - {POLLRDNORM, 0x0001}, {POLLRDBAND, 0x0002}, {POLLPRI, 0x0004}, {POLLWRNORM, 0x0008}, - {POLLWRBAND, 0x0010}, {POLLERR, 0x0020}, {POLLHUP, 0x0040}, {POLLNVAL, 0x0080}, - }; - - u32 unknown = Memory::Read_U32(request.buffer_in); - u32 timeout = Memory::Read_U32(request.buffer_in + 4); - - int nfds = request.buffer_out_size / 0xc; - if (nfds == 0) - ERROR_LOG(IOS_NET, "Hidden POLL"); - - std::vector ufds(nfds); - - for (int i = 0; i < nfds; ++i) - { - ufds[i].fd = Memory::Read_U32(request.buffer_out + 0xc * i); // fd - int events = Memory::Read_U32(request.buffer_out + 0xc * i + 4); // events - ufds[i].revents = Memory::Read_U32(request.buffer_out + 0xc * i + 8); // revents - - // Translate Wii to native events - int unhandled_events = events; - ufds[i].events = 0; - for (auto& map : mapping) - { - if (events & map.wii) - ufds[i].events |= map.native; - unhandled_events &= ~map.wii; - } - DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL(%d) " - "Sock: %08x, Unknown: %08x, Events: %08x, " - "NativeEvents: %08x", - i, ufds[i].fd, unknown, events, ufds[i].events); - - // Do not pass return-only events to the native poll - ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL); - - if (unhandled_events) - ERROR_LOG(IOS_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); - } - - int ret = poll(ufds.data(), nfds, timeout); - ret = WiiSockMan::GetNetErrorCode(ret, "SO_POLL", false); - - for (int i = 0; i < nfds; ++i) - { - // Translate native to Wii events - int revents = 0; - for (auto& map : mapping) - { - if (ufds[i].revents & map.native) - revents |= map.wii; - } - - // No need to change fd or events as they are input only. - // Memory::Write_U32(ufds[i].fd, request.buffer_out + 0xc*i); //fd - // Memory::Write_U32(events, request.buffer_out + 0xc*i + 4); //events - Memory::Write_U32(revents, request.buffer_out + 0xc * i + 8); // revents - - DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL socket %d wevents %08X events %08X revents %08X", i, - revents, ufds[i].events, ufds[i].revents); - } - - return_value = ret; - break; - } - - case IOCTL_SO_GETHOSTBYNAME: - { - if (request.buffer_out_size != 0x460) - { - ERROR_LOG(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME"); - return_value = -1; - break; - } - - std::string hostname = Memory::GetString(request.buffer_in); - hostent* remoteHost = gethostbyname(hostname.c_str()); - - INFO_LOG(IOS_NET, "IOCTL_SO_GETHOSTBYNAME " - "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, - request.buffer_out_size); - - if (remoteHost) - { - for (int i = 0; remoteHost->h_aliases[i]; ++i) - { - DEBUG_LOG(IOS_NET, "alias%i:%s", i, remoteHost->h_aliases[i]); - } - - for (int i = 0; remoteHost->h_addr_list[i]; ++i) - { - u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i])); - std::string ip_s = StringFromFormat("%i.%i.%i.%i", ip >> 24, (ip >> 16) & 0xff, - (ip >> 8) & 0xff, ip & 0xff); - DEBUG_LOG(IOS_NET, "addr%i:%s", i, ip_s.c_str()); - } - - // Host name; located immediately after struct - static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10; - static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110; - // Limit host name length to avoid buffer overflow. - u32 name_length = (u32)strlen(remoteHost->h_name) + 1; - if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE)) - { - ERROR_LOG(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME"); - return_value = -1; - break; - } - Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name, - name_length); - Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, request.buffer_out); - - // IP address list; located at offset 0x110. - u32 num_ip_addr = 0; - while (remoteHost->h_addr_list[num_ip_addr]) - num_ip_addr++; - // Limit number of IP addresses to avoid buffer overflow. - // (0x460 - 0x340) / sizeof(pointer) == 72 - static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71; - num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES); - for (u32 i = 0; i < num_ip_addr; ++i) - { - u32 addr = request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4; - Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr); - } - - // List of pointers to IP addresses; located at offset 0x340. - // This must be exact: PPC code to convert the struct hardcodes - // this offset. - static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340; - Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET, - request.buffer_out + 12); - for (u32 i = 0; i < num_ip_addr; ++i) - { - u32 addr = request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4; - Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr); - } - Memory::Write_U32(0, request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4); - - // Aliases - empty. (Hardware doesn't return anything.) - Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4, - request.buffer_out + 4); - - // Returned struct must be ipv4. - _assert_msg_(IOS_NET, - remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), - "returned host info is not IPv4"); - Memory::Write_U16(AF_INET, request.buffer_out + 8); - Memory::Write_U16(sizeof(u32), request.buffer_out + 10); - - return_value = 0; - } - else - { - return_value = -1; - } - - break; - } - - case IOCTL_SO_ICMPCANCEL: - ERROR_LOG(IOS_NET, "IOCTL_SO_ICMPCANCEL"); - - default: - request.DumpUnknown(GetDeviceName(), LogTypes::IOS_NET); - } - - return GetDefaultReply(return_value); -} - -IPCCommandResult NetIPTop::IOCtlV(const IOCtlVRequest& request) -{ - s32 return_value = 0; - - u32 param = 0, param2 = 0, param3, param4, param5 = 0; - switch (request.request) - { - case IOCTLV_SO_GETINTERFACEOPT: - { - param = Memory::Read_U32(request.in_vectors[0].address); - param2 = Memory::Read_U32(request.in_vectors[0].address + 4); - param3 = Memory::Read_U32(request.io_vectors[0].address); - param4 = Memory::Read_U32(request.io_vectors[1].address); - if (request.io_vectors[0].size >= 8) - { - param5 = Memory::Read_U32(request.io_vectors[0].address + 4); - } - - INFO_LOG(IOS_NET, "IOCTLV_SO_GETINTERFACEOPT(%08X, %08X, %X, %X, %X) " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i) ", - param, param2, param3, param4, param5, request.in_vectors[0].address, - request.in_vectors[0].size, - request.in_vectors.size() > 1 ? request.in_vectors[1].address : 0, - request.in_vectors.size() > 1 ? request.in_vectors[1].size : 0); - - switch (param2) - { - case 0xb003: // dns server table - { - u32 address = 0; -#ifdef _WIN32 - if (!Core::g_want_determinism) - { - PIP_ADAPTER_ADDRESSES AdapterAddresses = nullptr; - ULONG OutBufferLength = 0; - ULONG RetVal = 0, i; - for (i = 0; i < 5; ++i) - { - RetVal = GetAdaptersAddresses(AF_INET, 0, nullptr, AdapterAddresses, &OutBufferLength); - - if (RetVal != ERROR_BUFFER_OVERFLOW) - { - break; - } - - if (AdapterAddresses != nullptr) - { - FREE(AdapterAddresses); - } - - AdapterAddresses = (PIP_ADAPTER_ADDRESSES)MALLOC(OutBufferLength); - if (AdapterAddresses == nullptr) - { - RetVal = GetLastError(); - break; - } - } - if (RetVal == NO_ERROR) - { - unsigned long dwBestIfIndex = 0; - IPAddr dwDestAddr = (IPAddr)0x08080808; - // If successful, output some information from the data we received - PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; - if (GetBestInterface(dwDestAddr, &dwBestIfIndex) == NO_ERROR) - { - while (AdapterList) - { - if (AdapterList->IfIndex == dwBestIfIndex && AdapterList->FirstDnsServerAddress && - AdapterList->OperStatus == IfOperStatusUp) - { - INFO_LOG(IOS_NET, "Name of valid interface: %S", AdapterList->FriendlyName); - INFO_LOG(IOS_NET, "DNS: %u.%u.%u.%u", - (unsigned char) - AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2], - (unsigned char) - AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[3], - (unsigned char) - AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[4], - (unsigned char) - AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[5]); - address = Common::swap32( - *(u32*)(&AdapterList->FirstDnsServerAddress->Address.lpSockaddr->sa_data[2])); - break; - } - AdapterList = AdapterList->Next; - } - } - } - if (AdapterAddresses != nullptr) - { - FREE(AdapterAddresses); - } - } -#endif - if (address == 0) - address = 0x08080808; - - Memory::Write_U32(address, request.io_vectors[0].address); - Memory::Write_U32(0x08080404, request.io_vectors[0].address + 4); - break; - } - case 0x1003: // error - Memory::Write_U32(0, request.io_vectors[0].address); - break; - - case 0x1004: // mac address - u8 address[Common::MAC_ADDRESS_SIZE]; - GetMacAddress(address); - Memory::CopyToEmu(request.io_vectors[0].address, address, sizeof(address)); - break; - - case 0x1005: // link state - Memory::Write_U32(1, request.io_vectors[0].address); - break; - - case 0x4002: // ip addr number - Memory::Write_U32(1, request.io_vectors[0].address); - break; - - case 0x4003: // ip addr table - Memory::Write_U32(0xC, request.io_vectors[1].address); - Memory::Write_U32(10 << 24 | 1 << 8 | 30, request.io_vectors[0].address); - Memory::Write_U32(255 << 24 | 255 << 16 | 255 << 8 | 0, request.io_vectors[0].address + 4); - Memory::Write_U32(10 << 24 | 0 << 16 | 255 << 8 | 255, request.io_vectors[0].address + 8); - break; - - default: - ERROR_LOG(IOS_NET, "Unknown param2: %08X", param2); - break; - } - break; - } - case IOCTLV_SO_SENDTO: - { - u32 fd = Memory::Read_U32(request.in_vectors[1].address); - WiiSockMan& sm = WiiSockMan::GetInstance(); - sm.DoSock(fd, request, IOCTLV_SO_SENDTO); - return GetNoReply(); - break; - } - case IOCTLV_SO_RECVFROM: - { - u32 fd = Memory::Read_U32(request.in_vectors[0].address); - WiiSockMan& sm = WiiSockMan::GetInstance(); - sm.DoSock(fd, request, IOCTLV_SO_RECVFROM); - return GetNoReply(); - break; - } - case IOCTLV_SO_GETADDRINFO: - { - addrinfo hints; - - if (request.in_vectors.size() > 2 && request.in_vectors[2].size) - { - hints.ai_flags = Memory::Read_U32(request.in_vectors[2].address); - hints.ai_family = Memory::Read_U32(request.in_vectors[2].address + 0x4); - hints.ai_socktype = Memory::Read_U32(request.in_vectors[2].address + 0x8); - hints.ai_protocol = Memory::Read_U32(request.in_vectors[2].address + 0xC); - hints.ai_addrlen = Memory::Read_U32(request.in_vectors[2].address + 0x10); - hints.ai_canonname = nullptr; - hints.ai_addr = nullptr; - hints.ai_next = nullptr; - } - - // getaddrinfo allows a null pointer for the nodeName or serviceName strings - // So we have to do a bit of juggling here. - std::string nodeNameStr; - const char* pNodeName = nullptr; - if (request.in_vectors.size() > 0 && request.in_vectors[0].size > 0) - { - nodeNameStr = Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size); - pNodeName = nodeNameStr.c_str(); - } - - std::string serviceNameStr; - const char* pServiceName = nullptr; - if (request.in_vectors.size() > 1 && request.in_vectors[1].size > 0) - { - serviceNameStr = Memory::GetString(request.in_vectors[1].address, request.in_vectors[1].size); - pServiceName = serviceNameStr.c_str(); - } - - addrinfo* result = nullptr; - int ret = getaddrinfo( - pNodeName, pServiceName, - (request.in_vectors.size() > 2 && request.in_vectors[2].size) ? &hints : nullptr, &result); - u32 addr = request.io_vectors[0].address; - u32 sockoffset = addr + 0x460; - if (ret == 0) - { - for (addrinfo* result_iter = result; result_iter != nullptr; - result_iter = result_iter->ai_next) - { - Memory::Write_U32(result_iter->ai_flags, addr); - Memory::Write_U32(result_iter->ai_family, addr + 0x04); - Memory::Write_U32(result_iter->ai_socktype, addr + 0x08); - Memory::Write_U32(result_iter->ai_protocol, addr + 0x0C); - Memory::Write_U32((u32)result_iter->ai_addrlen, addr + 0x10); - // what to do? where to put? the buffer of 0x834 doesn't allow space for this - Memory::Write_U32(/*result->ai_cannonname*/ 0, addr + 0x14); - - if (result_iter->ai_addr) - { - Memory::Write_U32(sockoffset, addr + 0x18); - Memory::Write_U16(((result_iter->ai_addr->sa_family & 0xFF) << 8) | - (result_iter->ai_addrlen & 0xFF), - sockoffset); - Memory::CopyToEmu(sockoffset + 0x2, result_iter->ai_addr->sa_data, - sizeof(result_iter->ai_addr->sa_data)); - sockoffset += 0x1C; - } - else - { - Memory::Write_U32(0, addr + 0x18); - } - - if (result_iter->ai_next) - { - Memory::Write_U32(addr + sizeof(addrinfo), addr + 0x1C); - } - else - { - Memory::Write_U32(0, addr + 0x1C); - } - - addr += sizeof(addrinfo); - } - - freeaddrinfo(result); - } - else - { - // Host not found - ret = -305; - } - - request.Dump(GetDeviceName(), LogTypes::IOS_NET, LogTypes::LINFO); - return_value = ret; - break; - } - case IOCTLV_SO_ICMPPING: - { - struct - { - u8 length; - u8 addr_family; - u16 icmp_id; - u32 ip; - } ip_info; - - u32 fd = Memory::Read_U32(request.in_vectors[0].address); - u32 num_ip = Memory::Read_U32(request.in_vectors[0].address + 4); - u64 timeout = Memory::Read_U64(request.in_vectors[0].address + 8); - - if (num_ip != 1) - { - INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip); - } - - ip_info.length = Memory::Read_U8(request.in_vectors[0].address + 16); - ip_info.addr_family = Memory::Read_U8(request.in_vectors[0].address + 17); - ip_info.icmp_id = Memory::Read_U16(request.in_vectors[0].address + 18); - ip_info.ip = Memory::Read_U32(request.in_vectors[0].address + 20); - - if (ip_info.length != 8 || ip_info.addr_family != AF_INET) - { - INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING strange IPInfo:\n" - "length %x addr_family %x", - ip_info.length, ip_info.addr_family); - } - - INFO_LOG(IOS_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip); - - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = Common::swap32(ip_info.ip); - memset(addr.sin_zero, 0, 8); - - u8 data[0x20]; - memset(data, 0, sizeof(data)); - s32 icmp_length = sizeof(data); - - if (request.in_vectors.size() > 1 && request.in_vectors[1].size == sizeof(data)) - Memory::CopyFromEmu(data, request.in_vectors[1].address, request.in_vectors[1].size); - else - { - // TODO sequence number is incremented either statically, by - // port, or by socket. Doesn't seem to matter, so we just leave - // it 0 - ((u16*)data)[0] = Common::swap16(ip_info.icmp_id); - icmp_length = 22; - } - - int ret = icmp_echo_req(fd, &addr, data, icmp_length); - if (ret == icmp_length) - { - ret = icmp_echo_rep(fd, &addr, (u32)timeout, icmp_length); - } - - // TODO proper error codes - return_value = 0; - break; - } - default: - request.DumpUnknown(GetDeviceName(), LogTypes::IOS_NET); - } - - return GetDefaultReply(return_value); -} - -void NetIPTop::Update() -{ - WiiSockMan::GetInstance().Update(); -} } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/Network/Net.h b/Source/Core/Core/IOS/Network/Net.h index 672ec6d3b5..754a82a3b3 100644 --- a/Source/Core/Core/IOS/Network/Net.h +++ b/Source/Core/Core/IOS/Network/Net.h @@ -19,66 +19,9 @@ namespace IOS { namespace HLE { -enum NET_IOCTL -{ - IOCTL_SO_ACCEPT = 1, - IOCTL_SO_BIND, - IOCTL_SO_CLOSE, - IOCTL_SO_CONNECT, - IOCTL_SO_FCNTL, - IOCTL_SO_GETPEERNAME, - IOCTL_SO_GETSOCKNAME, - IOCTL_SO_GETSOCKOPT, - IOCTL_SO_SETSOCKOPT, - IOCTL_SO_LISTEN, - IOCTL_SO_POLL, - IOCTLV_SO_RECVFROM, - IOCTLV_SO_SENDTO, - IOCTL_SO_SHUTDOWN, - IOCTL_SO_SOCKET, - IOCTL_SO_GETHOSTID, - IOCTL_SO_GETHOSTBYNAME, - IOCTL_SO_GETHOSTBYADDR, - IOCTLV_SO_GETNAMEINFO, - IOCTL_SO_UNK14, - IOCTL_SO_INETATON, - IOCTL_SO_INETPTON, - IOCTL_SO_INETNTOP, - IOCTLV_SO_GETADDRINFO, - IOCTL_SO_SOCKATMARK, - IOCTLV_SO_UNK1A, - IOCTLV_SO_UNK1B, - IOCTLV_SO_GETINTERFACEOPT, - IOCTLV_SO_SETINTERFACEOPT, - IOCTL_SO_SETINTERFACE, - IOCTL_SO_STARTUP, - IOCTL_SO_ICMPSOCKET = 0x30, - IOCTLV_SO_ICMPPING, - IOCTL_SO_ICMPCANCEL, - IOCTL_SO_ICMPCLOSE -}; - // TODO: split this up. namespace Device { -class NetIPTop : public Device -{ -public: - NetIPTop(u32 device_id, const std::string& device_name); - - virtual ~NetIPTop(); - - IPCCommandResult IOCtl(const IOCtlRequest& request) override; - IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; - - void Update() override; - -private: -#ifdef _WIN32 - WSADATA InitData; -#endif -}; - // ********************************************************************************** // Interface for reading and changing network configuration (probably some other stuff as well) class NetNCDManage : public Device diff --git a/Source/Core/Core/IOS/Network/Socket.h b/Source/Core/Core/IOS/Network/Socket.h index 774fc72521..e923e8d27e 100644 --- a/Source/Core/Core/IOS/Network/Socket.h +++ b/Source/Core/Core/IOS/Network/Socket.h @@ -53,7 +53,7 @@ typedef struct pollfd pollfd_t; #include "Common/NonCopyable.h" #include "Core/HW/Memmap.h" #include "Core/IOS/IPC.h" -#include "Core/IOS/Network/Net.h" +#include "Core/IOS/Network/IP/Top.h" #include "Core/IOS/Network/SSL.h" namespace IOS