Make wii-network async.

* accept still needs to be made async.
This commit is contained in:
Matthew Parlane 2013-08-22 23:58:56 +12:00
parent d0d162e6ad
commit 124fe24f4c
10 changed files with 1716 additions and 1214 deletions

View File

@ -335,6 +335,7 @@
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb_kbd.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_WiiMote.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_Socket.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\Movie.cpp" />
<ClCompile Include="Src\NetPlay.cpp" />
@ -546,6 +547,7 @@
<ClInclude Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb.h" />
<ClInclude Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb_kbd.h" />
<ClInclude Include="Src\IPC_HLE\WII_IPC_HLE_WiiMote.h" />
<ClInclude Include="Src\IPC_HLE\WII_Socket.h" />
<ClInclude Include="Src\MemTools.h" />
<ClInclude Include="Src\Movie.h" />
<ClInclude Include="Src\NetPlay.h" />

View File

@ -574,6 +574,9 @@
<Filter>IPC HLE %28IOS/Starlet%29\USB</Filter>
</ClCompile>
<ClCompile Include="Src\ec_wii.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_Socket.cpp">
<Filter>IPC HLE %28IOS/Starlet%29\Net</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\ConfigManager.h" />
@ -1069,6 +1072,9 @@
<Filter>IPC HLE %28IOS/Starlet%29\USB</Filter>
</ClInclude>
<ClInclude Include="Src\ec_wii.h" />
<ClInclude Include="Src\IPC_HLE\WII_Socket.h">
<Filter>IPC HLE %28IOS/Starlet%29\Net</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -525,14 +525,15 @@ 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 commands have different reply delays
int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;

View File

