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.

758 lines
15 KiB

  1. /*++
  2. Copyright (c) 2001, Microsoft Corporation
  3. Module Name:
  4. cudpbcast.cpp
  5. Abstract:
  6. Implementation of CUdpBroadcastMapper -- support for mapping
  7. a public UDP port to the private network's broadcast address.
  8. Author:
  9. Jonathan Burstein (jonburs) 12 April 2001
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #define INADDR_LOOPBACK_NO 0x0100007f // 127.0.0.1 in network order
  15. //
  16. // ATL Methods
  17. //
  18. HRESULT
  19. CUdpBroadcastMapper::FinalConstruct()
  20. {
  21. HRESULT hr = S_OK;
  22. DWORD dwError;
  23. //
  24. // Create our UDP listening socket and obtain
  25. // its port.
  26. //
  27. dwError =
  28. NhCreateDatagramSocket(
  29. INADDR_LOOPBACK_NO,
  30. 0,
  31. &m_hsUdpListen
  32. );
  33. if (ERROR_SUCCESS == dwError)
  34. {
  35. m_usUdpListenPort = NhQueryPortSocket(m_hsUdpListen);
  36. }
  37. else
  38. {
  39. hr = HRESULT_FROM_WIN32(dwError);
  40. }
  41. if (SUCCEEDED(hr))
  42. {
  43. //
  44. // Create our raw UDP send socket
  45. //
  46. dwError = NhCreateRawDatagramSocket(&m_hsUdpRaw);
  47. if (ERROR_SUCCESS != dwError)
  48. {
  49. hr = HRESULT_FROM_WIN32(dwError);
  50. }
  51. }
  52. if (SUCCEEDED(hr))
  53. {
  54. //
  55. // Obtain a handle to the NAT
  56. //
  57. dwError = NatOpenDriver(&m_hNat);
  58. if (ERROR_SUCCESS != dwError)
  59. {
  60. hr = HRESULT_FROM_WIN32(dwError);
  61. }
  62. }
  63. return hr;
  64. }
  65. HRESULT
  66. CUdpBroadcastMapper::FinalRelease()
  67. {
  68. if (INVALID_SOCKET != m_hsUdpListen)
  69. {
  70. closesocket(m_hsUdpListen);
  71. }
  72. if (INVALID_SOCKET != m_hsUdpRaw)
  73. {
  74. closesocket(m_hsUdpRaw);
  75. }
  76. if (NULL != m_hNat)
  77. {
  78. CloseHandle(m_hNat);
  79. }
  80. ASSERT(IsListEmpty(&m_MappingList));
  81. return S_OK;
  82. }
  83. //
  84. // Initialization
  85. //
  86. HRESULT
  87. CUdpBroadcastMapper::Initialize(
  88. PCOMPONENT_REFERENCE pComponentReference
  89. )
  90. {
  91. HRESULT hr = S_OK;
  92. if (NULL != pComponentReference)
  93. {
  94. m_pCompRef = pComponentReference;
  95. }
  96. else
  97. {
  98. hr = E_INVALIDARG;
  99. }
  100. return hr;
  101. }
  102. //
  103. // IUdpBroadcastMapper methods
  104. //
  105. STDMETHODIMP
  106. CUdpBroadcastMapper::CreateUdpBroadcastMapping(
  107. USHORT usPublicPort,
  108. DWORD dwPublicInterfaceIndex,
  109. ULONG ulDestinationAddress,
  110. VOID **ppvCookie
  111. )
  112. {
  113. HRESULT hr = S_OK;
  114. CUdpBroadcast *pMapping;
  115. CUdpBroadcast *pDuplicate;
  116. PLIST_ENTRY pInsertionPoint;
  117. ULONG ulError;
  118. if (NULL != ppvCookie)
  119. {
  120. *ppvCookie = NULL;
  121. if (0 == usPublicPort
  122. || 0 == dwPublicInterfaceIndex
  123. || 0 == ulDestinationAddress)
  124. {
  125. hr = E_INVALIDARG;
  126. }
  127. else if (!m_fActive)
  128. {
  129. //
  130. // We've already been shutdown
  131. //
  132. hr = E_UNEXPECTED;
  133. }
  134. }
  135. else
  136. {
  137. hr = E_POINTER;
  138. }
  139. if (SUCCEEDED(hr))
  140. {
  141. pMapping = new CUdpBroadcast(
  142. usPublicPort,
  143. dwPublicInterfaceIndex,
  144. ulDestinationAddress
  145. );
  146. if (NULL == pMapping)
  147. {
  148. hr = E_OUTOFMEMORY;
  149. }
  150. }
  151. if (SUCCEEDED(hr))
  152. {
  153. //
  154. // Check for duplicate and insert on list. It's OK for
  155. // the entry to be on the list before we've created the
  156. // dynamic redirect for it.
  157. //
  158. Lock();
  159. pDuplicate =
  160. LookupMapping(
  161. usPublicPort,
  162. dwPublicInterfaceIndex,
  163. &pInsertionPoint
  164. );
  165. if (NULL == pDuplicate)
  166. {
  167. InsertTailList(pInsertionPoint, &pMapping->Link);
  168. }
  169. else
  170. {
  171. delete pMapping;
  172. hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS);
  173. }
  174. Unlock();
  175. }
  176. if (SUCCEEDED(hr))
  177. {
  178. //
  179. // Create the dynamic redirect for this entry
  180. //
  181. ulError =
  182. NatCreateDynamicAdapterRestrictedPortRedirect(
  183. NatRedirectFlagReceiveOnly,
  184. NAT_PROTOCOL_UDP,
  185. usPublicPort,
  186. INADDR_LOOPBACK_NO,
  187. m_usUdpListenPort,
  188. dwPublicInterfaceIndex,
  189. 0,
  190. &pMapping->hDynamicRedirect
  191. );
  192. if (ERROR_SUCCESS != ulError)
  193. {
  194. hr = HRESULT_FROM_WIN32(ulError);
  195. Lock();
  196. RemoveEntryList(&pMapping->Link);
  197. Unlock();
  198. delete pMapping;
  199. }
  200. }
  201. if (SUCCEEDED(hr))
  202. {
  203. //
  204. // Make sure that we've posted a read on our UDP socket
  205. //
  206. hr = StartUdpRead();
  207. if (SUCCEEDED(hr))
  208. {
  209. *ppvCookie = reinterpret_cast<PVOID>(pMapping);
  210. }
  211. else
  212. {
  213. NatCancelDynamicRedirect(pMapping->hDynamicRedirect);
  214. Lock();
  215. RemoveEntryList(&pMapping->Link);
  216. Unlock();
  217. delete pMapping;
  218. }
  219. }
  220. return hr;
  221. }
  222. STDMETHODIMP
  223. CUdpBroadcastMapper::CancelUdpBroadcastMapping(
  224. VOID *pvCookie
  225. )
  226. {
  227. HRESULT hr = S_OK;
  228. CUdpBroadcast *pMapping;
  229. ULONG ulError;
  230. if (NULL != pvCookie)
  231. {
  232. pMapping = reinterpret_cast<CUdpBroadcast*>(pvCookie);
  233. Lock();
  234. RemoveEntryList(&pMapping->Link);
  235. Unlock();
  236. ASSERT(NULL != pMapping->hDynamicRedirect);
  237. ulError = NatCancelDynamicRedirect(pMapping->hDynamicRedirect);
  238. if (ERROR_SUCCESS != ulError)
  239. {
  240. hr = HRESULT_FROM_WIN32(ulError);
  241. }
  242. delete pMapping;
  243. }
  244. else
  245. {
  246. hr = E_INVALIDARG;
  247. }
  248. return hr;
  249. }
  250. STDMETHODIMP
  251. CUdpBroadcastMapper::Shutdown()
  252. {
  253. InterlockedExchange(
  254. reinterpret_cast<LPLONG>(&m_fActive),
  255. FALSE
  256. );
  257. //
  258. // We need to close our read socket handle so that any
  259. // pending reads complete. We don't need to close our
  260. // raw send socket since for that completion will never
  261. // be blocked waiting for an incoming packet.
  262. //
  263. Lock();
  264. if (INVALID_SOCKET != m_hsUdpListen)
  265. {
  266. closesocket(m_hsUdpListen);
  267. m_hsUdpListen = INVALID_SOCKET;
  268. }
  269. Unlock();
  270. return S_OK;
  271. }
  272. //
  273. // Protected methods
  274. //
  275. CUdpBroadcast*
  276. CUdpBroadcastMapper::LookupMapping(
  277. USHORT usPublicPort,
  278. DWORD dwInterfaceIndex,
  279. PLIST_ENTRY * ppInsertionPoint
  280. )
  281. {
  282. PLIST_ENTRY pLink;
  283. CUdpBroadcast *pMapping;
  284. CUdpBroadcast *pMappingToReturn = NULL;
  285. //
  286. // The caller should have already locked the object before calling
  287. // this method to guarantee that what we return will still be
  288. // valid. However, we'll still grab the lock again to ensure that
  289. // it's safe to traverse the list.
  290. //
  291. Lock();
  292. for (pLink = m_MappingList.Flink;
  293. pLink != &m_MappingList;
  294. pLink = pLink->Flink)
  295. {
  296. pMapping = CONTAINING_RECORD(pLink, CUdpBroadcast, Link);
  297. if (pMapping->usPublicPort < usPublicPort)
  298. {
  299. continue;
  300. }
  301. else if (pMapping->usPublicPort > usPublicPort)
  302. {
  303. break;
  304. }
  305. //
  306. // Primary key matches, check secondary key
  307. //
  308. if (pMapping->dwInterfaceIndex < dwInterfaceIndex)
  309. {
  310. continue;
  311. }
  312. else if (pMapping->dwInterfaceIndex > dwInterfaceIndex)
  313. {
  314. break;
  315. }
  316. //
  317. // Found it.
  318. //
  319. pMappingToReturn = pMapping;
  320. break;
  321. }
  322. Unlock();
  323. if (NULL == pMappingToReturn
  324. && NULL != ppInsertionPoint)
  325. {
  326. *ppInsertionPoint = pLink;
  327. }
  328. return pMappingToReturn;
  329. }
  330. HRESULT
  331. CUdpBroadcastMapper::StartUdpRead()
  332. {
  333. HRESULT hr = S_OK;
  334. ULONG ulError;
  335. LONG fReadStarted;
  336. Lock();
  337. if (!m_fReadStarted)
  338. {
  339. AddRef();
  340. ulError =
  341. NhReadDatagramSocket(
  342. m_pCompRef,
  343. m_hsUdpListen,
  344. NULL,
  345. UdpReadCompletionRoutine,
  346. this,
  347. m_pCompRef
  348. );
  349. if (ERROR_SUCCESS == ulError)
  350. {
  351. m_fReadStarted = TRUE;
  352. }
  353. else
  354. {
  355. hr = HRESULT_FROM_WIN32(ulError);
  356. Release();
  357. }
  358. }
  359. Unlock();
  360. return hr;
  361. }
  362. VOID
  363. CUdpBroadcastMapper::UdpReadCompletionRoutine(
  364. ULONG ulError,
  365. ULONG ulBytesTransferred,
  366. PNH_BUFFER pBuffer
  367. )
  368. {
  369. CUdpBroadcastMapper *pMapper;
  370. PCOMPONENT_REFERENCE pCompRef;
  371. pMapper = reinterpret_cast<CUdpBroadcastMapper*>(pBuffer->Context);
  372. pCompRef = reinterpret_cast<PCOMPONENT_REFERENCE>(pBuffer->Context2);
  373. ASSERT(NULL != pMapper);
  374. ASSERT(NULL != pCompRef);
  375. //
  376. // Do the actual work
  377. //
  378. pMapper->ProcessUdpRead(ulError, ulBytesTransferred, pBuffer);
  379. //
  380. // Release the references obtained on both the object and
  381. // the component
  382. //
  383. pMapper->Release();
  384. ReleaseComponentReference(pCompRef);
  385. }
  386. VOID
  387. CUdpBroadcastMapper::ProcessUdpRead(
  388. ULONG ulError,
  389. ULONG ulBytesTransferred,
  390. PNH_BUFFER pBuffer
  391. )
  392. {
  393. NAT_KEY_SESSION_MAPPING_EX_INFORMATION MappingInfo;
  394. ULONG ulBufferSize;
  395. DWORD dwError;
  396. CUdpBroadcast *pMapping;
  397. ULONG ulDestinationAddress = 0;
  398. //
  399. // If an error occured check to see if we should repost
  400. // the read. If we're not active release the buffer
  401. // and exit.
  402. //
  403. if (ERROR_SUCCESS != ulError || !Active())
  404. {
  405. Lock();
  406. if (Active()
  407. && !NhIsFatalSocketError(ulError)
  408. && INVALID_SOCKET != m_hsUdpListen)
  409. {
  410. AddRef();
  411. dwError =
  412. NhReadDatagramSocket(
  413. m_pCompRef,
  414. m_hsUdpListen,
  415. pBuffer,
  416. UdpReadCompletionRoutine,
  417. this,
  418. m_pCompRef
  419. );
  420. if (ERROR_SUCCESS != dwError)
  421. {
  422. Release();
  423. NhReleaseBuffer(pBuffer);
  424. }
  425. }
  426. else
  427. {
  428. NhReleaseBuffer(pBuffer);
  429. }
  430. Unlock();
  431. return;
  432. }
  433. //
  434. // Lookup the original destination address for this packet.
  435. //
  436. ulBufferSize = sizeof(MappingInfo);
  437. dwError =
  438. NatLookupAndQueryInformationSessionMapping(
  439. m_hNat,
  440. NAT_PROTOCOL_UDP,
  441. INADDR_LOOPBACK_NO,
  442. m_usUdpListenPort,
  443. pBuffer->ReadAddress.sin_addr.s_addr,
  444. pBuffer->ReadAddress.sin_port,
  445. &MappingInfo,
  446. &ulBufferSize,
  447. NatKeySessionMappingExInformation
  448. );
  449. if (ERROR_SUCCESS == dwError)
  450. {
  451. //
  452. // See if we have a port mapping for the original destination,
  453. // and, if so, get the destination address
  454. //
  455. Lock();
  456. pMapping =
  457. LookupMapping(
  458. MappingInfo.DestinationPort,
  459. MappingInfo.AdapterIndex,
  460. NULL
  461. );
  462. if (NULL != pMapping)
  463. {
  464. ulDestinationAddress = pMapping->ulDestinationAddress;
  465. }
  466. Unlock();
  467. }
  468. if (0 != ulDestinationAddress)
  469. {
  470. //
  471. // Construct the new packet and send it on its way
  472. //
  473. BuildAndSendRawUdpPacket(
  474. ulDestinationAddress,
  475. MappingInfo.DestinationPort,
  476. pBuffer
  477. );
  478. }
  479. //
  480. // If we're still active repost the read, otherwise free the
  481. // buffer.
  482. //
  483. Lock();
  484. if (Active()
  485. && INVALID_SOCKET != m_hsUdpListen)
  486. {
  487. AddRef();
  488. dwError =
  489. NhReadDatagramSocket(
  490. m_pCompRef,
  491. m_hsUdpListen,
  492. pBuffer,
  493. UdpReadCompletionRoutine,
  494. this,
  495. m_pCompRef
  496. );
  497. if (ERROR_SUCCESS != dwError)
  498. {
  499. Release();
  500. NhReleaseBuffer(pBuffer);
  501. }
  502. }
  503. else
  504. {
  505. NhReleaseBuffer(pBuffer);
  506. }
  507. Unlock();
  508. }
  509. HRESULT
  510. CUdpBroadcastMapper::BuildAndSendRawUdpPacket(
  511. ULONG ulDestinationAddress,
  512. USHORT usDestinationPort,
  513. PNH_BUFFER pPacketData
  514. )
  515. {
  516. HRESULT hr = S_OK;
  517. PNH_BUFFER pBuffer;
  518. ULONG ulPacketSize;
  519. PIP_HEADER pIpHeader;
  520. UDP_HEADER UNALIGNED *pUdpHeader;
  521. PUCHAR pucData;
  522. DWORD dwError;
  523. //
  524. // Allocate a buffer large enough for the headers and packet data
  525. //
  526. ulPacketSize =
  527. sizeof(IP_HEADER) + sizeof(UDP_HEADER) + pPacketData->BytesTransferred;
  528. pBuffer = NhAcquireVariableLengthBuffer(ulPacketSize);
  529. if (NULL != pBuffer)
  530. {
  531. //
  532. // Locate offsets w/in the buffer
  533. //
  534. pIpHeader = reinterpret_cast<PIP_HEADER>(pBuffer->Buffer);
  535. pUdpHeader =
  536. reinterpret_cast<UDP_HEADER UNALIGNED *>(pBuffer->Buffer + sizeof(IP_HEADER));
  537. pucData = pBuffer->Buffer + sizeof(IP_HEADER) + sizeof(UDP_HEADER);
  538. //
  539. // Copy over the packet data
  540. //
  541. CopyMemory(pucData, pPacketData->Buffer, pPacketData->BytesTransferred);
  542. //
  543. // Fill out the IP header
  544. //
  545. pIpHeader->VersionAndHeaderLength =
  546. (4 << 4) | (sizeof(IP_HEADER) / sizeof(ULONG));
  547. pIpHeader->TypeOfService = 0;
  548. pIpHeader->TotalLength = htons(static_cast<USHORT>(ulPacketSize));
  549. pIpHeader->Identification = htons(++m_usIpId);
  550. pIpHeader->OffsetAndFlags = 0;
  551. pIpHeader->TimeToLive = 128;
  552. pIpHeader->Protocol = NAT_PROTOCOL_UDP;
  553. pIpHeader->Checksum = 0;
  554. pIpHeader->SourceAddress = pPacketData->ReadAddress.sin_addr.s_addr;
  555. pIpHeader->DestinationAddress = ulDestinationAddress;
  556. //
  557. // Fill out the UDP header
  558. //
  559. pUdpHeader->SourcePort = pPacketData->ReadAddress.sin_port;
  560. pUdpHeader->DestinationPort = usDestinationPort;
  561. pUdpHeader->Length =
  562. htons(
  563. static_cast<USHORT>(
  564. sizeof(UDP_HEADER) + pPacketData->BytesTransferred
  565. )
  566. );
  567. pUdpHeader->Checksum = 0;
  568. //
  569. // Send the buffer on its way
  570. //
  571. AddRef();
  572. dwError =
  573. NhWriteDatagramSocket(
  574. m_pCompRef,
  575. m_hsUdpRaw,
  576. ulDestinationAddress,
  577. usDestinationPort,
  578. pBuffer,
  579. ulPacketSize,
  580. RawWriteCompletionRoutine,
  581. this,
  582. m_pCompRef
  583. );
  584. if (ERROR_SUCCESS != dwError)
  585. {
  586. Release();
  587. NhReleaseBuffer(pBuffer);
  588. hr = HRESULT_FROM_WIN32(dwError);
  589. }
  590. }
  591. else
  592. {
  593. hr = E_OUTOFMEMORY;
  594. }
  595. return hr;
  596. }
  597. VOID
  598. CUdpBroadcastMapper::RawWriteCompletionRoutine(
  599. ULONG ulError,
  600. ULONG ulBytesTransferred,
  601. PNH_BUFFER pBuffer
  602. )
  603. {
  604. CUdpBroadcastMapper *pMapper;
  605. PCOMPONENT_REFERENCE pCompRef;
  606. pMapper = reinterpret_cast<CUdpBroadcastMapper*>(pBuffer->Context);
  607. pCompRef = reinterpret_cast<PCOMPONENT_REFERENCE>(pBuffer->Context2);
  608. ASSERT(NULL != pMapper);
  609. ASSERT(NULL != pCompRef);
  610. //
  611. // Free the passed-in buffer
  612. //
  613. NhReleaseBuffer(pBuffer);
  614. //
  615. // Release the references obtained on both the object and
  616. // the component
  617. //
  618. pMapper->Release();
  619. ReleaseComponentReference(pCompRef);
  620. }