From a0a09ed07a28f661e93e94ee1a1f352dcb153ac4 Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Fri, 1 Feb 2013 01:32:14 +1300 Subject: [PATCH] Started threading of network. Good results so far. --- .../Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp | 1858 +++++++++-------- .../Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h | 85 + 2 files changed, 1080 insertions(+), 863 deletions(-) diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp index fa4c98dac2..e534d28baf 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp @@ -55,6 +55,7 @@ it failed) #include "ICMP.h" #include "CommonPaths.h" #include "SettingsHandler.h" +#include "WII_IPC_HLE.h" #include "ec_wii.h" @@ -103,30 +104,30 @@ CWII_IPC_HLE_Device_net_kd_request::~CWII_IPC_HLE_Device_net_kd_request() { } -bool CWII_IPC_HLE_Device_net_kd_request::Open(u32 _CommandAddress, u32 _Mode) +bool CWII_IPC_HLE_Device_net_kd_request::Open(u32 CommandAddress, u32 _Mode) { INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress + 4); + Memory::Write_U32(GetDeviceID(), CommandAddress + 4); m_Active = true; return true; } -bool CWII_IPC_HLE_Device_net_kd_request::Close(u32 _CommandAddress, bool _bForce) +bool CWII_IPC_HLE_Device_net_kd_request::Close(u32 CommandAddress, bool _bForce) { INFO_LOG(WII_IPC_WC24, "NET_KD_REQ: Close"); if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); + Memory::Write_U32(0, CommandAddress + 4); m_Active = false; return true; } -bool CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 _CommandAddress) +bool CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 CommandAddress) { - u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); + u32 Parameter = Memory::Read_U32(CommandAddress + 0xC); + u32 BufferIn = Memory::Read_U32(CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(CommandAddress + 0x1C); u32 ReturnValue = 0; switch (Parameter) @@ -245,8 +246,8 @@ bool CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 _CommandAddress) break; } - // g_ReplyQueueLater.push(std::pair(_CommandAddress, GetDeviceName())); - Memory::Write_U32(ReturnValue, _CommandAddress + 4); + // g_ReplyQueueLater.push(std::pair(CommandAddress, GetDeviceName())); + Memory::Write_U32(ReturnValue, CommandAddress + 4); return true; } @@ -362,30 +363,30 @@ CWII_IPC_HLE_Device_net_ncd_manage::~CWII_IPC_HLE_Device_net_ncd_manage() { } -bool CWII_IPC_HLE_Device_net_ncd_manage::Open(u32 _CommandAddress, u32 _Mode) +bool CWII_IPC_HLE_Device_net_ncd_manage::Open(u32 CommandAddress, u32 _Mode) { INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); + Memory::Write_U32(GetDeviceID(), CommandAddress+4); m_Active = true; return true; } -bool CWII_IPC_HLE_Device_net_ncd_manage::Close(u32 _CommandAddress, bool _bForce) +bool CWII_IPC_HLE_Device_net_ncd_manage::Close(u32 CommandAddress, bool _bForce) { INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: Close"); if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); + Memory::Write_U32(0, CommandAddress + 4); m_Active = false; return true; } -bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress) +bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 CommandAddress) { u32 return_value = 0; u32 common_result = 0; u32 common_vector = 0; - SIOCtlVBuffer CommandBuffer(_CommandAddress); + SIOCtlVBuffer CommandBuffer(CommandAddress); switch (CommandBuffer.Parameter) { @@ -471,7 +472,7 @@ bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress) Memory::Write_U32(common_result, CommandBuffer.PayloadBuffer.at(common_vector).m_Address + 4); } - Memory::Write_U32(return_value, _CommandAddress + 4); + Memory::Write_U32(return_value, CommandAddress + 4); return true; } @@ -611,74 +612,673 @@ CWII_IPC_HLE_Device_net_ip_top::~CWII_IPC_HLE_Device_net_ip_top() #endif } -bool CWII_IPC_HLE_Device_net_ip_top::Open(u32 _CommandAddress, u32 _Mode) +bool CWII_IPC_HLE_Device_net_ip_top::Open(u32 CommandAddress, u32 _Mode) { INFO_LOG(WII_IPC_NET, "NET_IP_TOP: Open"); - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); + Memory::Write_U32(GetDeviceID(), CommandAddress+4); m_Active = true; return true; } -bool CWII_IPC_HLE_Device_net_ip_top::Close(u32 _CommandAddress, bool _bForce) +bool CWII_IPC_HLE_Device_net_ip_top::Close(u32 CommandAddress, bool _bForce) { INFO_LOG(WII_IPC_NET, "NET_IP_TOP: Close"); if (!_bForce) - Memory::Write_U32(0, _CommandAddress + 4); + Memory::Write_U32(0, CommandAddress + 4); m_Active = false; return true; } -bool CWII_IPC_HLE_Device_net_ip_top::IOCtl(u32 _CommandAddress) -{ - u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - u32 Command = Memory::Read_U32(_CommandAddress + 0x0C); +static int inet_pton(const char *src, unsigned char *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[4], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int newt = *tp * 10 + (pch - digits); + + 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); +} - u32 ReturnValue = ExecuteCommand(Command, BufferIn, BufferInSize, BufferOut, BufferOutSize); - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); +// 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 } +}; + + +bool CWII_IPC_HLE_Device_net_ip_top::IOCtl(u32 CommandAddress) +{ + u32 BufferIn = Memory::Read_U32(CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(CommandAddress + 0x1C); + u32 Command = Memory::Read_U32(CommandAddress + 0x0C); + s32 ReturnValue = 0; + + switch (Command) + { + case IOCTL_SO_CONNECT: + case IOCTL_SO_ACCEPT: + { + u32 s = Memory::Read_U32(BufferIn); + _tSocket * sock = NULL; + { + std::unique_lock lk(socketMapMutex); + if(socketMap.find(s) != socketMap.end()) + sock = socketMap[s]; + } + if(sock) + { + sock->addCommand(CommandAddress); + return false; + } + else + { + ReturnValue = -8; // EBADF + } + + ERROR_LOG(WII_IPC_NET, "Failed to find socket %X", s); + break; + } + + case IOCTL_SO_SOCKET: + { + u32 AF = Memory::Read_U32(BufferIn); + u32 TYPE = Memory::Read_U32(BufferIn + 0x04); + u32 PROT = Memory::Read_U32(BufferIn + 0x08); + u32 s = (u32)socket(AF, TYPE, PROT); + WARN_LOG(WII_IPC_NET, "IOCTL_SO_SOCKET " + "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + s, AF, TYPE, PROT, BufferIn, BufferInSize, BufferOut, BufferOutSize); + + ReturnValue = getNetErrorCode(s, "SO_SOCKET", false); + + if (ReturnValue > 0) + { + std::unique_lock lk(socketMapMutex); + _tSocket* sock = new _tSocket(); + socketMap[s] = sock; + sock->thread = new std::thread(&CWII_IPC_HLE_Device_net_ip_top::socketProcessor, this, s); + } + + break; + } + case IOCTL_SO_STARTUP: + { + WARN_LOG(WII_IPC_NET, "IOCTL_SO_STARTUP " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + break; + } + + case IOCTL_SO_SHUTDOWN: + { + WARN_LOG(WII_IPC_NET, "IOCTL_SO_SHUTDOWN " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + + u32 sock = Memory::Read_U32(BufferIn); + u32 how = Memory::Read_U32(BufferIn+4); + ReturnValue = shutdown(sock, how); + ReturnValue = getNetErrorCode(ReturnValue, "SO_SHUTDOWN", false); + break; + } + + case IOCTL_SO_CLOSE: + { + u32 s = Memory::Read_U32(BufferIn); + WARN_LOG(WII_IPC_NET, "IOCTL_SO_CLOSE (%08x)", s); + + #ifdef _WIN32 + ReturnValue = closesocket(s); + + ReturnValue = getNetErrorCode(ReturnValue, "IOCTL_SO_CLOSE", false); + #else + ReturnValue = close(s); + #endif + + _tSocket * sock = NULL; + { + std::unique_lock lk(socketMapMutex); + if(socketMap.find(s) != socketMap.end()) + sock = socketMap[s]; + if(sock) + { + //cascading failures hopefully + sock->StopAndJoin(); + delete sock; + socketMap.erase(s); + } + } + + + break; + } + case IOCTL_SO_BIND: + { + bind_params *addr = (bind_params*)Memory::GetPointer(BufferIn); + GC_sockaddr_in addrPC; + memcpy(&addrPC, addr->name, sizeof(GC_sockaddr_in)); + sockaddr_in address; + address.sin_family = addrPC.sin_family; + address.sin_addr.s_addr = addrPC.sin_addr.s_addr_; + address.sin_port = addrPC.sin_port; + ReturnValue = bind(Common::swap32(addr->socket), (sockaddr*)&address, sizeof(address)); + + WARN_LOG(WII_IPC_NET, "IOCTL_SO_BIND (%s:%d) = %d " + "Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + inet_ntoa(address.sin_addr), Common::swap16(address.sin_port), ReturnValue, + Common::swap32(addr->socket), BufferIn, BufferInSize, BufferOut, BufferOutSize); + + ReturnValue = getNetErrorCode(ReturnValue, "SO_BIND", false); + break; + } + + case IOCTL_SO_LISTEN: + { + WARN_LOG(WII_IPC_NET, "IOCTL_SO_LISTEN " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + + u32 S = Memory::Read_U32(BufferIn); + u32 BACKLOG = Memory::Read_U32(BufferIn + 0x04); + ReturnValue = listen(S, BACKLOG); + ReturnValue = getNetErrorCode(ReturnValue, "SO_LISTEN", false); + break; + } + + case IOCTL_SO_GETSOCKOPT: + { + u32 sock = Memory::Read_U32(BufferOut); + u32 level = Memory::Read_U32(BufferOut + 4); + u32 optname = Memory::Read_U32(BufferOut + 8); + + WARN_LOG(WII_IPC_NET,"IOCTL_SO_GETSOCKOPT(%08x, %08x, %08x)" + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + sock, level, optname, + BufferIn, BufferInSize, BufferOut, BufferOutSize); + + // Do the level/optname translation + int nat_level = -1, nat_optname = -1; + + for (unsigned int i = 0; i < sizeof (opt_level_mapping) / sizeof (opt_level_mapping[0]); ++i) + if (level == opt_level_mapping[i][1]) + nat_level = opt_level_mapping[i][0]; + + for (unsigned int i = 0; i < sizeof (opt_name_mapping) / sizeof (opt_name_mapping[0]); ++i) + if (optname == opt_name_mapping[i][1]) + nat_optname = opt_name_mapping[i][0]; + + u8 optval[20]; + u32 optlen = 4; + + ReturnValue = getsockopt (sock, nat_level, nat_optname, (char *) &optval, (socklen_t*)&optlen); + + ReturnValue = getNetErrorCode(ReturnValue, "SO_GETSOCKOPT", false); + + + Memory::Write_U32(optlen, BufferOut + 0xC); + Memory::WriteBigEData((u8 *) optval, BufferOut + 0x10, optlen); + + if(optname == 0x1007){ + s32 errorcode = Memory::Read_U32(BufferOut + 0x10); + WARN_LOG(WII_IPC_NET,"IOCTL_SO_GETSOCKOPT error code = %i", errorcode); + } + break; + } + + case IOCTL_SO_SETSOCKOPT: + { + u32 S = Memory::Read_U32(BufferIn); + u32 level = Memory::Read_U32(BufferIn + 4); + u32 optname = Memory::Read_U32(BufferIn + 8); + u32 optlen = Memory::Read_U32(BufferIn + 0xc); + u8 optval[20]; + Memory::ReadBigEData(optval, BufferIn + 0x10, optlen); + + //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)){ + ReturnValue = 0; + break; + } + WARN_LOG(WII_IPC_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", + S, level, optname, optlen, BufferIn, BufferInSize, BufferOut, BufferOutSize, + 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]); + + // Do the level/optname translation + int nat_level = -1, nat_optname = -1; + + for (unsigned int i = 0; i < sizeof (opt_level_mapping) / sizeof (opt_level_mapping[0]); ++i) + if (level == opt_level_mapping[i][1]) + nat_level = opt_level_mapping[i][0]; + + for (unsigned int i = 0; i < sizeof (opt_name_mapping) / sizeof (opt_name_mapping[0]); ++i) + if (optname == opt_name_mapping[i][1]) + nat_optname = opt_name_mapping[i][0]; + + if (nat_level == -1 || nat_optname == -1) + { + WARN_LOG(WII_IPC_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; + } + + ReturnValue = setsockopt(S, nat_level, nat_optname, (char*)optval, optlen); + ReturnValue = getNetErrorCode(ReturnValue, "SO_SETSOCKOPT", false); + + break; + } + + case IOCTL_SO_FCNTL: + { + u32 sock = Memory::Read_U32(BufferIn); + u32 cmd = Memory::Read_U32(BufferIn + 4); + u32 arg = Memory::Read_U32(BufferIn + 8); + + WARN_LOG(WII_IPC_NET, "IOCTL_SO_FCNTL(%08X, %08X) " + "Socket: %08x, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + cmd, arg, + sock, BufferIn, BufferInSize, BufferOut, BufferOutSize); + #ifdef _WIN32 + #define F_GETFL 3 + #define F_SETFL 4 + #define F_NONBLOCK 4 + if (cmd == F_GETFL) + { + WARN_LOG(WII_IPC_NET, "F_GETFL WTF?"); + } + else if (cmd == F_SETFL) + { + u_long iMode = 0; + if (arg & F_NONBLOCK) + iMode = 1; + ReturnValue = ioctlsocket(sock, FIONBIO, &iMode); + ReturnValue = getNetErrorCode(ReturnValue, "SO_FCNTL", false); + } + else + { + WARN_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); + } + #else + // Map POSIX <-> Wii socket flags + // First one is POSIX, second one is Wii + static int mapping[][2] = { + { O_NONBLOCK, 0x4 }, + }; + + if (cmd == F_GETFL) + { + int flags = fcntl(sock, F_GETFL, 0); + ReturnValue = 0; + + for (unsigned int i = 0; i < sizeof (mapping) / sizeof (mapping[0]); ++i) + if (flags & mapping[i][0]) + ReturnValue |= mapping[i][1]; + } + else if (cmd == F_SETFL) + { + int posix_flags = 0; + + for (unsigned int i = 0; i < sizeof (mapping) / sizeof (mapping[0]); ++i) + { + if (arg & mapping[i][1]) + { + posix_flags |= mapping[i][0]; + arg &= ~mapping[i][1]; + } + } + + if (arg) + WARN_LOG(WII_IPC_NET, "SO_FCNTL F_SETFL unhandled flags: %08x", arg); + + ReturnValue = fcntl(sock, F_SETFL, posix_flags); + ReturnValue = getNetErrorCode(ReturnValue, "SO_FCNTL", false); + } + else + { + WARN_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); + } + #endif + break; + } + + case IOCTL_SO_GETSOCKNAME: + { + u32 sock = Memory::Read_U32(BufferIn); + + WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETSOCKNAME " + "Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + sock, BufferIn, BufferInSize, BufferOut, BufferOutSize); + + sockaddr sa; + socklen_t sa_len; + sa_len = sizeof(sa); + ReturnValue = getsockname(sock, &sa, &sa_len); + + Memory::Write_U8(BufferOutSize, BufferOut); + Memory::Write_U8(sa.sa_family & 0xFF, BufferOut + 1); + Memory::WriteBigEData((u8*)&sa.sa_data, BufferOut + 2, BufferOutSize - 2); + break; + } + case IOCTL_SO_GETPEERNAME: + { + u32 sock = Memory::Read_U32(BufferIn); + + sockaddr sa; + socklen_t sa_len; + sa_len = sizeof(sa); + + ReturnValue = getpeername(sock, &sa, &sa_len); + + Memory::Write_U8(BufferOutSize, BufferOut); + Memory::Write_U8(AF_INET, BufferOut + 1); + Memory::WriteBigEData((u8*)&sa.sa_data, BufferOut + 2, BufferOutSize - 2); + + WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", sock); + + break; + } + case IOCTL_SO_GETHOSTID: + { + WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTID " + "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + BufferIn, BufferInSize, BufferOut, BufferOutSize); + ReturnValue = 192 << 24 | 168 << 16 | 1 << 8 | 150; + break; + } + case IOCTL_SO_INETATON: + { + struct hostent *remoteHost = gethostbyname((char*)Memory::GetPointer(BufferIn)); + + Memory::Write_U32(Common::swap32(*(u32 *)remoteHost->h_addr_list[0]), BufferOut); + WARN_LOG(WII_IPC_NET, "IOCTL_SO_INETATON = %d " + "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X",remoteHost->h_addr_list[0] == 0 ? -1 : 0, + (char*)Memory::GetPointer(BufferIn), BufferIn, BufferInSize, BufferOut, BufferOutSize, Common::swap32(*(u32 *)remoteHost->h_addr_list[0])); + ReturnValue = remoteHost->h_addr_list[0] == 0 ? 0 : 1; + break; + } + case IOCTL_SO_INETPTON: + { + WARN_LOG(WII_IPC_NET, "IOCTL_SO_INETPTON " + "(Translating: %s)", Memory::GetPointer(BufferIn)); + ReturnValue = inet_pton((char*)Memory::GetPointer(BufferIn), Memory::GetPointer(BufferOut+4)); + break; + } + case IOCTL_SO_INETNTOP: + { + u32 af = Memory::Read_U32(BufferIn); + //u32 af = Memory::Read_U32(BufferIn + 4); + u32 src = Memory::Read_U32(BufferIn + 8); + //u32 af = Memory::Read_U32(BufferIn + 12); + //u32 af = Memory::Read_U32(BufferIn + 16); + //u32 af = Memory::Read_U32(BufferIn + 20); + char ip_s[16]; + sprintf(ip_s, "%i.%i.%i.%i", + Memory::Read_U8(BufferIn + 8), + Memory::Read_U8(BufferIn + 8 + 1), + Memory::Read_U8(BufferIn + 8 + 2), + Memory::Read_U8(BufferIn + 8 + 3) + ); + WARN_LOG(WII_IPC_NET, "IOCTL_SO_INETNTOP %s", ip_s); + memset(Memory::GetPointer(BufferOut), 0, BufferOutSize); + memcpy(Memory::GetPointer(BufferOut), ip_s, strlen(ip_s)); + break; + } + + case IOCTL_SO_POLL: + { + // Map Wii/native poll events types + unsigned int mapping[][2] = { + { POLLIN, 0x0001 }, + { POLLOUT, 0x0008 }, + { POLLHUP, 0x0040 }, + }; + + u32 unknown = Memory::Read_U32(BufferIn); + u32 timeout = Memory::Read_U32(BufferIn + 4); + + int nfds = BufferOutSize / 0xc; + if (nfds == 0) + ERROR_LOG(WII_IPC_NET,"Hidden POLL"); + + pollfd_t* ufds = (pollfd_t *)malloc(sizeof(pollfd_t) * nfds); + if (ufds == NULL) + { + ReturnValue = -1; + break; + } + + for (int i = 0; i < nfds; i++) + { + ufds[i].fd = Memory::Read_U32(BufferOut + 0xc*i); //fd + int events = Memory::Read_U32(BufferOut + 0xc*i + 4); //events + ufds[i].revents = Memory::Read_U32(BufferOut + 0xc*i + 8); //revents + + // Translate Wii to native events + int unhandled_events = events; + ufds[i].events = 0; + for (unsigned int j = 0; j < sizeof (mapping) / sizeof (mapping[0]); ++j) + { + if (events & mapping[j][1]) + ufds[i].events |= mapping[j][0]; + unhandled_events &= ~mapping[j][1]; + } + + WARN_LOG(WII_IPC_NET, "IOCTL_SO_POLL(%d) " + "Sock: %08x, Unknown: %08x, Events: %08x, " + "NativeEvents: %08x", + i, ufds[i].fd, unknown, events, ufds[i].events + ); + + if (unhandled_events) + ERROR_LOG(WII_IPC_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); + } + + ReturnValue = poll(ufds, nfds, timeout); + ReturnValue = getNetErrorCode(ReturnValue, "SO_POLL", false); + + for (int i = 0; ih_aliases[i]; ++i) + { + WARN_LOG(WII_IPC_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])); + char ip_s[16]; + sprintf(ip_s, "%i.%i.%i.%i", + ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); + DEBUG_LOG(WII_IPC_NET, "addr%i:%s", i, ip_s); + } + + Memory::Memset(BufferOut, 0, BufferOutSize); + u32 wii_addr = BufferOut + 4 * 3 + 2 * 2; + + u32 name_length = strlen(remoteHost->h_name) + 1; + Memory::WriteBigEData((const u8 *)remoteHost->h_name, wii_addr, name_length); + Memory::Write_U32(wii_addr, BufferOut); + wii_addr += (name_length + 4) & ~3; + + // aliases - empty + Memory::Write_U32(wii_addr, BufferOut + 4); + Memory::Write_U32(wii_addr + sizeof(u32), wii_addr); + wii_addr += sizeof(u32); + Memory::Write_U32((u32)NULL, wii_addr); + wii_addr += sizeof(u32); + + // hardcode to ipv4 + _dbg_assert_msg_(WII_IPC_NET, + remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), + "returned host info is not IPv4"); + Memory::Write_U16(AF_INET, BufferOut + 8); + Memory::Write_U16(sizeof(u32), BufferOut + 10); + + // addrlist - probably only really need to return 1 anyways... + Memory::Write_U32(wii_addr, BufferOut + 12); + u32 num_addr = 0; + while (remoteHost->h_addr_list[num_addr]) + num_addr++; + for (u32 i = 0; i < num_addr; ++i) + { + Memory::Write_U32(wii_addr + sizeof(u32) * (num_addr + 1), wii_addr); + wii_addr += sizeof(u32); + } + // NULL terminated list + Memory::Write_U32((u32)NULL, wii_addr); + wii_addr += sizeof(u32); + // The actual IPs + for (int i = 0; remoteHost->h_addr_list[i]; i++) + { + Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), wii_addr); + wii_addr += sizeof(u32); + } + + //ERROR_LOG(WII_IPC_NET, "\n%s", + // ArrayToString(Memory::GetPointer(BufferOut), BufferOutSize, 16).c_str()); + ReturnValue = 0; + } + else + { + ReturnValue = -1; + } + + break; + } + + case IOCTL_SO_ICMPSOCKET: + { + // AF type? + u32 arg = Memory::Read_U32(BufferIn); + u32 sock = (u32)socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_ICMPSOCKET(%x) %x", arg, sock); + ReturnValue = getNetErrorCode(sock, "IOCTL_SO_ICMPSOCKET", false); + break; + } + + case IOCTL_SO_ICMPCANCEL: + ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCANCEL"); + goto default_; + + case IOCTL_SO_ICMPCLOSE: + { + u32 sock = Memory::Read_U32(BufferIn); + #ifdef _WIN32 + u32 ReturnValue = closesocket(sock); + #else + u32 ReturnValue = close(sock); + #endif + DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCLOSE(%x) %x", sock, ReturnValue); + ReturnValue = getNetErrorCode(ReturnValue, "IOCTL_SO_ICMPCLOSE", false); + break; + } + + default: + { + WARN_LOG(WII_IPC_NET,"0x%x " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + Command, BufferIn, BufferInSize, BufferOut, BufferOutSize); +default_: + if (BufferInSize) + { + ERROR_LOG(WII_IPC_NET, "in addr %x size %x", BufferIn, BufferInSize); + ERROR_LOG(WII_IPC_NET, "\n%s", + ArrayToString(Memory::GetPointer(BufferIn), BufferInSize, 4).c_str() + ); + } + + if (BufferOutSize) + { + ERROR_LOG(WII_IPC_NET, "out addr %x size %x", BufferOut, BufferOutSize); + } + break; + } + } + + Memory::Write_U32(ReturnValue, CommandAddress + 0x4); return true; } -struct bind_params -{ - u32 socket; - u32 has_name; - u8 name[28]; -}; - -struct GC_sockaddr -{ - u8 sa_len; - u8 sa_family; - s8 sa_data[14]; -}; - -struct GC_in_addr -{ - // this cannot be named s_addr under windows - collides with some crazy define. - u32 s_addr_; -}; - -struct GC_sockaddr_in -{ - u8 sin_len; - u8 sin_family; - u16 sin_port; - struct GC_in_addr sin_addr; - s8 sin_zero[8]; -}; - char* DecodeError(int ErrorCode) { #ifdef _WIN32 - static char Message[1024]; - // If this program was multi-threaded, we'd want to use FORMAT_MESSAGE_ALLOCATE_BUFFER - // instead of a static buffer here. - // (And of course, free the buffer when we were done with it) + char Message[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)Message, 1024, NULL); @@ -688,7 +1288,7 @@ char* DecodeError(int ErrorCode) #endif } -static int getNetErrorCode(int ret, std::string caller, bool isRW) +int getNetErrorCode(int ret, std::string caller, bool isRW) { #ifdef _WIN32 int errorCode = WSAGetLastError(); @@ -729,7 +1329,7 @@ static int getNetErrorCode(int ret, std::string caller, bool isRW) return -26; // EINPROGRESS } case EITHER(WSA_INVALID_HANDLE, EBADF): - return -26; // EINPROGRESS + return -26; // EINPROGRESS (should be -8) default: return -1; } @@ -738,720 +1338,328 @@ static int getNetErrorCode(int ret, std::string caller, bool isRW) #undef EITHER } -static int inet_pton(const char *src, unsigned char *dst) + +void CWII_IPC_HLE_Device_net_ip_top::socketProcessor(u32 socket) { - static const char digits[] = "0123456789"; - int saw_digit, octets, ch; - unsigned char tmp[4], *tp; - - saw_digit = 0; - octets = 0; - *(tp = tmp) = 0; - while ((ch = *src++) != '\0') { - const char *pch; - - if ((pch = strchr(digits, ch)) != NULL) { - unsigned int newt = *tp * 10 + (pch - digits); - - 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 } -}; - -u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command, - u32 _BufferIn, u32 BufferInSize, - u32 _BufferOut, u32 BufferOutSize) -{ - switch (_Command) + ERROR_LOG(WII_IPC_NET, "Socket %d has started a thread.... oh dear.", socket); + _tSocket* sock = NULL; { - case IOCTL_SO_STARTUP: - WARN_LOG(WII_IPC_NET, "IOCTL_SO_STARTUP " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - break; - - case IOCTL_SO_CONNECT: + std::unique_lock lk(socketMapMutex); + if(socketMap.find(socket) == socketMap.end()) { - //struct sockaddr_in echoServAddr; - struct connect_params - { - u32 socket; - u32 has_addr; - u8 addr[28]; - } params; - sockaddr_in serverAddr; - - Memory::ReadBigEData((u8*)¶ms, _BufferIn, sizeof(connect_params)); - - if (Common::swap32(params.has_addr) != 1) - return -1; - - memset(&serverAddr, 0, sizeof(serverAddr)); - memcpy(&serverAddr, params.addr, params.addr[0]); - - // GC/Wii sockets have a length param as well, we dont really care :) - serverAddr.sin_family = serverAddr.sin_family >> 8; - - int ret = connect(Common::swap32(params.socket), (struct sockaddr *) &serverAddr, sizeof(serverAddr)); - ret = getNetErrorCode(ret, "SO_CONNECT", false); - WARN_LOG(WII_IPC_NET,"IOCTL_SO_CONNECT (%08x, %s:%d)", - Common::swap32(params.socket), inet_ntoa(serverAddr.sin_addr), Common::swap16(serverAddr.sin_port)); - return ret; - break; + ERROR_LOG(WII_IPC_NET, "Socket %d could not be found in the socket map.", socket); + return; } - - case IOCTL_SO_SHUTDOWN: + sock = socketMap[socket]; + } + while((sock->WaitForEvent(), true) && sock->running) + { + u32 CommandAddress = 0; + while(sock->getCommand(CommandAddress)) { - WARN_LOG(WII_IPC_NET, "IOCTL_SO_SHUTDOWN " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - - u32 sock = Memory::Read_U32(_BufferIn); - u32 how = Memory::Read_U32(_BufferIn+4); - int ret = shutdown(sock, how); - return getNetErrorCode(ret, "SO_SHUTDOWN", false); - break; - } - - case IOCTL_SO_CLOSE: - { - u32 sock = Memory::Read_U32(_BufferIn); - WARN_LOG(WII_IPC_NET, "IOCTL_SO_CLOSE (%08x)", sock); - -#ifdef _WIN32 - u32 ret = closesocket(sock); - - return getNetErrorCode(ret, "IOCTL_SO_CLOSE", false); -#else - return close(sock); -#endif - break; - } - - case IOCTL_SO_SOCKET: - { - u32 AF = Memory::Read_U32(_BufferIn); - u32 TYPE = Memory::Read_U32(_BufferIn + 0x04); - u32 PROT = Memory::Read_U32(_BufferIn + 0x08); - u32 s = (u32)socket(AF, TYPE, PROT); - WARN_LOG(WII_IPC_NET, "IOCTL_SO_SOCKET " - "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - s, AF, TYPE, PROT, _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - int ret = getNetErrorCode(s, "SO_SOCKET", false); - if(ret>=0){ -#ifdef _WIN32 - u32 millis = 3000; -#else - struct timeval millis; - millis.tv_sec = 3; - millis.tv_usec = 0; -#endif - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&millis,sizeof(millis)); - } + using WII_IPC_HLE_Interface::ECommandType; + using WII_IPC_HLE_Interface::COMMAND_IOCTL; + using WII_IPC_HLE_Interface::COMMAND_IOCTLV; + s32 ReturnValue = 0; + ECommandType CommandType = static_cast(Memory::Read_U32(CommandAddress)); - return ret; - break; - } - - case IOCTL_SO_BIND: - { - bind_params *addr = (bind_params*)Memory::GetPointer(_BufferIn); - GC_sockaddr_in addrPC; - memcpy(&addrPC, addr->name, sizeof(GC_sockaddr_in)); - sockaddr_in address; - address.sin_family = addrPC.sin_family; - address.sin_addr.s_addr = addrPC.sin_addr.s_addr_; - address.sin_port = addrPC.sin_port; - int ret = bind(Common::swap32(addr->socket), (sockaddr*)&address, sizeof(address)); - - WARN_LOG(WII_IPC_NET, "IOCTL_SO_BIND (%s:%d) = %d " - "Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - inet_ntoa(address.sin_addr), Common::swap16(address.sin_port), ret, - Common::swap32(addr->socket), _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - - return getNetErrorCode(ret, "SO_BIND", false); - break; - } - - case IOCTL_SO_LISTEN: - { - WARN_LOG(WII_IPC_NET, "IOCTL_SO_LISTEN " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - - u32 S = Memory::Read_U32(_BufferIn); - u32 BACKLOG = Memory::Read_U32(_BufferIn + 0x04); - u32 ret = listen(S, BACKLOG); - return getNetErrorCode(ret, "SO_LISTEN", false); - break; - } - - case IOCTL_SO_ACCEPT: - { - WARN_LOG(WII_IPC_NET, "IOCTL_SO_ACCEPT " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - - u32 S = Memory::Read_U32(_BufferIn); - struct sockaddr* addr = (struct sockaddr*) Memory::GetPointer(_BufferOut); - socklen_t* addrlen = (socklen_t*) Memory::GetPointer(BufferOutSize); - *addrlen = sizeof(struct sockaddr); - int ret = accept(S, addr, addrlen); - return getNetErrorCode(ret, "SO_ACCEPT", false); - } - - case IOCTL_SO_GETSOCKOPT: - { - u32 sock = Memory::Read_U32(_BufferOut); - u32 level = Memory::Read_U32(_BufferOut + 4); - u32 optname = Memory::Read_U32(_BufferOut + 8); - - WARN_LOG(WII_IPC_NET,"IOCTL_SO_GETSOCKOPT(%08x, %08x, %08x)" - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - sock, level, optname, - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - - // Do the level/optname translation - int nat_level = -1, nat_optname = -1; - - for (unsigned int i = 0; i < sizeof (opt_level_mapping) / sizeof (opt_level_mapping[0]); ++i) - if (level == opt_level_mapping[i][1]) - nat_level = opt_level_mapping[i][0]; - - for (unsigned int i = 0; i < sizeof (opt_name_mapping) / sizeof (opt_name_mapping[0]); ++i) - if (optname == opt_name_mapping[i][1]) - nat_optname = opt_name_mapping[i][0]; - - u8 optval[20]; - u32 optlen = 4; - - int ret = getsockopt (sock, nat_level, nat_optname, (char *) &optval, (socklen_t*)&optlen); - - ret = getNetErrorCode(ret, "SO_GETSOCKOPT", false); - - - Memory::Write_U32(optlen, _BufferOut + 0xC); - Memory::WriteBigEData((u8 *) optval, _BufferOut + 0x10, optlen); - - if(optname == 0x1007){ - s32 errorcode = Memory::Read_U32(_BufferOut + 0x10); - WARN_LOG(WII_IPC_NET,"IOCTL_SO_GETSOCKOPT error code = %i", errorcode); - } - return ret; - } - - case IOCTL_SO_SETSOCKOPT: - { - u32 S = Memory::Read_U32(_BufferIn); - u32 level = Memory::Read_U32(_BufferIn + 4); - u32 optname = Memory::Read_U32(_BufferIn + 8); - u32 optlen = Memory::Read_U32(_BufferIn + 0xc); - u8 optval[20]; - Memory::ReadBigEData(optval, _BufferIn + 0x10, optlen); - - //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 0; - } - WARN_LOG(WII_IPC_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", - S, level, optname, optlen, _BufferIn, BufferInSize, _BufferOut, BufferOutSize, 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]); - - // Do the level/optname translation - int nat_level = -1, nat_optname = -1; - - for (unsigned int i = 0; i < sizeof (opt_level_mapping) / sizeof (opt_level_mapping[0]); ++i) - if (level == opt_level_mapping[i][1]) - nat_level = opt_level_mapping[i][0]; - - for (unsigned int i = 0; i < sizeof (opt_name_mapping) / sizeof (opt_name_mapping[0]); ++i) - if (optname == opt_name_mapping[i][1]) - nat_optname = opt_name_mapping[i][0]; - - if (nat_level == -1 || nat_optname == -1) + if(CommandType == COMMAND_IOCTL) { - WARN_LOG(WII_IPC_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(S, nat_level, nat_optname, (char*)optval, optlen); - - ret = getNetErrorCode(ret, "SO_SETSOCKOPT", false); - - return ret; - } - - case IOCTL_SO_FCNTL: - { - u32 sock = Memory::Read_U32(_BufferIn); - u32 cmd = Memory::Read_U32(_BufferIn + 4); - u32 arg = Memory::Read_U32(_BufferIn + 8); - - WARN_LOG(WII_IPC_NET, "IOCTL_SO_FCNTL(%08X, %08X) " - "Socket: %08x, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - cmd, arg, - sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize); -#ifdef _WIN32 -#define F_GETFL 3 -#define F_SETFL 4 -#define F_NONBLOCK 4 - if (cmd == F_GETFL) - { - WARN_LOG(WII_IPC_NET, "F_GETFL WTF?"); - } - else if (cmd == F_SETFL) - { - u_long iMode = 0; - //if (arg & F_NONBLOCK) - iMode = 1; - int ioctlret = ioctlsocket(sock, FIONBIO, &iMode); - return getNetErrorCode(ioctlret, "SO_FCNTL", false); - } - else - { - WARN_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); - } - return 0; -#else - // Map POSIX <-> Wii socket flags - // First one is POSIX, second one is Wii - static int mapping[][2] = { - { O_NONBLOCK, 0x4 }, - }; - - if (cmd == F_GETFL) - { - int flags = fcntl(sock, F_GETFL, 0); - int ret = 0; - - for (unsigned int i = 0; i < sizeof (mapping) / sizeof (mapping[0]); ++i) - if (flags & mapping[i][0]) - ret |= mapping[i][1]; - return ret; - } - else if (cmd == F_SETFL) - { - int posix_flags = O_NONBLOCK; //0; - - for (unsigned int i = 0; i < sizeof (mapping) / sizeof (mapping[0]); ++i) + u32 BufferIn = Memory::Read_U32(CommandAddress + 0x10); + u32 BufferInSize = Memory::Read_U32(CommandAddress + 0x14); + u32 BufferOut = Memory::Read_U32(CommandAddress + 0x18); + u32 BufferOutSize = Memory::Read_U32(CommandAddress + 0x1C); + u32 Command = Memory::Read_U32(CommandAddress + 0x0C); + WARN_LOG(WII_IPC_NET, "IOCTL command = %d", Command); + switch(Command) { - if (arg & mapping[i][1]) + case IOCTL_SO_ACCEPT: { - posix_flags |= mapping[i][0]; - arg &= ~mapping[i][1]; + WARN_LOG(WII_IPC_NET, "IOCTL_SO_ACCEPT(%d) " + "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + socket, BufferIn, BufferInSize, BufferOut, BufferOutSize); + struct sockaddr* addr = (struct sockaddr*) Memory::GetPointer(BufferOut); + socklen_t* addrlen = (socklen_t*) Memory::GetPointer(BufferOutSize); + *addrlen = sizeof(struct sockaddr); + ReturnValue = accept(socket, addr, addrlen); + ReturnValue = getNetErrorCode(ReturnValue, "SO_ACCEPT", false); + break; + } + case IOCTL_SO_CONNECT: + { + //struct sockaddr_in echoServAddr; + struct connect_params + { + u32 socket; + u32 has_addr; + u8 addr[28]; + } params; + sockaddr_in serverAddr; + + Memory::ReadBigEData((u8*)¶ms, BufferIn, sizeof(connect_params)); + + if (Common::swap32(params.has_addr) != 1) + { + WARN_LOG(WII_IPC_NET,"IOCTL_SO_CONNECT: failed"); + ReturnValue = -1; + break; + } + + memset(&serverAddr, 0, sizeof(serverAddr)); + memcpy(&serverAddr, params.addr, params.addr[0]); + + // GC/Wii sockets have a length param as well, we dont really care :) + serverAddr.sin_family = serverAddr.sin_family >> 8; + + ReturnValue = connect(socket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); + ReturnValue = getNetErrorCode(ReturnValue, "SO_CONNECT", false); + WARN_LOG(WII_IPC_NET,"IOCTL_SO_CONNECT (%08x, %s:%d)", + socket, inet_ntoa(serverAddr.sin_addr), Common::swap16(serverAddr.sin_port)); + break; + } + default: + { + + ERROR_LOG(WII_IPC_NET, "Socket %08x has received an unknown IOCTLV %d.", socket, Command); + break; } } - - if (arg) - WARN_LOG(WII_IPC_NET, "SO_FCNTL F_SETFL unhandled flags: %08x", arg); - - int ret = fcntl(sock, F_SETFL, posix_flags); - return getNetErrorCode(ret, "SO_FCNTL", false); + } - else + else if (CommandType == COMMAND_IOCTLV) { - WARN_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); + SIOCtlVBuffer CommandBuffer(CommandAddress); + + u32 BufferIn = 0, BufferIn2 = 0, BufferIn3 = 0; + u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; + + u32 BufferOut = 0, BufferOut2 = 0, BufferOut3 = 0; + u32 BufferOutSize = 0, BufferOutSize2 = 0, BufferOutSize3 = 0; + + if (CommandBuffer.InBuffer.size() > 0) + { + BufferIn = CommandBuffer.InBuffer.at(0).m_Address; + BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; + } + if (CommandBuffer.InBuffer.size() > 1) + { + BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; + BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; + } + if (CommandBuffer.InBuffer.size() > 2) + { + BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; + BufferInSize3 = CommandBuffer.InBuffer.at(2).m_Size; + } + + if (CommandBuffer.PayloadBuffer.size() > 0) + { + BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; + BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; + } + if (CommandBuffer.PayloadBuffer.size() > 1) + { + BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; + BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; + } + if (CommandBuffer.PayloadBuffer.size() > 2) + { + BufferOut3 = CommandBuffer.PayloadBuffer.at(2).m_Address; + BufferOutSize3 = CommandBuffer.PayloadBuffer.at(2).m_Size; + } + switch(CommandBuffer.Parameter) + { + case IOCTLV_SO_RECVFROM: + { + + u32 flags = Memory::Read_U32(BufferIn + 4); + + char *buf = (char *)Memory::GetPointer(BufferOut); + int len = BufferOutSize; + struct sockaddr_in addr; + memset(&addr, 0, sizeof(sockaddr_in)); + socklen_t fromlen = 0; + + if (BufferOutSize2 != 0) + { + fromlen = BufferOutSize2 >= sizeof(struct sockaddr) ? BufferOutSize2 : sizeof(struct sockaddr); + } + + if (flags != 2) + flags = 0; + else + flags = MSG_PEEK; + #ifdef _WIN32 + if(flags & MSG_PEEK){ + unsigned long totallen = 0; + ioctlsocket(socket, FIONREAD, &totallen); + ReturnValue = totallen; + break; + } + #endif + ReturnValue = recvfrom(socket, buf, len, flags, + fromlen ? (struct sockaddr*) &addr : NULL, + fromlen ? &fromlen : 0); + + ReturnValue = getNetErrorCode(ReturnValue, fromlen ? "SO_RECVFROM" : "SO_RECV", true); + + + WARN_LOG(WII_IPC_NET, "%s(%d, %p) Socket: %08X, Flags: %08X, " + "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " + "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)",fromlen ? "IOCTLV_SO_RECVFROM " : "IOCTLV_SO_RECV ", + ReturnValue, buf, socket, flags, + BufferIn, BufferInSize, BufferIn2, BufferInSize2, + BufferOut, BufferOutSize, BufferOut2, BufferOutSize2); + + if (BufferOutSize2 != 0) + { + addr.sin_family = (addr.sin_family << 8) | (BufferOutSize2&0xFF); + Memory::WriteBigEData((u8*)&addr, BufferOut2, BufferOutSize2); + } + + break; + } + case IOCTLV_SO_SENDTO: + { + struct sendto_params + { + u32 socket; + u32 flags; + u32 has_destaddr; + u8 destaddr[28]; + } params; + + char * data = (char*)Memory::GetPointer(BufferIn); + Memory::ReadBigEData((u8*)¶ms, BufferIn2, BufferInSize2); + + if (params.has_destaddr) + { + struct sockaddr_in* addr = (struct sockaddr_in*)¶ms.destaddr; + u8 len = sizeof(sockaddr); //addr->sin_family & 0xFF; + addr->sin_family = addr->sin_family >> 8; + + ReturnValue = sendto(socket, data, + BufferInSize, Common::swap32(params.flags), (struct sockaddr*)addr, len); + + WARN_LOG(WII_IPC_NET, + "IOCTLV_SO_SENDTO = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u", + ReturnValue, socket, BufferIn, BufferInSize, + BufferIn2, BufferInSize2, + addr->sin_addr.s_addr & 0xFF, + (addr->sin_addr.s_addr >> 8) & 0xFF, + (addr->sin_addr.s_addr >> 16) & 0xFF, + (addr->sin_addr.s_addr >> 24) & 0xFF + ); + + ReturnValue = getNetErrorCode(ReturnValue, "SO_SENDTO", true); + } + else + { + ReturnValue = send(socket, data, + BufferInSize, Common::swap32(params.flags)); + WARN_LOG(WII_IPC_NET, "IOCTLV_SO_SEND = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", + ReturnValue, socket, BufferIn, BufferInSize, + BufferIn2, BufferInSize2); + + ReturnValue = getNetErrorCode(ReturnValue, "SO_SEND", true); + } + break; + } + default: + { + + ERROR_LOG(WII_IPC_NET, "Socket %d has received an unknown IOCTLV %d.", socket, CommandBuffer.Parameter); + break; + } + } } - return 0; -#endif - } - - case IOCTL_SO_GETSOCKNAME: - { - u32 sock = Memory::Read_U32(_BufferIn); - - WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETSOCKNAME " - "Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - - sockaddr sa; - socklen_t sa_len; - sa_len = sizeof(sa); - int ret = getsockname(sock, &sa, &sa_len); - - Memory::Write_U8(BufferOutSize, _BufferOut); - Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut + 1); - Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut + 2, BufferOutSize - 2); - return ret; - } - case IOCTL_SO_GETPEERNAME: - { - u32 sock = Memory::Read_U32(_BufferIn); - - sockaddr sa; - socklen_t sa_len; - sa_len = sizeof(sa); - - int ret = getpeername(sock, &sa, &sa_len); - - Memory::Write_U8(BufferOutSize, _BufferOut); - Memory::Write_U8(AF_INET, _BufferOut + 1); - Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut + 2, BufferOutSize - 2); - WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", sock); - - return ret; + Memory::Write_U32(8, CommandAddress); + // IOS seems to write back the command that was responded to + Memory::Write_U32(CommandType, CommandAddress + 8); + // Return value + Memory::Write_U32(ReturnValue, CommandAddress + 4); + WII_IPC_HLE_Interface::EnqReply(CommandAddress); } - - case IOCTL_SO_GETHOSTID: - { - WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTID " - "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - return 192 << 24 | 168 << 16 | 1 << 8 | 150; - } - - case IOCTL_SO_INETATON: - { - struct hostent *remoteHost = gethostbyname((char*)Memory::GetPointer(_BufferIn)); - - Memory::Write_U32(Common::swap32(*(u32 *)remoteHost->h_addr_list[0]), _BufferOut); - WARN_LOG(WII_IPC_NET, "IOCTL_SO_INETATON = %d " - "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X",remoteHost->h_addr_list[0] == 0 ? -1 : 0, - (char*)Memory::GetPointer(_BufferIn), _BufferIn, BufferInSize, _BufferOut, BufferOutSize, Common::swap32(*(u32 *)remoteHost->h_addr_list[0])); - return remoteHost->h_addr_list[0] == 0 ? 0 : 1; - } - - case IOCTL_SO_INETPTON: - { - WARN_LOG(WII_IPC_NET, "IOCTL_SO_INETPTON " - "(Translating: %s)", Memory::GetPointer(_BufferIn)); - return inet_pton((char*)Memory::GetPointer(_BufferIn), Memory::GetPointer(_BufferOut+4)); - break; - } - - case IOCTL_SO_INETNTOP: - { - u32 af = Memory::Read_U32(_BufferIn); - //u32 af = Memory::Read_U32(_BufferIn + 4); - u32 src = Memory::Read_U32(_BufferIn + 8); - //u32 af = Memory::Read_U32(_BufferIn + 12); - //u32 af = Memory::Read_U32(_BufferIn + 16); - //u32 af = Memory::Read_U32(_BufferIn + 20); - char ip_s[16]; - sprintf(ip_s, "%i.%i.%i.%i", - Memory::Read_U8(_BufferIn + 8), - Memory::Read_U8(_BufferIn + 8 + 1), - Memory::Read_U8(_BufferIn + 8 + 2), - Memory::Read_U8(_BufferIn + 8 + 3) - ); - WARN_LOG(WII_IPC_NET, "IOCTL_SO_INETNTOP %s", ip_s); - memset(Memory::GetPointer(_BufferOut), 0, BufferOutSize); - memcpy(Memory::GetPointer(_BufferOut), ip_s, strlen(ip_s)); - return 0; - } - - case IOCTL_SO_POLL: - { - // Map Wii/native poll events types - unsigned int mapping[][2] = { - { POLLIN, 0x0001 }, - { POLLOUT, 0x0008 }, - { POLLHUP, 0x0040 }, - }; - - u32 unknown = Memory::Read_U32(_BufferIn); - u32 timeout = Memory::Read_U32(_BufferIn + 4); - - int nfds = BufferOutSize / 0xc; - if (nfds == 0) - ERROR_LOG(WII_IPC_NET,"Hidden POLL"); - - pollfd_t* ufds = (pollfd_t *)malloc(sizeof(pollfd_t) * nfds); - if (ufds == NULL) - return -1; - - for (int i = 0; i < nfds; i++) - { - ufds[i].fd = Memory::Read_U32(_BufferOut + 0xc*i); //fd - int events = Memory::Read_U32(_BufferOut + 0xc*i + 4); //events - ufds[i].revents = Memory::Read_U32(_BufferOut + 0xc*i + 8); //revents - - // Translate Wii to native events - int unhandled_events = events; - ufds[i].events = 0; - for (unsigned int j = 0; j < sizeof (mapping) / sizeof (mapping[0]); ++j) - { - if (events & mapping[j][1]) - ufds[i].events |= mapping[j][0]; - unhandled_events &= ~mapping[j][1]; - } - - WARN_LOG(WII_IPC_NET, "IOCTL_SO_POLL(%d) " - "Sock: %08x, Unknown: %08x, Events: %08x, " - "NativeEvents: %08x", - i, ufds[i].fd, unknown, events, ufds[i].events - ); - - if (unhandled_events) - ERROR_LOG(WII_IPC_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); - } - - int ret = poll(ufds, nfds, timeout); - - ret = getNetErrorCode(ret, "SO_POLL", false); - - for (int i = 0; ih_aliases[i]; ++i) - { - WARN_LOG(WII_IPC_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])); - char ip_s[16]; - sprintf(ip_s, "%i.%i.%i.%i", - ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); - DEBUG_LOG(WII_IPC_NET, "addr%i:%s", i, ip_s); - } - - Memory::Memset(_BufferOut, 0, BufferOutSize); - u32 wii_addr = _BufferOut + 4 * 3 + 2 * 2; - - u32 name_length = strlen(remoteHost->h_name) + 1; - Memory::WriteBigEData((const u8 *)remoteHost->h_name, wii_addr, name_length); - Memory::Write_U32(wii_addr, _BufferOut); - wii_addr += (name_length + 4) & ~3; - - // aliases - empty - Memory::Write_U32(wii_addr, _BufferOut + 4); - Memory::Write_U32(wii_addr + sizeof(u32), wii_addr); - wii_addr += sizeof(u32); - Memory::Write_U32((u32)NULL, wii_addr); - wii_addr += sizeof(u32); - - // hardcode to ipv4 - _dbg_assert_msg_(WII_IPC_NET, - remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), - "returned host info is not IPv4"); - Memory::Write_U16(AF_INET, _BufferOut + 8); - Memory::Write_U16(sizeof(u32), _BufferOut + 10); - - // addrlist - probably only really need to return 1 anyways... - Memory::Write_U32(wii_addr, _BufferOut + 12); - u32 num_addr = 0; - while (remoteHost->h_addr_list[num_addr]) - num_addr++; - for (u32 i = 0; i < num_addr; ++i) - { - Memory::Write_U32(wii_addr + sizeof(u32) * (num_addr + 1), wii_addr); - wii_addr += sizeof(u32); - } - // NULL terminated list - Memory::Write_U32((u32)NULL, wii_addr); - wii_addr += sizeof(u32); - // The actual IPs - for (int i = 0; remoteHost->h_addr_list[i]; i++) - { - Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), wii_addr); - wii_addr += sizeof(u32); - } - - //ERROR_LOG(WII_IPC_NET, "\n%s", - // ArrayToString(Memory::GetPointer(_BufferOut), BufferOutSize, 16).c_str()); - return 0; - } - else - { - return -1; - } - - break; - } - - case IOCTL_SO_ICMPSOCKET: - { - // AF type? - u32 arg = Memory::Read_U32(_BufferIn); - u32 sock = (u32)socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_ICMPSOCKET(%x) %x", arg, sock); - return getNetErrorCode(sock, "IOCTL_SO_ICMPSOCKET", false); - } - - case IOCTL_SO_ICMPCANCEL: - ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCANCEL"); - goto default_; - - case IOCTL_SO_ICMPCLOSE: - { - u32 sock = Memory::Read_U32(_BufferIn); -#ifdef _WIN32 - u32 ret = closesocket(sock); -#else - u32 ret = close(sock); -#endif - DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCLOSE(%x) %x", sock, ret); - return getNetErrorCode(ret, "IOCTL_SO_ICMPCLOSE", false); - } - - default: - WARN_LOG(WII_IPC_NET,"0x%x " - "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _Command, _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - default_: - if (BufferInSize) - { - ERROR_LOG(WII_IPC_NET, "in addr %x size %x", _BufferIn, BufferInSize); - ERROR_LOG(WII_IPC_NET, "\n%s", - ArrayToString(Memory::GetPointer(_BufferIn), BufferInSize, 4).c_str() - ); - } - - if (BufferOutSize) - { - ERROR_LOG(WII_IPC_NET, "out addr %x size %x", _BufferOut, BufferOutSize); - } - break; + + //DEBUG_LOG(WII_IPC_NET, "Socket %d has processed all events.", socket); } - - // We return a success for any potential unknown requests - return 0; + //DEBUG_LOG(WII_IPC_NET, "Socket %d has died.", socket); } -u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer) -{ - u32 _BufferIn = 0, _BufferIn2 = 0, _BufferIn3 = 0; + +bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) +{ + SIOCtlVBuffer CommandBuffer(CommandAddress); + + s32 ReturnValue = 0; + + u32 BufferIn = 0, BufferIn2 = 0, BufferIn3 = 0; u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; - u32 _BufferOut = 0, _BufferOut2 = 0, _BufferOut3 = 0; + u32 BufferOut = 0, BufferOut2 = 0, BufferOut3 = 0; u32 BufferOutSize = 0, BufferOutSize2 = 0, BufferOutSize3 = 0; if (CommandBuffer.InBuffer.size() > 0) { - _BufferIn = CommandBuffer.InBuffer.at(0).m_Address; + BufferIn = CommandBuffer.InBuffer.at(0).m_Address; BufferInSize = CommandBuffer.InBuffer.at(0).m_Size; } if (CommandBuffer.InBuffer.size() > 1) { - _BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; + BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address; BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size; } if (CommandBuffer.InBuffer.size() > 2) { - _BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; + BufferIn3 = CommandBuffer.InBuffer.at(2).m_Address; BufferInSize3 = CommandBuffer.InBuffer.at(2).m_Size; } if (CommandBuffer.PayloadBuffer.size() > 0) { - _BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; + BufferOut = CommandBuffer.PayloadBuffer.at(0).m_Address; BufferOutSize = CommandBuffer.PayloadBuffer.at(0).m_Size; } if (CommandBuffer.PayloadBuffer.size() > 1) { - _BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; + BufferOut2 = CommandBuffer.PayloadBuffer.at(1).m_Address; BufferOutSize2 = CommandBuffer.PayloadBuffer.at(1).m_Size; } if (CommandBuffer.PayloadBuffer.size() > 2) { - _BufferOut3 = CommandBuffer.PayloadBuffer.at(2).m_Address; + BufferOut3 = CommandBuffer.PayloadBuffer.at(2).m_Address; BufferOutSize3 = CommandBuffer.PayloadBuffer.at(2).m_Size; } - //struct ifreq { /* BUGBUG: reduced form of ifreq just for this hack */ - // char ifr_name[16]; - // struct sockaddr ifr_addr; - //}; - - //struct ifreq ifr; struct sockaddr_in saddr; - //int fd; - -#ifdef _WIN32 - PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; - ULONG OutBufferLength = 0; - ULONG RetVal = 0, i; -#endif - - u32 param = 0, param2 = 0, param3, param4, param5 = 0; - switch (CommandBuffer.Parameter) { case IOCTLV_SO_GETINTERFACEOPT: - { - param = Memory::Read_U32(_BufferIn); - param2 = Memory::Read_U32(_BufferIn+4); - param3 = Memory::Read_U32(_BufferOut); - param4 = Memory::Read_U32(_BufferOut2); + { + #ifdef _WIN32 + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + #endif + + u32 param = 0, param2 = 0, param3, param4, param5 = 0; + param = Memory::Read_U32(BufferIn); + param2 = Memory::Read_U32(BufferIn+4); + param3 = Memory::Read_U32(BufferOut); + param4 = Memory::Read_U32(BufferOut2); if (BufferOutSize >= 8) { - param5 = Memory::Read_U32(_BufferOut+4); + param5 = Memory::Read_U32(BufferOut+4); } WARN_LOG(WII_IPC_NET,"IOCTLV_SO_GETINTERFACEOPT(%08X, %08X) " "BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", param, param2, - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); + BufferIn, BufferInSize, BufferIn2, BufferInSize2); switch (param2) { @@ -1521,32 +1729,32 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer if (address == 0) address = 0x08080808; - Memory::Write_U32(address, _BufferOut); - Memory::Write_U32(0x08080808, _BufferOut+4); + Memory::Write_U32(address, BufferOut); + Memory::Write_U32(0x08080808, BufferOut+4); break; } case 0x1003: - Memory::Write_U32(0, _BufferOut); + Memory::Write_U32(0, BufferOut); break; case 0x1004: - Memory::WriteBigEData(default_address, _BufferOut, 6); + Memory::WriteBigEData(default_address, BufferOut, 6); break; case 0x1005: - Memory::Write_U32(1, _BufferOut); - Memory::Write_U32(4, _BufferOut2); + Memory::Write_U32(1, BufferOut); + Memory::Write_U32(4, BufferOut2); break; case 0x4002: - Memory::Write_U32(2, _BufferOut); + Memory::Write_U32(2, BufferOut); break; case 0x4003: - Memory::Write_U32(0xC, _BufferOut2); - Memory::Write_U32(10 << 24 | 1 << 8 | 30, _BufferOut); - Memory::Write_U32(255 << 24 | 255 << 16 | 255 << 8 | 0, _BufferOut+4); - Memory::Write_U32(10 << 24 | 0 << 16 | 255 << 8 | 255, _BufferOut+8); + Memory::Write_U32(0xC, BufferOut2); + Memory::Write_U32(10 << 24 | 1 << 8 | 30, BufferOut); + Memory::Write_U32(255 << 24 | 255 << 16 | 255 << 8 | 0, BufferOut+4); + Memory::Write_U32(10 << 24 | 0 << 16 | 255 << 8 | 255, BufferOut+8); break; default: @@ -1555,109 +1763,41 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer } - return 0; + ReturnValue = 0; break; } case IOCTLV_SO_SENDTO: - { - struct sendto_params - { - u32 socket; - u32 flags; - u32 has_destaddr; - u8 destaddr[28]; - } params; - - char * data = (char*)Memory::GetPointer(_BufferIn); - Memory::ReadBigEData((u8*)¶ms, _BufferIn2, BufferInSize2); - - if (params.has_destaddr) - { - struct sockaddr_in* addr = (struct sockaddr_in*)¶ms.destaddr; - u8 len = sizeof(sockaddr); //addr->sin_family & 0xFF; - addr->sin_family = addr->sin_family >> 8; - - int ret = sendto(Common::swap32(params.socket), data, - BufferInSize, Common::swap32(params.flags), (struct sockaddr*)addr, len); - - WARN_LOG(WII_IPC_NET, - "IOCTLV_SO_SENDTO = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u", - ret, Common::swap32(params.socket), _BufferIn, BufferInSize, - _BufferIn2, BufferInSize2, - addr->sin_addr.s_addr & 0xFF, - (addr->sin_addr.s_addr >> 8) & 0xFF, - (addr->sin_addr.s_addr >> 16) & 0xFF, - (addr->sin_addr.s_addr >> 24) & 0xFF - ); - - return getNetErrorCode(ret, "SO_SENDTO", true); - } - else - { - int ret = send(Common::swap32(params.socket), data, - BufferInSize, Common::swap32(params.flags)); - WARN_LOG(WII_IPC_NET, "IOCTLV_SO_SEND = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", - ret, Common::swap32(params.socket), _BufferIn, BufferInSize, - _BufferIn2, BufferInSize2); - - return getNetErrorCode(ret, "SO_SEND", true); - } - break; - } - case IOCTLV_SO_RECVFROM: + { + u32 s = 0; + if (CommandBuffer.Parameter == IOCTLV_SO_SENDTO) { - u32 sock = Memory::Read_U32(_BufferIn); - u32 flags = Memory::Read_U32(_BufferIn + 4); - - char *buf = (char *)Memory::GetPointer(_BufferOut); - int len = BufferOutSize; - struct sockaddr_in addr; - memset(&addr, 0, sizeof(sockaddr_in)); - socklen_t fromlen = 0; - - if (BufferOutSize2 != 0) - { - fromlen = BufferOutSize2 >= sizeof(struct sockaddr) ? BufferOutSize2 : sizeof(struct sockaddr); - } - - if (flags != 2) - flags = 0; - else - flags = MSG_PEEK; - - static int ret; -#ifdef _WIN32 - if(flags & MSG_PEEK){ - unsigned long totallen = 0; - ioctlsocket(sock, FIONREAD, &totallen); - return totallen; - } -#endif - ret = recvfrom(sock, buf, len, flags, - fromlen ? (struct sockaddr*) &addr : NULL, - fromlen ? &fromlen : 0); - - int err = getNetErrorCode(ret, fromlen ? "SO_RECVFROM" : "SO_RECV", true); - - - WARN_LOG(WII_IPC_NET, "%s(%d, %p) Socket: %08X, Flags: %08X, " - "BufferIn: (%08x, %i), BufferIn2: (%08x, %i), " - "BufferOut: (%08x, %i), BufferOut2: (%08x, %i)",fromlen ? "IOCTLV_SO_RECVFROM " : "IOCTLV_SO_RECV ", - err, buf, sock, flags, - _BufferIn, BufferInSize, _BufferIn2, BufferInSize2, - _BufferOut, BufferOutSize, _BufferOut2, BufferOutSize2); - - if (BufferOutSize2 != 0) - { - addr.sin_family = (addr.sin_family << 8) | (BufferOutSize2&0xFF); - Memory::WriteBigEData((u8*)&addr, _BufferOut2, BufferOutSize2); - } - - return err; + s = Memory::Read_U32(BufferIn2); + } else { + s = Memory::Read_U32(BufferIn); } + _tSocket * sock = NULL; + { + std::unique_lock lk(socketMapMutex); + if(socketMap.find(s) != socketMap.end()) + sock = socketMap[s]; + } + if(sock) + { + sock->addCommand(CommandAddress); + return false; + } + else + { + ReturnValue = -8; // EBADF + } + + ERROR_LOG(WII_IPC_NET, "Failed to find socket %d", s); + break; + } + case IOCTLV_SO_GETADDRINFO: { struct addrinfo hints; @@ -1665,28 +1805,28 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer if (BufferInSize3) { - hints.ai_flags = Memory::Read_U32(_BufferIn3); - hints.ai_family = Memory::Read_U32(_BufferIn3 + 0x4); - hints.ai_socktype = Memory::Read_U32(_BufferIn3 + 0x8); - hints.ai_protocol = Memory::Read_U32(_BufferIn3 + 0xC); - hints.ai_addrlen = Memory::Read_U32(_BufferIn3 + 0x10); - hints.ai_canonname = (char*)Memory::Read_U32(_BufferIn3 + 0x14); - hints.ai_addr = (sockaddr *)Memory::Read_U32(_BufferIn3 + 0x18); - hints.ai_next = (addrinfo *)Memory::Read_U32(_BufferIn3 + 0x1C); + hints.ai_flags = Memory::Read_U32(BufferIn3); + hints.ai_family = Memory::Read_U32(BufferIn3 + 0x4); + hints.ai_socktype = Memory::Read_U32(BufferIn3 + 0x8); + hints.ai_protocol = Memory::Read_U32(BufferIn3 + 0xC); + hints.ai_addrlen = Memory::Read_U32(BufferIn3 + 0x10); + hints.ai_canonname = (char*)Memory::Read_U32(BufferIn3 + 0x14); + hints.ai_addr = (sockaddr *)Memory::Read_U32(BufferIn3 + 0x18); + hints.ai_next = (addrinfo *)Memory::Read_U32(BufferIn3 + 0x1C); } char* pNodeName = NULL; if (BufferInSize > 0) - pNodeName = (char*)Memory::GetPointer(_BufferIn); + pNodeName = (char*)Memory::GetPointer(BufferIn); char* pServiceName = NULL; if (BufferInSize2 > 0) - pServiceName = (char*)Memory::GetPointer(_BufferIn2); + pServiceName = (char*)Memory::GetPointer(BufferIn2); - int ret = getaddrinfo(pNodeName, pServiceName, BufferInSize3 ? &hints : NULL, &result); - u32 addr = _BufferOut; + ReturnValue = getaddrinfo(pNodeName, pServiceName, BufferInSize3 ? &hints : NULL, &result); + u32 addr = BufferOut; u32 sockoffset = addr + 0x460; - if (ret >= 0) + if (ReturnValue >= 0) { while (result != NULL) { @@ -1726,9 +1866,9 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer WARN_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO " "(BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - _BufferIn, BufferInSize, _BufferOut, BufferOutSize); - WARN_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO: %s", Memory::GetPointer(_BufferIn)); - return ret; + BufferIn, BufferInSize, BufferOut, BufferOutSize); + WARN_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO: %s", Memory::GetPointer(BufferIn)); + break; } case IOCTLV_SO_ICMPPING: @@ -1741,19 +1881,19 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer u32 ip; } ip_info; - u32 sock = Memory::Read_U32(_BufferIn); - u32 num_ip = Memory::Read_U32(_BufferIn + 4); - u64 timeout = Memory::Read_U64(_BufferIn + 8); + u32 sock = Memory::Read_U32(BufferIn); + u32 num_ip = Memory::Read_U32(BufferIn + 4); + u64 timeout = Memory::Read_U64(BufferIn + 8); if (num_ip != 1) { WARN_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip); } - ip_info.length = Memory::Read_U8(_BufferIn + 16); - ip_info.addr_family = Memory::Read_U8(_BufferIn + 17); - ip_info.icmp_id = Memory::Read_U16(_BufferIn + 18); - ip_info.ip = Memory::Read_U32(_BufferIn + 20); + ip_info.length = Memory::Read_U8(BufferIn + 16); + ip_info.addr_family = Memory::Read_U8(BufferIn + 17); + ip_info.icmp_id = Memory::Read_U16(BufferIn + 18); + ip_info.ip = Memory::Read_U32(BufferIn + 20); if (ip_info.length != 8 || ip_info.addr_family != AF_INET) { @@ -1774,7 +1914,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer s32 icmp_length = sizeof(data); if (BufferInSize2 == sizeof(data)) - memcpy(data, Memory::GetPointer(_BufferIn2), BufferInSize2); + memcpy(data, Memory::GetPointer(BufferIn2), BufferInSize2); else { // TODO sequence number is incremented either statically, by @@ -1784,19 +1924,20 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer icmp_length = 22; } - int ret = icmp_echo_req(sock, &addr, data, icmp_length); - if (ret == icmp_length) + ReturnValue = icmp_echo_req(sock, &addr, data, icmp_length); + if (ReturnValue == icmp_length) { - ret = icmp_echo_rep(sock, &addr, (u32)timeout, icmp_length); + ReturnValue = icmp_echo_rep(sock, &addr, (u32)timeout, icmp_length); } // TODO proper error codes - return 0; + ReturnValue = 0; + break; } default: WARN_LOG(WII_IPC_NET,"0x%x (BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", - CommandBuffer.Parameter, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); + CommandBuffer.Parameter, BufferIn, BufferInSize, BufferIn2, BufferInSize2); default_: for (u32 i = 0; i < CommandBuffer.NumberInBuffer; ++i) { @@ -1815,16 +1956,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer } break; } - - return 0; -} - -bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) -{ - SIOCtlVBuffer buf(CommandAddress); - - u32 return_value = ExecuteCommandV(buf); - Memory::Write_U32(return_value, CommandAddress + 4); + Memory::Write_U32(ReturnValue, CommandAddress + 4); return true; } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h index 75ff25c6eb..6b98564ca7 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h @@ -29,6 +29,7 @@ #include #endif #include "Timer.h" +#include "Thread.h" #include "FileUtil.h" // data layout of the network configuration file (/shared2/sys/net/02/config.dat) @@ -568,6 +569,54 @@ private: } }; +class _tSocket +{ +public: + bool running; + std::mutex m_mutex; + std::thread* thread; + + _tSocket() + { + running = true; + } + + bool getCommand(u32& commandAddress) + { + std::unique_lock lk(m_mutex); + if (commands.empty()) + return false; + commandAddress = commands.front(); + commands.pop(); + return true; + } + + void addCommand(u32 commandAddress) + { + std::unique_lock lk(m_mutex); + commands.push(commandAddress); + event.Set(); + } + + void StopAndJoin() + { + running = false; + event.Set(); + thread->join(); + delete thread; + thread = NULL; + } + + void WaitForEvent() + { + event.Wait(); + } +private: + Common::Event event; + std::queue commands; + +}; + ////////////////////////////////////////////////////////////////////////// class CWII_IPC_HLE_Device_net_ip_top : public IWII_IPC_HLE_Device { @@ -585,6 +634,9 @@ private: #ifdef _WIN32 WSADATA InitData; #endif + std::map socketMap; + std::mutex socketMapMutex; + void socketProcessor(u32 socket); enum { @@ -629,6 +681,39 @@ private: u32 ExecuteCommandV(SIOCtlVBuffer& CommandBuffer); }; +static int getNetErrorCode(int ret, std::string caller, bool isRW); + + +struct bind_params +{ + u32 socket; + u32 has_name; + u8 name[28]; +}; + +struct GC_sockaddr +{ + u8 sa_len; + u8 sa_family; + s8 sa_data[14]; +}; + +struct GC_in_addr +{ + // this cannot be named s_addr under windows - collides with some crazy define. + u32 s_addr_; +}; + +struct GC_sockaddr_in +{ + u8 sin_len; + u8 sin_family; + u16 sin_port; + struct GC_in_addr sin_addr; + s8 sin_zero[8]; +}; + + // ********************************************************************************** // Interface for reading and changing network configuration (probably some other stuff as well) class CWII_IPC_HLE_Device_net_ncd_manage : public IWII_IPC_HLE_Device