Make IP Binding more global
Some checks failed
Generate Translation Template / Generate Translation Template (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ubuntu-24.04 gcc (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ubuntu-24.04-arm clang (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ubuntu-24.04 clang (push) Has been cancelled
Build RPCS3 / RPCS3 Windows (push) Has been cancelled

This commit is contained in:
RipleyTom 2025-05-10 03:40:21 +02:00 committed by Elad
parent d21358e91f
commit 3894c903bc
17 changed files with 80 additions and 36 deletions

View file

@ -7,6 +7,7 @@
#include "sys_net_helpers.h"
#include "Emu/NP/vport0.h"
#include "Emu/NP/np_handler.h"
#include "Emu/NP/np_helpers.h"
LOG_CHANNEL(sys_net);
@ -59,6 +60,7 @@ nt_p2p_port::nt_p2p_port(u16 port)
int ret_bind = 0;
const u16 be_port = std::bit_cast<u16, be_t<u16>>(port);
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
if (is_ipv6)
{
@ -73,15 +75,23 @@ nt_p2p_port::nt_p2p_port(u16 port)
else
{
::sockaddr_in p2p_ipv4_addr{.sin_family = AF_INET, .sin_port = be_port};
ret_bind = ::bind(p2p_socket, reinterpret_cast<sockaddr*>(&p2p_ipv4_addr), sizeof(p2p_ipv4_addr));
p2p_ipv4_addr.sin_addr.s_addr = nph.get_bind_ip();
if (ret_bind = ::bind(p2p_socket, reinterpret_cast<const sockaddr*>(&p2p_ipv4_addr), sizeof(p2p_ipv4_addr)); ret_bind == -1)
{
if (nph.get_bind_ip())
{
sys_net.error("Failed to bind to %s:%d, falling back to 0.0.0.0:%d", np::ip_to_string(nph.get_bind_ip()), port, port);
p2p_ipv4_addr.sin_addr.s_addr = 0;
ret_bind = ::bind(p2p_socket, reinterpret_cast<const sockaddr*>(&p2p_ipv4_addr), sizeof(p2p_ipv4_addr));
}
}
}
if (ret_bind == -1)
fmt::throw_exception("Failed to bind DGRAM socket to %d for P2P: %s!", port, get_last_error(true));
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
nph.upnp_add_port_mapping(port, "UDP");
sys_net.notice("P2P port %d was bound!", port);
}

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Emu/IdManager.h"
#include "Emu/system_config.h"
#include "Emu/Cell/PPUThread.h"
#include "lv2_socket.h"
#include "sys_net_helpers.h"
@ -199,6 +200,26 @@ void clear_ppu_to_awake(ppu_thread& ppu)
g_fxo->get<p2p_context>().del_ppu_to_awake(&ppu);
}
be_t<u32> resolve_binding_ip()
{
in_addr conv{};
const std::string cfg_bind_addr = g_cfg.net.bind_address.to_string();
if (cfg_bind_addr == "0.0.0.0" || cfg_bind_addr == "")
{
return 0;
}
if (!inet_pton(AF_INET, cfg_bind_addr.c_str(), &conv))
{
// Do not set to disconnected on invalid IP just error and continue using default (0.0.0.0)
sys_net.error("Provided IP(%s) address for bind is invalid!", g_cfg.net.bind_address.to_string());
return 0;
}
return conv.s_addr;
}
#ifdef _WIN32
// Workaround function for WSAPoll not reporting failed connections
// Note that this was fixed in Windows 10 version 2004 (after more than 10 years lol)

View file

@ -25,6 +25,7 @@ sys_net_sockaddr native_addr_to_sys_net_addr(const ::sockaddr_storage& native_ad
bool is_ip_public_address(const ::sockaddr_in& addr);
u32 network_clear_queue(ppu_thread& ppu);
void clear_ppu_to_awake(ppu_thread& ppu);
be_t<u32> resolve_binding_ip();
#ifdef _WIN32
void windows_poll(std::vector<pollfd>& fds, unsigned long nfds, int timeout, std::vector<bool>& connecting);

View file

@ -1,3 +1,4 @@
#include "Emu/Cell/lv2/sys_net/sys_net_helpers.h"
#include "stdafx.h"
#include "Emu/system_config.h"
#include "ip_address.h"
@ -6,6 +7,7 @@
#include "util/endian.hpp"
#include "util/types.hpp"
#include "Emu/NP/rpcn_config.h"
#include "Emu/Cell/lv2/sys_net/sys_net_helpers.h"
#include <algorithm>
#ifndef _WIN32
@ -103,6 +105,7 @@ namespace np
// -IPv6 is not disabled in config
// -Internet config is Connected
// -PSN config is RPCN
// -Bind IP is not set
// -RPCN host has an IPv6
// -Can connect to ipv6.google.com:413
bool is_ipv6_supported(std::optional<IPV6_SUPPORT> force_state)
@ -135,6 +138,9 @@ namespace np
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");
if (resolve_binding_ip())
return notice_and_disable("Bind IP is used");
addrinfo* addr_info{};
socket_type socket_ipv6{};
const addrinfo hints{.ai_family = AF_INET6};

View file

@ -412,7 +412,7 @@ namespace np
nc.bind_sce_np_port();
std::lock_guard lock(mutex_rpcn);
rpcn = rpcn::rpcn_client::get_instance();
rpcn = rpcn::rpcn_client::get_instance(bind_ip);
}
}
@ -455,19 +455,10 @@ namespace np
}
// Convert bind address
conv = {};
if (!inet_pton(AF_INET, g_cfg.net.bind_address.to_string().c_str(), &conv))
{
// Do not set to disconnected on invalid IP just error and continue using default (0.0.0.0)
nph_log.error("Provided IP(%s) address for bind is invalid!", g_cfg.net.bind_address.to_string());
}
else
{
bind_ip = conv.s_addr;
bind_ip = resolve_binding_ip();
if (bind_ip)
local_ip_addr = bind_ip;
}
if (bind_ip)
local_ip_addr = bind_ip;
if (g_cfg.net.upnp_enabled)
upnp.upnp_enable();
@ -793,7 +784,7 @@ namespace np
if (!rpcn)
{
rpcn = rpcn::rpcn_client::get_instance();
rpcn = rpcn::rpcn_client::get_instance(bind_ip);
was_already_started = false;
}