@ -36,6 +36,61 @@
//#define FS_EFATAL (u32)-119 // Fatal error not used by IOS as fatal ERROR
#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time
// A struct for IOS ioctlv calls
struct SIOCtlVBuffer
{
SIOCtlVBuffer(u32 _Address) : m_Address(_Address)
{
// These are the Ioctlv parameters in the IOS communication. The BufferVector
// is a memory address offset at where the in and out buffer addresses are
// stored.
Parameter = Memory::Read_U32(m_Address + 0x0C); // command 3, arg0
NumberInBuffer = Memory::Read_U32(m_Address + 0x10); // 4, arg1
NumberPayloadBuffer = Memory::Read_U32(m_Address + 0x14); // 5, arg2
BufferVector = Memory::Read_U32(m_Address + 0x18); // 6, arg3
// The start of the out buffer
u32 BufferVectorOffset = BufferVector;
// Write the address and size for all in messages
for (u32 i = 0; i < NumberInBuffer; i++)
{
SBuffer Buffer;
Buffer.m_Address = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
Buffer.m_Size = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
InBuffer.push_back(Buffer);
DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer in%i: 0x%08x, 0x%x",
i, Buffer.m_Address, Buffer.m_Size);
}
// Write the address and size for all out or in-out messages
for (u32 i = 0; i < NumberPayloadBuffer; i++)
{
SBuffer Buffer;
Buffer.m_Address = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
Buffer.m_Size = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
PayloadBuffer.push_back(Buffer);
DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer io%i: 0x%08x, 0x%x",
i, Buffer.m_Address, Buffer.m_Size);
}
}
const u32 m_Address;
u32 Parameter;
u32 NumberInBuffer;
u32 NumberPayloadBuffer;
u32 BufferVector;
struct SBuffer { u32 m_Address, m_Size; };
std::vector<SBuffer> InBuffer;
std::vector<SBuffer> PayloadBuffer;
};
class IWII_IPC_HLE_Device
{
public:
@ -104,61 +159,6 @@ protected:
bool m_Hardware;
bool m_Active;
// A struct for IOS ioctlv calls
struct SIOCtlVBuffer
{
SIOCtlVBuffer(u32 _Address) : m_Address(_Address)
{
// These are the Ioctlv parameters in the IOS communication. The BufferVector
// is a memory address offset at where the in and out buffer addresses are
// stored.
Parameter = Memory::Read_U32(m_Address + 0x0C); // command 3, arg0
NumberInBuffer = Memory::Read_U32(m_Address + 0x10); // 4, arg1
NumberPayloadBuffer = Memory::Read_U32(m_Address + 0x14); // 5, arg2
BufferVector = Memory::Read_U32(m_Address + 0x18); // 6, arg3
// The start of the out buffer
u32 BufferVectorOffset = BufferVector;
// Write the address and size for all in messages
for (u32 i = 0; i < NumberInBuffer; i++)
{
SBuffer Buffer;
Buffer.m_Address = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
Buffer.m_Size = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
InBuffer.push_back(Buffer);
DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer in%i: 0x%08x, 0x%x",
i, Buffer.m_Address, Buffer.m_Size);
}
// Write the address and size for all out or in-out messages
for (u32 i = 0; i < NumberPayloadBuffer; i++)
{
SBuffer Buffer;
Buffer.m_Address = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
Buffer.m_Size = Memory::Read_U32(BufferVectorOffset);
BufferVectorOffset += 4;
PayloadBuffer.push_back(Buffer);
DEBUG_LOG(WII_IPC_HLE, "SIOCtlVBuffer io%i: 0x%08x, 0x%x",
i, Buffer.m_Address, Buffer.m_Size);
}
}
const u32 m_Address;
u32 Parameter;
u32 NumberInBuffer;
u32 NumberPayloadBuffer;
u32 BufferVector;
struct SBuffer { u32 m_Address, m_Size; };
std::vector<SBuffer> InBuffer;
std::vector<SBuffer> PayloadBuffer;
};
// Write out the IPC struct from _CommandAddress to _NumberOfCommands numbers
// of 4 byte commands.
void DumpCommands(u32 _CommandAddress, size_t _NumberOfCommands = 8,

File diff suppressed because it is too large Load Diff

View File

@ -135,7 +135,7 @@ struct nwc24_config_t
NWC24_IDCS_GENERATED = 1,
NWC24_IDCS_REGISTERED = 2
};
enum
{
URL_COUNT = 0x05,
@ -143,7 +143,7 @@ struct nwc24_config_t
MAX_EMAIL_LENGTH = 0x40,
MAX_PASSWORD_LENGTH = 0x20,
};
u32 magic; /* 'WcCf' 0x57634366 */
u32 _unk_04; /* must be 8 */
u64 nwc24_id;
@ -167,21 +167,21 @@ class NWC24Config
private:
std::string path;
nwc24_config_t config;
public:
NWC24Config()
{
path = File::GetUserPath(D_WIIWC24_IDX) + "nwc24msg.cfg";
ReadConfig();
}
void ResetConfig()
{
int i;
if (File::Exists(path))
File::Delete(path);
const char* urls[5] = {
"https://amw.wc24.wii.com/cgi-bin/account.cgi",
"http://rcw.wc24.wii.com/cgi-bin/check.cgi",
@ -189,25 +189,25 @@ public:
"http://mtw.wc24.wii.com/cgi-bin/delete.cgi",
"http://mtw.wc24.wii.com/cgi-bin/send.cgi",
};
memset(&config, 0, sizeof(config));
SetMagic(0x57634366);
SetUnk(8);
SetCreationStage(nwc24_config_t::NWC24_IDCS_INITIAL);
SetEnableBooting(0);
SetEmail("@wii.com");
for(i=0; i<nwc24_config_t::URL_COUNT; i++)
{
strncpy(config.http_urls[i], urls[i], nwc24_config_t::MAX_URL_LENGTH);
}
SetChecksum(CalculateNwc24ConfigChecksum());
WriteConfig();
}
void WriteConfig()
{
if (!File::Exists(path))
@ -217,11 +217,11 @@ public:
ERROR_LOG(WII_IPC_WC24, "Failed to create directory for WC24");
}
}
File::IOFile(path, "wb").WriteBytes((void*)&config, sizeof(config));
}
void ReadConfig()
{
if (File::Exists(path))
@ -240,7 +240,7 @@ public:
ResetConfig();
}
}
u32 CalculateNwc24ConfigChecksum(void)
{
u32* ptr = (u32*)&config;
@ -252,7 +252,7 @@ public:
}
return sum;
}
s32 CheckNwc24Config(void)
{
if (Magic() != 0x57634366) /* 'WcCf' magic */
@ -274,16 +274,16 @@ public:
}
if (Unk() != 8)
return -27;
return 0;
}
u32 Magic(){return Common::swap32(config.magic);}
void SetMagic(u32 magic){config.magic = Common::swap32(magic);}
u32 Unk(){return Common::swap32(config._unk_04);}
void SetUnk(u32 _unk_04){config._unk_04 = Common::swap32(_unk_04);}
u32 IdGen(){return Common::swap32(config.id_generation);}
void SetIdGen(u32 id_generation){config.id_generation = Common::swap32(id_generation);}
void IncrementIdGen(){
@ -292,26 +292,26 @@ public:
id_ctr &= 0x1F;
SetIdGen(id_ctr);
}
u32 Checksum(){return Common::swap32(config.checksum);}
void SetChecksum(u32 checksum){config.checksum = Common::swap32(checksum);}
u32 CreationStage(){return Common::swap32(config.creation_stage);}
void SetCreationStage(u32 creation_stage){config.creation_stage = Common::swap32(creation_stage);}
u32 EnableBooting(){return Common::swap32(config.enable_booting);}
void SetEnableBooting(u32 enable_booting){config.enable_booting = Common::swap32(enable_booting);}
u64 Id(){return Common::swap64(config.nwc24_id);}
void SetId(u64 nwc24_id){config.nwc24_id = Common::swap64(nwc24_id);}
const char * Email(){return config.email;}
void SetEmail(const char * email)
{
strncpy(config.email, email, nwc24_config_t::MAX_EMAIL_LENGTH);
config.email[nwc24_config_t::MAX_EMAIL_LENGTH-1] = '\0';
}
};
class WiiNetConfig
@ -390,7 +390,7 @@ public:
class CWII_IPC_HLE_Device_net_kd_request : public IWII_IPC_HLE_Device
{
public:
CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName);
CWII_IPC_HLE_Device_net_kd_request(u32 _DeviceID, const std::string& _rDeviceName);
virtual ~CWII_IPC_HLE_Device_net_kd_request();
@ -399,32 +399,32 @@ public:
virtual bool IOCtl(u32 _CommandAddress);
private:
enum
{
IOCTL_NWC24_SUSPEND_SCHEDULAR = 0x01,
IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR = 0x02,
IOCTL_NWC24_EXEC_RESUME_SCHEDULAR = 0x03,
IOCTL_NWC24_KD_GET_TIME_TRIGGERS = 0x04,
IOCTL_NWC24_SET_SCHEDULE_SPAN = 0x05,
IOCTL_NWC24_STARTUP_SOCKET = 0x06,
IOCTL_NWC24_CLEANUP_SOCKET = 0x07,
IOCTL_NWC24_LOCK_SOCKET = 0x08,
IOCTL_NWC24_UNLOCK_SOCKET = 0x09,
IOCTL_NWC24_CHECK_MAIL_NOW = 0x0A,
IOCTL_NWC24_SEND_MAIL_NOW = 0x0B,
IOCTL_NWC24_RECEIVE_MAIL_NOW = 0x0C,
IOCTL_NWC24_SAVE_MAIL_NOW = 0x0D,
IOCTL_NWC24_DOWNLOAD_NOW_EX = 0x0E,
IOCTL_NWC24_REQUEST_GENERATED_USER_ID = 0x0F,
IOCTL_NWC24_REQUEST_REGISTER_USER_ID = 0x10,
IOCTL_NWC24_GET_SCHEDULAR_STAT = 0x1E,
IOCTL_NWC24_SET_FILTER_MODE = 0x1F,
IOCTL_NWC24_SET_DEBUG_MODE = 0x20,
IOCTL_NWC24_KD_SET_NEXT_WAKEUP = 0x21,
IOCTL_NWC24_SET_SCRIPT_MODE = 0x22,
IOCTL_NWC24_REQUEST_SHUTDOWN = 0x28,
};
enum
{
IOCTL_NWC24_SUSPEND_SCHEDULAR = 0x01,
IOCTL_NWC24_EXEC_TRY_SUSPEND_SCHEDULAR = 0x02,
IOCTL_NWC24_EXEC_RESUME_SCHEDULAR = 0x03,
IOCTL_NWC24_KD_GET_TIME_TRIGGERS = 0x04,
IOCTL_NWC24_SET_SCHEDULE_SPAN = 0x05,
IOCTL_NWC24_STARTUP_SOCKET = 0x06,
IOCTL_NWC24_CLEANUP_SOCKET = 0x07,
IOCTL_NWC24_LOCK_SOCKET = 0x08,
IOCTL_NWC24_UNLOCK_SOCKET = 0x09,
IOCTL_NWC24_CHECK_MAIL_NOW = 0x0A,
IOCTL_NWC24_SEND_MAIL_NOW = 0x0B,
IOCTL_NWC24_RECEIVE_MAIL_NOW = 0x0C,
IOCTL_NWC24_SAVE_MAIL_NOW = 0x0D,
IOCTL_NWC24_DOWNLOAD_NOW_EX = 0x0E,
IOCTL_NWC24_REQUEST_GENERATED_USER_ID = 0x0F,
IOCTL_NWC24_REQUEST_REGISTER_USER_ID = 0x10,
IOCTL_NWC24_GET_SCHEDULAR_STAT = 0x1E,
IOCTL_NWC24_SET_FILTER_MODE = 0x1F,
IOCTL_NWC24_SET_DEBUG_MODE = 0x20,
IOCTL_NWC24_KD_SET_NEXT_WAKEUP = 0x21,
IOCTL_NWC24_SET_SCRIPT_MODE = 0x22,
IOCTL_NWC24_REQUEST_SHUTDOWN = 0x28,
};
enum {
MODEL_RVT = 0,
MODEL_RVV = 0,
@ -432,15 +432,16 @@ private:
MODEL_RVD = 2,
MODEL_ELSE = 7
};
u8 GetAreaCode(const char * area);
u8 GetHardwareModel(const char * model);
s32 NWC24MakeUserID(u64* nwc24_id, u32 hollywood_id, u16 id_ctr, u8 hardware_model, u8 area_code);
NWC24Config config;
};
//////////////////////////////////////////////////////////////////////////
class CWII_IPC_HLE_Device_net_kd_time : public IWII_IPC_HLE_Device
{
@ -457,14 +458,14 @@ public:
virtual bool Open(u32 _CommandAddress, u32 _Mode)
{
INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Open");
INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Open");
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
return true;
}
virtual bool Close(u32 _CommandAddress, bool _bForce)
{
INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Close");
INFO_LOG(WII_IPC_NET, "NET_KD_TIME: Close");
if (!_bForce)
Memory::Write_U32(0, _CommandAddress + 4);
return true;
@ -472,9 +473,9 @@ public:
virtual bool IOCtl(u32 _CommandAddress)
{
u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
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);
@ -483,8 +484,8 @@ public:
// TODO Writes stuff to /shared2/nwc24/misc.bin
u32 update_misc = 0;
switch (Parameter)
{
switch (Parameter)
{
case IOCTL_NW24_GET_UNIVERSAL_TIME:
Memory::Write_U64(GetAdjustedUTC(), BufferOut + 4);
break;
@ -494,7 +495,7 @@ public:
update_misc = Memory::Read_U32(BufferIn + 8);
break;
case IOCTL_NW24_SET_RTC_COUNTER:
case IOCTL_NW24_SET_RTC_COUNTER:
rtc = Memory::Read_U32(BufferIn);
update_misc = Memory::Read_U32(BufferIn + 4);
break;
@ -507,11 +508,11 @@ public:
result = -9;
break;
default:
default:
ERROR_LOG(WII_IPC_NET, "%s - unknown IOCtl: %x\n",
GetDeviceName().c_str(), Parameter);
break;
}
break;
}
// write return values
Memory::Write_U32(common_result, BufferOut);
@ -520,14 +521,14 @@ public:
}
private:
enum
{
enum
{
IOCTL_NW24_GET_UNIVERSAL_TIME = 0x14,
IOCTL_NW24_SET_UNIVERSAL_TIME = 0x15,
IOCTL_NW24_UNIMPLEMENTED = 0x16,
IOCTL_NW24_SET_RTC_COUNTER = 0x17,
IOCTL_NW24_GET_TIME_DIFF = 0x18,
};
};
u64 rtc;
s64 utcdiff;
@ -550,6 +551,75 @@ private:
}
};
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];
};
enum NET_IOCTL
{
IOCTL_SO_ACCEPT = 1,
IOCTL_SO_BIND,
IOCTL_SO_CLOSE,
IOCTL_SO_CONNECT,
IOCTL_SO_FCNTL,
IOCTL_SO_GETPEERNAME,
IOCTL_SO_GETSOCKNAME,
IOCTL_SO_GETSOCKOPT,
IOCTL_SO_SETSOCKOPT,
IOCTL_SO_LISTEN,
IOCTL_SO_POLL,
IOCTLV_SO_RECVFROM,
IOCTLV_SO_SENDTO,
IOCTL_SO_SHUTDOWN,
IOCTL_SO_SOCKET,
IOCTL_SO_GETHOSTID,
IOCTL_SO_GETHOSTBYNAME,
IOCTL_SO_GETHOSTBYADDR,
IOCTLV_SO_GETNAMEINFO,
IOCTL_SO_UNK14,
IOCTL_SO_INETATON,
IOCTL_SO_INETPTON,
IOCTL_SO_INETNTOP,
IOCTLV_SO_GETADDRINFO,
IOCTL_SO_SOCKATMARK,
IOCTLV_SO_UNK1A,
IOCTLV_SO_UNK1B,
IOCTLV_SO_GETINTERFACEOPT,
IOCTLV_SO_SETINTERFACEOPT,
IOCTL_SO_SETINTERFACE,
IOCTL_SO_STARTUP,
IOCTL_SO_ICMPSOCKET = 0x30,
IOCTLV_SO_ICMPPING,
IOCTL_SO_ICMPCANCEL,
IOCTL_SO_ICMPCLOSE
};
//////////////////////////////////////////////////////////////////////////
class CWII_IPC_HLE_Device_net_ip_top : public IWII_IPC_HLE_Device
{
@ -562,51 +632,13 @@ public:
virtual bool Close(u32 _CommandAddress, bool _bForce);
virtual bool IOCtl(u32 _CommandAddress);
virtual bool IOCtlV(u32 _CommandAddress);
virtual u32 Update();
private:
#ifdef _WIN32
WSADATA InitData;
#endif
enum
{
IOCTL_SO_ACCEPT = 1,
IOCTL_SO_BIND,
IOCTL_SO_CLOSE,
IOCTL_SO_CONNECT,
IOCTL_SO_FCNTL,
IOCTL_SO_GETPEERNAME,
IOCTL_SO_GETSOCKNAME,
IOCTL_SO_GETSOCKOPT,
IOCTL_SO_SETSOCKOPT,
IOCTL_SO_LISTEN,
IOCTL_SO_POLL,
IOCTLV_SO_RECVFROM,
IOCTLV_SO_SENDTO,
IOCTL_SO_SHUTDOWN,
IOCTL_SO_SOCKET,
IOCTL_SO_GETHOSTID,
IOCTL_SO_GETHOSTBYNAME,
IOCTL_SO_GETHOSTBYADDR,
IOCTLV_SO_GETNAMEINFO,
IOCTL_SO_UNK14,
IOCTL_SO_INETATON,
IOCTL_SO_INETPTON,
IOCTL_SO_INETNTOP,
IOCTLV_SO_GETADDRINFO,
IOCTL_SO_SOCKATMARK,
IOCTLV_SO_UNK1A,
IOCTLV_SO_UNK1B,
IOCTLV_SO_GETINTERFACEOPT,
IOCTLV_SO_SETINTERFACEOPT,
IOCTL_SO_SETINTERFACE,
IOCTL_SO_STARTUP,
IOCTL_SO_ICMPSOCKET = 0x30,
IOCTLV_SO_ICMPPING,
IOCTL_SO_ICMPCANCEL,
IOCTL_SO_ICMPCLOSE
};
u32 ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize);
u32 ExecuteCommandV(SIOCtlVBuffer& CommandBuffer);
};
@ -628,7 +660,7 @@ private:
enum
{
IOCTLV_NCD_LOCKWIRELESSDRIVER = 0x1, // NCDLockWirelessDriver
IOCTLV_NCD_UNLOCKWIRELESSDRIVER = 0x2, // NCDUnlockWirelessDriver
IOCTLV_NCD_UNLOCKWIRELESSDRIVER = 0x2, // NCDUnlockWirelessDriver
IOCTLV_NCD_GETCONFIG = 0x3, // NCDiGetConfig
IOCTLV_NCD_SETCONFIG = 0x4, // NCDiSetConfig
IOCTLV_NCD_READCONFIG = 0x5,
@ -687,7 +719,7 @@ private:
SCAN_PASSIVE
};
#pragma pack(push, 1)
#pragma pack(push, 1)
struct ScanInfo
{
u16 channel_bitmap;
@ -731,7 +763,7 @@ private:
char wlversion[0x50];
u8 unk[0x30];
};
#pragma pack(pop)
#pragma pack(pop)
};
#endif

