mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-27 21:08:00 +03:00
Fix IPv6 support detection
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ubuntu-24.04 gcc (push) Waiting to run
Build RPCS3 / RPCS3 Linux ubuntu-24.04-arm clang (push) Waiting to run
Build RPCS3 / RPCS3 Linux ubuntu-24.04 clang (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ubuntu-24.04 gcc (push) Waiting to run
Build RPCS3 / RPCS3 Linux ubuntu-24.04-arm clang (push) Waiting to run
Build RPCS3 / RPCS3 Linux ubuntu-24.04 clang (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
This commit is contained in:
parent
ab269f6155
commit
89dea9bd92
8 changed files with 126 additions and 80 deletions
|
@ -18,7 +18,7 @@ bool send_packet_from_p2p_port_ipv4(const std::vector<u8>& data, const sockaddr_
|
|||
{
|
||||
auto& def_port = ::at32(nc.list_p2p_ports, SCE_NP_PORT);
|
||||
|
||||
if (def_port.is_ipv6)
|
||||
if (np::is_ipv6_supported())
|
||||
{
|
||||
const auto addr6 = np::sockaddr_to_sockaddr6(addr);
|
||||
|
||||
|
@ -52,7 +52,7 @@ bool send_packet_from_p2p_port_ipv6(const std::vector<u8>& data, const sockaddr_
|
|||
if (nc.list_p2p_ports.contains(SCE_NP_PORT))
|
||||
{
|
||||
auto& def_port = ::at32(nc.list_p2p_ports, SCE_NP_PORT);
|
||||
ensure(def_port.is_ipv6);
|
||||
ensure(np::is_ipv6_supported());
|
||||
|
||||
if (::sendto(def_port.p2p_socket, reinterpret_cast<const char*>(data.data()), ::size32(data), 0, reinterpret_cast<const sockaddr*>(&addr), sizeof(sockaddr_in6)) == -1)
|
||||
{
|
||||
|
|
|
@ -40,10 +40,10 @@ namespace sys_net_helpers
|
|||
nt_p2p_port::nt_p2p_port(u16 port)
|
||||
: port(port)
|
||||
{
|
||||
is_ipv6 = np::is_ipv6_supported();
|
||||
const bool is_ipv6 = np::is_ipv6_supported();
|
||||
|
||||
// Creates and bind P2P Socket
|
||||
p2p_socket = is_ipv6 ? ::socket(AF_INET6, SOCK_DGRAM, 0) : ::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
p2p_socket = ::socket(is_ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
|
||||
#ifdef _WIN32
|
||||
if (p2p_socket == INVALID_SOCKET)
|
||||
#else
|
||||
|
@ -145,13 +145,13 @@ bool nt_p2p_port::recv_data()
|
|||
{
|
||||
::sockaddr_storage native_addr{};
|
||||
::socklen_t native_addrlen = sizeof(native_addr);
|
||||
const auto recv_res = ::recvfrom(p2p_socket, reinterpret_cast<char*>(p2p_recv_data.data()), ::size32(p2p_recv_data), 0, reinterpret_cast<struct sockaddr*>(&native_addr), &native_addrlen);
|
||||
const auto recv_res = ::recvfrom(p2p_socket, reinterpret_cast<char*>(p2p_recv_data.data()), ::size32(p2p_recv_data), 0, reinterpret_cast<struct sockaddr*>(&native_addr), &native_addrlen);
|
||||
|
||||
if (recv_res == -1)
|
||||
{
|
||||
auto lerr = get_last_error(false);
|
||||
if (lerr != SYS_NET_EINPROGRESS && lerr != SYS_NET_EWOULDBLOCK)
|
||||
sys_net.error("Error recvfrom on %s P2P socket: %d", is_ipv6 ? "IPv6" : "IPv4", lerr);
|
||||
sys_net.error("Error recvfrom on %s P2P socket: %d", np::is_ipv6_supported() ? "IPv6" : "IPv4", lerr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ bool nt_p2p_port::recv_data()
|
|||
|
||||
u16 dst_vport = reinterpret_cast<le_t<u16>&>(p2p_recv_data[0]);
|
||||
|
||||
if (is_ipv6)
|
||||
if (np::is_ipv6_supported())
|
||||
{
|
||||
const auto* addr_ipv6 = reinterpret_cast<sockaddr_in6*>(&native_addr);
|
||||
const auto addr_ipv4 = np::sockaddr6_to_sockaddr(*addr_ipv6);
|
||||
|
|
|
@ -48,8 +48,6 @@ struct nt_p2p_port
|
|||
socket_type p2p_socket = 0;
|
||||
u16 port = 0;
|
||||
|
||||
bool is_ipv6 = false;
|
||||
|
||||
shared_mutex bound_p2p_vports_mutex;
|
||||
// For DGRAM_P2P sockets (vport, sock_ids)
|
||||
std::map<u16, std::set<s32>> bound_p2p_vports{};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "ip_address.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
@ -89,33 +90,54 @@ namespace np
|
|||
}
|
||||
}
|
||||
|
||||
struct ipv6_support_state
|
||||
{
|
||||
ipv6_support_state() = default;
|
||||
ipv6_support_state(const ipv6_support_state&) = delete;
|
||||
ipv6_support_state& operator=(const ipv6_support_state&) = delete;
|
||||
|
||||
atomic_t<IPV6_SUPPORT> status = IPV6_SUPPORT::IPV6_UNKNOWN;
|
||||
};
|
||||
|
||||
// The conditions for IPv6 to be enabled are, in order:
|
||||
// -IPv6 is not disabled in config
|
||||
// -Internet config is Connected
|
||||
// -PSN config is RPCN
|
||||
// -RPCN host has an IPv6
|
||||
// -Can connect to ipv6.google.com:413
|
||||
bool is_ipv6_supported(std::optional<IPV6_SUPPORT> force_state)
|
||||
{
|
||||
static atomic_t<IPV6_SUPPORT> ipv6_status = IPV6_SUPPORT::IPV6_UNKNOWN;
|
||||
auto& ipv6_support = g_fxo->get<ipv6_support_state>();
|
||||
|
||||
if (force_state)
|
||||
ipv6_status = *force_state;
|
||||
ipv6_support.status = *force_state;
|
||||
|
||||
if (ipv6_status != IPV6_SUPPORT::IPV6_UNKNOWN)
|
||||
return ipv6_status == IPV6_SUPPORT::IPV6_SUPPORTED;
|
||||
if (ipv6_support.status != IPV6_SUPPORT::IPV6_UNKNOWN)
|
||||
return ipv6_support.status == IPV6_SUPPORT::IPV6_SUPPORTED;
|
||||
|
||||
static shared_mutex mtx;
|
||||
std::lock_guard lock(mtx);
|
||||
|
||||
if (ipv6_status != IPV6_SUPPORT::IPV6_UNKNOWN)
|
||||
return ipv6_status == IPV6_SUPPORT::IPV6_SUPPORTED;
|
||||
if (ipv6_support.status != IPV6_SUPPORT::IPV6_UNKNOWN)
|
||||
return ipv6_support.status == IPV6_SUPPORT::IPV6_SUPPORTED;
|
||||
|
||||
auto notice_and_disable = [&](std::string_view reason) -> bool
|
||||
{
|
||||
IPv6_log.notice("is_ipv6_supported(): disabled cause: %s", reason);
|
||||
ipv6_support.status = IPV6_SUPPORT::IPV6_UNSUPPORTED;
|
||||
return false;
|
||||
};
|
||||
|
||||
// IPv6 feature is only used by RPCN
|
||||
if (!g_cfg_rpcn.get_ipv6_support())
|
||||
{
|
||||
IPv6_log.notice("is_ipv6_supported(): disabled through config");
|
||||
ipv6_status = IPV6_SUPPORT::IPV6_UNSUPPORTED;
|
||||
return false;
|
||||
}
|
||||
return notice_and_disable("force-disabled through config");
|
||||
|
||||
if (g_cfg.net.net_active != np_internet_status::enabled || g_cfg.net.psn_status != np_psn_status::psn_rpcn)
|
||||
return notice_and_disable("RPCN is disabled");
|
||||
|
||||
// We try to connect to ipv6.google.com:8080
|
||||
addrinfo* addr_info{};
|
||||
socket_type socket_ipv6{};
|
||||
const addrinfo hints{.ai_family = AF_INET6};
|
||||
|
||||
auto cleanup = [&]()
|
||||
{
|
||||
|
@ -126,31 +148,54 @@ namespace np
|
|||
freeaddrinfo(addr_info);
|
||||
};
|
||||
|
||||
auto error_and_disable = [&](const char* message) -> bool
|
||||
auto error_and_disable = [&](std::string_view message) -> bool
|
||||
{
|
||||
IPv6_log.error("is_ipv6_supported(): %s", message);
|
||||
ipv6_status = IPV6_SUPPORT::IPV6_UNSUPPORTED;
|
||||
IPv6_log.error("is_ipv6_supported(): disabled cause: %s", message);
|
||||
ipv6_support.status = IPV6_SUPPORT::IPV6_UNSUPPORTED;
|
||||
cleanup();
|
||||
return false;
|
||||
};
|
||||
|
||||
addrinfo hints{.ai_family = AF_INET6};
|
||||
|
||||
if (getaddrinfo("ipv6.google.com", nullptr, &hints, &addr_info))
|
||||
return error_and_disable("Failed to resolve ipv6.google.com!");
|
||||
|
||||
addrinfo* found = addr_info;
|
||||
|
||||
while (found != nullptr)
|
||||
auto get_ipv6 = [](const addrinfo* addr_info) -> const addrinfo*
|
||||
{
|
||||
if (found->ai_family == AF_INET6)
|
||||
break;
|
||||
const addrinfo* found = addr_info;
|
||||
|
||||
found = found->ai_next;
|
||||
}
|
||||
while (found != nullptr)
|
||||
{
|
||||
if (found->ai_family == AF_INET6)
|
||||
break;
|
||||
|
||||
if (found == nullptr)
|
||||
return error_and_disable("Failed to find IPv6 for ipv6.google.com");
|
||||
found = found->ai_next;
|
||||
}
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
// Check if RPCN has an IPv6 address
|
||||
const auto parsed_host = parse_rpcn_host(g_cfg_rpcn.get_host());
|
||||
|
||||
if (!parsed_host)
|
||||
return error_and_disable("failed to parse RPCN host");
|
||||
|
||||
const auto [hostname, _] = *parsed_host;
|
||||
|
||||
if (getaddrinfo(hostname.c_str(), nullptr, &hints, &addr_info))
|
||||
return error_and_disable("failed to resolve RPCN host");
|
||||
|
||||
if (!get_ipv6(addr_info))
|
||||
return error_and_disable("RPCN host doesn't support IPv6");
|
||||
|
||||
freeaddrinfo(addr_info);
|
||||
addr_info = {};
|
||||
|
||||
// We try to connect to ipv6.google.com:8080
|
||||
if (getaddrinfo("ipv6.google.com", nullptr, &hints, &addr_info))
|
||||
return error_and_disable("failed to resolve ipv6.google.com");
|
||||
|
||||
const auto* google_ipv6_addr = get_ipv6(addr_info);
|
||||
|
||||
if (!google_ipv6_addr)
|
||||
return error_and_disable("failed to find IPv6 for ipv6.google.com");
|
||||
|
||||
socket_type socket_or_err = ::socket(AF_INET6, SOCK_STREAM, 0);
|
||||
|
||||
|
@ -162,7 +207,7 @@ namespace np
|
|||
return error_and_disable("Failed to create IPv6 socket!");
|
||||
|
||||
socket_ipv6 = socket_or_err;
|
||||
sockaddr_in6 ipv6_addr = *reinterpret_cast<const sockaddr_in6*>(found->ai_addr);
|
||||
sockaddr_in6 ipv6_addr = *reinterpret_cast<const sockaddr_in6*>(google_ipv6_addr->ai_addr);
|
||||
ipv6_addr.sin6_port = std::bit_cast<u16, be_t<u16>>(443);
|
||||
|
||||
if (::connect(socket_ipv6, reinterpret_cast<const sockaddr*>(&ipv6_addr), sizeof(ipv6_addr)) != 0)
|
||||
|
@ -171,7 +216,7 @@ namespace np
|
|||
cleanup();
|
||||
|
||||
IPv6_log.success("Successfully tested IPv6 support!");
|
||||
ipv6_status = IPV6_SUPPORT::IPV6_SUPPORTED;
|
||||
ipv6_support.status = IPV6_SUPPORT::IPV6_SUPPORTED;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -970,33 +970,15 @@ namespace rpcn
|
|||
|
||||
state = rpcn_state::failure_no_failure;
|
||||
|
||||
if (host.empty())
|
||||
const auto hostname_and_port = parse_rpcn_host(host);
|
||||
|
||||
if (!hostname_and_port)
|
||||
{
|
||||
rpcn_log.error("connect: RPCN host is empty!");
|
||||
state = rpcn_state::failure_input;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto splithost = fmt::split(host, {":"});
|
||||
if (splithost.size() != 1 && splithost.size() != 2)
|
||||
{
|
||||
rpcn_log.error("connect: RPCN host is invalid!");
|
||||
state = rpcn_state::failure_input;
|
||||
return false;
|
||||
}
|
||||
|
||||
u16 port = 31313;
|
||||
|
||||
if (splithost.size() == 2)
|
||||
{
|
||||
port = ::narrow<u16>(std::stoul(splithost[1]));
|
||||
if (port == 0)
|
||||
{
|
||||
rpcn_log.error("connect: RPCN port is invalid!");
|
||||
state = rpcn_state::failure_input;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const auto [hostname, port] = *hostname_and_port;
|
||||
|
||||
{
|
||||
// Ensures both read & write threads are in waiting state
|
||||
|
@ -1037,14 +1019,14 @@ namespace rpcn
|
|||
|
||||
addrinfo* addr_info{};
|
||||
|
||||
if (getaddrinfo(splithost[0].c_str(), nullptr, nullptr, &addr_info))
|
||||
if (getaddrinfo(hostname.c_str(), nullptr, nullptr, &addr_info))
|
||||
{
|
||||
rpcn_log.error("connect: Failed to getaddrinfo %s", host);
|
||||
state = rpcn_state::failure_resolve;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found_ipv4 = false, found_ipv6 = false;
|
||||
bool found_ipv4 = false;
|
||||
addrinfo* found = addr_info;
|
||||
|
||||
while (found != nullptr)
|
||||
|
@ -1059,13 +1041,9 @@ namespace rpcn
|
|||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
if (np::is_ipv6_supported())
|
||||
{
|
||||
addr_rpcn_udp_ipv6.sin6_family = AF_INET6;
|
||||
addr_rpcn_udp_ipv6.sin6_port = std::bit_cast<u16, be_t<u16>>(3657);
|
||||
addr_rpcn_udp_ipv6.sin6_addr = reinterpret_cast<sockaddr_in6*>(found->ai_addr)->sin6_addr;
|
||||
found_ipv6 = true;
|
||||
}
|
||||
addr_rpcn_udp_ipv6.sin6_family = AF_INET6;
|
||||
addr_rpcn_udp_ipv6.sin6_port = std::bit_cast<u16, be_t<u16>>(3657);
|
||||
addr_rpcn_udp_ipv6.sin6_addr = reinterpret_cast<sockaddr_in6*>(found->ai_addr)->sin6_addr;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
@ -1081,12 +1059,6 @@ namespace rpcn
|
|||
return false;
|
||||
}
|
||||
|
||||
if (np::is_ipv6_supported() && !found_ipv6)
|
||||
{
|
||||
rpcn_log.warning("IPv6 seems supported but no IPv6 could be found for the RPCN server, IPv6 is disabled!");
|
||||
is_ipv6_supported(np::IPV6_SUPPORT::IPV6_UNSUPPORTED);
|
||||
}
|
||||
|
||||
memcpy(&addr_rpcn_udp_ipv4, &addr_rpcn, sizeof(addr_rpcn_udp_ipv4));
|
||||
addr_rpcn_udp_ipv4.sin_port = std::bit_cast<u16, be_t<u16>>(3657); // htons
|
||||
|
||||
|
|
|
@ -211,3 +211,33 @@ bool cfg_rpcn::del_host(std::string_view del_description, std::string_view del_h
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, u16>> parse_rpcn_host(std::string_view host)
|
||||
{
|
||||
if (host.empty())
|
||||
{
|
||||
rpcn_log.error("RPCN host is empty!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto splithost = fmt::split(host, {":"});
|
||||
if (splithost.size() != 1 && splithost.size() != 2)
|
||||
{
|
||||
rpcn_log.error("RPCN host is invalid!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
u16 port = 31313;
|
||||
|
||||
if (splithost.size() == 2)
|
||||
{
|
||||
port = ::narrow<u16>(std::stoul(splithost[1]));
|
||||
if (port == 0)
|
||||
{
|
||||
rpcn_log.error("RPCN port is invalid!");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(std::move(splithost[0]), port);
|
||||
}
|
||||
|
|
|
@ -36,4 +36,6 @@ private:
|
|||
void set_hosts(const std::vector<std::pair<std::string, std::string>>& vec_hosts);
|
||||
};
|
||||
|
||||
std::optional<std::pair<std::string, u16>> parse_rpcn_host(std::string_view host);
|
||||
|
||||
extern cfg_rpcn g_cfg_rpcn;
|
||||
|
|
|
@ -200,9 +200,8 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent)
|
|||
g_cfg_rpcn.set_host(host.toString().toStdString());
|
||||
g_cfg_rpcn.save();
|
||||
|
||||
// Resets the state in case the support was limited by the RPCN server
|
||||
if (!np::is_ipv6_supported())
|
||||
np::is_ipv6_supported(np::IPV6_SUPPORT::IPV6_UNKNOWN);
|
||||
// Resets the ipv6 support as it depends on availability of the feature on the server
|
||||
np::is_ipv6_supported(np::IPV6_SUPPORT::IPV6_UNKNOWN);
|
||||
});
|
||||
|
||||
connect(btn_add_server, &QAbstractButton::clicked, this, [this]()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue