Added UPnP port forwarding support

This commit is contained in:
Souryo 2014-07-07 18:43:50 -04:00
parent 6b00a1f5c8
commit 0fd2fb23c5
4 changed files with 145 additions and 4 deletions

View File

@ -1,6 +1,7 @@
#pragma once
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#include "stdafx.h"
#include "UPnPPortMapper.h"
#include <winsock2.h>
class Socket
@ -11,6 +12,7 @@ private:
bool _cleanupWSA = false;
char* _sendBuffer;
int _bufferPosition;
int32_t _UPnPPort = -1;
public:
Socket()
@ -51,6 +53,10 @@ public:
~Socket()
{
if(_UPnPPort != -1) {
UPnPPortMapper::RemoveNATPortMapping(_UPnPPort, IPProtocol::TCP);
}
if(_socket != INVALID_SOCKET) {
Close();
}
@ -84,7 +90,7 @@ public:
void Close()
{
std::cout << "Client disconnected!\r\n";
std::cout << "Socket closed." << std::endl;
shutdown(_socket, SD_SEND);
closesocket(_socket);
SetConnectionErrorFlag();
@ -102,6 +108,10 @@ public:
serverInf.sin_addr.s_addr = INADDR_ANY;
serverInf.sin_port = htons(port);
if(UPnPPortMapper::AddNATPortMapping(port, port, IPProtocol::TCP)) {
_UPnPPort = port;
}
if(bind(_socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR) {
std::cout << "Unable to bind socket." << std::endl;
SetConnectionErrorFlag();
@ -193,7 +203,6 @@ public:
int Recv(char *buf, int len, int flags)
{
static ofstream received("received.log", ios::out | ios::binary);
int returnVal = recv(_socket, buf, len, flags);
int nError = WSAGetLastError();

132
Utilities/UPnPPortMapper.h Normal file
View File

@ -0,0 +1,132 @@
#pragma once
#include "stdafx.h"
#include <natupnp.h>
#include <ws2tcpip.h>
enum class IPProtocol
{
TCP = 0,
UDP = 1
};
class UPnPPortMapper
{
public:
static bool AddNATPortMapping(WORD internalPort, WORD externalPort, IPProtocol protocol)
{
bool result = false;
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
IUPnPNAT *nat = nullptr;
HRESULT hResult = CoCreateInstance(__uuidof(UPnPNAT), nullptr, CLSCTX_ALL, __uuidof(IUPnPNAT), (void**)&nat);
BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP");
if(SUCCEEDED(hResult) && nat) {
IStaticPortMappingCollection *spmc = nullptr;
hResult = nat->get_StaticPortMappingCollection(&spmc);
if(SUCCEEDED(hResult) && spmc) {
IStaticPortMapping *spm = nullptr;
hResult = spmc->get_Item(externalPort, proto, &spm);
if(spm != nullptr) {
//An identical mapping already exists, remove it
if(RemoveNATPortMapping(externalPort, protocol)) {
std::cout << "Removed existing UPnP mapping." << std::endl;
spm->Release();
spm = nullptr;
}
}
if(!SUCCEEDED(hResult) || spm == nullptr) {
std::cout << "Attempting to automatically forward port via UPnP..." << std::endl;
wstring localIP = GetLocalIP();
BSTR desc = SysAllocString(L"NESEmu for NetPlay");
BSTR clientStr = SysAllocString(localIP.c_str());
hResult = spmc->Add(externalPort, proto, internalPort, clientStr, true, desc, &spm);
SysFreeString(clientStr);
SysFreeString(desc);
if(SUCCEEDED(hResult) && spm) {
//Successfully added a new port mapping
std::cout << std::dec << "Forwarded port " << externalPort << " to IP ";
std::wcout << localIP.c_str() << std::endl;
spm->Release();
result = true;
}
spmc->Release();
} else {
std::cout << "Unable to add UPnP port mapping." << std::endl;
}
}
nat->Release();
}
SysFreeString(proto);
CoUninitialize();
return result;
}
static bool RemoveNATPortMapping(WORD externalPort, IPProtocol protocol)
{
IUPnPNAT *nat = nullptr;
IStaticPortMappingCollection *spmc;
bool result = false;
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
HRESULT hResult = ::CoCreateInstance(__uuidof(UPnPNAT), nullptr, CLSCTX_ALL, __uuidof(IUPnPNAT), (void**)&nat);
BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP");
if(SUCCEEDED(hResult) && nat) {
hResult = nat->get_StaticPortMappingCollection(&spmc);
if(SUCCEEDED(hResult) && spmc) {
spmc->Remove(externalPort, proto);
spmc->Release();
result = true;
}
nat->Release();
}
SysFreeString(proto);
CoUninitialize();
return result;
}
static wstring GetLocalIP()
{
wstring localIP;
ADDRINFOW *result = nullptr;
ADDRINFOW hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
wchar_t hostName[255];
DWORD hostSize = 255;
GetComputerName(hostName, &hostSize);
if(GetAddrInfoW(hostName, nullptr, &hints, &result) == 0) {
wchar_t ipAddr[255];
DWORD ipSize = 255;
if(WSAAddressToString(result->ai_addr, result->ai_addrlen, nullptr, ipAddr, &ipSize) == 0) {
localIP = ipAddr;
}
FreeAddrInfoW(result);
}
return localIP;
}
};

View File

@ -73,7 +73,7 @@
<ItemGroup>
<ClInclude Include="ConfigManager.h" />
<ClInclude Include="FolderUtilities.h" />
<ClInclude Include="NATPortMapper.h" />
<ClInclude Include="UPnPPortMapper.h" />
<ClInclude Include="SimpleLock.h" />
<ClInclude Include="Socket.h" />
<ClInclude Include="stdafx.h" />

View File

@ -48,7 +48,7 @@
<ClInclude Include="SimpleLock.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NATPortMapper.h">
<ClInclude Include="UPnPPortMapper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>