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.

580 lines
16 KiB

  1. // DPortMap.cpp : Implementation of CDynamicPortMapping
  2. #include "stdafx.h"
  3. #pragma hdrstop
  4. #include "NATUPnP.h"
  5. #include "DPortMap.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. // CDynamicPortMapping
  8. STDMETHODIMP CDynamicPortMapping::get_ExternalIPAddress (BSTR *pVal)
  9. {
  10. NAT_API_ENTER
  11. if (!pVal)
  12. return E_POINTER;
  13. *pVal = NULL;
  14. return GetExternalIPAddress (m_spUPS, pVal);
  15. NAT_API_LEAVE
  16. }
  17. STDMETHODIMP CDynamicPortMapping::get_LeaseDuration (long *pVal)
  18. {
  19. NAT_API_ENTER
  20. if (!pVal)
  21. return E_POINTER;
  22. *pVal = 0;
  23. // live
  24. return GetAllData (pVal);
  25. NAT_API_LEAVE
  26. }
  27. STDMETHODIMP CDynamicPortMapping::get_RemoteHost (BSTR *pVal)
  28. {
  29. NAT_API_ENTER
  30. if (!pVal)
  31. return E_POINTER;
  32. *pVal = NULL;
  33. if (m_eComplete != eAllData) {
  34. HRESULT hr = GetAllData ();
  35. if (FAILED(hr))
  36. return hr;
  37. }
  38. *pVal = SysAllocString (m_cbRemoteHost); // "" == wildcard (for static)
  39. if (!*pVal)
  40. return E_OUTOFMEMORY;
  41. return S_OK;
  42. NAT_API_LEAVE
  43. }
  44. STDMETHODIMP CDynamicPortMapping::get_ExternalPort (long *pVal)
  45. {
  46. NAT_API_ENTER
  47. if (!pVal)
  48. return E_POINTER;
  49. *pVal = 0;
  50. if (m_eComplete != eAllData) {
  51. HRESULT hr = GetAllData ();
  52. if (FAILED(hr))
  53. return hr;
  54. }
  55. *pVal = m_lExternalPort;
  56. return S_OK;
  57. NAT_API_LEAVE
  58. }
  59. STDMETHODIMP CDynamicPortMapping::get_Protocol (BSTR *pVal)
  60. {
  61. NAT_API_ENTER
  62. if (!pVal)
  63. return E_POINTER;
  64. *pVal = NULL;
  65. if (m_eComplete != eAllData) {
  66. HRESULT hr = GetAllData ();
  67. if (FAILED(hr))
  68. return hr;
  69. }
  70. *pVal = SysAllocString (m_cbProtocol); // "TCP" or "UDP"
  71. if (!*pVal)
  72. return E_OUTOFMEMORY;
  73. return S_OK;
  74. NAT_API_LEAVE
  75. }
  76. STDMETHODIMP CDynamicPortMapping::get_InternalPort (long *pVal)
  77. {
  78. NAT_API_ENTER
  79. if (!pVal)
  80. return E_POINTER;
  81. *pVal = 0;
  82. if (m_eComplete != eAllData) {
  83. HRESULT hr = GetAllData ();
  84. if (FAILED(hr))
  85. return hr;
  86. }
  87. *pVal = m_lInternalPort;
  88. return S_OK;
  89. NAT_API_LEAVE
  90. }
  91. STDMETHODIMP CDynamicPortMapping::get_InternalClient (BSTR *pVal)
  92. {
  93. NAT_API_ENTER
  94. if (!pVal)
  95. return E_POINTER;
  96. *pVal = NULL;
  97. if (m_eComplete != eAllData) {
  98. HRESULT hr = GetAllData ();
  99. if (FAILED(hr))
  100. return hr;
  101. }
  102. *pVal = SysAllocString (m_cbInternalClient);
  103. if (!*pVal)
  104. return E_OUTOFMEMORY;
  105. return S_OK;
  106. NAT_API_LEAVE
  107. }
  108. STDMETHODIMP CDynamicPortMapping::get_Enabled (VARIANT_BOOL *pVal)
  109. {
  110. NAT_API_ENTER
  111. if (!pVal)
  112. return E_POINTER;
  113. *pVal = VARIANT_FALSE; // REVIEW: true?
  114. if (m_eComplete != eAllData) {
  115. HRESULT hr = GetAllData ();
  116. if (FAILED(hr))
  117. return hr;
  118. }
  119. *pVal = m_vbEnabled;
  120. return S_OK;
  121. NAT_API_LEAVE
  122. }
  123. STDMETHODIMP CDynamicPortMapping::get_Description (BSTR *pVal)
  124. {
  125. NAT_API_ENTER
  126. if (!pVal)
  127. return E_POINTER;
  128. *pVal = NULL;
  129. if (m_eComplete != eAllData) {
  130. HRESULT hr = GetAllData ();
  131. if (FAILED(hr))
  132. return hr;
  133. }
  134. *pVal = SysAllocString (m_cbDescription);
  135. if (!*pVal)
  136. return E_OUTOFMEMORY;
  137. return S_OK;
  138. NAT_API_LEAVE
  139. }
  140. STDMETHODIMP CDynamicPortMapping::RenewLease (long lLeaseDurationDesired, long * pLeaseDurationReturned)
  141. {
  142. NAT_API_ENTER
  143. if (!pLeaseDurationReturned)
  144. return E_POINTER;
  145. *pLeaseDurationReturned = 0;
  146. HRESULT hr;
  147. if (m_eComplete != eAllData) {
  148. HRESULT hr = GetAllData ();
  149. if (FAILED(hr))
  150. return hr;
  151. }
  152. hr = AddPortMapping (m_spUPS,
  153. m_cbRemoteHost,
  154. m_lExternalPort,
  155. m_cbProtocol,
  156. m_lInternalPort,
  157. m_cbInternalClient,
  158. m_vbEnabled,
  159. m_cbDescription,
  160. lLeaseDurationDesired);
  161. if (SUCCEEDED(hr))
  162. hr = get_LeaseDuration (pLeaseDurationReturned);
  163. return hr;
  164. NAT_API_LEAVE
  165. }
  166. static BOOL IsBuiltIn (BSTR bstrDescription)
  167. {
  168. #define BUILTIN_KEY L" [MICROSOFT]"
  169. OLECHAR * tmp = wcsstr (bstrDescription, BUILTIN_KEY);
  170. if (tmp && (tmp[wcslen(BUILTIN_KEY)] == 0))
  171. return TRUE;
  172. return FALSE;
  173. }
  174. HRESULT CDynamicPortMapping::EditInternalClient (BSTR bstrInternalClient)
  175. {
  176. NAT_API_ENTER
  177. if (!bstrInternalClient)
  178. return E_INVALIDARG;
  179. long lLease = 0;
  180. HRESULT hr = get_LeaseDuration (&lLease);
  181. if (SUCCEEDED(hr)) {
  182. if (IsBuiltIn (m_cbDescription)) {
  183. // built-in mappings can't be deleted.
  184. // if enabled, I won't be able to edit the internal client.
  185. // so, disable it first. Note that this must be done after
  186. // the call to get_LeaseDuration so that all the data is up-to-date.
  187. VARIANT_BOOL vbEnabled = m_vbEnabled; // put in local variable, so I can change it back
  188. if (m_vbEnabled == VARIANT_TRUE)
  189. hr = Enable (VARIANT_FALSE);
  190. if (SUCCEEDED(hr)) {
  191. hr = AddPortMapping (m_spUPS,
  192. m_cbRemoteHost,
  193. m_lExternalPort,
  194. m_cbProtocol,
  195. m_lInternalPort,
  196. bstrInternalClient,
  197. vbEnabled,
  198. m_cbDescription,
  199. lLease);
  200. if (SUCCEEDED(hr))
  201. m_vbEnabled = vbEnabled;
  202. }
  203. } else {
  204. hr = DeletePortMapping (m_spUPS,
  205. m_cbRemoteHost,
  206. m_lExternalPort,
  207. m_cbProtocol);
  208. if (SUCCEEDED(hr))
  209. hr = AddPortMapping (m_spUPS,
  210. m_cbRemoteHost,
  211. m_lExternalPort,
  212. m_cbProtocol,
  213. m_lInternalPort,
  214. bstrInternalClient,
  215. m_vbEnabled,
  216. m_cbDescription,
  217. lLease);
  218. }
  219. if (SUCCEEDED(hr)) {
  220. m_cbInternalClient = bstrInternalClient;
  221. if (!m_cbInternalClient.m_str)
  222. return E_OUTOFMEMORY;
  223. }
  224. }
  225. return hr;
  226. NAT_API_LEAVE
  227. }
  228. HRESULT CDynamicPortMapping::Enable (VARIANT_BOOL vb)
  229. {
  230. NAT_API_ENTER
  231. long lLease = 0;
  232. HRESULT hr = get_LeaseDuration (&lLease);
  233. if (SUCCEEDED(hr)) {
  234. hr = AddPortMapping (m_spUPS,
  235. m_cbRemoteHost,
  236. m_lExternalPort,
  237. m_cbProtocol,
  238. m_lInternalPort,
  239. m_cbInternalClient,
  240. vb,
  241. m_cbDescription,
  242. lLease);
  243. if (SUCCEEDED(hr))
  244. m_vbEnabled = vb;
  245. }
  246. return hr;
  247. NAT_API_LEAVE
  248. }
  249. HRESULT CDynamicPortMapping::EditDescription (BSTR bstrDescription)
  250. {
  251. NAT_API_ENTER
  252. if (!bstrDescription)
  253. return E_INVALIDARG;
  254. long lLease = 0;
  255. HRESULT hr = get_LeaseDuration (&lLease);
  256. if (SUCCEEDED(hr)) {
  257. hr = AddPortMapping (m_spUPS,
  258. m_cbRemoteHost,
  259. m_lExternalPort,
  260. m_cbProtocol,
  261. m_lInternalPort,
  262. m_cbInternalClient,
  263. m_vbEnabled,
  264. bstrDescription,
  265. lLease);
  266. if (SUCCEEDED(hr)) {
  267. m_cbDescription = bstrDescription;
  268. if (!m_cbDescription.m_str)
  269. return E_OUTOFMEMORY;
  270. }
  271. }
  272. return hr;
  273. NAT_API_LEAVE
  274. }
  275. HRESULT CDynamicPortMapping::EditInternalPort (long lInternalPort)
  276. {
  277. NAT_API_ENTER
  278. if ((lInternalPort < 0) || (lInternalPort > 65535))
  279. return E_INVALIDARG;
  280. long lLease = 0;
  281. HRESULT hr = get_LeaseDuration (&lLease);
  282. if (SUCCEEDED(hr)) {
  283. hr = AddPortMapping (m_spUPS,
  284. m_cbRemoteHost,
  285. m_lExternalPort,
  286. m_cbProtocol,
  287. lInternalPort,
  288. m_cbInternalClient,
  289. m_vbEnabled,
  290. m_cbDescription,
  291. lLease);
  292. if (SUCCEEDED(hr))
  293. m_lInternalPort = lInternalPort;
  294. }
  295. return hr;
  296. NAT_API_LEAVE
  297. }
  298. HRESULT CDynamicPortMapping::GetAllData (long * pLease)
  299. {
  300. if (pLease)
  301. *pLease = NULL;
  302. _ASSERT (m_cbRemoteHost);
  303. _ASSERT (m_lExternalPort != 0);
  304. _ASSERT (m_cbProtocol);
  305. SAFEARRAYBOUND rgsaBound[1];
  306. rgsaBound[0].lLbound = 0;
  307. rgsaBound[0].cElements = 3;
  308. SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound);
  309. if (!psa)
  310. return E_OUTOFMEMORY;
  311. CComVariant cvIn;
  312. V_VT (&cvIn) = VT_VARIANT | VT_ARRAY;
  313. V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
  314. HRESULT
  315. hr = AddToSafeArray (psa, &CComVariant(m_cbRemoteHost), 0);
  316. if (SUCCEEDED(hr))
  317. hr = AddToSafeArray (psa, &CComVariant(m_lExternalPort), 1);
  318. if (SUCCEEDED(hr))
  319. hr = AddToSafeArray (psa, &CComVariant(m_cbProtocol), 2);
  320. if (SUCCEEDED(hr)) {
  321. CComVariant cvOut, cvRet;
  322. hr = InvokeAction (m_spUPS, CComBSTR(L"GetSpecificPortMappingEntry"), cvIn, &cvOut, &cvRet);
  323. if (SUCCEEDED(hr)) {
  324. if (V_VT (&cvOut) != (VT_VARIANT | VT_ARRAY)) {
  325. _ASSERT (0 && "InvokeAction didn't fill out a [out] parameter (properly)!");
  326. hr = E_UNEXPECTED;
  327. } else {
  328. SAFEARRAY * pSA = V_ARRAY (&cvOut);
  329. _ASSERT (pSA);
  330. long lLower = 0, lUpper = -1;
  331. SafeArrayGetLBound (pSA, 1, &lLower);
  332. SafeArrayGetUBound (pSA, 1, &lUpper);
  333. if (lUpper - lLower != 5 - 1)
  334. hr = E_UNEXPECTED;
  335. else {
  336. hr = GetLongFromSafeArray (pSA, &m_lInternalPort, 0);
  337. if (SUCCEEDED(hr)) {
  338. m_cbInternalClient.Empty();
  339. hr = GetBSTRFromSafeArray (pSA, &m_cbInternalClient, 1);
  340. if (SUCCEEDED(hr)) {
  341. hr = GetBoolFromSafeArray (pSA, &m_vbEnabled, 2);
  342. if (SUCCEEDED(hr)) {
  343. m_cbDescription.Empty();
  344. hr = GetBSTRFromSafeArray (pSA, &m_cbDescription, 3);
  345. if (SUCCEEDED(hr)) {
  346. if (pLease)
  347. hr = GetLongFromSafeArray (pSA, pLease, 4);
  348. }
  349. }
  350. }
  351. }
  352. }
  353. }
  354. }
  355. }
  356. if (SUCCEEDED(hr))
  357. m_eComplete = eAllData;
  358. return hr;
  359. }
  360. HRESULT CDynamicPortMapping::CreateInstance (IUPnPService * pUPS, long lIndex, IDynamicPortMapping ** ppDPM)
  361. {
  362. if (ppDPM)
  363. *ppDPM = NULL;
  364. if (!pUPS)
  365. return E_INVALIDARG;
  366. if (!ppDPM)
  367. return E_POINTER;
  368. CComObject<CDynamicPortMapping> * pDPM = NULL;
  369. HRESULT hr = CComObject<CDynamicPortMapping>::CreateInstance (&pDPM);
  370. if (pDPM) {
  371. pDPM->AddRef();
  372. hr = pDPM->Initialize (pUPS, lIndex);
  373. if (SUCCEEDED(hr))
  374. hr = pDPM->QueryInterface (__uuidof(IDynamicPortMapping),
  375. (void**)ppDPM);
  376. pDPM->Release();
  377. }
  378. return hr;
  379. }
  380. HRESULT CDynamicPortMapping::Initialize (IUPnPService * pUPS, long lIndex)
  381. {
  382. _ASSERT (m_spUPS == NULL);
  383. _ASSERT (m_eComplete == eNoData);
  384. m_spUPS = pUPS;
  385. SAFEARRAYBOUND rgsaBound[1];
  386. rgsaBound[0].lLbound = 0;
  387. rgsaBound[0].cElements = 1;
  388. SAFEARRAY * psa = SafeArrayCreate (VT_VARIANT, 1, rgsaBound);
  389. if (!psa)
  390. return E_OUTOFMEMORY;
  391. CComVariant cvIn;
  392. V_VT (&cvIn) = VT_VARIANT | VT_ARRAY;
  393. V_ARRAY (&cvIn) = psa; // psa will be freed in dtor
  394. HRESULT hr = AddToSafeArray (psa, &CComVariant(lIndex), 0);
  395. if (SUCCEEDED(hr)) {
  396. CComVariant cvOut, cvRet;
  397. hr = InvokeAction (m_spUPS, CComBSTR(L"GetGenericPortMappingEntry"), cvIn, &cvOut, &cvRet);
  398. if (0) {
  399. long l = 0;
  400. HRESULT hr1 = m_spUPS->get_LastTransportStatus (&l);
  401. _ASSERT (l == 200);
  402. }
  403. if (SUCCEEDED(hr)) {
  404. if (V_VT (&cvOut) != (VT_VARIANT | VT_ARRAY)) {
  405. _ASSERT (0 && "InvokeAction didn't fill out a [out] parameter (properly)!");
  406. hr = E_UNEXPECTED;
  407. } else {
  408. SAFEARRAY * pSA = V_ARRAY (&cvOut);
  409. _ASSERT (pSA);
  410. long lLower = 0, lUpper = -1;
  411. SafeArrayGetLBound (pSA, 1, &lLower);
  412. SafeArrayGetUBound (pSA, 1, &lUpper);
  413. if (lUpper - lLower != 8 - 1)
  414. hr = E_UNEXPECTED;
  415. else {
  416. hr = GetBSTRFromSafeArray (pSA, &m_cbRemoteHost, 0);
  417. if (SUCCEEDED(hr))
  418. hr = GetLongFromSafeArray (pSA, &m_lExternalPort, 1);
  419. if (SUCCEEDED(hr))
  420. hr = GetBSTRFromSafeArray (pSA, &m_cbProtocol, 2);
  421. if (SUCCEEDED(hr))
  422. hr = GetLongFromSafeArray (pSA, &m_lInternalPort, 3);
  423. if (SUCCEEDED(hr))
  424. hr = GetBSTRFromSafeArray (pSA, &m_cbInternalClient, 4);
  425. if (SUCCEEDED(hr))
  426. hr = GetBoolFromSafeArray (pSA, &m_vbEnabled, 5);
  427. if (SUCCEEDED(hr))
  428. hr = GetBSTRFromSafeArray (pSA, &m_cbDescription, 6);
  429. // skip lease duration, since it's live and we get it every time.
  430. }
  431. }
  432. }
  433. }
  434. return hr;
  435. }
  436. HRESULT CDynamicPortMapping::CreateInstance (IUPnPService * pUPS, BSTR bstrRemoteHost, long lExternalPort, BSTR bstrProtocol, IDynamicPortMapping ** ppDPM)
  437. {
  438. if (ppDPM)
  439. *ppDPM = NULL;
  440. if (!pUPS)
  441. return E_INVALIDARG;
  442. if (!ppDPM)
  443. return E_POINTER;
  444. CComObject<CDynamicPortMapping> * pDPM = NULL;
  445. HRESULT hr = CComObject<CDynamicPortMapping>::CreateInstance (&pDPM);
  446. if (pDPM) {
  447. pDPM->AddRef();
  448. hr = pDPM->Initialize (pUPS, bstrRemoteHost, lExternalPort, bstrProtocol);
  449. if (SUCCEEDED(hr))
  450. hr = pDPM->QueryInterface (__uuidof(IDynamicPortMapping),
  451. (void**)ppDPM);
  452. pDPM->Release();
  453. }
  454. return hr;
  455. }
  456. HRESULT CDynamicPortMapping::Initialize (IUPnPService * pUPS, BSTR bstrRemoteHost, long lExternalPort, BSTR bstrProtocol)
  457. {
  458. if (!pUPS)
  459. return E_INVALIDARG;
  460. if (!bstrRemoteHost)
  461. return E_INVALIDARG;
  462. if ((lExternalPort < 0) || (lExternalPort > 65535))
  463. return E_INVALIDARG;
  464. if (!bstrProtocol)
  465. return E_INVALIDARG;
  466. if (wcscmp (bstrProtocol, L"TCP") && wcscmp (bstrProtocol, L"UDP"))
  467. return E_INVALIDARG;
  468. _ASSERT (m_spUPS == NULL);
  469. _ASSERT (m_eComplete == eNoData);
  470. m_spUPS = pUPS;
  471. m_cbRemoteHost = bstrRemoteHost;
  472. m_lExternalPort = lExternalPort;
  473. m_cbProtocol = bstrProtocol;
  474. if (!m_cbRemoteHost || !m_cbProtocol)
  475. return E_OUTOFMEMORY;
  476. else
  477. return GetAllData();
  478. }