20 #include "C4Version.h"
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
25 #pragma GCC diagnostic ignored "-Wredundant-decls"
26 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
30 #pragma GCC diagnostic pop
33 #if defined(__MINGW32__) || defined(__MINGW64__)
35 extern "C" const CLSID CLSID_UPnPNAT = { 0xAE1E00AA, 0x3FD5, 0x403C, { 0x8A, 0x27, 0x2B, 0xBD, 0xC3, 0x0C, 0xD0, 0xE1 } };
36 extern "C" const IID IID_IUPnPNAT = { 0xB171C812, 0xCC76, 0x485A, { 0x94, 0xD8, 0xB6, 0xB3, 0xA2, 0x79, 0x4E, 0x99 } };
41 static BSTR PROTO_UDP = ::SysAllocString(L
"UDP");
42 static BSTR PROTO_TCP = ::SysAllocString(L
"TCP");
44 template<
class T>
inline void SafeRelease(T* &t)
57 IStaticPortMappingCollection *
mappings{
nullptr};
72 if (FAILED(CoInitializeEx(
nullptr, COINIT_APARTMENTTHREADED)))
75 Log(
"UPnP fail (no COM).");
78 p->MustReleaseCOM =
true;
81 IUPnPNAT *nat =
nullptr;
82 if (FAILED(CoCreateInstance(CLSID_UPnPNAT,
nullptr, CLSCTX_INPROC_SERVER, IID_IUPnPNAT,
reinterpret_cast<void**
>(&nat))))
84 Log(
"UPnP fail (no service).");
89 for (
int ctr = 0; ctr < 10; ++ctr)
92 if (SUCCEEDED(nat->get_StaticPortMappingCollection(&p->mappings)) && p->mappings)
94 LogF(
"UPnP: Got NAT port mapping table after %d tries", ctr+1);
103 if (!p->mappings)
Log(
"UPnP fail (no mapping).");
114 delete p; p =
nullptr;
131 for(IStaticPortMapping *mapping: added_mappings)
134 long intport, extport;
135 mapping->get_ExternalPort(&extport);
136 mapping->get_InternalPort(&intport);
137 mapping->get_InternalClient(&client);
138 mapping->get_Protocol(&proto);
139 if (SUCCEEDED(
mappings->Remove(extport, proto)))
140 LogF(
"UPnP: Closed port %d->%s:%d (%s)", (
int)extport,
StdStrBuf(client).getData(), (
int)intport,
StdStrBuf(proto).getData());
141 ::SysFreeString(proto);
142 ::SysFreeString(client);
143 SafeRelease(mapping);
153 char hostname[MAX_PATH];
155 if (gethostname(hostname, MAX_PATH) == 0 && (host = gethostbyname(hostname)) !=
nullptr)
158 addr.s_addr = *(ULONG*)host->h_addr_list[0];
160 BSTR description = ::SysAllocString(
ADDL(C4ENGINECAPTION));
161 BSTR client = ::SysAllocString(
GetWideChar(inet_ntoa(addr)));
162 IStaticPortMapping *mapping =
nullptr;
163 if (SUCCEEDED(
mappings->Add(extport, protocol ==
P_TCP ? PROTO_TCP : PROTO_UDP, intport, client, VARIANT_TRUE, description, &mapping)))
165 LogF(
"UPnP: Successfully opened port %d->%s:%d (%s)", extport,
StdStrBuf(client).getData(), intport, protocol ==
P_TCP ?
"TCP" :
"UDP");
166 added_mappings.insert(mapping);
168 ::SysFreeString(description);
169 ::SysFreeString(client);
const char * LoadResStr(const char *id)
bool Log(const char *szMessage)
bool LogF(const char *strMessage,...)
StdStrBuf::wchar_t_holder GetWideChar(const char *utf8, bool double_null_terminate=false)
void AddMapping(enum C4Network2IOProtocol protocol, uint16_t intport, uint16_t extport)
void AddMapping(C4Network2IOProtocol protocol, uint16_t intport, uint16_t extport)
IStaticPortMappingCollection * mappings
std::set< IStaticPortMapping * > added_mappings
C4Network2UPnPP()=default
void RemoveMapping(C4Network2IOProtocol protocol, uint16_t extport)