Fix for Windows ENOTCONN on connecting socket

Fixes Windows returns ENOTCONN when using recvfrom/sendto on connecting socket instead of the expected EAGAIN.
This commit is contained in:
RipleyTom 2023-02-24 23:02:18 +01:00 committed by Megamouse
parent c570fd03d1
commit d9e0d016c6
3 changed files with 26 additions and 12 deletions

View File

@ -239,7 +239,7 @@ std::optional<s32> lv2_socket_native::connect(const sys_net_sockaddr& addr)
else else
{ {
// TODO: check error formats (both native and translated) // TODO: check error formats (both native and translated)
so_error = native_error ? get_last_error(false, native_error) : 0; so_error = native_error ? convert_error(false, native_error) : 0;
} }
return true; return true;
@ -270,7 +270,7 @@ s32 lv2_socket_native::connect_followup()
} }
// TODO: check error formats (both native and translated) // TODO: check error formats (both native and translated)
return native_error ? -get_last_error(false, native_error) : 0; return native_error ? -convert_error(false, native_error) : 0;
} }
std::pair<s32, sys_net_sockaddr> lv2_socket_native::getpeername() std::pair<s32, sys_net_sockaddr> lv2_socket_native::getpeername()
@ -906,9 +906,10 @@ std::optional<std::tuple<s32, std::vector<u8>, sys_net_sockaddr>> lv2_socket_nat
return {{0, {}, sn_addr}}; return {{0, {}, sn_addr}};
} }
} }
#endif const auto result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0, connecting);
#else
const auto result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0); const auto result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0);
#endif
if (result) if (result)
{ {
@ -974,7 +975,11 @@ std::optional<s32> lv2_socket_native::sendto(s32 flags, const std::vector<u8>& b
return {native_result}; return {native_result};
} }
result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0); #ifdef _WIN32
get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0, connecting);
#else
get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0);
#endif
if (result) if (result)
{ {

View File

@ -20,17 +20,12 @@ int get_native_error()
return native_error; return native_error;
} }
sys_net_error get_last_error(bool is_blocking, int native_error) sys_net_error convert_error(bool is_blocking, int native_error, [[maybe_unused]] bool is_connecting)
{ {
// Convert the error code for socket functions to a one for sys_net // Convert the error code for socket functions to a one for sys_net
sys_net_error result{}; sys_net_error result{};
const char* name{}; const char* name{};
if (!native_error)
{
native_error = get_native_error();
}
#ifdef _WIN32 #ifdef _WIN32
#define ERROR_CASE(error) \ #define ERROR_CASE(error) \
case WSA##error: \ case WSA##error: \
@ -92,6 +87,14 @@ sys_net_error get_last_error(bool is_blocking, int native_error)
fmt::throw_exception("sys_net get_last_error(is_blocking=%d, native_error=%d): Unknown/illegal socket error", is_blocking, native_error); fmt::throw_exception("sys_net get_last_error(is_blocking=%d, native_error=%d): Unknown/illegal socket error", is_blocking, native_error);
} }
#ifdef _WIN32
// Windows will return SYS_NET_ENOTCONN when recvfrom/sendto is called on a socket that is connecting but not yet connected
if (is_connecting && result == SYS_NET_ENOTCONN)
{
return SYS_NET_EAGAIN;
}
#endif
if (name && result != SYS_NET_EWOULDBLOCK && result != SYS_NET_EINPROGRESS) if (name && result != SYS_NET_EWOULDBLOCK && result != SYS_NET_EINPROGRESS)
{ {
sys_net.error("Socket error %s", name); sys_net.error("Socket error %s", name);
@ -111,6 +114,11 @@ sys_net_error get_last_error(bool is_blocking, int native_error)
#undef ERROR_CASE #undef ERROR_CASE
} }
sys_net_error get_last_error(bool is_blocking, bool is_connecting)
{
return convert_error(is_blocking, get_native_error(), is_connecting);
}
sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_addr) sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_addr)
{ {
ensure(native_addr.ss_family == AF_INET || native_addr.ss_family == AF_UNSPEC); ensure(native_addr.ss_family == AF_INET || native_addr.ss_family == AF_UNSPEC);

View File

@ -18,7 +18,8 @@
#include "Emu/Cell/lv2/sys_net.h" #include "Emu/Cell/lv2/sys_net.h"
int get_native_error(); int get_native_error();
sys_net_error get_last_error(bool is_blocking, int native_error = 0); sys_net_error convert_error(bool is_blocking, int native_error, bool is_connecting = false);
sys_net_error get_last_error(bool is_blocking, bool is_connecting = false);
sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_addr); sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_addr);
::sockaddr_in sys_net_addr_to_native_addr(const sys_net_sockaddr& sn_addr); ::sockaddr_in sys_net_addr_to_native_addr(const sys_net_sockaddr& sn_addr);
bool is_ip_public_address(const ::sockaddr_in& addr); bool is_ip_public_address(const ::sockaddr_in& addr);