mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
Simplify signaling by making Matching2 a layer over normal signaling. Implements UPNP port forwarding Implement sceNpMatching2AbortRequest Fix reported bw in sceNpUtil Hack for Fat Princess binding udp on 3658 Reenable CB for sceNpBasicAddPlayersHistoryAsync Misc fixes
187 lines
4.7 KiB
C++
187 lines
4.7 KiB
C++
#include "stdafx.h"
|
|
#include "upnp_handler.h"
|
|
#include "util/logs.hpp"
|
|
|
|
#include <miniwget.h>
|
|
#include <upnpcommands.h>
|
|
|
|
LOG_CHANNEL(upnp_log, "UPNP");
|
|
|
|
upnp_handler::~upnp_handler()
|
|
{
|
|
std::lock_guard lock(m_mutex);
|
|
|
|
for (const auto& [protocol, prot_bindings] : m_bindings)
|
|
{
|
|
for (const auto& [internal_port, external_port] : prot_bindings)
|
|
{
|
|
remove_port_redir_external(external_port, protocol);
|
|
}
|
|
}
|
|
|
|
m_active = false;
|
|
}
|
|
|
|
void upnp_handler::upnp_enable()
|
|
{
|
|
std::lock_guard lock(m_mutex);
|
|
|
|
m_cfg.load();
|
|
|
|
auto check_igd = [&](const char* url) -> bool
|
|
{
|
|
int desc_xml_size = 0;
|
|
int status_code = 0;
|
|
|
|
m_igd_data = {};
|
|
m_igd_urls = {};
|
|
|
|
char* desc_xml = static_cast<char*>(miniwget(url, &desc_xml_size, 1, &status_code));
|
|
|
|
if (!desc_xml)
|
|
return false;
|
|
|
|
parserootdesc(desc_xml, desc_xml_size, &m_igd_data);
|
|
free(desc_xml);
|
|
desc_xml = nullptr;
|
|
GetUPNPUrls(&m_igd_urls, &m_igd_data, url, 1);
|
|
|
|
return true;
|
|
};
|
|
|
|
std::string dev_url = m_cfg.get_device_url();
|
|
|
|
if (!dev_url.empty())
|
|
{
|
|
if (check_igd(dev_url.c_str()))
|
|
{
|
|
upnp_log.notice("Saved UPNP(%s) enabled", dev_url);
|
|
m_active = true;
|
|
return;
|
|
}
|
|
|
|
upnp_log.error("Saved UPNP(%s) isn't available anymore", dev_url);
|
|
}
|
|
|
|
upnp_log.notice("Starting UPNP search");
|
|
|
|
int upnperror = 0;
|
|
UPNPDev* devlist = upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror);
|
|
|
|
if (!devlist)
|
|
{
|
|
upnp_log.error("No UPNP device was found");
|
|
return;
|
|
}
|
|
|
|
const UPNPDev* dev = devlist;
|
|
for (; dev; dev = dev->pNext)
|
|
{
|
|
if (strstr(dev->st, "InternetGatewayDevice"))
|
|
break;
|
|
}
|
|
|
|
if (dev)
|
|
{
|
|
int desc_xml_size = 0;
|
|
int status_code = 0;
|
|
char* desc_xml = static_cast<char*>(miniwget(dev->descURL, &desc_xml_size, 1, &status_code));
|
|
|
|
if (desc_xml)
|
|
{
|
|
IGDdatas igd_data{};
|
|
UPNPUrls igd_urls{};
|
|
parserootdesc(desc_xml, desc_xml_size, &igd_data);
|
|
free(desc_xml);
|
|
desc_xml = nullptr;
|
|
GetUPNPUrls(&igd_urls, &igd_data, dev->descURL, 1);
|
|
|
|
upnp_log.notice("Found UPnP device type:%s at %s", dev->st, dev->descURL);
|
|
|
|
m_cfg.set_device_url(dev->descURL);
|
|
m_cfg.save();
|
|
|
|
m_active = true;
|
|
}
|
|
else
|
|
{
|
|
upnp_log.error("Failed to retrieve UPNP xml for %s", dev->descURL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
upnp_log.error("No UPNP IGD device was found");
|
|
}
|
|
|
|
freeUPNPDevlist(devlist);
|
|
}
|
|
|
|
void upnp_handler::add_port_redir(std::string_view addr, u16 internal_port, std::string_view protocol)
|
|
{
|
|
if (!m_active)
|
|
return;
|
|
|
|
std::lock_guard lock(m_mutex);
|
|
|
|
u16 external_port = internal_port;
|
|
std::string internal_port_str = fmt::format("%d", internal_port);
|
|
int res = 0;
|
|
|
|
for (u16 external_port = internal_port; external_port < internal_port + 100; external_port++)
|
|
{
|
|
std::string external_port_str = fmt::format("%d", external_port);
|
|
res = UPNP_AddPortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, external_port_str.c_str(), internal_port_str.c_str(), addr.data(), "RPCS3", protocol.data(), nullptr, nullptr);
|
|
if (res == UPNPCOMMAND_SUCCESS)
|
|
{
|
|
m_bindings[std::string(protocol)][internal_port] = external_port;
|
|
upnp_log.notice("Successfully bound %s:%d(%s) to IGD:%d", addr, internal_port, protocol, external_port);
|
|
return;
|
|
}
|
|
|
|
// need more testing, may vary per router, etc, for now assume port conflict silently
|
|
// else if (res != 718) // ConflictInMappingEntry
|
|
// {
|
|
// upnp_log.error("Failed to bind %s:%d(%s) to IGD:%d: %d", addr, internal_port, protocol, external_port, res);
|
|
// return;
|
|
// }
|
|
}
|
|
|
|
upnp_log.error("Failed to bind %s:%d(%s) to IGD:(%d=>%d): %d", addr, internal_port, protocol, internal_port, external_port, res);
|
|
}
|
|
|
|
void upnp_handler::remove_port_redir(u16 internal_port, std::string_view protocol)
|
|
{
|
|
if (!m_active)
|
|
return;
|
|
|
|
std::lock_guard lock(m_mutex);
|
|
|
|
const std::string str_protocol(protocol);
|
|
|
|
if (!m_bindings.contains(str_protocol) || !::at32(m_bindings, str_protocol).contains(internal_port))
|
|
{
|
|
upnp_log.error("tried to unbind port mapping %d to IGD(%s) but it isn't bound", internal_port, protocol);
|
|
return;
|
|
}
|
|
|
|
const u16 external_port = ::at32(::at32(m_bindings, str_protocol), internal_port);
|
|
|
|
remove_port_redir_external(external_port, protocol);
|
|
|
|
ensure(::at32(m_bindings, str_protocol).erase(internal_port));
|
|
upnp_log.notice("Successfully deleted port mapping %d to IGD:%d(%s)", internal_port, external_port, protocol);
|
|
}
|
|
|
|
void upnp_handler::remove_port_redir_external(u16 external_port, std::string_view protocol, bool verbose)
|
|
{
|
|
const std::string str_ext_port = fmt::format("%d", external_port);
|
|
|
|
if (int res = UPNP_DeletePortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, str_ext_port.c_str(), protocol.data(), nullptr); res != 0 && verbose)
|
|
upnp_log.error("Failed to delete port mapping IGD:%s(%s): %d", str_ext_port, protocol, res);
|
|
}
|
|
|
|
bool upnp_handler::is_active() const
|
|
{
|
|
return m_active;
|
|
}
|