sys_net/lv2_socket_native: Various fixes

Fix is_socket_connected(always returned false)
Implement SYS_NET_IP_TTLCHK and SYS_NET_IP_MAXTTL
Fix lv2_socket_native::sendmsg, it was only sending the first iovec
Fix sys_net_bnet_sendto addrlen check
Fix assert in lv2_socket_native::recvfrom()
This commit is contained in:
RipleyTom
2026-02-19 23:44:10 +01:00
committed by Elad
parent 53dcf2ba00
commit b7b0e06a54
4 changed files with 33 additions and 25 deletions
+1 -1
View File
@@ -992,7 +992,7 @@ error_code sys_net_bnet_sendto(ppu_thread& ppu, s32 s, vm::cptr<void> buf, u32 l
fmt::throw_exception("sys_net_bnet_sendto(s=%d): unknown flags (0x%x)", flags); fmt::throw_exception("sys_net_bnet_sendto(s=%d): unknown flags (0x%x)", flags);
} }
if (addr && addrlen < 8) if (addr && addrlen < sizeof(sys_net_sockaddr))
{ {
sys_net.error("sys_net_bnet_sendto(s=%d): bad addrlen (%u)", s, addrlen); sys_net.error("sys_net_bnet_sendto(s=%d): bad addrlen (%u)", s, addrlen);
return -SYS_NET_EINVAL; return -SYS_NET_EINVAL;
+1 -1
View File
@@ -107,7 +107,7 @@ enum lv2_ip_option : s32
SYS_NET_IP_MULTICAST_LOOP = 11, SYS_NET_IP_MULTICAST_LOOP = 11,
SYS_NET_IP_ADD_MEMBERSHIP = 12, SYS_NET_IP_ADD_MEMBERSHIP = 12,
SYS_NET_IP_DROP_MEMBERSHIP = 13, SYS_NET_IP_DROP_MEMBERSHIP = 13,
SYS_NET_IP_TTLCHK = 23, SYS_NET_IP_TTLCHK = 23, // This is probably the equivalent of IP_MINTTL on FreeBSD
SYS_NET_IP_MAXTTL = 24, SYS_NET_IP_MAXTTL = 24,
SYS_NET_IP_DONTFRAG = 26 SYS_NET_IP_DONTFRAG = 26
}; };
@@ -551,12 +551,14 @@ std::tuple<s32, lv2_socket::sockopt_data, u32> lv2_socket_native::getsockopt(s32
} }
case SYS_NET_IP_TTLCHK: case SYS_NET_IP_TTLCHK:
{ {
sys_net.error("sys_net_bnet_getsockopt(IPPROTO_IP, SYS_NET_IP_TTLCHK): stubbed option"); out_val._int = min_ttl;
out_len = sizeof(s32);
return {CELL_OK, out_val, out_len}; return {CELL_OK, out_val, out_len};
} }
case SYS_NET_IP_MAXTTL: case SYS_NET_IP_MAXTTL:
{ {
sys_net.error("sys_net_bnet_getsockopt(IPPROTO_IP, SYS_NET_IP_MAXTTL): stubbed option"); out_val._int = max_ttl;
out_len = sizeof(s32);
return {CELL_OK, out_val, out_len}; return {CELL_OK, out_val, out_len};
} }
case SYS_NET_IP_DONTFRAG: case SYS_NET_IP_DONTFRAG:
@@ -834,13 +836,13 @@ s32 lv2_socket_native::setsockopt(s32 level, s32 optname, const std::vector<u8>&
} }
case SYS_NET_IP_TTLCHK: case SYS_NET_IP_TTLCHK:
{ {
sys_net.error("sys_net_bnet_setsockopt(s=%d, IPPROTO_IP): Stubbed option (0x%x) (SYS_NET_IP_TTLCHK)", lv2_id, optname); min_ttl = native_int;
break; return {};
} }
case SYS_NET_IP_MAXTTL: case SYS_NET_IP_MAXTTL:
{ {
sys_net.error("sys_net_bnet_setsockopt(s=%d, IPPROTO_IP): Stubbed option (0x%x) (SYS_NET_IP_MAXTTL)", lv2_id, optname); max_ttl = native_int;
break; return {};
} }
case SYS_NET_IP_DONTFRAG: case SYS_NET_IP_DONTFRAG:
{ {
@@ -910,7 +912,7 @@ std::optional<std::tuple<s32, std::vector<u8>, sys_net_sockaddr>> lv2_socket_nat
{ {
auto& nph = g_fxo->get<named_thread<np::np_handler>>(); auto& nph = g_fxo->get<named_thread<np::np_handler>>();
const auto packet = dnshook.get_dns_packet(lv2_id); const auto packet = dnshook.get_dns_packet(lv2_id);
ensure(packet.size() < len); ensure(packet.size() <= len);
memcpy(res_buf.data(), packet.data(), packet.size()); memcpy(res_buf.data(), packet.data(), packet.size());
native_addr.ss_family = AF_INET; native_addr.ss_family = AF_INET;
(reinterpret_cast<::sockaddr_in*>(&native_addr))->sin_port = std::bit_cast<u16, be_t<u16>>(53); // htons(53) (reinterpret_cast<::sockaddr_in*>(&native_addr))->sin_port = std::bit_cast<u16, be_t<u16>>(53); // htons(53)
@@ -1069,11 +1071,14 @@ std::optional<s32> lv2_socket_native::sendmsg(s32 flags, const sys_net_msghdr& m
return {-SYS_NET_ECONNRESET}; return {-SYS_NET_ECONNRESET};
} }
std::vector<u8> buf_copy;
for (int i = 0; i < msg.msg_iovlen; i++) for (int i = 0; i < msg.msg_iovlen; i++)
{ {
auto iov_base = msg.msg_iov[i].iov_base; auto iov_base = msg.msg_iov[i].iov_base;
const u32 len = msg.msg_iov[i].iov_len; const u32 len = msg.msg_iov[i].iov_len;
const std::vector<u8> buf_copy(vm::_ptr<const char>(iov_base.addr()), vm::_ptr<const char>(iov_base.addr()) + len); const auto* src = vm::_ptr<const char>(iov_base.addr());
buf_copy.insert(buf_copy.end(), src, src + len);
}
native_result = ::send(native_socket, reinterpret_cast<const char*>(buf_copy.data()), ::narrow<int>(buf_copy.size()), native_flags); native_result = ::send(native_socket, reinterpret_cast<const char*>(buf_copy.data()), ::narrow<int>(buf_copy.size()), native_flags);
@@ -1081,7 +1086,6 @@ std::optional<s32> lv2_socket_native::sendmsg(s32 flags, const sys_net_msghdr& m
{ {
return {native_result}; return {native_result};
} }
}
result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0); result = get_last_error(!so_nbio && (flags & SYS_NET_MSG_DONTWAIT) == 0);
@@ -1232,16 +1236,16 @@ bool lv2_socket_native::is_socket_connected()
return false; return false;
} }
fd_set readfds, writefds; pollfd pfd{};
struct timeval timeout{0, 0}; // Zero timeout pfd.fd = native_socket;
pfd.events = POLLIN | POLLOUT;
FD_ZERO(&readfds); // Use poll to check for readability and writability
FD_ZERO(&writefds); #ifdef _WIN32
FD_SET(native_socket, &readfds); const int result = WSAPoll(&pfd, 1, 0);
FD_SET(native_socket, &writefds); #else
const int result = ::poll(&pfd, 1, 0);
// Use select to check for readability and writability #endif
const int result = ::select(1, &readfds, &writefds, NULL, &timeout);
if (result < 0) if (result < 0)
{ {
@@ -1250,5 +1254,5 @@ bool lv2_socket_native::is_socket_connected()
} }
// Socket is connected if it's readable or writable // Socket is connected if it's readable or writable
return FD_ISSET(native_socket, &readfds) || FD_ISSET(native_socket, &writefds); return (pfd.revents & (POLLIN | POLLOUT)) != 0;
} }
@@ -70,6 +70,10 @@ private:
s32 so_reuseaddr = 0; s32 so_reuseaddr = 0;
s32 so_reuseport = 0; s32 so_reuseport = 0;
#endif #endif
// Those values come from FreeBSD
s32 min_ttl = 1;
s32 max_ttl = 64;
u16 bound_port = 0; u16 bound_port = 0;
bool feign_tcp_conn_failure = false; // Savestate load related bool feign_tcp_conn_failure = false; // Savestate load related
}; };