271 lines
8.3 KiB
C++
271 lines
8.3 KiB
C++
|
// UPnPNAT.cpp : Implementation of CUPnPNAT
|
||
|
#include "stdafx.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "UPnPNAT.h"
|
||
|
#include "NATEM.h"
|
||
|
#include "dprtmapc.h"
|
||
|
#include "sprtmapc.h"
|
||
|
|
||
|
DEFINE_GUID(CLSID_CInternetGatewayFinder,
|
||
|
0x4d3f9715, 0x73da, 0x4506, 0x89, 0x33, 0x1e, 0xe, 0x17, 0x18, 0xba, 0x3b);
|
||
|
|
||
|
void __cdecl nat_trans_func (unsigned int uSECode, EXCEPTION_POINTERS* pExp)
|
||
|
{
|
||
|
throw NAT_SEH_Exception (uSECode);
|
||
|
}
|
||
|
void EnableNATExceptionHandling()
|
||
|
{
|
||
|
_set_se_translator (nat_trans_func);
|
||
|
}
|
||
|
void DisableNATExceptionHandling()
|
||
|
{
|
||
|
_set_se_translator (NULL);
|
||
|
}
|
||
|
|
||
|
HRESULT GetServiceFromINetConnection (IUnknown * pUnk, IUPnPService ** ppUPS)
|
||
|
{
|
||
|
CComPtr<INetConnection> spNC = NULL;
|
||
|
HRESULT hr = pUnk->QueryInterface (__uuidof(INetConnection), (void**)&spNC);
|
||
|
if (!spNC)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
SAHOST_SERVICES sas;
|
||
|
|
||
|
// make sure we have either
|
||
|
// NCM_SHAREDACCESSHOST_LAN or NCM_SHAREDACCESSHOST_RAS
|
||
|
switch (GetMediaType (spNC)) {
|
||
|
case NCM_SHAREDACCESSHOST_LAN:
|
||
|
sas = SAHOST_SERVICE_WANIPCONNECTION;
|
||
|
break;
|
||
|
case NCM_SHAREDACCESSHOST_RAS:
|
||
|
sas = SAHOST_SERVICE_WANPPPCONNECTION;
|
||
|
break;
|
||
|
default:
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
CComPtr<INetSharedAccessConnection> spNSAC = NULL;
|
||
|
hr = pUnk->QueryInterface (__uuidof(INetSharedAccessConnection), (void**)&spNSAC);
|
||
|
if (spNSAC)
|
||
|
hr = spNSAC->GetService (sas, ppUPS);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT GetServiceFromFinder (IInternetGatewayFinder * pIGF, IUPnPService ** ppUPS)
|
||
|
{
|
||
|
CComPtr<IInternetGateway> spIG = NULL;
|
||
|
HRESULT hr = pIGF->GetInternetGateway (NULL, &spIG); // NULL gets default.
|
||
|
if (spIG) {
|
||
|
NETCON_MEDIATYPE MediaType = NCM_NONE;
|
||
|
hr = spIG->GetMediaType (&MediaType);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
switch (MediaType) {
|
||
|
case NCM_SHAREDACCESSHOST_LAN:
|
||
|
hr = spIG->GetService (SAHOST_SERVICE_WANIPCONNECTION, ppUPS);
|
||
|
break;
|
||
|
case NCM_SHAREDACCESSHOST_RAS:
|
||
|
hr = spIG->GetService (SAHOST_SERVICE_WANPPPCONNECTION, ppUPS);
|
||
|
break;
|
||
|
default:
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT GetService (IUPnPService ** ppUPS)
|
||
|
{
|
||
|
if (!ppUPS)
|
||
|
return E_POINTER;
|
||
|
*ppUPS = NULL;
|
||
|
|
||
|
// either enum all netconnections, or
|
||
|
// for downlevel, use Ken's object
|
||
|
|
||
|
CComPtr<INetConnectionManager> spNCM = NULL;
|
||
|
HRESULT hr = ::CoCreateInstance (CLSID_ConnectionManager,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
__uuidof(INetConnectionManager),
|
||
|
(void**)&spNCM);
|
||
|
if (spNCM) {
|
||
|
CComPtr<IUnknown> spUnk = NULL;
|
||
|
CComPtr<IEnumNetConnection> spENC = NULL;
|
||
|
hr = spNCM->EnumConnections (NCME_DEFAULT, &spENC);
|
||
|
if (spENC) {
|
||
|
ULONG ul = 0;
|
||
|
CComPtr<INetConnection> spNC = NULL;
|
||
|
while (S_OK == spENC->Next (1, &spNC, &ul)) {
|
||
|
NETCON_PROPERTIES * pProps = NULL;
|
||
|
spNC->GetProperties (&pProps);
|
||
|
if (pProps) {
|
||
|
NETCON_MEDIATYPE MediaType = pProps->MediaType;
|
||
|
NcFreeNetconProperties (pProps);
|
||
|
if ((MediaType == NCM_SHAREDACCESSHOST_LAN) ||
|
||
|
(MediaType == NCM_SHAREDACCESSHOST_RAS) ){
|
||
|
// found it
|
||
|
spNC->QueryInterface (__uuidof(IUnknown),
|
||
|
(void**)&spUnk);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
spNC = NULL;
|
||
|
}
|
||
|
}
|
||
|
if (spUnk)
|
||
|
hr = GetServiceFromINetConnection (spUnk, ppUPS);
|
||
|
} else {
|
||
|
// downlevel
|
||
|
CComPtr<IInternetGatewayFinder> spIGF = NULL;
|
||
|
hr = ::CoCreateInstance (CLSID_CInternetGatewayFinder,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
__uuidof(IInternetGatewayFinder),
|
||
|
(void**)&spIGF);
|
||
|
if (spIGF)
|
||
|
hr = GetServiceFromFinder (spIGF, ppUPS);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
template<class C, class I> class UN {
|
||
|
public:
|
||
|
HRESULT Create (I ** ppI)
|
||
|
{
|
||
|
if (ppI)
|
||
|
*ppI = NULL;
|
||
|
|
||
|
if (!ppI)
|
||
|
return E_POINTER;
|
||
|
|
||
|
CComPtr<IUPnPService> spUPS = NULL;
|
||
|
HRESULT hr = GetService (&spUPS);
|
||
|
if (spUPS) {
|
||
|
// create class so that I can initialize it
|
||
|
CComObject<C> * pC = NULL;
|
||
|
hr = CComObject<C>::CreateInstance (&pC);
|
||
|
if (pC) {
|
||
|
pC->AddRef();
|
||
|
// init
|
||
|
hr = pC->Initialize (spUPS);
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = pC->QueryInterface (__uuidof(I), (void**)ppI);
|
||
|
pC->Release();
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CUPnPNAT
|
||
|
|
||
|
STDMETHODIMP CUPnPNAT::get_NATEventManager(INATEventManager ** ppNEM)
|
||
|
{
|
||
|
NAT_API_ENTER
|
||
|
|
||
|
UN<CNATEventManager, INATEventManager> un;
|
||
|
return un.Create (ppNEM);
|
||
|
|
||
|
NAT_API_LEAVE
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUPnPNAT::get_DynamicPortMappingCollection (IDynamicPortMappingCollection ** ppDPMC)
|
||
|
{
|
||
|
NAT_API_ENTER
|
||
|
|
||
|
// remove the section below when turning dynamic port mappings back on
|
||
|
if (!ppDPMC)
|
||
|
return E_POINTER;
|
||
|
*ppDPMC = NULL;
|
||
|
return E_NOTIMPL;
|
||
|
// remove the section above when turning dynamic port mappings back on
|
||
|
|
||
|
UN<CDynamicPortMappingCollection, IDynamicPortMappingCollection> un;
|
||
|
return un.Create (ppDPMC);
|
||
|
|
||
|
NAT_API_LEAVE
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CUPnPNAT::get_StaticPortMappingCollection (IStaticPortMappingCollection ** ppSPMC)
|
||
|
{
|
||
|
NAT_API_ENTER
|
||
|
|
||
|
UN<CStaticPortMappingCollection, IStaticPortMappingCollection> un;
|
||
|
return un.Create (ppSPMC);
|
||
|
|
||
|
NAT_API_LEAVE
|
||
|
}
|
||
|
|
||
|
// private method(s)
|
||
|
HRESULT GetOSInfoService (IUPnPService ** ppUPS)
|
||
|
{
|
||
|
if (!ppUPS)
|
||
|
return E_POINTER;
|
||
|
*ppUPS = NULL;
|
||
|
|
||
|
// either enum all netconnections, or
|
||
|
// for downlevel, use Ken's object
|
||
|
|
||
|
CComPtr<INetConnectionManager> spNCM = NULL;
|
||
|
HRESULT hr = ::CoCreateInstance (CLSID_ConnectionManager,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
__uuidof(INetConnectionManager),
|
||
|
(void**)&spNCM);
|
||
|
if (spNCM) {
|
||
|
CComPtr<IEnumNetConnection> spENC = NULL;
|
||
|
hr = spNCM->EnumConnections (NCME_DEFAULT, &spENC);
|
||
|
if (spENC) {
|
||
|
ULONG ul = 0;
|
||
|
CComPtr<INetConnection> spNC = NULL;
|
||
|
while (S_OK == spENC->Next (1, &spNC, &ul)) {
|
||
|
NETCON_PROPERTIES * pProps = NULL;
|
||
|
spNC->GetProperties (&pProps);
|
||
|
if (pProps) {
|
||
|
NETCON_MEDIATYPE MediaType = pProps->MediaType;
|
||
|
NcFreeNetconProperties (pProps);
|
||
|
if ((MediaType == NCM_SHAREDACCESSHOST_LAN) ||
|
||
|
(MediaType == NCM_SHAREDACCESSHOST_RAS) ){
|
||
|
// found it
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
spNC = NULL;
|
||
|
}
|
||
|
if (spNC) {
|
||
|
CComPtr<INetSharedAccessConnection> spNSAC = NULL;
|
||
|
hr = spNC->QueryInterface (__uuidof(INetSharedAccessConnection), (void**)&spNSAC);
|
||
|
if (spNSAC)
|
||
|
hr = spNSAC->GetService (SAHOST_SERVICE_OSINFO, ppUPS);
|
||
|
} else
|
||
|
hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND);
|
||
|
}
|
||
|
} else {
|
||
|
// downlevel
|
||
|
CComPtr<IInternetGatewayFinder> spIGF = NULL;
|
||
|
hr = ::CoCreateInstance (CLSID_CInternetGatewayFinder,
|
||
|
NULL,
|
||
|
CLSCTX_ALL,
|
||
|
__uuidof(IInternetGatewayFinder),
|
||
|
(void**)&spIGF);
|
||
|
if (spIGF) {
|
||
|
CComPtr<IInternetGateway> spIG = NULL;
|
||
|
hr = spIGF->GetInternetGateway (NULL, &spIG); // NULL gets default.
|
||
|
if (spIG)
|
||
|
hr = spIG->GetService (SAHOST_SERVICE_OSINFO, ppUPS);
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
BOOL IsICSHost ()
|
||
|
{
|
||
|
CComPtr<IUPnPService> spOSI = NULL;
|
||
|
GetOSInfoService (&spOSI);
|
||
|
if (spOSI)
|
||
|
return TRUE;
|
||
|
return FALSE;
|
||
|
}
|