Merge pull request #5898 from ligfx/extractupnp
Common: extract UPnP namespace from NetPlayServer
This commit is contained in:
commit
a53b01360c
|
@ -6,6 +6,9 @@ set(SRCS
|
||||||
Config/Config.cpp
|
Config/Config.cpp
|
||||||
Config/Layer.cpp
|
Config/Layer.cpp
|
||||||
Config/Section.cpp
|
Config/Section.cpp
|
||||||
|
Crypto/AES.cpp
|
||||||
|
Crypto/bn.cpp
|
||||||
|
Crypto/ec.cpp
|
||||||
ENetUtil.cpp
|
ENetUtil.cpp
|
||||||
File.cpp
|
File.cpp
|
||||||
FileSearch.cpp
|
FileSearch.cpp
|
||||||
|
@ -15,7 +18,9 @@ set(SRCS
|
||||||
HttpRequest.cpp
|
HttpRequest.cpp
|
||||||
IniFile.cpp
|
IniFile.cpp
|
||||||
JitRegister.cpp
|
JitRegister.cpp
|
||||||
|
Logging/LogManager.cpp
|
||||||
MathUtil.cpp
|
MathUtil.cpp
|
||||||
|
MD5.cpp
|
||||||
MemArena.cpp
|
MemArena.cpp
|
||||||
MemoryUtil.cpp
|
MemoryUtil.cpp
|
||||||
MsgHandler.cpp
|
MsgHandler.cpp
|
||||||
|
@ -32,14 +37,10 @@ set(SRCS
|
||||||
Thread.cpp
|
Thread.cpp
|
||||||
Timer.cpp
|
Timer.cpp
|
||||||
TraversalClient.cpp
|
TraversalClient.cpp
|
||||||
|
UPnP.cpp
|
||||||
Version.cpp
|
Version.cpp
|
||||||
x64ABI.cpp
|
x64ABI.cpp
|
||||||
x64Emitter.cpp
|
x64Emitter.cpp
|
||||||
MD5.cpp
|
|
||||||
Crypto/AES.cpp
|
|
||||||
Crypto/bn.cpp
|
|
||||||
Crypto/ec.cpp
|
|
||||||
Logging/LogManager.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBS ${LIBS} ${MBEDTLS_LIBRARIES})
|
set(LIBS ${LIBS} ${MBEDTLS_LIBRARIES})
|
||||||
|
|
|
@ -151,6 +151,7 @@
|
||||||
<ClInclude Include="Timer.h" />
|
<ClInclude Include="Timer.h" />
|
||||||
<ClInclude Include="TraversalClient.h" />
|
<ClInclude Include="TraversalClient.h" />
|
||||||
<ClInclude Include="TraversalProto.h" />
|
<ClInclude Include="TraversalProto.h" />
|
||||||
|
<ClInclude Include="UPnP.h" />
|
||||||
<ClInclude Include="x64ABI.h" />
|
<ClInclude Include="x64ABI.h" />
|
||||||
<ClInclude Include="x64Emitter.h" />
|
<ClInclude Include="x64Emitter.h" />
|
||||||
<ClInclude Include="x64Reg.h" />
|
<ClInclude Include="x64Reg.h" />
|
||||||
|
@ -202,6 +203,7 @@
|
||||||
<ClCompile Include="Thread.cpp" />
|
<ClCompile Include="Thread.cpp" />
|
||||||
<ClCompile Include="Timer.cpp" />
|
<ClCompile Include="Timer.cpp" />
|
||||||
<ClCompile Include="TraversalClient.cpp" />
|
<ClCompile Include="TraversalClient.cpp" />
|
||||||
|
<ClCompile Include="UPnP.cpp" />
|
||||||
<ClCompile Include="Version.cpp" />
|
<ClCompile Include="Version.cpp" />
|
||||||
<ClCompile Include="x64ABI.cpp" />
|
<ClCompile Include="x64ABI.cpp" />
|
||||||
<ClCompile Include="x64CPUDetect.cpp" />
|
<ClCompile Include="x64CPUDetect.cpp" />
|
||||||
|
|
|
@ -94,6 +94,7 @@
|
||||||
<ClInclude Include="JitRegister.h" />
|
<ClInclude Include="JitRegister.h" />
|
||||||
<ClInclude Include="TraversalClient.h" />
|
<ClInclude Include="TraversalClient.h" />
|
||||||
<ClInclude Include="TraversalProto.h" />
|
<ClInclude Include="TraversalProto.h" />
|
||||||
|
<ClInclude Include="UPnP.h" />
|
||||||
<ClInclude Include="GL\GLUtil.h">
|
<ClInclude Include="GL\GLUtil.h">
|
||||||
<Filter>GL</Filter>
|
<Filter>GL</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -307,6 +308,7 @@
|
||||||
<ClCompile Include="GekkoDisassembler.cpp" />
|
<ClCompile Include="GekkoDisassembler.cpp" />
|
||||||
<ClCompile Include="JitRegister.cpp" />
|
<ClCompile Include="JitRegister.cpp" />
|
||||||
<ClCompile Include="TraversalClient.cpp" />
|
<ClCompile Include="TraversalClient.cpp" />
|
||||||
|
<ClCompile Include="UPnP.cpp" />
|
||||||
<ClCompile Include="Logging\ConsoleListenerWin.cpp">
|
<ClCompile Include="Logging\ConsoleListenerWin.cpp">
|
||||||
<Filter>Logging</Filter>
|
<Filter>Logging</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#ifdef USE_UPNP
|
||||||
|
|
||||||
|
#include "Common/UPnP.h"
|
||||||
|
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <miniupnpc.h>
|
||||||
|
#include <miniwget.h>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <upnpcommands.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
static UPNPUrls s_urls;
|
||||||
|
static IGDdatas s_data;
|
||||||
|
static std::array<char, 20> s_our_ip;
|
||||||
|
static u16 s_mapped = 0;
|
||||||
|
static std::thread s_thread;
|
||||||
|
|
||||||
|
// called from ---UPnP--- thread
|
||||||
|
// discovers the IGD
|
||||||
|
static bool InitUPnP()
|
||||||
|
{
|
||||||
|
static bool s_inited = false;
|
||||||
|
static bool s_error = false;
|
||||||
|
|
||||||
|
// Don't init if already inited
|
||||||
|
if (s_inited)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Don't init if it failed before
|
||||||
|
if (s_error)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_urls = {};
|
||||||
|
s_data = {};
|
||||||
|
|
||||||
|
// Find all UPnP devices
|
||||||
|
int upnperror = 0;
|
||||||
|
std::unique_ptr<UPNPDev, decltype(&freeUPNPDevlist)> devlist(nullptr, freeUPNPDevlist);
|
||||||
|
#if MINIUPNPC_API_VERSION >= 14
|
||||||
|
devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror));
|
||||||
|
#else
|
||||||
|
devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, &upnperror));
|
||||||
|
#endif
|
||||||
|
if (!devlist)
|
||||||
|
{
|
||||||
|
WARN_LOG(NETPLAY, "An error occurred trying to discover UPnP devices.");
|
||||||
|
|
||||||
|
s_error = true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for the IGD
|
||||||
|
for (UPNPDev* dev = devlist.get(); dev; dev = dev->pNext)
|
||||||
|
{
|
||||||
|
if (!std::strstr(dev->st, "InternetGatewayDevice"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int desc_xml_size = 0;
|
||||||
|
std::unique_ptr<char, decltype(&std::free)> desc_xml(nullptr, std::free);
|
||||||
|
int statusCode = 200;
|
||||||
|
#if MINIUPNPC_API_VERSION >= 16
|
||||||
|
desc_xml.reset(
|
||||||
|
static_cast<char*>(miniwget_getaddr(dev->descURL, &desc_xml_size, s_our_ip.data(),
|
||||||
|
static_cast<int>(s_our_ip.size()), 0, &statusCode)));
|
||||||
|
#else
|
||||||
|
desc_xml.reset(static_cast<char*>(miniwget_getaddr(
|
||||||
|
dev->descURL, &desc_xml_size, s_our_ip.data(), static_cast<int>(s_our_ip.size()), 0)));
|
||||||
|
#endif
|
||||||
|
if (desc_xml && statusCode == 200)
|
||||||
|
{
|
||||||
|
parserootdesc(desc_xml.get(), desc_xml_size, &s_data);
|
||||||
|
GetUPNPUrls(&s_urls, &s_data, dev->descURL, 0);
|
||||||
|
|
||||||
|
NOTICE_LOG(NETPLAY, "Got info from IGD at %s.", dev->descURL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN_LOG(NETPLAY, "Error getting info from IGD at %s.", dev->descURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_inited = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called from ---UPnP--- thread
|
||||||
|
// Attempt to stop portforwarding.
|
||||||
|
// --
|
||||||
|
// NOTE: It is important that this happens! A few very crappy routers
|
||||||
|
// apparently do not delete UPnP mappings on their own, so if you leave them
|
||||||
|
// hanging, the NVRAM will fill with portmappings, and eventually all UPnP
|
||||||
|
// requests will fail silently, with the only recourse being a factory reset.
|
||||||
|
// --
|
||||||
|
static bool UnmapPort(const u16 port)
|
||||||
|
{
|
||||||
|
std::string port_str = std::to_string(port);
|
||||||
|
UPNP_DeletePortMapping(s_urls.controlURL, s_data.first.servicetype, port_str.c_str(), "UDP",
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called from ---UPnP--- thread
|
||||||
|
// Attempt to portforward!
|
||||||
|
static bool MapPort(const char* addr, const u16 port)
|
||||||
|
{
|
||||||
|
if (s_mapped > 0)
|
||||||
|
UnmapPort(s_mapped);
|
||||||
|
|
||||||
|
std::string port_str = std::to_string(port);
|
||||||
|
int result = UPNP_AddPortMapping(
|
||||||
|
s_urls.controlURL, s_data.first.servicetype, port_str.c_str(), port_str.c_str(), addr,
|
||||||
|
(std::string("dolphin-emu UDP on ") + addr).c_str(), "UDP", nullptr, nullptr);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_mapped = port;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPnP thread: try to map a port
|
||||||
|
static void MapPortThread(const u16 port)
|
||||||
|
{
|
||||||
|
if (InitUPnP() && MapPort(s_our_ip.data(), port))
|
||||||
|
{
|
||||||
|
NOTICE_LOG(NETPLAY, "Successfully mapped port %d to %s.", port, s_our_ip.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_LOG(NETPLAY, "Failed to map port %d to %s.", port, s_our_ip.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPnP thread: try to unmap a port
|
||||||
|
static void UnmapPortThread()
|
||||||
|
{
|
||||||
|
if (s_mapped > 0)
|
||||||
|
UnmapPort(s_mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPnP::TryPortmapping(u16 port)
|
||||||
|
{
|
||||||
|
if (s_thread.joinable())
|
||||||
|
s_thread.join();
|
||||||
|
s_thread = std::thread(&MapPortThread, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPnP::StopPortmapping()
|
||||||
|
{
|
||||||
|
if (s_thread.joinable())
|
||||||
|
s_thread.join();
|
||||||
|
s_thread = std::thread(&UnmapPortThread);
|
||||||
|
s_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_UPNP
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace UPnP
|
||||||
|
{
|
||||||
|
void TryPortmapping(u16 port);
|
||||||
|
void StopPortmapping();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -74,13 +74,12 @@ NetPlayClient::~NetPlayClient()
|
||||||
|
|
||||||
// called from ---GUI--- thread
|
// called from ---GUI--- thread
|
||||||
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog,
|
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog,
|
||||||
const std::string& name, bool traversal,
|
const std::string& name, const NetTraversalConfig& traversal_config)
|
||||||
const std::string& centralServer, u16 centralPort)
|
|
||||||
: m_dialog(dialog), m_player_name(name)
|
: m_dialog(dialog), m_player_name(name)
|
||||||
{
|
{
|
||||||
ClearBuffers();
|
ClearBuffers();
|
||||||
|
|
||||||
if (!traversal)
|
if (!traversal_config.use_traversal)
|
||||||
{
|
{
|
||||||
// Direct Connection
|
// Direct Connection
|
||||||
m_client = enet_host_create(nullptr, 1, 3, 0, 0);
|
m_client = enet_host_create(nullptr, 1, 3, 0, 0);
|
||||||
|
@ -124,7 +123,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EnsureTraversalClient(centralServer, centralPort))
|
if (!EnsureTraversalClient(traversal_config.traversal_host, traversal_config.traversal_port))
|
||||||
return;
|
return;
|
||||||
m_client = g_MainNetHost.get();
|
m_client = g_MainNetHost.get();
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,7 @@ public:
|
||||||
void SendAsync(sf::Packet&& packet);
|
void SendAsync(sf::Packet&& packet);
|
||||||
|
|
||||||
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog,
|
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog,
|
||||||
const std::string& name, bool traversal, const std::string& centralServer,
|
const std::string& name, const NetTraversalConfig& traversal_config);
|
||||||
u16 centralPort);
|
|
||||||
~NetPlayClient();
|
~NetPlayClient();
|
||||||
|
|
||||||
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
|
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
|
||||||
|
|
|
@ -27,6 +27,20 @@ struct NetSettings
|
||||||
ExpansionInterface::TEXIDevices m_EXIDevice[2];
|
ExpansionInterface::TEXIDevices m_EXIDevice[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NetTraversalConfig
|
||||||
|
{
|
||||||
|
NetTraversalConfig() = default;
|
||||||
|
NetTraversalConfig(bool use_traversal_, std::string traversal_host_, u16 traversal_port_)
|
||||||
|
: use_traversal{use_traversal_}, traversal_host{std::move(traversal_host_)},
|
||||||
|
traversal_port{traversal_port_}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_traversal = false;
|
||||||
|
std::string traversal_host;
|
||||||
|
u16 traversal_port = 0;
|
||||||
|
};
|
||||||
|
|
||||||
extern NetSettings g_NetPlaySettings;
|
extern NetSettings g_NetPlaySettings;
|
||||||
extern u64 g_netplay_initial_rtc;
|
extern u64 g_netplay_initial_rtc;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Common/UPnP.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/HW/Sram.h"
|
#include "Core/HW/Sram.h"
|
||||||
#include "Core/NetPlayClient.h" //for NetPlayUI
|
#include "Core/NetPlayClient.h" //for NetPlayUI
|
||||||
|
@ -57,16 +58,13 @@ NetPlayServer::~NetPlayServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
if (m_upnp_thread.joinable())
|
UPnP::StopPortmapping();
|
||||||
m_upnp_thread.join();
|
|
||||||
m_upnp_thread = std::thread(&NetPlayServer::unmapPortThread);
|
|
||||||
m_upnp_thread.join();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---GUI--- thread
|
// called from ---GUI--- thread
|
||||||
NetPlayServer::NetPlayServer(const u16 port, bool traversal, const std::string& centralServer,
|
NetPlayServer::NetPlayServer(const u16 port, const bool forward_port,
|
||||||
u16 centralPort)
|
const NetTraversalConfig& traversal_config)
|
||||||
{
|
{
|
||||||
//--use server time
|
//--use server time
|
||||||
if (enet_initialize() != 0)
|
if (enet_initialize() != 0)
|
||||||
|
@ -77,9 +75,10 @@ NetPlayServer::NetPlayServer(const u16 port, bool traversal, const std::string&
|
||||||
m_pad_map.fill(-1);
|
m_pad_map.fill(-1);
|
||||||
m_wiimote_map.fill(-1);
|
m_wiimote_map.fill(-1);
|
||||||
|
|
||||||
if (traversal)
|
if (traversal_config.use_traversal)
|
||||||
{
|
{
|
||||||
if (!EnsureTraversalClient(centralServer, centralPort, port))
|
if (!EnsureTraversalClient(traversal_config.traversal_host, traversal_config.traversal_port,
|
||||||
|
port))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_TraversalClient->m_Client = this;
|
g_TraversalClient->m_Client = this;
|
||||||
|
@ -105,6 +104,11 @@ NetPlayServer::NetPlayServer(const u16 port, bool traversal, const std::string&
|
||||||
m_do_loop = true;
|
m_do_loop = true;
|
||||||
m_thread = std::thread(&NetPlayServer::ThreadFunc, this);
|
m_thread = std::thread(&NetPlayServer::ThreadFunc, this);
|
||||||
m_target_buffer_size = 5;
|
m_target_buffer_size = 5;
|
||||||
|
|
||||||
|
#ifdef USE_UPNP
|
||||||
|
if (forward_port)
|
||||||
|
UPnP::TryPortmapping(port);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -933,155 +937,3 @@ std::vector<std::pair<std::string, std::string>> NetPlayServer::GetInterfaceList
|
||||||
result.emplace_back(std::make_pair("!local!", "127.0.0.1"));
|
result.emplace_back(std::make_pair("!local!", "127.0.0.1"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
|
||||||
#include <miniupnpc.h>
|
|
||||||
#include <miniwget.h>
|
|
||||||
#include <upnpcommands.h>
|
|
||||||
|
|
||||||
struct UPNPUrls NetPlayServer::m_upnp_urls;
|
|
||||||
struct IGDdatas NetPlayServer::m_upnp_data;
|
|
||||||
std::string NetPlayServer::m_upnp_ourip;
|
|
||||||
u16 NetPlayServer::m_upnp_mapped = 0;
|
|
||||||
std::thread NetPlayServer::m_upnp_thread;
|
|
||||||
|
|
||||||
// called from ---GUI--- thread
|
|
||||||
void NetPlayServer::TryPortmapping(u16 port)
|
|
||||||
{
|
|
||||||
if (m_upnp_thread.joinable())
|
|
||||||
m_upnp_thread.join();
|
|
||||||
m_upnp_thread = std::thread(&NetPlayServer::mapPortThread, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
// UPnP thread: try to map a port
|
|
||||||
void NetPlayServer::mapPortThread(const u16 port)
|
|
||||||
{
|
|
||||||
if (initUPnP() && UPnPMapPort(m_upnp_ourip, port))
|
|
||||||
{
|
|
||||||
NOTICE_LOG(NETPLAY, "Successfully mapped port %d to %s.", port, m_upnp_ourip.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WARN_LOG(NETPLAY, "Failed to map port %d to %s.", port, m_upnp_ourip.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// UPnP thread: try to unmap a port
|
|
||||||
void NetPlayServer::unmapPortThread()
|
|
||||||
{
|
|
||||||
if (m_upnp_mapped > 0)
|
|
||||||
UPnPUnmapPort(m_upnp_mapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// called from ---UPnP--- thread
|
|
||||||
// discovers the IGD
|
|
||||||
bool NetPlayServer::initUPnP()
|
|
||||||
{
|
|
||||||
static bool s_inited = false;
|
|
||||||
static bool s_error = false;
|
|
||||||
|
|
||||||
std::vector<UPNPDev*> igds;
|
|
||||||
int descXMLsize = 0, upnperror = 0;
|
|
||||||
char cIP[20];
|
|
||||||
|
|
||||||
// Don't init if already inited
|
|
||||||
if (s_inited)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Don't init if it failed before
|
|
||||||
if (s_error)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
memset(&m_upnp_urls, 0, sizeof(UPNPUrls));
|
|
||||||
memset(&m_upnp_data, 0, sizeof(IGDdatas));
|
|
||||||
|
|
||||||
// Find all UPnP devices
|
|
||||||
std::unique_ptr<UPNPDev, decltype(&freeUPNPDevlist)> devlist(nullptr, freeUPNPDevlist);
|
|
||||||
#if MINIUPNPC_API_VERSION >= 14
|
|
||||||
devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror));
|
|
||||||
#else
|
|
||||||
devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, &upnperror));
|
|
||||||
#endif
|
|
||||||
if (!devlist)
|
|
||||||
{
|
|
||||||
WARN_LOG(NETPLAY, "An error occurred trying to discover UPnP devices.");
|
|
||||||
|
|
||||||
s_error = true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for the IGD
|
|
||||||
for (UPNPDev* dev = devlist.get(); dev; dev = dev->pNext)
|
|
||||||
{
|
|
||||||
if (strstr(dev->st, "InternetGatewayDevice"))
|
|
||||||
igds.push_back(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const UPNPDev* dev : igds)
|
|
||||||
{
|
|
||||||
std::unique_ptr<char, decltype(&std::free)> descXML(nullptr, std::free);
|
|
||||||
int statusCode = 200;
|
|
||||||
#if MINIUPNPC_API_VERSION >= 16
|
|
||||||
descXML.reset(static_cast<char*>(
|
|
||||||
miniwget_getaddr(dev->descURL, &descXMLsize, cIP, sizeof(cIP), 0, &statusCode)));
|
|
||||||
#else
|
|
||||||
descXML.reset(
|
|
||||||
static_cast<char*>(miniwget_getaddr(dev->descURL, &descXMLsize, cIP, sizeof(cIP), 0)));
|
|
||||||
#endif
|
|
||||||
if (descXML && statusCode == 200)
|
|
||||||
{
|
|
||||||
parserootdesc(descXML.get(), descXMLsize, &m_upnp_data);
|
|
||||||
GetUPNPUrls(&m_upnp_urls, &m_upnp_data, dev->descURL, 0);
|
|
||||||
|
|
||||||
m_upnp_ourip = cIP;
|
|
||||||
|
|
||||||
NOTICE_LOG(NETPLAY, "Got info from IGD at %s.", dev->descURL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WARN_LOG(NETPLAY, "Error getting info from IGD at %s.", dev->descURL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_inited = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// called from ---UPnP--- thread
|
|
||||||
// Attempt to portforward!
|
|
||||||
bool NetPlayServer::UPnPMapPort(const std::string& addr, const u16 port)
|
|
||||||
{
|
|
||||||
if (m_upnp_mapped > 0)
|
|
||||||
UPnPUnmapPort(m_upnp_mapped);
|
|
||||||
|
|
||||||
std::string port_str = StringFromFormat("%d", port);
|
|
||||||
int result = UPNP_AddPortMapping(
|
|
||||||
m_upnp_urls.controlURL, m_upnp_data.first.servicetype, port_str.c_str(), port_str.c_str(),
|
|
||||||
addr.c_str(), (std::string("dolphin-emu UDP on ") + addr).c_str(), "UDP", nullptr, nullptr);
|
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_upnp_mapped = port;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// called from ---UPnP--- thread
|
|
||||||
// Attempt to stop portforwarding.
|
|
||||||
// --
|
|
||||||
// NOTE: It is important that this happens! A few very crappy routers
|
|
||||||
// apparently do not delete UPnP mappings on their own, so if you leave them
|
|
||||||
// hanging, the NVRAM will fill with portmappings, and eventually all UPnP
|
|
||||||
// requests will fail silently, with the only recourse being a factory reset.
|
|
||||||
// --
|
|
||||||
bool NetPlayServer::UPnPUnmapPort(const u16 port)
|
|
||||||
{
|
|
||||||
std::string port_str = StringFromFormat("%d", port);
|
|
||||||
UPNP_DeletePortMapping(m_upnp_urls.controlURL, m_upnp_data.first.servicetype, port_str.c_str(),
|
|
||||||
"UDP", nullptr);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
void ThreadFunc();
|
void ThreadFunc();
|
||||||
void SendAsyncToClients(sf::Packet&& packet);
|
void SendAsyncToClients(sf::Packet&& packet);
|
||||||
|
|
||||||
NetPlayServer(const u16 port, bool traversal, const std::string& centralServer, u16 centralPort);
|
NetPlayServer(u16 port, bool forward_port, const NetTraversalConfig& traversal_config);
|
||||||
~NetPlayServer();
|
~NetPlayServer();
|
||||||
|
|
||||||
bool ChangeGame(const std::string& game);
|
bool ChangeGame(const std::string& game);
|
||||||
|
@ -58,10 +58,6 @@ public:
|
||||||
|
|
||||||
bool is_connected = false;
|
bool is_connected = false;
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
|
||||||
void TryPortmapping(u16 port);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
|
@ -123,19 +119,4 @@ private:
|
||||||
ENetHost* m_server = nullptr;
|
ENetHost* m_server = nullptr;
|
||||||
TraversalClient* m_traversal_client = nullptr;
|
TraversalClient* m_traversal_client = nullptr;
|
||||||
NetPlayUI* m_dialog = nullptr;
|
NetPlayUI* m_dialog = nullptr;
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
|
||||||
static void mapPortThread(const u16 port);
|
|
||||||
static void unmapPortThread();
|
|
||||||
|
|
||||||
static bool initUPnP();
|
|
||||||
static bool UPnPMapPort(const std::string& addr, const u16 port);
|
|
||||||
static bool UPnPUnmapPort(const u16 port);
|
|
||||||
|
|
||||||
static struct UPNPUrls m_upnp_urls;
|
|
||||||
static struct IGDdatas m_upnp_data;
|
|
||||||
static std::string m_upnp_ourip;
|
|
||||||
static u16 m_upnp_mapped;
|
|
||||||
static std::thread m_upnp_thread;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -663,9 +663,8 @@ bool MainWindow::NetPlayJoin()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
std::string host_ip, traversal_host, nickname;
|
std::string host_ip;
|
||||||
int host_port, traversal_port;
|
u16 host_port;
|
||||||
bool is_traversal;
|
|
||||||
if (Settings::Instance().GetNetPlayServer() != nullptr)
|
if (Settings::Instance().GetNetPlayServer() != nullptr)
|
||||||
{
|
{
|
||||||
host_ip = "127.0.0.1";
|
host_ip = "127.0.0.1";
|
||||||
|
@ -677,18 +676,18 @@ bool MainWindow::NetPlayJoin()
|
||||||
host_port = Config::Get(Config::NETPLAY_HOST_PORT);
|
host_port = Config::Get(Config::NETPLAY_HOST_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
const std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
||||||
is_traversal = traversal_choice == "traversal";
|
const bool is_traversal = traversal_choice == "traversal";
|
||||||
|
|
||||||
traversal_host = Config::Get(Config::NETPLAY_TRAVERSAL_SERVER);
|
const std::string traversal_host = Config::Get(Config::NETPLAY_TRAVERSAL_SERVER);
|
||||||
traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
|
const u16 traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
|
||||||
nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
const std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
||||||
|
|
||||||
// Create Client
|
// Create Client
|
||||||
Settings::Instance().ResetNetPlayClient(
|
Settings::Instance().ResetNetPlayClient(new NetPlayClient(
|
||||||
new NetPlayClient(host_ip, host_port, m_netplay_dialog, nickname,
|
host_ip, host_port, m_netplay_dialog, nickname,
|
||||||
Settings::Instance().GetNetPlayServer() != nullptr ? false : is_traversal,
|
NetTraversalConfig{Settings::Instance().GetNetPlayServer() != nullptr ? false : is_traversal,
|
||||||
traversal_host, traversal_port));
|
traversal_host, traversal_port}));
|
||||||
|
|
||||||
if (!Settings::Instance().GetNetPlayClient()->IsConnected())
|
if (!Settings::Instance().GetNetPlayClient()->IsConnected())
|
||||||
{
|
{
|
||||||
|
@ -721,26 +720,21 @@ bool MainWindow::NetPlayHost(const QString& game_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
std::string traversal_host, nickname;
|
u16 host_port = Config::Get(Config::NETPLAY_HOST_PORT);
|
||||||
int host_port, traversal_port;
|
const std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
||||||
bool is_traversal, use_upnp;
|
const bool is_traversal = traversal_choice == "traversal";
|
||||||
|
const bool use_upnp = Config::Get(Config::NETPLAY_USE_UPNP);
|
||||||
|
|
||||||
host_port = Config::Get(Config::NETPLAY_HOST_PORT);
|
const std::string traversal_host = Config::Get(Config::NETPLAY_TRAVERSAL_SERVER);
|
||||||
std::string traversal_choice;
|
const u16 traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
|
||||||
traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
const std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
||||||
is_traversal = traversal_choice == "traversal";
|
|
||||||
use_upnp = Config::Get(Config::NETPLAY_USE_UPNP);
|
|
||||||
|
|
||||||
traversal_host = Config::Get(Config::NETPLAY_TRAVERSAL_SERVER);
|
|
||||||
traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT);
|
|
||||||
nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
|
||||||
|
|
||||||
if (is_traversal)
|
if (is_traversal)
|
||||||
host_port = Config::Get(Config::NETPLAY_LISTEN_PORT);
|
host_port = Config::Get(Config::NETPLAY_LISTEN_PORT);
|
||||||
|
|
||||||
// Create Server
|
// Create Server
|
||||||
Settings::Instance().ResetNetPlayServer(
|
Settings::Instance().ResetNetPlayServer(new NetPlayServer(
|
||||||
new NetPlayServer(host_port, is_traversal, traversal_host, traversal_port));
|
host_port, use_upnp, NetTraversalConfig{is_traversal, traversal_host, traversal_port}));
|
||||||
|
|
||||||
if (!Settings::Instance().GetNetPlayServer()->is_connected)
|
if (!Settings::Instance().GetNetPlayServer()->is_connected)
|
||||||
{
|
{
|
||||||
|
@ -754,11 +748,6 @@ bool MainWindow::NetPlayHost(const QString& game_id)
|
||||||
|
|
||||||
Settings::Instance().GetNetPlayServer()->ChangeGame(game_id.toStdString());
|
Settings::Instance().GetNetPlayServer()->ChangeGame(game_id.toStdString());
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
|
||||||
if (use_upnp)
|
|
||||||
Settings::Instance().GetNetPlayServer()->TryPortmapping(host_port);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Join our local server
|
// Join our local server
|
||||||
return NetPlayJoin();
|
return NetPlayJoin();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,9 @@ bool NetPlayLauncher::Host(const NetPlayHostConfig& config)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
netplay_server = new NetPlayServer(config.listen_port, config.use_traversal,
|
netplay_server = new NetPlayServer(
|
||||||
config.traversal_host, config.traversal_port);
|
config.listen_port, config.forward_port,
|
||||||
|
NetTraversalConfig{config.use_traversal, config.traversal_host, config.traversal_port});
|
||||||
|
|
||||||
if (!netplay_server->is_connected)
|
if (!netplay_server->is_connected)
|
||||||
{
|
{
|
||||||
|
@ -35,19 +36,11 @@ bool NetPlayLauncher::Host(const NetPlayHostConfig& config)
|
||||||
|
|
||||||
netplay_server->ChangeGame(config.game_name);
|
netplay_server->ChangeGame(config.game_name);
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
|
||||||
if (config.forward_port)
|
|
||||||
{
|
|
||||||
netplay_server->TryPortmapping(config.listen_port);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
npd = new NetPlayDialog(config.parent_window, config.game_list_ctrl, config.game_name, true);
|
npd = new NetPlayDialog(config.parent_window, config.game_list_ctrl, config.game_name, true);
|
||||||
|
|
||||||
NetPlayClient*& netplay_client = NetPlayDialog::GetNetPlayClient();
|
NetPlayClient*& netplay_client = NetPlayDialog::GetNetPlayClient();
|
||||||
netplay_client =
|
netplay_client = new NetPlayClient("127.0.0.1", netplay_server->GetPort(), npd,
|
||||||
new NetPlayClient("127.0.0.1", netplay_server->GetPort(), npd, config.player_name, false,
|
config.player_name, NetTraversalConfig{});
|
||||||
config.traversal_host, config.traversal_port);
|
|
||||||
|
|
||||||
if (netplay_client->IsConnected())
|
if (netplay_client->IsConnected())
|
||||||
{
|
{
|
||||||
|
@ -76,9 +69,9 @@ bool NetPlayLauncher::Join(const NetPlayJoinConfig& config)
|
||||||
else
|
else
|
||||||
host = config.connect_host;
|
host = config.connect_host;
|
||||||
|
|
||||||
netplay_client =
|
netplay_client = new NetPlayClient(
|
||||||
new NetPlayClient(host, config.connect_port, npd, config.player_name, config.use_traversal,
|
host, config.connect_port, npd, config.player_name,
|
||||||
config.traversal_host, config.traversal_port);
|
NetTraversalConfig{config.use_traversal, config.traversal_host, config.traversal_port});
|
||||||
if (netplay_client->IsConnected())
|
if (netplay_client->IsConnected())
|
||||||
{
|
{
|
||||||
npd->SetSize(config.window_pos);
|
npd->SetSize(config.window_pos);
|
||||||
|
|
|
@ -34,9 +34,7 @@ public:
|
||||||
|
|
||||||
std::string game_name;
|
std::string game_name;
|
||||||
u16 listen_port = 0;
|
u16 listen_port = 0;
|
||||||
#ifdef USE_UPNP
|
bool forward_port = false;
|
||||||
bool forward_port;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetPlayJoinConfig : public NetPlayLaunchConfig
|
class NetPlayJoinConfig : public NetPlayLaunchConfig
|
||||||
|
|
Loading…
Reference in New Issue