mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Merge pull request #5898 from ligfx/extractupnp
Common: extract UPnP namespace from NetPlayServer
This commit is contained in:
@ -6,6 +6,9 @@ set(SRCS
|
||||
Config/Config.cpp
|
||||
Config/Layer.cpp
|
||||
Config/Section.cpp
|
||||
Crypto/AES.cpp
|
||||
Crypto/bn.cpp
|
||||
Crypto/ec.cpp
|
||||
ENetUtil.cpp
|
||||
File.cpp
|
||||
FileSearch.cpp
|
||||
@ -15,7 +18,9 @@ set(SRCS
|
||||
HttpRequest.cpp
|
||||
IniFile.cpp
|
||||
JitRegister.cpp
|
||||
Logging/LogManager.cpp
|
||||
MathUtil.cpp
|
||||
MD5.cpp
|
||||
MemArena.cpp
|
||||
MemoryUtil.cpp
|
||||
MsgHandler.cpp
|
||||
@ -32,14 +37,10 @@ set(SRCS
|
||||
Thread.cpp
|
||||
Timer.cpp
|
||||
TraversalClient.cpp
|
||||
UPnP.cpp
|
||||
Version.cpp
|
||||
x64ABI.cpp
|
||||
x64Emitter.cpp
|
||||
MD5.cpp
|
||||
Crypto/AES.cpp
|
||||
Crypto/bn.cpp
|
||||
Crypto/ec.cpp
|
||||
Logging/LogManager.cpp
|
||||
)
|
||||
|
||||
set(LIBS ${LIBS} ${MBEDTLS_LIBRARIES})
|
||||
|
@ -151,6 +151,7 @@
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="TraversalClient.h" />
|
||||
<ClInclude Include="TraversalProto.h" />
|
||||
<ClInclude Include="UPnP.h" />
|
||||
<ClInclude Include="x64ABI.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
<ClInclude Include="x64Reg.h" />
|
||||
@ -202,6 +203,7 @@
|
||||
<ClCompile Include="Thread.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="TraversalClient.cpp" />
|
||||
<ClCompile Include="UPnP.cpp" />
|
||||
<ClCompile Include="Version.cpp" />
|
||||
<ClCompile Include="x64ABI.cpp" />
|
||||
<ClCompile Include="x64CPUDetect.cpp" />
|
||||
|
@ -94,6 +94,7 @@
|
||||
<ClInclude Include="JitRegister.h" />
|
||||
<ClInclude Include="TraversalClient.h" />
|
||||
<ClInclude Include="TraversalProto.h" />
|
||||
<ClInclude Include="UPnP.h" />
|
||||
<ClInclude Include="GL\GLUtil.h">
|
||||
<Filter>GL</Filter>
|
||||
</ClInclude>
|
||||
@ -307,6 +308,7 @@
|
||||
<ClCompile Include="GekkoDisassembler.cpp" />
|
||||
<ClCompile Include="JitRegister.cpp" />
|
||||
<ClCompile Include="TraversalClient.cpp" />
|
||||
<ClCompile Include="UPnP.cpp" />
|
||||
<ClCompile Include="Logging\ConsoleListenerWin.cpp">
|
||||
<Filter>Logging</Filter>
|
||||
</ClCompile>
|
||||
|
169
Source/Core/Common/UPnP.cpp
Normal file
169
Source/Core/Common/UPnP.cpp
Normal file
@ -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
|
17
Source/Core/Common/UPnP.h
Normal file
17
Source/Core/Common/UPnP.h
Normal file
@ -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
|
Reference in New Issue
Block a user