Skip to content

Commit

Permalink
Merge pull request #5898 from ligfx/extractupnp
Browse files Browse the repository at this point in the history
Common: extract UPnP namespace from NetPlayServer
  • Loading branch information
leoetlino committed Aug 16, 2017
2 parents 70931f4 + 8702ffc commit a53b013
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 240 deletions.
11 changes: 6 additions & 5 deletions Source/Core/Common/CMakeLists.txt
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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})
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Common/Common.vcxproj
Expand Up @@ -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" />
Expand Down Expand Up @@ -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" />
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Common/Common.vcxproj.filters
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down
169 changes: 169 additions & 0 deletions Source/Core/Common/UPnP.cpp
@@ -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 changes: 17 additions & 0 deletions Source/Core/Common/UPnP.h
@@ -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
7 changes: 3 additions & 4 deletions Source/Core/Core/NetPlayClient.cpp
Expand Up @@ -74,13 +74,12 @@ NetPlayClient::~NetPlayClient()

// called from ---GUI--- thread
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog,
const std::string& name, bool traversal,
const std::string& centralServer, u16 centralPort)
const std::string& name, const NetTraversalConfig& traversal_config)
: m_dialog(dialog), m_player_name(name)
{
ClearBuffers();

if (!traversal)
if (!traversal_config.use_traversal)
{
// Direct Connection
m_client = enet_host_create(nullptr, 1, 3, 0, 0);
Expand Down Expand Up @@ -124,7 +123,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
return;
}

if (!EnsureTraversalClient(centralServer, centralPort))
if (!EnsureTraversalClient(traversal_config.traversal_host, traversal_config.traversal_port))
return;
m_client = g_MainNetHost.get();

Expand Down
3 changes: 1 addition & 2 deletions Source/Core/Core/NetPlayClient.h
Expand Up @@ -67,8 +67,7 @@ class NetPlayClient : public TraversalClientClient
void SendAsync(sf::Packet&& packet);

NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog,
const std::string& name, bool traversal, const std::string& centralServer,
u16 centralPort);
const std::string& name, const NetTraversalConfig& traversal_config);
~NetPlayClient();

void GetPlayerList(std::string& list, std::vector<int>& pid_list);
Expand Down
14 changes: 14 additions & 0 deletions Source/Core/Core/NetPlayProto.h
Expand Up @@ -27,6 +27,20 @@ struct NetSettings
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 u64 g_netplay_initial_rtc;

Expand Down

0 comments on commit a53b013

Please sign in to comment.