From d33c19b0cd2bae982c8d35e86a9d3551f9e5c72f Mon Sep 17 00:00:00 2001 From: skidau Date: Wed, 27 Mar 2013 12:58:04 +1100 Subject: [PATCH] Revert the threading of wii-network. This rolls back to commit bca2cac640e4aff69a97b919411855d0e4b305da. --- Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp | 12 +- .../Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp | 1822 ++++++++--------- .../Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h | 87 - 3 files changed, 817 insertions(+), 1104 deletions(-) diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index 9c1072f030..83e2fa9092 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -535,14 +535,14 @@ void ExecuteCommand(u32 _Address) } } + // It seems that the original hardware overwrites the command after it has been + // executed. We write 8 which is not any valid command, and what IOS does + Memory::Write_U32(8, _Address); + // IOS seems to write back the command that was responded to + Memory::Write_U32(Command, _Address + 8); + if (CmdSuccess) { - // It seems that the original hardware overwrites the command after it has been - // executed. We write 8 which is not any valid command, and what IOS does - Memory::Write_U32(8, _Address); - // IOS seems to write back the command that was responded to - Memory::Write_U32(Command, _Address + 8); - // Ensure replies happen in order, fairly ugly // Without this, tons of games fail now that DI commads have different reply delays int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0; 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 e7a9896fae..fa4c98dac2 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,7 +55,6 @@ it failed) #include "ICMP.h" #include "CommonPaths.h" #include "SettingsHandler.h" -#include "WII_IPC_HLE.h" #include "ec_wii.h" @@ -90,10 +89,6 @@ typedef struct pollfd pollfd_t; #include #endif -#ifdef _WIN32 -#define SHUT_RDWR SD_BOTH -#endif - extern std::queue > g_ReplyQueueLater; const u8 default_address[] = { 0x00, 0x17, 0xAB, 0x99, 0x99, 0x99 }; @@ -108,30 +103,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) @@ -250,8 +245,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; } @@ -367,30 +362,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) { @@ -476,7 +471,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; } @@ -607,13 +602,6 @@ CWII_IPC_HLE_Device_net_ip_top::CWII_IPC_HLE_Device_net_ip_top(u32 _DeviceID, co int ret = WSAStartup(MAKEWORD(2,2), &InitData); INFO_LOG(WII_IPC_NET, "WSAStartup: %d", ret); #endif - - u32 s = 0xDEADBEEF; - std::lock_guard lk(socketMapMutex); - _tSocket* sock = new _tSocket(); - socketMap[s] = sock; - sock->thread = new std::thread([this, s]{this->processSocket(s);}); - } CWII_IPC_HLE_Device_net_ip_top::~CWII_IPC_HLE_Device_net_ip_top() @@ -621,646 +609,76 @@ CWII_IPC_HLE_Device_net_ip_top::~CWII_IPC_HLE_Device_net_ip_top() #ifdef _WIN32 WSACleanup(); #endif - - std::lock_guard lk(socketMapMutex); - auto i = socketMap.begin(); - while(i != socketMap.end()) - { - u32 s = i->first; - _tSocket * sock = i->second; - if(s != 0xDEADBEEF) - { - (void)shutdown(s, SHUT_RDWR); - #ifdef _WIN32 - (void)closesocket(s); - #else - (void)close(s); - #endif - } - - sock->StopAndJoin(); - delete sock; - socketMap.erase(i++); - } } -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; } -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); -} - -// 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) +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::lock_guard 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 %08X", s, Command); - break; - } - case IOCTL_SO_POLL: - { - u32 s = 0xDEADBEEF; - _tSocket * sock = NULL; - { - std::lock_guard 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 %08X", s, Command); - 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::lock_guard lk(socketMapMutex); - _tSocket* sock = new _tSocket(); - socketMap[s] = sock; - sock->thread = new std::thread([this, s]{this->processSocket(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); - - ReturnValue = shutdown(s, SHUT_RDWR); - #ifdef _WIN32 - ReturnValue = closesocket(s); - #else - ReturnValue = close(s); - #endif - - ReturnValue = getNetErrorCode(ReturnValue, "IOCTL_SO_CLOSE", false); - - _tSocket * sock = NULL; - { - std::lock_guard lk(socketMapMutex); - if(socketMap.find(s) != socketMap.end()) - sock = socketMap[s]; - if(sock) - { - //cascading failures hopefully - sock->StopAndJoin(); - delete sock; - socketMap.erase(s); - } - } - - WARN_LOG(WII_IPC_NET, "IOCTL_SO_CLOSE finished (%08x) = ", s, ReturnValue); - - 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); - ReturnValue = getNetErrorCode(ReturnValue, "IOCTL_SO_GETPEERNAME", false); - - 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_GETHOSTBYNAME: - { - hostent *remoteHost = gethostbyname((char*)Memory::GetPointer(BufferIn)); - - WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTBYNAME " - "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - (char*)Memory::GetPointer(BufferIn), BufferIn, BufferInSize, BufferOut, BufferOutSize); - - if (remoteHost) - { - for (int i = 0; remoteHost->h_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); + 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); + + u32 ReturnValue = ExecuteCommand(Command, BufferIn, BufferInSize, BufferOut, BufferOutSize); + 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 - char Message[1024]; + 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) 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); @@ -1270,7 +688,7 @@ char* DecodeError(int ErrorCode) #endif } -int getNetErrorCode(int ret, std::string caller, bool isRW) +static int getNetErrorCode(int ret, std::string caller, bool isRW) { #ifdef _WIN32 int errorCode = WSAGetLastError(); @@ -1311,7 +729,7 @@ int getNetErrorCode(int ret, std::string caller, bool isRW) return -26; // EINPROGRESS } case EITHER(WSA_INVALID_HANDLE, EBADF): - return -26; // EINPROGRESS (should be -8) + return -26; // EINPROGRESS default: return -1; } @@ -1320,30 +738,69 @@ int getNetErrorCode(int ret, std::string caller, bool isRW) #undef EITHER } - -s32 CWII_IPC_HLE_Device_net_ip_top::processSocketIoctl(u32 CommandAddress, u32 socket) +static int inet_pton(const char *src, unsigned char *dst) { - s32 ReturnValue = 0; - 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); - switch(Command) + 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) { - case IOCTL_SO_ACCEPT: - { - WARN_LOG(WII_IPC_NET, "IOCTL_SO_ACCEPT(%d) " + case IOCTL_SO_STARTUP: + WARN_LOG(WII_IPC_NET, "IOCTL_SO_STARTUP " "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: + _BufferIn, BufferInSize, _BufferOut, BufferOutSize); + break; + + case IOCTL_SO_CONNECT: { //struct sockaddr_in echoServAddr; struct connect_params @@ -1353,57 +810,400 @@ s32 CWII_IPC_HLE_Device_net_ip_top::processSocketIoctl(u32 CommandAddress, u32 s u8 addr[28]; } params; sockaddr_in serverAddr; - - Memory::ReadBigEData((u8*)¶ms, BufferIn, sizeof(connect_params)); - + + 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; - } - + 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; - - ReturnValue = connect(socket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); - ReturnValue = getNetErrorCode(ReturnValue, "SO_CONNECT", false); + + 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)", - socket, inet_ntoa(serverAddr.sin_addr), Common::swap16(serverAddr.sin_port)); + Common::swap32(params.socket), inet_ntoa(serverAddr.sin_addr), Common::swap16(serverAddr.sin_port)); + return ret; break; } - case IOCTL_SO_POLL: + + 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); + 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)); + } + + + + 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) + { + 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) + { + 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); + + int ret = fcntl(sock, F_SETFL, posix_flags); + return getNetErrorCode(ret, "SO_FCNTL", false); + } + else + { + WARN_LOG(WII_IPC_NET, "SO_FCNTL unknown command"); + } + 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; + } + + 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 }, + { POLLIN, 0x0001 }, { POLLOUT, 0x0008 }, { POLLHUP, 0x0040 }, }; - - u32 unknown = Memory::Read_U32(BufferIn); - u32 timeout = Memory::Read_U32(BufferIn + 4); - + + 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; - } - + 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 - + 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; @@ -1413,20 +1213,21 @@ s32 CWII_IPC_HLE_Device_net_ip_top::processSocketIoctl(u32 CommandAddress, u32 s 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 + "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); - + + int ret = poll(ufds, nfds, timeout); + + ret = getNetErrorCode(ret, "SO_POLL", false); + for (int i = 0; i 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) + hostent *remoteHost = gethostbyname((char*)Memory::GetPointer(_BufferIn)); + + WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTBYNAME " + "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + (char*)Memory::GetPointer(_BufferIn), _BufferIn, BufferInSize, _BufferOut, BufferOutSize); + + if (remoteHost) { - 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) + for (int i = 0; remoteHost->h_aliases[i]; ++i) { - addr.sin_family = (addr.sin_family << 8) | (BufferOutSize2&0xFF); - Memory::WriteBigEData((u8*)&addr, BufferOut2, BufferOutSize2); + WARN_LOG(WII_IPC_NET, "alias%i:%s", i, remoteHost->h_aliases[i]); } - - break; - } - default: - { - - ERROR_LOG(WII_IPC_NET, "Socket %d has received an unknown IOCTLV %d.", socket, CommandBuffer.Parameter); + + 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; } - return ReturnValue; + + // We return a success for any potential unknown requests + return 0; } -void CWII_IPC_HLE_Device_net_ip_top::processSocket(u32 socket) +u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer) { - //DEBUG_LOG(WII_IPC_NET, "Socket %08X has started a thread.... oh dear.", socket); - _tSocket* sock = NULL; - { - std::lock_guard lk(socketMapMutex); - if(socketMap.find(socket) == socketMap.end()) - { - ERROR_LOG(WII_IPC_NET, "Socket %d could not be found in the socket map.", socket); - return; - } - sock = socketMap[socket]; - } - while((sock->WaitForEvent(), true) && sock->running) - { - u32 CommandAddress = 0; - while(sock->getCommand(CommandAddress)) - { - - 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)); - - if(CommandType == COMMAND_IOCTL) - { - ReturnValue = processSocketIoctl(CommandAddress, socket); - } - else if (CommandType == COMMAND_IOCTLV) - { - ReturnValue = processSocketIoctlv(CommandAddress, socket); - } - - 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); - } - - //DEBUG_LOG(WII_IPC_NET, "Socket %d has processed all events.", socket); - } - //DEBUG_LOG(WII_IPC_NET, "Socket %d has died.", socket); -} - - -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 _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: - { - #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); + { + 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) { @@ -1751,32 +1521,32 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) 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: @@ -1785,87 +1555,109 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) } - ReturnValue = 0; + return 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) { - s = Memory::Read_U32(BufferIn2); - } else { - s = Memory::Read_U32(BufferIn); - } - ERROR_LOG(WII_IPC_NET, "Adding sendto or recvfrom %08X %08X", s, CommandBuffer.Parameter); - - _tSocket * sock = NULL; - { - std::lock_guard lk(socketMapMutex); - if(socketMap.find(s) != socketMap.end()) - sock = socketMap[s]; - } - if(sock) - { - sock->addCommand(CommandAddress); - return false; - } - else - { - ReturnValue = -8; // EBADF + 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; } - ERROR_LOG(WII_IPC_NET, "Failed to find socket %d %08X", s, CommandBuffer.Parameter); - break; - } - - case IOCTLV_SO_SENDTO: - { - struct sendto_params - { - u32 socket; - u32 flags; - u32 has_destaddr; - u8 destaddr[28]; - } params; - u32 socket = Memory::Read_U32(BufferIn2); - 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_in); //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; - } case IOCTLV_SO_GETADDRINFO: { struct addrinfo hints; @@ -1873,28 +1665,28 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) 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); - ReturnValue = getaddrinfo(pNodeName, pServiceName, BufferInSize3 ? &hints : NULL, &result); - u32 addr = BufferOut; + int ret = getaddrinfo(pNodeName, pServiceName, BufferInSize3 ? &hints : NULL, &result); + u32 addr = _BufferOut; u32 sockoffset = addr + 0x460; - if (ReturnValue >= 0) + if (ret >= 0) { while (result != NULL) { @@ -1934,9 +1726,9 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) 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)); - break; + _BufferIn, BufferInSize, _BufferOut, BufferOutSize); + WARN_LOG(WII_IPC_NET, "IOCTLV_SO_GETADDRINFO: %s", Memory::GetPointer(_BufferIn)); + return ret; } case IOCTLV_SO_ICMPPING: @@ -1949,19 +1741,19 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) 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) { @@ -1982,7 +1774,7 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) 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 @@ -1992,20 +1784,19 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) icmp_length = 22; } - ReturnValue = icmp_echo_req(sock, &addr, data, icmp_length); - if (ReturnValue == icmp_length) + int ret = icmp_echo_req(sock, &addr, data, icmp_length); + if (ret == icmp_length) { - ReturnValue = icmp_echo_rep(sock, &addr, (u32)timeout, icmp_length); + ret = icmp_echo_rep(sock, &addr, (u32)timeout, icmp_length); } // TODO proper error codes - ReturnValue = 0; - break; + return 0; } 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) { @@ -2024,7 +1815,16 @@ bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) } break; } - Memory::Write_U32(ReturnValue, CommandAddress + 4); + + 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); 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 209d7a240b..75ff25c6eb 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,7 +29,6 @@ #include #endif #include "Timer.h" -#include "Thread.h" #include "FileUtil.h" // data layout of the network configuration file (/shared2/sys/net/02/config.dat) @@ -569,54 +568,6 @@ private: } }; -class _tSocket -{ -public: - bool running; - std::mutex m_mutex; - std::thread* thread; - - _tSocket() - { - running = true; - } - - bool getCommand(u32& commandAddress) - { - std::lock_guard lk(m_mutex); - if (commands.empty()) - return false; - commandAddress = commands.front(); - commands.pop(); - return true; - } - - void addCommand(u32 commandAddress) - { - std::lock_guard 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 { @@ -634,11 +585,6 @@ private: #ifdef _WIN32 WSADATA InitData; #endif - std::map socketMap; - std::mutex socketMapMutex; - void processSocket(u32 socket); - s32 processSocketIoctl(u32 CommandAddress, u32 socket); - s32 processSocketIoctlv(u32 CommandAddress, u32 socket); enum { @@ -683,39 +629,6 @@ 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