Move flags and other constants from InetSocket onto SceNetInet.

This commit is contained in:
White Blood Cell 2023-12-27 12:13:07 -08:00 committed by Henrik Rydgård
parent 4bc79481da
commit 727203e88f
3 changed files with 220 additions and 235 deletions

View file

@ -250,7 +250,7 @@ static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtoco
}
// Map opened socket to an inet socket which is 1-indexed
const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId, nonBlocking);
const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId, nativeProtocol, nonBlocking);
// Set non-blocking mode since the translation function does not translate non-blocking mode due to platform incompatibilities
if (nonBlocking) {
@ -276,7 +276,7 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EINVAL);
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket);
}
@ -288,14 +288,14 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname
return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel);
}
if (!inetSocket->IsSockoptNameAllowed(inetOptname)) {
sceNetInet->SetLastError(EINVAL);
int nativeOptname;
if (!SceNetInet::TranslateInetOptnameToNativeOptname(nativeOptname, inetOptname)) {
sceNetInet->SetLastError(ENOPROTOOPT);
return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname);
}
const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast<InetSocketOptionName>(inetOptname));
if (optname != inetOptname) {
DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname);
if (nativeOptname != inetOptname) {
DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname);
}
#if PPSSPP_PLATFORM(WINDOWS)
@ -314,7 +314,7 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname
return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen);
}
switch (optname) {
switch (nativeOptname) {
// No direct equivalents
case INET_SO_NONBLOCK: {
if (*optlen != sizeof(u32)) {
@ -327,7 +327,7 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname
// Direct 1:1 mappings
default: {
// TODO: implement non-blocking getsockopt
const int ret = getsockopt(nativeSocketId, nativeSocketLevel, optname, optval, optlen);
const int ret = getsockopt(nativeSocketId, nativeSocketLevel, nativeOptname, optval, optlen);
if (ret < 0) {
const auto error = sceNetInet->SetLastErrorToMatchPlatform();
return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error));
@ -347,7 +347,7 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EFAULT);
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket);
}
@ -359,14 +359,14 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname
return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel);
}
if (!inetSocket->IsSockoptNameAllowed(inetOptname)) {
sceNetInet->SetLastError(EINVAL);
int nativeOptname;
if (!SceNetInet::TranslateInetOptnameToNativeOptname(nativeOptname, inetOptname)) {
sceNetInet->SetLastError(ENOPROTOOPT);
return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname);
}
const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast<InetSocketOptionName>(inetOptname));
if (optname != inetOptname) {
DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname);
if (nativeOptname != inetOptname) {
DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname);
}
// If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability
@ -381,9 +381,9 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname
}
auto optval = Memory::Read_U32(optvalPtr);
DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, optname, optval);
DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, nativeOptname, optval);
switch (optname) {
switch (nativeOptname) {
// Unmatched PSP functions - no direct equivalent
case INET_SO_NONBLOCK: {
const bool nonblocking = optval != 0;
@ -397,12 +397,12 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname
}
// Functions with identical structs to native functions
default: {
INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, optname, optval, 4);
const int ret = setsockopt(nativeSocketId, nativeSocketLevel, optname, reinterpret_cast<netBufferType*>(&optval), sizeof(optval));
INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, nativeOptname, optval, 4);
const int ret = setsockopt(nativeSocketId, nativeSocketLevel, nativeOptname, reinterpret_cast<netBufferType*>(&optval), sizeof(optval));
INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId);
if (ret < 0) {
const auto error = sceNetInet->SetLastErrorToMatchPlatform();
return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, optname, optval, error, strerror(error));
return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, nativeOptname, optval, error, strerror(error));
}
return hleLogSuccessI(SCENET, ret);
}
@ -614,7 +614,7 @@ static int sceNetInetClose(int socket) {
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EINVAL);
sceNetInet->SetLastError(EBADF);
return hleLogWarning(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket);
}
@ -830,8 +830,8 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) {
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
WARN_LOG(SCENET, "%s: Attempting to close socket %i which does not exist", __func__, socket);
return -1;
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket);
}
const auto nativeSocketId = inetSocket->GetNativeSocketId();
@ -840,7 +840,7 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) {
return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen);
}
const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags);
const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking());
const int ret = recv(nativeSocketId, dstBuf, bufLen, nativeFlags);
DEBUG_LOG(SCENET, "[%i] %s: Called recv with buf size %i which returned %i", nativeSocketId, __func__, bufLen, ret);
if (ret < 0) {
@ -861,7 +861,7 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EFAULT);
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket);
}
@ -873,7 +873,7 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32
}
// Translate PSP flags to native flags and prepare sockaddrIn to receive peer address
const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags);
const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking());
sockaddr_in sockaddrIn{};
socklen_t socklen = sizeof(sockaddr_in);
Memory::Memset(bufPtr, 0, bufLen, __func__);
@ -906,7 +906,7 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) {
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EFAULT);
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket);
}
@ -917,7 +917,7 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) {
}
// Translate PSP flags to native flags and send
const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags);
const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking());
const int ret = send(inetSocket->GetNativeSocketId(), buf, bufLen, nativeFlags);
if (ret < 0) {
const auto error = sceNetInet->SetLastErrorToMatchPlatform();
@ -935,7 +935,7 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EFAULT);
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket);
}
@ -947,7 +947,7 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t
}
// Translate PSP flags to native flags and convert toAddr to native addr
const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags);
const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking());
sockaddr_in convertedSockAddr{};
if (!inetSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) {
ERROR_LOG(SCENET, "[%i] %s: Unable to translate sceSockAddr to native sockaddr", nativeSocketId, __func__);
@ -979,7 +979,7 @@ static int sceNetInetGetErrno() {
INFO_LOG(SCENET, "Requested %s %i=%s", __func__, nativeError, strerror(nativeError));
}
return InetSocket::TranslateNativeErrorToInetError(nativeError);
return SceNetInet::TranslateNativeErrorToInetError(nativeError);
}
static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) {
@ -991,7 +991,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) {
const auto inetSocket = sceNetInet->GetInetSocket(socket);
if (!inetSocket) {
sceNetInet->SetLastError(EFAULT);
sceNetInet->SetLastError(EBADF);
return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket);
}
@ -1023,12 +1023,13 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) {
// Set UPnP
const auto port = ntohs(convertedSockaddr.sin_port);
switch (inetSocket->GetProtocol()) {
case INET_PROTOCOL_TCP: {
UPnP_Add(IP_PROTOCOL_TCP, port, port);
case IPPROTO_UDP: {
UPnP_Add(IP_PROTOCOL_UDP, port, port);
break;
}
case INET_PROTOCOL_UDP: {
UPnP_Add(IP_PROTOCOL_UDP, port, port);
case IPPROTO_IP:
case IPPROTO_TCP: {
UPnP_Add(IP_PROTOCOL_TCP, port, port);
break;
}
// TODO: Unknown IP protocol 000f when attempting to set up UPnP port forwarding
@ -1076,23 +1077,24 @@ const HLEFunction sceNetInet[] = {
};;
std::shared_ptr<SceNetInet> SceNetInet::gInstance;
std::shared_mutex SceNetInet::gLock;
std::unordered_map<PspInetAddressFamily, int> SceNetInet::gInetAddressFamilyToNativeAddressFamily =
{
std::unordered_map<PspInetAddressFamily, int> SceNetInet::gInetAddressFamilyToNativeAddressFamily = {
{ PSP_NET_INET_AF_UNSPEC, AF_UNSPEC },
{ PSP_NET_INET_AF_LOCAL, AF_UNIX },
{ PSP_NET_INET_AF_INET, AF_INET },
};
std::unordered_map<PspInetSocketType, int> SceNetInet::gInetSocketTypeToNativeSocketType =
{
std::unordered_map<PspInetSocketType, int> SceNetInet::gInetSocketTypeToNativeSocketType = {
{ PSP_NET_INET_SOCK_STREAM, SOCK_STREAM },
{ PSP_NET_INET_SOCK_DGRAM, SOCK_DGRAM },
{ PSP_NET_INET_SOCK_RAW, SOCK_RAW },
{ PSP_NET_INET_SOCK_RDM, SOCK_RDM },
{ PSP_NET_INET_SOCK_SEQPACKET, SOCK_SEQPACKET },
};
std::unordered_map<PspInetProtocol, int> SceNetInet::gInetProtocolToNativeProtocol =
{
std::unordered_map<PspInetProtocol, int> SceNetInet::gInetProtocolToNativeProtocol = {
{ PSP_NET_INET_IPPROTO_IP, IPPROTO_IP },
{ PSP_NET_INET_IPPROTO_ICMP, IPPROTO_ICMP },
{ PSP_NET_INET_IPPROTO_IGMP, IPPROTO_IGMP },
@ -1104,6 +1106,54 @@ std::unordered_map<PspInetProtocol, int> SceNetInet::gInetProtocolToNativeProtoc
{ PSP_NET_INET_IPPROTO_RAW, IPPROTO_RAW },
};
// TODO: commented out optnames
std::unordered_map<PspInetSocketOptionName, int> SceNetInet::gInetSocketOptnameToNativeOptname = {
{ INET_SO_ACCEPTCONN, SO_ACCEPTCONN },
{ INET_SO_REUSEADDR, SO_REUSEADDR },
{ INET_SO_KEEPALIVE, SO_KEEPALIVE },
{ INET_SO_DONTROUTE, SO_DONTROUTE },
{ INET_SO_BROADCAST, SO_BROADCAST },
// { INET_SO_USELOOPBACK, INET_SO_USELOOPBACK },
{ INET_SO_LINGER, SO_LINGER },
{ INET_SO_OOBINLINE, SO_OOBINLINE },
{ INET_SO_REUSEPORT, SO_REUSEPORT },
{ INET_SO_TIMESTAMP, SO_TIMESTAMP },
// { INET_SO_ONESBCAST, INET_SO_ONESBCAST },
{ INET_SO_SNDBUF, SO_SNDBUF },
{ INET_SO_RCVBUF, SO_RCVBUF },
{ INET_SO_SNDLOWAT, SO_SNDLOWAT },
{ INET_SO_RCVLOWAT, SO_RCVLOWAT },
{ INET_SO_SNDTIMEO, SO_SNDTIMEO },
{ INET_SO_RCVTIMEO, SO_RCVTIMEO },
{ INET_SO_ERROR, SO_ERROR },
{ INET_SO_TYPE, SO_TYPE },
// { INET_SO_OVERFLOWED, INET_SO_OVERFLOWED },
{ INET_SO_NONBLOCK, INET_SO_NONBLOCK },
};
std::unordered_map<PspInetMessageFlag, int> SceNetInet::gInetMessageFlagToNativeMessageFlag = {
{ INET_MSG_OOB, MSG_OOB },
{ INET_MSG_PEEK, MSG_PEEK },
{ INET_MSG_DONTROUTE, MSG_DONTROUTE },
#if defined(MSG_EOR)
{ INET_MSG_EOR, MSG_EOR },
#endif
{ INET_MSG_TRUNC, MSG_TRUNC },
{ INET_MSG_CTRUNC, MSG_CTRUNC },
{ INET_MSG_WAITALL, MSG_WAITALL },
{ INET_MSG_DONTWAIT, MSG_DONTWAIT },
#if defined(MSG_BCAST)
{ INET_MSG_BCAST, MSG_BCAST },
#endif
#if defined(MSG_MCAST)
{ INET_MSG_MCAST, MSG_MCAST },
#endif
};
std::unordered_map<int, InetErrorCode> SceNetInet::gNativeErrorCodeToInetErrorCode = {
{ EINPROGRESS, INET_EINPROGRESS }
};
bool SceNetInet::Init() {
auto lock = std::unique_lock(gLock);
if (gInstance) {
@ -1186,6 +1236,50 @@ bool SceNetInet::TranslateInetProtocolToNative(int &destProtocol, int srcProtoco
return true;
}
bool SceNetInet::TranslateInetOptnameToNativeOptname(int &destOptname, const int inetOptname) {
const auto it = gInetSocketOptnameToNativeOptname.find(static_cast<PspInetSocketOptionName>(inetOptname));
if (it == gInetSocketOptnameToNativeOptname.end()) {
return false;
}
destOptname = it->second;
return true;
}
int SceNetInet::TranslateInetFlagsToNativeFlags(const int messageFlags, const bool nonBlocking) {
int nativeFlags = 0; // The actual platform flags
int foundFlags = 0; // The inet equivalent of the native flags, used to verify that no remaining flags need to be set
for (const auto [inetFlag, nativeFlag] : gInetMessageFlagToNativeMessageFlag) {
if ((messageFlags & inetFlag) != 0) {
nativeFlags |= nativeFlag;
foundFlags |= inetFlag;
}
}
#if !PPSSPP_PLATFORM(WINDOWS)
if (nonBlocking) {
nativeFlags |= MSG_DONTWAIT;
}
#endif
// Check for any inet flags which were not successfully mapped into a native flag
if (const int missingFlags = messageFlags & ~foundFlags; missingFlags != 0) {
for (int i = 0; i < sizeof(int) * 8; i++) {
if (const int val = 1 << i; (missingFlags & val) != 0) {
DEBUG_LOG(SCENET, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val);
}
}
}
return nativeFlags;
}
int SceNetInet::TranslateNativeErrorToInetError(const int nativeError) {
if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError);
it != gNativeErrorCodeToInetErrorCode.end()) {
return it->second;
}
return nativeError;
}
int SceNetInet::GetLastError() {
auto lock = std::shared_lock(mLock);
return mLastError;
@ -1207,7 +1301,7 @@ int SceNetInet::SetLastErrorToMatchPlatform() {
return error;
}
std::shared_ptr<InetSocket> SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking) {
std::shared_ptr<InetSocket> SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId, int protocol, bool nonBlocking) {
auto lock = std::unique_lock(mLock);
int inetSocketId = ++mCurrentInetSocketId;
@ -1215,7 +1309,7 @@ std::shared_ptr<InetSocket> SceNetInet::CreateAndAssociateInetSocket(int nativeS
WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated inetSocketId: %i", __func__, inetSocketId);
return nullptr;
}
auto inetSocket = std::make_shared<InetSocket>(inetSocketId, nativeSocketId);
auto inetSocket = std::make_shared<InetSocket>(inetSocketId, nativeSocketId, protocol, nonBlocking);
inetSocket->SetNonBlocking(nonBlocking);
mInetSocketIdToNativeSocket.emplace(inetSocketId, inetSocket);
return inetSocket;

View file

@ -91,6 +91,53 @@ enum PspInetProtocol {
PSP_NET_INET_IPPROTO_RAW = 255, // raw IP packet
};
// TODO: INET_
enum PspInetSocketOptionName {
// TODO: also specify minimum socket size
INET_SO_ACCEPTCONN = 0x0002, // socket has had listen()
INET_SO_REUSEADDR = 0x0004, // allow local address reuse
INET_SO_KEEPALIVE = 0x0008, // keep connections alive
INET_SO_DONTROUTE = 0x0010, // just use interface addresses
INET_SO_BROADCAST = 0x0020, // permit sending of broadcast msgs
INET_SO_USELOOPBACK = 0x0040, // bypass hardware when possible
INET_SO_LINGER = 0x0080, // linger on close if data present
INET_SO_OOBINLINE = 0x0100, // leave received OOB data in line
INET_SO_REUSEPORT = 0x0200, // allow local address & port reuse
INET_SO_TIMESTAMP = 0x0400, // timestamp received dgram traffic
INET_SO_ONESBCAST = 0x0800, // allow broadcast to 255.255.255.255
INET_SO_SNDBUF = 0x1001, // send buffer size
INET_SO_RCVBUF = 0x1002, // receive buffer size
INET_SO_SNDLOWAT = 0x1003, // send low-water mark
INET_SO_RCVLOWAT = 0x1004, // receive low-water mark
INET_SO_SNDTIMEO = 0x1005, // send timeout
INET_SO_RCVTIMEO = 0x1006, // receive timeout
INET_SO_ERROR = 0x1007, // get error status and clear
INET_SO_TYPE = 0x1008, // get socket type
INET_SO_OVERFLOWED = 0x1009, // datagrams: return packets dropped
INET_SO_NONBLOCK = 0x1009, // non-blocking I/O
};
enum PspInetLimit {
PSP_NET_INET_SOMAXCONN = 128,
};
enum PspInetMessageFlag {
INET_MSG_OOB = 1,
INET_MSG_PEEK = 1 << 1,
INET_MSG_DONTROUTE = 1 << 2,
INET_MSG_EOR = 1 << 3,
INET_MSG_TRUNC = 1 << 4,
INET_MSG_CTRUNC = 1 << 5,
INET_MSG_WAITALL = 1 << 6,
INET_MSG_DONTWAIT = 1 << 7,
INET_MSG_BCAST = 1 << 8,
INET_MSG_MCAST = 1 << 9
};
enum InetErrorCode {
INET_EINPROGRESS = 119,
};
class SceNetInet {
public:
static bool Init();
@ -106,13 +153,17 @@ public:
static bool TranslateInetSocketTypeToNative(int &destSocketType, bool &destNonBlocking, int srcSocketType);
// TODO: document that errno should be set to EPROTONOSUPPORT when this returns false
static bool TranslateInetProtocolToNative(int &destProtocol, int srcProtocol);
// TODO: document that errno should be set to EPROTONOSUPPORT when this returns false
static bool TranslateInetOptnameToNativeOptname(int &destOptname, int inetOptname);
static int TranslateInetFlagsToNativeFlags(int messageFlags, bool nonBlocking);
static int TranslateNativeErrorToInetError(int nativeError);
// TODO: document
int GetLastError();
void SetLastError(int error);
int SetLastErrorToMatchPlatform();
std::shared_ptr<InetSocket> CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking);
std::shared_ptr<InetSocket> CreateAndAssociateInetSocket(int nativeSocketId, int protocol, bool nonBlocking);
std::shared_ptr<InetSocket> GetInetSocket(int inetSocketId);
bool GetNativeSocketIdForInetSocketId(int &nativeSocketId, int inetSocketId);
bool EraseNativeSocket(int inetSocketId);
@ -127,6 +178,11 @@ private:
// TODO: document that this does not include flags
static std::unordered_map<PspInetSocketType, int> gInetSocketTypeToNativeSocketType;
static std::unordered_map<PspInetProtocol, int> gInetProtocolToNativeProtocol;
// TODO: Handle commented out options
static std::unordered_map<PspInetSocketOptionName, int> gInetSocketOptnameToNativeOptname;
static std::unordered_map<PspInetMessageFlag, int> gInetMessageFlagToNativeMessageFlag;
static std::unordered_map<int, InetErrorCode> gNativeErrorCodeToInetErrorCode;
int mLastError = 0;
std::unordered_map<int, std::shared_ptr<InetSocket>> mInetSocketIdToNativeSocket;

View file

@ -1,202 +1,37 @@
#pragma once
#include "ppsspp_config.h"
#include <unordered_map>
#include <unordered_set>
#if !PPSSPP_PLATFORM(WINDOWS)
#include <sys/socket.h>
#endif
#include "Log.h"
enum Protocol {
INET_PROTOCOL_UDP = SOCK_DGRAM,
INET_PROTOCOL_TCP = SOCK_STREAM
};
// TODO: INET_
enum InetSocketOptionName {
// TODO: also specify minimum socket size
INET_SO_ACCEPTCONN = 0x0002, // socket has had listen()
INET_SO_REUSEADDR = 0x0004, // allow local address reuse
INET_SO_KEEPALIVE = 0x0008, // keep connections alive
INET_SO_DONTROUTE = 0x0010, // just use interface addresses
INET_SO_BROADCAST = 0x0020, // permit sending of broadcast msgs
INET_SO_USELOOPBACK = 0x0040, // bypass hardware when possible
INET_SO_LINGER = 0x0080, // linger on close if data present
INET_SO_OOBINLINE = 0x0100, // leave received OOB data in line
INET_SO_REUSEPORT = 0x0200, // allow local address & port reuse
INET_SO_TIMESTAMP = 0x0400, // timestamp received dgram traffic
INET_SO_ONESBCAST = 0x0800, // allow broadcast to 255.255.255.255
INET_SO_SNDBUF = 0x1001, // send buffer size
INET_SO_RCVBUF = 0x1002, // receive buffer size
INET_SO_SNDLOWAT = 0x1003, // send low-water mark
INET_SO_RCVLOWAT = 0x1004, // receive low-water mark
INET_SO_SNDTIMEO = 0x1005, // send timeout
INET_SO_RCVTIMEO = 0x1006, // receive timeout
INET_SO_ERROR = 0x1007, // get error status and clear
INET_SO_TYPE = 0x1008, // get socket type
INET_SO_OVERFLOWED = 0x1009, // datagrams: return packets dropped
INET_SO_NONBLOCK = 0x1009, // non-blocking I/O
};
// TODO: Handle commented out options
static std::unordered_map<InetSocketOptionName, int> gInetSocketOptnameToNativeOptname = {
{ INET_SO_ACCEPTCONN, SO_ACCEPTCONN },
{ INET_SO_REUSEADDR, SO_REUSEADDR },
{ INET_SO_KEEPALIVE, SO_KEEPALIVE },
{ INET_SO_DONTROUTE, SO_DONTROUTE },
{ INET_SO_BROADCAST, SO_BROADCAST },
// { INET_SO_USELOOPBACK, INET_SO_USELOOPBACK },
{ INET_SO_LINGER, SO_LINGER },
{ INET_SO_OOBINLINE, SO_OOBINLINE },
{ INET_SO_REUSEPORT, SO_REUSEPORT },
{ INET_SO_TIMESTAMP, SO_TIMESTAMP },
// { INET_SO_ONESBCAST, INET_SO_ONESBCAST },
{ INET_SO_SNDBUF, SO_SNDBUF },
{ INET_SO_RCVBUF, SO_RCVBUF },
{ INET_SO_SNDLOWAT, SO_SNDLOWAT },
{ INET_SO_RCVLOWAT, SO_RCVLOWAT },
{ INET_SO_SNDTIMEO, SO_SNDTIMEO },
{ INET_SO_RCVTIMEO, SO_RCVTIMEO },
{ INET_SO_ERROR, SO_ERROR },
{ INET_SO_TYPE, SO_TYPE },
// { INET_SO_OVERFLOWED, INET_SO_OVERFLOWED },
{ INET_SO_NONBLOCK, INET_SO_NONBLOCK },
};
enum InetLimit {
PSP_NET_INET_SOMAXCONN = 128,
};
enum InetMessageFlag {
INET_MSG_OOB = 1,
INET_MSG_PEEK = 1 << 1,
INET_MSG_DONTROUTE = 1 << 2,
INET_MSG_EOR = 1 << 3,
INET_MSG_TRUNC = 1 << 4,
INET_MSG_CTRUNC = 1 << 5,
INET_MSG_WAITALL = 1 << 6,
INET_MSG_DONTWAIT = 1 << 7,
INET_MSG_BCAST = 1 << 8,
INET_MSG_MCAST = 1 << 9
};
// TODO: move to better place
static std::unordered_map<InetMessageFlag, int> gInetMessageFlagToNativeMessageFlag = {
{ INET_MSG_OOB, MSG_OOB },
{ INET_MSG_PEEK, MSG_PEEK },
{ INET_MSG_DONTROUTE, MSG_DONTROUTE },
#if defined(MSG_EOR)
{ INET_MSG_EOR, MSG_EOR },
#endif
{ INET_MSG_TRUNC, MSG_TRUNC },
{ INET_MSG_CTRUNC, MSG_CTRUNC },
{ INET_MSG_WAITALL, MSG_WAITALL },
{ INET_MSG_DONTWAIT, MSG_DONTWAIT },
#if defined(MSG_BCAST)
{ INET_MSG_BCAST, MSG_BCAST },
#endif
#if defined(MSG_MCAST)
{ INET_MSG_MCAST, MSG_MCAST },
#endif
};
enum InetErrorCode {
INET_EINPROGRESS = 119,
};
static std::unordered_map<int, InetErrorCode> gNativeErrorCodeToInetErrorCode = {
{ EINPROGRESS, INET_EINPROGRESS }
};
// TODO: document
class InetSocket {
public:
InetSocket(int sceSocketId, int nativeSocketId) : mInetSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {}
InetSocket(int sceSocketId, int nativeSocketId, int protocol, bool nonBlocking) :
mInetSocketId(sceSocketId),
mNativeSocketId(nativeSocketId),
mProtocol(protocol),
mNonBlocking(nonBlocking) {}
int GetInetSocketId() const {
return mInetSocketId;
}
int GetInetSocketId() const {
return mInetSocketId;
}
int GetNativeSocketId() const {
return mNativeSocketId;
}
int GetNativeSocketId() const {
return mNativeSocketId;
}
// TODO: get mask of options
bool IsNonBlocking() const {
return mNonBlocking;
}
bool IsNonBlocking() const {
return mNonBlocking;
}
void SetNonBlocking(const bool nonBlocking) {
mNonBlocking = nonBlocking;
}
Protocol GetProtocol() const {
return mProtocol;
}
void SetProtocol(const Protocol protocol) {
mProtocol = protocol;
}
// TODO: Move me
static bool IsSockoptNameAllowed(const int optname) {
return gInetSocketOptnameToNativeOptname.find(static_cast<InetSocketOptionName>(optname)) != gInetSocketOptnameToNativeOptname.end();
}
// TODO: rename this or the other
static int TranslateInetOptnameToNativeOptname(const InetSocketOptionName inetOptname) {
const auto it = gInetSocketOptnameToNativeOptname.find(inetOptname);
if (it == gInetSocketOptnameToNativeOptname.end()) {
return inetOptname;
}
return it->second;
}
int TranslateInetFlagsToNativeFlags(const int messageFlags) const {
int nativeFlags = 0; // The actual platform flags
int foundFlags = 0; // The inet equivalent of the native flags, used to verify that no remaining flags need to be set
for (const auto [inetFlag, nativeFlag] : gInetMessageFlagToNativeMessageFlag) {
if ((messageFlags & inetFlag) != 0) {
nativeFlags |= nativeFlag;
foundFlags |= inetFlag;
}
}
#if !PPSSPP_PLATFORM(WINDOWS)
if (this->IsNonBlocking()) {
nativeFlags |= MSG_DONTWAIT;
}
#endif
// Check for any inet flags which were not successfully mapped into a native flag
if (const int missingFlags = messageFlags & ~foundFlags; missingFlags != 0) {
for (int i = 0; i < sizeof(int) * 8; i++) {
if (const int val = 1 << i; (missingFlags & val) != 0) {
DEBUG_LOG(Log::sceNet, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val);
}
}
}
// DEBUG_LOG(SCENET, "Translated %04x to %04x", messageFlags, nativeFlags);
return nativeFlags;
}
// TODO: consider moving to SceNetInet
static int TranslateNativeErrorToInetError(const int nativeError) {
if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError);
it != gNativeErrorCodeToInetErrorCode.end()) {
return it->second;
}
return nativeError;
}
void SetNonBlocking(const bool nonBlocking) {
mNonBlocking = nonBlocking;
}
// TODO: document that this is the native protocol
int GetProtocol() const {
return mProtocol;
}
private:
int mInetSocketId;
int mNativeSocketId;
Protocol mProtocol;
bool mNonBlocking = false;
int mInetSocketId;
int mNativeSocketId;
int mProtocol;
bool mNonBlocking = false;
};