From e5f756205c7884ab117f05d2e5a40125bd8f595c Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 25 Sep 2017 18:52:34 +0300 Subject: [PATCH] sys_net full rewrite Implement sys_net syscalls Clean libnet functions Use libnet.sprx Use libhttp.sprx Use libssl.sprx Use librudp.sprx Implement sys_ss_random_number_generator --- rpcs3/Emu/Cell/Modules/cellNetCtl.cpp | 4 + rpcs3/Emu/Cell/Modules/cellRudp.h | 6 +- rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp | 10 +- rpcs3/Emu/Cell/Modules/sys_net.cpp | 1359 ----------------- rpcs3/Emu/Cell/Modules/sys_net.h | 245 --- rpcs3/Emu/Cell/Modules/sys_net_.cpp | 737 +++++++++ rpcs3/Emu/Cell/Modules/sys_net_.h | 41 + rpcs3/Emu/Cell/PPUFunction.cpp | 10 +- rpcs3/Emu/Cell/PPUModule.cpp | 2 +- rpcs3/Emu/Cell/PPUModule.h | 2 +- rpcs3/Emu/Cell/PPUThread.cpp | 4 +- rpcs3/Emu/Cell/lv2/lv2.cpp | 57 +- rpcs3/Emu/Cell/lv2/sys_net.cpp | 1772 ++++++++++++++++++++++ rpcs3/Emu/Cell/lv2/sys_net.h | 383 +++++ rpcs3/Emu/Cell/lv2/sys_prx.cpp | 4 - rpcs3/Emu/Cell/lv2/sys_ss.cpp | 56 + rpcs3/Emu/Cell/lv2/sys_ss.h | 1 + rpcs3/Emu/System.cpp | 3 + rpcs3/emucore.vcxproj | 6 +- rpcs3/emucore.vcxproj.filters | 18 +- rpcs3/main.cpp | 3 - 21 files changed, 3061 insertions(+), 1662 deletions(-) delete mode 100644 rpcs3/Emu/Cell/Modules/sys_net.cpp delete mode 100644 rpcs3/Emu/Cell/Modules/sys_net.h create mode 100644 rpcs3/Emu/Cell/Modules/sys_net_.cpp create mode 100644 rpcs3/Emu/Cell/Modules/sys_net_.h create mode 100644 rpcs3/Emu/Cell/lv2/sys_net.cpp create mode 100644 rpcs3/Emu/Cell/lv2/sys_net.h diff --git a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp index 91461e6d9f..1f252e24fc 100644 --- a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp @@ -156,6 +156,10 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr info) { strcpy_trunc(info->netmask, "255.255.255.255"); } + else if (code == CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG) + { + info->http_proxy_config = 0; + } return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellRudp.h b/rpcs3/Emu/Cell/Modules/cellRudp.h index 5a314100a7..95d9f34530 100644 --- a/rpcs3/Emu/Cell/Modules/cellRudp.h +++ b/rpcs3/Emu/Cell/Modules/cellRudp.h @@ -1,7 +1,5 @@ #pragma once -#include "sys_net.h" - namespace vm { using namespace ps3; } // Return Codes @@ -79,7 +77,9 @@ enum CELL_RUDP_POLL_EV_ERROR = 0x0008, }; -using CellRudpEventHandler = s32(s32 event_id, s32 soc, vm::cptr data, u32 datalen, vm::cptr addr, u32 addrlen, vm::ptr arg); +struct sys_net_sockaddr; + +using CellRudpEventHandler = s32(s32 event_id, s32 soc, vm::cptr data, u32 datalen, vm::cptr addr, u32 addrlen, vm::ptr arg); using CellRudpAllocatorFuncAlloc = vm::ptr(u32 size); using CellRudpAllocatorFuncFree = void(vm::ptr ptr); diff --git a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index 15424290ae..17f4c5b334 100644 --- a/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -5,6 +5,7 @@ #include "Emu/Cell/lv2/sys_mutex.h" #include "Emu/Cell/lv2/sys_interrupt.h" #include "Emu/Cell/lv2/sys_process.h" +#include "Emu/Cell/lv2/sys_ss.h" #include "sysPrxForUser.h" logs::channel sysPrxForUser("sysPrxForUser"); @@ -71,7 +72,7 @@ s32 sys_process_get_paramsfo(vm::ptr buffer) return _sys_process_get_paramsfo(buffer); } -s32 sys_get_random_number(vm::ptr addr, u64 size) +s32 sys_get_random_number(vm::ptr addr, u64 size) { sysPrxForUser.warning("sys_get_random_number(addr=*0x%x, size=%d)", addr, size); @@ -80,9 +81,12 @@ s32 sys_get_random_number(vm::ptr addr, u64 size) return CELL_EINVAL; } - for (u32 i = 0; i < (u32)size; i++) + switch (u32 rs = sys_ss_random_number_generator(2, addr, size)) { - addr[i] = rand() & 0xff; + case 0x80010501: return CELL_ENOMEM; + case 0x80010503: return CELL_EAGAIN; + case 0x80010509: return CELL_EINVAL; + default: if (rs) return CELL_EABORT; } return CELL_OK; diff --git a/rpcs3/Emu/Cell/Modules/sys_net.cpp b/rpcs3/Emu/Cell/Modules/sys_net.cpp deleted file mode 100644 index 76912b9f06..0000000000 --- a/rpcs3/Emu/Cell/Modules/sys_net.cpp +++ /dev/null @@ -1,1359 +0,0 @@ -#include "stdafx.h" -#include "Emu/Cell/PPUModule.h" -#include "Emu/IdManager.h" - -#include "sys_net.h" - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#endif - -#include - -logs::channel libnet("libnet"); - -namespace sys_net -{ -#ifdef _WIN32 - using socket_t = SOCKET; - - bool socket_error(const socket_t& sock) - { - return sock == SOCKET_ERROR || sock == INVALID_SOCKET; - } -#else -#define SOCKET_ERROR (-1) - using socket_t = int; - - bool socket_error(const socket_t& sock) - { - return sock < 0; - } -#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"; - int saw_digit, octets, ch; - unsigned char tmp[4], *tp; - - saw_digit = 0; - octets = 0; - *(tp = tmp) = 0; - while ((ch = *src++) != '\0') { - const char *pch; - - if ((pch = strchr(digits, ch)) != NULL) { - unsigned int n = *tp * 10 + (pch - digits); - - if (n > 255) - return (0); - *tp = n; - if (! saw_digit) { - if (++octets > 4) - return (0); - saw_digit = 1; - } - } else if (ch == '.' && saw_digit) { - if (octets == 4) - return 0; - *++tp = 0; - saw_digit = 0; - } else - return (0); - } - if (octets < 4) - return 0; - - memcpy(dst, tmp, 4); - return 1; -} - -int inet_pton(int af, const char *src, char *dst) -{ - switch (af) { - case AF_INET: - return (inet_pton4(src, dst)); - - default: - errno = EAFNOSUPPORT; - return -1; - } -} - -// 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 -{ - static const u32 id_base = 0; - static const u32 id_step = 1; - static const u32 id_count = 1024; - - sys_net::socket_t s = SOCKET_ERROR; - - explicit sys_net_socket(s32 socket) : s(socket) - { - } - - ~sys_net_socket() - { - if (!sys_net::socket_error(s)) -#ifdef _WIN32 - ::closesocket(s); -#else - ::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 src) -{ - FD_ZERO(set); - - if (src) - { - // Go through the bit set fds_bits and calculate the - // socket FDs from it, setting it in the native fd-set. - - for (s32 i = 0; i < 32; i++) - { - for (s32 bit = 0; bit < 32; bit++) - { - if (src->fds_bits[i] & (1 << bit)) - { - sys_net::socket_t sock = idm::get((i << 5) | bit)->s; - //libnet.error("setting: fd %d", sock); - FD_SET(sock, set); - } - } - } - } -} - -namespace sys_net -{ - struct _tls_data_t - { - be_t _errno; - be_t _h_errno; - char addr[16]; - }; - - // TODO - thread_local vm::ptr<_tls_data_t> g_tls_net_data{}; - - static NEVER_INLINE void initialize_tls() - { - // allocate if not initialized - 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()] - { - vm::dealloc_verbose_nothrow(addr, vm::main); - }); - } - } - - vm::ref get_errno() - { - initialize_tls(); - - return g_tls_net_data.ref(&_tls_data_t::_errno); - } - - vm::ref get_h_errno() - { - initialize_tls(); - - 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: libnet.error("Unknown/illegal socket error: %d" HERE, code); - } - - if (name && result != SYS_NET_EWOULDBLOCK) - { - libnet.error("Socket error %s", name); - } - - return result; -#undef ERROR_CASE - } - - // Functions - s32 accept(s32 s, vm::ptr addr, vm::ptr paddrlen) - { - libnet.warning("accept(s=%d, family=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("accept(): socket does not exist"); - return -1; - } - - 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 - { - ::sockaddr _addr; - ::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; - addr->sa_len = _paddrlen; - addr->sa_family = _addr.sa_family; - memcpy(addr->sa_data, _addr.sa_data, addr->sa_len - 2); - } - - return idm::make(ret); - } - - s32 bind(s32 s, vm::cptr addr, u32 addrlen) - { - libnet.warning("bind(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("bind(): socket does not exist"); - return -1; - } - - ::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 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; - } - - s32 connect(s32 s, vm::ptr addr, u32 addrlen) - { - libnet.warning("connect(s=%d, family=*0x%x, addrlen=%d)", s, addr, addrlen); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("connect(): socket does not exist"); - return -1; - } - - ::sockaddr_in saddr; - memcpy(&saddr, addr.get_ptr(), sizeof(::sockaddr_in)); - saddr.sin_family = addr->sa_family; - - 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; - } - - s32 gethostbyaddr() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 gethostbyname() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 getpeername() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 getsockname() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 getsockopt() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - u32 inet_addr(vm::cptr cp) - { - libnet.warning("inet_addr(cp=%s)", cp); - return htonl(::inet_addr(cp.get_ptr())); // return a big-endian IP address (WTF? function should return LITTLE-ENDIAN value) - } - - s32 inet_aton() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 inet_lnaof() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 inet_makeaddr() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 inet_netof() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 inet_network() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - vm::ptr inet_ntoa(u32 in) - { - 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::make(vm::get_addr(g_tls_net_data->addr)); - } - - vm::cptr inet_ntop(s32 af, vm::ptr src, vm::ptr dst, u32 size) - { - libnet.warning("inet_ntop(af=%d, src=%s, dst=*0x%x, size=%d)", af, src, dst, size); - const char* result = ::inet_ntop(af, src.get_ptr(), dst.get_ptr(), size); - - if (result == nullptr) - { - return vm::null; - } - - return dst; - } - - s32 inet_pton(s32 af, vm::cptr src, vm::ptr dst) - { - libnet.warning("inet_pton(af=%d, src=%s, dst=*0x%x)", af, src, dst); - return ::inet_pton(af, src.get_ptr(), dst.get_ptr()); - } - - s32 listen(s32 s, s32 backlog) - { - libnet.warning("listen(s=%d, backlog=%d)", s, backlog); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("listen(): socket does not exist"); - return -1; - } - - s32 ret = ::listen(sock->s, backlog); - - if (ret != 0) - { - libnet.error("listen(): error %d", get_errno() = get_last_error()); - return -1; - } - - return ret; - } - - s32 recv(s32 s, vm::ptr buf, u32 len, s32 flags) - { - libnet.warning("recv(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("recv(): socket does not exist"); - return -1; - } - - 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; - } - - s32 recvfrom(s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr addr, vm::ptr 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); - std::shared_ptr sock = idm::get(s); - - ::sockaddr _addr; - ::socklen_t _paddrlen; - - memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr)); - _addr.sa_family = addr->sa_family; - - if (!sock || !buf || len == 0) - { - libnet.error("recvfrom(): invalid arguments buf= *0x%x, len=%d", buf, len); - return SYS_NET_EINVAL; - } - - if (s < 0) { - libnet.error("recvfrom(): invalid socket %d", s); - return SYS_NET_EBADF; - } - - s32 ret = ::recvfrom(sock->s, buf.get_ptr(), len, flags, &_addr, &_paddrlen); - *paddrlen = _paddrlen; - - if (ret < 0) - { - libnet.error("recvfrom(): error %d", get_errno() = get_last_error()); - return -1; - } - - return ret; - } - - s32 recvmsg() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 send(s32 s, vm::cptr buf, u32 len, s32 flags) - { - libnet.warning("send(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("send(): socket does not exist"); - return -1; - } - - 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; - } - - s32 sendmsg() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sendto(s32 s, vm::cptr buf, u32 len, s32 flags, vm::ptr 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); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("sendto(): socket does not exist"); - return -1; - } - - ::sockaddr _addr; - memcpy(&_addr, addr.get_ptr(), sizeof(::sockaddr)); - _addr.sa_family = addr->sa_family; - 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 optval, u32 optlen) - { - libnet.warning("setsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=%d)", s, level, optname, optval, optlen); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("setsockopt(): socket does not exist"); - return -1; - } - - if (level != PS3_SOL_SOCKET && level != IPPROTO_TCP) - { - fmt::throw_exception("Invalid socket option level!" HERE); - } - - s32 ret; - - if (level == PS3_SOL_SOCKET) - { - switch (optname) - { -#ifdef _WIN32 - case OP_SO_NBIO: - { - u_long mode = *static_cast*>(optval.get_ptr()); - ret = ioctlsocket(sock->s, FIONBIO, &mode); - break; - } -#else - case OP_SO_NBIO: - { - // Obtain the flags - s32 flags = fcntl(s, F_GETFL, 0); - - if (flags < 0) - { - fmt::throw_exception("Failed to obtain socket flags." HERE); - } - - 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; - } -#endif - case OP_SO_SNDBUF: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_SNDBUF, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_RCVBUF: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_RCVBUF, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_SNDTIMEO: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_SNDTIMEO, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_RCVTIMEO: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_RCVTIMEO, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_SNDLOWAT: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_SNDLOWAT, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_RCVLOWAT: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_RCVLOWAT, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_USECRYPTO: - { - libnet.todo("Socket option OP_SO_USECRYPTO is unimplemented"); - ret = CELL_OK; - break; - } - case OP_SO_USESIGNATURE: - { - libnet.todo("Socket option OP_SO_USESIGNATURE is unimplemented"); - ret = CELL_OK; - break; - } - case OP_SO_BROADCAST: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_BROADCAST, (const char*)¶m, sizeof(param)); - break; - } - case OP_SO_REUSEADDR: - { - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, SOL_SOCKET, SO_REUSEADDR, (const char*)¶m, sizeof(param)); - break; - } - default: - libnet.error("Unknown socket option: 0x%x", optname); - } - } - else if (level == PROTO_IPPROTO_TCP) - { - switch (optname) - { - case OP_TCP_NODELAY: - { -#ifdef _WIN32 - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, (const char*)¶m, sizeof(param)); -#else - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, (const char*)¶m, sizeof(param)); -#endif - break; - } - - case OP_TCP_MAXSEG: - { -#ifdef _WIN32 - libnet.warning("TCP_MAXSEG can't be set on Windows."); -#else - const u32 param = *static_cast*>(optval.get_ptr()); - ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_MAXSEG, (const char*)¶m, sizeof(param)); -#endif - break; - } - - default: - libnet.error("Unknown TCP option: 0x%x", optname); - } - } - - if (ret != 0) - { - libnet.error("setsockopt(): error %d", get_errno() = get_last_error()); - return -1; - } - - return ret; - } - - s32 shutdown(s32 s, s32 how) - { - libnet.warning("shutdown(s=%d, how=%d)", s, how); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("shutdown(): non existent socket cannot be shutdown"); - return -1; - } - - s32 ret = ::shutdown(sock->s, how); - - if (ret != 0) - { - libnet.error("shutdown(): error %d", get_errno() = get_last_error()); - return -1; - } - - return ret; - } - - s32 socket(s32 family, s32 type, s32 protocol) - { - libnet.warning("socket(family=%d, type=%d, protocol=%d)", family, type, protocol); - - if (type < 1 || type > 10 || (type > 4 && type < 6) || (type > 6 && type < 10)) - { - get_errno() = SYS_NET_EPROTONOSUPPORT; - return -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 (socket_error(sock)) - { - libnet.error("socket(): error %d", get_errno() = get_last_error()); - return -1; - } - - return idm::make(sock); - } - - s32 socketclose(s32 s) - { - libnet.warning("socketclose(s=%d)", s); - std::shared_ptr sock = idm::get(s); - - if (!sock) - { - libnet.error("socketclose(): socket does not exist, or was already closed"); - return -1; - } - -#ifdef _WIN32 - s32 ret = ::closesocket(sock->s); -#else - s32 ret = ::close(sock->s); -#endif - - if (ret != 0) - { - libnet.error("socketclose(): error %d", get_errno() = get_last_error()); - return -1; - } - - idm::get(s)->s = -1; - idm::remove(s); - - return ret; - } - - s32 socketpoll() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 socketselect(s32 nfds, vm::ptr readfds, vm::ptr writefds, vm::ptr exceptfds, vm::ptr timeout) - { - libnet.warning("socketselect(nfds=%d, readfds=*0x%x, writefds=*0x%x, exceptfds=*0x%x, timeout.tv_sec=%d, timeout.tv_usec=%d)", - nfds, readfds, writefds, exceptfds, timeout->tv_sec, timeout->tv_usec); - ::timeval _timeout; - - if (timeout) - { - _timeout.tv_sec = timeout->tv_sec; - _timeout.tv_usec = timeout->tv_usec; - } - - if (_timeout.tv_usec >= 1000000) - { - _timeout.tv_sec = _timeout.tv_sec ? _timeout.tv_sec - 1 : _timeout.tv_sec + 1; - _timeout.tv_usec = 0; - } - - ::fd_set _readfds; - ::fd_set _writefds; - ::fd_set _exceptfds; - - // Copy the fd_sets to native ones - copy_fdset(&_readfds, readfds); - copy_fdset(&_writefds, writefds); - copy_fdset(&_exceptfds, exceptfds); - -#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) - { - 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; - } - - s32 sys_net_initialize_network_ex(vm::ptr param) - { - libnet.warning("sys_net_initialize_network_ex(param=*0x%x)", param); - - // Errno is set to 0 upon initialization - get_errno() = 0; - - return CELL_OK; - } - - s32 sys_net_get_udpp2p_test_param() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_set_udpp2p_test_param() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_lib_name_server() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_if_ctl() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_if_list() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_name_server() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_netemu_test_param() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_routing_table_af() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_sockinfo(s32 s, vm::ptr p, s32 n) - { - libnet.todo("sys_net_get_sockinfo()"); - return CELL_OK; - } - - s32 sys_net_close_dump() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_set_test_param() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_show_nameserver() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - vm::ptr _sys_net_errno_loc() - { - libnet.warning("_sys_net_errno_loc()"); - return get_errno().ptr(); - } - - s32 sys_net_set_resolver_configurations() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_show_route() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_read_dump() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_abort_resolver() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_abort_socket() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_set_lib_name_server() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_test_param() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_get_sockinfo_ex() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_open_dump() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_show_ifconfig() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_finalize_network() - { - libnet.warning("sys_net_finalize_network()"); - - // Errno is set to SYS_NET_EBUSY after finalization - get_errno() = SYS_NET_EBUSY; - - return CELL_OK; - } - - vm::ptr _sys_net_h_errno_loc() - { - libnet.warning("_sys_net_h_errno_loc()"); - return get_h_errno().ptr(); - } - - s32 sys_net_set_netemu_test_param() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_net_free_thread_context(u64 tid, s32 flags) - { - libnet.todo("sys_net_free_thread_context(tid=%d, flags=%d)", tid, flags); - return CELL_OK; - } - - s32 _sys_net_lib_abort() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_bnet_control() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 __sys_net_lib_calloc() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_free() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_get_system_time() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_if_nametoindex() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_ioctl() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 __sys_net_lib_malloc() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_rand() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 __sys_net_lib_realloc() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_reset_libnetctl_queue() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_set_libnetctl_queue() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_thread_create() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_thread_exit() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_thread_join() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_sync_clear() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_sync_create() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_sync_destroy() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_sync_signal() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_sync_wait() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_sysctl() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sys_net_lib_usleep() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_abort() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_close() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_get_if_id() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_get_status() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_if_down() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_get_key_value() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - s32 sys_netset_if_up() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 sys_netset_open() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_get_name_server() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_add_name_server() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_add_name_server_with_char() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_flush_route() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_set_default_gateway() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_set_ip_and_mask() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } - - s32 _sce_net_set_name_server() - { - UNIMPLEMENTED_FUNC(libnet); - return CELL_OK; - } -} - -// Define macro for namespace -#define REG_FUNC_(name) REG_FNID(sys_net, ppu_generate_id(#name), sys_net::name) - -DECLARE(ppu_module_manager::libnet)("sys_net", []() -{ - REG_FUNC_(accept); - REG_FUNC_(bind); - REG_FUNC_(connect); - REG_FUNC_(gethostbyaddr); - REG_FUNC_(gethostbyname); - REG_FUNC_(getpeername); - REG_FUNC_(getsockname); - REG_FUNC_(getsockopt); - REG_FUNC_(inet_addr); - REG_FUNC_(inet_aton); - REG_FUNC_(inet_lnaof); - REG_FUNC_(inet_makeaddr); - REG_FUNC_(inet_netof); - REG_FUNC_(inet_network); - REG_FUNC_(inet_ntoa); - REG_FUNC_(inet_ntop); - REG_FUNC_(inet_pton); - REG_FUNC_(listen); - REG_FUNC_(recv); - REG_FUNC_(recvfrom); - REG_FUNC_(recvmsg); - REG_FUNC_(send); - REG_FUNC_(sendmsg); - REG_FUNC_(sendto); - REG_FUNC_(setsockopt); - REG_FUNC_(shutdown); - REG_FUNC_(socket); - REG_FUNC_(socketclose); - REG_FUNC_(socketpoll); - REG_FUNC_(socketselect); - - REG_FUNC_(sys_net_initialize_network_ex); - REG_FUNC_(sys_net_get_udpp2p_test_param); - REG_FUNC_(sys_net_set_udpp2p_test_param); - REG_FUNC_(sys_net_get_lib_name_server); - REG_FUNC_(sys_net_if_ctl); - REG_FUNC_(sys_net_get_if_list); - REG_FUNC_(sys_net_get_name_server); - REG_FUNC_(sys_net_get_netemu_test_param); - REG_FUNC_(sys_net_get_routing_table_af); - REG_FUNC_(sys_net_get_sockinfo); - REG_FUNC_(sys_net_close_dump); - REG_FUNC_(sys_net_set_test_param); - REG_FUNC_(sys_net_show_nameserver); - REG_FUNC_(_sys_net_errno_loc); - REG_FUNC_(sys_net_set_resolver_configurations); - REG_FUNC_(sys_net_show_route); - REG_FUNC_(sys_net_read_dump); - REG_FUNC_(sys_net_abort_resolver); - REG_FUNC_(sys_net_abort_socket); - REG_FUNC_(sys_net_set_lib_name_server); - REG_FUNC_(sys_net_get_test_param); - REG_FUNC_(sys_net_get_sockinfo_ex); - REG_FUNC_(sys_net_open_dump); - REG_FUNC_(sys_net_show_ifconfig); - REG_FUNC_(sys_net_finalize_network); - REG_FUNC_(_sys_net_h_errno_loc); - REG_FUNC_(sys_net_set_netemu_test_param); - REG_FUNC_(sys_net_free_thread_context); - - REG_FUNC_(_sys_net_lib_abort); - REG_FUNC_(_sys_net_lib_bnet_control); - REG_FUNC_(__sys_net_lib_calloc); - REG_FUNC_(_sys_net_lib_free); - REG_FUNC_(_sys_net_lib_get_system_time); - REG_FUNC_(_sys_net_lib_if_nametoindex); - REG_FUNC_(_sys_net_lib_ioctl); - REG_FUNC_(__sys_net_lib_malloc); - REG_FUNC_(_sys_net_lib_rand); - REG_FUNC_(__sys_net_lib_realloc); - REG_FUNC_(_sys_net_lib_reset_libnetctl_queue); - REG_FUNC_(_sys_net_lib_set_libnetctl_queue); - - REG_FUNC_(_sys_net_lib_thread_create); - REG_FUNC_(_sys_net_lib_thread_exit); - REG_FUNC_(_sys_net_lib_thread_join); - - REG_FUNC_(_sys_net_lib_sync_clear); - REG_FUNC_(_sys_net_lib_sync_create); - REG_FUNC_(_sys_net_lib_sync_destroy); - REG_FUNC_(_sys_net_lib_sync_signal); - REG_FUNC_(_sys_net_lib_sync_wait); - - REG_FUNC_(_sys_net_lib_sysctl); - REG_FUNC_(_sys_net_lib_usleep); - - REG_FUNC_(sys_netset_abort); - REG_FUNC_(sys_netset_close); - REG_FUNC_(sys_netset_get_if_id); - REG_FUNC_(sys_netset_get_key_value); - REG_FUNC_(sys_netset_get_status); - REG_FUNC_(sys_netset_if_down); - REG_FUNC_(sys_netset_if_up); - REG_FUNC_(sys_netset_open); - - REG_FUNC_(_sce_net_add_name_server); - REG_FUNC_(_sce_net_add_name_server_with_char); - REG_FUNC_(_sce_net_flush_route); - - REG_FUNC_(_sce_net_get_name_server); - REG_FUNC_(_sce_net_set_default_gateway); - REG_FUNC_(_sce_net_set_ip_and_mask); - REG_FUNC_(_sce_net_set_name_server); -}); diff --git a/rpcs3/Emu/Cell/Modules/sys_net.h b/rpcs3/Emu/Cell/Modules/sys_net.h deleted file mode 100644 index 3cbac55b8d..0000000000 --- a/rpcs3/Emu/Cell/Modules/sys_net.h +++ /dev/null @@ -1,245 +0,0 @@ -#if defined(__FreeBSD__) -#include -#undef fds_bits -#endif - -#pragma once - -namespace vm { using namespace ps3; } - -namespace sys_net -{ - -// It turns out SOL_SOCKET is equal to 1 on Linux, but 0xffff on Windows, and it appears the PS3 uses 0xffff, like Windows -#define PS3_SOL_SOCKET 0xffff - // 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, - - OP_SO_REUSEADDR = 0x0004, - OP_SO_KEEPALIVE = 0x0008, - OP_SO_BROADCAST = 0x0020, - OP_SO_LINGER = 0x0080, - OP_SO_OOBINLINE = 0x0100, - OP_SO_REUSEPORT = 0x0200, - OP_SO_ONESBCAST = 0x0800, - OP_SO_USECRYPTO = 0x1000, - OP_SO_USESIGNATURE = 0x2000, - }; - - // 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 sa_family_t = u8; - using socklen_t = u32; - - struct fd_set - { - be_t fds_bits[32]; - }; - - struct hostent - { - vm::bptr h_name; - vm::bpptr h_aliases; - be_t h_addrtype; - be_t h_length; - vm::bpptr h_addr_list; - }; - - struct in_addr - { - be_t s_addr; - }; - - struct iovec - { - be_t zero1; - vm::bptr iov_base; - be_t zero2; - be_t iov_len; - }; - - struct ip_mreq - { - be_t imr_multiaddr; - be_t imr_interface; - }; - - struct msghdr - { - be_t zero1; - vm::bptr msg_name; - be_t msg_namelen; - be_t pad1; - be_t zero2; - vm::bptr msg_iov; - be_t msg_iovlen; - be_t pad2; - be_t zero3; - vm::bptr msg_control; - be_t msg_controllen; - be_t msg_flags; - }; - - struct pollfd - { - be_t fd; - be_t events; - be_t revents; - }; - - struct sockaddr - { - u8 sa_len; - u8 sa_family; - char sa_data[14]; - }; - - struct sockaddr_dl - { - u8 sdl_len; - u8 sdl_family; - be_t sdl_index; - u8 sdl_type; - u8 sdl_nlen; - u8 sdl_alen; - u8 sdl_slen; - char sdl_data[12]; - }; - - struct sockaddr_in - { - u8 sin_len; - u8 sin_family; - be_t sin_port; - be_t sin_addr; - char sin_zero[8]; - }; - - struct sockaddr_in_p2p - { - u8 sin_len; - u8 sin_family; - be_t sin_port; - be_t sin_addr; - be_t sin_vport; - char sin_zero[6]; - }; - - struct timeval - { - be_t tv_sec; - be_t tv_usec; - }; - - struct sys_net_sockinfo_t - { - be_t s; - be_t proto; - be_t recv_queue_length; - be_t send_queue_length; - in_addr local_adr; - be_t local_port; - in_addr remote_adr; - be_t remote_port; - be_t state; - }; -} - -struct sys_net_initialize_parameter_t -{ - vm::bptr memory; - be_t memory_size; - be_t flags; -}; - -// PS3 libnet socket struct -struct net_socket_t -{ - std::intptr_t native_handle; -}; diff --git a/rpcs3/Emu/Cell/Modules/sys_net_.cpp b/rpcs3/Emu/Cell/Modules/sys_net_.cpp new file mode 100644 index 0000000000..ec824cba46 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/sys_net_.cpp @@ -0,0 +1,737 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/IdManager.h" + +#include "sys_net_.h" + +namespace vm { using namespace ps3; } + +logs::channel libnet("libnet"); + +struct sys_net_tls_data +{ + be_t _errno; + be_t _h_errno; + char addr[16]; +}; + +// TODO +thread_local vm::ptr g_tls_net_data{}; + +static NEVER_INLINE vm::ptr get_tls() +{ + // Allocate if not initialized + 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()] + { + vm::dealloc_verbose_nothrow(addr, vm::main); + }); + } + + return g_tls_net_data; +} + +s32 sys_net_accept(s32 s, vm::ptr addr, vm::ptr paddrlen) +{ + libnet.todo("accept(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); + + return 0; +} + +s32 sys_net_bind(s32 s, vm::cptr addr, u32 addrlen) +{ + libnet.todo("bind(s=%d, addr=*0x%x, addrlen=%u)", s, addr, addrlen); + + return 0; +} + +s32 sys_net_connect(s32 s, vm::ptr addr, u32 addrlen) +{ + libnet.todo("connect(s=%d, addr=*0x%x, addrlen=%u)", s, addr, addrlen); + + return 0; +} + +s32 sys_net_gethostbyaddr() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_gethostbyname() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_getpeername(s32 s, vm::ptr addr, vm::ptr paddrlen) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_getsockname(s32 s, vm::ptr addr, vm::ptr paddrlen) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_getsockopt(s32 s, s32 level, s32 optname, vm::ptr optval, vm::ptr optlen) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +u32 sys_net_inet_addr(vm::cptr cp) +{ + libnet.todo("inet_addr(cp=%s)", cp); + + return 0xffffffff; +} + +s32 sys_net_inet_aton() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_inet_lnaof() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_inet_makeaddr() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_inet_netof() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_inet_network() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +vm::ptr sys_net_inet_ntoa(u32 in) +{ + libnet.todo("inet_ntoa(in=0x%x)", in); + + return vm::null; +} + +vm::cptr sys_net_inet_ntop(s32 af, vm::ptr src, vm::ptr dst, u32 size) +{ + libnet.todo("inet_ntop(af=%d, src=%s, dst=*0x%x, size=%d)", af, src, dst, size); + + return vm::null; +} + +s32 sys_net_inet_pton(s32 af, vm::cptr src, vm::ptr dst) +{ + libnet.todo("inet_pton(af=%d, src=%s, dst=*0x%x)", af, src, dst); + + return 0; +} + +s32 sys_net_listen(s32 s, s32 backlog) +{ + libnet.todo("listen(s=%d, backlog=%d)", s, backlog); + + return 0; +} + +s32 sys_net_recv(s32 s, vm::ptr buf, u32 len, s32 flags) +{ + libnet.todo("recv(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags); + + return 0; +} + +s32 sys_net_recvfrom(s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr addr, vm::ptr paddrlen) +{ + libnet.todo("recvfrom(s=%d, buf=*0x%x, len=%d, flags=0x%x, addr=*0x%x, paddrlen=*0x%x)", s, buf, len, flags, addr, paddrlen); + + return 0; +} + +s32 sys_net_recvmsg(s32 s, vm::ptr msg, s32 flags) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_send(s32 s, vm::cptr buf, u32 len, s32 flags) +{ + libnet.todo("send(s=%d, buf=*0x%x, len=%d, flags=0x%x)", s, buf, len, flags); + + return 0; +} + +s32 sys_net_sendmsg(s32 s, vm::cptr msg, s32 flags) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_sendto(s32 s, vm::cptr buf, u32 len, s32 flags, vm::cptr addr, u32 addrlen) +{ + libnet.todo("sendto(s=%d, buf=*0x%x, len=%d, flags=0x%x, addr=*0x%x, addrlen=%d)", s, buf, len, flags, addr, addrlen); + + return 0; +} + +s32 sys_net_setsockopt(s32 s, s32 level, s32 optname, vm::cptr optval, u32 optlen) +{ + libnet.todo("setsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=%d)", s, level, optname, optval, optlen); + + return 0; +} + +s32 sys_net_shutdown(s32 s, s32 how) +{ + libnet.todo("shutdown(s=%d, how=%d)", s, how); + + return 0; +} + +s32 sys_net_socket(s32 family, s32 type, s32 protocol) +{ + libnet.todo("socket(family=%d, type=%d, protocol=%d)", family, type, protocol); + + return 0; +} + +s32 sys_net_socketclose(s32 s) +{ + libnet.warning("socketclose(s=%d)", s); + + return 0; +} + +s32 sys_net_socketpoll(vm::ptr fds, s32 nfds, s32 ms) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_socketselect(s32 nfds, vm::ptr readfds, vm::ptr writefds, vm::ptr exceptfds, vm::ptr timeout) +{ + libnet.todo("socketselect(nfds=%d, readfds=*0x%x, writefds=*0x%x, exceptfds=*0x%x, timeout=*0x%x)", nfds, readfds, writefds, exceptfds, timeout); + + return 0; +} + +s32 sys_net_initialize_network_ex(vm::ptr param) +{ + libnet.todo("sys_net_initialize_network_ex(param=*0x%x)", param); + + return CELL_OK; +} + +s32 sys_net_get_udpp2p_test_param() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_set_udpp2p_test_param() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_lib_name_server() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_if_ctl() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_if_list() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_name_server() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_netemu_test_param() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_routing_table_af() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_sockinfo(s32 s, vm::ptr p, s32 n) +{ + libnet.todo("sys_net_get_sockinfo(s=%d, p=*0x%x, n=%d)", s, p, n); + + return CELL_OK; +} + +s32 sys_net_close_dump(s32 id, vm::ptr pflags) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_set_test_param() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_show_nameserver() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +vm::ptr _sys_net_errno_loc() +{ + libnet.warning("_sys_net_errno_loc()"); + + return get_tls().ptr(&sys_net_tls_data::_errno); +} + +s32 sys_net_set_resolver_configurations() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_show_route() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_read_dump(s32 id, vm::ptr buf, s32 len, vm::ptr pflags) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_abort_resolver() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_abort_socket() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_set_lib_name_server() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_test_param() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_get_sockinfo_ex() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_open_dump(s32 len, s32 flags) +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_show_ifconfig() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_finalize_network() +{ + libnet.todo("sys_net_finalize_network()"); + + return CELL_OK; +} + +vm::ptr _sys_net_h_errno_loc() +{ + libnet.warning("_sys_net_h_errno_loc()"); + + return get_tls().ptr(&sys_net_tls_data::_h_errno); +} + +s32 sys_net_set_netemu_test_param() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_net_free_thread_context(u64 tid, s32 flags) +{ + libnet.todo("sys_net_free_thread_context(tid=0x%x, flags=%d)", tid, flags); + + return CELL_OK; +} + +s32 _sys_net_lib_abort() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_bnet_control() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 __sys_net_lib_calloc() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_free() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_get_system_time() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_if_nametoindex() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_ioctl() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 __sys_net_lib_malloc() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_rand() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 __sys_net_lib_realloc() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_reset_libnetctl_queue() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_set_libnetctl_queue() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_thread_create() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_thread_exit() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_thread_join() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_sync_clear() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_sync_create() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_sync_destroy() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_sync_signal() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_sync_wait() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_sysctl() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sys_net_lib_usleep() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_abort() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_close() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_get_if_id() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_get_status() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_if_down() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_get_key_value() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} +s32 sys_netset_if_up() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 sys_netset_open() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_get_name_server() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_add_name_server() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_add_name_server_with_char() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_flush_route() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_set_default_gateway() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_set_ip_and_mask() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +s32 _sce_net_set_name_server() +{ + UNIMPLEMENTED_FUNC(libnet); + return CELL_OK; +} + +DECLARE(ppu_module_manager::sys_net)("sys_net", []() +{ + REG_FNID(sys_net, "accept", sys_net_accept); + REG_FNID(sys_net, "bind", sys_net_bind); + REG_FNID(sys_net, "connect", sys_net_connect); + REG_FNID(sys_net, "gethostbyaddr", sys_net_gethostbyaddr); + REG_FNID(sys_net, "gethostbyname", sys_net_gethostbyname); + REG_FNID(sys_net, "getpeername", sys_net_getpeername); + REG_FNID(sys_net, "getsockname", sys_net_getsockname); + REG_FNID(sys_net, "getsockopt", sys_net_getsockopt); + REG_FNID(sys_net, "inet_addr", sys_net_inet_addr); + REG_FNID(sys_net, "inet_aton", sys_net_inet_aton); + REG_FNID(sys_net, "inet_lnaof", sys_net_inet_lnaof); + REG_FNID(sys_net, "inet_makeaddr", sys_net_inet_makeaddr); + REG_FNID(sys_net, "inet_netof", sys_net_inet_netof); + REG_FNID(sys_net, "inet_network", sys_net_inet_network); + REG_FNID(sys_net, "inet_ntoa", sys_net_inet_ntoa); + REG_FNID(sys_net, "inet_ntop", sys_net_inet_ntop); + REG_FNID(sys_net, "inet_pton", sys_net_inet_pton); + REG_FNID(sys_net, "listen", sys_net_listen); + REG_FNID(sys_net, "recv", sys_net_recv); + REG_FNID(sys_net, "recvfrom", sys_net_recvfrom); + REG_FNID(sys_net, "recvmsg", sys_net_recvmsg); + REG_FNID(sys_net, "send", sys_net_send); + REG_FNID(sys_net, "sendmsg", sys_net_sendmsg); + REG_FNID(sys_net, "sendto", sys_net_sendto); + REG_FNID(sys_net, "setsockopt", sys_net_setsockopt); + REG_FNID(sys_net, "shutdown", sys_net_shutdown); + REG_FNID(sys_net, "socket", sys_net_socket); + REG_FNID(sys_net, "socketclose", sys_net_socketclose); + REG_FNID(sys_net, "socketpoll", sys_net_socketpoll); + REG_FNID(sys_net, "socketselect", sys_net_socketselect); + + REG_FUNC(sys_net, sys_net_initialize_network_ex); + REG_FUNC(sys_net, sys_net_get_udpp2p_test_param); + REG_FUNC(sys_net, sys_net_set_udpp2p_test_param); + REG_FUNC(sys_net, sys_net_get_lib_name_server); + REG_FUNC(sys_net, sys_net_if_ctl); + REG_FUNC(sys_net, sys_net_get_if_list); + REG_FUNC(sys_net, sys_net_get_name_server); + REG_FUNC(sys_net, sys_net_get_netemu_test_param); + REG_FUNC(sys_net, sys_net_get_routing_table_af); + REG_FUNC(sys_net, sys_net_get_sockinfo); + REG_FUNC(sys_net, sys_net_close_dump); + REG_FUNC(sys_net, sys_net_set_test_param); + REG_FUNC(sys_net, sys_net_show_nameserver); + REG_FUNC(sys_net, _sys_net_errno_loc); + REG_FUNC(sys_net, sys_net_set_resolver_configurations); + REG_FUNC(sys_net, sys_net_show_route); + REG_FUNC(sys_net, sys_net_read_dump); + REG_FUNC(sys_net, sys_net_abort_resolver); + REG_FUNC(sys_net, sys_net_abort_socket); + REG_FUNC(sys_net, sys_net_set_lib_name_server); + REG_FUNC(sys_net, sys_net_get_test_param); + REG_FUNC(sys_net, sys_net_get_sockinfo_ex); + REG_FUNC(sys_net, sys_net_open_dump); + REG_FUNC(sys_net, sys_net_show_ifconfig); + REG_FUNC(sys_net, sys_net_finalize_network); + REG_FUNC(sys_net, _sys_net_h_errno_loc); + REG_FUNC(sys_net, sys_net_set_netemu_test_param); + REG_FUNC(sys_net, sys_net_free_thread_context); + + REG_FUNC(sys_net, _sys_net_lib_abort); + REG_FUNC(sys_net, _sys_net_lib_bnet_control); + REG_FUNC(sys_net, __sys_net_lib_calloc); + REG_FUNC(sys_net, _sys_net_lib_free); + REG_FUNC(sys_net, _sys_net_lib_get_system_time); + REG_FUNC(sys_net, _sys_net_lib_if_nametoindex); + REG_FUNC(sys_net, _sys_net_lib_ioctl); + REG_FUNC(sys_net, __sys_net_lib_malloc); + REG_FUNC(sys_net, _sys_net_lib_rand); + REG_FUNC(sys_net, __sys_net_lib_realloc); + REG_FUNC(sys_net, _sys_net_lib_reset_libnetctl_queue); + REG_FUNC(sys_net, _sys_net_lib_set_libnetctl_queue); + + REG_FUNC(sys_net, _sys_net_lib_thread_create); + REG_FUNC(sys_net, _sys_net_lib_thread_exit); + REG_FUNC(sys_net, _sys_net_lib_thread_join); + + REG_FUNC(sys_net, _sys_net_lib_sync_clear); + REG_FUNC(sys_net, _sys_net_lib_sync_create); + REG_FUNC(sys_net, _sys_net_lib_sync_destroy); + REG_FUNC(sys_net, _sys_net_lib_sync_signal); + REG_FUNC(sys_net, _sys_net_lib_sync_wait); + + REG_FUNC(sys_net, _sys_net_lib_sysctl); + REG_FUNC(sys_net, _sys_net_lib_usleep); + + REG_FUNC(sys_net, sys_netset_abort); + REG_FUNC(sys_net, sys_netset_close); + REG_FUNC(sys_net, sys_netset_get_if_id); + REG_FUNC(sys_net, sys_netset_get_key_value); + REG_FUNC(sys_net, sys_netset_get_status); + REG_FUNC(sys_net, sys_netset_if_down); + REG_FUNC(sys_net, sys_netset_if_up); + REG_FUNC(sys_net, sys_netset_open); + + REG_FUNC(sys_net, _sce_net_add_name_server); + REG_FUNC(sys_net, _sce_net_add_name_server_with_char); + REG_FUNC(sys_net, _sce_net_flush_route); + + REG_FUNC(sys_net, _sce_net_get_name_server); + REG_FUNC(sys_net, _sce_net_set_default_gateway); + REG_FUNC(sys_net, _sce_net_set_ip_and_mask); + REG_FUNC(sys_net, _sce_net_set_name_server); +}); diff --git a/rpcs3/Emu/Cell/Modules/sys_net_.h b/rpcs3/Emu/Cell/Modules/sys_net_.h new file mode 100644 index 0000000000..1263ee2226 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/sys_net_.h @@ -0,0 +1,41 @@ +#pragma once + +#include "Emu/Cell/lv2/sys_net.h" +#include "Emu/Memory/vm.h" + +struct sys_net_sockinfo_t +{ + be_t s; + be_t proto; + be_t recv_queue_length; + be_t send_queue_length; + sys_net_in_addr local_adr; + be_t local_port; + sys_net_in_addr remote_adr; + be_t remote_port; + be_t state; +}; + +struct sys_net_sockinfo_ex_t +{ + be_t s; + be_t proto; + be_t recv_queue_length; + be_t send_queue_length; + sys_net_in_addr local_adr; + be_t local_port; + sys_net_in_addr remote_adr; + be_t remote_port; + be_t state; + be_t socket_type; + be_t local_vport; + be_t remote_vport; + be_t reserved[8]; +}; + +struct sys_net_initialize_parameter_t +{ + vm::ps3::bptr memory; + be_t memory_size; + be_t flags; +}; diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp index d257b0e787..e2d85c994e 100644 --- a/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -413,16 +413,16 @@ extern std::string ppu_get_syscall_name(u64 code) case 708: return "sys_net_bnet_recvmsg"; case 709: return "sys_net_bnet_sendmsg"; case 710: return "sys_net_bnet_sendto"; - case 711: return "sys_net_bnet_setsockop"; + case 711: return "sys_net_bnet_setsockopt"; case 712: return "sys_net_bnet_shutdown"; case 713: return "sys_net_bnet_socket"; case 714: return "sys_net_bnet_close"; case 715: return "sys_net_bnet_poll"; case 716: return "sys_net_bnet_select"; - case 717: return "sys_net_open_dump"; - case 718: return "sys_net_read_dump"; - case 719: return "sys_net_close_dump"; - case 720: return "sys_net_write_dump"; + case 717: return "_sys_net_open_dump"; + case 718: return "_sys_net_read_dump"; + case 719: return "_sys_net_close_dump"; + case 720: return "_sys_net_write_dump"; case 721: return "sys_net_abort"; case 722: return "sys_net_infoctl"; case 723: return "sys_net_control"; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index a5578f1452..ce6c6f63d7 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -248,7 +248,7 @@ static void ppu_initialize_modules(const std::shared_ptr& link &ppu_module_manager::sceNpTus, &ppu_module_manager::sceNpUtil, &ppu_module_manager::sys_io, - &ppu_module_manager::libnet, + &ppu_module_manager::sys_net, &ppu_module_manager::sysPrxForUser, &ppu_module_manager::sys_libc, &ppu_module_manager::sys_lv2dbg, diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h index 720469ef6e..10082a6f26 100644 --- a/rpcs3/Emu/Cell/PPUModule.h +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -243,7 +243,7 @@ public: static const ppu_static_module sceNpTus; static const ppu_static_module sceNpUtil; static const ppu_static_module sys_io; - static const ppu_static_module libnet; + static const ppu_static_module sys_net; static const ppu_static_module sysPrxForUser; static const ppu_static_module sys_libc; static const ppu_static_module sys_lv2dbg; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 65065cb16d..41640cf2e5 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1164,9 +1164,9 @@ extern void ppu_initialize(const ppu_module& info) sha1_update(&ctx, vm::ps3::_ptr(func.addr), func.size); } - if (info.name == "liblv2.sprx") + if (info.name == "liblv2.sprx" || info.name == "libsysmodule.sprx" || info.name == "libnet.sprx") { - const be_t forced_upd = 2; + const be_t forced_upd = 3; sha1_update(&ctx, reinterpret_cast(&forced_upd), sizeof(forced_upd)); } diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 55f797b19f..339f65b543 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -14,6 +14,7 @@ #include "sys_interrupt.h" #include "sys_memory.h" #include "sys_mmapper.h" +#include "sys_net.h" #include "sys_ppu_thread.h" #include "sys_process.h" #include "sys_prx.h" @@ -663,33 +664,33 @@ const std::array s_ppu_syscall_table null_func,//BIND_FUNC(sys_...) //697 (0x2B9) UNS null_func,//BIND_FUNC(sys_...) //698 (0x2BA) UNS null_func,//BIND_FUNC(sys_bdemu_send_command) //699 (0x2BB) - null_func,//BIND_FUNC(sys_net_bnet_accept) //700 (0x2BC) - null_func,//BIND_FUNC(sys_net_bnet_bind) //701 (0x2BD) - null_func,//BIND_FUNC(sys_net_bnet_connect) //702 (0x2BE) - null_func,//BIND_FUNC(sys_net_bnet_getpeername) //703 (0x2BF) - null_func,//BIND_FUNC(sys_net_bnet_getsockname) //704 (0x2C0) - null_func,//BIND_FUNC(sys_net_bnet_getsockopt) //705 (0x2C1) - null_func,//BIND_FUNC(sys_net_bnet_listen) //706 (0x2C2) - null_func,//BIND_FUNC(sys_net_bnet_recvfrom) //707 (0x2C3) - null_func,//BIND_FUNC(sys_net_bnet_recvmsg) //708 (0x2C4) - null_func,//BIND_FUNC(sys_net_bnet_sendmsg) //709 (0x2C5) - null_func,//BIND_FUNC(sys_net_bnet_sendto) //710 (0x2C6) - null_func,//BIND_FUNC(sys_net_bnet_setsockop) //711 (0x2C7) - null_func,//BIND_FUNC(sys_net_bnet_shutdown) //712 (0x2C8) - null_func,//BIND_FUNC(sys_net_bnet_socket) //713 (0x2C9) - null_func,//BIND_FUNC(sys_net_bnet_close) //714 (0x2CA) - null_func,//BIND_FUNC(sys_net_bnet_poll) //715 (0x2CB) - null_func,//BIND_FUNC(sys_net_bnet_select) //716 (0x2CC) - null_func,//BIND_FUNC(sys_net_open_dump) //717 (0x2CD) - null_func,//BIND_FUNC(sys_net_read_dump) //718 (0x2CE) - null_func,//BIND_FUNC(sys_net_close_dump) //719 (0x2CF) - null_func,//BIND_FUNC(sys_net_write_dump) //720 (0x2D0) - null_func,//BIND_FUNC(sys_net_abort) //721 (0x2D1) - null_func,//BIND_FUNC(sys_net_infoctl) //722 (0x2D2) - null_func,//BIND_FUNC(sys_net_control) //723 (0x2D3) - null_func,//BIND_FUNC(sys_net_bnet_ioctl) //724 (0x2D4) - null_func,//BIND_FUNC(sys_net_bnet_sysctl) //725 (0x2D5) - null_func,//BIND_FUNC(sys_net_eurus_post_command) //726 (0x2D6) + BIND_FUNC(sys_net_bnet_accept), //700 (0x2BC) + BIND_FUNC(sys_net_bnet_bind), //701 (0x2BD) + BIND_FUNC(sys_net_bnet_connect), //702 (0x2BE) + BIND_FUNC(sys_net_bnet_getpeername), //703 (0x2BF) + BIND_FUNC(sys_net_bnet_getsockname), //704 (0x2C0) + BIND_FUNC(sys_net_bnet_getsockopt), //705 (0x2C1) + BIND_FUNC(sys_net_bnet_listen), //706 (0x2C2) + BIND_FUNC(sys_net_bnet_recvfrom), //707 (0x2C3) + BIND_FUNC(sys_net_bnet_recvmsg), //708 (0x2C4) + BIND_FUNC(sys_net_bnet_sendmsg), //709 (0x2C5) + BIND_FUNC(sys_net_bnet_sendto), //710 (0x2C6) + BIND_FUNC(sys_net_bnet_setsockopt), //711 (0x2C7) + BIND_FUNC(sys_net_bnet_shutdown), //712 (0x2C8) + BIND_FUNC(sys_net_bnet_socket), //713 (0x2C9) + BIND_FUNC(sys_net_bnet_close), //714 (0x2CA) + BIND_FUNC(sys_net_bnet_poll), //715 (0x2CB) + BIND_FUNC(sys_net_bnet_select), //716 (0x2CC) + BIND_FUNC(_sys_net_open_dump), //717 (0x2CD) + BIND_FUNC(_sys_net_read_dump), //718 (0x2CE) + BIND_FUNC(_sys_net_close_dump), //719 (0x2CF) + BIND_FUNC(_sys_net_write_dump), //720 (0x2D0) + BIND_FUNC(sys_net_abort), //721 (0x2D1) + BIND_FUNC(sys_net_infoctl), //722 (0x2D2) + BIND_FUNC(sys_net_control), //723 (0x2D3) + BIND_FUNC(sys_net_bnet_ioctl), //724 (0x2D4) + BIND_FUNC(sys_net_bnet_sysctl), //725 (0x2D5) + BIND_FUNC(sys_net_eurus_post_command), //726 (0x2D6) null_func, null_func, null_func, //729 UNS null_func, null_func, null_func, null_func, null_func, //734 UNS @@ -765,7 +766,7 @@ const std::array s_ppu_syscall_table null_func,//BIND_FUNC(syscall_...) //862 ROOT null_func,//BIND_FUNC(syscall_...) //863 ROOT null_func,//BIND_FUNC(syscall_...) //864 DBG - null_func,//BIND_FUNC(sys_ss_random_number_generator), //865 (0x361) ROOT AUTHID + BIND_FUNC(sys_ss_random_number_generator), //865 (0x361) null_func,//BIND_FUNC(sys_...) //866 ROOT null_func,//BIND_FUNC(sys_...) //867 ROOT null_func,//BIND_FUNC(sys_...) //868 ROOT / DBG AUTHID diff --git a/rpcs3/Emu/Cell/lv2/sys_net.cpp b/rpcs3/Emu/Cell/lv2/sys_net.cpp new file mode 100644 index 0000000000..608a042998 --- /dev/null +++ b/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -0,0 +1,1772 @@ +#include "stdafx.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUThread.h" +#include "Utilities/Thread.h" + +#include "sys_sync.h" +#include "sys_net.h" + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace vm { using namespace ps3; } + +logs::channel sys_net("sys_net"); + +static std::vector s_to_awake; + +static semaphore<> s_nw_mutex; + +extern u64 get_system_time(); + +// Error helper functions +static s32 get_last_error(bool is_blocking, int native_error = 0) +{ + // Convert the error code for socket functions to a one for sys_net + s32 result; + const char* name{}; + +#ifdef _WIN32 + if (!native_error) + { + native_error = WSAGetLastError(); + } + + switch (native_error) +#define ERROR_CASE(error) case WSA ## error: result = SYS_NET_ ## error; name = #error; break; +#else + if (!native_error) + { + native_error = errno; + } + + switch (native_error) +#define ERROR_CASE(error) case error: result = SYS_NET_ ## error; name = #error; break; +#endif + { + ERROR_CASE(EWOULDBLOCK); + ERROR_CASE(EINPROGRESS); + ERROR_CASE(EALREADY); + ERROR_CASE(ENOTCONN); + ERROR_CASE(ECONNRESET); + default: sys_net.error("Unknown/illegal socket error: %d", native_error); + } + + if (name && result != SYS_NET_EWOULDBLOCK && result != SYS_NET_EINPROGRESS) + { + sys_net.error("Socket error %s", name); + } + + if (is_blocking && result == SYS_NET_EWOULDBLOCK) + { + return 0; + } + + if (is_blocking && result == SYS_NET_EINPROGRESS) + { + return 0; + } + + return result; +#undef ERROR_CASE +} + +static void network_clear_queue(ppu_thread& ppu) +{ + idm::select([&](u32 id, lv2_socket& sock) + { + semaphore_lock lock(sock.mutex); + + for (auto it = sock.queue.begin(); it != sock.queue.end();) + { + if (it->first == ppu.id) + { + it = sock.queue.erase(it); + continue; + } + + it++; + } + + if (sock.queue.empty()) + { + sock.events = {}; + } + }); +} + +extern void network_thread_init() +{ + thread_ctrl::spawn("Network Thread", []() + { + std::vector> socklist; + socklist.reserve(lv2_socket::id_count); + + s_to_awake.clear(); + +#ifdef _WIN32 + HANDLE _eventh = CreateEventW(nullptr, false, false, nullptr); + + WSADATA wsa_data; + WSAStartup(MAKEWORD(2, 2), &wsa_data); +#else + ::pollfd fds[lv2_socket::id_count]{}; +#endif + + do + { + // Wait with 1ms timeout +#ifdef _WIN32 + WaitForSingleObjectEx(_eventh, 1, false); +#else + ::poll(fds, socklist.size(), 1); +#endif + + semaphore_lock lock(s_nw_mutex); + + for (std::size_t i = 0; i < socklist.size(); i++) + { + bs_t events{}; + + lv2_socket& sock = *socklist[i]; + +#ifdef _WIN32 + WSANETWORKEVENTS nwe; + if (WSAEnumNetworkEvents(sock.socket, nullptr, &nwe) == 0) + { + sock.ev_set |= nwe.lNetworkEvents; + + if (sock.ev_set & (FD_READ | FD_ACCEPT | FD_CLOSE) && sock.events.test_and_reset(lv2_socket::poll::read)) + events += lv2_socket::poll::read; + if (sock.ev_set & (FD_WRITE | FD_CONNECT) && sock.events.test_and_reset(lv2_socket::poll::write)) + events += lv2_socket::poll::write; + + if ((nwe.lNetworkEvents & FD_READ && nwe.iErrorCode[FD_READ_BIT]) || + (nwe.lNetworkEvents & FD_ACCEPT && nwe.iErrorCode[FD_ACCEPT_BIT]) || + (nwe.lNetworkEvents & FD_CLOSE && nwe.iErrorCode[FD_CLOSE_BIT]) || + (nwe.lNetworkEvents & FD_WRITE && nwe.iErrorCode[FD_WRITE_BIT]) || + (nwe.lNetworkEvents & FD_CONNECT && nwe.iErrorCode[FD_CONNECT_BIT])) + { + // TODO + if (sock.events.test_and_reset(lv2_socket::poll::error)) + events += lv2_socket::poll::error; + } + } + else + { + sys_net.error("WSAEnumNetworkEvents() failed (s=%d)", i); + } +#else + if (fds[i].revents & (POLLIN | POLLHUP) && socklist[i]->events.test_and_reset(lv2_socket::poll::read)) + events += lv2_socket::poll::read; + if (fds[i].revents & POLLOUT && socklist[i]->events.test_and_reset(lv2_socket::poll::write)) + events += lv2_socket::poll::write; + if (fds[i].revents & POLLERR && socklist[i]->events.test_and_reset(lv2_socket::poll::error)) + events += lv2_socket::poll::error; +#endif + + if (test(events)) + { + semaphore_lock lock(socklist[i]->mutex); + + for (auto it = socklist[i]->queue.begin(); test(events) && it != socklist[i]->queue.end();) + { + if (it->second(events)) + { + it = socklist[i]->queue.erase(it); + continue; + } + + it++; + } + + if (socklist[i]->queue.empty()) + { + socklist[i]->events = {}; + } + } + } + + s_to_awake.erase(std::unique(s_to_awake.begin(), s_to_awake.end()), s_to_awake.end()); + + for (ppu_thread* ppu : s_to_awake) + { + network_clear_queue(*ppu); + lv2_obj::awake(*ppu); + } + + s_to_awake.clear(); + socklist.clear(); + + // Obtain all active sockets + idm::select([&](u32 id, lv2_socket&) + { + socklist.emplace_back(idm::get_unlocked(id)); + }); + + for (std::size_t i = 0; i < socklist.size(); i++) + { + auto events = socklist[i]->events.load(); + +#ifdef _WIN32 + verify(HERE), 0 == WSAEventSelect(socklist[i]->socket, _eventh, FD_READ | FD_ACCEPT | FD_CLOSE | FD_WRITE | FD_CONNECT); +#else + fds[i].fd = test(events) ? socklist[i]->socket : -1; + fds[i].events = + (test(events, lv2_socket::poll::read) ? POLLIN : 0) | + (test(events, lv2_socket::poll::write) ? POLLOUT : 0) | + 0; + fds[i].revents = 0; +#endif + } + } + while (!Emu.IsStopped()); + +#ifdef _WIN32 + CloseHandle(_eventh); + WSACleanup(); +#endif + }); +} + +lv2_socket::lv2_socket(lv2_socket::socket_type s) + : socket(s) +{ + // Set non-blocking +#ifdef _WIN32 + u_long _true = 1; + ::ioctlsocket(socket, FIONBIO, &_true); +#else + ::fcntl(socket, F_SETFL, ::fcntl(socket, F_GETFL, 0) | O_NONBLOCK); +#endif +} + +lv2_socket::~lv2_socket() +{ +#ifdef _WIN32 + ::closesocket(socket); +#else + ::close(socket); +#endif +} + +s32 sys_net_bnet_accept(ppu_thread& ppu, s32 s, vm::ptr addr, vm::ptr paddrlen) +{ + sys_net.warning("sys_net_bnet_accept(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); + + lv2_socket::socket_type native_socket = -1; + ::sockaddr_storage native_addr; + ::socklen_t native_addrlen = sizeof(native_addr); + s32 result = 0; + + const auto sock = idm::check(s, [&](lv2_socket& sock) + { + semaphore_lock lock(sock.mutex); + + //if (!test(sock.events, lv2_socket::poll::read)) + { +#ifdef _WIN32 + sock.ev_set &= ~FD_ACCEPT; +#endif + native_socket = ::accept(sock.socket, (::sockaddr*)&native_addr, &native_addrlen); + + if (native_socket != -1) + { + return true; + } + + result = get_last_error(!sock.so_nbio); + + if (result) + { + return false; + } + } + + // Enable read event + sock.events += lv2_socket::poll::read; + sock.queue.emplace_back(ppu.id, [&](bs_t events) -> bool + { + if (test(events, lv2_socket::poll::read)) + { +#ifdef _WIN32 + sock.ev_set &= ~FD_ACCEPT; +#endif + native_socket = ::accept(sock.socket, (::sockaddr*)&native_addr, &native_addrlen); + + if (native_socket != -1 || (result = get_last_error(!sock.so_nbio))) + { + lv2_obj::awake(ppu); + return true; + } + } + + sock.events += lv2_socket::poll::read; + return false; + }); + + lv2_obj::sleep(ppu); + return false; + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + if (!sock.ret && result) + { + return -result; + } + + if (!sock.ret) + { + while (!ppu.state.test_and_reset(cpu_flag::signal)) + { + thread_ctrl::wait(); + } + + if (result) + { + return -result; + } + + if (ppu.gpr[3] == -SYS_NET_EINTR) + { + return -SYS_NET_EINTR; + } + } + + auto newsock = std::make_shared(native_socket); + + result = idm::import_existing(newsock); + + if (result == -1) + { + return -SYS_NET_EMFILE; + } + + if (addr) + { + verify(HERE), native_addr.ss_family == AF_INET; + + vm::ptr paddr = vm::cast(addr.addr()); + + if (paddrlen) + { + *paddrlen = sizeof(sys_net_sockaddr_in); + } + + paddr->sin_len = sizeof(sys_net_sockaddr_in); + paddr->sin_family = SYS_NET_AF_INET; + paddr->sin_port = ntohs(((::sockaddr_in*)&native_addr)->sin_port); + paddr->sin_addr = ntohl(((::sockaddr_in*)&native_addr)->sin_addr.s_addr); + paddr->sin_zero = 0; + } + + // Socket id + return result; +} + +s32 sys_net_bnet_bind(ppu_thread& ppu, s32 s, vm::cptr addr, u32 addrlen) +{ + sys_net.warning("sys_net_bnet_bind(s=%d, addr=*0x%x, addrlen=%u)", s, addr, addrlen); + + if (addr->sa_family != SYS_NET_AF_INET) + { + sys_net.error("sys_net_bnet_bind(s=%d): unsupported sa_family (%d)", s, addr->sa_family); + return -SYS_NET_EAFNOSUPPORT; + } + + ::sockaddr_in name{}; + name.sin_family = AF_INET; + name.sin_port = htons(((sys_net_sockaddr_in*)addr.get_ptr())->sin_port); + name.sin_addr.s_addr = htonl(((sys_net_sockaddr_in*)addr.get_ptr())->sin_addr); + ::socklen_t namelen = sizeof(name); + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + + if (::bind(sock.socket, (::sockaddr*)&name, namelen) == 0) + { + return 0; + } + + return get_last_error(false); + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_connect(ppu_thread& ppu, s32 s, vm::ptr addr, u32 addrlen) +{ + sys_net.warning("sys_net_bnet_connect(s=%d, addr=*0x%x, addrlen=%u)", s, addr, addrlen); + + s32 result = 0; + ::sockaddr_in name{}; + name.sin_family = AF_INET; + name.sin_port = htons(((sys_net_sockaddr_in*)addr.get_ptr())->sin_port); + name.sin_addr.s_addr = htonl(((sys_net_sockaddr_in*)addr.get_ptr())->sin_addr); + ::socklen_t namelen = sizeof(name); + + const auto sock = idm::check(s, [&](lv2_socket& sock) + { + semaphore_lock lock(sock.mutex); + + if (addr->sa_family == 0 && !((sys_net_sockaddr_in*)addr.get_ptr())->sin_port && !((sys_net_sockaddr_in*)addr.get_ptr())->sin_addr) + { + // Hack for DNS (8.8.8.8:53) + name.sin_port = htons(53); + name.sin_addr.s_addr = 0x08080808; + + // Overwrite arg (probably used to validate recvfrom addr) + ((sys_net_sockaddr_in*)addr.get_ptr())->sin_family = SYS_NET_AF_INET; + ((sys_net_sockaddr_in*)addr.get_ptr())->sin_port = 53; + ((sys_net_sockaddr_in*)addr.get_ptr())->sin_addr = 0x08080808; + sys_net.warning("sys_net_bnet_connect(s=%d): using DNS 8.8.8.8:53..."); + } + else if (addr->sa_family != SYS_NET_AF_INET) + { + sys_net.error("sys_net_bnet_connect(s=%d): unsupported sa_family (%d)", s, addr->sa_family); + } + + if (::connect(sock.socket, (::sockaddr*)&name, namelen) == 0) + { + return true; + } + + const bool is_blocking = !sock.so_nbio; + + result = get_last_error(is_blocking); + + if (result) + { + if (result == SYS_NET_EWOULDBLOCK) + { + result = SYS_NET_EINPROGRESS; + } + + if (result == SYS_NET_EINPROGRESS) + { + sock.events += lv2_socket::poll::write; + sock.queue.emplace_back(u32{0}, [&sock](bs_t events) -> bool + { + if (test(events, lv2_socket::poll::write)) + { +#ifdef _WIN32 + sock.ev_set &= ~FD_CONNECT; +#endif + int native_error; + ::socklen_t size = sizeof(native_error); + if (::getsockopt(sock.socket, SOL_SOCKET, SO_ERROR, (char*)&native_error, &size) != 0 || size != sizeof(int)) + { + sock.so_error = 1; + } + else + { + // TODO: check error formats (both native and translated) + sock.so_error = native_error ? get_last_error(false, native_error) : 0; + } + + return true; + } + + sock.events += lv2_socket::poll::write; + return false; + }); + } + + return false; + } + + sock.events += lv2_socket::poll::write; + sock.queue.emplace_back(ppu.id, [&](bs_t events) -> bool + { + if (test(events, lv2_socket::poll::write)) + { +#ifdef _WIN32 + sock.ev_set &= ~FD_CONNECT; +#endif + int native_error; + ::socklen_t size = sizeof(native_error); + if (::getsockopt(sock.socket, SOL_SOCKET, SO_ERROR, (char*)&native_error, &size) != 0 || size != sizeof(int)) + { + result = 1; + } + else + { + // TODO: check error formats (both native and translated) + result = native_error ? get_last_error(false, native_error) : 0; + } + + lv2_obj::awake(ppu); + return true; + } + + sock.events += lv2_socket::poll::write; + return false; + }); + + lv2_obj::sleep(ppu); + return false; + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + if (!sock.ret && result) + { + return -result; + } + + if (!sock.ret) + { + while (!ppu.state.test_and_reset(cpu_flag::signal)) + { + thread_ctrl::wait(); + } + + if (result) + { + return -result; + } + + if (ppu.gpr[3] == -SYS_NET_EINTR) + { + return -SYS_NET_EINTR; + } + } + + return CELL_OK; +} + +s32 sys_net_bnet_getpeername(ppu_thread& ppu, s32 s, vm::ptr addr, vm::ptr paddrlen) +{ + sys_net.warning("sys_net_bnet_getpeername(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + + ::sockaddr_storage native_addr; + ::socklen_t native_addrlen = sizeof(native_addr); + + if (::getpeername(sock.socket, (::sockaddr*)&native_addr, &native_addrlen) == 0) + { + verify(HERE), native_addr.ss_family == AF_INET; + + vm::ptr paddr = vm::cast(addr.addr()); + + if (paddrlen) + { + *paddrlen = sizeof(sys_net_sockaddr_in); + } + + paddr->sin_len = sizeof(sys_net_sockaddr_in); + paddr->sin_family = SYS_NET_AF_INET; + paddr->sin_port = ntohs(((::sockaddr_in*)&native_addr)->sin_port); + paddr->sin_addr = ntohl(((::sockaddr_in*)&native_addr)->sin_addr.s_addr); + paddr->sin_zero = 0; + return 0; + } + + return get_last_error(false); + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_getsockname(ppu_thread& ppu, s32 s, vm::ptr addr, vm::ptr paddrlen) +{ + sys_net.warning("sys_net_bnet_getsockname(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + + ::sockaddr_storage native_addr; + ::socklen_t native_addrlen = sizeof(native_addr); + + if (::getsockname(sock.socket, (::sockaddr*)&native_addr, &native_addrlen) == 0) + { + verify(HERE), native_addr.ss_family == AF_INET; + + vm::ptr paddr = vm::cast(addr.addr()); + + if (paddrlen) + { + *paddrlen = sizeof(sys_net_sockaddr_in); + } + + paddr->sin_len = sizeof(sys_net_sockaddr_in); + paddr->sin_family = SYS_NET_AF_INET; + paddr->sin_port = ntohs(((::sockaddr_in*)&native_addr)->sin_port); + paddr->sin_addr = ntohl(((::sockaddr_in*)&native_addr)->sin_addr.s_addr); + paddr->sin_zero = 0; + return 0; + } + + return get_last_error(false); + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_getsockopt(ppu_thread& ppu, s32 s, s32 level, s32 optname, vm::ptr optval, vm::ptr optlen) +{ + sys_net.warning("sys_net_bnet_getsockopt(s=%d, level=0x%x, optname=0x%x, optval=*0x%x, optlen=*0x%x)", s, level, optname, optval, optlen); + + int native_level = -1; + int native_opt = -1; + + union + { + char ch[128]; + int _int = 0; + ::timeval timeo; + ::linger linger; + } native_val; + ::socklen_t native_len = sizeof(native_val); + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + + if (*optlen < sizeof(int)) + { + return SYS_NET_EINVAL; + } + + if (level == SYS_NET_SOL_SOCKET) + { + native_level = SOL_SOCKET; + + switch (optname) + { + case SYS_NET_SO_NBIO: + { + // Special + *(be_t*)optval.get_ptr() = sock.so_nbio; + return 0; + } + case SYS_NET_SO_ERROR: + { + // Special + *(be_t*)optval.get_ptr() = std::exchange(sock.so_error, 0); + return 0; + } + case SYS_NET_SO_KEEPALIVE: + { + native_opt = SO_KEEPALIVE; + break; + } + case SYS_NET_SO_SNDBUF: + { + native_opt = SO_SNDBUF; + break; + } + case SYS_NET_SO_RCVBUF: + { + native_opt = SO_RCVBUF; + break; + } + case SYS_NET_SO_SNDLOWAT: + { + native_opt = SO_SNDLOWAT; + break; + } + case SYS_NET_SO_RCVLOWAT: + { + native_opt = SO_RCVLOWAT; + break; + } + case SYS_NET_SO_BROADCAST: + { + native_opt = SO_BROADCAST; + break; + } + case SYS_NET_SO_REUSEADDR: + { + native_opt = SO_REUSEADDR; + break; + } + case SYS_NET_SO_SNDTIMEO: + case SYS_NET_SO_RCVTIMEO: + { + if (*optlen < sizeof(sys_net_timeval)) + return SYS_NET_EINVAL; + + native_opt = optname == SYS_NET_SO_SNDTIMEO ? SO_SNDTIMEO : SO_RCVTIMEO; + break; + } + case SYS_NET_SO_LINGER: + { + if (*optlen < sizeof(sys_net_linger)) + return SYS_NET_EINVAL; + + native_opt = SO_LINGER; + break; + } + default: + { + sys_net.error("sys_net_bnet_getsockopt(s=%d, SOL_SOCKET): unknown option (0x%x)", s, optname); + return SYS_NET_EINVAL; + } + } + } + else if (level == SYS_NET_IPPROTO_TCP) + { + native_level = IPPROTO_TCP; + + switch (optname) + { + case SYS_NET_TCP_MAXSEG: + { + // Special (no effect) + *(be_t*)optval.get_ptr() = sock.so_tcp_maxseg; + return 0; + } + case SYS_NET_TCP_NODELAY: + { + native_opt = TCP_NODELAY; + break; + } + default: + { + sys_net.error("sys_net_bnet_getsockopt(s=%d, IPPROTO_TCP): unknown option (0x%x)", s, optname); + return SYS_NET_EINVAL; + } + } + } + else + { + sys_net.error("sys_net_bnet_getsockopt(s=%d): unknown level (0x%x)", s, level); + return SYS_NET_EINVAL; + } + + if (::getsockopt(sock.socket, native_level, native_opt, native_val.ch, &native_len) != 0) + { + return get_last_error(false); + } + + if (level == SYS_NET_SOL_SOCKET) + { + switch (optname) + { + case SYS_NET_SO_SNDTIMEO: + case SYS_NET_SO_RCVTIMEO: + { + // TODO + *(sys_net_timeval*)optval.get_ptr() = { ::narrow(native_val.timeo.tv_sec), ::narrow(native_val.timeo.tv_usec) }; + return 0; + } + case SYS_NET_SO_LINGER: + { + // TODO + *(sys_net_linger*)optval.get_ptr() = { ::narrow(native_val.linger.l_onoff), ::narrow(native_val.linger.l_linger) }; + return 0; + } + } + } + + // Fallback to int + *(be_t*)optval.get_ptr() = native_val._int; + return 0; + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_listen(ppu_thread& ppu, s32 s, s32 backlog) +{ + sys_net.warning("sys_net_bnet_listen(s=%d, backlog=%d)", s, backlog); + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + + if (::listen(sock.socket, backlog) == 0) + { + return 0; + } + + return get_last_error(false); + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_recvfrom(ppu_thread& ppu, s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr addr, vm::ptr paddrlen) +{ + sys_net.warning("sys_net_bnet_recvfrom(s=%d, buf=*0x%x, len=%u, flags=0x%x, addr=*0x%x, paddrlen=*0x%x)", s, buf, len, flags, addr, paddrlen); + + if (flags & ~(SYS_NET_MSG_PEEK | SYS_NET_MSG_DONTWAIT | SYS_NET_MSG_WAITALL)) + { + fmt::throw_exception("sys_net_bnet_recvfrom(s=%d): unknown flags (0x%x)", flags); + } + + int native_flags = 0; + int native_result = -1; + ::sockaddr_storage native_addr; + ::socklen_t native_addrlen = sizeof(native_addr); + s32 result = 0; + + if (flags & SYS_NET_MSG_PEEK) + { + native_flags |= MSG_PEEK; + } + + if (flags & SYS_NET_MSG_WAITALL) + { + native_flags |= MSG_WAITALL; + } + + const auto sock = idm::check(s, [&](lv2_socket& sock) + { + semaphore_lock lock(sock.mutex); + + //if (!test(sock.events, lv2_socket::poll::read)) + { +#ifdef _WIN32 + if (!(native_flags & MSG_PEEK)) sock.ev_set &= ~FD_READ; +#endif + native_result = ::recvfrom(sock.socket, (char*)buf.get_ptr(), len, native_flags, (::sockaddr*)&native_addr, &native_addrlen); + + if (native_result >= 0) + { + return true; + } + + result = get_last_error(!sock.so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0); + + if (result) + { + return false; + } + } + + // Enable read event + sock.events += lv2_socket::poll::read; + sock.queue.emplace_back(ppu.id, [&](bs_t events) -> bool + { + if (test(events, lv2_socket::poll::read)) + { +#ifdef _WIN32 + if (!(native_flags & MSG_PEEK)) sock.ev_set &= ~FD_READ; +#endif + native_result = ::recvfrom(sock.socket, (char*)buf.get_ptr(), len, native_flags, (::sockaddr*)&native_addr, &native_addrlen); + + if (native_result >= 0 || (result = get_last_error(!sock.so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0))) + { + lv2_obj::awake(ppu); + return true; + } + } + + sock.events += lv2_socket::poll::read; + return false; + }); + + lv2_obj::sleep(ppu); + return false; + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + if (!sock.ret && result) + { + return -result; + } + + if (!sock.ret) + { + while (!ppu.state.test_and_reset(cpu_flag::signal)) + { + thread_ctrl::wait(); + } + + if (result) + { + return -result; + } + + if (ppu.gpr[3] == -SYS_NET_EINTR) + { + return -SYS_NET_EINTR; + } + } + + // TODO + if (addr) + { + verify(HERE), native_addr.ss_family == AF_INET; + + vm::ptr paddr = vm::cast(addr.addr()); + + if (paddrlen) + { + *paddrlen = sizeof(sys_net_sockaddr_in); + } + + paddr->sin_len = sizeof(sys_net_sockaddr_in); + paddr->sin_family = SYS_NET_AF_INET; + paddr->sin_port = ntohs(((::sockaddr_in*)&native_addr)->sin_port); + paddr->sin_addr = ntohl(((::sockaddr_in*)&native_addr)->sin_addr.s_addr); + paddr->sin_zero = 0; + } + + // Length + return native_result; +} + +s32 sys_net_bnet_recvmsg(ppu_thread& ppu, s32 s, vm::ptr msg, s32 flags) +{ + sys_net.todo("sys_net_bnet_recvmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags); + return 0; +} + +s32 sys_net_bnet_sendmsg(ppu_thread& ppu, s32 s, vm::cptr msg, s32 flags) +{ + sys_net.todo("sys_net_bnet_sendmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags); + return 0; +} + +s32 sys_net_bnet_sendto(ppu_thread& ppu, s32 s, vm::cptr buf, u32 len, s32 flags, vm::cptr addr, u32 addrlen) +{ + sys_net.warning("sys_net_bnet_sendto(s=%d, buf=*0x%x, len=%u, flags=0x%x, addr=*0x%x, addrlen=%u)", s, buf, len, flags, addr, addrlen); + + if (flags & ~(SYS_NET_MSG_DONTWAIT | SYS_NET_MSG_WAITALL)) + { + fmt::throw_exception("sys_net_bnet_sendto(s=%d): unknown flags (0x%x)", flags); + } + + if (addr && addrlen < 8) + { + sys_net.error("sys_net_bnet_sendto(s=%d): bad addrlen (%u)", s, addrlen); + return -SYS_NET_EINVAL; + } + + if (addr && addr->sa_family != SYS_NET_AF_INET) + { + sys_net.error("sys_net_bnet_sendto(s=%d): unsupported sa_family (%d)", s, addr->sa_family); + return -SYS_NET_EAFNOSUPPORT; + } + + int native_flags = 0; + int native_result = -1; + ::sockaddr_in name{}; + + if (addr) + { + name.sin_family = AF_INET; + name.sin_port = htons(((sys_net_sockaddr_in*)addr.get_ptr())->sin_port); + name.sin_addr.s_addr = htonl(((sys_net_sockaddr_in*)addr.get_ptr())->sin_addr); + } + + ::socklen_t namelen = sizeof(name); + s32 result = 0; + + if (flags & SYS_NET_MSG_WAITALL) + { + native_flags |= MSG_WAITALL; + } + + const auto sock = idm::check(s, [&](lv2_socket& sock) + { + semaphore_lock lock(sock.mutex); + + //if (!test(sock.events, lv2_socket::poll::write)) + { +#ifdef _WIN32 + sock.ev_set &= ~FD_WRITE; +#endif + native_result = ::sendto(sock.socket, (const char*)buf.get_ptr(), len, native_flags, addr ? (::sockaddr*)&name : nullptr, addr ? namelen : 0); + + if (native_result >= 0) + { + return true; + } + + result = get_last_error(!sock.so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0); + + if (result) + { + return false; + } + } + + // Enable write event + sock.events += lv2_socket::poll::write; + sock.queue.emplace_back(ppu.id, [&](bs_t events) -> bool + { + if (test(events, lv2_socket::poll::write)) + { +#ifdef _WIN32 + sock.ev_set &= ~FD_WRITE; +#endif + native_result = ::sendto(sock.socket, (const char*)buf.get_ptr(), len, native_flags, addr ? (::sockaddr*)&name : nullptr, addr ? namelen : 0); + + if (native_result >= 0 || (result = get_last_error(!sock.so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0))) + { + lv2_obj::awake(ppu); + return true; + } + } + + sock.events += lv2_socket::poll::write; + return false; + }); + + lv2_obj::sleep(ppu); + return false; + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + if (!sock.ret && result) + { + return -result; + } + + if (!sock.ret) + { + while (!ppu.state.test_and_reset(cpu_flag::signal)) + { + thread_ctrl::wait(); + } + + if (result) + { + return -result; + } + + if (ppu.gpr[3] == -SYS_NET_EINTR) + { + return -SYS_NET_EINTR; + } + } + + // Length + return native_result; +} + +s32 sys_net_bnet_setsockopt(ppu_thread& ppu, s32 s, s32 level, s32 optname, vm::cptr optval, u32 optlen) +{ + sys_net.warning("sys_net_bnet_setsockopt(s=%d, level=0x%x, optname=0x%x, optval=*0x%x, optlen=%u)", s, level, optname, optval, optlen); + + int native_int = 0; + int native_level = -1; + int native_opt = -1; + const void* native_val = &native_int; + ::socklen_t native_len = sizeof(int); + ::timeval native_timeo; + ::linger native_linger; + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + + if (optlen >= sizeof(int)) + { + native_int = *(const be_t*)optval.get_ptr(); + } + else + { + return SYS_NET_EINVAL; + } + + if (level == SYS_NET_SOL_SOCKET) + { + native_level = SOL_SOCKET; + + switch (optname) + { + case SYS_NET_SO_NBIO: + { + // Special + sock.so_nbio = native_int; + return 0; + } + case SYS_NET_SO_KEEPALIVE: + { + native_opt = SO_KEEPALIVE; + break; + } + case SYS_NET_SO_SNDBUF: + { + native_opt = SO_SNDBUF; + break; + } + case SYS_NET_SO_RCVBUF: + { + native_opt = SO_RCVBUF; + break; + } + case SYS_NET_SO_SNDLOWAT: + { + native_opt = SO_SNDLOWAT; + break; + } + case SYS_NET_SO_RCVLOWAT: + { + native_opt = SO_RCVLOWAT; + break; + } + case SYS_NET_SO_BROADCAST: + { + native_opt = SO_BROADCAST; + break; + } + case SYS_NET_SO_REUSEADDR: + { + native_opt = SO_REUSEADDR; + break; + } + case SYS_NET_SO_SNDTIMEO: + case SYS_NET_SO_RCVTIMEO: + { + if (optlen < sizeof(sys_net_timeval)) + return SYS_NET_EINVAL; + + native_opt = optname == SYS_NET_SO_SNDTIMEO ? SO_SNDTIMEO : SO_RCVTIMEO; + native_val = &native_timeo; + native_len = sizeof(native_timeo); + native_timeo.tv_sec = ::narrow(((const sys_net_timeval*)optval.get_ptr())->tv_sec); + native_timeo.tv_usec = ::narrow(((const sys_net_timeval*)optval.get_ptr())->tv_usec); + break; + } + case SYS_NET_SO_LINGER: + { + if (optlen < sizeof(sys_net_linger)) + return SYS_NET_EINVAL; + + // TODO + native_opt = SO_LINGER; + native_val = &native_linger; + native_len = sizeof(native_linger); + native_linger.l_onoff = ((const sys_net_linger*)optval.get_ptr())->l_onoff; + native_linger.l_linger = ((const sys_net_linger*)optval.get_ptr())->l_linger; + break; + } + default: + { + sys_net.error("sys_net_bnet_setsockopt(s=%d, SOL_SOCKET): unknown option (0x%x)", s, optname); + return SYS_NET_EINVAL; + } + } + } + else if (level == SYS_NET_IPPROTO_TCP) + { + native_level = IPPROTO_TCP; + + switch (optname) + { + case SYS_NET_TCP_MAXSEG: + { + // Special (no effect) + sock.so_tcp_maxseg = native_int; + return 0; + } + case SYS_NET_TCP_NODELAY: + { + native_opt = TCP_NODELAY; + break; + } + default: + { + sys_net.error("sys_net_bnet_setsockopt(s=%d, IPPROTO_TCP): unknown option (0x%x)", s, optname); + return SYS_NET_EINVAL; + } + } + } + else + { + sys_net.error("sys_net_bnet_setsockopt(s=%d): unknown level (0x%x)", s, level); + return SYS_NET_EINVAL; + } + + if (::setsockopt(sock.socket, native_level, native_opt, (const char*)native_val, native_len) == 0) + { + return 0; + } + + return get_last_error(false); + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_shutdown(ppu_thread& ppu, s32 s, s32 how) +{ + sys_net.warning("sys_net_bnet_shutdown(s=%d, how=%d)", s, how); + + if (how < 0 || how > 2) + { + return -SYS_NET_EINVAL; + } + + const auto sock = idm::check(s, [&](lv2_socket& sock) -> s32 + { + semaphore_lock lock(sock.mutex); + +#ifdef _WIN32 + const int native_how = + how == SYS_NET_SHUT_RD ? SD_RECEIVE : + how == SYS_NET_SHUT_WR ? SD_SEND : SD_BOTH; +#else + const int native_how = + how == SYS_NET_SHUT_RD ? SHUT_RD : + how == SYS_NET_SHUT_WR ? SHUT_WR : SHUT_RDWR; +#endif + + if (::shutdown(sock.socket, native_how) == 0) + { + return 0; + } + + return get_last_error(false); + }); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + return -sock.ret; +} + +s32 sys_net_bnet_socket(ppu_thread& ppu, s32 family, s32 type, s32 protocol) +{ + sys_net.warning("sys_net_bnet_socket(family=%d, type=%d, protocol=%d)", family, type, protocol); + + if (family != SYS_NET_AF_INET) + { + sys_net.error("sys_net_bnet_socket(): unknown family (%d)", family); + } + + if (type != SYS_NET_SOCK_STREAM && type != SYS_NET_SOCK_DGRAM) + { + sys_net.error("sys_net_bnet_socket(): unsupported type (%d)", type); + return -SYS_NET_EPROTONOSUPPORT; + } + + const int native_domain = AF_INET; + const int native_type = + type == SYS_NET_SOCK_STREAM ? SOCK_STREAM : + type == SYS_NET_SOCK_DGRAM ? SOCK_DGRAM : SOCK_RAW; + const int native_proto = + type == SYS_NET_SOCK_STREAM ? 0 : + type == SYS_NET_SOCK_DGRAM ? 0 : 0; + + const auto native_socket = ::socket(native_domain, native_type, native_proto); + + if (native_socket == -1) + { + return -get_last_error(false); + } + + const s32 s = idm::import_existing(std::make_shared(native_socket)); + + if (s == -1) + { + return -SYS_NET_EMFILE; + } + + return s; +} + +s32 sys_net_bnet_close(ppu_thread& ppu, s32 s) +{ + sys_net.warning("sys_net_bnet_close(s=%d)", s); + + const auto sock = idm::withdraw(s); + + if (!sock) + { + return -SYS_NET_EBADF; + } + + if (!sock->queue.empty()) + sys_net.fatal("CLOSE"); + + return 0; +} + +s32 sys_net_bnet_poll(ppu_thread& ppu, vm::ptr fds, s32 nfds, s32 ms) +{ + sys_net.warning("sys_net_bnet_poll(fds=*0x%x, nfds=%d, ms=%d)", fds, nfds, ms); + + atomic_t signaled{0}; + + u64 timeout = ms < 0 ? 0 : ms * 1000ull; + + if (nfds) + { + semaphore_lock nw_lock(s_nw_mutex); + + reader_lock lock(id_manager::g_mutex); + +#ifndef _WIN32 + ::pollfd _fds[1024]{}; +#endif + + for (s32 i = 0; i < nfds; i++) + { +#ifndef _WIN32 + _fds[i].fd = -1; +#endif + fds[i].revents = 0; + + if (fds[i].fd < 0) + { + continue; + } + + if (auto sock = idm::check_unlocked(fds[i].fd)) + { + if (fds[i].events & ~(SYS_NET_POLLIN | SYS_NET_POLLOUT)) + sys_net.error("sys_net_bnet_poll(fd=%d): events=0x%x", fds[i].fd, fds[i].events); +#ifdef _WIN32 + if (fds[i].events & SYS_NET_POLLIN && sock->ev_set & (FD_READ | FD_ACCEPT | FD_CLOSE)) + fds[i].revents |= SYS_NET_POLLIN; + if (fds[i].events & SYS_NET_POLLOUT && sock->ev_set & (FD_WRITE | FD_CONNECT)) + fds[i].revents |= SYS_NET_POLLOUT; + + if (fds[i].revents) + { + signaled++; + } +#else + _fds[i].fd = sock->socket; + if (fds[i].events & SYS_NET_POLLIN) + _fds[i].events |= POLLIN; + if (fds[i].events & SYS_NET_POLLOUT) + _fds[i].events |= POLLOUT; +#endif + } + else + { + fds[i].revents |= SYS_NET_POLLNVAL; + signaled++; + } + } + +#ifndef _WIN32 + ::poll(_fds, nfds, 0); + + for (s32 i = 0; i < nfds; i++) + { + if (_fds[i].revents & (POLLIN | POLLHUP)) + fds[i].revents |= SYS_NET_POLLIN; + if (_fds[i].revents & POLLOUT) + fds[i].revents |= SYS_NET_POLLOUT; + if (_fds[i].revents & POLLERR) + fds[i].revents |= SYS_NET_POLLERR; + + if (fds[i].revents) + { + signaled++; + } + } +#endif + + if (ms == 0 || signaled) + { + return signaled; + } + + for (s32 i = 0; i < nfds; i++) + { + if (fds[i].fd < 0) + { + continue; + } + + if (auto sock = idm::check_unlocked(fds[i].fd)) + { + semaphore_lock lock(sock->mutex); + + bs_t selected = +lv2_socket::poll::error; + + if (fds[i].events & SYS_NET_POLLIN) + selected += lv2_socket::poll::read; + if (fds[i].events & SYS_NET_POLLOUT) + selected += lv2_socket::poll::write; + //if (fds[i].events & SYS_NET_POLLPRI) // Unimplemented + // selected += lv2_socket::poll::error; + + sock->events += selected; + sock->queue.emplace_back(ppu.id, [sock, selected, fds, i, &signaled, &ppu](bs_t events) + { + if (test(events, selected)) + { + if (test(events, selected & lv2_socket::poll::read)) + fds[i].revents |= SYS_NET_POLLIN; + if (test(events, selected & lv2_socket::poll::write)) + fds[i].revents |= SYS_NET_POLLOUT; + if (test(events, selected & lv2_socket::poll::error)) + fds[i].revents |= SYS_NET_POLLERR; + + signaled++; + s_to_awake.emplace_back(&ppu); + return true; + } + + sock->events += selected; + return false; + }); + } + } + + lv2_obj::sleep(ppu, timeout); + } + else + { + return 0; + } + + while (!ppu.state.test_and_reset(cpu_flag::signal)) + { + if (timeout) + { + const u64 passed = get_system_time() - ppu.start_time; + + if (passed >= timeout) + { + semaphore_lock nw_lock(s_nw_mutex); + + if (signaled) + { + timeout = 0; + continue; + } + + network_clear_queue(ppu); + break; + } + + thread_ctrl::wait_for(timeout - passed); + } + else + { + thread_ctrl::wait(); + } + } + + return signaled; +} + +s32 sys_net_bnet_select(ppu_thread& ppu, s32 nfds, vm::ptr readfds, vm::ptr writefds, vm::ptr exceptfds, vm::ptr _timeout) +{ + sys_net.warning("sys_net_bnet_select(nfds=%d, readfds=*0x%x, writefds=*0x%x, exceptfds=*0x%x, timeout=*0x%x)", nfds, readfds, writefds, exceptfds, _timeout); + + atomic_t signaled{0}; + + if (exceptfds) + { + sys_net.error("sys_net_bnet_select(): exceptfds not implemented"); + } + + sys_net_fd_set rread{}; + sys_net_fd_set rwrite{}; + sys_net_fd_set rexcept{}; + u64 timeout = !_timeout ? 0 : _timeout->tv_sec * 1000000ull + _timeout->tv_usec; + + if (nfds >= 0) + { + semaphore_lock nw_lock(s_nw_mutex); + + reader_lock lock(id_manager::g_mutex); + +#ifndef _WIN32 + ::pollfd _fds[1024]{}; +#endif + + for (s32 i = 0; i < nfds; i++) + { +#ifndef _WIN32 + _fds[i].fd = -1; +#endif + bs_t selected{}; + + if (readfds && readfds->bit(i)) + selected += lv2_socket::poll::read; + if (writefds && writefds->bit(i)) + selected += lv2_socket::poll::write; + //if (exceptfds && exceptfds->bit(i)) + // selected += lv2_socket::poll::error; + + if (test(selected)) + { + selected += lv2_socket::poll::error; + } + else + { + continue; + } + + if (auto sock = idm::check_unlocked(i)) + { +#ifdef _WIN32 + bool sig = false; + if (sock->ev_set & (FD_READ | FD_ACCEPT | FD_CLOSE) && test(selected, lv2_socket::poll::read)) + sig = true, rread.set(i); + if (sock->ev_set & (FD_WRITE | FD_CONNECT) && test(selected, lv2_socket::poll::write)) + sig = true, rwrite.set(i); + + if (sig) + { + signaled++; + } +#else + _fds[i].fd = sock->socket; + if (test(selected, lv2_socket::poll::read)) + _fds[i].events |= POLLIN; + if (test(selected, lv2_socket::poll::write)) + _fds[i].events |= POLLOUT; +#endif + } + else + { + return -SYS_NET_EBADF; + } + } + +#ifndef _WIN32 + ::poll(_fds, nfds, 0); + + for (s32 i = 0; i < nfds; i++) + { + bool sig = false; + if (_fds[i].revents & (POLLIN | POLLHUP | POLLERR)) + sig = true, rread.set(i); + if (_fds[i].revents & (POLLOUT | POLLERR)) + sig = true, rwrite.set(i); + + if (sig) + { + signaled++; + } + } +#endif + + if ((_timeout && !timeout) || signaled) + { + if (readfds) + *readfds = rread; + if (writefds) + *writefds = rwrite; + if (exceptfds) + *exceptfds = rexcept; + return signaled; + } + + for (s32 i = 0; i < nfds; i++) + { + bs_t selected{}; + + if (readfds && readfds->bit(i)) + selected += lv2_socket::poll::read; + if (writefds && writefds->bit(i)) + selected += lv2_socket::poll::write; + //if (exceptfds && exceptfds->bit(i)) + // selected += lv2_socket::poll::error; + + if (test(selected)) + { + selected += lv2_socket::poll::error; + } + else + { + continue; + } + + if (auto sock = idm::check_unlocked(i)) + { + semaphore_lock lock(sock->mutex); + + sock->events += selected; + sock->queue.emplace_back(ppu.id, [sock, selected, i, &rread, &rwrite, &rexcept, &signaled, &ppu](bs_t events) + { + if (test(events, selected)) + { + if (test(selected, lv2_socket::poll::read) && test(events, lv2_socket::poll::read + lv2_socket::poll::error)) + rread.set(i); + if (test(selected, lv2_socket::poll::write) && test(events, lv2_socket::poll::write + lv2_socket::poll::error)) + rwrite.set(i); + //if (test(events, selected & lv2_socket::poll::error)) + // rexcept.set(i); + + signaled++; + s_to_awake.emplace_back(&ppu); + return true; + } + + sock->events += selected; + return false; + }); + } + else + { + return -SYS_NET_EBADF; + } + } + + lv2_obj::sleep(ppu, timeout); + } + else + { + return -SYS_NET_EINVAL; + } + + while (!ppu.state.test_and_reset(cpu_flag::signal)) + { + if (timeout) + { + const u64 passed = get_system_time() - ppu.start_time; + + if (passed >= timeout) + { + semaphore_lock nw_lock(s_nw_mutex); + + if (signaled) + { + timeout = 0; + continue; + } + + network_clear_queue(ppu); + break; + } + + thread_ctrl::wait_for(timeout - passed); + } + else + { + thread_ctrl::wait(); + } + } + + if (readfds) + *readfds = rread; + if (writefds) + *writefds = rwrite; + if (exceptfds) + *exceptfds = rexcept; + + return signaled; +} + +s32 _sys_net_open_dump(ppu_thread& ppu, s32 len, s32 flags) +{ + sys_net.todo("_sys_net_open_dump(len=%d, flags=0x%x)", len, flags); + return 0; +} + +s32 _sys_net_read_dump(ppu_thread& ppu, s32 id, vm::ptr buf, s32 len, vm::ptr pflags) +{ + sys_net.todo("_sys_net_read_dump(id=0x%x, buf=*0x%x, len=%d, pflags=*0x%x)", id, buf, len, pflags); + return 0; +} + +s32 _sys_net_close_dump(ppu_thread& ppu, s32 id, vm::ptr pflags) +{ + sys_net.todo("_sys_net_close_dump(id=0x%x, pflags=*0x%x)", id, pflags); + return 0; +} + +s32 _sys_net_write_dump(ppu_thread& ppu, s32 id, vm::cptr buf, s32 len, u32 unknown) +{ + sys_net.todo(__func__); + return 0; +} + +s32 sys_net_abort(ppu_thread& ppu, s32 type, u64 arg, s32 flags) +{ + sys_net.todo("sys_net_abort(type=%d, arg=0x%x, flags=0x%x)", type, arg, flags); + return 0; +} + +s32 sys_net_infoctl(ppu_thread& ppu, s32 cmd, vm::ptr arg) +{ + sys_net.todo("sys_net_infoctl(cmd=%d, arg=*0x%x)", cmd, arg); + return 0; +} + +s32 sys_net_control(ppu_thread& ppu, u32 arg1, s32 arg2, vm::ptr arg3, s32 arg4) +{ + sys_net.todo("sys_net_control(0x%x, %d, *0x%x, %d)", arg1, arg2, arg3, arg4); + return 0; +} + +s32 sys_net_bnet_ioctl(ppu_thread& ppu, s32 arg1, u32 arg2, u32 arg3) +{ + sys_net.todo("sys_net_bnet_ioctl(%d, 0x%x, 0x%x)", arg1, arg2, arg3); + return 0; +} + +s32 sys_net_bnet_sysctl(ppu_thread& ppu, u32 arg1, u32 arg2, u32 arg3, vm::ptr arg4, u32 arg5, u32 arg6) +{ + sys_net.todo("sys_net_bnet_sysctl(0x%x, 0x%x, 0x%x, *0x%x, 0x%x, 0x%x)", arg1, arg2, arg3, arg4, arg5, arg6); + return 0; +} + +s32 sys_net_eurus_post_command(ppu_thread& ppu, s32 arg1, u32 arg2, u32 arg3) +{ + sys_net.todo("sys_net_eurus_post_command(%d, 0x%x, 0x%x)", arg1, arg2, arg3); + return 0; +} diff --git a/rpcs3/Emu/Cell/lv2/sys_net.h b/rpcs3/Emu/Cell/lv2/sys_net.h new file mode 100644 index 0000000000..ed5ad3b8f9 --- /dev/null +++ b/rpcs3/Emu/Cell/lv2/sys_net.h @@ -0,0 +1,383 @@ +#pragma once + +#include "Utilities/bit_set.h" +#include "Utilities/sema.h" + +#include +#include +#include + +// 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 (prefixed with SYS_NET_) +enum +{ + SYS_NET_SOCK_STREAM = 1, + SYS_NET_SOCK_DGRAM = 2, + SYS_NET_SOCK_RAW = 3, + SYS_NET_SOCK_DGRAM_P2P = 6, + SYS_NET_SOCK_STREAM_P2P = 10, +}; + +// Socket options (prefixed with SYS_NET_) +enum +{ + SYS_NET_SO_SNDBUF = 0x1001, + SYS_NET_SO_RCVBUF = 0x1002, + SYS_NET_SO_SNDLOWAT = 0x1003, + SYS_NET_SO_RCVLOWAT = 0x1004, + SYS_NET_SO_SNDTIMEO = 0x1005, + SYS_NET_SO_RCVTIMEO = 0x1006, + SYS_NET_SO_ERROR = 0x1007, + SYS_NET_SO_TYPE = 0x1008, + SYS_NET_SO_NBIO = 0x1100, // Non-blocking IO + SYS_NET_SO_TPPOLICY = 0x1101, + + SYS_NET_SO_REUSEADDR = 0x0004, + SYS_NET_SO_KEEPALIVE = 0x0008, + SYS_NET_SO_BROADCAST = 0x0020, + SYS_NET_SO_LINGER = 0x0080, + SYS_NET_SO_OOBINLINE = 0x0100, + SYS_NET_SO_REUSEPORT = 0x0200, + SYS_NET_SO_ONESBCAST = 0x0800, + SYS_NET_SO_USECRYPTO = 0x1000, + SYS_NET_SO_USESIGNATURE = 0x2000, + + SYS_NET_SOL_SOCKET = 0xffff, +}; + +// Family (prefixed with SYS_NET_) +enum +{ + SYS_NET_AF_UNSPEC = 0, + SYS_NET_AF_LOCAL = 1, + SYS_NET_AF_UNIX = SYS_NET_AF_LOCAL, + SYS_NET_AF_INET = 2, + SYS_NET_AF_INET6 = 24, +}; + +// Flags (prefixed with SYS_NET_) +enum +{ + SYS_NET_MSG_OOB = 0x1, + SYS_NET_MSG_PEEK = 0x2, + SYS_NET_MSG_DONTROUTE = 0x4, + SYS_NET_MSG_EOR = 0x8, + SYS_NET_MSG_TRUNC = 0x10, + SYS_NET_MSG_CTRUNC = 0x20, + SYS_NET_MSG_WAITALL = 0x40, + SYS_NET_MSG_DONTWAIT = 0x80, + SYS_NET_MSG_BCAST = 0x100, + SYS_NET_MSG_MCAST = 0x200, + SYS_NET_MSG_USECRYPTO = 0x400, + SYS_NET_MSG_USESIGNATURE= 0x800, +}; + +// Shutdown types (prefixed with SYS_NET_) +enum +{ + SYS_NET_SHUT_RD = 0, + SYS_NET_SHUT_WR = 1, + SYS_NET_SHUT_RDWR = 2, +}; + +// TCP options (prefixed with SYS_NET_) +enum +{ + SYS_NET_TCP_NODELAY = 1, + SYS_NET_TCP_MAXSEG = 2, + SYS_NET_TCP_MSS_TO_ADVERTISE = 3, +}; + +// IP protocols (prefixed with SYS_NET_) +enum +{ + SYS_NET_IPPROTO_IP = 0, + SYS_NET_IPPROTO_ICMP = 1, + SYS_NET_IPPROTO_IGMP = 2, + SYS_NET_IPPROTO_TCP = 6, + SYS_NET_IPPROTO_UDP = 17, + SYS_NET_IPPROTO_ICMPV6 = 58, +}; + +// Poll events (prefixed with SYS_NET_) +enum +{ + SYS_NET_POLLIN = 0x0001, + SYS_NET_POLLPRI = 0x0002, + SYS_NET_POLLOUT = 0x0004, + SYS_NET_POLLERR = 0x0008, /* revent only */ + SYS_NET_POLLHUP = 0x0010, /* revent only */ + SYS_NET_POLLNVAL = 0x0020, /* revent only */ + SYS_NET_POLLRDNORM = 0x0040, + SYS_NET_POLLWRNORM = SYS_NET_POLLOUT, + SYS_NET_POLLRDBAND = 0x0080, + SYS_NET_POLLWRBAND = 0x0100, +}; + +// in_addr_t type prefixed with sys_net_ +using sys_net_in_addr_t = u32; + +// in_port_t type prefixed with sys_net_ +using sys_net_in_port_t = u16; + +// sa_family_t type prefixed with sys_net_ +using sys_net_sa_family_t = u8; + +// socklen_t type prefixed with sys_net_ +using sys_net_socklen_t = u32; + +// fd_set prefixed with sys_net_ +struct sys_net_fd_set +{ + be_t fds_bits[32]; + + u32 bit(s32 s) + { + return (fds_bits[(s >> 5) & 31] >> (s & 31)) & 1u; + } + + void set(s32 s) + { + fds_bits[(s >> 5) & 31] |= (1u << (s & 31)); + } +}; + +// hostent prefixed with sys_net_ +struct sys_net_hostent +{ + vm::ps3::bptr h_name; + vm::ps3::bpptr h_aliases; + be_t h_addrtype; + be_t h_length; + vm::ps3::bpptr h_addr_list; +}; + +// in_addr prefixed with sys_net_ +struct sys_net_in_addr +{ + be_t _s_addr; +}; + +// iovec prefixed with sys_net_ +struct sys_net_iovec +{ + be_t zero1; + vm::ps3::bptr iov_base; + be_t zero2; + be_t iov_len; +}; + +// ip_mreq prefixed with sys_net_ +struct sys_net_ip_mreq +{ + be_t imr_multiaddr; + be_t imr_interface; +}; + +// msghdr prefixed with sys_net_ +struct sys_net_msghdr +{ + be_t zero1; + vm::ps3::bptr msg_name; + be_t msg_namelen; + be_t pad1; + be_t zero2; + vm::ps3::bptr msg_iov; + be_t msg_iovlen; + be_t pad2; + be_t zero3; + vm::ps3::bptr msg_control; + be_t msg_controllen; + be_t msg_flags; +}; + +// pollfd prefixed with sys_net_ +struct sys_net_pollfd +{ + be_t fd; + be_t events; + be_t revents; +}; + +// sockaddr prefixed with sys_net_ +struct sys_net_sockaddr +{ + u8 sa_len; + u8 sa_family; + char sa_data[14]; +}; + +// sockaddr_dl prefixed with sys_net_ +struct sys_net_sockaddr_dl +{ + u8 sdl_len; + u8 sdl_family; + be_t sdl_index; + u8 sdl_type; + u8 sdl_nlen; + u8 sdl_alen; + u8 sdl_slen; + char sdl_data[12]; +}; + +// sockaddr_in prefixed with sys_net_ +struct sys_net_sockaddr_in +{ + u8 sin_len; + u8 sin_family; + be_t sin_port; + be_t sin_addr; + be_t sin_zero; +}; + +// sockaddr_in_p2p prefixed with sys_net_ +struct sys_net_sockaddr_in_p2p +{ + u8 sin_len; + u8 sin_family; + be_t sin_port; + be_t sin_addr; + be_t sin_vport; + char sin_zero[6]; +}; + +// timeval prefixed with sys_net_ +struct sys_net_timeval +{ + be_t tv_sec; + be_t tv_usec; +}; + +// linger prefixed with sys_net_ +struct sys_net_linger +{ + be_t l_onoff; + be_t l_linger; +}; + +// 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 lv2_socket final +{ +#ifdef _WIN32 + using socket_type = std::uintptr_t; +#else + using socket_type = int; +#endif + + static const u32 id_base = 0; + static const u32 id_step = 1; + static const u32 id_count = 1024; + + // Poll events + enum class poll + { + read, + write, + error, + + __bitset_enum_max + }; + + lv2_socket(socket_type s); + ~lv2_socket(); + + semaphore<> mutex; + +#ifdef _WIN32 + // Remember events (WSAEnumNetworkEvents) + u32 ev_set = 0; +#endif + + // Native socket (must be non-blocking) + socket_type socket; + + // Events selected for polling + atomic_t> events{}; + + // Non-blocking IO option + s32 so_nbio = 0; + + // Connection result + s32 so_error = 0; + + // Unsupported option + s32 so_tcp_maxseg = 1500; + + // Event processing workload (pair of thread id and the processing function) + std::vector)>>> queue; +}; + +class ppu_thread; + +// Syscalls + +s32 sys_net_bnet_accept(ppu_thread&, s32 s, vm::ps3::ptr addr, vm::ps3::ptr paddrlen); +s32 sys_net_bnet_bind(ppu_thread&, s32 s, vm::ps3::cptr addr, u32 addrlen); +s32 sys_net_bnet_connect(ppu_thread&, s32 s, vm::ps3::ptr addr, u32 addrlen); +s32 sys_net_bnet_getpeername(ppu_thread&, s32 s, vm::ps3::ptr addr, vm::ps3::ptr paddrlen); +s32 sys_net_bnet_getsockname(ppu_thread&, s32 s, vm::ps3::ptr addr, vm::ps3::ptr paddrlen); +s32 sys_net_bnet_getsockopt(ppu_thread&, s32 s, s32 level, s32 optname, vm::ps3::ptr optval, vm::ps3::ptr optlen); +s32 sys_net_bnet_listen(ppu_thread&, s32 s, s32 backlog); +s32 sys_net_bnet_recvfrom(ppu_thread&, s32 s, vm::ps3::ptr buf, u32 len, s32 flags, vm::ps3::ptr addr, vm::ps3::ptr paddrlen); +s32 sys_net_bnet_recvmsg(ppu_thread&, s32 s, vm::ps3::ptr msg, s32 flags); +s32 sys_net_bnet_sendmsg(ppu_thread&, s32 s, vm::ps3::cptr msg, s32 flags); +s32 sys_net_bnet_sendto(ppu_thread&, s32 s, vm::ps3::cptr buf, u32 len, s32 flags, vm::ps3::cptr addr, u32 addrlen); +s32 sys_net_bnet_setsockopt(ppu_thread&, s32 s, s32 level, s32 optname, vm::ps3::cptr optval, u32 optlen); +s32 sys_net_bnet_shutdown(ppu_thread&, s32 s, s32 how); +s32 sys_net_bnet_socket(ppu_thread&, s32 family, s32 type, s32 protocol); +s32 sys_net_bnet_close(ppu_thread&, s32 s); +s32 sys_net_bnet_poll(ppu_thread&, vm::ps3::ptr fds, s32 nfds, s32 ms); +s32 sys_net_bnet_select(ppu_thread&, s32 nfds, vm::ps3::ptr readfds, vm::ps3::ptr writefds, vm::ps3::ptr exceptfds, vm::ps3::ptr timeout); +s32 _sys_net_open_dump(ppu_thread&, s32 len, s32 flags); +s32 _sys_net_read_dump(ppu_thread&, s32 id, vm::ps3::ptr buf, s32 len, vm::ps3::ptr pflags); +s32 _sys_net_close_dump(ppu_thread&, s32 id, vm::ps3::ptr pflags); +s32 _sys_net_write_dump(ppu_thread&, s32 id, vm::ps3::cptr buf, s32 len, u32 unknown); +s32 sys_net_abort(ppu_thread&, s32 type, u64 arg, s32 flags); +s32 sys_net_infoctl(ppu_thread&, s32 cmd, vm::ps3::ptr arg); +s32 sys_net_control(ppu_thread&, u32 arg1, s32 arg2, vm::ps3::ptr arg3, s32 arg4); +s32 sys_net_bnet_ioctl(ppu_thread&, s32 arg1, u32 arg2, u32 arg3); +s32 sys_net_bnet_sysctl(ppu_thread&, u32 arg1, u32 arg2, u32 arg3, vm::ps3::ptr arg4, u32 arg5, u32 arg6); +s32 sys_net_eurus_post_command(ppu_thread&, s32 arg1, u32 arg2, u32 arg3); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 88edbd2757..83bd7737e2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -23,14 +23,10 @@ static const std::unordered_map s_prx_ignore { "/dev_flash/sys/external/libbeisobmf.sprx", 0 }, { "/dev_flash/sys/external/libcamera.sprx", 0 }, { "/dev_flash/sys/external/libgem.sprx", 0 }, - { "/dev_flash/sys/external/libhttp.sprx", 0 }, { "/dev_flash/sys/external/libio.sprx", 0 }, { "/dev_flash/sys/external/libmedi.sprx", 0 }, { "/dev_flash/sys/external/libmic.sprx", 0 }, - { "/dev_flash/sys/external/libnet.sprx", 0 }, { "/dev_flash/sys/external/libnetctl.sprx", 0 }, - { "/dev_flash/sys/external/librudp.sprx", 0 }, - { "/dev_flash/sys/external/libssl.sprx", 0 }, { "/dev_flash/sys/external/libsysutil.sprx", 0 }, { "/dev_flash/sys/external/libsysutil_ap.sprx", 0 }, { "/dev_flash/sys/external/libsysutil_authdialog.sprx", 0 }, diff --git a/rpcs3/Emu/Cell/lv2/sys_ss.cpp b/rpcs3/Emu/Cell/lv2/sys_ss.cpp index 0077bb3413..60bb9e53b1 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ss.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ss.cpp @@ -3,10 +3,66 @@ #include "sys_ss.h" +#ifdef _WIN32 +#include +#include + +const HCRYPTPROV s_crypto_provider = []() -> HCRYPTPROV +{ + HCRYPTPROV result; + + if (!CryptAcquireContextW(&result, nullptr, nullptr, PROV_RSA_FULL, 0)) + { + return 0; + } + + ::atexit([]() + { + if (s_crypto_provider) + { + CryptReleaseContext(s_crypto_provider, 0); + } + }); + + return result; +}(); +#endif + namespace vm { using namespace ps3; } logs::channel sys_ss("sys_ss"); +error_code sys_ss_random_number_generator(u32 arg1, vm::ptr buf, u64 size) +{ + sys_ss.warning("sys_ss_random_number_generator(arg1=%u, buf=*0x%x, size=0x%x)", arg1, buf, size); + + if (arg1 != 2) + { + return 0x80010509; + } + + if (size > 0x10000000) + { + return 0x80010501; + } + +#ifdef _WIN32 + if (!s_crypto_provider || !CryptGenRandom(s_crypto_provider, size, (BYTE*)buf.get_ptr())) + { + return CELL_EABORT; + } +#else + fs::file rnd{"/dev/random/"}; + + if (!rnd || rnd.read(buf.get_ptr(), size) != size) + { + return CELL_EABORT; + } +#endif + + return CELL_OK; +} + s32 sys_ss_get_console_id(vm::ps3::ptr buf) { sys_ss.todo("sys_ss_get_console_id(buf=*0x%x)", buf); diff --git a/rpcs3/Emu/Cell/lv2/sys_ss.h b/rpcs3/Emu/Cell/lv2/sys_ss.h index 655532adf4..4aefcb51ed 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ss.h +++ b/rpcs3/Emu/Cell/lv2/sys_ss.h @@ -9,5 +9,6 @@ struct CellSsOpenPSID be_t low; }; +error_code sys_ss_random_number_generator(u32 arg1, vm::ps3::ptr buf, u64 size); s32 sys_ss_get_console_id(vm::ps3::ptr buf); s32 sys_ss_get_open_psid(vm::ps3::ptr ptr); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 72ede67be2..98b3693edc 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -43,6 +43,8 @@ extern void spu_load_exec(const spu_exec_object&); extern void arm_load_exec(const arm_exec_object&); extern std::shared_ptr ppu_load_prx(const ppu_prx_object&, const std::string&); +extern void network_thread_init(); + fs::file g_tty; template <> @@ -548,6 +550,7 @@ void Emulator::Load(bool add_only) ppu_load_exec(ppu_exec); fxm::import(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall + network_thread_init(); } else if (ppu_prx.open(elf_file) == elf_error::ok) { diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index cb274188b5..ee2c2d2aff 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -115,6 +115,7 @@ + NotUsing @@ -262,7 +263,7 @@ - + @@ -454,6 +455,7 @@ + @@ -626,7 +628,7 @@ - + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index b94d771642..6c560119d1 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -626,9 +626,6 @@ Emu\Cell\Modules - - Emu\Cell\Modules - Emu\Cell\Modules @@ -932,6 +929,12 @@ Source Files + + Emu\Cell\Modules + + + Emu\Cell\lv2 + @@ -1447,9 +1450,6 @@ Emu\Cell\Modules - - Emu\Cell\Modules - Emu\Cell\Modules @@ -1801,5 +1801,11 @@ Emu\GPU\RSX\Common + + Emu\Cell\Modules + + + Emu\Cell\lv2 + \ No newline at end of file diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index cd51970606..31b6b64d29 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -29,14 +29,11 @@ int main(int argc, char** argv) //QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); SetProcessDPIAware(); - WSADATA wsa_data; - WSAStartup(MAKEWORD(2, 2), &wsa_data); timeBeginPeriod(1); atexit([] { timeEndPeriod(1); - WSACleanup(); }); #else qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");