View File

@ -17,14 +17,17 @@
#include "FileUtil.h"
#include "WII_IPC_HLE_Device_net_ssl.h"
#include "WII_Socket.h"
#include "../Debugger/Debugger_SymbolMap.h"
WII_SSL CWII_IPC_HLE_Device_net_ssl::_SSL[NET_SSL_MAXINSTANCES];
CWII_IPC_HLE_Device_net_ssl::CWII_IPC_HLE_Device_net_ssl(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{
for (int i = 0; i < NET_SSL_MAXINSTANCES; ++i)
{
memset(&_SSL[i], 0, sizeof(struct _SSL));
memset(&_SSL[i], 0, sizeof(WII_SSL));
}
}
@ -45,7 +48,7 @@ CWII_IPC_HLE_Device_net_ssl::~CWII_IPC_HLE_Device_net_ssl()
memset(&_SSL[i].ctx, 0, sizeof(ssl_context));
memset(&_SSL[i].session, 0, sizeof(ssl_session));
memset(&_SSL[i].hs, 0, sizeof(havege_state));
memset(_SSL[i].hostname, 0, MAX_HOSTNAME_LEN);
memset(_SSL[i].hostname, 0, NET_SSL_MAX_HOSTNAME_LEN);
_SSL[i].active = false;
}
@ -94,16 +97,7 @@ bool CWII_IPC_HLE_Device_net_ssl::IOCtl(u32 _CommandAddress)
return true;
}
bool CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress)
{
u32 ReturnValue = 0;
SIOCtlVBuffer CommandBuffer(_CommandAddress);
ReturnValue = ExecuteCommandV(CommandBuffer.Parameter, CommandBuffer);
Memory::Write_U32(ReturnValue, _CommandAddress+4);
return true;
}
static int
_verify_certificate_callback (void *data, x509_cert *crt, int depth, int *flags)
@ -145,14 +139,17 @@ _verify_certificate_callback (void *data, x509_cert *crt, int depth, int *flags)
return( 0 );
}
u32 CWII_IPC_HLE_Device_net_ssl::ExecuteCommandV(u32 _Parameter, SIOCtlVBuffer CommandBuffer)
{
bool CWII_IPC_HLE_Device_net_ssl::IOCtlV(u32 _CommandAddress)
{
u32 ReturnValue = 0;
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)
@ -173,26 +170,26 @@ u32 CWII_IPC_HLE_Device_net_ssl::ExecuteCommandV(u32 _Parameter, SIOCtlVBuffer C
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;
}
switch (_Parameter)
switch (CommandBuffer.Parameter)
{
case IOCTLV_NET_SSL_NEW:
{
int verifyOption = Memory::Read_U32(_BufferOut);
const char * hostname = (const char*) Memory::GetPointer(_BufferOut2);
int verifyOption = Memory::Read_U32(BufferOut);
const char * hostname = (const char*) Memory::GetPointer(BufferOut2);
int freeSSL = this->getSSLFreeID();
if (freeSSL)
@ -221,8 +218,8 @@ u32 CWII_IPC_HLE_Device_net_ssl::ExecuteCommandV(u32 _Parameter, SIOCtlVBuffer C
ssl_set_authmode(&_SSL[sslID].ctx, SSL_VERIFY_OPTIONAL);
ssl_set_renegotiation(&_SSL[sslID].ctx, SSL_RENEGOTIATION_ENABLED);
memcpy(_SSL[sslID].hostname, hostname, min((int)BufferOutSize2, MAX_HOSTNAME_LEN));
_SSL[sslID].hostname[MAX_HOSTNAME_LEN-1] = '\0';
memcpy(_SSL[sslID].hostname, hostname, min((int)BufferOutSize2, NET_SSL_MAX_HOSTNAME_LEN));
_SSL[sslID].hostname[NET_SSL_MAX_HOSTNAME_LEN-1] = '\0';
ssl_set_hostname(&_SSL[sslID].ctx, _SSL[sslID].hostname);
_SSL[sslID].active = true;
@ -240,13 +237,13 @@ _SSL_NEW_ERROR:
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
verifyOption, hostname,
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_SHUTDOWN:
{
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
ssl_close_notify(&_SSL[sslID].ctx);
@ -259,7 +256,7 @@ _SSL_NEW_ERROR:
memset(&_SSL[sslID].ctx, 0, sizeof(ssl_context));
memset(&_SSL[sslID].session, 0, sizeof(ssl_session));
memset(&_SSL[sslID].hs, 0, sizeof(havege_state));
memset(_SSL[sslID].hostname, 0, MAX_HOSTNAME_LEN);
memset(_SSL[sslID].hostname, 0, NET_SSL_MAX_HOSTNAME_LEN);
_SSL[sslID].active = false;
@ -274,8 +271,8 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_SETROOTCA:
@ -285,16 +282,16 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
int ret = x509parse_crt_der(
&_SSL[sslID].cacert,
Memory::GetPointer(_BufferOut2),
Memory::GetPointer(BufferOut2),
BufferOutSize2);
if (ret)
@ -322,10 +319,10 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
std::string cert_base_path(File::GetUserPath(D_WIIUSER_IDX));
@ -361,10 +358,10 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
x509_free(&_SSL[sslID].clicert);
@ -384,7 +381,7 @@ _SSL_NEW_ERROR:
}
case IOCTLV_NET_SSL_SETBUILTINROOTCA:
{
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
std::string cert_base_path(File::GetUserPath(D_WIIUSER_IDX));
@ -411,16 +408,16 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_CONNECT:
{
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
_SSL[sslID].sockfd = Memory::Read_U32(_BufferOut2);
_SSL[sslID].sockfd = Memory::Read_U32(BufferOut2);
WARN_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_CONNECT socket = %d", _SSL[sslID].sockfd);
ssl_set_bio(&_SSL[sslID].ctx, net_recv, &_SSL[sslID].sockfd, net_send, &_SSL[sslID].sockfd);
Memory::Write_U32(SSL_OK, _BufferIn);
@ -434,77 +431,33 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_DOHANDSHAKE:
{
int ret = 0;
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
ret = ssl_handshake(&_SSL[sslID].ctx);
switch (ret)
{
case 0:
Memory::Write_U32(SSL_OK, _BufferIn);
break;
case POLARSSL_ERR_NET_WANT_READ:
Memory::Write_U32(SSL_ERR_RAGAIN, _BufferIn);
break;
case POLARSSL_ERR_NET_WANT_WRITE:
Memory::Write_U32(SSL_ERR_WAGAIN, _BufferIn);
break;
default:
Memory::Write_U32(SSL_ERR_FAILED, _BufferIn);
break;
}
WiiSockMan &sm = WiiSockMan::getInstance();
sm.doSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_DOHANDSHAKE);
return false;
}
else
{
Memory::Write_U32(SSL_ERR_ID, _BufferIn);
}
WARN_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) "
"BufferIn: (%08x, %i), BufferIn2: (%08x, %i), "
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
ret,
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_WRITE:
{
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
int ret = ssl_write( &_SSL[sslID].ctx, Memory::GetPointer(_BufferOut2), BufferOutSize2);
#ifdef DEBUG_SSL
File::IOFile("ssl_write.bin", "ab").WriteBytes(Memory::GetPointer(_BufferOut2), BufferOutSize2);
#endif
if (ret >= 0)
{
// Return bytes written or SSL_ERR_ZERO if none
Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, _BufferIn);
}
else
{
switch (ret)
{
case POLARSSL_ERR_NET_WANT_READ:
Memory::Write_U32(SSL_ERR_RAGAIN, _BufferIn);
break;
case POLARSSL_ERR_NET_WANT_WRITE:
Memory::Write_U32(SSL_ERR_WAGAIN, _BufferIn);
break;
default:
Memory::Write_U32(SSL_ERR_FAILED, _BufferIn);
break;
}
}
WiiSockMan &sm = WiiSockMan::getInstance();
sm.doSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_WRITE);
return false;
}
else
{
@ -515,45 +468,21 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
WARN_LOG(WII_IPC_SSL, "%s", Memory::GetPointer(_BufferOut2));
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
WARN_LOG(WII_IPC_SSL, "%s", Memory::GetPointer(BufferOut2));
break;
}
case IOCTLV_NET_SSL_READ:
{
int ret = 0;
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
ret = ssl_read( &_SSL[sslID].ctx, Memory::GetPointer(_BufferIn2), BufferInSize2);
#ifdef DEBUG_SSL
if (ret > 0)
{
File::IOFile("ssl_read.bin", "ab").WriteBytes(Memory::GetPointer(_BufferIn2), ret);
}
#endif
if (ret >= 0)
{
// Return bytes read or SSL_ERR_ZERO if none
Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, _BufferIn);
}
else
{
switch (ret)
{
case POLARSSL_ERR_NET_WANT_READ:
Memory::Write_U32(SSL_ERR_RAGAIN, _BufferIn);
break;
case POLARSSL_ERR_NET_WANT_WRITE:
Memory::Write_U32(SSL_ERR_WAGAIN, _BufferIn);
break;
default:
Memory::Write_U32(SSL_ERR_FAILED, _BufferIn);
break;
}
}
WiiSockMan &sm = WiiSockMan::getInstance();
sm.doSock(_SSL[sslID].sockfd, _CommandAddress, IOCTLV_NET_SSL_READ);
return false;
}
else
{
@ -566,13 +495,13 @@ _SSL_NEW_ERROR:
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
ret,
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_SETROOTCADEFAULT:
{
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
Memory::Write_U32(SSL_OK, _BufferIn);
@ -586,8 +515,8 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
case IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT:
@ -597,13 +526,13 @@ _SSL_NEW_ERROR:
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
int sslID = Memory::Read_U32(_BufferOut) - 1;
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
Memory::Write_U32(SSL_OK, _BufferIn);
Memory::Write_U32(SSL_OK, _BufferIn);
}
else
{
@ -616,22 +545,24 @@ _SSL_NEW_ERROR:
"BufferIn: (%08x, %i), BufferIn2: (%08x, %i), "
"BufferIn3: (%08x, %i), BufferOut: (%08x, %i), "
"BufferOut2: (%08x, %i), BufferOut3: (%08x, %i)",
_Parameter,
CommandBuffer.Parameter,
_BufferIn, BufferInSize, _BufferIn2, BufferInSize2,
_BufferIn3, BufferInSize3, _BufferOut, BufferOutSize,
_BufferOut2, BufferOutSize2, _BufferOut3, BufferOutSize3);
_BufferIn3, BufferInSize3, BufferOut, BufferOutSize,
BufferOut2, BufferOutSize2, BufferOut3, BufferOutSize3);
break;
}
return returnValue;
Memory::Write_U32(ReturnValue, _CommandAddress+4);
return true;
}
u32 CWII_IPC_HLE_Device_net_ssl::ExecuteCommand(u32 _Command,
u32 _BufferIn, u32 BufferInSize,
u32 _BufferOut, u32 BufferOutSize)
u32 BufferOut, u32 BufferOutSize)
{
WARN_LOG(WII_IPC_SSL, "%s unknown %i "
"(BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
GetDeviceName().c_str(), _Command,
_BufferIn, BufferInSize, _BufferOut, BufferOutSize);
_BufferIn, BufferInSize, BufferOut, BufferOutSize);
return 0;
}

