IOS: Move net/ip/top code to its own source files

This commit is contained in:
Lioncash 2017-02-15 13:56:02 -05:00
parent 245de3fa4f
commit 92e17d2eb8
9 changed files with 1051 additions and 991 deletions

View File

@ -152,6 +152,7 @@ set(SRCS ActionReplay.cpp
IOS/Network/Net.cpp IOS/Network/Net.cpp
IOS/Network/Socket.cpp IOS/Network/Socket.cpp
IOS/Network/SSL.cpp IOS/Network/SSL.cpp
IOS/Network/IP/Top.cpp
IOS/Network/KD/NetKDRequest.cpp IOS/Network/KD/NetKDRequest.cpp
IOS/Network/KD/NetKDTime.cpp IOS/Network/KD/NetKDTime.cpp
IOS/Network/KD/NWC24Config.cpp IOS/Network/KD/NWC24Config.cpp

View File

@ -184,6 +184,7 @@
<ClCompile Include="IOS\Network\Net.cpp" /> <ClCompile Include="IOS\Network\Net.cpp" />
<ClCompile Include="IOS\Network\Socket.cpp" /> <ClCompile Include="IOS\Network\Socket.cpp" />
<ClCompile Include="IOS\Network\SSL.cpp" /> <ClCompile Include="IOS\Network\SSL.cpp" />
<ClCompile Include="IOS\Network\IP\Top.cpp" />
<ClCompile Include="IOS\Network\KD\NetKDRequest.cpp" /> <ClCompile Include="IOS\Network\KD\NetKDRequest.cpp" />
<ClCompile Include="IOS\Network\KD\NetKDTime.cpp" /> <ClCompile Include="IOS\Network\KD\NetKDTime.cpp" />
<ClCompile Include="IOS\Network\KD\NWC24Config.cpp" /> <ClCompile Include="IOS\Network\KD\NWC24Config.cpp" />
@ -425,6 +426,7 @@
<ClInclude Include="IOS\Network\Net.h" /> <ClInclude Include="IOS\Network\Net.h" />
<ClInclude Include="IOS\Network\Socket.h" /> <ClInclude Include="IOS\Network\Socket.h" />
<ClInclude Include="IOS\Network\SSL.h" /> <ClInclude Include="IOS\Network\SSL.h" />
<ClInclude Include="IOS\Network\IP\Top.h" />
<ClInclude Include="IOS\Network\KD\NetKDRequest.h" /> <ClInclude Include="IOS\Network\KD\NetKDRequest.h" />
<ClInclude Include="IOS\Network\KD\NetKDTime.h" /> <ClInclude Include="IOS\Network\KD\NetKDTime.h" />
<ClInclude Include="IOS\Network\KD\NWC24Config.h" /> <ClInclude Include="IOS\Network\KD\NWC24Config.h" />

View File

@ -127,6 +127,9 @@
<Filter Include="IOS\Network"> <Filter Include="IOS\Network">
<UniqueIdentifier>{ab9cdd90-54d7-4f42-9248-d7903ce52cc8}</UniqueIdentifier> <UniqueIdentifier>{ab9cdd90-54d7-4f42-9248-d7903ce52cc8}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="IOS\Network\IP">
<UniqueIdentifier>{f20fc3ea-846b-4629-b86c-fd7860f73ee9}</UniqueIdentifier>
</Filter>
<Filter Include="IOS\Network\KD"> <Filter Include="IOS\Network\KD">
<UniqueIdentifier>{165768ae-ee50-4789-8051-5c5b7023fa4b}</UniqueIdentifier> <UniqueIdentifier>{165768ae-ee50-4789-8051-5c5b7023fa4b}</UniqueIdentifier>
</Filter> </Filter>
@ -770,6 +773,9 @@
<ClCompile Include="IOS\Network\SSL.cpp"> <ClCompile Include="IOS\Network\SSL.cpp">
<Filter>IOS\Network</Filter> <Filter>IOS\Network</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="IOS\Network\IP\Top.cpp">
<Filter>IOS\Network\IP</Filter>
</ClCompile>
<ClCompile Include="IOS\Network\KD\NetKDRequest.cpp"> <ClCompile Include="IOS\Network\KD\NetKDRequest.cpp">
<Filter>IOS\Network\KD</Filter> <Filter>IOS\Network\KD</Filter>
</ClCompile> </ClCompile>
@ -1368,6 +1374,9 @@
<ClInclude Include="IOS\Network\SSL.h"> <ClInclude Include="IOS\Network\SSL.h">
<Filter>IOS\Network</Filter> <Filter>IOS\Network</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="IOS\Network\IP\Top.h">
<Filter>IOS\Network\IP</Filter>
</ClInclude>
<ClInclude Include="IOS\Network\KD\NetKDRequest.h"> <ClInclude Include="IOS\Network\KD\NetKDRequest.h">
<Filter>IOS\Network\KD</Filter> <Filter>IOS\Network\KD</Filter>
</ClInclude> </ClInclude>

View File

@ -44,6 +44,7 @@
#include "Core/IOS/FS/FS.h" #include "Core/IOS/FS/FS.h"
#include "Core/IOS/FS/FileIO.h" #include "Core/IOS/FS/FileIO.h"
#include "Core/IOS/MIOS.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/NetKDRequest.h"
#include "Core/IOS/Network/KD/NetKDTime.h" #include "Core/IOS/Network/KD/NetKDTime.h"
#include "Core/IOS/Network/Net.h" #include "Core/IOS/Network/Net.h"

View File

@ -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 <algorithm>
#include <cstddef>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#ifndef _WIN32
#include <netdb.h>
#include <poll.h>
#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 <iphlpapi.h>
#include <ws2tcpip.h>
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
#elif defined(__linux__) or defined(__APPLE__)
#include <netinet/in.h>
#include <sys/socket.h>
typedef struct pollfd pollfd_t;
#else
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#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<NET_IOCTL>(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<size_t>(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<size_t>(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<MIB_IPFORWARDTABLE> forwardTable;
std::unique_ptr<MIB_IPADDRTABLE> ipTable;
forwardTableSize = 0;
if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER)
{
forwardTable =
std::unique_ptr<MIB_IPFORWARDTABLE>((PMIB_IPFORWARDTABLE) operator new(forwardTableSize));
}
ipTableSize = 0;
if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER)
{
ipTable = std::unique_ptr<MIB_IPADDRTABLE>((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<pollfd_t> 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

View File

@ -0,0 +1,79 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "Common/CommonTypes.h"
#include "Core/IOS/Device.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#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

View File

@ -4,58 +4,20 @@
#include "Core/IOS/Network/Net.h" #include "Core/IOS/Network/Net.h"
#include <algorithm>
#include <cinttypes>
#include <cstddef> #include <cstddef>
#include <cstdio>
#include <cstring> #include <cstring>
#include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#ifndef _WIN32
#include <netdb.h>
#include <poll.h>
#endif
#include "Common/Assert.h"
#include "Common/CommonFuncs.h" #include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/Network.h" #include "Common/Network.h"
#include "Common/StringUtil.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/IOS/Network/ICMP.h"
#include "Core/IOS/Network/MACUtils.h" #include "Core/IOS/Network/MACUtils.h"
#include "Core/IOS/Network/Socket.h" #include "Core/IOS/Network/Socket.h"
#ifdef _WIN32
#include <iphlpapi.h>
#include <ws2tcpip.h>
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
#elif defined(__linux__) or defined(__APPLE__)
#include <netinet/in.h>
#include <sys/socket.h>
typedef struct pollfd pollfd_t;
#else
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#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 IOS
{ {
namespace HLE namespace HLE
@ -213,901 +175,6 @@ IPCCommandResult NetWDCommand::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(return_value); 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<NET_IOCTL>(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<size_t>(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<size_t>(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<MIB_IPFORWARDTABLE> forwardTable;
std::unique_ptr<MIB_IPADDRTABLE> ipTable;
forwardTableSize = 0;
if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER)
{
forwardTable =
std::unique_ptr<MIB_IPFORWARDTABLE>((PMIB_IPFORWARDTABLE) operator new(forwardTableSize));
}
ipTableSize = 0;
if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER)
{
ipTable = std::unique_ptr<MIB_IPADDRTABLE>((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<pollfd_t> 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 Device
} // namespace HLE } // namespace HLE
} // namespace IOS } // namespace IOS

View File

@ -19,66 +19,9 @@ namespace IOS
{ {
namespace HLE 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. // TODO: split this up.
namespace Device 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) // Interface for reading and changing network configuration (probably some other stuff as well)
class NetNCDManage : public Device class NetNCDManage : public Device

View File

@ -53,7 +53,7 @@ typedef struct pollfd pollfd_t;
#include "Common/NonCopyable.h" #include "Common/NonCopyable.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/IOS/IPC.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" #include "Core/IOS/Network/SSL.h"
namespace IOS namespace IOS