windows-nt/Source/XPSP1/NT/net/homenet/beacon/server/cwanconnectionbase.cpp
2020-09-26 16:20:57 +08:00

2259 lines
62 KiB
C++

#include "pch.h"
#pragma hdrstop
#include "CWANConnectionBase.h"
#include "beacon.h"
#include <ipnat.h>
#include <iphlpapi.h>
#include <ntddip.h>
#include <winsock.h>
#include "debug.h"
#include "util.h"
extern "C"
ULONG
NhpAllocateAndGetInterfaceInfoFromStack(
IP_INTERFACE_NAME_INFO** Table,
PULONG Count,
BOOL SortOutput,
HANDLE AllocationHeap,
ULONG AllocationFlags
);
CWANConnectionBase::CWANConnectionBase()
{
m_pConnectionPoint = NULL;
m_pHomenetConnection = NULL;
m_pEventSink = NULL;
m_pStatisticsProvider = NULL;
m_IcsSettingsp = NULL;
m_hAdviseNATEventsResult = E_FAIL;
}
HRESULT CWANConnectionBase::FinalConstruct()
{
HRESULT hr = S_OK;
hr = StartNetmanEvents(this);
if(SUCCEEDED(hr))
{
hr = AdviseNATEvents(this);
m_hAdviseNATEventsResult = hr;
}
return hr;
}
HRESULT CWANConnectionBase::FinalRelease()
{
if ( NULL != m_pHomenetConnection)
{
m_pHomenetConnection->Release();
}
if ( NULL != m_IcsSettingsp)
{
m_IcsSettingsp->Release();
}
if(NULL != m_pStatisticsProvider)
{
m_pStatisticsProvider->Release();
}
DestroyDebugger();
return S_OK;
}
HRESULT CWANConnectionBase::StopListening()
{
HRESULT hr = S_OK;
if(NULL != m_pConnectionPoint)
{
hr = m_pConnectionPoint->Unadvise(m_dwConnectionManagerConnectionPointCookie);
m_pConnectionPoint->Release();
m_pConnectionPoint = NULL;
}
if(SUCCEEDED(m_hAdviseNATEventsResult))
{
UnadviseNATEvents(this);
}
return hr;
}
HRESULT CWANConnectionBase::StartNetmanEvents(INetConnectionNotifySink* pSink)
{
HRESULT hr = S_OK;
INetConnectionManager* pConnectionManager;
hr = CoCreateInstance(CLSID_ConnectionManager, NULL, CLSCTX_SERVER, IID_INetConnectionManager, reinterpret_cast<void**>(&pConnectionManager));
if SUCCEEDED(hr)
{
IConnectionPointContainer* pConnectionPointContainer;
hr = pConnectionManager->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void**>(&pConnectionPointContainer));
if(SUCCEEDED(hr))
{
hr = pConnectionPointContainer->FindConnectionPoint(IID_INetConnectionNotifySink, &m_pConnectionPoint);
if(SUCCEEDED(hr))
{
hr = m_pConnectionPoint->Advise(pSink, &m_dwConnectionManagerConnectionPointCookie);
if(FAILED(hr))
{
m_pConnectionPoint->Release();
m_pConnectionPoint = NULL;
}
// release in stop listening on success
}
pConnectionPointContainer->Release();
}
pConnectionManager->Release();
}
return hr;
}
HRESULT
CWANConnectionBase::Initialize(
GUID* pGuid,
IHNetConnection* pHomenetConnection,
IStatisticsProvider* pStatisticsProvider
)
{
HRESULT hr = S_OK;
InitDebugger();
DBG_SPEW(TM_STATIC, TL_INFO, L" > Initialize ");
m_pStatisticsProvider = pStatisticsProvider;
m_pStatisticsProvider->AddRef();
m_pHomenetConnection = pHomenetConnection;
m_pHomenetConnection->AddRef();
CopyMemory(&m_SharedGuid, pGuid, sizeof(GUID));
hr = CoCreateInstance(CLSID_HNetCfgMgr,
NULL,
CLSCTX_SERVER,
IID_IHNetIcsSettings,
reinterpret_cast<void**>(&m_IcsSettingsp));
return hr;
}
HRESULT CWANConnectionBase::FireEvent(DISPID DispatchId)
{
HRESULT hr = S_OK;
IUPnPEventSink* pEventSink = NULL;
Lock();
if(NULL != m_pEventSink)
{
pEventSink = m_pEventSink;
pEventSink->AddRef();
}
Unlock();
if(NULL != pEventSink)
{
hr = pEventSink->OnStateChanged(1, &DispatchId);
pEventSink->Release();
}
return hr;
}
// IUPnPEventSource methods
HRESULT CWANConnectionBase::Advise(IUPnPEventSink* pesSubscriber)
{
HRESULT hr = S_OK;
Lock();
m_pEventSink = pesSubscriber;
m_pEventSink->AddRef();
Unlock();
return hr;
}
HRESULT CWANConnectionBase::Unadvise(IUPnPEventSink *pesSubscriber)
{
HRESULT hr = S_OK;
Lock();
m_pEventSink->Release();
m_pEventSink = NULL;
Unlock();
return hr;
}
// INATEventsNotifySink
HRESULT CWANConnectionBase::PublicIPAddressChanged(void)
{
return FireEvent(IWANIPCONNECTION_DISPID_EXTERNALIPADDRESS);
}
HRESULT CWANConnectionBase::PortMappingsChanged(void)
{
return FireEvent(IWANIPCONNECTION_DISPID_PORTMAPPINGNUMBEROFENTRIES);
}
// INetConnectionNotifySink methods
HRESULT CWANConnectionBase::ConnectionAdded(const NETCON_PROPERTIES_EX* pProps)
{
HRESULT hr = S_OK;
return hr;
}
HRESULT CWANConnectionBase::ConnectionBandWidthChange(const GUID* pguidId)
{
HRESULT hr = S_OK;
return hr;
}
HRESULT CWANConnectionBase::ConnectionDeleted(const GUID* pguidId)
{
HRESULT hr = S_OK;
return hr;
}
HRESULT CWANConnectionBase::ConnectionModified(const NETCON_PROPERTIES_EX* pProps)
{
HRESULT hr = S_OK;
return hr;
}
HRESULT CWANConnectionBase::ConnectionRenamed(const GUID* pguidId, LPCWSTR pszwNewName)
{
HRESULT hr = S_OK;
if(IsEqualGUID(*pguidId, m_SharedGuid))
{
hr = FireEvent(IWANIPCONNECTION_DISPID_NAME);
}
return hr;
}
HRESULT CWANConnectionBase::ConnectionStatusChange(const GUID* pguidId, NETCON_STATUS Status)
{
HRESULT hr = S_OK;
if(IsEqualGUID(*pguidId, m_SharedGuid))
{
hr = FireEvent(IWANIPCONNECTION_DISPID_CONNECTIONSTATUS);
}
return hr;
}
HRESULT CWANConnectionBase::ConnectionAddressChange(const GUID* pguidId)
{
HRESULT hr = S_OK;
if ( IsEqualGUID(*pguidId, m_SharedGuid) )
{
hr = FireEvent( IWANIPCONNECTION_DISPID_EXTERNALIPADDRESS );
}
return hr;
}
HRESULT CWANConnectionBase::ShowBalloon(const GUID* pguidId, const BSTR szCookie, const BSTR szBalloonText)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::RefreshAll()
{
HRESULT hr = S_OK;
return hr;
}
HRESULT CWANConnectionBase::DisableEvents(const BOOL fDisable, const ULONG ulDisableTimeout)
{
HRESULT hr = S_OK;
return hr;
}
// IWANIPConnection and IWANPPPConnection methods
HRESULT CWANConnectionBase::get_ConnectionType(BSTR *pConnectionType)
{
HRESULT hr = S_OK;
*pConnectionType = SysAllocString(L"IP_Routed");
if(NULL == *pConnectionType)
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CWANConnectionBase::get_PossibleConnectionTypes(BSTR *pPossibleConnectionTypes)
{
HRESULT hr = S_OK;
*pPossibleConnectionTypes = SysAllocString(L"IP_Routed");
if(NULL == *pPossibleConnectionTypes)
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CWANConnectionBase::get_ConnectionStatus(BSTR *pConnectionStatus)
{
HRESULT hr = S_OK;
*pConnectionStatus = NULL;
INetConnection* pNetConnection;
hr = m_pHomenetConnection->GetINetConnection(&pNetConnection);
if(SUCCEEDED(hr))
{
NETCON_PROPERTIES* pProperties;
hr = pNetConnection->GetProperties(&pProperties);
if(SUCCEEDED(hr))
{
LPWSTR pszStatus;
switch(pProperties->Status)
{
case NCS_AUTHENTICATION_SUCCEEDED:
case NCS_CONNECTED:
pszStatus = L"Connected";
break;
case NCS_DISCONNECTED:
pszStatus = L"Disconnected";
break;
case NCS_AUTHENTICATING:
case NCS_CONNECTING:
pszStatus = L"Connecting";
break;
case NCS_DISCONNECTING:
pszStatus = L"Disconnecting";
break;
case NCS_INVALID_ADDRESS:
case NCS_CREDENTIALS_REQUIRED:
case NCS_AUTHENTICATION_FAILED:
case NCS_HARDWARE_DISABLED:
case NCS_HARDWARE_MALFUNCTION:
case NCS_HARDWARE_NOT_PRESENT:
default:
pszStatus = L"Unconfigured";
break;
}
*pConnectionStatus = SysAllocString(pszStatus);
if(NULL == *pConnectionStatus)
{
hr = E_OUTOFMEMORY;
}
NcFreeNetconProperties(pProperties);
}
pNetConnection->Release();
}
return hr;
}
HRESULT CWANConnectionBase::get_Uptime(ULONG *pUptime)
{
HRESULT hr = S_OK;
hr = m_pStatisticsProvider->GetStatistics(NULL, NULL, NULL, NULL, NULL, pUptime);
return hr;
}
HRESULT CWANConnectionBase::get_UpstreamMaxBitRate(ULONG *pUpstreamMaxBitRate)
{
HRESULT hr = S_OK;
hr = m_pStatisticsProvider->GetStatistics(NULL, NULL, NULL, NULL, pUpstreamMaxBitRate, NULL);
return hr;
}
HRESULT CWANConnectionBase::get_DownstreamMaxBitRate(ULONG *pDownstreamMaxBitRate)
{
HRESULT hr = S_OK;
hr = m_pStatisticsProvider->GetStatistics(NULL, NULL, NULL, NULL, pDownstreamMaxBitRate, NULL);
return hr;
}
HRESULT CWANConnectionBase::get_RSIPAvailable(VARIANT_BOOL *pRSIPAvailable)
{
HRESULT hr = S_OK;
*pRSIPAvailable = VARIANT_FALSE;
return hr;
}
HRESULT CWANConnectionBase::get_NATEnabled(VARIANT_BOOL *pNATEnabled)
{
HRESULT hr = S_OK;
*pNATEnabled = VARIANT_TRUE;
return hr;
}
HRESULT CWANConnectionBase::get_X_Name(BSTR* pName)
{
HRESULT hr = S_OK;
*pName = NULL;
INetConnection* pNetConnection;
hr = m_pHomenetConnection->GetINetConnection(&pNetConnection);
if(SUCCEEDED(hr))
{
NETCON_PROPERTIES* pProperties;
hr = pNetConnection->GetProperties(&pProperties);
if(SUCCEEDED(hr))
{
*pName = SysAllocString(pProperties->pszwName);
if(NULL == *pName)
{
hr = E_OUTOFMEMORY;
}
NcFreeNetconProperties(pProperties);
}
pNetConnection->Release();
}
return hr;
}
HRESULT
get_HrLocalAdaptersInfo(PIP_ADAPTER_INFO* ppAdapter)
{
HRESULT hr = S_OK, dwErr = NO_ERROR;
PIP_ADAPTER_INFO paAdapterInfo = NULL;
ULONG uBufLen = (2 * BUF_SIZE);
_ASSERT( ppAdapter != NULL );
*ppAdapter = NULL;
paAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc( uBufLen );
if ( NULL == paAdapterInfo ) { return E_OUTOFMEMORY; }
//
// Discover How much Memory we need. If we need at all.
// Note that paAdapterInfo may be non-NULL and that is desired.
dwErr = GetAdaptersInfo( paAdapterInfo, &uBufLen );
if ( ERROR_BUFFER_OVERFLOW == dwErr )
{
CoTaskMemFree( paAdapterInfo );
paAdapterInfo = (PIP_ADAPTER_INFO) CoTaskMemAlloc( uBufLen );
if ( paAdapterInfo != NULL)
{
dwErr = GetAdaptersInfo ( paAdapterInfo, &uBufLen );
}
}
if ( paAdapterInfo == NULL)
{
return E_OUTOFMEMORY;
}
if ( ERROR_SUCCESS != dwErr )
{
DBG_SPEW( TM_INFO, TL_ERROR,
L" GetAdapterInfo has failed with E(%u) BufSize(%u) ",
dwErr, uBufLen );
CoTaskMemFree(paAdapterInfo);
return HRESULT_FROM_WIN32( dwErr );
}
if ( ppAdapter && paAdapterInfo ) { *ppAdapter = paAdapterInfo; }
return hr;
}
// {c200e360-38c5-11ce-ae62-08002b2b79ef} - 38 chars
#define GUID_STRING_LENGTH 38
PIP_ADAPTER_INFO
GetExternalAdapterInfo( GUID* pGUID )
{
HRESULT hr = S_OK;
WCHAR szwGUID[ GUID_STRING_LENGTH + 1 ] = { 0 };
char ascGUID[ GUID_STRING_LENGTH + 1 ] = { 0 };
PIP_ADAPTER_INFO pRetAdapter = NULL;
PIP_ADAPTER_INFO pAdapterList = NULL, pTempAdapter = NULL;
_ASSERT( pGUID != NULL );
//
// Change the given GUID to a String
if ( StringFromGUID2( *pGUID, szwGUID, GUID_STRING_LENGTH + 1 ) == 0 )
{ return NULL; }
if ( WideCharToMultiByte( CP_ACP, 0, szwGUID, -1, ascGUID, sizeof(ascGUID), NULL, NULL) == 0 )
{ return NULL; }
hr = get_HrLocalAdaptersInfo( &pAdapterList );
if ( FAILED(hr) || (pAdapterList == NULL) ) { return NULL; }
pTempAdapter = pAdapterList;
while ( pAdapterList != NULL )
{
if ( 0 == strcmp(ascGUID, pAdapterList->AdapterName) )
{
pRetAdapter = (PIP_ADAPTER_INFO) CoTaskMemAlloc( sizeof(IP_ADAPTER_INFO) );
if ( NULL != pRetAdapter )
{
memcpy( pRetAdapter, pAdapterList, sizeof(IP_ADAPTER_INFO) );
pRetAdapter->Next = NULL;
break;
}
}
pAdapterList = pAdapterList->Next;
}
CoTaskMemFree( pTempAdapter );
return pRetAdapter;
}
HRESULT CWANConnectionBase::get_ExternalIPAddress(BSTR *pExternalIPAddress)
{
HRESULT hr = S_OK;
ULONG AddressCount = 0;
LPOLESTR swAddr = NULL;
PIP_ADAPTER_INFO pExternalAdapterInfo = NULL;
ULONG numOfChar = 0, uTemp = 0, Error = NO_ERROR;
WCHAR szwGUID[ GUID_STRING_LENGTH + 1 ] = { 0 };
IP_INTERFACE_NAME_INFO* Table = NULL;
ULONG Count = 0;
_ASSERT( pExternalIPAddress != NULL );
if ( pExternalIPAddress != NULL )
{
*pExternalIPAddress = NULL;
}
else
{
return E_POINTER;
}
_ASSERT( pExternalIPAddress != NULL );
StringFromGUID2( m_SharedGuid, szwGUID, GUID_STRING_LENGTH + 1 );
DBG_SPEW(TM_INFO, TL_TRACE, L"> get_ExternalIpAddress Looking for GUID %s", szwGUID);
Error = NhpAllocateAndGetInterfaceInfoFromStack(&Table,
&Count,
FALSE,
GetProcessHeap(),
0);
if ( (NO_ERROR == Error) && (Table != NULL) )
{
for (ULONG i = 0; i < Count ; i++)
{
#if DBG
StringFromGUID2( Table[i].DeviceGuid, szwGUID, GUID_STRING_LENGTH + 1 );
DBG_SPEW(TM_INFO, TL_DUMP, L" DeviceGUID[%u] = %s", i, szwGUID);
StringFromGUID2( Table[i].InterfaceGuid, szwGUID, GUID_STRING_LENGTH + 1 );
DBG_SPEW(TM_INFO, TL_DUMP, L" DeviceGUID[%u] = %s", i, szwGUID);
#endif
if ( IsEqualGUID((Table[i].InterfaceGuid), m_SharedGuid) )
{
pExternalAdapterInfo = GetExternalAdapterInfo( &Table[i].DeviceGuid );
break;
}
}
HeapFree(GetProcessHeap(), 0, Table);
}
if ( pExternalAdapterInfo == NULL )
{
pExternalAdapterInfo = GetExternalAdapterInfo( &m_SharedGuid );
}
if ( pExternalAdapterInfo != NULL )
{
if ( strcmp("0.0.0.0", pExternalAdapterInfo->IpAddressList.IpAddress.String) )
{
numOfChar = strlen( pExternalAdapterInfo->IpAddressList.IpAddress.String );
swAddr = (LPOLESTR) CoTaskMemAlloc( (numOfChar + 1) * sizeof(WCHAR) );
if ( swAddr != NULL )
{
memset( swAddr, 0, (numOfChar + 1) * sizeof(WCHAR));
uTemp = _snwprintf( swAddr, numOfChar, L"%S",
pExternalAdapterInfo->IpAddressList.IpAddress.String );
_ASSERT( numOfChar == uTemp );
swAddr[ numOfChar] = L'\0';
*pExternalIPAddress = SysAllocString( swAddr );
CoTaskMemFree( swAddr );
}
}
else
{
*pExternalIPAddress = SysAllocString( L"" );
}
CoTaskMemFree( pExternalAdapterInfo );
}
else
{
*pExternalIPAddress = SysAllocString( L"" );
}
if ( *pExternalIPAddress == NULL )
{
hr = E_OUTOFMEMORY;
}
else
{
DBG_SPEW(TM_INFO, TL_INFO, L"Returning IP String (%s)", *pExternalIPAddress);
}
return hr;
}
HRESULT CWANConnectionBase::get_RemoteHost(BSTR *pRemoteHost)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_ExternalPort(USHORT *pExternalPort)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_InternalPort(USHORT *pInternalPort)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_PortMappingProtocol(BSTR *pProtocol)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_InternalClient(BSTR *pInternalClient)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_PortMappingDescription(BSTR *pDescription)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_PortMappingEnabled(VARIANT_BOOL *pEnabled)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_PortMappingLeaseDuration(ULONG *LeaseDuration)
{
HRESULT hr = E_NOTIMPL;
return hr;
}
HRESULT CWANConnectionBase::get_PortMappingNumberOfEntries(USHORT *pNumberOfEntries)
{
HRESULT hr = S_OK;
IHNetPortMappingProtocol* MappingProtocolp = NULL;
IHNetProtocolSettings* ProtocolSettingsp = NULL;
IEnumHNetPortMappingProtocols* EnumProtocolsp = NULL;
_ASSERT( pNumberOfEntries != NULL );
*pNumberOfEntries = 0;
do
{
hr = m_IcsSettingsp->QueryInterface(IID_IHNetProtocolSettings,
reinterpret_cast<void**>(&ProtocolSettingsp));
if( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Query Interface failed for ProtocolSettingsp E:(%X)", hr);
break;
}
hr = ProtocolSettingsp->EnumPortMappingProtocols(&EnumProtocolsp);
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Enum Interface can't be retrieved E(%X)", hr);
break;
}
while( S_OK == EnumProtocolsp->Next(1, &MappingProtocolp, NULL) )
{
(*pNumberOfEntries)++;
_ASSERT( MappingProtocolp != NULL );
MappingProtocolp->Release();
}
} while ( FALSE );
if ( ProtocolSettingsp != NULL ) { ProtocolSettingsp->Release(); }
if ( EnumProtocolsp != NULL) { EnumProtocolsp->Release(); }
return hr;
}
HRESULT CWANConnectionBase::SetConnectionType(BSTR NewConnectionType)
{
HRESULT hr = S_OK;
if(0 != lstrcmp(NewConnectionType, L"IP_Routed"))
{
hr = E_FAIL; // we only support IP_Routed
}
return hr;
}
HRESULT CWANConnectionBase::GetConnectionTypeInfo(BSTR* pNewConnectionType, BSTR* pNewPossibleConnectionTypes)
{
HRESULT hr = S_OK;
SysFreeString(*pNewConnectionType);
SysFreeString(*pNewPossibleConnectionTypes);
*pNewConnectionType = NULL;
*pNewPossibleConnectionTypes = NULL;
hr = get_ConnectionType(pNewConnectionType);
if(SUCCEEDED(hr))
{
hr = get_PossibleConnectionTypes(pNewPossibleConnectionTypes);
}
if(FAILED(hr))
{
if(NULL != *pNewConnectionType)
{
SysFreeString(*pNewConnectionType);
*pNewConnectionType = NULL;
}
}
return hr;
}
HRESULT CWANConnectionBase::GetStatusInfo(BSTR* pNewConnectionStatus, BSTR* pNewLastConnectionError, ULONG* pNewUptime)
{
HRESULT hr = S_OK;
SysFreeString(*pNewConnectionStatus);
SysFreeString(*pNewLastConnectionError);
*pNewConnectionStatus = NULL;
*pNewLastConnectionError = NULL;
hr = get_ConnectionStatus(pNewConnectionStatus);
if(SUCCEEDED(hr))
{
hr = get_LastConnectionError(pNewLastConnectionError);
}
if(SUCCEEDED(hr) && 0 == lstrcmp(L"Connected", *pNewConnectionStatus))
{
hr = get_Uptime(pNewUptime);
}
else
{
*pNewUptime = 0;
}
if(FAILED(hr))
{
if(NULL != *pNewConnectionStatus)
{
SysFreeString(*pNewConnectionStatus);
*pNewConnectionStatus = NULL;
}
if(NULL != *pNewLastConnectionError)
{
SysFreeString(*pNewLastConnectionError);
*pNewLastConnectionError = NULL;
}
}
return hr;
}
HRESULT CWANConnectionBase::GetNATRSIPStatus(VARIANT_BOOL* pNewRSIPAvailable, VARIANT_BOOL* pNewNATEnabled)
{
HRESULT hr = S_OK;
hr = get_RSIPAvailable(pNewRSIPAvailable);
if(SUCCEEDED(hr))
{
hr = get_NATEnabled(pNewNATEnabled);
}
return hr;
}
HRESULT CWANConnectionBase::GetLinkLayerMaxBitRates(ULONG* pNewUpstreamMaxBitRate, ULONG* pNewDownstreamMaxBitRate)
{
HRESULT hr = S_OK;
hr = get_UpstreamMaxBitRate(pNewUpstreamMaxBitRate);
if(SUCCEEDED(hr))
{
hr = get_DownstreamMaxBitRate(pNewDownstreamMaxBitRate);
}
return hr;
}
HRESULT
CWANConnectionBase::GetGenericPortMappingEntry(
USHORT ulIndex,
BSTR* RemoteHostp,
USHORT* uExternalPortp,
BSTR* Protocolp,
USHORT* uInternalPortp,
BSTR* InternalClientp,
VARIANT_BOOL* bEnabledp,
BSTR* Descriptionp,
ULONG* ulLeaseDurationp
)
{
HRESULT hr = S_OK;
IHNetPortMappingProtocol* MappingProtocolp = NULL;
IHNetPortMappingBinding* Bindingp = NULL;
USHORT BoundaryPort = 0, InternalPort = 0;
_ASSERT ( RemoteHostp != NULL );
_ASSERT ( uExternalPortp != NULL );
_ASSERT ( Protocolp != NULL );
_ASSERT ( uInternalPortp != NULL );
_ASSERT ( InternalClientp != NULL );
_ASSERT ( bEnabledp != NULL );
_ASSERT ( Descriptionp != NULL );
_ASSERT ( ulLeaseDurationp != NULL );
//
// In/Out Parameters to COM Interfaces needs cleanup
//
SysFreeString(*RemoteHostp);
SysFreeString(*Protocolp);
SysFreeString(*InternalClientp);
SysFreeString(*Descriptionp);
*RemoteHostp = NULL;
*Protocolp = NULL;
*InternalClientp = NULL;
*Descriptionp = NULL;
*ulLeaseDurationp = 0;
DBG_SPEW(TM_INFO, TL_TRACE, L"> GetGenericPortMapping");
//
// check for access
hr = this->ControlEnabled();
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR, L"Control Disabled returning E(%X)", hr);
return hr;
}
do
{
//
// SECURITY - SECURITY - SECURITY
// Here we're allowing the out-of-proc COM call
// into our service to have SYSTEM access rights.
//
// REASON: UPnP works in LOCAL_SERVICE and COM
// Calls into our service which modify
// the WMI repository will FAIL. This
// Call alleviates that problem by changing
// The Security to that of the SYSTEM
// and is reverted back when the class
// is out of scope by the destructor of.
// CSwitchSecurityContext
//
CSwitchSecurityContext SwSecCxt;
hr = SearchPortMapping(m_IcsSettingsp,
ulIndex,
0,
0,
&MappingProtocolp);
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR,
L"Enum - Seeking the port has failed E(%X)", hr);
SetUPnPError(L"713");
break;
}
//
// Getting the binding - is this how it should be?
//
hr = m_pHomenetConnection->GetBindingForPortMappingProtocol(MappingProtocolp,
&Bindingp);
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR,
L"Enum - Error In Getting Binding for Protocol E(%X)", hr);
break;
}
hr = FillStaticMappingInformation(MappingProtocolp,
Bindingp,
&BoundaryPort,
Protocolp,
&InternalPort,
InternalClientp,
bEnabledp,
Descriptionp);
_ASSERT( SUCCEEDED(hr) );
if ( SUCCEEDED(hr) ) // correct the port Byte Ordering
{
*uExternalPortp = ntohs( BoundaryPort );
*uInternalPortp = ntohs( InternalPort );
}
else
{
DBG_SPEW(TM_INFO, TL_ERROR,
L"Enum - Error In Getting Binding for Protocol E(%X)" , hr);
}
} while ( FALSE );
if ( MappingProtocolp != NULL) MappingProtocolp->Release();
if ( Bindingp != NULL ) Bindingp->Release();
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR,
L"Enum - GetGenericEntry has failed with E(%X)", hr);
}
return hr;
} // GetArrayEntry
HRESULT
CWANConnectionBase::GetSpecificPortMappingEntry(
IN BSTR RemoteHost,
IN USHORT uwExternalPort,
IN BSTR Protocol,
OUT USHORT* puwInternalPort,
OUT BSTR* InternalClientp,
OUT VARIANT_BOOL* pbEnabled,
OUT BSTR* Descriptionp,
OUT ULONG* pulLeaseDuration
)
//
// Note that every port is expected to arrive in HOST order
// and will be returned in HOST order
//
{
HRESULT hr = S_OK;
IHNetPortMappingProtocol* MappingProtocolp = NULL;
IHNetPortMappingBinding* Bindingp = NULL;
USHORT tempExtPort = 0, tempIntPort = 0;
UCHAR searchProtocol = NULL;
_ASSERT( RemoteHost != NULL );
_ASSERT( uwExternalPort != 0 );
_ASSERT( Protocol != NULL );
SysFreeString( *InternalClientp );
SysFreeString( *Descriptionp );
*InternalClientp = NULL;
*Descriptionp = NULL;
tempExtPort = htons( uwExternalPort ); // flip to Network order
DBG_SPEW(TM_INFO, TL_TRACE, L"> GetSpecificPortMapping");
//
// check for access
hr = this->ControlEnabled();
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR, L"Control is Disabled E(%X)", hr);
return hr;
}
if ( 0 == uwExternalPort)
{
DBG_SPEW(TM_INFO, TL_ERROR, L"Parameters Incorrect Port(%hu)", uwExternalPort );
SetUPnPError(L"402");
return E_INVALIDARG;
}
do
{
//
// SECURITY - SECURITY - SECURITY
// Here we're allowing the out-of-proc COM call
// into our service to have SYSTEM access rights.
//
// REASON: UPnP works in LOCAL_SERVICE and COM
// Calls into our service which modify
// the WMI repository will FAIL. This
// Call alleviates that problem by changing
// The Security to that of the SYSTEM
// and is reverted back when the class
// is out of scope by the destructor of.
// CSwitchSecurityContext
//
CSwitchSecurityContext SwSecCxt;
//
// Resolve the Protocol to the appropriate enum.
//
RESOLVE_PROTOCOL_TYPE(searchProtocol, Protocol);
DBG_SPEW(TM_INFO, TL_INFO,
L"Search Specific - ExtPort (%hu) Protocol (%s)",
htons( tempExtPort ),
(NAT_PROTOCOL_TCP == searchProtocol)?L"TCP":L"UDP");
hr = SearchPortMapping(m_IcsSettingsp,
0,
tempExtPort,
searchProtocol,
&MappingProtocolp);
if ( FAILED(hr))
{
DBG_SPEW(TM_INFO, TL_ERROR, L"Error or can't get Search E(%X)", hr);
SetUPnPError(L"714");
break;
}
//
// Getting the binding
//
hr = m_pHomenetConnection->GetBindingForPortMappingProtocol(MappingProtocolp,
&Bindingp);
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR,
L"Error In Getting Binding for Protocol E(%X)", hr);
break;
}
hr = FillStaticMappingInformation(MappingProtocolp,
Bindingp,
&tempExtPort,
&Protocol,
&tempIntPort,
InternalClientp,
pbEnabled,
Descriptionp);
_ASSERT( SUCCEEDED(hr) );
*puwInternalPort = ntohs( tempIntPort );
DBG_SPEW(TM_INFO, TL_TRACE,
L"Returning IntClient (%s) IntPort (%hu) IntProtocol (%s), Enabled (%s), Desc (%s)",
*InternalClientp,
*puwInternalPort,
Protocol,
(*pbEnabled == VARIANT_TRUE)?L"TRUE":L"FALSE",
*Descriptionp);
} while ( FALSE );
if ( MappingProtocolp != NULL) MappingProtocolp->Release();
if ( Bindingp != NULL ) Bindingp->Release();
if ( FAILED(hr) )
{
DBG_SPEW(TM_INFO, TL_ERROR, L"Error or can't get Search Done E(%X)", hr);
}
return hr;
}
HRESULT
CWANConnectionBase::AddPortMapping(
BSTR RemoteHost,
USHORT uwExternalPort,
BSTR Protocol,
USHORT uwInternalPort,
BSTR InternalClient,
VARIANT_BOOL bEnabled,
BSTR Description,
ULONG ulLeaseDuration
)
{
HRESULT hr = S_OK;
MAPPING_TYPE MappingType = ePortMappingInvalid;
DBG_SPEW(TM_STATIC, TL_TRACE, L"> AddPortMapping");
//
// Check for Access status
hr = this->ControlEnabled();
if ( SUCCEEDED(hr) )
{
hr = ValidatePortMappingParameters(RemoteHost,
uwExternalPort,
Protocol,
uwInternalPort,
InternalClient,
bEnabled,
Description,
ulLeaseDuration,
&MappingType);
if ( SUCCEEDED(hr) )
{
DBG_SPEW(TM_STATIC, TL_TRACE,
L"Add PortMapping - ExtPort (%hu) Protocol (%s)",
uwExternalPort, Protocol);
DBG_SPEW(TM_STATIC, TL_TRACE,
L"IntClient (%s) IntPort (%hu) Enabled (%s), Desc (%s)",
InternalClient,
uwInternalPort,
(bEnabled == VARIANT_TRUE)?L"TRUE":L"FALSE",
Description);
if ( ePortMappingStatic == MappingType )
{
//
// SECURITY - SECURITY - SECURITY
// Here we're allowing the out-of-proc COM call
// into our service to have SYSTEM access rights.
//
// REASON: UPnP works in LOCAL_SERVICE and COM
// Calls into our service which modify
// the WMI repository will FAIL. This
// Call alleviates that problem by changing
// The Security to that of the SYSTEM
// and is reverted back when the class
// is out of scope by the destructor of.
// CSwitchSecurityContext
//
CSwitchSecurityContext SwSecCxt;
hr = AddStaticPortMapping(RemoteHost,
uwExternalPort,
Protocol,
uwInternalPort,
InternalClient,
bEnabled,
Description,
ulLeaseDuration);
}
else
{
hr = AddDynamicPortMapping(RemoteHost,
uwExternalPort,
Protocol,
uwInternalPort,
InternalClient,
bEnabled,
Description,
ulLeaseDuration);
}
}
}
else
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Control Disabled E(%X)", hr);
}
return hr;
}
HRESULT
CWANConnectionBase::AddDynamicPortMapping(
BSTR RemoteHost,
USHORT uwExternalPort,
BSTR Protocol,
USHORT uwInternalPort,
BSTR InternalClient,
VARIANT_BOOL bEnabled,
BSTR Description,
ULONG ulLeaseDuration
)
{
//
// We currently don't handle any Dynamic Port Redirections.
//
DBG_SPEW(TM_DYNAMIC, TL_ERROR, L"Only Static Mappings are allowed [Lease]");
SetUPnPError(L"725");
return E_INVALIDARG;
}
HRESULT
CWANConnectionBase::AddStaticPortMapping(
BSTR RemoteHost,
USHORT uwExternalPort,
BSTR Protocol,
USHORT uwInternalPort,
BSTR InternalClient,
VARIANT_BOOL bEnabled,
BSTR Description,
ULONG ulLeaseDuration
)
{
HRESULT hr = S_OK;
UCHAR ProtocolType = 0;
IHNetProtocolSettings* ProtocolSettingsp = NULL;
IHNetPortMappingProtocol* PortMappingProtocolp = NULL;
IHNetPortMappingBinding* PortMappingBindingp = NULL;
ULONG ClientAddr = 0;
BOOLEAN bLetsEnable = FALSE;
BOOLEAN bCreatedProtocol = FALSE;
ULONG tempStrLen = 0;
WCHAR tempPortStr[] = L"00000";
LPOLESTR tempStr = NULL;
USHORT tempExtPort = 0, tempIntPort = 0;
BSTR ProtocolFromBinding = NULL;
BSTR ClientFromBinding = NULL;
BSTR DescriptionFromBinding = NULL;
VARIANT_BOOL boolEnabled;
_ASSERT( uwExternalPort );
_ASSERT( uwInternalPort );
//
// Convert both ends to Network Order
//
tempExtPort = htons( uwExternalPort );
tempIntPort = htons( uwInternalPort );
//
// Convert VARIANT_BOOL to boolean
//
bLetsEnable = ( bEnabled == VARIANT_TRUE );
//
// Process the Operation
//
do
{
RESOLVE_PROTOCOL_TYPE(ProtocolType, Protocol);
//
// IF there is no description crate one
// using PORT and PROTOCOL
//
if ( wcscmp(Description, L"\0") == 0 )
{
// Get Internal ClientName + the seperator
tempStrLen = ( SysStringLen( InternalClient ) + 1 );
// Get port len + plus the seperator
_itow ( uwExternalPort, tempPortStr, 10);
tempStrLen += (wcslen (tempPortStr) + 1);
// Get Protocol Name
tempStrLen += SysStringLen( Protocol );
// Create out from these two
tempStr = (LPOLESTR)CoTaskMemAlloc( (tempStrLen + 1) * sizeof(WCHAR) );
if ( tempStr != NULL )
{
_snwprintf(tempStr, tempStrLen, L"%s-%s-%s",
InternalClient, tempPortStr, Protocol);
tempStr[ tempStrLen ] = L'\0';
Description = SysAllocString ( tempStr );
}
if ( (tempStr == NULL) || (Description == NULL) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Can't Initialize Strings - out of mem");
hr = E_OUTOFMEMORY;
break;
}
}
//
// Find Existing Mapping
//
hr = SearchPortMapping(m_IcsSettingsp,
0,
tempExtPort,
ProtocolType,
&PortMappingProtocolp);
//
// if found it is in Edit Mode.
//
if ( SUCCEEDED(hr) )
{
hr = m_pHomenetConnection->GetBindingForPortMappingProtocol(PortMappingProtocolp,
&PortMappingBindingp);
_ASSERT( SUCCEEDED(hr) );
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Can't get Binding for Port Mapping E(X)", hr);
_ASSERT( FALSE );
break;
}
//
// Fill the information
//
hr = FillStaticMappingInformation(PortMappingProtocolp,
PortMappingBindingp,
&tempExtPort,
&ProtocolFromBinding,
&tempIntPort,
&ClientFromBinding,
&boolEnabled,
&DescriptionFromBinding);
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Filling has failed for Mapping Information E(%X)", hr);
break;
}
//
// If the existin Mapping was disabled we should be able to change
// the Internal Client
//
if ( boolEnabled == VARIANT_TRUE )
{
if ( _wcsicmp( InternalClient, ClientFromBinding) != 0 ) // if diff then error
{
hr = E_INVALIDARG;
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Will not change the internal client for an enabled PortMapping");
SetUPnPError(L"718");
break;
}
}
//
// if the Internal Port has changed reflect the change
//
if ( tempIntPort != htons( uwInternalPort ) )
{
tempIntPort = htons( uwInternalPort );
hr = PortMappingBindingp->SetTargetPort( tempIntPort );
_ASSERT( SUCCEEDED(hr) );
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Changin Internal Port has Failed E(%X)", hr);
break;
}
}
//
// Set the description if changed
//
if ( _wcsicmp(DescriptionFromBinding, Description) != 0)
{
hr = PortMappingProtocolp->SetName(Description);
if ( FAILED(hr) )
{
hr = E_INVALIDARG;
DBG_SPEW(TM_STATIC, TL_ERROR, L"Set Name has failed E(%X)", hr);
break;
}
}
}
else
{
//
// Start Getting the Interface
//
hr = m_IcsSettingsp->QueryInterface(IID_IHNetProtocolSettings,
reinterpret_cast<void**>(&ProtocolSettingsp));
if ( SUCCEEDED(hr) )
{
hr = ProtocolSettingsp->CreatePortMappingProtocol(Description,
ProtocolType,
tempExtPort,
&PortMappingProtocolp);
if ( SUCCEEDED(hr) )
{
hr = m_pHomenetConnection->GetBindingForPortMappingProtocol(PortMappingProtocolp,
&PortMappingBindingp);
if ( SUCCEEDED(hr) )
{
hr = PortMappingBindingp->SetTargetPort( tempIntPort );
_ASSERT( SUCCEEDED(hr) );
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Set Target Port has Failed E(%X)", hr);
}
bCreatedProtocol = TRUE;
}
else
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Getting Binding has Failed E(X)", hr);
PortMappingProtocolp->Delete();
break;
}
}
else
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Creating the PortMapping has Failed E(%X)", hr);
break;
}
}
else
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Getting the Protocol Settings has failed E(X)", hr);
break;
}
}
//
// Setting the Client name / address
// For Edit mode we already checked wether this code will be run or not.
//
if (
( wcscmp(L"0.0.0.0", InternalClient) != 0 ) &&
( InternalClient[0] != L'\0' )
)
{
ClientAddr = INET_ADDR((LPOLESTR) InternalClient );
//
// if the address is not valid (INADDR_NONE)
// and if the address is different than Broadcast address (which also is INADDR_NONE)
//
if ( (ClientAddr == INADDR_NONE) && wcscmp(L"255.255.255.255", InternalClient) )
{
hr = PortMappingBindingp->SetTargetComputerName( InternalClient );
}
else
{
hr = PortMappingBindingp->SetTargetComputerAddress( ClientAddr );
}
_ASSERT( SUCCEEDED(hr) );
if ( SUCCEEDED(hr) )
{
hr = PortMappingBindingp->SetEnabled( bLetsEnable );
}
if ( FAILED(hr) ) DBG_SPEW(TM_STATIC, TL_ERROR, L"Client Add/Edit IntClient failed - E(%X)", hr);
}
if ( FAILED(hr) && (TRUE == bCreatedProtocol) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Client Add / Edit failed - E(%X)", hr);
hr = PortMappingProtocolp->Delete();
}
} while ( FALSE );
if ( tempStr != NULL)
{
CoTaskMemFree ( tempStr );
SysFreeString ( Description ); // you can free a NULL string.
}
if ( ProtocolFromBinding ) SysFreeString(ProtocolFromBinding);
if ( ClientFromBinding ) SysFreeString(ClientFromBinding);
if ( DescriptionFromBinding ) SysFreeString(DescriptionFromBinding);
if ( PortMappingBindingp != NULL ) PortMappingBindingp->Release();
if ( PortMappingProtocolp != NULL ) PortMappingProtocolp->Release();
if ( ProtocolSettingsp != NULL ) ProtocolSettingsp->Release();
if ( FAILED(hr) ) { DBG_SPEW(TM_STATIC, TL_ERROR, L"Error Returning hr (%X)", hr); }
return hr;
} // CWANConnectionBase :: AddStaticPortMapping
HRESULT
CWANConnectionBase::DeletePortMapping(
BSTR RemoteHost,
USHORT uwExternalPort,
BSTR Protocol
)
{
HRESULT hr = S_OK;
UCHAR ProtocolType = 0;
IHNetPortMappingProtocol* PortMappingProtocolp = NULL;
USHORT tempExtPort = 0;
//
// SECURITY - SECURITY - SECURITY
// Here we're allowing the out-of-proc COM call
// into our service to have SYSTEM access rights.
//
// REASON: UPnP works in LOCAL_SERVICE and COM
// Calls into our service which modify
// the WMI repository will FAIL. This
// Call alleviates that problem by changing
// The Security to that of the SYSTEM
// and is reverted back when the class
// is out of scope by the destructor of.
// CSwitchSecurityContext
//
CSwitchSecurityContext SwSecCxt;
_ASSERT( RemoteHost != NULL );
_ASSERT( uwExternalPort != 0 );
_ASSERT( Protocol != NULL );
DBG_SPEW(TM_STATIC, TL_TRACE, L"> DeletePortMapping");
//
// check for access
hr = this->ControlEnabled();
if ( FAILED(hr) ) { return hr; }
//
// Convert to Network order
//
tempExtPort = htons(uwExternalPort );
DBG_SPEW(TM_STATIC, TL_INFO,
L"Search Specific - ExtPort (%hu) Protocol (%s)",
uwExternalPort, Protocol);
do
{
RESOLVE_PROTOCOL_TYPE( ProtocolType, Protocol );
hr = SearchPortMapping(m_IcsSettingsp,
0,
tempExtPort,
ProtocolType,
&PortMappingProtocolp);
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Error in Searching E(%X)", hr );
SetUPnPError(L"714");
break;
}
hr = PortMappingProtocolp->Delete();
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"ProtocolMapping deletion failure, Might be Built in E(%X)", hr );
}
PortMappingProtocolp->Release();
} while ( FALSE );
if ( FAILED(hr) ) DBG_SPEW(TM_STATIC, TL_ERROR, L"Delete failed with hr - %X", hr);
return hr;
}
HRESULT CWANConnectionBase::GetExternalIPAddress(BSTR* pExternalIPAddress)
{
HRESULT hr = S_OK;
SysFreeString(*pExternalIPAddress);
*pExternalIPAddress = NULL;
hr = get_ExternalIPAddress(pExternalIPAddress);
return hr;
}
HRESULT CWANConnectionBase::ControlEnabled()
{
HRESULT hr = S_OK;
// check the reg key. Only disable if key exists and is 0.
HKEY hKey;
DWORD dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_SHAREDACCESSCLIENTKEYPATH, 0, KEY_QUERY_VALUE, &hKey);
if(ERROR_SUCCESS == dwError) // if this fails we assume it is on, set the box, and commit on apply
{
DWORD dwType;
DWORD dwData = 0;
DWORD dwSize = sizeof(dwData);
dwError = RegQueryValueEx(hKey, REGVAL_SHAREDACCESSCLIENTENABLECONTROL, 0, &dwType, reinterpret_cast<LPBYTE>(&dwData), &dwSize);
if(ERROR_SUCCESS == dwError && REG_DWORD == dwType && 0 == dwData)
{
hr = E_ACCESSDENIED;
}
RegCloseKey(hKey);
}
return hr;
}
HRESULT
SearchPortMapping(
IN IHNetIcsSettings* IcsSettingsp,
IN OPTIONAL ULONG searchIndex,
IN OPTIONAL USHORT searchPort,
IN OPTIONAL UCHAR searchProtocol,
OUT IHNetPortMappingProtocol **Protocolpp
)
//
// Two ways of Seeking an entry..
// 1) By Index.. Enumerate until you hit the giventh Index.
// 2) Seeks and retrieves Port and ProtocolType
//
{
HRESULT hr = S_OK;
IHNetProtocolSettings* ProtocolSettingsp = NULL;
IEnumHNetPortMappingProtocols* EnumProtocolsp = NULL;
IHNetPortMappingProtocol* tempProtocolp = NULL;
USHORT ProtocolPort = 0;
UCHAR ProtocolType = 0;
BOOLEAN bFound = FALSE;
ULONG iIndex = 0;
DBG_SPEW(TM_STATIC, TL_ERROR, L" > SearchPortMapping ");
//
// Index = 0 is a valid search
// searchPort and searcProtocol should exist both or not.
//
_ASSERT( !((searchPort == NULL) ^ (searchProtocol == 0)) );
_ASSERT( IcsSettingsp != NULL );
_ASSERT( Protocolpp != NULL );
do
{
hr = IcsSettingsp->QueryInterface(IID_IHNetProtocolSettings,
reinterpret_cast<void**>(&ProtocolSettingsp));
if( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Query Interface failed for ProtocolSettingsp E(%X)", hr);
break;
}
hr = ProtocolSettingsp->EnumPortMappingProtocols(&EnumProtocolsp);
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Enum Interface can't be retrieved E(%X)", hr);
break;
}
while( (FALSE == bFound) &&
(S_OK == EnumProtocolsp->Next(1, &tempProtocolp, NULL)) )
{
if ( searchPort != 0 )
{
hr = tempProtocolp->GetPort( &ProtocolPort );
if ( SUCCEEDED(hr) )
{
hr = tempProtocolp->GetIPProtocol(&ProtocolType);
}
if( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Search info Failure E(%X)", hr);
}
else if((searchPort == ProtocolPort) &&
(ProtocolType == searchProtocol))
{
bFound = TRUE;
}
}
else // if the search key == the Index
{
if ( iIndex == searchIndex )
{
bFound = TRUE;
}
}
//
// if Nothing is found
if (FALSE == bFound)
{
tempProtocolp->Release();
}
iIndex++;
}
EnumProtocolsp->Release();
} while ( FALSE );
if(ProtocolSettingsp != NULL)
{
ProtocolSettingsp->Release();
}
if( (bFound == TRUE) &&
(tempProtocolp != NULL))
{
*Protocolpp = tempProtocolp;
}
else
{
return E_INVALIDARG;
}
return hr;
}
HRESULT
FillStaticMappingInformation(
IN IHNetPortMappingProtocol* MappingProtocolp,
IN OPTIONAL IHNetPortMappingBinding* Bindingp,
OUT PUSHORT uExternalPortp,
OUT BSTR* Protocolp,
OUT PUSHORT uInternalPortp,
OUT BSTR* InternalClientp,
OUT VARIANT_BOOL* bEnabledp,
OUT BSTR* Descriptionp
)
//
// Note that Will return the port in Network Byte Order
//
{
HRESULT hr = S_OK;
UCHAR ProtocolType = NULL;
LPOLESTR szInternalHostAddr = NULL;
LPOLESTR szDescription = NULL;
BOOLEAN bEnabled = FALSE;
BOOLEAN bUseName = FALSE;
ULONG InternalHostAddr = 0;
_ASSERT ( uExternalPortp != NULL );
_ASSERT ( Protocolp != NULL );
_ASSERT ( InternalClientp != NULL );
_ASSERT ( bEnabledp != NULL );
_ASSERT ( Descriptionp != NULL );
_ASSERT ( MappingProtocolp != NULL );
_ASSERT ( Bindingp != NULL );
*uExternalPortp = 0;
*Protocolp = NULL;
*InternalClientp = NULL;
*bEnabledp = VARIANT_FALSE;
*Descriptionp = NULL;
DBG_SPEW(TM_STATIC, TL_TRACE, L"> FillStaticMappingInformation");
do
{
//
// Description
//
hr = MappingProtocolp->GetName(&szDescription);
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Getting the Name has failed E(%X)", hr);
break;
}
BOOLEAN fBuiltin = FALSE;
hr = MappingProtocolp->GetBuiltIn( &fBuiltin );
_ASSERT( SUCCEEDED(hr) );
if ( fBuiltin )
{
#define BUILTIN_KEY L" [MICROSOFT]"
UINT uiLength = wcslen(szDescription );
uiLength += wcslen(BUILTIN_KEY);
*Descriptionp = SysAllocStringLen(NULL, uiLength);
if ( *Descriptionp )
{
wcscpy (*Descriptionp, szDescription);
wcscat (*Descriptionp, BUILTIN_KEY);
}
}
else
{
*Descriptionp = SysAllocString(szDescription);
}
if(*Descriptionp == NULL)
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Memory Allocation for Description has Failed");
hr = E_OUTOFMEMORY;
break;
}
//
// Protocol
//
hr = MappingProtocolp->GetIPProtocol(&ProtocolType);
_ASSERT( SUCCEEDED(hr) );
if ( ProtocolType == NAT_PROTOCOL_TCP )
{
*Protocolp = SysAllocString(L"TCP");
}
else if ( ProtocolType == NAT_PROTOCOL_UDP )
{
*Protocolp = SysAllocString(L"UDP");
}
else
{
_ASSERT( FALSE );
}
if (*Protocolp == NULL)
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"Memory Allocation for Description has Failed");
hr = E_OUTOFMEMORY;
break;
}
//
// External Port
//
hr = MappingProtocolp->GetPort( uExternalPortp );
_ASSERT( SUCCEEDED(hr) );
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"GetPort for Protocol has failed E(%X)", hr);
break;
}
// Getting the Binding Information
if ( Bindingp != NULL )
{
//
// Enabled
hr = Bindingp->GetEnabled(&bEnabled);
_ASSERT( SUCCEEDED(hr) );
if ( bEnabled == TRUE)
{
*bEnabledp = VARIANT_TRUE;
}
else
{
*bEnabledp = VARIANT_FALSE;
}
hr = Bindingp->GetTargetPort( uInternalPortp );
_ASSERT( SUCCEEDED(hr) );
if ( FAILED(hr) )
{
DBG_SPEW(TM_STATIC, TL_ERROR,
L"GetPort for Binding has failed E(%X)", hr);
break;
}
//
// InternalClient
hr = Bindingp->GetCurrentMethod(&bUseName);
if( SUCCEEDED(hr) )
{
if ( bUseName == TRUE)
{
hr = Bindingp->GetTargetComputerName(&szInternalHostAddr);
if ( FAILED(hr) )
{
break;
}
_ASSERT( SUCCEEDED(hr) );
}
else
{
hr = Bindingp->GetTargetComputerAddress(&InternalHostAddr);
_ASSERT( SUCCEEDED(hr) );
if ( FAILED(hr) )
{
break;
}
//
// IF the address is Loopback change it to a name which would make more
// sense to any client who sees it.
//
if ( INADDR_LOOPBACK == htonl(InternalHostAddr) )
{
ULONG uCount = 0;
if ( 0 == GetComputerNameEx( ComputerNameDnsHostname, NULL, &uCount) )
{
if ( (ERROR_MORE_DATA == GetLastError()) )
{
szInternalHostAddr =
(LPOLESTR) CoTaskMemAlloc( uCount * sizeof(WCHAR) );
if ( NULL != szInternalHostAddr )
{
if (!GetComputerNameEx(ComputerNameDnsHostname,
szInternalHostAddr,
&uCount))
{
hr = HRESULT_FROM_WIN32( GetLastError() );
break;
}
}
else
{
hr = E_OUTOFMEMORY;
break;
}
}
else
{
hr = E_FAIL;
break;
}
}
}
else if ( 0 != InternalHostAddr )
{
szInternalHostAddr = INET_NTOW_TS( InternalHostAddr );
}
else
{
szInternalHostAddr = (LPOLESTR) CoTaskMemAlloc( sizeof(WCHAR) );
if ( NULL != szInternalHostAddr) szInternalHostAddr[0] = 0;
}
if ( szInternalHostAddr == NULL )
{
hr = E_OUTOFMEMORY;
break;
}
} // if Name method
}
*InternalClientp = SysAllocString( szInternalHostAddr );
if ( *InternalClientp == NULL)
{
DBG_SPEW(TM_STATIC, TL_ERROR, L"Mem Allocation for Internal Client Name");
hr = E_OUTOFMEMORY;
break;
}
} // if bindingp
} while ( FALSE );
if ( szDescription ) CoTaskMemFree( szDescription );
if ( szInternalHostAddr ) CoTaskMemFree( szInternalHostAddr );
if ( FAILED(hr) )
{
if(*Protocolp) { SysFreeString(*Protocolp); *Protocolp = NULL; }
if(*InternalClientp) { SysFreeString(*InternalClientp); *InternalClientp = NULL;}
if(*Descriptionp) { SysFreeString(*Descriptionp); *Descriptionp = NULL;}
}
return hr;
}
inline HRESULT
ValidatePortMappingParameters
(
IN BSTR RemoteHost,
IN USHORT uwExternalPort,
IN BSTR Protocol,
IN USHORT uwInternalPort,
IN BSTR InternalClient,
IN VARIANT_BOOL bEnabled,
IN BSTR Description,
IN ULONG ulLeaseDuration,
OUT MAPPING_TYPE* pMappingType
)
//
// Decide wether a Mapping is to be dynamic or static
// Validate the parameters pre-emptively
//
{
MAPPING_TYPE MappingType = ePortMappingInvalid;
_ASSERT( RemoteHost != NULL );
_ASSERT( Protocol != NULL );
_ASSERT( Protocol[0] != 0 );
_ASSERT( Description != NULL );
_ASSERT( uwInternalPort != 0 );
_ASSERT( pMappingType != NULL );
_ASSERT( InternalClient != NULL );
_ASSERT( RemoteHost[0] == 0 );
//
// An Internal Port as well as an external Port should exist all time
//
if ( (0 == uwInternalPort) || (0 == uwExternalPort) )
{
SetUPnPError(L"716");
return E_INVALIDARG;
}
//
// is this a dynamic request?
//
if ( 0 != ulLeaseDuration )
{
MappingType = ePortMappingDynamic;
}
else
{
MappingType = ePortMappingStatic;
}
//
// A Dynamic Port Mapping needs to be with
// an Internal Client
//
if (
( ePortMappingDynamic == MappingType ) &&
( InternalClient[0] == L'\0' )
)
{
SetUPnPError(L"402");
return E_INVALIDARG;
}
//
// A remote Host is defined.. we can't process this
//
if ( RemoteHost[0] != L'\0' )
{
SetUPnPError(L"726");
return E_INVALIDARG;
}
//
// Check the bEnabled bool value
//
if ( (bEnabled != VARIANT_TRUE) && (bEnabled != VARIANT_FALSE) )
{
SetUPnPError(L"402");
return E_INVALIDARG;
}
*pMappingType = MappingType;
return S_OK;
}