View File

@ -24,10 +24,60 @@
#include <polarssl/ssl.h>
#include <polarssl/havege.h>
#define MAX_HOSTNAME_LEN 256
#define NET_SSL_MAX_HOSTNAME_LEN 256
#define NET_SSL_MAXINSTANCES 4
#define SSLID_VALID(x) (x >= 0 && x < NET_SSL_MAXINSTANCES && _SSL[x].active)
#define SSLID_VALID(x) (x >= 0 && x < NET_SSL_MAXINSTANCES && CWII_IPC_HLE_Device_net_ssl::_SSL[x].active)
enum ssl_err_t
{
SSL_OK = 0,
SSL_ERR_FAILED = -1,
SSL_ERR_RAGAIN = -2,
SSL_ERR_WAGAIN = -3,
SSL_ERR_SYSCALL = -5,
SSL_ERR_ZERO = -6, // read or write returned 0
SSL_ERR_CAGAIN = -7, // BIO not connected
SSL_ERR_ID = -8, // invalid SSL id
SSL_ERR_VCOMMONNAME = -9, // verify failed: common name
SSL_ERR_VROOTCA = -10, // verify failed: root ca
SSL_ERR_VCHAIN = -11, // verify failed: certificate chain
SSL_ERR_VDATE = -12, // verify failed: date invalid
SSL_ERR_SERVER_CERT = -13, // certificate cert invalid
};
enum SSL_IOCTL
{
IOCTLV_NET_SSL_NEW = 0x01,
IOCTLV_NET_SSL_CONNECT = 0x02,
IOCTLV_NET_SSL_DOHANDSHAKE = 0x03,
IOCTLV_NET_SSL_READ = 0x04,
IOCTLV_NET_SSL_WRITE = 0x05,
IOCTLV_NET_SSL_SHUTDOWN = 0x06,
IOCTLV_NET_SSL_SETCLIENTCERT = 0x07,
IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT = 0x08,
IOCTLV_NET_SSL_REMOVECLIENTCERT = 0x09,
IOCTLV_NET_SSL_SETROOTCA = 0x0A,
IOCTLV_NET_SSL_SETROOTCADEFAULT = 0x0B,
IOCTLV_NET_SSL_DOHANDSHAKEEX = 0x0C,
IOCTLV_NET_SSL_SETBUILTINROOTCA = 0x0D,
IOCTLV_NET_SSL_SETBUILTINCLIENTCERT = 0x0E,
IOCTLV_NET_SSL_DISABLEVERIFYOPTIONFORDEBUG = 0x0F,
IOCTLV_NET_SSL_DEBUGGETVERSION = 0x14,
IOCTLV_NET_SSL_DEBUGGETTIME = 0x15,
};
typedef struct {
ssl_context ctx;
ssl_session session;
havege_state hs;
x509_cert cacert;
x509_cert clicert;
rsa_context rsa;
int sockfd;
char hostname[NET_SSL_MAX_HOSTNAME_LEN];
bool active;
} WII_SSL;
class CWII_IPC_HLE_Device_net_ssl : public IWII_IPC_HLE_Device
{
@ -44,58 +94,11 @@ public:
virtual bool IOCtl(u32 _CommandAddress);
virtual bool IOCtlV(u32 _CommandAddress);
int getSSLFreeID();
static WII_SSL _SSL[NET_SSL_MAXINSTANCES];
private:
struct _SSL{
ssl_context ctx;
ssl_session session;
havege_state hs;
x509_cert cacert;
x509_cert clicert;
rsa_context rsa;
int sockfd;
char hostname[MAX_HOSTNAME_LEN];
bool active;
} _SSL[NET_SSL_MAXINSTANCES];
enum
{
IOCTLV_NET_SSL_NEW = 0x01,
IOCTLV_NET_SSL_CONNECT = 0x02,
IOCTLV_NET_SSL_DOHANDSHAKE = 0x03,
IOCTLV_NET_SSL_READ = 0x04,
IOCTLV_NET_SSL_WRITE = 0x05,
IOCTLV_NET_SSL_SHUTDOWN = 0x06,
IOCTLV_NET_SSL_SETCLIENTCERT = 0x07,
IOCTLV_NET_SSL_SETCLIENTCERTDEFAULT = 0x08,
IOCTLV_NET_SSL_REMOVECLIENTCERT = 0x09,
IOCTLV_NET_SSL_SETROOTCA = 0x0A,
IOCTLV_NET_SSL_SETROOTCADEFAULT = 0x0B,
IOCTLV_NET_SSL_DOHANDSHAKEEX = 0x0C,
IOCTLV_NET_SSL_SETBUILTINROOTCA = 0x0D,
IOCTLV_NET_SSL_SETBUILTINCLIENTCERT = 0x0E,
IOCTLV_NET_SSL_DISABLEVERIFYOPTIONFORDEBUG = 0x0F,
IOCTLV_NET_SSL_DEBUGGETVERSION = 0x14,
IOCTLV_NET_SSL_DEBUGGETTIME = 0x15,
};
enum ssl_err_t
{
SSL_OK = 0,
SSL_ERR_FAILED = -1,
SSL_ERR_RAGAIN = -2,
SSL_ERR_WAGAIN = -3,
SSL_ERR_SYSCALL = -5,
SSL_ERR_ZERO = -6, // read or write returned 0
SSL_ERR_CAGAIN = -7, // BIO not connected
SSL_ERR_ID = -8, // invalid SSL id
SSL_ERR_VCOMMONNAME = -9, // verify failed: common name
SSL_ERR_VROOTCA = -10, // verify failed: root ca
SSL_ERR_VCHAIN = -11, // verify failed: certificate chain
SSL_ERR_VDATE = -12, // verify failed: date invalid
SSL_ERR_SERVER_CERT = -13, // certificate cert invalid
};
u32 ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize);
u32 ExecuteCommandV(u32 _Parameter, SIOCtlVBuffer CommandBuffer);

