mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 03:55:32 +00:00
Merge pull request #1670 from tambry/flower
HLE: Improvements and fixes
This commit is contained in:
commit
ed93c77433
11 changed files with 554 additions and 119 deletions
|
@ -1017,9 +1017,10 @@ s32 cellFsChangeFileSizeWithoutAllocation()
|
|||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
s32 cellFsAllocateFileAreaWithoutZeroFill()
|
||||
s32 cellFsAllocateFileAreaWithoutZeroFill(vm::cptr<char> path, u64 size)
|
||||
{
|
||||
throw EXCEPTION("");
|
||||
cellFs.warning("cellFsAllocateFileAreaWithoutZeroFill(path=*0x%x, size=0x%llx)", path, size);
|
||||
return sys_fs_truncate(path, size);
|
||||
}
|
||||
|
||||
s32 cellFsChangeFileSizeByFdWithoutAllocation()
|
||||
|
|
|
@ -587,11 +587,10 @@ s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> da
|
|||
// Check if the outputWidthByte is smaller than the intended output length of a line. For example an image might be in RGB, but we need to output 4 components, so we need to perform alpha padding.
|
||||
else if (stream->out_param.outputWidthByte < (stream->out_param.outputWidth * stream->out_param.outputComponents))
|
||||
{
|
||||
// Not sure what to do, when a fixed alpha value isn't specified, but specifying full opaque seems to cause no issues currently. Logging this just in case.
|
||||
// If fixed alpha is not specified in such a case, the default value for the alpha is 0xFF (255)
|
||||
if (!stream->fixed_alpha)
|
||||
{
|
||||
cellPngDec.error("Fixed alpha not specified for padding. Please notify a developer of this.");
|
||||
stream->fixed_alpha_colour = 255;
|
||||
stream->fixed_alpha_colour = 0xFF;
|
||||
}
|
||||
|
||||
// We need to fill alpha (before or after, depending on the output colour format) using the fixed alpha value passed by the game.
|
||||
|
|
|
@ -13,7 +13,9 @@ s32 cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
|||
cellUserInfo.warning("cellUserInfoGetStat(id=%d, stat=*0x%x)", id, stat);
|
||||
|
||||
if (id > CELL_SYSUTIL_USERID_MAX)
|
||||
{
|
||||
return CELL_USERINFO_ERROR_NOUSER;
|
||||
}
|
||||
|
||||
if (id == CELL_SYSUTIL_USERID_CURRENT)
|
||||
{
|
||||
|
@ -22,15 +24,24 @@ s32 cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
|||
}
|
||||
|
||||
const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id));
|
||||
|
||||
if (!fs::is_dir(path))
|
||||
{
|
||||
cellUserInfo.error("cellUserInfoGetStat(): CELL_USERINFO_ERROR_NOUSER. User %d doesn't exist. Did you delete the user folder?", id);
|
||||
return CELL_USERINFO_ERROR_NOUSER;
|
||||
}
|
||||
|
||||
const fs::file f(path + "localusername");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
cellUserInfo.error("cellUserInfoGetStat(): CELL_USERINFO_ERROR_INTERNAL. Username for user %d doesn't exist. Did you delete the username file?", id);
|
||||
return CELL_USERINFO_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
stat->id = id;
|
||||
strcpy_trunc(stat->name, f.to_string());
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -52,20 +63,31 @@ s32 cellUserInfoEnableOverlay()
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellUserInfoGetList(vm::ptr<u32> listNum, vm::ptr<CellUserInfoUserList> listBuf, vm::ptr<u32> currentUserId)
|
||||
ppu_error_code cellUserInfoGetList(vm::ptr<u32> listNum, vm::ptr<CellUserInfoUserList> listBuf, vm::ptr<u32> currentUserId)
|
||||
{
|
||||
cellUserInfo.warning("cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)", listNum, listBuf, currentUserId);
|
||||
cellUserInfo.todo("cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)", listNum, listBuf, currentUserId);
|
||||
|
||||
// If only listNum is NULL, an error will be returned
|
||||
if (listBuf && !listNum)
|
||||
{
|
||||
return CELL_USERINFO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
if (listNum)
|
||||
{
|
||||
*listNum = 1;
|
||||
}
|
||||
|
||||
if (listBuf)
|
||||
{
|
||||
listBuf->userId[0] = 1;
|
||||
}
|
||||
|
||||
if (currentUserId)
|
||||
{
|
||||
// TODO: Properly set the current user ID here, once implemented
|
||||
*currentUserId = 1;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
|
|
@ -3,16 +3,30 @@
|
|||
namespace vm { using namespace ps3; }
|
||||
|
||||
// Return Codes
|
||||
enum
|
||||
enum CellUserInfoError : s32
|
||||
{
|
||||
CELL_USERINFO_RET_OK = 0,
|
||||
CELL_USERINFO_RET_CANCEL = 1,
|
||||
CELL_USERINFO_ERROR_BUSY = 0x8002c301,
|
||||
CELL_USERINFO_ERROR_INTERNAL = 0x8002c302,
|
||||
CELL_USERINFO_ERROR_PARAM = 0x8002c303,
|
||||
CELL_USERINFO_ERROR_NOUSER = 0x8002c304,
|
||||
CELL_USERINFO_ERROR_BUSY = ERROR_CODE(0x8002c301),
|
||||
CELL_USERINFO_ERROR_INTERNAL = ERROR_CODE(0x8002c302),
|
||||
CELL_USERINFO_ERROR_PARAM = ERROR_CODE(0x8002c303),
|
||||
CELL_USERINFO_ERROR_NOUSER = ERROR_CODE(0x8002c304),
|
||||
};
|
||||
|
||||
template<>
|
||||
inline const char* ppu_error_code::print(CellUserInfoError error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_USERINFO_ERROR_BUSY);
|
||||
STR_CASE(CELL_USERINFO_ERROR_INTERNAL);
|
||||
STR_CASE(CELL_USERINFO_ERROR_PARAM);
|
||||
STR_CASE(CELL_USERINFO_ERROR_NOUSER);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Enums
|
||||
enum CellUserInfoParamSize
|
||||
{
|
||||
|
|
|
@ -1445,9 +1445,16 @@ s32 sceNpSignalingGetPeerNetInfoResult()
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpUtilCmpNpId()
|
||||
s32 sceNpUtilCmpNpId(vm::ptr<SceNpId> id1, vm::ptr<SceNpId> id2)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp);
|
||||
sceNp.warning("sceNpUtilCmpNpId(id1=*0x%x, id2=*0x%x)", id1, id2);
|
||||
|
||||
// TODO: Improve the comparison.
|
||||
if (strcmp(id1->handle.data, id2->handle.data) != 0)
|
||||
{
|
||||
return SCE_NP_UTIL_ERROR_NOT_MATCH;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,23 @@ enum
|
|||
SCE_NP_EXT_ERROR_NO_CONTEXT = 0x8002a6a3,
|
||||
SCE_NP_EXT_ERROR_NO_ORIGIN = 0x8002a6a4,
|
||||
|
||||
// NP Common Utility
|
||||
SCE_NP_UTIL_ERROR_INVALID_ARGUMENT = 0x8002ab01,
|
||||
SCE_NP_UTIL_ERROR_OUT_OF_MEMORY = 0x8002ab02,
|
||||
SCE_NP_UTIL_ERROR_INSUFFICIENT = 0x8002ab03,
|
||||
SCE_NP_UTIL_ERROR_PARSER_FAILED = 0x8002ab04,
|
||||
SCE_NP_UTIL_ERROR_INVALID_PROTOCOL_ID = 0x8002ab05,
|
||||
SCE_NP_UTIL_ERROR_INVALID_NP_ID = 0x8002ab06,
|
||||
SCE_NP_UTIL_ERROR_INVALID_NP_LOBBY_ID = 0x8002ab07,
|
||||
SCE_NP_UTIL_ERROR_INVALID_NP_ROOM_ID = 0x8002ab08,
|
||||
SCE_NP_UTIL_ERROR_INVALID_NP_ENV = 0x8002ab09,
|
||||
SCE_NP_UTIL_ERROR_INVALID_TITLEID = 0x8002ab0a,
|
||||
SCE_NP_UTIL_ERROR_INVALID_CHARACTER = 0x8002ab0b,
|
||||
SCE_NP_UTIL_ERROR_INVALID_ESCAPE_STRING = 0x8002ab0c,
|
||||
SCE_NP_UTIL_ERROR_UNKNOWN_TYPE = 0x8002ab0d,
|
||||
SCE_NP_UTIL_ERROR_UNKNOWN = 0x8002ab0e,
|
||||
SCE_NP_UTIL_ERROR_NOT_MATCH = 0x8002ab0f,
|
||||
|
||||
// NP Community Utility
|
||||
SCE_NP_COMMUNITY_ERROR_ALREADY_INITIALIZED = 0x8002a101,
|
||||
SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED = 0x8002a102,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
||||
#include "sys_net.h"
|
||||
|
||||
|
@ -10,18 +11,26 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
logs::channel libnet("libnet", logs::level::notice);
|
||||
|
||||
// We map host sockets to sequential IDs to return as FDs because syscalls using
|
||||
// socketselect(), etc. expect socket FDs to be under 1024.
|
||||
// We start at 1 because 0 is an invalid socket.
|
||||
std::vector<s64> g_socketMap{ 0 };
|
||||
namespace sys_net
|
||||
{
|
||||
#ifdef _WIN32
|
||||
using socket_t = SOCKET;
|
||||
#else
|
||||
using socket_t = int;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Auxiliary Functions
|
||||
// FIXME: Use the variant from OS instead? Why do we even have such a custom function?
|
||||
int inet_pton4(const char *src, char *dst)
|
||||
{
|
||||
const char digits[] = "0123456789";
|
||||
|
@ -72,18 +81,34 @@ int inet_pton(int af, const char *src, char *dst)
|
|||
}
|
||||
}
|
||||
|
||||
s32 getLastError()
|
||||
// Custom structure for sockets
|
||||
// We map host sockets to sequential IDs to return as descriptors because syscalls expect socket IDs to be under 1024.
|
||||
struct sys_net_socket final
|
||||
{
|
||||
using id_base = sys_net_socket;
|
||||
|
||||
static constexpr u32 id_min = 0; // Minimal valid socket number is 0 (not 1).
|
||||
static constexpr u32 id_max = 1023;
|
||||
|
||||
sys_net::socket_t s = -1;
|
||||
|
||||
explicit sys_net_socket(s32 socket) : s(socket)
|
||||
{
|
||||
}
|
||||
|
||||
~sys_net_socket()
|
||||
{
|
||||
if (s != -1)
|
||||
#ifdef _WIN32
|
||||
s32 ret = WSAGetLastError();
|
||||
if (ret > 10000 && ret < 11000)
|
||||
return ret % 10000;
|
||||
else
|
||||
return -1;
|
||||
::closesocket(s);
|
||||
#else
|
||||
return errno;
|
||||
::close(s);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sys_net_socket(sys_net_socket const &) = delete;
|
||||
sys_net_socket& operator=(const sys_net_socket&) = delete;
|
||||
};
|
||||
|
||||
void copy_fdset(fd_set* set, vm::ptr<sys_net::fd_set> src)
|
||||
{
|
||||
|
@ -94,15 +119,15 @@ void copy_fdset(fd_set* set, vm::ptr<sys_net::fd_set> src)
|
|||
// Go through the bit set fds_bits and calculate the
|
||||
// socket FDs from it, setting it in the native fd-set.
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (s32 i = 0; i < 32; i++)
|
||||
{
|
||||
for (int bit = 0; bit < 32; bit++)
|
||||
for (s32 bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (src->fds_bits[i] & (1 << bit))
|
||||
{
|
||||
u32 sock = (i << 5) | bit;
|
||||
sys_net::socket_t sock = idm::get<sys_net_socket>((i << 5) | bit)->s;
|
||||
//libnet.error("setting: fd %d", sock);
|
||||
FD_SET(g_socketMap[sock], set);
|
||||
FD_SET(sock, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +140,7 @@ namespace sys_net
|
|||
{
|
||||
be_t<s32> _errno;
|
||||
be_t<s32> _h_errno;
|
||||
char addr[16];
|
||||
};
|
||||
|
||||
// TODO
|
||||
|
@ -126,6 +152,9 @@ namespace sys_net
|
|||
if (!g_tls_net_data)
|
||||
{
|
||||
g_tls_net_data.set(vm::alloc(sizeof(decltype(g_tls_net_data)::type), vm::main));
|
||||
|
||||
// Initial values
|
||||
g_tls_net_data->_errno = SYS_NET_EBUSY;
|
||||
|
||||
thread_ctrl::atexit([addr = g_tls_net_data.addr()]
|
||||
{
|
||||
|
@ -148,41 +177,91 @@ namespace sys_net
|
|||
return g_tls_net_data.ref(&_tls_data_t::_h_errno);
|
||||
}
|
||||
|
||||
// Error helper functions
|
||||
s32 get_last_error()
|
||||
{
|
||||
// Convert the error code for socket functions to a one for sys_net
|
||||
s32 result;
|
||||
const char* name{};
|
||||
|
||||
#ifdef _WIN32
|
||||
switch (s32 code = WSAGetLastError())
|
||||
#define ERROR_CASE(error) case WSA ## error: result = SYS_NET_ ## error; name = #error; break;
|
||||
#else
|
||||
switch (s32 code = errno)
|
||||
#define ERROR_CASE(error) case error: result = SYS_NET_ ## error; name = #error; break;
|
||||
#endif
|
||||
{
|
||||
ERROR_CASE(EWOULDBLOCK);
|
||||
default: throw fmt::exception("Unknown/illegal socket error: %d" HERE, code);
|
||||
}
|
||||
|
||||
if (name && result != SYS_NET_EWOULDBLOCK)
|
||||
{
|
||||
ppu_error_code::report(result, name);
|
||||
}
|
||||
|
||||
return result;
|
||||
#undef ERROR_CASE
|
||||
}
|
||||
|
||||
// Functions
|
||||
s32 accept(s32 s, vm::ptr<sockaddr> addr, vm::ptr<u32> paddrlen)
|
||||
{
|
||||
libnet.warning("accept(s=%d, family=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
if (!addr) {
|
||||
int ret = ::accept(s, nullptr, nullptr);
|
||||
get_errno() = getLastError();
|
||||
return ret;
|
||||
s32 ret;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
ret = ::accept(sock->s, nullptr, nullptr);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("accept(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
::sockaddr _addr;
|
||||
memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr));
|
||||
_addr.sa_family = addr->sa_family;
|
||||
::socklen_t _paddrlen;
|
||||
s32 ret = ::accept(s, &_addr, &_paddrlen);
|
||||
::socklen_t _paddrlen = 16;
|
||||
|
||||
ret = ::accept(sock->s, &_addr, &_paddrlen);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("accept(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
*paddrlen = _paddrlen;
|
||||
get_errno() = getLastError();
|
||||
return ret;
|
||||
addr->sa_len = _paddrlen;
|
||||
addr->sa_family = _addr.sa_family;
|
||||
memcpy(addr->sa_data, _addr.sa_data, addr->sa_len - 2);
|
||||
}
|
||||
|
||||
return idm::make<sys_net_socket>(ret);
|
||||
}
|
||||
|
||||
s32 bind(s32 s, vm::cptr<sockaddr> addr, u32 addrlen)
|
||||
{
|
||||
libnet.warning("bind(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
::sockaddr_in saddr;
|
||||
memcpy(&saddr, addr.get_ptr(), sizeof(::sockaddr_in));
|
||||
saddr.sin_family = addr->sa_family;
|
||||
const char *ipaddr = ::inet_ntoa(saddr.sin_addr);
|
||||
libnet.warning("binding on %s to port %d", ipaddr, ntohs(saddr.sin_port));
|
||||
s32 ret = ::bind(s, (const ::sockaddr*)&saddr, addrlen);
|
||||
get_errno() = getLastError();
|
||||
libnet.warning("binding to %s on port %d", ipaddr, ntohs(saddr.sin_port));
|
||||
s32 ret = ::bind(sock->s, (const ::sockaddr*)&saddr, addrlen);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
libnet.error("bind(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -190,15 +269,24 @@ namespace sys_net
|
|||
s32 connect(s32 s, vm::ptr<sockaddr> addr, u32 addrlen)
|
||||
{
|
||||
libnet.warning("connect(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
::sockaddr_in saddr;
|
||||
memcpy(&saddr, addr.get_ptr(), sizeof(::sockaddr_in));
|
||||
saddr.sin_family = addr->sa_family;
|
||||
const char *ipaddr = ::inet_ntoa(saddr.sin_addr);
|
||||
libnet.warning("connecting on %s to port %d", ipaddr, ntohs(saddr.sin_port));
|
||||
s32 ret = ::connect(s, (const ::sockaddr*)&saddr, addrlen);
|
||||
get_errno() = getLastError();
|
||||
|
||||
libnet.warning("connecting to %s on port %d", ::inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
|
||||
s32 ret = ::connect(sock->s, (const ::sockaddr*)&saddr, addrlen);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
if ((get_errno() = get_last_error()) != SYS_NET_EWOULDBLOCK)
|
||||
{
|
||||
libnet.error("connect(): error %d", get_errno().get_ref());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -269,10 +357,18 @@ namespace sys_net
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 inet_ntoa()
|
||||
vm::ptr<char> inet_ntoa(u32 in)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(libnet);
|
||||
return CELL_OK;
|
||||
libnet.warning("inet_ntoa(in=0x%x)", in);
|
||||
initialize_tls();
|
||||
|
||||
::in_addr addr;
|
||||
addr.s_addr = in;
|
||||
|
||||
char* result = ::inet_ntoa(addr);
|
||||
strcpy(g_tls_net_data->addr, result);
|
||||
|
||||
return vm::ptr<char>::make(vm::get_addr(g_tls_net_data->addr));
|
||||
}
|
||||
|
||||
vm::cptr<char> inet_ntop(s32 af, vm::ptr<void> src, vm::ptr<char> dst, u32 size)
|
||||
|
@ -297,9 +393,15 @@ namespace sys_net
|
|||
s32 listen(s32 s, s32 backlog)
|
||||
{
|
||||
libnet.warning("listen(s=%d, backlog=%d)", s, backlog);
|
||||
s = g_socketMap[s];
|
||||
s32 ret = ::listen(s, backlog);
|
||||
get_errno() = getLastError();
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
s32 ret = ::listen(sock->s, backlog);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
libnet.error("listen(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -307,10 +409,15 @@ namespace sys_net
|
|||
s32 recv(s32 s, vm::ptr<char> buf, u32 len, s32 flags)
|
||||
{
|
||||
libnet.warning("recv(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
s32 ret = ::recv(s, buf.get_ptr(), len, flags);
|
||||
get_errno() = getLastError();
|
||||
s32 ret = ::recv(sock->s, buf.get_ptr(), len, flags);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("recv(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -318,15 +425,21 @@ namespace sys_net
|
|||
s32 recvfrom(s32 s, vm::ptr<char> buf, u32 len, s32 flags, vm::ptr<sockaddr> addr, vm::ptr<u32> paddrlen)
|
||||
{
|
||||
libnet.warning("recvfrom(s=%d, buf=*0x%x, len=%d, flags=0x%x, addr=*0x%x, paddrlen=*0x%x)", s, buf, len, flags, addr, paddrlen);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
::sockaddr _addr;
|
||||
::socklen_t _paddrlen;
|
||||
|
||||
memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr));
|
||||
_addr.sa_family = addr->sa_family;
|
||||
::socklen_t _paddrlen;
|
||||
s32 ret = ::recvfrom(s, buf.get_ptr(), len, flags, &_addr, &_paddrlen);
|
||||
s32 ret = ::recvfrom(sock->s, buf.get_ptr(), len, flags, &_addr, &_paddrlen);
|
||||
*paddrlen = _paddrlen;
|
||||
get_errno() = getLastError();
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("recvfrom(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -340,10 +453,15 @@ namespace sys_net
|
|||
s32 send(s32 s, vm::cptr<char> buf, u32 len, s32 flags)
|
||||
{
|
||||
libnet.warning("send(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
s32 ret = ::send(s, buf.get_ptr(), len, flags);
|
||||
get_errno() = getLastError();
|
||||
s32 ret = ::send(sock->s, buf.get_ptr(), len, flags);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("send(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -357,24 +475,127 @@ namespace sys_net
|
|||
s32 sendto(s32 s, vm::cptr<char> buf, u32 len, s32 flags, vm::ptr<sockaddr> addr, u32 addrlen)
|
||||
{
|
||||
libnet.warning("sendto(s=%d, buf=*0x%x, len=%d, flags=0x%x, addr=*0x%x, addrlen=%d)", s, buf, len, flags, addr, addrlen);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
::sockaddr _addr;
|
||||
memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr));
|
||||
_addr.sa_family = addr->sa_family;
|
||||
s32 ret = ::sendto(s, buf.get_ptr(), len, flags, &_addr, addrlen);
|
||||
get_errno() = getLastError();
|
||||
s32 ret = ::sendto(sock->s, buf.get_ptr(), len, flags, &_addr, addrlen);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("sendto(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 setsockopt(s32 s, s32 level, s32 optname, vm::cptr<char> optval, u32 optlen)
|
||||
s32 setsockopt(s32 s, s32 level, s32 optname, vm::cptr<void> optval, u32 optlen)
|
||||
{
|
||||
libnet.warning("socket(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=%d)", s, level, optname, optval, optlen);
|
||||
s = g_socketMap[s];
|
||||
libnet.warning("setsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=%d)", s, level, optname, optval, optlen);
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
s32 ret = ::setsockopt(s, level, optname, optval.get_ptr(), optlen);
|
||||
get_errno() = getLastError();
|
||||
if (level != SOL_SOCKET && level != IPPROTO_TCP)
|
||||
{
|
||||
throw EXCEPTION("Invalid socket option level!");
|
||||
}
|
||||
|
||||
s32 ret;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (level == SOL_SOCKET)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
case OP_SO_NBIO:
|
||||
{
|
||||
unsigned long mode = *(unsigned long*)optval.get_ptr();
|
||||
ret = ioctlsocket(sock->s, FIONBIO, &mode);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw EXCEPTION("Unknown socket option for Win32: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
else if (level == PROTO_IPPROTO_TCP)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
case OP_TCP_NODELAY:
|
||||
{
|
||||
const char delay = *(char*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, sizeof(delay));
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_TCP_MAXSEG:
|
||||
{
|
||||
libnet.warning("TCP_MAXSEG can't be set on Windows.");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw EXCEPTION("Unknown TCP option for Win32: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (level == SOL_SOCKET)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
case OP_SO_NBIO:
|
||||
{
|
||||
// Obtain the flags
|
||||
s32 flags = fcntl(s, F_GETFL, 0);
|
||||
|
||||
if (flags < 0)
|
||||
{
|
||||
throw EXCEPTION("Failed to obtain socket flags.");
|
||||
}
|
||||
|
||||
u32 mode = *(u32*)optval.get_ptr();
|
||||
flags = mode ? (flags &~O_NONBLOCK) : (flags | O_NONBLOCK);
|
||||
|
||||
// Re-set the flags
|
||||
ret = fcntl(sock->s, F_SETFL, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw EXCEPTION("Unknown socket option for Unix: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
else if (level == PROTO_IPPROTO_TCP)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
case OP_TCP_NODELAY:
|
||||
{
|
||||
u32 delay = *(u32*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, optlen);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_TCP_MAXSEG:
|
||||
{
|
||||
u32 maxseg = *(u32*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_MAXSEG, &maxseg, optlen);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw EXCEPTION("Unknown TCP option for Win32: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
libnet.error("setsockopt(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -382,10 +603,15 @@ namespace sys_net
|
|||
s32 shutdown(s32 s, s32 how)
|
||||
{
|
||||
libnet.warning("shutdown(s=%d, how=%d)", s, how);
|
||||
s = g_socketMap[s];
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
s32 ret = ::shutdown(s, how);
|
||||
get_errno() = getLastError();
|
||||
s32 ret = ::shutdown(sock->s, how);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
libnet.error("shutdown(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -394,24 +620,56 @@ namespace sys_net
|
|||
{
|
||||
libnet.warning("socket(family=%d, type=%d, protocol=%d)", family, type, protocol);
|
||||
|
||||
s32 sock = ::socket(family, type, protocol);
|
||||
get_errno() = getLastError();
|
||||
if (type < 1 || type > 10 || (type > 4 && type < 6) || (type > 6 && type < 10))
|
||||
{
|
||||
get_errno() = SYS_NET_EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_socketMap.push_back(sock);
|
||||
return g_socketMap.size() - 1;
|
||||
// HACKS: Neither Unix nor Windows support TCP/UDP over UDPP2P.
|
||||
// But what's the usage of it anyways?
|
||||
if (type == SOCK_STREAM_P2P)
|
||||
{
|
||||
libnet.warning("SOCK_STREAM_P2P is not properly implemented.");
|
||||
type = SOCK_STREAM;
|
||||
}
|
||||
else if (type == SOCK_DGRAM_P2P)
|
||||
{
|
||||
libnet.warning("SOCK_DGRAM_P2P is not properly implemented.");
|
||||
type = SOCK_DGRAM;
|
||||
}
|
||||
|
||||
socket_t sock = ::socket(family, type, protocol);
|
||||
|
||||
if (sock < 0)
|
||||
{
|
||||
libnet.error("socket(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return idm::make<sys_net_socket>(sock);
|
||||
}
|
||||
|
||||
s32 socketclose(s32 s)
|
||||
{
|
||||
libnet.warning("socket(s=%d)", s);
|
||||
s = g_socketMap[s];
|
||||
libnet.warning("socketclose(s=%d)", s);
|
||||
std::shared_ptr<sys_net_socket> sock = idm::get<sys_net_socket>(s);
|
||||
|
||||
#ifdef _WIN32
|
||||
int ret = ::closesocket(s);
|
||||
s32 ret = ::closesocket(sock->s);
|
||||
#else
|
||||
int ret = ::close(s);
|
||||
s32 ret = ::close(sock->s);
|
||||
#endif
|
||||
get_errno() = getLastError();
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
libnet.error("socketclose(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
idm::get<sys_net_socket>(s)->s = -1;
|
||||
idm::remove<sys_net_socket>(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -444,27 +702,36 @@ namespace sys_net
|
|||
copy_fdset(&_writefds, writefds);
|
||||
copy_fdset(&_exceptfds, exceptfds);
|
||||
|
||||
s32 ret = ::select(nfds, &_readfds, &_writefds, &_exceptfds, timeout ? &_timeout : NULL);
|
||||
get_errno() = getLastError();
|
||||
|
||||
if (getLastError() >= 0)
|
||||
#ifdef _WIN32
|
||||
// On Unix, when the sets are empty (thus nothing to wait on), it waits until the timeout.
|
||||
// This behaviour is often used to "sleep" on Unix based systems.
|
||||
// WinSock in such case returns WSAEINVAL and doesn't allow such behaviour.
|
||||
// Since it's not possible on Windows, we just return and say that the timeout is over and hope that it's good enough.
|
||||
if (_readfds.fd_count == 0 && _writefds.fd_count == 0 && _exceptfds.fd_count == 0)
|
||||
{
|
||||
libnet.error("socketselect(): error %d", getLastError());
|
||||
return 0; // Timeout!
|
||||
}
|
||||
#endif
|
||||
|
||||
// There's no good way to determine nfds and it shouldn't be too slow, so let's let it check the whole set. It also isn't used on Windows.
|
||||
s32 ret = ::select(FD_SETSIZE, &_readfds, &_writefds, &_exceptfds, timeout ? &_timeout : nullptr);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
libnet.error("socketselect(): error %d", get_errno() = get_last_error());
|
||||
return -1;
|
||||
}
|
||||
|
||||
//return ret;
|
||||
return CELL_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 sys_net_initialize_network_ex(vm::ptr<sys_net_initialize_parameter_t> param)
|
||||
{
|
||||
libnet.warning("sys_net_initialize_network_ex(param=*0x%x)", param);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
#endif
|
||||
// Errno is set to 0 upon initialization
|
||||
get_errno() = 0;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -498,9 +765,9 @@ namespace sys_net
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_net_get_sockinfo()
|
||||
s32 sys_net_get_sockinfo(s32 s, vm::ptr<sys_net_sockinfo_t> p, s32 n)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(libnet);
|
||||
libnet.todo("sys_net_get_sockinfo()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -525,7 +792,6 @@ namespace sys_net
|
|||
vm::ptr<s32> _sys_net_errno_loc()
|
||||
{
|
||||
libnet.warning("_sys_net_errno_loc()");
|
||||
|
||||
return get_errno().ptr();
|
||||
}
|
||||
|
||||
|
@ -591,18 +857,18 @@ namespace sys_net
|
|||
|
||||
s32 sys_net_finalize_network()
|
||||
{
|
||||
libnet.warning("sys_net_initialize_network_ex()");
|
||||
libnet.warning("sys_net_finalize_network()");
|
||||
|
||||
// Errno is set to SYS_NET_EBUSY after finalization
|
||||
get_errno() = SYS_NET_EBUSY;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_net_h_errno_loc()
|
||||
vm::ptr<s32> _sys_net_h_errno_loc()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(libnet);
|
||||
return CELL_OK;
|
||||
libnet.warning("_sys_net_h_errno_loc()");
|
||||
return get_h_errno().ptr();
|
||||
}
|
||||
|
||||
s32 sys_net_set_netemu_test_param()
|
||||
|
@ -611,9 +877,9 @@ namespace sys_net
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_net_free_thread_context()
|
||||
s32 sys_net_free_thread_context(u64 tid, s32 flags)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(libnet);
|
||||
libnet.todo("sys_net_free_thread_context(tid=%d, flags=%d)", tid, flags);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,102 @@
|
|||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
// must die
|
||||
#undef s_addr
|
||||
|
||||
namespace sys_net
|
||||
{
|
||||
// Error codes
|
||||
enum
|
||||
{
|
||||
SYS_NET_ENOENT = 2,
|
||||
SYS_NET_EINTR = 4,
|
||||
SYS_NET_EBADF = 9,
|
||||
SYS_NET_ENOMEM = 12,
|
||||
SYS_NET_EACCES = 13,
|
||||
SYS_NET_EFAULT = 14,
|
||||
SYS_NET_EBUSY = 16,
|
||||
SYS_NET_EINVAL = 22,
|
||||
SYS_NET_EMFILE = 24,
|
||||
SYS_NET_ENOSPC = 28,
|
||||
SYS_NET_EPIPE = 32,
|
||||
SYS_NET_EAGAIN = 35,
|
||||
SYS_NET_EWOULDBLOCK = SYS_NET_EAGAIN,
|
||||
SYS_NET_EINPROGRESS = 36,
|
||||
SYS_NET_EALREADY = 37,
|
||||
SYS_NET_EDESTADDRREQ = 39,
|
||||
SYS_NET_EMSGSIZE = 40,
|
||||
SYS_NET_EPROTOTYPE = 41,
|
||||
SYS_NET_ENOPROTOOPT = 42,
|
||||
SYS_NET_EPROTONOSUPPORT = 43,
|
||||
SYS_NET_EOPNOTSUPP = 45,
|
||||
SYS_NET_EPFNOSUPPORT = 46,
|
||||
SYS_NET_EAFNOSUPPORT = 47,
|
||||
SYS_NET_EADDRINUSE = 48,
|
||||
SYS_NET_EADDRNOTAVAIL = 49,
|
||||
SYS_NET_ENETDOWN = 50,
|
||||
SYS_NET_ENETUNREACH = 51,
|
||||
SYS_NET_ECONNABORTED = 53,
|
||||
SYS_NET_ECONNRESET = 54,
|
||||
SYS_NET_ENOBUFS = 55,
|
||||
SYS_NET_EISCONN = 56,
|
||||
SYS_NET_ENOTCONN = 57,
|
||||
SYS_NET_ESHUTDOWN = 58,
|
||||
SYS_NET_ETOOMANYREFS = 59,
|
||||
SYS_NET_ETIMEDOUT = 60,
|
||||
SYS_NET_ECONNREFUSED = 61,
|
||||
SYS_NET_EHOSTDOWN = 64,
|
||||
SYS_NET_EHOSTUNREACH = 65,
|
||||
};
|
||||
|
||||
// Socket types
|
||||
enum
|
||||
{
|
||||
SOCK_STREAM = 1,
|
||||
SOCK_DGRAM = 2,
|
||||
SOCK_RAW = 3,
|
||||
SOCK_DGRAM_P2P = 6,
|
||||
SOCK_STREAM_P2P = 10,
|
||||
};
|
||||
|
||||
// Socket options
|
||||
// Note: All options are prefixed with "OP_" to prevent name conflicts.
|
||||
enum
|
||||
{
|
||||
OP_SO_SNDBUF = 0x1001,
|
||||
OP_SO_RCVBUF = 0x1002,
|
||||
OP_SO_SNDLOWAT = 0x1003,
|
||||
OP_SO_RCVLOWAT = 0x1004,
|
||||
OP_SO_SNDTIMEO = 0x1005,
|
||||
OP_SO_RCVTIMEO = 0x1006,
|
||||
OP_SO_ERROR = 0x1007,
|
||||
OP_SO_TYPE = 0x1008,
|
||||
OP_SO_NBIO = 0x1100, // Non-blocking IO
|
||||
OP_SO_TPPOLICY = 0x1101,
|
||||
};
|
||||
|
||||
// TCP options
|
||||
enum
|
||||
{
|
||||
OP_TCP_NODELAY = 1,
|
||||
OP_TCP_MAXSEG = 2,
|
||||
OP_TCP_MSS_TO_ADVERTISE = 3,
|
||||
};
|
||||
|
||||
// IP protocols
|
||||
// Note: Proctols are prefixed with "PROTO_" to prevent name conflicts
|
||||
enum
|
||||
{
|
||||
PROTO_IPPROTO_IP = 0,
|
||||
PROTO_IPPROTO_ICMP = 1,
|
||||
PROTO_IPPROTO_IGMP = 2,
|
||||
PROTO_IPPROTO_TCP = 6,
|
||||
PROTO_IPPROTO_UDP = 17,
|
||||
PROTO_IPPROTO_ICMPV6 = 58,
|
||||
};
|
||||
|
||||
// only for reference, no need to use it
|
||||
using in_addr_t = u32;
|
||||
using in_port_t = u16;
|
||||
using in_addr_t = u32;
|
||||
using in_port_t = u16;
|
||||
using sa_family_t = u8;
|
||||
using socklen_t = u32;
|
||||
using socklen_t = u32;
|
||||
|
||||
struct fd_set
|
||||
{
|
||||
|
@ -112,6 +198,19 @@ namespace sys_net
|
|||
be_t<s64> tv_sec;
|
||||
be_t<s64> tv_usec;
|
||||
};
|
||||
|
||||
struct sys_net_sockinfo_t
|
||||
{
|
||||
be_t<s32> s;
|
||||
be_t<s32> proto;
|
||||
be_t<s32> recv_queue_length;
|
||||
be_t<s32> send_queue_length;
|
||||
in_addr local_adr;
|
||||
be_t<s32> local_port;
|
||||
in_addr remote_adr;
|
||||
be_t<s32> remote_port;
|
||||
be_t<s32> state;
|
||||
};
|
||||
}
|
||||
|
||||
struct sys_net_initialize_parameter_t
|
||||
|
|
|
@ -124,7 +124,12 @@ s32 sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::c
|
|||
|
||||
s32 sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
{
|
||||
sys_fs.trace("sys_fs_read(fd=%d, buf=0x%x, nbytes=0x%llx, nread=0x%x)", fd, buf, nbytes, nread);
|
||||
sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread);
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_file_t>(fd);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include <thread>
|
||||
|
||||
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot");
|
||||
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true);
|
||||
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
|
||||
|
||||
std::string g_cfg_defaults;
|
||||
|
|
|
@ -254,9 +254,14 @@ Rpcs3App::Rpcs3App()
|
|||
#ifdef _WIN32
|
||||
timeBeginPeriod(1);
|
||||
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
|
||||
std::atexit([]
|
||||
{
|
||||
timeEndPeriod(1);
|
||||
WSACleanup();
|
||||
});
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue