forked from Mirrors/openclonk
win32: Add UPnP port mapping support
parent
687c1f4920
commit
683800c33c
|
@ -1,7 +1,7 @@
|
||||||
# OpenClonk, http://www.openclonk.org
|
# OpenClonk, http://www.openclonk.org
|
||||||
#
|
#
|
||||||
# Copyright (c) 2009-2011 Günther Brammer
|
# Copyright (c) 2009-2011 Günther Brammer
|
||||||
# Copyright (c) 2009-2011 Nicolas Hake
|
# Copyright (c) 2009-2012 Nicolas Hake
|
||||||
# Copyright (c) 2009 David Dormagen
|
# Copyright (c) 2009 David Dormagen
|
||||||
# Copyright (c) 2009-2011 Armin Burgmeier
|
# Copyright (c) 2009-2011 Armin Burgmeier
|
||||||
# Copyright (c) 2009-2010 Sven Eberhardt
|
# Copyright (c) 2009-2010 Sven Eberhardt
|
||||||
|
@ -465,6 +465,7 @@ set(OC_CLONK_SOURCES
|
||||||
src/network/C4Network2Res.h
|
src/network/C4Network2Res.h
|
||||||
src/network/C4Network2Stats.cpp
|
src/network/C4Network2Stats.cpp
|
||||||
src/network/C4Network2Stats.h
|
src/network/C4Network2Stats.h
|
||||||
|
src/network/C4Network2UPnP.h
|
||||||
src/network/C4Packet2.cpp
|
src/network/C4Packet2.cpp
|
||||||
src/network/C4PacketBase.h
|
src/network/C4PacketBase.h
|
||||||
src/platform/Bitmap256.cpp
|
src/platform/Bitmap256.cpp
|
||||||
|
@ -712,7 +713,7 @@ if(USE_CONSOLE)
|
||||||
CHECK_INCLUDE_FILE_CXX(readline.h HAVE_READLINE_H)
|
CHECK_INCLUDE_FILE_CXX(readline.h HAVE_READLINE_H)
|
||||||
CHECK_INCLUDE_FILE_CXX(readline/readline.h HAVE_READLINE_READLINE_H)
|
CHECK_INCLUDE_FILE_CXX(readline/readline.h HAVE_READLINE_READLINE_H)
|
||||||
endif()
|
endif()
|
||||||
|
CHECK_INCLUDE_FILE_CXX(natupnp.h HAVE_NATUPNP_H)
|
||||||
|
|
||||||
# ck 09-09-20: The following headers require Xlib.h for things such as
|
# ck 09-09-20: The following headers require Xlib.h for things such as
|
||||||
# 'Bool' and 'Window' to be defined. Unfortunately, this doesn't exist
|
# 'Bool' and 'Window' to be defined. Unfortunately, this doesn't exist
|
||||||
|
@ -741,6 +742,16 @@ if(HAVE_ICONV)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(HAVE_NATUPNP_H)
|
||||||
|
list(APPEND OC_SYSTEM_SOURCES
|
||||||
|
src/network/C4Network2UPnPWin32.cpp
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
list(APPEND OC_SYSTEM_SOURCES
|
||||||
|
src/network/C4Network2UPnPDummy.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
# Locate necessary libraries
|
# Locate necessary libraries
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include <C4Game.h>
|
#include <C4Game.h>
|
||||||
#include <C4GameControl.h>
|
#include <C4GameControl.h>
|
||||||
|
|
||||||
|
#include "network/C4Network2Upnp.h"
|
||||||
|
|
||||||
#ifndef HAVE_WINSOCK
|
#ifndef HAVE_WINSOCK
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
@ -51,6 +53,7 @@ struct C4Network2IO::NetEvPacketData
|
||||||
C4Network2IO::C4Network2IO()
|
C4Network2IO::C4Network2IO()
|
||||||
: pNetIO_TCP(NULL), pNetIO_UDP(NULL),
|
: pNetIO_TCP(NULL), pNetIO_UDP(NULL),
|
||||||
pNetIODiscover(NULL), pRefServer(NULL),
|
pNetIODiscover(NULL), pRefServer(NULL),
|
||||||
|
UPnPMgr(NULL),
|
||||||
pConnList(NULL),
|
pConnList(NULL),
|
||||||
iNextConnID(0),
|
iNextConnID(0),
|
||||||
fAllowConnect(false),
|
fAllowConnect(false),
|
||||||
|
@ -84,6 +87,13 @@ bool C4Network2IO::Init(int16_t iPortTCP, int16_t iPortUDP, int16_t iPortDiscove
|
||||||
Thread.SetCallback(Ev_Net_Disconn, this);
|
Thread.SetCallback(Ev_Net_Disconn, this);
|
||||||
Thread.SetCallback(Ev_Net_Packet, this);
|
Thread.SetCallback(Ev_Net_Packet, this);
|
||||||
|
|
||||||
|
// initialize UPnP manager
|
||||||
|
if (iPortTCP > 0 || iPortUDP > 0)
|
||||||
|
{
|
||||||
|
assert(!UPnPMgr);
|
||||||
|
UPnPMgr = new C4Network2UPnP;
|
||||||
|
}
|
||||||
|
|
||||||
// initialize net i/o classes: TCP first
|
// initialize net i/o classes: TCP first
|
||||||
if (iPortTCP > 0)
|
if (iPortTCP > 0)
|
||||||
{
|
{
|
||||||
|
@ -103,6 +113,7 @@ bool C4Network2IO::Init(int16_t iPortTCP, int16_t iPortUDP, int16_t iPortDiscove
|
||||||
{
|
{
|
||||||
Thread.AddProc(pNetIO_TCP);
|
Thread.AddProc(pNetIO_TCP);
|
||||||
pNetIO_TCP->SetCallback(this);
|
pNetIO_TCP->SetCallback(this);
|
||||||
|
UPnPMgr->AddMapping(P_TCP, iPortTCP, iPortTCP);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -138,8 +149,8 @@ bool C4Network2IO::Init(int16_t iPortTCP, int16_t iPortUDP, int16_t iPortDiscove
|
||||||
{
|
{
|
||||||
Thread.AddProc(pNetIO_UDP);
|
Thread.AddProc(pNetIO_UDP);
|
||||||
pNetIO_UDP->SetCallback(this);
|
pNetIO_UDP->SetCallback(this);
|
||||||
|
UPnPMgr->AddMapping(P_UDP, iPortUDP, iPortUDP);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no protocols?
|
// no protocols?
|
||||||
|
@ -224,6 +235,7 @@ void C4Network2IO::Clear() // by main thread
|
||||||
if (pNetIO_TCP) { Thread.RemoveProc(pNetIO_TCP); delete pNetIO_TCP; pNetIO_TCP = NULL; }
|
if (pNetIO_TCP) { Thread.RemoveProc(pNetIO_TCP); delete pNetIO_TCP; pNetIO_TCP = NULL; }
|
||||||
if (pNetIO_UDP) { Thread.RemoveProc(pNetIO_UDP); delete pNetIO_UDP; pNetIO_UDP = NULL; }
|
if (pNetIO_UDP) { Thread.RemoveProc(pNetIO_UDP); delete pNetIO_UDP; pNetIO_UDP = NULL; }
|
||||||
if (pRefServer) { Thread.RemoveProc(pRefServer); delete pRefServer; pRefServer = NULL; }
|
if (pRefServer) { Thread.RemoveProc(pRefServer); delete pRefServer; pRefServer = NULL; }
|
||||||
|
delete UPnPMgr; UPnPMgr = NULL;
|
||||||
// remove auto-accepts
|
// remove auto-accepts
|
||||||
ClearAutoAccept();
|
ClearAutoAccept();
|
||||||
// reset flags
|
// reset flags
|
||||||
|
|
|
@ -59,6 +59,9 @@ protected:
|
||||||
// reference server
|
// reference server
|
||||||
class C4Network2RefServer *pRefServer;
|
class C4Network2RefServer *pRefServer;
|
||||||
|
|
||||||
|
// UPnP port mapping manager
|
||||||
|
class C4Network2UPnP *UPnPMgr;
|
||||||
|
|
||||||
// local client core
|
// local client core
|
||||||
C4ClientCore LCCore;
|
C4ClientCore LCCore;
|
||||||
CStdCSec LCCoreCSec;
|
CStdCSec LCCoreCSec;
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Nicolas Hake
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
/* Interface to a UPnP port mapper */
|
||||||
|
|
||||||
|
#ifndef INC_C4Network2Upnp
|
||||||
|
#define INC_C4Network2Upnp
|
||||||
|
|
||||||
|
#include "platform/StdScheduler.h"
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
class C4Network2UPnP : boost::noncopyable
|
||||||
|
{
|
||||||
|
struct C4Network2UPnPP *p;
|
||||||
|
public:
|
||||||
|
C4Network2UPnP();
|
||||||
|
~C4Network2UPnP();
|
||||||
|
|
||||||
|
void AddMapping(enum C4Network2IOProtocol protocol, uint16_t intport, uint16_t extport);
|
||||||
|
void ClearMappings();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Nicolas Hake
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
/* Dummy implementation of a UPnP port mapper; does nothing */
|
||||||
|
|
||||||
|
#include "C4Include.h"
|
||||||
|
#include "network/C4Network2UPnP.h"
|
||||||
|
|
||||||
|
C4Network2UPnP::C4Network2UPnP() {}
|
||||||
|
C4Network2UPnP::~C4Network2UPnP() {}
|
||||||
|
void C4Network2UPnP::AddMapping(C4Network2IOProtocol, uint16_t, uint16_t) {}
|
||||||
|
void C4Network2UPnP::ClearMappings() {}
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* OpenClonk, http://www.openclonk.org
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Nicolas Hake
|
||||||
|
*
|
||||||
|
* Portions might be copyrighted by other authors who have contributed
|
||||||
|
* to OpenClonk.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
* See isc_license.txt for full license and disclaimer.
|
||||||
|
*
|
||||||
|
* "Clonk" is a registered trademark of Matthes Bender.
|
||||||
|
* See clonk_trademark_license.txt for full license.
|
||||||
|
*/
|
||||||
|
/* Win32 implementation of a UPnP port mapper */
|
||||||
|
|
||||||
|
#include "C4Include.h"
|
||||||
|
#include "platform/C4windowswrapper.h"
|
||||||
|
#include "network/C4Network2IO.h"
|
||||||
|
#include "network/C4Network2UPnP.h"
|
||||||
|
#include "C4Version.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <natupnp.h>
|
||||||
|
#include <upnp.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static BSTR PROTO_UDP = ::SysAllocString(L"UDP");
|
||||||
|
static BSTR PROTO_TCP = ::SysAllocString(L"TCP");
|
||||||
|
|
||||||
|
template<class T> inline void SafeRelease(T* &t)
|
||||||
|
{
|
||||||
|
if (t) t->Release();
|
||||||
|
t = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C4Network2UPnPP
|
||||||
|
{
|
||||||
|
bool MustReleaseCOM;
|
||||||
|
|
||||||
|
// NAT
|
||||||
|
IStaticPortMappingCollection *mappings;
|
||||||
|
std::set<IStaticPortMapping*> added_mappings;
|
||||||
|
|
||||||
|
C4Network2UPnPP()
|
||||||
|
: MustReleaseCOM(false),
|
||||||
|
mappings(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void AddMapping(C4Network2IOProtocol protocol, uint16_t intport, uint16_t extport);
|
||||||
|
void RemoveMapping(C4Network2IOProtocol protocol, uint16_t extport);
|
||||||
|
void ClearNatMappings();
|
||||||
|
};
|
||||||
|
|
||||||
|
C4Network2UPnP::C4Network2UPnP()
|
||||||
|
: p(new C4Network2UPnPP)
|
||||||
|
{
|
||||||
|
// Make sure COM is available
|
||||||
|
if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED)))
|
||||||
|
{
|
||||||
|
// Didn't work, don't do UPnP then
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p->MustReleaseCOM = true;
|
||||||
|
|
||||||
|
// Get the NAT service
|
||||||
|
IUPnPNAT *nat = NULL;
|
||||||
|
if (FAILED(CoCreateInstance(CLSID_UPnPNAT, NULL, CLSCTX_INPROC_SERVER, IID_IUPnPNAT, reinterpret_cast<void**>(&nat))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Fetch NAT mappings
|
||||||
|
for (int ctr = 0; ctr < 10; ++ctr)
|
||||||
|
{
|
||||||
|
// Usually it doesn't work on the first try, give Windows some time to query the IGD
|
||||||
|
if (SUCCEEDED(nat->get_StaticPortMappingCollection(&p->mappings)) && p->mappings)
|
||||||
|
{
|
||||||
|
LogF("UPnP: Got NAT port mapping table after %d tries", ctr+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeRelease(nat);
|
||||||
|
}
|
||||||
|
|
||||||
|
C4Network2UPnP::~C4Network2UPnP()
|
||||||
|
{
|
||||||
|
p->ClearNatMappings();
|
||||||
|
if (p->MustReleaseCOM)
|
||||||
|
{
|
||||||
|
// Decrement COM reference count
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
delete p; p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4Network2UPnP::AddMapping(C4Network2IOProtocol protocol, uint16_t intport, uint16_t extport)
|
||||||
|
{
|
||||||
|
p->AddMapping(protocol, intport, extport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4Network2UPnP::ClearMappings()
|
||||||
|
{
|
||||||
|
p->ClearNatMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4Network2UPnPP::ClearNatMappings()
|
||||||
|
{
|
||||||
|
if (!mappings)
|
||||||
|
return;
|
||||||
|
BOOST_FOREACH(IStaticPortMapping *mapping, added_mappings)
|
||||||
|
{
|
||||||
|
BSTR proto, client;
|
||||||
|
long intport, extport;
|
||||||
|
mapping->get_ExternalPort(&extport);
|
||||||
|
mapping->get_InternalPort(&intport);
|
||||||
|
mapping->get_InternalClient(&client);
|
||||||
|
mapping->get_Protocol(&proto);
|
||||||
|
if (SUCCEEDED(mappings->Remove(extport, proto)))
|
||||||
|
LogF("UPnP: Closed port %d->%s:%d (%s)", extport, StdStrBuf(client).getData(), intport, StdStrBuf(proto).getData());
|
||||||
|
::SysFreeString(proto);
|
||||||
|
::SysFreeString(client);
|
||||||
|
SafeRelease(mapping);
|
||||||
|
}
|
||||||
|
SafeRelease(mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void C4Network2UPnPP::AddMapping(C4Network2IOProtocol protocol, uint16_t intport, uint16_t extport)
|
||||||
|
{
|
||||||
|
if (mappings)
|
||||||
|
{
|
||||||
|
// Get (one of the) local host address(es)
|
||||||
|
char hostname[MAX_PATH];
|
||||||
|
hostent *host;
|
||||||
|
if (gethostname(hostname, MAX_PATH) == 0 && (host = gethostbyname(hostname)) != NULL)
|
||||||
|
{
|
||||||
|
in_addr addr;
|
||||||
|
addr.s_addr = *(ULONG*)host->h_addr_list[0];
|
||||||
|
|
||||||
|
BSTR description = ::SysAllocString(ADDL(C4ENGINECAPTION));
|
||||||
|
BSTR client = ::SysAllocString(GetWideChar(inet_ntoa(addr)));
|
||||||
|
IStaticPortMapping *mapping = NULL;
|
||||||
|
if (SUCCEEDED(mappings->Add(extport, protocol == P_TCP ? PROTO_TCP : PROTO_UDP, intport, client, VARIANT_TRUE, description, &mapping)))
|
||||||
|
{
|
||||||
|
LogF("UPnP: Successfully opened port %d->%s:%d (%s)", extport, StdStrBuf(client).getData(), intport, protocol == P_TCP ? "TCP" : "UDP");
|
||||||
|
added_mappings.insert(mapping);
|
||||||
|
}
|
||||||
|
::SysFreeString(description);
|
||||||
|
::SysFreeString(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef INC_C4windowswrapper
|
#ifndef INC_C4windowswrapper
|
||||||
#define INC_C4windowswrapper
|
#define INC_C4windowswrapper
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define NOMINMAX
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#undef RGB
|
#undef RGB
|
||||||
#undef GetRValue
|
#undef GetRValue
|
||||||
|
|
Loading…
Reference in New Issue