View File

@ -0,0 +1,615 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "WII_Socket.h"
#include "WII_IPC_HLE.h"
#include "WII_IPC_HLE_Device.h"
using WII_IPC_HLE_Interface::ECommandType;
using WII_IPC_HLE_Interface::COMMAND_IOCTL;
using WII_IPC_HLE_Interface::COMMAND_IOCTLV;
#ifdef _WIN32
#define ERRORCODE(name) WSA ## name
#define EITHER(win32, posix) win32
#else
#define ERRORCODE(name) name
#define EITHER(win32, posix) posix
#endif
char* WiiSockMan::DecodeError(s32 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)
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)Message, 1024, NULL);
return Message;
#else
return strerror(ErrorCode);
#endif
}
s32 WiiSockMan::getNetErrorCode(s32 ret, std::string caller, bool isRW)
{
#ifdef _WIN32
s32 errorCode = WSAGetLastError();
#else
s32 errorCode = errno;
#endif
if (ret >= 0)
return ret;
WARN_LOG(WII_IPC_NET, "%s failed with error %d: %s, ret= %d",
caller.c_str(), errorCode, DecodeError(errorCode), ret);
switch (errorCode)
{
case ERRORCODE(EMSGSIZE):
ERROR_LOG(WII_IPC_NET, "Find out why this happened, looks like PEEK failure?");
return -1; // Should be -SO_EMSGSIZE
case EITHER(WSAENOTSOCK, EBADF):
return -SO_EBADF;
case ERRORCODE(EADDRINUSE):
return -SO_EADDRINUSE;
case ERRORCODE(ECONNRESET):
return -SO_ECONNRESET;
case ERRORCODE(EISCONN):
return -SO_EISCONN;
case ERRORCODE(ENOTCONN):
return -SO_EAGAIN; // After proper blocking SO_EAGAIN shouldn't be needed...
case ERRORCODE(EINPROGRESS):
return -SO_EINPROGRESS;
case ERRORCODE(EALREADY):
return -SO_EALREADY;
case ERRORCODE(EACCES):
return -SO_EACCES;
case EITHER(WSAEWOULDBLOCK, EAGAIN):
if(isRW){
return -SO_EAGAIN; // EAGAIN
}else{
return -SO_EINPROGRESS; // EINPROGRESS
}
// TODO: remove as this should no longer be a problem once blocking is supported.
case EITHER(WSA_INVALID_HANDLE, EBADF):
return -SO_EINPROGRESS; // EINPROGRESS
default:
return -1;
}
}
WiiSocket::~WiiSocket()
{
if (fd >= 0)
{
(void)closeFd();
}
}
void WiiSocket::setFd(s32 s)
{
if (fd >= 0)
(void)closeFd();
nonBlock = false;
fd = s;
// TODO: Remove on completion of async
#ifdef _WIN32
u_long iMode = 1;
int ioctlret = ioctlsocket(fd, FIONBIO, &iMode);
u32 millis = 3000;
#else
int flags;
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
struct timeval millis;
millis.tv_sec = 3;
millis.tv_usec = 0;
#endif
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&millis,sizeof(millis));
}
s32 WiiSocket::closeFd()
{
s32 ReturnValue = 0;
if (fd >= 0)
{
#ifdef _WIN32
s32 ret = closesocket(fd);
#else
s32 ret = close(sock);
#endif
ReturnValue = WiiSockMan::getNetErrorCode(ret, "delSocket", false);
}
else
{
ReturnValue = WiiSockMan::getNetErrorCode(EITHER(WSAENOTSOCK, EBADF), "delSocket", false);
}
fd = -1;
return ReturnValue;
}
s32 WiiSocket::_connect(sockaddr_in* name, s32 namelen)
{
int ret = connect(fd, (sockaddr*)name, namelen);
ret = WiiSockMan::getNetErrorCode(ret, "SO_CONNECT", false);
WARN_LOG(WII_IPC_NET,"IOCTL_SO_CONNECT (%08x, %s:%d)",
fd, inet_ntoa(name->sin_addr), Common::swap16(name->sin_port));
return ret;
}
s32 WiiSocket::_bind(sockaddr_in* name, s32 namelen)
{
int ret = bind(fd, (sockaddr*)name, namelen);
ret = WiiSockMan::getNetErrorCode(ret, "SO_BIND", false);
WARN_LOG(WII_IPC_NET, "IOCTL_SO_BIND (%08X %s:%d) = %d ", fd,
inet_ntoa(name->sin_addr), Common::swap16(name->sin_port), ret);
return ret;
}
s32 WiiSocket::_fcntl(u32 cmd, u32 arg)
{
#define F_GETFL 3
#define F_SETFL 4
#define F_NONBLOCK 4
s32 ret = 0;
if (cmd == F_GETFL)
{
ret = nonBlock ? F_NONBLOCK : 0;
}
else if (cmd == F_SETFL)
{
nonBlock = (arg & F_NONBLOCK) == F_NONBLOCK;
}
else
{
ERROR_LOG(WII_IPC_NET, "SO_FCNTL unknown command");
}
WARN_LOG(WII_IPC_NET, "IOCTL_SO_FCNTL(%08x, %08X, %08X)",
fd, cmd, arg);
return ret;
}
void WiiSocket::update(bool read, bool write, bool except)
{
auto it = pending_sockops.begin();
while (it != pending_sockops.end())
{
s32 ReturnValue = 0;
bool forceNonBlock = false;
ECommandType ct = static_cast<ECommandType>(Memory::Read_U32(it->_CommandAddress));
if (!it->is_ssl && ct == COMMAND_IOCTL)
{
u32 BufferIn = Memory::Read_U32(it->_CommandAddress + 0x10);
switch(it->net_type)
{
case IOCTL_SO_FCNTL:
{
u32 cmd = Memory::Read_U32(BufferIn + 4);
u32 arg = Memory::Read_U32(BufferIn + 8);
ReturnValue = _fcntl(cmd, arg);
break;
}
case IOCTL_SO_BIND:
{
//TODO: tidy
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(&address, sizeof(address));
break;
}
case IOCTL_SO_CONNECT:
{
//struct sockaddr_in echoServAddr;
u32 has_addr = Memory::Read_U32(BufferIn + 0x04);
sockaddr_in serverAddr;
u8 addr[28];
Memory::ReadBigEData(addr, BufferIn + 0x08, sizeof(addr));
if (has_addr != 1)
{
ReturnValue = -1;
break;
}
memset(&serverAddr, 0, sizeof(serverAddr));
memcpy(&serverAddr, addr, addr[0]);
// GC/Wii sockets have a length param as well, we dont really care :)
serverAddr.sin_family = serverAddr.sin_family >> 8;
ReturnValue = _connect(&serverAddr, sizeof(serverAddr));
break;
}
default:
break;
}
// Fix blocking error codes
if (!nonBlock)
{
if (it->net_type == IOCTL_SO_CONNECT
&& ReturnValue == -SO_EISCONN)
{
ReturnValue = SO_SUCCESS;
}
}
}
else if (ct == COMMAND_IOCTLV)
{
SIOCtlVBuffer CommandBuffer(it->_CommandAddress);
u32 BufferIn = 0, BufferIn2 = 0;
u32 BufferInSize = 0, BufferInSize2 = 0;
u32 BufferOut = 0, BufferOut2 = 0;
u32 BufferOutSize = 0, BufferOutSize2 = 0;
if (CommandBuffer.InBuffer.size() > 0)
{
BufferIn = CommandBuffer.InBuffer.at(0).m_Address;
BufferInSize = CommandBuffer.InBuffer.at(0).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.InBuffer.size() > 1)
{
BufferIn2 = CommandBuffer.InBuffer.at(1).m_Address;
BufferInSize2 = CommandBuffer.InBuffer.at(1).m_Size;
}
if (it->is_ssl)
{
int sslID = Memory::Read_U32(BufferOut) - 1;
if (SSLID_VALID(sslID))
{
switch(it->ssl_type)
{
case IOCTLV_NET_SSL_DOHANDSHAKE:
{
int ret = ssl_handshake(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx);
switch (ret)
{
case 0:
Memory::Write_U32(SSL_OK, BufferIn);
break;
case POLARSSL_ERR_NET_WANT_READ:
Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn);
if (!nonBlock)
ReturnValue = SSL_ERR_RAGAIN;
break;
case POLARSSL_ERR_NET_WANT_WRITE:
Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn);
if (!nonBlock)
ReturnValue = SSL_ERR_WAGAIN;
break;
default:
Memory::Write_U32(SSL_ERR_FAILED, BufferIn);
break;
}
WARN_LOG(WII_IPC_SSL, "IOCTLV_NET_SSL_DOHANDSHAKE = (%d) "
"BufferIn: (%08x, %i), BufferIn2: (%08x, %i), "
"BufferOut: (%08x, %i), BufferOut2: (%08x, %i)",
ret,
BufferIn, BufferInSize, BufferIn2, BufferInSize2,
BufferOut, BufferOutSize, BufferOut2, BufferOutSize2);
break;
}
case IOCTLV_NET_SSL_WRITE:
{
int ret = ssl_write(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferOut2), BufferOutSize2);
#ifdef DEBUG_SSL
File::IOFile("ssl_write.bin", "ab").WriteBytes(Memory::GetPointer(BufferOut2), BufferOutSize2);
#endif
if (ret >= 0)
{
// Return bytes written or SSL_ERR_ZERO if none
Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
}
else
{
switch (ret)
{
case POLARSSL_ERR_NET_WANT_READ:
Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn);
if (!nonBlock)
ReturnValue = SSL_ERR_RAGAIN;
break;
case POLARSSL_ERR_NET_WANT_WRITE:
Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn);
if (!nonBlock)
ReturnValue = SSL_ERR_WAGAIN;
break;
default:
Memory::Write_U32(SSL_ERR_FAILED, BufferIn);
break;
}
}
break;
}
case IOCTLV_NET_SSL_READ:
{
int ret = ssl_read(&CWII_IPC_HLE_Device_net_ssl::_SSL[sslID].ctx, Memory::GetPointer(BufferIn2), BufferInSize2);
#ifdef DEBUG_SSL
if (ret > 0)
{
File::IOFile("ssl_read.bin", "ab").WriteBytes(Memory::GetPointer(_BufferIn2), ret);
}
#endif
if (ret >= 0)
{
// Return bytes read or SSL_ERR_ZERO if none
Memory::Write_U32((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
}
else
{
switch (ret)
{
case POLARSSL_ERR_NET_WANT_READ:
Memory::Write_U32(SSL_ERR_RAGAIN, BufferIn);
if (!nonBlock)
ReturnValue = SSL_ERR_RAGAIN;
break;
case POLARSSL_ERR_NET_WANT_WRITE:
Memory::Write_U32(SSL_ERR_WAGAIN, BufferIn);
if (!nonBlock)
ReturnValue = SSL_ERR_WAGAIN;
break;
default:
Memory::Write_U32(SSL_ERR_FAILED, BufferIn);
break;
}
}
break;
}
default:
break;
}
}
else
{
Memory::Write_U32(SSL_ERR_ID, BufferIn);
}
}
else
{
switch (it->net_type)
{
case IOCTLV_SO_SENDTO:
{
char * data = (char*)Memory::GetPointer(BufferIn);
u32 flags = Common::swap32(BufferIn2 + 0x04);
u32 has_destaddr = Common::swap32(BufferIn2 + 0x08);
// Act as non blocking when SO_MSG_NONBLOCK is specified
forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK);
// send/sendto only handles PEEK
flags &= SO_MSG_PEEK | SO_MSG_OOB;
u8 destaddr[28];
struct sockaddr_in* addr = (struct sockaddr_in*)&destaddr;
if (has_destaddr)
{
Memory::ReadBigEData((u8*)&destaddr, BufferIn2 + 0x0C, BufferInSize2 - 0x0C);
addr->sin_family = addr->sin_family >> 8;
}
int ret = sendto(fd, data, BufferInSize, flags,
has_destaddr ? (struct sockaddr*)addr : NULL,
has_destaddr ? sizeof(sockaddr) : 0);
ReturnValue = WiiSockMan::getNetErrorCode(ret, "SO_SENDTO", true);
WARN_LOG(WII_IPC_NET,
"%s = %d Socket: %08x, BufferIn: (%08x, %i), BufferIn2: (%08x, %i), %u.%u.%u.%u",
has_destaddr ? "IOCTLV_SO_SENDTO " : "IOCTLV_SO_SEND ",
ReturnValue, fd, 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
);
break;
}
case IOCTLV_SO_RECVFROM:
{
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);
}
// Act as non blocking when SO_MSG_NONBLOCK is specified
forceNonBlock = ((flags & SO_MSG_NONBLOCK) == SO_MSG_NONBLOCK);
// recv/recvfrom only handles PEEK
flags &= SO_MSG_PEEK | SO_MSG_OOB;
#ifdef _WIN32
if(flags & MSG_PEEK){
unsigned long totallen = 0;
ioctlsocket(sock, FIONREAD, &totallen);
ReturnValue = totallen;
break;
}
#endif
int ret = recvfrom(sock, buf, len, flags,
fromlen ? (struct sockaddr*) &addr : NULL,
fromlen ? &fromlen : 0);
ReturnValue = WiiSockMan::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 ",
ReturnValue, 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);
}
break;
}
default:
break;
}
}
}
if ( nonBlock || forceNonBlock
|| (!it->is_ssl && ReturnValue != -SO_EAGAIN && ReturnValue != -SO_EINPROGRESS && ReturnValue != -SO_EALREADY)
|| (it->is_ssl && ReturnValue != SSL_ERR_WAGAIN && ReturnValue != SSL_ERR_RAGAIN))
{
WARN_LOG(WII_IPC_NET, "IOCTL(V) Sock: %d ioctl/v: %d returned: %d nonBlock: %d forceNonBlock: %d",
fd, it->is_ssl ? it->ssl_type : it->net_type, ReturnValue, nonBlock, forceNonBlock);
WiiSockMan::EnqueueReply(it->_CommandAddress, ReturnValue);
it = pending_sockops.erase(it);
}
else
{
++it;
}
}
}
void WiiSocket::doSock(u32 _CommandAddress, NET_IOCTL type)
{
sockop so = {_CommandAddress, false};
so.net_type = type;
pending_sockops.push_back(so);
}
void WiiSocket::doSock(u32 _CommandAddress, SSL_IOCTL type)
{
sockop so = {_CommandAddress, true};
so.ssl_type = type;
pending_sockops.push_back(so);
}
s32 WiiSockMan::newSocket(s32 af, s32 type, s32 protocol)
{
s32 s = (s32)socket(af, type, protocol);
s32 ret = getNetErrorCode(s, "newSocket", false);
if (ret >= 0)
{
WiiSocket& sock = WiiSockets[ret];
sock.setFd(ret);
}
return ret;
}
s32 WiiSockMan::delSocket(s32 s)
{
s32 ReturnValue = WiiSockets[s].closeFd();
WiiSockets.erase(s);
return ReturnValue;
}
void WiiSockMan::Update()
{
s32 nfds = 0;
fd_set read_fds, write_fds, except_fds;
struct timeval t = {0,0};
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
for (auto it = WiiSockets.begin(); it != WiiSockets.end(); ++it)
{
WiiSocket& sock = it->second;
if (sock.valid())
{
FD_SET(sock.fd, &read_fds);
FD_SET(sock.fd, &write_fds);
FD_SET(sock.fd, &except_fds);
nfds = max(nfds, sock.fd+1);
}
else
{
// Good time to clean up invalid sockets.
WiiSockets.erase(sock.fd);
}
}
s32 ret = select(nfds, &read_fds, &write_fds, &except_fds, &t);
if(ret >= 0)
{
for (auto it = WiiSockets.begin(); it != WiiSockets.end(); ++it)
{
WiiSocket& sock = it->second;
sock.update(
FD_ISSET(sock.fd, &read_fds) != 0,
FD_ISSET(sock.fd, &write_fds) != 0,
FD_ISSET(sock.fd, &except_fds) != 0
);
}
}
else
{
for (auto it = WiiSockets.begin(); it != WiiSockets.end(); ++it)
{
it->second.update(false, false, false);
}
}
}
void WiiSockMan::EnqueueReply(u32 CommandAddress, s32 ReturnValue)
{
Memory::Write_U32(8, CommandAddress);
// IOS seems to write back the command that was responded to
Memory::Write_U32(Memory::Read_U32(CommandAddress), CommandAddress + 8);
// Return value
Memory::Write_U32(ReturnValue, CommandAddress + 4);
WII_IPC_HLE_Interface::EnqReply(CommandAddress);
}
#undef ERRORCODE
#undef EITHER