View file

@ -11,7 +11,7 @@ namespace np
{
std::string ip_to_string(u32 ip_addr)
{
char ip_str[16];
char ip_str[16]{};
inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str));
return std::string(ip_str);

View file

@ -212,6 +212,7 @@ namespace rpcn
case rpcn::rpcn_state::failure_input: return localized_string_id::RPCN_ERROR_INVALID_INPUT;
case rpcn::rpcn_state::failure_wolfssl: return localized_string_id::RPCN_ERROR_WOLFSSL;
case rpcn::rpcn_state::failure_resolve: return localized_string_id::RPCN_ERROR_RESOLVE;
case rpcn::rpcn_state::failure_binding: return localized_string_id::RPCN_ERROR_BINDING;
case rpcn::rpcn_state::failure_connect: return localized_string_id::RPCN_ERROR_CONNECT;
case rpcn::rpcn_state::failure_id: return localized_string_id::RPCN_ERROR_LOGIN_ERROR;
case rpcn::rpcn_state::failure_id_already_logged_in: return localized_string_id::RPCN_ERROR_ALREADY_LOGGED;
@ -316,8 +317,8 @@ namespace rpcn
// Constructor, destructor & singleton manager
rpcn_client::rpcn_client()
: sem_connected(0), sem_authentified(0), sem_reader(0), sem_writer(0), sem_rpcn(0),
rpcn_client::rpcn_client(u32 binding_address)
: binding_address(binding_address), sem_connected(0), sem_authentified(0), sem_reader(0), sem_writer(0), sem_rpcn(0),
thread_rpcn(std::thread(&rpcn_client::rpcn_thread, this)),
thread_rpcn_reader(std::thread(&rpcn_client::rpcn_reader_thread, this)),
thread_rpcn_writer(std::thread(&rpcn_client::rpcn_writer_thread, this))
@ -349,7 +350,7 @@ namespace rpcn
sem_authentified.release();
}
std::shared_ptr<rpcn_client> rpcn_client::get_instance(bool check_config)
std::shared_ptr<rpcn_client> rpcn_client::get_instance(u32 binding_address, bool check_config)
{
if (check_config && g_cfg.net.psn_status != np_psn_status::psn_rpcn)
{
@ -362,7 +363,7 @@ namespace rpcn
sptr = instance.lock();
if (!sptr)
{
sptr = std::shared_ptr<rpcn_client>(new rpcn_client());
sptr = std::shared_ptr<rpcn_client>(new rpcn_client(binding_address));
sptr->register_friend_cb(overlay_friend_callback, nullptr);
instance = sptr;
}
@ -1074,6 +1075,16 @@ namespace rpcn
return false;
}
sockaddr_in sock_addr = {.sin_family = AF_INET};
sock_addr.sin_addr.s_addr = binding_address;
if (::bind(sockfd, reinterpret_cast<const sockaddr*>(&sock_addr), sizeof(sock_addr)) == -1)
{
rpcn_log.error("bind: Failed to bind RPCN client socket to binding address!");
state = rpcn_state::failure_binding;
return false;
}
if (::connect(sockfd, reinterpret_cast<struct sockaddr*>(&addr_rpcn), sizeof(addr_rpcn)) != 0)
{
rpcn_log.error("connect: Failed to connect to RPCN server!");

View file

@ -227,6 +227,7 @@ namespace rpcn
atomic_t<bool> authentified = false;
atomic_t<bool> want_conn = false;
atomic_t<bool> want_auth = false;
u32 binding_address = 0;
std::binary_semaphore sem_connected, sem_authentified;
std::mutex mutex_connected, mutex_authentified;
@ -253,7 +254,7 @@ namespace rpcn
void handle_message(std::vector<u8> data);
private:
rpcn_client();
rpcn_client(u32 binding_address);
void rpcn_reader_thread();
void rpcn_writer_thread();
@ -287,7 +288,7 @@ namespace rpcn
~rpcn_client();
rpcn_client(rpcn_client& other) = delete;
void operator=(const rpcn_client&) = delete;
static std::shared_ptr<rpcn_client> get_instance(bool check_config = false);
static std::shared_ptr<rpcn_client> get_instance(u32 binding_address, bool check_config = false);
rpcn_state wait_for_connection();
rpcn_state wait_for_authentified();
bool terminate_connection();

View file

@ -98,6 +98,7 @@ namespace rpcn
failure_input,
failure_wolfssl,
failure_resolve,
failure_binding,
failure_connect,
failure_id,
failure_id_already_logged_in,

View file

@ -655,7 +655,7 @@ namespace rsx
g_cfg_rpcn.load(); // Ensures config is loaded even if rpcn is not running for simulated
m_rpcn = rpcn::rpcn_client::get_instance();
m_rpcn = rpcn::rpcn_client::get_instance(0);
m_rpcn->register_friend_cb(friend_callback, this);

View file

@ -213,7 +213,7 @@ namespace rsx
const bool preserve = options & SCE_NP_BASIC_RECV_MESSAGE_OPTIONS_PRESERVE;
const bool include_bootable = options & SCE_NP_BASIC_RECV_MESSAGE_OPTIONS_INCLUDE_BOOTABLE;
m_rpcn = rpcn::rpcn_client::get_instance(true);
m_rpcn = rpcn::rpcn_client::get_instance(0, true);
// Get list of messages
const auto messages = m_rpcn->get_messages_and_register_cb(type, include_bootable, recvmessage_callback, this);

View file

@ -183,7 +183,7 @@ namespace rsx
break; // Title already set in constructor
}
m_rpcn = rpcn::rpcn_client::get_instance(true);
m_rpcn = rpcn::rpcn_client::get_instance(0, true);
// Get list of messages
rpcn::friend_data data;

View file

@ -163,6 +163,7 @@ enum class localized_string_id
RPCN_ERROR_INVALID_INPUT,
RPCN_ERROR_WOLFSSL,
RPCN_ERROR_RESOLVE,
RPCN_ERROR_BINDING,
RPCN_ERROR_CONNECT,
RPCN_ERROR_LOGIN_ERROR,
RPCN_ERROR_ALREADY_LOGGED,

View file

@ -185,6 +185,7 @@ private:
case localized_string_id::RPCN_ERROR_INVALID_INPUT: return tr("RPCN: Invalid Input (Wrong Host/Port)");
case localized_string_id::RPCN_ERROR_WOLFSSL: return tr("RPCN Connection Error: WolfSSL Error");
case localized_string_id::RPCN_ERROR_RESOLVE: return tr("RPCN Connection Error: Resolve Error");
case localized_string_id::RPCN_ERROR_BINDING: return tr("RPCN Connection Error: Failed to bind to given binding IP");
case localized_string_id::RPCN_ERROR_CONNECT: return tr("RPCN Connection Error");
case localized_string_id::RPCN_ERROR_LOGIN_ERROR: return tr("RPCN Login Error: Identification Error");
case localized_string_id::RPCN_ERROR_ALREADY_LOGGED: return tr("RPCN Login Error: User Already Logged In");

View file

@ -42,7 +42,7 @@ error_code recvmessage_dialog_frame::Exec(SceNpBasicMessageMainType type, SceNpB
m_dialog->setWindowTitle(tr("Choose message:"));
m_rpcn = rpcn::rpcn_client::get_instance(true);
m_rpcn = rpcn::rpcn_client::get_instance(0, true);
QVBoxLayout* vbox_global = new QVBoxLayout();

View file

@ -270,7 +270,7 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent)
return;
{
const auto rpcn = rpcn::rpcn_client::get_instance();
const auto rpcn = rpcn::rpcn_client::get_instance(0);
const auto avatar_url = "https://rpcs3.net/cdn/netplay/DefaultAvatar.png";
if (auto result = rpcn->wait_for_connection(); result != rpcn::rpcn_state::failure_no_failure)
@ -325,7 +325,7 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent)
connect(btn_test, &QAbstractButton::clicked, this, [this]()
{
auto rpcn = rpcn::rpcn_client::get_instance();
auto rpcn = rpcn::rpcn_client::get_instance(0);
if (auto res = rpcn->wait_for_connection(); res != rpcn::rpcn_state::failure_no_failure)
{
@ -342,7 +342,7 @@ rpcn_account_dialog::rpcn_account_dialog(QWidget* parent)
QMessageBox::information(this, tr("RPCN Account Valid!"), tr("Your account is valid!"), QMessageBox::Ok);
});
connect(checkbox_disable_ipv6, &QCheckBox::checkStateChanged, this, [this](Qt::CheckState state)
{
g_cfg_rpcn.set_ipv6_support(state == Qt::Unchecked);
@ -761,7 +761,7 @@ void rpcn_account_edit_dialog::resend_token()
if (!save_config())
return;
const auto rpcn = rpcn::rpcn_client::get_instance();
const auto rpcn = rpcn::rpcn_client::get_instance(0);
const std::string npid = g_cfg_rpcn.get_npid();
const std::string password = g_cfg_rpcn.get_password();
@ -814,7 +814,7 @@ void rpcn_account_edit_dialog::change_password()
return;
{
const auto rpcn = rpcn::rpcn_client::get_instance();
const auto rpcn = rpcn::rpcn_client::get_instance(0);
if (auto result = rpcn->wait_for_connection(); result != rpcn::rpcn_state::failure_no_failure)
{
const QString error_message = tr("Failed to connect to RPCN server:\n%0").arg(QString::fromStdString(rpcn::rpcn_state_to_string(result)));
@ -859,7 +859,7 @@ void rpcn_account_edit_dialog::change_password()
return;
{
const auto rpcn = rpcn::rpcn_client::get_instance();
const auto rpcn = rpcn::rpcn_client::get_instance(0);
if (auto result = rpcn->wait_for_connection(); result != rpcn::rpcn_state::failure_no_failure)
{
const QString error_message = tr("Failed to connect to RPCN server:\n%0").arg(QString::fromStdString(rpcn::rpcn_state_to_string(result)));
@ -1048,7 +1048,7 @@ rpcn_friends_dialog::rpcn_friends_dialog(QWidget* parent)
setLayout(vbox_global);
// Tries to connect to RPCN
m_rpcn = rpcn::rpcn_client::get_instance();
m_rpcn = rpcn::rpcn_client::get_instance(0);
if (auto res = m_rpcn->wait_for_connection(); res != rpcn::rpcn_state::failure_no_failure)
{

View file

@ -40,7 +40,7 @@ error_code sendmessage_dialog_frame::Exec(message_data& msg_data, std::set<std::
m_dialog->setWindowTitle(tr("Choose friend to message:"));
m_rpcn = rpcn::rpcn_client::get_instance(true);
m_rpcn = rpcn::rpcn_client::get_instance(0, true);
QVBoxLayout* vbox_global = new QVBoxLayout();