1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 12:12:50 +01:00

Savestates/Network: Feign connection failure on startup

This commit is contained in:
Eladash 2024-04-04 09:00:27 +03:00 committed by Elad Ashkenazi
parent 72ad1abd39
commit 8effbf7e4d
3 changed files with 101 additions and 1 deletions

View File

@ -22,6 +22,8 @@ lv2_socket_native::lv2_socket_native(lv2_socket_family family, lv2_socket_type t
lv2_socket_native::lv2_socket_native(utils::serial& ar, lv2_socket_type type)
: lv2_socket(stx::make_exact(ar), type)
{
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(lv2_net);
#ifdef _WIN32
ar(so_reuseaddr, so_reuseport);
#else
@ -33,16 +35,26 @@ lv2_socket_native::lv2_socket_native(utils::serial& ar, lv2_socket_type type)
sys_net.error("[Native] Savestate tried to load Win32 specific data, compatibility may be affected");
}
#endif
if (version >= 2)
{
// Flag to signal failure of TCP connection on socket start
ar(feign_tcp_conn_failure);
}
}
void lv2_socket_native::save(utils::serial& ar)
{
USING_SERIALIZATION_VERSION(lv2_net);
lv2_socket::save(ar, true);
#ifdef _WIN32
ar(so_reuseaddr, so_reuseport);
#else
ar(std::array<char, 8>{});
#endif
ar(is_socket_connected());
}
lv2_socket_native::~lv2_socket_native()
@ -106,6 +118,11 @@ std::tuple<bool, s32, std::shared_ptr<lv2_socket>, sys_net_sockaddr> lv2_socket_
::sockaddr_storage native_addr;
::socklen_t native_addrlen = sizeof(native_addr);
if (feign_tcp_conn_failure)
{
sys_net.error("Calling socket::accpet() from a previously connected socket!");
}
socket_type native_socket = ::accept(socket, reinterpret_cast<struct sockaddr*>(&native_addr), &native_addrlen);
if (native_socket != invalid_socket)
@ -143,6 +160,11 @@ s32 lv2_socket_native::bind(const sys_net_sockaddr& addr)
saddr = std::bit_cast<u32>(psa_in->sin_addr);
}
if (feign_tcp_conn_failure)
{
sys_net.error("Calling socket::bind() from a previously connected socket!");
}
::sockaddr_in native_addr{};
native_addr.sin_family = AF_INET;
native_addr.sin_port = std::bit_cast<u16>(psa_in->sin_port);
@ -225,6 +247,12 @@ std::optional<s32> lv2_socket_native::connect(const sys_net_sockaddr& addr)
bool was_connecting = connecting;
#endif
if (feign_tcp_conn_failure)
{
// As if still connected
return -SYS_NET_EALREADY;
}
if (::connect(socket, reinterpret_cast<struct sockaddr*>(&native_addr), native_addr_len) == 0)
{
return CELL_OK;
@ -873,6 +901,13 @@ std::optional<std::tuple<s32, std::vector<u8>, sys_net_sockaddr>> lv2_socket_nat
lock.lock();
}
if (feign_tcp_conn_failure)
{
// As if just lost the connection
feign_tcp_conn_failure = false;
return {{-SYS_NET_ECONNRESET, {},{}}};
}
int native_flags = 0;
::sockaddr_storage native_addr{};
::socklen_t native_addrlen = sizeof(native_addr);
@ -963,6 +998,12 @@ std::optional<s32> lv2_socket_native::sendto(s32 flags, const std::vector<u8>& b
return -SYS_NET_EADDRNOTAVAIL;
}
}
else if (feign_tcp_conn_failure)
{
// As if just lost the connection
feign_tcp_conn_failure = false;
return -SYS_NET_ECONNRESET;
}
sys_net_error result{};
@ -1029,6 +1070,12 @@ std::optional<s32> lv2_socket_native::sendmsg(s32 flags, const sys_net_msghdr& m
native_flags |= MSG_WAITALL;
}
if (feign_tcp_conn_failure)
{
// As if just lost the connection
feign_tcp_conn_failure = false;
return {-SYS_NET_ECONNRESET};
}
for (int i = 0; i < msg.msg_iovlen; i++)
{
@ -1082,6 +1129,12 @@ s32 lv2_socket_native::shutdown(s32 how)
{
std::lock_guard lock(mutex);
if (feign_tcp_conn_failure)
{
// As if still connected
return CELL_OK;
}
#ifdef _WIN32
const int native_how =
how == SYS_NET_SHUT_RD ? SD_RECEIVE :
@ -1172,3 +1225,47 @@ void lv2_socket_native::set_non_blocking()
::fcntl(socket, F_SETFL, ::fcntl(socket, F_GETFL, 0) | O_NONBLOCK);
#endif
}
bool lv2_socket_native::is_socket_connected()
{
if (type != SYS_NET_SOCK_STREAM)
{
return false;
}
std::lock_guard lock(mutex);
int listening = 0;
socklen_t len = sizeof(listening);
if (::getsockopt(socket, SOL_SOCKET, SO_ACCEPTCONN, reinterpret_cast<char*>(&listening), &len) == -1)
{
return false;
}
if (listening)
{
// Would be handled in other ways
return false;
}
fd_set readfds, writefds;
struct timeval timeout{0, 0}; // Zero timeout
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(socket, &readfds);
FD_SET(socket, &writefds);
// Use select to check for readability and writability
const int result = ::select(1, &readfds, &writefds, NULL, &timeout);
if (result < 0)
{
// Error occurred
return false;
}
// Socket is connected if it's readable or writable
return FD_ISSET(socket, &readfds) || FD_ISSET(socket, &writefds);
}

View File

@ -53,6 +53,8 @@ public:
s32 poll(sys_net_pollfd& sn_pfd, pollfd& native_pfd) override;
std::tuple<bool, bool, bool> select(bs_t<poll_t> selected, pollfd& native_pfd) override;
bool is_socket_connected();
s32 listen(s32 backlog) override;
void close() override;
s32 shutdown(s32 how) override;
@ -69,4 +71,5 @@ private:
s32 so_reuseport = 0;
#endif
u16 bound_port = 0;
bool feign_tcp_conn_failure = false; // Savestate load related
};

View File

@ -46,7 +46,7 @@ SERIALIZATION_VER(ppu, 1, 1, 2/*PPU sleep
SERIALIZATION_VER(spu, 2, 1)
SERIALIZATION_VER(lv2_sync, 3, 1)
SERIALIZATION_VER(lv2_vm, 4, 1)
SERIALIZATION_VER(lv2_net, 5, 1)
SERIALIZATION_VER(lv2_net, 5, 1, 2/*TCP Feign conection loss*/)
SERIALIZATION_VER(lv2_fs, 6, 1, 2/*NPDRM key saving*/)
SERIALIZATION_VER(lv2_prx_overlay, 7, 1)
SERIALIZATION_VER(lv2_memory, 8, 1)