View File

@ -0,0 +1,214 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _WII_SOCKET_H_
#define _WII_SOCKET_H_
#ifdef _WIN32
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <iphlpapi.h>
#include "fakepoll.h"
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
#elif defined(__linux__) or defined(__APPLE__)
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <errno.h>
#include <poll.h>
#include <string.h>
typedef struct pollfd pollfd_t;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <errno.h>
#endif
#include <algorithm> // std::for_each
#include <unordered_map>
#include <stdio.h>
#include <string>
#include <list>
#include "FileUtil.h"
#include "WII_IPC_HLE.h"
#include "WII_IPC_HLE_Device_net.h"
#include "WII_IPC_HLE_Device_net_ssl.h"
enum {
SO_MSG_OOB = 0x01,
SO_MSG_PEEK = 0x02,
SO_MSG_NONBLOCK = 0x04,
};
enum {
SO_SUCCESS,
SO_E2BIG = 1,
SO_EACCES,
SO_EADDRINUSE,
SO_EADDRNOTAVAIL,
SO_EAFNOSUPPORT,
SO_EAGAIN,
SO_EALREADY,
SO_EBADF,
SO_EBADMSG,
SO_EBUSY,
SO_ECANCELED,
SO_ECHILD,
SO_ECONNABORTED,
SO_ECONNREFUSED,
SO_ECONNRESET,
SO_EDEADLK,
SO_EDESTADDRREQ,
SO_EDOM,
SO_EDQUOT,
SO_EEXIST,
SO_EFAULT,
SO_EFBIG,
SO_EHOSTUNREACH,
SO_EIDRM,
SO_EILSEQ,
SO_EINPROGRESS,
SO_EINTR,
SO_EINVAL,
SO_EIO,
SO_EISCONN,
SO_EISDIR,
SO_ELOOP,
SO_EMFILE,
SO_EMLINK,
SO_EMSGSIZE,
SO_EMULTIHOP,
SO_ENAMETOOLONG,
SO_ENETDOWN,
SO_ENETRESET,
SO_ENETUNREACH,
SO_ENFILE,
SO_ENOBUFS,
SO_ENODATA,
SO_ENODEV,
SO_ENOENT,
SO_ENOEXEC,
SO_ENOLCK,
SO_ENOLINK,
SO_ENOMEM,
SO_ENOMSG,
SO_ENOPROTOOPT,
SO_ENOSPC,
SO_ENOSR,
SO_ENOSTR,
SO_ENOSYS,
SO_ENOTCONN,
SO_ENOTDIR,
SO_ENOTEMPTY,
SO_ENOTSOCK,
SO_ENOTSUP,
SO_ENOTTY,
SO_ENXIO,
SO_EOPNOTSUPP,
SO_EOVERFLOW,
SO_EPERM,
SO_EPIPE,
SO_EPROTO,
SO_EPROTONOSUPPORT,
SO_EPROTOTYPE,
SO_ERANGE,
SO_EROFS,
SO_ESPIPE,
SO_ESRCH,
SO_ESTALE,
SO_ETIME,
SO_ETIMEDOUT,
SO_ETXTBSY,
SO_EXDEV
};
class WiiSocket
{
struct sockop{
u32 _CommandAddress;
bool is_ssl;
union
{
NET_IOCTL net_type;
SSL_IOCTL ssl_type;
};
};
private:
s32 fd;
bool nonBlock;
std::list<sockop> pending_sockops;
friend class WiiSockMan;
void setFd(s32 s);
s32 closeFd();
s32 _fcntl(u32 cmd, u32 arg);
s32 _bind(sockaddr_in* name, s32 namelen);
s32 _connect(sockaddr_in* name, s32 namelen);
void doSock(u32 _CommandAddress, NET_IOCTL type);
void doSock(u32 _CommandAddress, SSL_IOCTL type);
void update(bool read, bool write, bool except);
bool valid() {return fd >= 0;}
public:
WiiSocket() : fd(-1), nonBlock(false) {}
~WiiSocket();
void operator=(WiiSocket const&); // Don't implement
};
class WiiSockMan
{
public:
static s32 getNetErrorCode(s32 ret, std::string caller, bool isRW);
static char* DecodeError(s32 ErrorCode);
static WiiSockMan& getInstance()
{
static WiiSockMan instance; // Guaranteed to be destroyed.
return instance; // Instantiated on first use.
}
void Update();
static void EnqueueReply(u32 CommandAddress, s32 ReturnValue);
// NON-BLOCKING FUNCTIONS
s32 newSocket(s32 af, s32 type, s32 protocol);
s32 delSocket(s32 s);
template <typename T>
void doSock(s32 sock, u32 CommandAddress, T type)
{
if (WiiSockets.find(sock) == WiiSockets.end())
{
ERROR_LOG(WII_IPC_NET,
"doSock: Error, fd not found (%08x, %08X, %08X)",
sock, CommandAddress, type);
EnqueueReply(CommandAddress, -SO_EBADF);
}
else
{
WiiSockets[sock].doSock(CommandAddress, type);
}
}
private:
WiiSockMan() {}; // Constructor? (the {} brackets) are needed here.
WiiSockMan(WiiSockMan const&); // Don't Implement
void operator=(WiiSockMan const&); // Don't implement
std::unordered_map<s32, WiiSocket> WiiSockets;
};
#endif