Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

437 lines
15 KiB

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. #include <winsock.h>
  4. // upnp functions
  5. HRESULT TranslateError (HRESULT hr)
  6. {
  7. if ((hr >= UPNP_E_ACTION_SPECIFIC_BASE) &&
  8. (hr <= UPNP_E_ACTION_SPECIFIC_MAX)) {
  9. int iError = FAULT_ACTION_SPECIFIC_BASE - 0x300 + (int)(0xFFFF & hr);
  10. switch (iError) {
  11. case 401: // FAULT_INVALID_ACTION
  12. hr = HRESULT_FROM_WIN32 (ERROR_INVALID_FUNCTION);
  13. break;
  14. case 402: // FAULT_INVALID_ARG
  15. hr = HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER);
  16. break;
  17. case 403: // FAULT_INVALID_SEQUENCE_NUMBER
  18. hr = HRESULT_FROM_WIN32 (ERROR_INVALID_SIGNAL_NUMBER);
  19. break;
  20. case 404: // FAULT_INVALID_VARIABLE
  21. hr = HRESULT_FROM_WIN32 (ERROR_PROC_NOT_FOUND);
  22. break;
  23. case 501: // FAULT_DEVICE_INTERNAL_ERROR
  24. hr = HRESULT_FROM_WIN32 (ERROR_GEN_FAILURE);
  25. break;
  26. default:
  27. _ASSERT (0 && "unknown error");
  28. // fall thru
  29. case 701: // ValueAlreadySpecified: The value specified in the action is already available in the list and is consequently ignored.
  30. case 703: // InactiveConnectionStateRequired: Current value of ConnectionStatus should be either Disconnected or Unconfigured to permit this action.
  31. case 704: // ConnectionSetupFailed: There was a failure in setting up the IP or PPP connection with the service provider. See LastConnectoinError for more details.
  32. case 705: // ConnectionSetupInProgress: The connection is already in the process of being setup
  33. case 706: // ConnectionNotConfigured: Current ConnectionStatus is Unconfigured
  34. case 707: // DisconnectInProgress: The connection is in the process of being torn down.
  35. case 708: // InvalidLayer2Address: Corresponding Link Config service has an invalid VPI/VPC or phone number.
  36. case 709: // InternetAccessDisabled: The EnabledForInternet flag is set to 0.
  37. case 710: // InvalidConnectionType: This command is valid only when ConnectionType is IP-Routed
  38. case 711: // ConnectionAlreadyTerminated: An attempt was made to terminate a connection that is no longer active.
  39. case 715: // WildCardNoPermitedInSrcIP: The source IP address cannot be wild-carded
  40. case 716: // WildCardNotPermittedInExtPort: The external port cannot be wild-carded
  41. case 719: // ActionDisallowedWhenAutoConfigEnabled: The specified action is not permitted when auto configuration is enabled on the modem.
  42. case 720: // InvalidDeviceUUID: the UUID of a device specified in the action arguments is invalid.
  43. case 721: // InvalidServiceID: The Service ID of a service specified in the action arguments in invalid.
  44. case 723: // InvalidConnServiceSelection: The selected connection service instance cannot be set as a default connection.
  45. hr = HRESULT_FROM_WIN32 (ERROR_SERVICE_SPECIFIC_ERROR);
  46. break;
  47. case 702: // ValueSpecifiedIsInvalid: The specified value is not present in the list
  48. hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND);
  49. break;
  50. case 712: // The specified array index holds a NULL value
  51. hr = E_UNEXPECTED; // ?? shouldn't the array compact?
  52. break;
  53. case 713: // The specified array index is out of bounds
  54. case 714: // NoSuchEntryInArray: The specified value does not exist in the array
  55. hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND);
  56. break;
  57. case 718: // ConflictInMappingEntry: The service mapping entry specified conflicts with a mapping assigned previously to another client
  58. hr = HRESULT_FROM_WIN32 (ERROR_BUSY);
  59. break;
  60. case 724: // SamePortValuesRequired: Internal and External port valuse must be the same.
  61. case 725: // OnlyPermanentLeasesSupported: The NAT implementation only supports permanent lease times on port mappings
  62. hr = HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER);
  63. break;
  64. }
  65. }
  66. return hr;
  67. }
  68. HRESULT InvokeAction (IUPnPService * pUPS, CComBSTR & bstrActionName, VARIANT pvIn, VARIANT * pvOut, VARIANT * pvRet)
  69. {
  70. if (!bstrActionName.m_str)
  71. return E_OUTOFMEMORY;
  72. HRESULT hr = pUPS->InvokeAction (bstrActionName, pvIn, pvOut, pvRet);
  73. if (FAILED(hr))
  74. hr = TranslateError (hr);
  75. return hr;
  76. }
  77. HRESULT QueryStateVariable (IUPnPService * pUPS, CComBSTR & bstrVariableName, VARIANT * pvOut)
  78. {
  79. if (!bstrVariableName.m_str)
  80. return E_OUTOFMEMORY;
  81. HRESULT hr = pUPS->QueryStateVariable (bstrVariableName, pvOut);
  82. if (FAILED(hr))
  83. hr = TranslateError (hr);
  84. return hr;
  85. }
  86. HRESULT GetNumberOfEntries (IUPnPService * pUS, ULONG * pul)
  87. {
  88. if (!pul)
  89. return E_POINTER;
  90. *pul = 0;
  91. CComVariant cv;
  92. HRESULT hr = QueryStateVariable (pUS, CComBSTR(L"PortMappingNumberOfEntries"), &cv);
  93. if (SUCCEEDED (hr)) {
  94. if ((V_VT (&cv) != VT_I4) &&
  95. (V_VT (&cv) != VT_UI4)) {
  96. _ASSERT (0 && "bad type from QueryStateVariable (PortMappingNumberOfEntries, ...)?");
  97. hr = E_UNEXPECTED;
  98. } else
  99. *pul = V_UI4 (&cv); // it's a union, so this works in either case
  100. }
  101. return hr;
  102. }
  103. HRESULT GetExternalIPAddress (IUPnPService * pUPS, BSTR * pbstr)
  104. {
  105. SAFEARRAYBOUND rgsaBound[1];
  106. rgsaBound[0].lLbound = 0;
  107. rgsaBound[0].cElements = 0;
  108. SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound);
  109. if (!psa)
  110. return E_OUTOFMEMORY;
  111. CComVariant cvIn;
  112. V_VT (&cvIn) = VT_VARIANT | VT_ARRAY;
  113. V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
  114. CComVariant cvOut, cvRet;
  115. HRESULT hr = InvokeAction (pUPS, CComBSTR(L"GetExternalIPAddress"), cvIn, &cvOut, &cvRet);
  116. if (SUCCEEDED (hr)) {
  117. if (V_VT (&cvOut) != (VT_VARIANT | VT_ARRAY)) {
  118. _ASSERT (0 && "InvokeAction didn't fill out a [out] parameter (properly)!");
  119. hr = E_UNEXPECTED;
  120. } else {
  121. SAFEARRAY * pSA = V_ARRAY (&cvOut);
  122. _ASSERT (pSA);
  123. long lLower = 0, lUpper = -1;
  124. SafeArrayGetLBound (pSA, 1, &lLower);
  125. SafeArrayGetUBound (pSA, 1, &lUpper);
  126. if (lUpper - lLower != 1 - 1)
  127. hr = E_UNEXPECTED;
  128. else {
  129. hr = GetBSTRFromSafeArray (pSA, pbstr, 0);
  130. }
  131. }
  132. }
  133. return hr;
  134. }
  135. // some utils
  136. HRESULT GetOnlyVariantElementFromVariantSafeArray (VARIANT * pvSA, VARIANT * pv)
  137. {
  138. HRESULT hr = S_OK;
  139. if (V_VT (pvSA) != (VT_VARIANT | VT_ARRAY)) {
  140. _ASSERT (0 && "InvokeAction didn't fill out a [out,retval] parameter (properly)!");
  141. hr = E_UNEXPECTED;
  142. } else {
  143. SAFEARRAY * pSA = V_ARRAY (pvSA);
  144. _ASSERT (pSA);
  145. // this should contain a VARIANT that's really a BSTR
  146. long lLower = 0, lUpper = -1;
  147. SafeArrayGetLBound (pSA, 1, &lLower);
  148. SafeArrayGetUBound (pSA, 1, &lUpper);
  149. if (lUpper != lLower)
  150. hr = E_UNEXPECTED;
  151. else
  152. hr = SafeArrayGetElement (pSA, &lLower, (void*)pv);
  153. }
  154. return hr;
  155. }
  156. HRESULT AddToSafeArray (SAFEARRAY * psa, VARIANT * pv, long lIndex)
  157. {
  158. if (V_VT (pv) == VT_ERROR)
  159. return V_ERROR (pv);
  160. return SafeArrayPutElement (psa, &lIndex, (void*)pv);
  161. }
  162. HRESULT GetBSTRFromSafeArray (SAFEARRAY * psa, BSTR * pbstr, long lIndex)
  163. {
  164. *pbstr = NULL;
  165. CComVariant cv;
  166. HRESULT hr = SafeArrayGetElement (psa, &lIndex, (void*)&cv);
  167. if (SUCCEEDED(hr)) {
  168. if (V_VT (&cv) != VT_BSTR)
  169. hr = E_UNEXPECTED;
  170. else {
  171. *pbstr = SysAllocString (V_BSTR (&cv));
  172. if (!*pbstr)
  173. hr = E_OUTOFMEMORY;
  174. }
  175. }
  176. return hr;
  177. }
  178. HRESULT GetLongFromSafeArray (SAFEARRAY * psa, long * pl, long lIndex)
  179. {
  180. *pl = 0;
  181. CComVariant cv;
  182. HRESULT hr = SafeArrayGetElement (psa, &lIndex, (void*)&cv);
  183. if (SUCCEEDED(hr)) {
  184. if ((V_VT (&cv) == VT_I4) || (V_VT (&cv) == VT_UI4))
  185. *pl = V_I4 (&cv); // it's a union, so this works in either case
  186. else
  187. if ((V_VT (&cv) == VT_I2) || (V_VT (&cv) == VT_UI2))
  188. *pl = V_UI2 (&cv); // it's a union, so this works in either case
  189. else
  190. hr = E_UNEXPECTED;
  191. }
  192. return hr;
  193. }
  194. HRESULT GetBoolFromSafeArray (SAFEARRAY * psa, VARIANT_BOOL * pvb, long lIndex)
  195. {
  196. *pvb = 0;
  197. CComVariant cv;
  198. HRESULT hr = SafeArrayGetElement (psa, &lIndex, (void*)&cv);
  199. if (SUCCEEDED(hr)) {
  200. if (V_VT (&cv) != VT_BOOL)
  201. hr = E_UNEXPECTED;
  202. else
  203. *pvb = V_BOOL (&cv);
  204. }
  205. return hr;
  206. }
  207. #ifdef KEEP
  208. HRESULT FindDeviceByType (IUPnPDevices * pUPDs, BSTR bstrType, IUPnPDevice ** ppUPD)
  209. { // finds a device in a collection of devices, by type.
  210. CComPtr<IUnknown> spUnk = NULL;
  211. HRESULT hr = pUPDs->get__NewEnum (&spUnk);
  212. if (spUnk) {
  213. CComPtr<IEnumVARIANT> spEV = NULL;
  214. hr = spUnk->QueryInterface (__uuidof(IEnumVARIANT), (void**)&spEV);
  215. spUnk = NULL; // don't need this anymore
  216. if (spEV) {
  217. CComVariant cv;
  218. while (S_OK == (hr = spEV->Next (1, &cv, NULL))) {
  219. if (V_VT (&cv) == VT_DISPATCH) {
  220. CComPtr<IUPnPDevice> spUPD = NULL;
  221. hr = V_DISPATCH (&cv)->QueryInterface (
  222. __uuidof(IUPnPDevice),
  223. (void**)&spUPD);
  224. if (spUPD) {
  225. // see if this device is of the right type
  226. CComBSTR cb;
  227. spUPD->get_Type (&cb);
  228. if (cb == bstrType) {
  229. // found it!
  230. return spUPD->QueryInterface (
  231. __uuidof(IUPnPDevice),
  232. (void**)ppUPD);
  233. }
  234. }
  235. }
  236. cv.Clear();
  237. }
  238. }
  239. }
  240. // if we got here, we either didn't find it, or there was an error
  241. if (SUCCEEDED(hr))
  242. hr = HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND);
  243. return hr;
  244. }
  245. HRESULT GetOnlyChildDevice (IUPnPDevice * pParent, IUPnPDevice ** ppChild)
  246. {
  247. *ppChild = NULL;
  248. CComPtr<IUPnPDevices> spUPDs = NULL;
  249. HRESULT hr = pParent->get_Children (&spUPDs);
  250. if (spUPDs) {
  251. long lCount = 0;
  252. spUPDs->get_Count (&lCount);
  253. if (lCount != 1)
  254. return E_INVALIDARG;
  255. CComPtr<IUnknown> spUnk = NULL;
  256. hr = spUPDs->get__NewEnum (&spUnk);
  257. if (spUnk) {
  258. CComPtr<IEnumVARIANT> spEV = NULL;
  259. hr = spUnk->QueryInterface (__uuidof(IEnumVARIANT), (void**)&spEV);
  260. if (spEV) {
  261. spEV->Reset(); // probably not necessary
  262. CComVariant cv;
  263. hr = spEV->Next (1, &cv, NULL);
  264. if (hr == S_OK) {
  265. if (V_VT (&cv) != VT_DISPATCH)
  266. hr = E_FAIL;
  267. else {
  268. hr = V_DISPATCH (&cv)->QueryInterface (
  269. __uuidof(IUPnPDevice),
  270. (void**)ppChild);
  271. }
  272. }
  273. }
  274. }
  275. }
  276. return hr;
  277. }
  278. #endif
  279. NETCON_MEDIATYPE GetMediaType (INetConnection * pNC)
  280. {
  281. NETCON_PROPERTIES* pProps = NULL;
  282. pNC->GetProperties (&pProps);
  283. if (pProps) {
  284. NETCON_MEDIATYPE MediaType = pProps->MediaType;
  285. NcFreeNetconProperties (pProps);
  286. return MediaType;
  287. }
  288. return NCM_NONE;
  289. }
  290. HRESULT AddPortMapping (IUPnPService * pUPS,
  291. BSTR bstrRemoteHost,
  292. long lExternalPort,
  293. BSTR bstrProtocol,
  294. long lInternalPort,
  295. BSTR bstrInternalClient,
  296. VARIANT_BOOL vbEnabled,
  297. BSTR bstrDescription,
  298. long lLeaseDurationDesired)
  299. {
  300. // special handling for loopback and localhost
  301. CComBSTR cbInternalClient;
  302. USES_CONVERSION;
  303. #define LOOPBACK_ADDR 0x0100007f
  304. if ((LOOPBACK_ADDR == inet_addr (OLE2A (bstrInternalClient))) ||
  305. (!_wcsicmp (bstrInternalClient, L"localhost"))) {
  306. // use computer name, using A version
  307. CHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  308. DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
  309. if (!GetComputerNameA (szComputerName, &dwSize))
  310. return HRESULT_FROM_WIN32(GetLastError());
  311. else {
  312. cbInternalClient = A2OLE(szComputerName);
  313. }
  314. } else {
  315. cbInternalClient = bstrInternalClient;
  316. }
  317. if (!cbInternalClient.m_str)
  318. return E_OUTOFMEMORY;
  319. SAFEARRAYBOUND rgsaBound[1];
  320. rgsaBound[0].lLbound = 0;
  321. rgsaBound[0].cElements = 8;
  322. SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound);
  323. if (!psa)
  324. return E_OUTOFMEMORY;
  325. CComVariant cvIn;
  326. V_VT (&cvIn) = VT_VARIANT | VT_ARRAY;
  327. V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
  328. HRESULT
  329. hr = AddToSafeArray (psa, &CComVariant(bstrRemoteHost), 0);
  330. if (SUCCEEDED(hr))
  331. hr = AddToSafeArray (psa, &CComVariant(lExternalPort), 1);
  332. if (SUCCEEDED(hr))
  333. hr = AddToSafeArray (psa, &CComVariant(bstrProtocol), 2);
  334. if (SUCCEEDED(hr))
  335. hr = AddToSafeArray (psa, &CComVariant(lInternalPort), 3);
  336. if (SUCCEEDED(hr))
  337. hr = AddToSafeArray (psa, &CComVariant(cbInternalClient), 4);
  338. if (SUCCEEDED(hr))
  339. hr = AddToSafeArray (psa, &CComVariant((bool)!!vbEnabled), 5);
  340. if (SUCCEEDED(hr))
  341. hr = AddToSafeArray (psa, &CComVariant(bstrDescription), 6);
  342. if (SUCCEEDED(hr))
  343. hr = AddToSafeArray (psa, &CComVariant(lLeaseDurationDesired), 7);
  344. if (SUCCEEDED(hr)) {
  345. CComVariant cvOut, cvRet;
  346. hr = InvokeAction (pUPS, CComBSTR(L"AddPortMapping"), cvIn, &cvOut, &cvRet);
  347. }
  348. return hr;
  349. }
  350. HRESULT DeletePortMapping (IUPnPService * pUPS,
  351. BSTR bstrRemoteHost,
  352. long lExternalPort,
  353. BSTR bstrProtocol)
  354. {
  355. if (!bstrRemoteHost)
  356. return E_INVALIDARG;
  357. if ((lExternalPort < 0) || (lExternalPort > 65535))
  358. return E_INVALIDARG;
  359. if (!bstrProtocol)
  360. return E_INVALIDARG;
  361. if (wcscmp (bstrProtocol, L"TCP") && wcscmp (bstrProtocol, L"UDP"))
  362. return E_INVALIDARG;
  363. SAFEARRAYBOUND rgsaBound[1];
  364. rgsaBound[0].lLbound = 0;
  365. rgsaBound[0].cElements = 3;
  366. SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound);
  367. if (!psa)
  368. return E_OUTOFMEMORY;
  369. CComVariant cvIn;
  370. V_VT (&cvIn) = VT_VARIANT | VT_ARRAY;
  371. V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
  372. HRESULT
  373. hr = AddToSafeArray (psa, &CComVariant(bstrRemoteHost), 0);
  374. if (SUCCEEDED(hr))
  375. hr = AddToSafeArray (psa, &CComVariant(lExternalPort), 1);
  376. if (SUCCEEDED(hr))
  377. hr = AddToSafeArray (psa, &CComVariant(bstrProtocol), 2);
  378. if (SUCCEEDED(hr)) {
  379. CComVariant cvOut, cvRet;
  380. hr = InvokeAction (pUPS, CComBSTR(L"DeletePortMapping"), cvIn, &cvOut, &cvRet);
  381. // no [out] or [out,retval] paramters
  382. }
  383. return hr;
  384. }