|
|
#include "stdafx.h"
#pragma hdrstop
#include <winsock.h>
// upnp functions
HRESULT TranslateError (HRESULT hr) { if ((hr >= UPNP_E_ACTION_SPECIFIC_BASE) && (hr <= UPNP_E_ACTION_SPECIFIC_MAX)) {
int iError = FAULT_ACTION_SPECIFIC_BASE - 0x300 + (int)(0xFFFF & hr); switch (iError) { case 401: // FAULT_INVALID_ACTION
hr = HRESULT_FROM_WIN32 (ERROR_INVALID_FUNCTION); break;
case 402: // FAULT_INVALID_ARG
hr = HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER); break;
case 403: // FAULT_INVALID_SEQUENCE_NUMBER
hr = HRESULT_FROM_WIN32 (ERROR_INVALID_SIGNAL_NUMBER); break;
case 404: // FAULT_INVALID_VARIABLE
hr = HRESULT_FROM_WIN32 (ERROR_PROC_NOT_FOUND); break;
case 501: // FAULT_DEVICE_INTERNAL_ERROR
hr = HRESULT_FROM_WIN32 (ERROR_GEN_FAILURE); break;
default: _ASSERT (0 && "unknown error"); // fall thru
case 701: // ValueAlreadySpecified: The value specified in the action is already available in the list and is consequently ignored.
case 703: // InactiveConnectionStateRequired: Current value of ConnectionStatus should be either Disconnected or Unconfigured to permit this action.
case 704: // ConnectionSetupFailed: There was a failure in setting up the IP or PPP connection with the service provider. See LastConnectoinError for more details.
case 705: // ConnectionSetupInProgress: The connection is already in the process of being setup
case 706: // ConnectionNotConfigured: Current ConnectionStatus is Unconfigured
case 707: // DisconnectInProgress: The connection is in the process of being torn down.
case 708: // InvalidLayer2Address: Corresponding Link Config service has an invalid VPI/VPC or phone number.
case 709: // InternetAccessDisabled: The EnabledForInternet flag is set to 0.
case 710: // InvalidConnectionType: This command is valid only when ConnectionType is IP-Routed
case 711: // ConnectionAlreadyTerminated: An attempt was made to terminate a connection that is no longer active.
case 715: // WildCardNoPermitedInSrcIP: The source IP address cannot be wild-carded
case 716: // WildCardNotPermittedInExtPort: The external port cannot be wild-carded
case 719: // ActionDisallowedWhenAutoConfigEnabled: The specified action is not permitted when auto configuration is enabled on the modem.
case 720: // InvalidDeviceUUID: the UUID of a device specified in the action arguments is invalid.
case 721: // InvalidServiceID: The Service ID of a service specified in the action arguments in invalid.
case 723: // InvalidConnServiceSelection: The selected connection service instance cannot be set as a default connection.
hr = HRESULT_FROM_WIN32 (ERROR_SERVICE_SPECIFIC_ERROR); break;
case 702: // ValueSpecifiedIsInvalid: The specified value is not present in the list
hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND); break;
case 712: // The specified array index holds a NULL value
hr = E_UNEXPECTED; // ?? shouldn't the array compact?
break;
case 713: // The specified array index is out of bounds
case 714: // NoSuchEntryInArray: The specified value does not exist in the array
hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND); break;
case 718: // ConflictInMappingEntry: The service mapping entry specified conflicts with a mapping assigned previously to another client
hr = HRESULT_FROM_WIN32 (ERROR_BUSY); break;
case 724: // SamePortValuesRequired: Internal and External port valuse must be the same.
case 725: // OnlyPermanentLeasesSupported: The NAT implementation only supports permanent lease times on port mappings
hr = HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER); break;
} } return hr; }
HRESULT InvokeAction (IUPnPService * pUPS, CComBSTR & bstrActionName, VARIANT pvIn, VARIANT * pvOut, VARIANT * pvRet) { if (!bstrActionName.m_str) return E_OUTOFMEMORY;
HRESULT hr = pUPS->InvokeAction (bstrActionName, pvIn, pvOut, pvRet); if (FAILED(hr)) hr = TranslateError (hr); return hr; }
HRESULT QueryStateVariable (IUPnPService * pUPS, CComBSTR & bstrVariableName, VARIANT * pvOut) { if (!bstrVariableName.m_str) return E_OUTOFMEMORY;
HRESULT hr = pUPS->QueryStateVariable (bstrVariableName, pvOut); if (FAILED(hr)) hr = TranslateError (hr); return hr; }
HRESULT GetNumberOfEntries (IUPnPService * pUS, ULONG * pul) { if (!pul) return E_POINTER; *pul = 0;
CComVariant cv; HRESULT hr = QueryStateVariable (pUS, CComBSTR(L"PortMappingNumberOfEntries"), &cv); if (SUCCEEDED (hr)) {
if ((V_VT (&cv) != VT_I4) && (V_VT (&cv) != VT_UI4)) { _ASSERT (0 && "bad type from QueryStateVariable (PortMappingNumberOfEntries, ...)?"); hr = E_UNEXPECTED; } else *pul = V_UI4 (&cv); // it's a union, so this works in either case
} return hr; }
HRESULT GetExternalIPAddress (IUPnPService * pUPS, BSTR * pbstr) { SAFEARRAYBOUND rgsaBound[1]; rgsaBound[0].lLbound = 0; rgsaBound[0].cElements = 0; SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound); if (!psa) return E_OUTOFMEMORY;
CComVariant cvIn; V_VT (&cvIn) = VT_VARIANT | VT_ARRAY; V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
CComVariant cvOut, cvRet; HRESULT hr = InvokeAction (pUPS, CComBSTR(L"GetExternalIPAddress"), cvIn, &cvOut, &cvRet); if (SUCCEEDED (hr)) { if (V_VT (&cvOut) != (VT_VARIANT | VT_ARRAY)) { _ASSERT (0 && "InvokeAction didn't fill out a [out] parameter (properly)!"); hr = E_UNEXPECTED; } else { SAFEARRAY * pSA = V_ARRAY (&cvOut); _ASSERT (pSA);
long lLower = 0, lUpper = -1; SafeArrayGetLBound (pSA, 1, &lLower); SafeArrayGetUBound (pSA, 1, &lUpper); if (lUpper - lLower != 1 - 1) hr = E_UNEXPECTED; else { hr = GetBSTRFromSafeArray (pSA, pbstr, 0); } } } return hr; }
// some utils
HRESULT GetOnlyVariantElementFromVariantSafeArray (VARIANT * pvSA, VARIANT * pv) { HRESULT hr = S_OK; if (V_VT (pvSA) != (VT_VARIANT | VT_ARRAY)) { _ASSERT (0 && "InvokeAction didn't fill out a [out,retval] parameter (properly)!"); hr = E_UNEXPECTED; } else { SAFEARRAY * pSA = V_ARRAY (pvSA); _ASSERT (pSA); // this should contain a VARIANT that's really a BSTR
long lLower = 0, lUpper = -1; SafeArrayGetLBound (pSA, 1, &lLower); SafeArrayGetUBound (pSA, 1, &lUpper); if (lUpper != lLower) hr = E_UNEXPECTED; else hr = SafeArrayGetElement (pSA, &lLower, (void*)pv); } return hr; }
HRESULT AddToSafeArray (SAFEARRAY * psa, VARIANT * pv, long lIndex) { if (V_VT (pv) == VT_ERROR) return V_ERROR (pv); return SafeArrayPutElement (psa, &lIndex, (void*)pv); }
HRESULT GetBSTRFromSafeArray (SAFEARRAY * psa, BSTR * pbstr, long lIndex) { *pbstr = NULL;
CComVariant cv; HRESULT hr = SafeArrayGetElement (psa, &lIndex, (void*)&cv); if (SUCCEEDED(hr)) { if (V_VT (&cv) != VT_BSTR) hr = E_UNEXPECTED; else { *pbstr = SysAllocString (V_BSTR (&cv)); if (!*pbstr) hr = E_OUTOFMEMORY; } } return hr; }
HRESULT GetLongFromSafeArray (SAFEARRAY * psa, long * pl, long lIndex) { *pl = 0;
CComVariant cv; HRESULT hr = SafeArrayGetElement (psa, &lIndex, (void*)&cv); if (SUCCEEDED(hr)) { if ((V_VT (&cv) == VT_I4) || (V_VT (&cv) == VT_UI4)) *pl = V_I4 (&cv); // it's a union, so this works in either case
else if ((V_VT (&cv) == VT_I2) || (V_VT (&cv) == VT_UI2)) *pl = V_UI2 (&cv); // it's a union, so this works in either case
else hr = E_UNEXPECTED; } return hr; }
HRESULT GetBoolFromSafeArray (SAFEARRAY * psa, VARIANT_BOOL * pvb, long lIndex) { *pvb = 0;
CComVariant cv; HRESULT hr = SafeArrayGetElement (psa, &lIndex, (void*)&cv); if (SUCCEEDED(hr)) { if (V_VT (&cv) != VT_BOOL) hr = E_UNEXPECTED; else *pvb = V_BOOL (&cv); } return hr; }
#ifdef KEEP
HRESULT FindDeviceByType (IUPnPDevices * pUPDs, BSTR bstrType, IUPnPDevice ** ppUPD) { // finds a device in a collection of devices, by type.
CComPtr<IUnknown> spUnk = NULL; HRESULT hr = pUPDs->get__NewEnum (&spUnk); if (spUnk) { CComPtr<IEnumVARIANT> spEV = NULL; hr = spUnk->QueryInterface (__uuidof(IEnumVARIANT), (void**)&spEV); spUnk = NULL; // don't need this anymore
if (spEV) { CComVariant cv; while (S_OK == (hr = spEV->Next (1, &cv, NULL))) { if (V_VT (&cv) == VT_DISPATCH) { CComPtr<IUPnPDevice> spUPD = NULL; hr = V_DISPATCH (&cv)->QueryInterface ( __uuidof(IUPnPDevice), (void**)&spUPD); if (spUPD) { // see if this device is of the right type
CComBSTR cb; spUPD->get_Type (&cb); if (cb == bstrType) { // found it!
return spUPD->QueryInterface ( __uuidof(IUPnPDevice), (void**)ppUPD); } } } cv.Clear(); } } } // if we got here, we either didn't find it, or there was an error
if (SUCCEEDED(hr)) hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND); return hr; }
HRESULT GetOnlyChildDevice (IUPnPDevice * pParent, IUPnPDevice ** ppChild) { *ppChild = NULL;
CComPtr<IUPnPDevices> spUPDs = NULL; HRESULT hr = pParent->get_Children (&spUPDs); if (spUPDs) { long lCount = 0; spUPDs->get_Count (&lCount); if (lCount != 1) return E_INVALIDARG;
CComPtr<IUnknown> spUnk = NULL; hr = spUPDs->get__NewEnum (&spUnk); if (spUnk) { CComPtr<IEnumVARIANT> spEV = NULL; hr = spUnk->QueryInterface (__uuidof(IEnumVARIANT), (void**)&spEV); if (spEV) { spEV->Reset(); // probably not necessary
CComVariant cv; hr = spEV->Next (1, &cv, NULL); if (hr == S_OK) { if (V_VT (&cv) != VT_DISPATCH) hr = E_FAIL; else { hr = V_DISPATCH (&cv)->QueryInterface ( __uuidof(IUPnPDevice), (void**)ppChild); } } } } } return hr; } #endif
NETCON_MEDIATYPE GetMediaType (INetConnection * pNC) { NETCON_PROPERTIES* pProps = NULL; pNC->GetProperties (&pProps); if (pProps) { NETCON_MEDIATYPE MediaType = pProps->MediaType; NcFreeNetconProperties (pProps); return MediaType; } return NCM_NONE; }
HRESULT AddPortMapping (IUPnPService * pUPS, BSTR bstrRemoteHost, long lExternalPort, BSTR bstrProtocol, long lInternalPort, BSTR bstrInternalClient, VARIANT_BOOL vbEnabled, BSTR bstrDescription, long lLeaseDurationDesired) { // special handling for loopback and localhost
CComBSTR cbInternalClient; USES_CONVERSION; #define LOOPBACK_ADDR 0x0100007f
if ((LOOPBACK_ADDR == inet_addr (OLE2A (bstrInternalClient))) || (!_wcsicmp (bstrInternalClient, L"localhost"))) { // use computer name, using A version
CHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1]; DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1; if (!GetComputerNameA (szComputerName, &dwSize)) return HRESULT_FROM_WIN32(GetLastError()); else { cbInternalClient = A2OLE(szComputerName); } } else { cbInternalClient = bstrInternalClient; } if (!cbInternalClient.m_str) return E_OUTOFMEMORY;
SAFEARRAYBOUND rgsaBound[1]; rgsaBound[0].lLbound = 0; rgsaBound[0].cElements = 8; SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound); if (!psa) return E_OUTOFMEMORY;
CComVariant cvIn; V_VT (&cvIn) = VT_VARIANT | VT_ARRAY; V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
HRESULT hr = AddToSafeArray (psa, &CComVariant(bstrRemoteHost), 0); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(lExternalPort), 1); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(bstrProtocol), 2); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(lInternalPort), 3); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(cbInternalClient), 4); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant((bool)!!vbEnabled), 5); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(bstrDescription), 6); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(lLeaseDurationDesired), 7);
if (SUCCEEDED(hr)) { CComVariant cvOut, cvRet; hr = InvokeAction (pUPS, CComBSTR(L"AddPortMapping"), cvIn, &cvOut, &cvRet); } return hr; }
HRESULT DeletePortMapping (IUPnPService * pUPS, BSTR bstrRemoteHost, long lExternalPort, BSTR bstrProtocol) { if (!bstrRemoteHost) return E_INVALIDARG; if ((lExternalPort < 0) || (lExternalPort > 65535)) return E_INVALIDARG; if (!bstrProtocol) return E_INVALIDARG; if (wcscmp (bstrProtocol, L"TCP") && wcscmp (bstrProtocol, L"UDP")) return E_INVALIDARG;
SAFEARRAYBOUND rgsaBound[1]; rgsaBound[0].lLbound = 0; rgsaBound[0].cElements = 3; SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound); if (!psa) return E_OUTOFMEMORY;
CComVariant cvIn; V_VT (&cvIn) = VT_VARIANT | VT_ARRAY; V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
HRESULT hr = AddToSafeArray (psa, &CComVariant(bstrRemoteHost), 0); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(lExternalPort), 1); if (SUCCEEDED(hr)) hr = AddToSafeArray (psa, &CComVariant(bstrProtocol), 2);
if (SUCCEEDED(hr)) { CComVariant cvOut, cvRet; hr = InvokeAction (pUPS, CComBSTR(L"DeletePortMapping"), cvIn, &cvOut, &cvRet); // no [out] or [out,retval] paramters
} return hr; }
|