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.

12627 lines
329 KiB

  1. /***************************************************************************
  2. *
  3. * Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dpnhpastintfobj.cpp
  6. *
  7. * Content: DPNHPAST main interface object class.
  8. *
  9. * History:
  10. * Date By Reason
  11. * ======== ======== =========
  12. * 04/16/01 VanceO Split DPNATHLP into DPNHUPNP and DPNHPAST.
  13. *
  14. ***************************************************************************/
  15. #include "dpnhpasti.h"
  16. //=============================================================================
  17. // Definitions
  18. //=============================================================================
  19. #define DEFAULT_INITIAL_PAST_RETRY_TIMEOUT 25000 // start retry timer at 25 ms
  20. #define PAST_CONNECT_RETRY_INTERVAL_MS 250 // 250 ms
  21. #define PAST_CONNECT_RETRY_INTERVAL_US (PAST_CONNECT_RETRY_INTERVAL_MS * 1000)
  22. #define MAX_NUM_PAST_TRIES_CONNECT 2 // how many times to send a registration request message, in case of packet loss
  23. #define MAX_PAST_RETRY_TIME_US 250000 // max retry interval is 250 ms
  24. #define MAX_NUM_PAST_TRIES 5
  25. #define PAST_RESPONSE_BUFFER_SIZE 150
  26. #define LEASE_RENEW_TIME 120000 // renew if less than 2 minutes remaining
  27. #define FAKE_PORT_LEASE_TIME 300000 // 5 minutes
  28. #define IOCOMPLETE_WAIT_INTERVAL 100 // 100 ms between attempts
  29. #define MAX_NUM_IOCOMPLETE_WAITS 10 // wait at most 1 second
  30. #define MAX_RESERVED_PORT 1024
  31. #define MAX_NUM_RANDOM_PORT_TRIES 5
  32. #ifndef DPNBUILD_NOWINSOCK2
  33. //=============================================================================
  34. // WinSock 1 version of IP options
  35. //=============================================================================
  36. #define IP_TTL_WINSOCK1 7
  37. #endif // ! DPNBUILD_NOWINSOCK2
  38. //=============================================================================
  39. // Macros
  40. //=============================================================================
  41. //#ifdef _X86
  42. #define IS_CLASSD_IPV4_ADDRESS(dwAddr) (( (*((BYTE*) &(dwAddr))) & 0xF0) == 0xE0) // 1110 high bits or 224.0.0.0 - 239.255.255.255 multicast address, in network byte order
  43. #define NTOHS(x) ( (((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00) )
  44. #define HTONS(x) NTOHS(x)
  45. //#endif _X86
  46. //=============================================================================
  47. // Local static variables
  48. //=============================================================================
  49. static timeval s_tv0 = {0, 0};
  50. #undef DPF_MODNAME
  51. #define DPF_MODNAME "CNATHelpPAST::CNATHelpPAST"
  52. //=============================================================================
  53. // CNATHelpPAST constructor
  54. //-----------------------------------------------------------------------------
  55. //
  56. // Description: Initializes the new CNATHelpPAST object.
  57. //
  58. // Arguments:
  59. // BOOL fNotCreatedWithCOM - TRUE if this object is being instantiated
  60. // without COM, FALSE if it is through COM.
  61. //
  62. // Returns: None (the object).
  63. //=============================================================================
  64. CNATHelpPAST::CNATHelpPAST(const BOOL fNotCreatedWithCOM)
  65. {
  66. this->m_blList.Initialize();
  67. this->m_Sig[0] = 'N';
  68. this->m_Sig[1] = 'A';
  69. this->m_Sig[2] = 'T';
  70. this->m_Sig[3] = 'H';
  71. this->m_lRefCount = 1; // someone must have a pointer to this object
  72. if (fNotCreatedWithCOM)
  73. {
  74. this->m_dwFlags = NATHELPPASTOBJ_NOTCREATEDWITHCOM;
  75. }
  76. else
  77. {
  78. this->m_dwFlags = 0;
  79. }
  80. this->m_dwLockThreadID = 0;
  81. this->m_hAlertEvent = NULL;
  82. this->m_hAlertIOCompletionPort = NULL;
  83. this->m_dwAlertCompletionKey = 0;
  84. this->m_blDevices.Initialize();
  85. this->m_blRegisteredPorts.Initialize();
  86. this->m_blUnownedPorts.Initialize();
  87. this->m_dwLastUpdateServerStatusTime = 0;
  88. this->m_dwNextPollInterval = 0;
  89. this->m_dwNumLeases = 0;
  90. this->m_dwEarliestLeaseExpirationTime = 0;
  91. this->m_hIpHlpApiDLL = NULL;
  92. this->m_pfnGetAdaptersInfo = NULL;
  93. this->m_pfnGetIpForwardTable = NULL;
  94. this->m_pfnGetBestRoute = NULL;
  95. this->m_sIoctls = INVALID_SOCKET;
  96. this->m_wIoctlSocketPort = 0;
  97. this->m_polAddressListChange = NULL;
  98. this->m_hWinSockDLL = NULL;
  99. this->m_pfnWSAStartup = NULL;
  100. this->m_pfnWSACleanup = NULL;
  101. this->m_pfnWSAGetLastError = NULL;
  102. this->m_pfnsocket = NULL;
  103. this->m_pfnclosesocket = NULL;
  104. this->m_pfnbind = NULL;
  105. this->m_pfnsetsockopt = NULL;
  106. this->m_pfngetsockname = NULL;
  107. this->m_pfnselect = NULL;
  108. this->m_pfn__WSAFDIsSet = NULL;
  109. this->m_pfnrecvfrom = NULL;
  110. this->m_pfnsendto = NULL;
  111. this->m_pfngethostname = NULL;
  112. this->m_pfngethostbyname = NULL;
  113. this->m_pfninet_addr = NULL;
  114. this->m_pfnWSASocketA = NULL;
  115. this->m_pfnWSAIoctl = NULL;
  116. this->m_pfnWSAGetOverlappedResult = NULL;
  117. #ifdef DBG
  118. this->m_dwNumDeviceAdds = 0;
  119. this->m_dwNumDeviceRemoves = 0;
  120. this->m_dwNumServerFailures = 0;
  121. #endif // DBG
  122. } // CNATHelpPAST::CNATHelpPAST
  123. #undef DPF_MODNAME
  124. #define DPF_MODNAME "CNATHelpPAST::~CNATHelpPAST"
  125. //=============================================================================
  126. // CNATHelpPAST destructor
  127. //-----------------------------------------------------------------------------
  128. //
  129. // Description: Frees the CNATHelpPAST object.
  130. //
  131. // Arguments: None.
  132. //
  133. // Returns: None.
  134. //=============================================================================
  135. CNATHelpPAST::~CNATHelpPAST(void)
  136. {
  137. DPFX(DPFPREP, 7, "(0x%p) NumDeviceAdds = %u, NumDeviceRemoves = %u, NumServerFailures = %u",
  138. this, this->m_dwNumDeviceAdds, this->m_dwNumDeviceRemoves,
  139. this->m_dwNumServerFailures);
  140. DNASSERT(this->m_blList.IsEmpty());
  141. DNASSERT(this->m_lRefCount == 0);
  142. DNASSERT((this->m_dwFlags & ~NATHELPPASTOBJ_NOTCREATEDWITHCOM) == 0);
  143. DNASSERT(this->m_dwLockThreadID == 0);
  144. DNASSERT(this->m_hAlertEvent == NULL);
  145. DNASSERT(this->m_hAlertIOCompletionPort == NULL);
  146. DNASSERT(this->m_blDevices.IsEmpty());
  147. DNASSERT(this->m_blRegisteredPorts.IsEmpty());
  148. DNASSERT(this->m_blUnownedPorts.IsEmpty());
  149. DNASSERT(this->m_dwNumLeases == 0);
  150. DNASSERT(this->m_hIpHlpApiDLL == NULL);
  151. DNASSERT(this->m_hWinSockDLL == NULL);
  152. DNASSERT(this->m_sIoctls == INVALID_SOCKET);
  153. DNASSERT(this->m_polAddressListChange == NULL);
  154. //
  155. // For grins, change the signature before deleting the object.
  156. //
  157. this->m_Sig[3] = 'h';
  158. } // CNATHelpPAST::~CNATHelpPAST
  159. #undef DPF_MODNAME
  160. #define DPF_MODNAME "CNATHelpPAST::QueryInterface"
  161. //=============================================================================
  162. // CNATHelpPAST::QueryInterface
  163. //-----------------------------------------------------------------------------
  164. //
  165. // Description: Retrieves a new reference for an interfaces supported by this
  166. // CNATHelpPAST object.
  167. //
  168. // Arguments:
  169. // REFIID riid - Reference to interface ID GUID.
  170. // LPVOID * ppvObj - Place to store pointer to object.
  171. //
  172. // Returns: HRESULT
  173. // S_OK - Returning a valid interface pointer.
  174. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  175. // DPNHERR_INVALIDPOINTER - The destination pointer is invalid.
  176. // E_NOINTERFACE - Invalid interface was specified.
  177. //=============================================================================
  178. STDMETHODIMP CNATHelpPAST::QueryInterface(REFIID riid, LPVOID * ppvObj)
  179. {
  180. HRESULT hr = DPNH_OK;
  181. DPFX(DPFPREP, 3, "(0x%p) Parameters: (REFIID, 0x%p)", this, ppvObj);
  182. //
  183. // Validate the object.
  184. //
  185. if (! this->IsValidObject())
  186. {
  187. DPFX(DPFPREP, 0, "Invalid NATHelper object!");
  188. hr = DPNHERR_INVALIDOBJECT;
  189. goto Failure;
  190. }
  191. //
  192. // Validate the parameters.
  193. //
  194. if ((! IsEqualIID(riid, IID_IUnknown)) &&
  195. (! IsEqualIID(riid, IID_IDirectPlayNATHelp)))
  196. {
  197. DPFX(DPFPREP, 0, "Unsupported interface!");
  198. hr = E_NOINTERFACE;
  199. goto Failure;
  200. }
  201. if ((ppvObj == NULL) ||
  202. (IsBadWritePtr(ppvObj, sizeof(void*))))
  203. {
  204. DPFX(DPFPREP, 0, "Invalid interface pointer specified!");
  205. hr = DPNHERR_INVALIDPOINTER;
  206. goto Failure;
  207. }
  208. //
  209. // Add a reference, and return the interface pointer (which is actually
  210. // just the object pointer, they line up because CNATHelpPAST inherits from
  211. // the interface declaration).
  212. //
  213. this->AddRef();
  214. (*ppvObj) = this;
  215. Exit:
  216. DPFX(DPFPREP, 3, "(0x%p) Returning: [0x%lx]", this, hr);
  217. return hr;
  218. Failure:
  219. goto Exit;
  220. } // CNATHelpPAST::QueryInterface
  221. #undef DPF_MODNAME
  222. #define DPF_MODNAME "CNATHelpPAST::AddRef"
  223. //=============================================================================
  224. // CNATHelpPAST::AddRef
  225. //-----------------------------------------------------------------------------
  226. //
  227. // Description: Adds a reference to this CNATHelpPAST object.
  228. //
  229. // Arguments: None.
  230. //
  231. // Returns: New refcount.
  232. //=============================================================================
  233. STDMETHODIMP_(ULONG) CNATHelpPAST::AddRef(void)
  234. {
  235. LONG lRefCount;
  236. DNASSERT(this->IsValidObject());
  237. //
  238. // There must be at least 1 reference to this object, since someone is
  239. // calling AddRef.
  240. //
  241. DNASSERT(this->m_lRefCount > 0);
  242. lRefCount = InterlockedIncrement(&this->m_lRefCount);
  243. DPFX(DPFPREP, 3, "[0x%p] RefCount [0x%lx]", this, lRefCount);
  244. return lRefCount;
  245. } // CNATHelpPAST::AddRef
  246. #undef DPF_MODNAME
  247. #define DPF_MODNAME "CNATHelpPAST::Release"
  248. //=============================================================================
  249. // CNATHelpPAST::Release
  250. //-----------------------------------------------------------------------------
  251. //
  252. // Description: Removes a reference to this CNATHelpPAST object. When the
  253. // refcount reaches 0, this object is destroyed.
  254. // You must NULL out your pointer to this object after calling
  255. // this function.
  256. //
  257. // Arguments: None.
  258. //
  259. // Returns: New refcount.
  260. //=============================================================================
  261. STDMETHODIMP_(ULONG) CNATHelpPAST::Release(void)
  262. {
  263. LONG lRefCount;
  264. DNASSERT(this->IsValidObject());
  265. //
  266. // There must be at least 1 reference to this object, since someone is
  267. // calling Release.
  268. //
  269. DNASSERT(this->m_lRefCount > 0);
  270. lRefCount = InterlockedDecrement(&this->m_lRefCount);
  271. //
  272. // Was that the last reference? If so, we're going to destroy this object.
  273. //
  274. if (lRefCount == 0)
  275. {
  276. DPFX(DPFPREP, 3, "[0x%p] RefCount hit 0, destroying object.", this);
  277. //
  278. // First pull it off the global list.
  279. //
  280. DNEnterCriticalSection(&g_csGlobalsLock);
  281. this->m_blList.RemoveFromList();
  282. DNASSERT(g_lOutstandingInterfaceCount > 0);
  283. g_lOutstandingInterfaceCount--; // update count so DLL can unload now works correctly
  284. DNLeaveCriticalSection(&g_csGlobalsLock);
  285. //
  286. // Make sure it's closed.
  287. //
  288. if (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED)
  289. {
  290. //
  291. // Assert so that the user can fix his/her broken code!
  292. //
  293. DNASSERT(! "DirectPlayNATHelpPAST object being released without calling Close first!");
  294. //
  295. // Then go ahead and do the right thing. Ignore error, we can't do
  296. // much about it.
  297. //
  298. this->Close(0);
  299. }
  300. //
  301. // Then uninitialize the object.
  302. //
  303. this->UninitializeObject();
  304. //
  305. // Finally delete this (!) object.
  306. //
  307. delete this;
  308. }
  309. else
  310. {
  311. DPFX(DPFPREP, 3, "[0x%p] RefCount [0x%lx]", this, lRefCount);
  312. }
  313. return lRefCount;
  314. } // CNATHelpPAST::Release
  315. #undef DPF_MODNAME
  316. #define DPF_MODNAME "CNATHelpPAST::Initialize"
  317. //=============================================================================
  318. // CNATHelpPAST::Initialize
  319. //-----------------------------------------------------------------------------
  320. //
  321. // Description: Prepares the object for use. No attempt is made to contact
  322. // any Internet gateway servers at this time. The user should
  323. // call GetCaps with the DPNHGETCAPS_UPDATESERVERSTATUS flag to
  324. // search for a server.
  325. //
  326. // Initialize must be called before using any other function,
  327. // and must be balanced with a call to Close. Initialize can only
  328. // be called once unless Close returns it to the uninitialized
  329. // state.
  330. //
  331. // One of DPNHINITIALIZE_DISABLEREMOTENATSUPPORT or
  332. // DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT may be specified,
  333. // but not both.
  334. //
  335. // Arguments:
  336. // DWORD dwFlags - Flags to use when initializing.
  337. //
  338. // Returns: HRESULT
  339. // DPNH_OK - Initialization was successful.
  340. // DPNHERR_ALREADYINITIALIZED - Initialize has already been called.
  341. // DPNHERR_GENERIC - An error occurred while initializing.
  342. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  343. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  344. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  345. // DPNHERR_OUTOFMEMORY - There is not enough memory to initialize.
  346. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  347. // thread.
  348. //=============================================================================
  349. STDMETHODIMP CNATHelpPAST::Initialize(const DWORD dwFlags)
  350. {
  351. HRESULT hr;
  352. BOOL fHaveLock = FALSE;
  353. BOOL fSetFlags = FALSE;
  354. BOOL fWinSockStarted = FALSE;
  355. WSADATA wsadata;
  356. int iError;
  357. SOCKADDR_IN saddrinTemp;
  358. int iAddressSize;
  359. #ifdef DBG
  360. DWORD dwError;
  361. #endif // DBG
  362. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%lx)", this, dwFlags);
  363. //
  364. // Validate the object.
  365. //
  366. if (! this->IsValidObject())
  367. {
  368. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  369. hr = DPNHERR_INVALIDOBJECT;
  370. //
  371. // Skip the failure cleanup code, we haven't set anything up.
  372. //
  373. goto Exit;
  374. }
  375. //
  376. // Validate the parameters.
  377. //
  378. if (dwFlags & ~(DPNHINITIALIZE_DISABLEGATEWAYSUPPORT | DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT))
  379. {
  380. DPFX(DPFPREP, 0, "Invalid flags specified!");
  381. hr = DPNHERR_INVALIDFLAGS;
  382. //
  383. // Skip the failure cleanup code, we haven't set anything up.
  384. //
  385. goto Exit;
  386. }
  387. //
  388. // Both flags cannot be specified at the same time. If the caller doesn't
  389. // want any NAT functionality, why use this object all?
  390. //
  391. if ((dwFlags & (DPNHINITIALIZE_DISABLEGATEWAYSUPPORT | DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT)) == (DPNHINITIALIZE_DISABLEGATEWAYSUPPORT | DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT))
  392. {
  393. DPFX(DPFPREP, 0, "Either DISABLEGATEWAYSUPPORT flag or DISABLELOCALFIREWALLSUPPORT flag can be used, but not both!");
  394. hr = DPNHERR_INVALIDFLAGS;
  395. //
  396. // Skip the failure cleanup code, we haven't set anything up.
  397. //
  398. goto Exit;
  399. }
  400. //
  401. // Attempt to take the lock, but be prepared for the re-entrancy error.
  402. //
  403. hr = this->TakeLock();
  404. if (hr != DPNH_OK)
  405. {
  406. DPFX(DPFPREP, 0, "Could not lock object!");
  407. //
  408. // Skip the failure cleanup code, we haven't set anything up.
  409. //
  410. goto Exit;
  411. }
  412. fHaveLock = TRUE;
  413. //
  414. // Make sure object is in right state.
  415. //
  416. if ((this->m_dwFlags & ~NATHELPPASTOBJ_NOTCREATEDWITHCOM) != 0)
  417. {
  418. DPFX(DPFPREP, 0, "Object already initialized!");
  419. hr = DPNHERR_ALREADYINITIALIZED;
  420. //
  421. // Skip the failure cleanup code, we haven't set anything up.
  422. //
  423. goto Exit;
  424. }
  425. //
  426. // Read in the manual override settings from the registry
  427. //
  428. ReadRegistrySettings();
  429. //
  430. // We're not completely initialized yet, but set the flag(s) now.
  431. //
  432. this->m_dwFlags |= NATHELPPASTOBJ_INITIALIZED;
  433. fSetFlags = TRUE;
  434. //
  435. // Store the user's settings.
  436. //
  437. if (dwFlags & DPNHINITIALIZE_DISABLEGATEWAYSUPPORT)
  438. {
  439. DPFX(DPFPREP, 1, "User requested that Internet gateways not be supported.");
  440. }
  441. else
  442. {
  443. this->m_dwFlags |= NATHELPPASTOBJ_USEPASTICS;
  444. }
  445. if (dwFlags & DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT)
  446. {
  447. DPFX(DPFPREP, 1, "User requested that local PAST PFW not be supported.");
  448. }
  449. else
  450. {
  451. this->m_dwFlags |= NATHELPPASTOBJ_USEPASTPFW;
  452. }
  453. //
  454. // Take into account the registry override settings.
  455. //
  456. switch (g_dwPASTICSMode)
  457. {
  458. case OVERRIDEMODE_FORCEON:
  459. {
  460. //
  461. // Force PAST ICS on.
  462. //
  463. DPFX(DPFPREP, 1, "Forcing PAST ICS support on.");
  464. this->m_dwFlags |= NATHELPPASTOBJ_USEPASTICS;
  465. break;
  466. }
  467. case OVERRIDEMODE_FORCEOFF:
  468. {
  469. //
  470. // Force PAST ICS off.
  471. //
  472. DPFX(DPFPREP, 1, "Forcing PAST ICS support off.");
  473. this->m_dwFlags &= ~NATHELPPASTOBJ_USEPASTICS;
  474. break;
  475. }
  476. default:
  477. {
  478. //
  479. // Leave PAST ICS settings alone.
  480. //
  481. break;
  482. }
  483. }
  484. switch (g_dwPASTPFWMode)
  485. {
  486. case OVERRIDEMODE_FORCEON:
  487. {
  488. //
  489. // Force PAST PFW on.
  490. //
  491. DPFX(DPFPREP, 1, "Forcing PAST PFW support on.");
  492. this->m_dwFlags |= NATHELPPASTOBJ_USEPASTPFW;
  493. break;
  494. }
  495. case OVERRIDEMODE_FORCEOFF:
  496. {
  497. //
  498. // Force PAST PFW off.
  499. //
  500. DPFX(DPFPREP, 1, "Forcing PAST PFW support off.");
  501. this->m_dwFlags &= ~NATHELPPASTOBJ_USEPASTPFW;
  502. break;
  503. }
  504. default:
  505. {
  506. //
  507. // Leave PAST PFW settings alone.
  508. //
  509. break;
  510. }
  511. }
  512. //
  513. // Try loading the IP helper DLL.
  514. //
  515. this->m_hIpHlpApiDLL = LoadLibrary( _T("iphlpapi.dll") );
  516. if (this->m_hIpHlpApiDLL == NULL)
  517. {
  518. #ifdef DBG
  519. dwError = GetLastError();
  520. DPFX(DPFPREP, 1, "Unable to load \"iphlpapi.dll\" (error = 0x%lx).",
  521. dwError);
  522. #endif // DBG
  523. //
  524. // That's not fatal, we can still function.
  525. //
  526. }
  527. else
  528. {
  529. //
  530. // Load the functions we'll use.
  531. //
  532. this->m_pfnGetAdaptersInfo = (PFN_GETADAPTERSINFO) GetProcAddress(this->m_hIpHlpApiDLL,
  533. "GetAdaptersInfo");
  534. if (this->m_pfnGetAdaptersInfo == NULL)
  535. {
  536. #ifdef DBG
  537. dwError = GetLastError();
  538. DPFX(DPFPREP, 0, "Unable to get \"GetAdaptersInfo\" function (error = 0x%lx)!",
  539. dwError);
  540. #endif // DBG
  541. goto Exit;
  542. }
  543. this->m_pfnGetIpForwardTable = (PFN_GETIPFORWARDTABLE) GetProcAddress(this->m_hIpHlpApiDLL,
  544. "GetIpForwardTable");
  545. if (this->m_pfnGetIpForwardTable == NULL)
  546. {
  547. #ifdef DBG
  548. dwError = GetLastError();
  549. DPFX(DPFPREP, 0, "Unable to get \"GetIpForwardTable\" function (error = 0x%lx)!",
  550. dwError);
  551. #endif // DBG
  552. goto Exit;
  553. }
  554. this->m_pfnGetBestRoute = (PFN_GETBESTROUTE) GetProcAddress(this->m_hIpHlpApiDLL,
  555. "GetBestRoute");
  556. if (this->m_pfnGetBestRoute == NULL)
  557. {
  558. #ifdef DBG
  559. dwError = GetLastError();
  560. DPFX(DPFPREP, 0, "Unable to get \"GetBestRoute\" function (error = 0x%lx)!",
  561. dwError);
  562. #endif // DBG
  563. goto Exit;
  564. }
  565. }
  566. //
  567. // Load WinSock, we always need it.
  568. //
  569. this->m_hWinSockDLL = LoadLibrary( _T("ws2_32.dll") );
  570. if (this->m_hWinSockDLL == NULL)
  571. {
  572. #ifdef DBG
  573. dwError = GetLastError();
  574. DPFX(DPFPREP, 1, "Couldn't load \"ws2_32.dll\" (err = 0x%lx), resorting to WinSock 1 functionality.",
  575. dwError);
  576. #endif // DBG
  577. this->m_hWinSockDLL = LoadLibrary( _T("wsock32.dll") );
  578. if (this->m_hWinSockDLL == NULL)
  579. {
  580. #ifdef DBG
  581. dwError = GetLastError();
  582. DPFX(DPFPREP, 0, "Couldn't load \"wsock32.dll\" either (err = 0x%lx)!.",
  583. dwError);
  584. #endif // DBG
  585. hr = DPNHERR_GENERIC;
  586. goto Failure;
  587. }
  588. //
  589. // Remember that we had to resort to WinSock 1.
  590. //
  591. this->m_dwFlags |= NATHELPPASTOBJ_WINSOCK1;
  592. }
  593. else
  594. {
  595. DPFX(DPFPREP, 1, "Loaded \"ws2_32.dll\", using WinSock 2 functionality.");
  596. }
  597. //
  598. // Load pointers to all the functions we use in WinSock.
  599. //
  600. hr = this->LoadWinSockFunctionPointers();
  601. if (hr != DPNH_OK)
  602. {
  603. DPFX(DPFPREP, 0, "Couldn't load WinSock function pointers!");
  604. goto Failure;
  605. }
  606. //
  607. // Fire up WinSock. Request 2.2 if we can. For the most part we only use
  608. // version 1.1 capabilities and interfaces anyway. The only exceptions are
  609. // using using the event or I/O completion port handles for notification.
  610. //
  611. ZeroMemory(&wsadata, sizeof(wsadata));
  612. if (this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1)
  613. {
  614. iError = this->m_pfnWSAStartup(MAKEWORD(1, 1), &wsadata);
  615. }
  616. else
  617. {
  618. iError = this->m_pfnWSAStartup(MAKEWORD(2, 2), &wsadata);
  619. }
  620. if (iError != 0)
  621. {
  622. DPFX(DPFPREP, 0, "Couldn't startup WinSock (error = %i)!", iError);
  623. hr = DPNHERR_GENERIC;
  624. goto Failure;
  625. }
  626. fWinSockStarted = TRUE;
  627. DPFX(DPFPREP, 4, "Initialized WinSock version %u.%u.",
  628. LOBYTE(wsadata.wVersion), HIBYTE(wsadata.wVersion));
  629. //
  630. // Try creating a UDP socket for use with WSAIoctl. Do this even if we're
  631. // WinSock 1 and can't use WSAIoctl socket. This allows us to make sure
  632. // TCP/IP is installed and working.
  633. //
  634. this->m_sIoctls = this->m_pfnsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  635. if (this->m_sIoctls == INVALID_SOCKET)
  636. {
  637. #ifdef DBG
  638. dwError = this->m_pfnWSAGetLastError();
  639. DPFX(DPFPREP, 0, "Couldn't create Ioctl socket, error = %u!", dwError);
  640. #endif // DBG
  641. hr = DPNHERR_GENERIC;
  642. goto Failure;
  643. }
  644. //
  645. // Try binding the socket. This is a continuation of the validation.
  646. //
  647. ZeroMemory(&saddrinTemp, sizeof(saddrinTemp));
  648. saddrinTemp.sin_family = AF_INET;
  649. //saddrinTemp.sin_addr.S_un.S_addr = INADDR_ANY;
  650. //saddrinTemp.sin_port = 0;
  651. if (this->m_pfnbind(this->m_sIoctls,
  652. (SOCKADDR *) (&saddrinTemp),
  653. sizeof(saddrinTemp)) != 0)
  654. {
  655. #ifdef DBG
  656. dwError = this->m_pfnWSAGetLastError();
  657. DPFX(DPFPREP, 0, "Couldn't bind the Ioctl socket to arbitrary port on any interface, error = %u!",
  658. dwError);
  659. #endif // DBG
  660. hr = DPNHERR_GENERIC;
  661. goto Failure;
  662. }
  663. //
  664. // Get the address + port tuple actually bound.
  665. //
  666. iAddressSize = sizeof(saddrinTemp);
  667. if (this->m_pfngetsockname(this->m_sIoctls,
  668. (SOCKADDR*) (&saddrinTemp),
  669. &iAddressSize) != 0)
  670. {
  671. #ifdef DBG
  672. dwError = this->m_pfnWSAGetLastError();
  673. DPFX(DPFPREP, 0, "Couldn't get socket name, error = %u!", dwError);
  674. #endif // DBG
  675. hr = DPNHERR_GENERIC;
  676. goto Failure;
  677. }
  678. //
  679. // WinSock needs to have bound to all adapters (because we told it to).
  680. //
  681. DNASSERT(saddrinTemp.sin_addr.S_un.S_addr == INADDR_ANY);
  682. this->m_wIoctlSocketPort = saddrinTemp.sin_port;
  683. DPFX(DPFPREP, 8, "Bound Ioctl socket to port %u.",
  684. NTOHS(this->m_wIoctlSocketPort));
  685. //
  686. // Build the list of IP capable devices.
  687. //
  688. hr = this->CheckForNewDevices(NULL);
  689. if (hr != DPNH_OK)
  690. {
  691. DPFX(DPFPREP, 0, "Couldn't build device list!");
  692. goto Failure;
  693. }
  694. //
  695. // We could technically try to contact PAST servers right now, but we don't
  696. // because it's a slow blocking operation, and users have to call GetCaps
  697. // at least once anyway.
  698. //
  699. Exit:
  700. if (fHaveLock)
  701. {
  702. this->DropLock();
  703. fHaveLock = FALSE;
  704. }
  705. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  706. return hr;
  707. Failure:
  708. this->RemoveAllItems();
  709. if (this->m_sIoctls != INVALID_SOCKET)
  710. {
  711. this->m_pfnclosesocket(this->m_sIoctls); // ignore error
  712. this->m_sIoctls = INVALID_SOCKET;
  713. }
  714. if (fWinSockStarted)
  715. {
  716. this->m_pfnWSACleanup(); // ignore error
  717. }
  718. if (this->m_hWinSockDLL != NULL)
  719. {
  720. this->m_pfnWSAStartup = NULL;
  721. this->m_pfnWSACleanup = NULL;
  722. this->m_pfnWSAGetLastError = NULL;
  723. this->m_pfnsocket = NULL;
  724. this->m_pfnclosesocket = NULL;
  725. this->m_pfnbind = NULL;
  726. this->m_pfnsetsockopt = NULL;
  727. this->m_pfngetsockname = NULL;
  728. this->m_pfnselect = NULL;
  729. this->m_pfn__WSAFDIsSet = NULL;
  730. this->m_pfnrecvfrom = NULL;
  731. this->m_pfnsendto = NULL;
  732. this->m_pfngethostname = NULL;
  733. this->m_pfngethostbyname = NULL;
  734. this->m_pfninet_addr = NULL;
  735. this->m_pfnWSASocketA = NULL;
  736. this->m_pfnWSAIoctl = NULL;
  737. this->m_pfnWSAGetOverlappedResult = NULL;
  738. this->m_dwFlags &= ~NATHELPPASTOBJ_WINSOCK1;
  739. FreeLibrary(this->m_hWinSockDLL);
  740. this->m_hWinSockDLL = NULL;
  741. }
  742. if (this->m_hIpHlpApiDLL != NULL)
  743. {
  744. this->m_pfnGetAdaptersInfo = NULL;
  745. this->m_pfnGetIpForwardTable = NULL;
  746. this->m_pfnGetBestRoute = NULL;
  747. FreeLibrary(this->m_hIpHlpApiDLL);
  748. this->m_hIpHlpApiDLL = NULL;
  749. }
  750. if (fSetFlags)
  751. {
  752. this->m_dwFlags &= ~(NATHELPPASTOBJ_INITIALIZED |
  753. NATHELPPASTOBJ_USEPASTICS |
  754. NATHELPPASTOBJ_USEPASTPFW |
  755. NATHELPPASTOBJ_DEVICECHANGED);
  756. }
  757. goto Exit;
  758. } // CNATHelpPAST::Initialize
  759. #undef DPF_MODNAME
  760. #define DPF_MODNAME "CNATHelpPAST::Close"
  761. //=============================================================================
  762. // CNATHelpPAST::Close
  763. //-----------------------------------------------------------------------------
  764. //
  765. // Description: Shuts down and de-registers this application with any
  766. // Internet gateway servers. All port assignments are implicitly
  767. // freed as a result of this operation.
  768. //
  769. // This must balance a successful call to Initialize.
  770. //
  771. // Arguments:
  772. // DWORD dwFlags - Unused, must be zero.
  773. //
  774. // Returns: HRESULT
  775. // DPNH_OK - Closing the helper API was successful.
  776. // DPNHERR_GENERIC - An error occurred while closing.
  777. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  778. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  779. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  780. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  781. // DPNHERR_OUTOFMEMORY - There is not enough memory to close.
  782. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  783. // thread.
  784. //=============================================================================
  785. STDMETHODIMP CNATHelpPAST::Close(const DWORD dwFlags)
  786. {
  787. HRESULT hr;
  788. BOOL fHaveLock = FALSE;
  789. int iError;
  790. #ifdef DBG
  791. DWORD dwError;
  792. #endif // DBG
  793. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%lx)", this, dwFlags);
  794. //
  795. // Validate the object.
  796. //
  797. if (! this->IsValidObject())
  798. {
  799. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  800. hr = DPNHERR_INVALIDOBJECT;
  801. goto Failure;
  802. }
  803. //
  804. // Validate the parameters.
  805. //
  806. if (dwFlags != 0)
  807. {
  808. DPFX(DPFPREP, 0, "Invalid flags specified!");
  809. hr = DPNHERR_INVALIDFLAGS;
  810. goto Failure;
  811. }
  812. //
  813. // Attempt to take the lock, but be prepared for the re-entrancy error.
  814. //
  815. hr = this->TakeLock();
  816. if (hr != DPNH_OK)
  817. {
  818. DPFX(DPFPREP, 0, "Could not lock object!");
  819. goto Failure;
  820. }
  821. fHaveLock = TRUE;
  822. //
  823. // Make sure object is in right state.
  824. //
  825. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  826. {
  827. DPFX(DPFPREP, 0, "Object not initialized!");
  828. hr = DPNHERR_NOTINITIALIZED;
  829. goto Failure;
  830. }
  831. //
  832. // We need to actively deregister any devices which are registered with
  833. // Internet gateways.
  834. //
  835. this->RemoveAllItems();
  836. //
  837. // Close the Ioctl socket.
  838. //
  839. DNASSERT(this->m_sIoctls != INVALID_SOCKET);
  840. this->m_pfnclosesocket(this->m_sIoctls); // ignore error
  841. this->m_sIoctls = INVALID_SOCKET;
  842. //
  843. // If we submitted overlapped I/O, see if it got cancelled.
  844. //
  845. if (this->m_polAddressListChange != NULL)
  846. {
  847. OSVERSIONINFO osvi;
  848. OSVERSIONINFOEX osvix;
  849. BOOL fCanWait;
  850. DWORD dwAttempt;
  851. ZeroMemory(&osvi, sizeof(osvi));
  852. osvi.dwOSVersionInfoSize = sizeof(osvi);
  853. if (GetVersionEx(&osvi))
  854. {
  855. //
  856. // Any platform but Win2K Gold, Win2K + SP1, or Win2K + SP2 can
  857. // just go ahead and wait for the I/O to complete.
  858. //
  859. if ((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) ||
  860. (osvi.dwMajorVersion > 5) ||
  861. (osvi.dwMinorVersion > 0))
  862. {
  863. DPFX(DPFPREP, 3, "Windows %s version %u.%u detected, waiting for address list change Ioctl to complete.",
  864. ((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) ? _T("9x") : _T("NT")),
  865. osvi.dwMajorVersion, osvi.dwMinorVersion);
  866. fCanWait = TRUE;
  867. }
  868. else
  869. {
  870. //
  871. // Win2K versions < SP3 have a bug where the I/O is not always
  872. // cancelled by closing the socket. We can't wait for the
  873. // completion, sometimes it doesn't happen.
  874. //
  875. fCanWait = FALSE;
  876. ZeroMemory(&osvix, sizeof(osvix));
  877. osvix.dwOSVersionInfoSize = sizeof(osvix);
  878. if (GetVersionEx((LPOSVERSIONINFO) (&osvix)))
  879. {
  880. //
  881. // If SP3 or later is applied, we know it's fixed.
  882. //
  883. if (osvix.wServicePackMajor >= 3)
  884. {
  885. DPFX(DPFPREP, 3, "Windows 2000 Service Pack %u detected, waiting for address list change Ioctl to complete.",
  886. osvix.wServicePackMajor);
  887. fCanWait = TRUE;
  888. }
  889. #ifdef DBG
  890. else
  891. {
  892. if (osvix.wServicePackMajor == 0)
  893. {
  894. DPFX(DPFPREP, 2, "Windows 2000 Gold detected, not waiting for address list change Ioctl to complete.");
  895. }
  896. else
  897. {
  898. DPFX(DPFPREP, 2, "Windows 2000 Service Pack %u detected, not waiting for address list change Ioctl to complete.",
  899. osvix.wServicePackMajor);
  900. }
  901. }
  902. #endif // DBG
  903. }
  904. #ifdef DBG
  905. else
  906. {
  907. dwError = GetLastError();
  908. DPFX(DPFPREP, 0, "Couldn't get extended OS version information (err = %u)!.",
  909. dwError);
  910. }
  911. #endif // DBG
  912. }
  913. //
  914. // Wait, if we can. Otherwise, leak the memory.
  915. //
  916. if (fCanWait)
  917. {
  918. //
  919. // Keep looping until I/O completes. We will give up after a
  920. // while to prevent hangs.
  921. //
  922. dwAttempt = 0;
  923. while (! HasOverlappedIoCompleted(this->m_polAddressListChange))
  924. {
  925. DPFX(DPFPREP, 2, "Waiting %u ms for address list change Ioctl to complete.",
  926. IOCOMPLETE_WAIT_INTERVAL);
  927. //
  928. // Give the OS some time to complete it.
  929. //
  930. Sleep(IOCOMPLETE_WAIT_INTERVAL);
  931. dwAttempt++;
  932. if (dwAttempt >= MAX_NUM_IOCOMPLETE_WAITS)
  933. {
  934. break;
  935. }
  936. }
  937. }
  938. else
  939. {
  940. //
  941. // Just leak the memory. See above notes and debug print
  942. // statements
  943. //
  944. }
  945. }
  946. #ifdef DBG
  947. else
  948. {
  949. dwError = GetLastError();
  950. DPFX(DPFPREP, 0, "Couldn't get OS version information (err = %u)!",
  951. dwError);
  952. }
  953. #endif // DBG
  954. //
  955. // We've either freed the memory or committed to leaking the object.
  956. //
  957. if (HasOverlappedIoCompleted(this->m_polAddressListChange))
  958. {
  959. //
  960. // We didn't allocate it through DNMalloc, use the matching free
  961. // function.
  962. //
  963. HeapFree(GetProcessHeap(), 0, this->m_polAddressListChange);
  964. }
  965. else
  966. {
  967. DPFX(DPFPREP, 1, "Overlapped address list change Ioctl has not completed yet, leaking %u byte overlapped structure at 0x%p.",
  968. sizeof(WSAOVERLAPPED), this->m_polAddressListChange);
  969. }
  970. this->m_polAddressListChange = NULL;
  971. }
  972. //
  973. // Cleanup WinSock.
  974. //
  975. iError = this->m_pfnWSACleanup();
  976. if (iError != 0)
  977. {
  978. #ifdef DBG
  979. dwError = this->m_pfnWSAGetLastError();
  980. DPFX(DPFPREP, 0, "Couldn't cleanup WinSock (error = %u)!", dwError);
  981. #endif // DBG
  982. //
  983. // Continue anyway, so we can finish cleaning up the object.
  984. //
  985. }
  986. //
  987. // Unload the library.
  988. //
  989. this->m_pfnWSAStartup = NULL;
  990. this->m_pfnWSACleanup = NULL;
  991. this->m_pfnWSAGetLastError = NULL;
  992. this->m_pfnsocket = NULL;
  993. this->m_pfnclosesocket = NULL;
  994. this->m_pfnbind = NULL;
  995. this->m_pfnsetsockopt = NULL;
  996. this->m_pfngetsockname = NULL;
  997. this->m_pfnselect = NULL;
  998. this->m_pfn__WSAFDIsSet = NULL;
  999. this->m_pfnrecvfrom = NULL;
  1000. this->m_pfnsendto = NULL;
  1001. this->m_pfngethostname = NULL;
  1002. this->m_pfngethostbyname = NULL;
  1003. this->m_pfninet_addr = NULL;
  1004. this->m_pfnWSASocketA = NULL;
  1005. this->m_pfnWSAIoctl = NULL;
  1006. this->m_pfnWSAGetOverlappedResult = NULL;
  1007. FreeLibrary(this->m_hWinSockDLL);
  1008. this->m_hWinSockDLL = NULL;
  1009. //
  1010. // If we loaded IPHLPAPI.DLL, unload it.
  1011. //
  1012. if (this->m_hIpHlpApiDLL != NULL)
  1013. {
  1014. this->m_pfnGetAdaptersInfo = NULL;
  1015. this->m_pfnGetIpForwardTable = NULL;
  1016. this->m_pfnGetBestRoute = NULL;
  1017. FreeLibrary(this->m_hIpHlpApiDLL);
  1018. this->m_hIpHlpApiDLL = NULL;
  1019. }
  1020. //
  1021. // If there was an alert event, we're done with it.
  1022. //
  1023. if (this->m_hAlertEvent != NULL)
  1024. {
  1025. CloseHandle(this->m_hAlertEvent);
  1026. this->m_hAlertEvent = NULL;
  1027. }
  1028. //
  1029. // If there was an alert I/O completion port, we're done with it.
  1030. //
  1031. if (this->m_hAlertIOCompletionPort != NULL)
  1032. {
  1033. CloseHandle(this->m_hAlertIOCompletionPort);
  1034. this->m_hAlertIOCompletionPort = NULL;
  1035. }
  1036. //
  1037. // Turn off flags which should reset it back to 0 or just the
  1038. // NOTCREATEDWITHCOM flag.
  1039. //
  1040. this->m_dwFlags &= ~(NATHELPPASTOBJ_INITIALIZED |
  1041. NATHELPPASTOBJ_USEPASTICS |
  1042. NATHELPPASTOBJ_USEPASTPFW |
  1043. NATHELPPASTOBJ_WINSOCK1 |
  1044. NATHELPPASTOBJ_DEVICECHANGED |
  1045. NATHELPPASTOBJ_ADDRESSESCHANGED |
  1046. NATHELPPASTOBJ_PORTREGISTERED);
  1047. DNASSERT((this->m_dwFlags & ~NATHELPPASTOBJ_NOTCREATEDWITHCOM) == 0);
  1048. this->DropLock();
  1049. fHaveLock = FALSE;
  1050. Exit:
  1051. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  1052. return hr;
  1053. Failure:
  1054. if (fHaveLock)
  1055. {
  1056. this->DropLock();
  1057. fHaveLock = FALSE;
  1058. }
  1059. goto Exit;
  1060. } // CNATHelpPAST::Close
  1061. #undef DPF_MODNAME
  1062. #define DPF_MODNAME "CNATHelpPAST::GetCaps"
  1063. //=============================================================================
  1064. // CNATHelpPAST::GetCaps
  1065. //-----------------------------------------------------------------------------
  1066. //
  1067. // Description: Retrieves the capabilities of the Internet gateway server(s)
  1068. // and information on leased ports. This function should be
  1069. // called periodically with the DPNHGETCAPS_UPDATESERVERSTATUS
  1070. // flag to automatically extend port leases that are about to
  1071. // expire (that are in last 2 minutes of their lease).
  1072. //
  1073. // The DPNHGETCAPS_UPDATESERVERSTATUS flag also causes
  1074. // detection of changes in the servers' status since the last
  1075. // similar call to GetCaps. If a new server becomes available, an
  1076. // existing one became unavailable, or a server's public address
  1077. // changed in a way that affects an existing registered port
  1078. // mapping, then DPNHSUCCESS_ADDRESSESCHANGED is returned instead
  1079. // of DPNH_OK. The user should then update its port binding
  1080. // information via GetRegisteredAddresses.
  1081. //
  1082. // When DPNHGETCAPS_UPDATESERVERSTATUS is specified, this
  1083. // function may block for a short period of time while attempts
  1084. // are made to communicate with the server(s).
  1085. //
  1086. // GetCaps must be called with the
  1087. // DPNHGETCAPS_UPDATESERVERSTATUS flag at least once prior to
  1088. // using the GetRegisteredAddresses or QueryAddress methods.
  1089. //
  1090. // Arguments:
  1091. // DPNHCAPS * pdpnhcaps - Pointer to structure to be filled with the NAT
  1092. // helper's current capabilities. The dwSize
  1093. // field of the structure must be filled in before
  1094. // calling GetCaps.
  1095. // DWORD dwFlags - Flags to use when retrieving capabilities
  1096. // (DPNHGETCAPS_xxx).
  1097. //
  1098. // Returns: HRESULT
  1099. // DPNH_OK - Determining capabilities was successful.
  1100. // Address status has not changed.
  1101. // DPNHSUCCESS_ADDRESSESCHANGED - One or more of the registered port
  1102. // mappings' addresses changed, retrieve
  1103. // updated mappings with
  1104. // GetRegisteredAddress.
  1105. // DPNHERR_GENERIC - An error occurred while determining
  1106. // capabilities.
  1107. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  1108. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  1109. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  1110. // DPNHERR_INVALIDPOINTER - An invalid pointer was specified.
  1111. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  1112. // DPNHERR_OUTOFMEMORY - There is not enough memory to get
  1113. // capabilities.
  1114. // DPNHERR_REENTRANT - The interface has been re-entered on the
  1115. // same thread.
  1116. //=============================================================================
  1117. STDMETHODIMP CNATHelpPAST::GetCaps(DPNHCAPS * const pdpnhcaps,
  1118. const DWORD dwFlags)
  1119. {
  1120. HRESULT hr;
  1121. BOOL fHaveLock = FALSE;
  1122. DWORD dwCurrentTime;
  1123. DWORD dwLeaseTimeRemaining;
  1124. CBilink * pBilink;
  1125. CRegisteredPort * pRegisteredPort;
  1126. CDevice * pDevice;
  1127. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, 0x%lx)",
  1128. this, pdpnhcaps, dwFlags);
  1129. //
  1130. // Validate the object.
  1131. //
  1132. if (! this->IsValidObject())
  1133. {
  1134. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  1135. hr = DPNHERR_INVALIDOBJECT;
  1136. goto Failure;
  1137. }
  1138. //
  1139. // Validate the parameters.
  1140. //
  1141. if ((pdpnhcaps == NULL) ||
  1142. (IsBadWritePtr(pdpnhcaps, sizeof(DPNHCAPS))))
  1143. {
  1144. DPFX(DPFPREP, 0, "Invalid caps structure pointer specified!");
  1145. hr = DPNHERR_INVALIDPOINTER;
  1146. goto Failure;
  1147. }
  1148. if (pdpnhcaps->dwSize != sizeof(DPNHCAPS))
  1149. {
  1150. DPFX(DPFPREP, 0, "Invalid caps structure specified, dwSize must be %u!",
  1151. sizeof(DPNHCAPS));
  1152. hr = DPNHERR_INVALIDPARAM;
  1153. goto Failure;
  1154. }
  1155. if (dwFlags & ~DPNHGETCAPS_UPDATESERVERSTATUS)
  1156. {
  1157. DPFX(DPFPREP, 0, "Invalid flags specified!");
  1158. hr = DPNHERR_INVALIDFLAGS;
  1159. goto Failure;
  1160. }
  1161. //
  1162. // Attempt to take the lock, but be prepared for the re-entrancy error.
  1163. //
  1164. hr = this->TakeLock();
  1165. if (hr != DPNH_OK)
  1166. {
  1167. DPFX(DPFPREP, 0, "Could not lock object!");
  1168. goto Failure;
  1169. }
  1170. fHaveLock = TRUE;
  1171. //
  1172. // Make sure object is in right state.
  1173. //
  1174. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  1175. {
  1176. DPFX(DPFPREP, 0, "Object not initialized!");
  1177. hr = DPNHERR_NOTINITIALIZED;
  1178. goto Failure;
  1179. }
  1180. //
  1181. // Fill in the base caps structure.
  1182. //
  1183. pdpnhcaps->dwFlags = 0;
  1184. pdpnhcaps->dwNumRegisteredPorts = 0;
  1185. pdpnhcaps->dwMinLeaseTimeRemaining = -1;
  1186. //
  1187. // pdpnhcaps->dwRecommendedGetCapsInterval is initialized below
  1188. //
  1189. if (dwFlags & DPNHGETCAPS_UPDATESERVERSTATUS)
  1190. {
  1191. //
  1192. // Remove any cached mappings that have expired.
  1193. //
  1194. this->ExpireOldCachedMappings();
  1195. //
  1196. // Extend leases, if necessary.
  1197. //
  1198. hr = this->ExtendAllExpiringLeases();
  1199. if (hr != DPNH_OK)
  1200. {
  1201. DPFX(DPFPREP, 0, "Extending all expiring leases failed!");
  1202. goto Failure;
  1203. }
  1204. //
  1205. // Check for any new devices.
  1206. //
  1207. hr = this->CheckForNewDevices(NULL);
  1208. if (hr != DPNH_OK)
  1209. {
  1210. DPFX(DPFPREP, 0, "Checking for new devices failed!");
  1211. goto Failure;
  1212. }
  1213. //
  1214. // Check for possible changes in any server's status. The
  1215. // ADDRESSESCHANGED flag will be set on this object if there were
  1216. // changes that affected existing port mappings.
  1217. //
  1218. hr = this->UpdateServerStatus();
  1219. if (hr != DPNH_OK)
  1220. {
  1221. DPFX(DPFPREP, 0, "Updating servers' status failed!");
  1222. goto Failure;
  1223. }
  1224. //
  1225. // Okay, so if things are different, alert the caller.
  1226. //
  1227. if (this->m_dwFlags & NATHELPPASTOBJ_ADDRESSESCHANGED)
  1228. {
  1229. hr = DPNHSUCCESS_ADDRESSESCHANGED;
  1230. this->m_dwFlags &= ~NATHELPPASTOBJ_ADDRESSESCHANGED;
  1231. }
  1232. #ifdef DBG
  1233. //
  1234. // This flag should have been turned off by now if it ever got turned
  1235. // on.
  1236. //
  1237. DNASSERT(! (this->m_dwFlags & NATHELPPASTOBJ_DEVICECHANGED));
  1238. //
  1239. // Print the current device and mapping status for debugging purposes.
  1240. //
  1241. this->DebugPrintCurrentStatus();
  1242. #endif // DBG
  1243. }
  1244. else
  1245. {
  1246. //
  1247. // Not extending expiring leases or updating server status.
  1248. //
  1249. }
  1250. //
  1251. // Loop through all the devices, getting their gateway capabilities.
  1252. //
  1253. pBilink = this->m_blDevices.GetNext();
  1254. while (pBilink != (&this->m_blDevices))
  1255. {
  1256. pDevice = DEVICE_FROM_BILINK(pBilink);
  1257. if (pDevice->GetPASTClientID(TRUE) != 0)
  1258. {
  1259. //
  1260. // PAST servers do not actively notify you of address changes.
  1261. //
  1262. pdpnhcaps->dwFlags |= DPNHCAPSFLAG_GATEWAYPRESENT | DPNHCAPSFLAG_NOTALLSUPPORTACTIVENOTIFY;
  1263. if (pDevice->IsPASTPublicAddressAvailable(TRUE))
  1264. {
  1265. pdpnhcaps->dwFlags |= DPNHCAPSFLAG_PUBLICADDRESSAVAILABLE;
  1266. }
  1267. }
  1268. if (pDevice->GetPASTClientID(FALSE) != 0)
  1269. {
  1270. if (pDevice->HasLocalPFWOnlyPASTServer())
  1271. {
  1272. //
  1273. // PAST servers do not actively notify you of address changes.
  1274. //
  1275. pdpnhcaps->dwFlags |= DPNHCAPSFLAG_LOCALFIREWALLPRESENT | DPNHCAPSFLAG_NOTALLSUPPORTACTIVENOTIFY;
  1276. DNASSERT(pDevice->IsPASTPublicAddressAvailable(FALSE));
  1277. }
  1278. else
  1279. {
  1280. //
  1281. // PAST servers do not actively notify you of address changes.
  1282. //
  1283. pdpnhcaps->dwFlags |= DPNHCAPSFLAG_GATEWAYPRESENT | DPNHCAPSFLAG_GATEWAYISLOCAL | DPNHCAPSFLAG_NOTALLSUPPORTACTIVENOTIFY;
  1284. if (pDevice->IsPASTPublicAddressAvailable(FALSE))
  1285. {
  1286. pdpnhcaps->dwFlags |= DPNHCAPSFLAG_PUBLICADDRESSAVAILABLE;
  1287. }
  1288. }
  1289. }
  1290. pBilink = pBilink->GetNext();
  1291. }
  1292. //
  1293. // Loop through all registered ports, counting them.
  1294. // We have the appropriate lock.
  1295. //
  1296. pBilink = this->m_blRegisteredPorts.GetNext();
  1297. dwCurrentTime = timeGetTime();
  1298. while (pBilink != (&this->m_blRegisteredPorts))
  1299. {
  1300. pRegisteredPort = REGPORT_FROM_GLOBAL_BILINK(pBilink);
  1301. //
  1302. // Count these registered addresses toward the total.
  1303. //
  1304. pdpnhcaps->dwNumRegisteredPorts += pRegisteredPort->GetNumAddresses();
  1305. pDevice = pRegisteredPort->GetOwningDevice();
  1306. if (pDevice != NULL)
  1307. {
  1308. DNASSERT(! (pRegisteredPort->m_blDeviceList.IsListMember(&this->m_blUnownedPorts)));
  1309. //
  1310. // If they're registered with any PAST servers and also calculate
  1311. // the minimum lease time remaining.
  1312. //
  1313. if (pDevice->GetPASTClientID(FALSE) != 0)
  1314. {
  1315. dwLeaseTimeRemaining = pRegisteredPort->GetPASTLeaseExpiration(FALSE) - dwCurrentTime;
  1316. if (dwLeaseTimeRemaining < pdpnhcaps->dwMinLeaseTimeRemaining)
  1317. {
  1318. //
  1319. // Temporarily store how much time remains.
  1320. //
  1321. pdpnhcaps->dwMinLeaseTimeRemaining = dwLeaseTimeRemaining;
  1322. }
  1323. }
  1324. if (pDevice->GetPASTClientID(TRUE) != 0)
  1325. {
  1326. dwLeaseTimeRemaining = pRegisteredPort->GetPASTLeaseExpiration(TRUE) - dwCurrentTime;
  1327. if (dwLeaseTimeRemaining < pdpnhcaps->dwMinLeaseTimeRemaining)
  1328. {
  1329. //
  1330. // Temporarily store how much time remains.
  1331. //
  1332. pdpnhcaps->dwMinLeaseTimeRemaining = dwLeaseTimeRemaining;
  1333. }
  1334. }
  1335. }
  1336. else
  1337. {
  1338. DNASSERT(pRegisteredPort->m_blDeviceList.IsListMember(&this->m_blUnownedPorts));
  1339. }
  1340. pBilink = pBilink->GetNext();
  1341. }
  1342. //
  1343. // There are different default recommended GetCaps intervals depending on
  1344. // whether there's a server present, and whether it supports active address
  1345. // change notification (that we can alert on) or not.
  1346. //
  1347. // If there are any leases which need to be renewed before that default
  1348. // time, the recommendation will be shortened appropriately.
  1349. //
  1350. //
  1351. // If GetCaps hasn't been called with UPDATESERVERSTATUS yet, recommend an
  1352. // immediate check.
  1353. //
  1354. if (this->m_dwLastUpdateServerStatusTime == 0)
  1355. {
  1356. DPFX(DPFPREP, 1, "Server status has not been updated yet, recommending immediate GetCaps.");
  1357. //
  1358. // Drop the lock, we're done here.
  1359. //
  1360. this->DropLock();
  1361. fHaveLock = FALSE;
  1362. goto Exit;
  1363. }
  1364. //
  1365. // In an ideal world, we could get notified of changes and we would never
  1366. // have to poll. Unfortunately that isn't the case. We need to recommend
  1367. // a relatively short poll interval.
  1368. //
  1369. // Start by figuring out how long it's been since the last server update.
  1370. // This calculation really should not go negative. If it does, it means
  1371. // the caller hasn't updated the server status in ages anyway, so we should
  1372. // recommend immediate GetCaps.
  1373. //
  1374. // Otherwise if the 'port registered' flag is still set at this point, then
  1375. // the user must have called GetCaps previously, then RegisterPorts, then
  1376. // made this second GetCaps call before g_dwMinUpdateServerStatusInterval
  1377. // elapsed. Recommend that the user call us again as soon as the minimum
  1378. // update interval does elapse.
  1379. //
  1380. // In all other cases, generate a recommendation based on the current
  1381. // backed off poll interval.
  1382. //
  1383. dwCurrentTime = dwCurrentTime - this->m_dwLastUpdateServerStatusTime;
  1384. if ((int) dwCurrentTime < 0)
  1385. {
  1386. DPFX(DPFPREP, 1, "Server status was last updated a really long time ago (%u ms), recommending immediate GetCaps.",
  1387. dwCurrentTime);
  1388. pdpnhcaps->dwRecommendedGetCapsInterval = 0;
  1389. }
  1390. else if (this->m_dwFlags & NATHELPPASTOBJ_PORTREGISTERED)
  1391. {
  1392. DPFX(DPFPREP, 1, "Didn't handle new port registration because server was last updated %u ms ago, (poll interval staying at %u ms).",
  1393. dwCurrentTime, this->m_dwNextPollInterval);
  1394. pdpnhcaps->dwRecommendedGetCapsInterval = g_dwMinUpdateServerStatusInterval - dwCurrentTime;
  1395. if ((int) pdpnhcaps->dwRecommendedGetCapsInterval < 0)
  1396. {
  1397. pdpnhcaps->dwRecommendedGetCapsInterval = 0;
  1398. }
  1399. }
  1400. else
  1401. {
  1402. DPFX(DPFPREP, 7, "Server was last updated %u ms ago, current poll interval is %u ms.",
  1403. dwCurrentTime, this->m_dwNextPollInterval);
  1404. //
  1405. // Calculate a new recommended interval based on the current value, and
  1406. // backoff that interval if necessary.
  1407. //
  1408. pdpnhcaps->dwRecommendedGetCapsInterval = this->m_dwNextPollInterval - dwCurrentTime;
  1409. this->m_dwNextPollInterval += GetGlobalRand() % g_dwPollIntervalBackoff;
  1410. if (this->m_dwNextPollInterval > g_dwMaxPollInterval)
  1411. {
  1412. this->m_dwNextPollInterval = g_dwMaxPollInterval;
  1413. DPFX(DPFPREP, 3, "Capping next poll interval at %u ms.",
  1414. this->m_dwNextPollInterval);
  1415. }
  1416. else
  1417. {
  1418. DPFX(DPFPREP, 8, "Next poll interval will be %u ms.",
  1419. this->m_dwNextPollInterval);
  1420. }
  1421. //
  1422. // If that time went negative, then it implies that the interval has
  1423. // already elapsed. Recommend immediate GetCaps.
  1424. //
  1425. if (((int) pdpnhcaps->dwRecommendedGetCapsInterval) < 0)
  1426. {
  1427. DPFX(DPFPREP, 1, "Recommended interval already elapsed (%i ms), suggesting immediate GetCaps.",
  1428. ((int) pdpnhcaps->dwRecommendedGetCapsInterval));
  1429. pdpnhcaps->dwRecommendedGetCapsInterval = 0;
  1430. }
  1431. }
  1432. this->DropLock();
  1433. fHaveLock = FALSE;
  1434. //
  1435. // If there is a non-INFINITE lease time remaining, see if that affects the
  1436. // GetCaps interval.
  1437. //
  1438. if (pdpnhcaps->dwMinLeaseTimeRemaining != -1)
  1439. {
  1440. //
  1441. // If there are leases that need to be refreshed before the default
  1442. // recommendation, then use those instead.
  1443. //
  1444. if (pdpnhcaps->dwMinLeaseTimeRemaining < LEASE_RENEW_TIME)
  1445. {
  1446. DPFX(DPFPREP, 1, "Lease needs renewing right away (min %u < %u ms), recommending immediate GetCaps.",
  1447. pdpnhcaps->dwMinLeaseTimeRemaining, LEASE_RENEW_TIME);
  1448. pdpnhcaps->dwRecommendedGetCapsInterval = 0;
  1449. }
  1450. else
  1451. {
  1452. //
  1453. // Either pick the time when the lease should be renewed or leave
  1454. // it as the recommended time, whichever is shorter.
  1455. //
  1456. if ((pdpnhcaps->dwMinLeaseTimeRemaining - LEASE_RENEW_TIME) < pdpnhcaps->dwRecommendedGetCapsInterval)
  1457. {
  1458. pdpnhcaps->dwRecommendedGetCapsInterval = pdpnhcaps->dwMinLeaseTimeRemaining - LEASE_RENEW_TIME;
  1459. }
  1460. }
  1461. }
  1462. DPFX(DPFPREP, 7, "GetCaps flags = 0x%lx, num registered ports = %u, min lease time remaining = %i, recommended interval = %i.",
  1463. pdpnhcaps->dwFlags,
  1464. pdpnhcaps->dwNumRegisteredPorts,
  1465. ((int) pdpnhcaps->dwMinLeaseTimeRemaining),
  1466. ((int) pdpnhcaps->dwRecommendedGetCapsInterval));
  1467. Exit:
  1468. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  1469. return hr;
  1470. Failure:
  1471. if (fHaveLock)
  1472. {
  1473. this->DropLock();
  1474. fHaveLock = FALSE;
  1475. }
  1476. goto Exit;
  1477. } // CNATHelpPAST::GetCaps
  1478. #undef DPF_MODNAME
  1479. #define DPF_MODNAME "CNATHelpPAST::RegisterPorts"
  1480. //=============================================================================
  1481. // CNATHelpPAST::RegisterPorts
  1482. //-----------------------------------------------------------------------------
  1483. //
  1484. // Description: Asks for public realm port(s) that are aliases for the local
  1485. // port(s) on this private realm node. If a server is available,
  1486. // all traffic directed to the gateway on the public side at the
  1487. // allocated public ports-- which the gateway provides and
  1488. // specifies in the response-- will be directed to the specified
  1489. // local ports. If the DPNHREGISTERPORTS_FIXEDPORTS flag is not
  1490. // specified, the ports assigned on the public interface are
  1491. // arbitrary (i.e. may not be the same as those in awLocalPort).
  1492. // The address and ports actually allocated can be retrieved by
  1493. // calling GetRegisteredAddresses.
  1494. //
  1495. // The address component for every SOCKADDR structure in the
  1496. // array must be the same. A separate RegisterPorts call is
  1497. // required to register multiple ports that are not using the same
  1498. // interface. The address can be INADDR_ANY, in which case the
  1499. // "best" server will be used. If multiple servers are available
  1500. // via different adapters, an adapter with an Internet gateway is
  1501. // selected. If no adapters have Internet gateways, the first
  1502. // adapter with a local firewall is selected. If neither are
  1503. // available, then the first one where either a gateway or a
  1504. // firewall becomes available will be automatically selected.
  1505. // Once one of the adapters has been assigned, it cannot be
  1506. // changed. Since the server chosen by this method may not be
  1507. // optimal for a particular application, it is recommended that
  1508. // individual addresses be registered instead of INADDR_ANY.
  1509. //
  1510. // If the address in aLocalAddresses is not one of those
  1511. // available to the local machine, the registration will still
  1512. // succeed. If an adapter with that address becomes available,
  1513. // the port mapping will automatically be applied, and it will
  1514. // gain a public mapping with any server available to that
  1515. // adapter. If the address was originally available but the
  1516. // network adapter is subsequently removed from the system, any
  1517. // public address mapping is lost. It will be automatically
  1518. // regained if the local address becomes available again. It is
  1519. // recommended that the caller detect local address changes
  1520. // independently and de-register/re-register mappings per adapter
  1521. // as appropriate for maximum control.
  1522. //
  1523. // If the DPNHREGISTERPORTS_SHAREDPORTS flag is used, the
  1524. // server will allow other NAT clients to register it as well.
  1525. // Any UDP traffic received on the public interface will be
  1526. // forwarded to all clients registered. This requires the
  1527. // DPNHREGISTERPORTS_FIXEDPORTS flag and cannot be used with
  1528. // DPNHREGISTERPORTS_TCP.
  1529. //
  1530. // The user should specify a requested lease time that the
  1531. // server will attempt to honor. The actual time remaining can be
  1532. // can be retrieved by calling GetRegisteredAddresses.
  1533. //
  1534. // Note that if a server is not available, this function will
  1535. // still succeed. GetRegisteredAddresses will return
  1536. // DPNHERR_NOMAPPING for the handle returned in phRegisteredPorts
  1537. // in that case. If the server arrives later during the session,
  1538. // calling GetCaps periodically can detect this and automatically
  1539. // map previously registered ports. Use GetRegisteredAddresses to
  1540. // retrieve the newly mapped address when that occurs.
  1541. //
  1542. // Only 16 ports may be registered at a time, but RegisterPorts
  1543. // may be called as many times as desired.
  1544. //
  1545. // The same array of addresses may be registered more than
  1546. // once. Each DPNHHANDLE returned must be released with
  1547. // DeregisterPorts or Close. If an individual address was
  1548. // previously registered but in a different array or a different
  1549. // order in the array, then the DPNHERR_PORTALREADYREGISTERED
  1550. // error code is returned.
  1551. //
  1552. // Arguments:
  1553. // SOCKADDR * aLocalAddresses - Array of local address and port tuples
  1554. // for which remote ports are requested.
  1555. // DWORD dwAddressesSize - Size of entire local addresses array.
  1556. // DWORD dwNumAddresses - Number of SOCKADDR structures in local
  1557. // addresses array.
  1558. // DWORD dwLeaseTime - Requested time, in milliseconds, to lease
  1559. // the ports. As long as GetCaps is
  1560. // called before this time has expired,
  1561. // the lease will automatically be
  1562. // renewed.
  1563. // DPNHHANDLE * phRegisteredPorts - Place to store an identifier for this
  1564. // binding which can later be used to
  1565. // query or release the binding.
  1566. // DWORD dwFlags - Flags to use when registering the port
  1567. // (DPNHREGISTERPORTS_xxx).
  1568. //
  1569. // Returns: HRESULT
  1570. // DPNH_OK - The ports were successfully registered
  1571. // (although no public address may be
  1572. // available yet).
  1573. // DPNHERR_GENERIC - An error occurred that prevented
  1574. // registration of the requested ports.
  1575. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  1576. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  1577. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  1578. // DPNHERR_INVALIDPOINTER - An invalid pointer was specified.
  1579. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  1580. // DPNHERR_OUTOFMEMORY - There is not enough memory to register
  1581. // the ports.
  1582. // DPNHERR_PORTALREADYREGISTERED - At least one of the ports has already
  1583. // been registered in a different address
  1584. // array or order.
  1585. // DPNHERR_REENTRANT - The interface has been re-entered on the
  1586. // same thread.
  1587. //=============================================================================
  1588. STDMETHODIMP CNATHelpPAST::RegisterPorts(const SOCKADDR * const aLocalAddresses,
  1589. const DWORD dwAddressesSize,
  1590. const DWORD dwNumAddresses,
  1591. const DWORD dwLeaseTime,
  1592. DPNHHANDLE * const phRegisteredPorts,
  1593. const DWORD dwFlags)
  1594. {
  1595. HRESULT hr;
  1596. HRESULT temphr;
  1597. ULONG ulFirstAddress;
  1598. DWORD dwTemp;
  1599. DWORD dwMatch;
  1600. BOOL fHaveLock = FALSE;
  1601. BOOL fGotLocalPASTMapping = FALSE;
  1602. BOOL fGotRemotePASTMapping = FALSE;
  1603. CRegisteredPort * pRegisteredPort = NULL;
  1604. CDevice * pDevice = NULL;
  1605. CBilink * pBilink;
  1606. SOCKADDR_IN * psaddrinTemp;
  1607. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, %u, %u, %u, 0x%p, 0x%lx)",
  1608. this, aLocalAddresses, dwAddressesSize, dwNumAddresses, dwLeaseTime,
  1609. phRegisteredPorts, dwFlags);
  1610. //
  1611. // Validate the object.
  1612. //
  1613. if (! this->IsValidObject())
  1614. {
  1615. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  1616. hr = DPNHERR_INVALIDOBJECT;
  1617. goto Failure;
  1618. }
  1619. //
  1620. // Validate the parameters.
  1621. //
  1622. if (aLocalAddresses == NULL)
  1623. {
  1624. DPFX(DPFPREP, 0, "Local addresses array cannot be NULL!");
  1625. hr = DPNHERR_INVALIDPOINTER;
  1626. goto Failure;
  1627. }
  1628. if (dwNumAddresses == 0)
  1629. {
  1630. DPFX(DPFPREP, 0, "Number of addresses cannot be 0!");
  1631. hr = DPNHERR_INVALIDPARAM;
  1632. goto Failure;
  1633. }
  1634. if (dwAddressesSize != (dwNumAddresses * sizeof(SOCKADDR)))
  1635. {
  1636. DPFX(DPFPREP, 0, "Addresses array size invalid!");
  1637. hr = DPNHERR_INVALIDPARAM;
  1638. goto Failure;
  1639. }
  1640. if (IsBadReadPtr(aLocalAddresses, dwAddressesSize))
  1641. {
  1642. DPFX(DPFPREP, 0, "Local addresses array buffer is invalid!");
  1643. hr = DPNHERR_INVALIDPOINTER;
  1644. goto Failure;
  1645. }
  1646. if (dwNumAddresses > DPNH_MAX_SIMULTANEOUS_PORTS)
  1647. {
  1648. DPFX(DPFPREP, 0, "Only %u ports may be registered at a time!", DPNH_MAX_SIMULTANEOUS_PORTS);
  1649. hr = DPNHERR_INVALIDPARAM;
  1650. goto Failure;
  1651. }
  1652. if (((SOCKADDR_IN*) aLocalAddresses)->sin_family != AF_INET)
  1653. {
  1654. DPFX(DPFPREP, 0, "First address in array is not AF_INET, only IPv4 addresses are supported!");
  1655. hr = DPNHERR_INVALIDPARAM;
  1656. goto Failure;
  1657. }
  1658. if (((SOCKADDR_IN*) aLocalAddresses)->sin_addr.S_un.S_addr == INADDR_BROADCAST)
  1659. {
  1660. DPFX(DPFPREP, 0, "First address cannot be broadcast address!");
  1661. hr = DPNHERR_INVALIDPARAM;
  1662. goto Failure;
  1663. }
  1664. if (((SOCKADDR_IN*) aLocalAddresses)->sin_port == 0)
  1665. {
  1666. DPFX(DPFPREP, 0, "First port in array is 0, a valid port must be specified!");
  1667. hr = DPNHERR_INVALIDPARAM;
  1668. goto Failure;
  1669. }
  1670. ulFirstAddress = ((SOCKADDR_IN*) aLocalAddresses)->sin_addr.S_un.S_addr;
  1671. for(dwTemp = 1; dwTemp < dwNumAddresses; dwTemp++)
  1672. {
  1673. //
  1674. // Make sure this address family type is supported.
  1675. //
  1676. if (((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_family != AF_INET)
  1677. {
  1678. DPFX(DPFPREP, 0, "Address at array index %u is not AF_INET, all items in the array must be the same IPv4 address!",
  1679. dwTemp);
  1680. hr = DPNHERR_INVALIDPARAM;
  1681. goto Failure;
  1682. }
  1683. //
  1684. // If this address doesn't match the first, then the caller broke the
  1685. // rules.
  1686. //
  1687. if (((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_addr != ulFirstAddress)
  1688. {
  1689. //
  1690. // Don't use inet_ntoa because we may not be initialized yet.
  1691. //
  1692. DPFX(DPFPREP, 0, "Address %u.%u.%u.%u at array index %u differs from the first, all addresses in the array must match!",
  1693. ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_un_b.s_b1,
  1694. ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_un_b.s_b2,
  1695. ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_un_b.s_b3,
  1696. ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_un_b.s_b4,
  1697. dwTemp);
  1698. hr = DPNHERR_INVALIDPARAM;
  1699. goto Failure;
  1700. }
  1701. //
  1702. // Make sure this port isn't 0 either.
  1703. //
  1704. if (((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_port == 0)
  1705. {
  1706. DPFX(DPFPREP, 0, "Port at array index %u is 0, valid ports must be specified!", dwTemp);
  1707. hr = DPNHERR_INVALIDPARAM;
  1708. goto Failure;
  1709. }
  1710. }
  1711. if (dwLeaseTime == 0)
  1712. {
  1713. DPFX(DPFPREP, 0, "Invalid lease time specified!");
  1714. hr = DPNHERR_INVALIDPARAM;
  1715. goto Failure;
  1716. }
  1717. if ((phRegisteredPorts == NULL) ||
  1718. (IsBadWritePtr(phRegisteredPorts, sizeof(DPNHHANDLE))))
  1719. {
  1720. DPFX(DPFPREP, 0, "Invalid port mapping handle pointer specified!");
  1721. hr = DPNHERR_INVALIDPOINTER;
  1722. goto Failure;
  1723. }
  1724. if (dwFlags & ~(DPNHREGISTERPORTS_TCP | DPNHREGISTERPORTS_FIXEDPORTS | DPNHREGISTERPORTS_SHAREDPORTS))
  1725. {
  1726. DPFX(DPFPREP, 0, "Invalid flags specified!");
  1727. hr = DPNHERR_INVALIDFLAGS;
  1728. goto Failure;
  1729. }
  1730. if (dwFlags & DPNHREGISTERPORTS_SHAREDPORTS)
  1731. {
  1732. //
  1733. // SHAREDPORTS cannot be used with TCP and requires a FIXEDPORTS.
  1734. //
  1735. if ((dwFlags & DPNHREGISTERPORTS_TCP) || (! (dwFlags & DPNHREGISTERPORTS_FIXEDPORTS)))
  1736. {
  1737. DPFX(DPFPREP, 0, "SHAREDPORTS flag requires FIXEDPORTS flag and cannot be used with TCP flag!");
  1738. hr = DPNHERR_INVALIDFLAGS;
  1739. goto Failure;
  1740. }
  1741. }
  1742. //
  1743. // Attempt to take the lock, but be prepared for the re-entrancy error.
  1744. //
  1745. hr = this->TakeLock();
  1746. if (hr != DPNH_OK)
  1747. {
  1748. DPFX(DPFPREP, 0, "Could not lock object!");
  1749. goto Failure;
  1750. }
  1751. fHaveLock = TRUE;
  1752. //
  1753. // Make sure object is in right state.
  1754. //
  1755. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  1756. {
  1757. DPFX(DPFPREP, 0, "Object not initialized!");
  1758. hr = DPNHERR_NOTINITIALIZED;
  1759. goto Failure;
  1760. }
  1761. //
  1762. // Loop through all existing registered port mappings and look for this
  1763. // array of ports.
  1764. //
  1765. pBilink = this->m_blRegisteredPorts.GetNext();
  1766. while (pBilink != &this->m_blRegisteredPorts)
  1767. {
  1768. pRegisteredPort = REGPORT_FROM_GLOBAL_BILINK(pBilink);
  1769. //
  1770. // Don't bother looking at addresses of the wrong type or at arrays of
  1771. // the wrong size.
  1772. //
  1773. if (((pRegisteredPort->IsTCP() && (dwFlags & DPNHREGISTERPORTS_TCP)) ||
  1774. ((! pRegisteredPort->IsTCP()) && (! (dwFlags & DPNHREGISTERPORTS_TCP)))) &&
  1775. (pRegisteredPort->GetNumAddresses() == dwNumAddresses))
  1776. {
  1777. psaddrinTemp = pRegisteredPort->GetPrivateAddressesArray();
  1778. for(dwTemp = 0; dwTemp < dwNumAddresses; dwTemp++)
  1779. {
  1780. //
  1781. // If the addresses don't match, stop looping.
  1782. //
  1783. if ((psaddrinTemp[dwTemp].sin_port != ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_port) ||
  1784. (psaddrinTemp[dwTemp].sin_addr.S_un.S_addr != ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_addr))
  1785. {
  1786. break;
  1787. }
  1788. }
  1789. //
  1790. // If all the addresses matched, then this item was already
  1791. // registered.
  1792. //
  1793. if (dwTemp >= dwNumAddresses)
  1794. {
  1795. DPFX(DPFPREP, 1, "Array of %u addresses was already registered, returning existing mapping 0x%p.",
  1796. dwNumAddresses, pRegisteredPort);
  1797. goto ReturnUserHandle;
  1798. }
  1799. DPFX(DPFPREP, 7, "Existing mapping 0x%p does not match all %u addresses.",
  1800. pRegisteredPort, dwNumAddresses);
  1801. }
  1802. else
  1803. {
  1804. //
  1805. // Existing mapping isn't same type or doesn't have same number of
  1806. // items in array.
  1807. //
  1808. }
  1809. pBilink = pBilink->GetNext();
  1810. }
  1811. //
  1812. // If we're here, none of the existing mappings match. Loop through each
  1813. // of the ports and make sure they aren't already registered inside some
  1814. // other mapping.
  1815. //
  1816. for(dwTemp = 0; dwTemp < dwNumAddresses; dwTemp++)
  1817. {
  1818. pBilink = this->m_blRegisteredPorts.GetNext();
  1819. while (pBilink != &this->m_blRegisteredPorts)
  1820. {
  1821. pRegisteredPort = REGPORT_FROM_GLOBAL_BILINK(pBilink);
  1822. psaddrinTemp = pRegisteredPort->GetPrivateAddressesArray();
  1823. for(dwMatch = 0; dwMatch < pRegisteredPort->GetNumAddresses(); dwMatch++)
  1824. {
  1825. //
  1826. // If the addresses match, then we can't map these ports.
  1827. //
  1828. if ((psaddrinTemp[dwMatch].sin_port == ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_port) &&
  1829. (psaddrinTemp[dwMatch].sin_addr.S_un.S_addr == ((SOCKADDR_IN*) (&aLocalAddresses[dwTemp]))->sin_addr.S_un.S_addr))
  1830. {
  1831. DPFX(DPFPREP, 0, "Existing mapping 0x%p already registered the address %u.%u.%u.%u:%u!",
  1832. pRegisteredPort,
  1833. psaddrinTemp[dwMatch].sin_addr.S_un.S_un_b.s_b1,
  1834. psaddrinTemp[dwMatch].sin_addr.S_un.S_un_b.s_b2,
  1835. psaddrinTemp[dwMatch].sin_addr.S_un.S_un_b.s_b3,
  1836. psaddrinTemp[dwMatch].sin_addr.S_un.S_un_b.s_b4,
  1837. NTOHS(psaddrinTemp[dwMatch].sin_port));
  1838. //
  1839. // Clear the pointer so we don't delete the object.
  1840. //
  1841. pRegisteredPort = NULL;
  1842. hr = DPNHERR_PORTALREADYREGISTERED;
  1843. goto Failure;
  1844. }
  1845. }
  1846. pBilink = pBilink->GetNext();
  1847. }
  1848. }
  1849. //
  1850. // If we're here the ports are all unique. Create a new mapping object
  1851. // we'll use to refer to the binding.
  1852. //
  1853. pRegisteredPort = new CRegisteredPort(dwLeaseTime, dwFlags);
  1854. if (pRegisteredPort == NULL)
  1855. {
  1856. hr = DPNHERR_OUTOFMEMORY;
  1857. goto Failure;
  1858. }
  1859. hr = pRegisteredPort->SetPrivateAddresses((SOCKADDR_IN*) aLocalAddresses, dwNumAddresses);
  1860. if (hr != DPNH_OK)
  1861. {
  1862. DPFX(DPFPREP, 0, "Couldn't store private addresses array!");
  1863. goto Failure;
  1864. }
  1865. //
  1866. // Find the device that matches the given addresses.
  1867. //
  1868. // The first entry of aLocalAddresses is representative of all entries since
  1869. // they should all share the same address.
  1870. //
  1871. // Since there won't be an existing registered port for this address, don't
  1872. // bother looking through them for a matching address.
  1873. //
  1874. pDevice = this->FindMatchingDevice((SOCKADDR_IN*) (&aLocalAddresses[0]),
  1875. FALSE);
  1876. if (pDevice == NULL)
  1877. {
  1878. DPFX(DPFPREP, 1, "No device for given address (%u.%u.%u.%u), storing 0x%p in unowned list.",
  1879. ((SOCKADDR_IN*) aLocalAddresses)->sin_addr.S_un.S_un_b.s_b1,
  1880. ((SOCKADDR_IN*) aLocalAddresses)->sin_addr.S_un.S_un_b.s_b2,
  1881. ((SOCKADDR_IN*) aLocalAddresses)->sin_addr.S_un.S_un_b.s_b3,
  1882. ((SOCKADDR_IN*) aLocalAddresses)->sin_addr.S_un.S_un_b.s_b4,
  1883. pRegisteredPort);
  1884. pRegisteredPort->m_blDeviceList.InsertBefore(&this->m_blUnownedPorts);
  1885. }
  1886. else
  1887. {
  1888. pRegisteredPort->MakeDeviceOwner(pDevice);
  1889. //
  1890. // If we have a client ID, that means the server is available. So if
  1891. // there's either a local or remote PAST server, we can request the
  1892. // mapping right now.
  1893. // Start with the local PAST server.
  1894. //
  1895. if (pDevice->GetPASTClientID(FALSE) != 0)
  1896. {
  1897. hr = this->AssignOrListenPASTPort(pRegisteredPort, FALSE);
  1898. if (hr != DPNH_OK)
  1899. {
  1900. if (hr != DPNHERR_PORTUNAVAILABLE)
  1901. {
  1902. DPFX(DPFPREP, 0, "Couldn't assign port mapping with local PAST server (0x%lx)! Ignoring.", hr);
  1903. //
  1904. // We'll treat this as non-fatal, but we have to dump the
  1905. // server.
  1906. //
  1907. this->ClearDevicesPASTServer(pDevice, FALSE);
  1908. }
  1909. else
  1910. {
  1911. DPFX(DPFPREP, 1, "Local PAST server indicated that the port was unavailable.");
  1912. pRegisteredPort->NotePASTPortUnavailable(FALSE);
  1913. }
  1914. hr = DPNH_OK;
  1915. }
  1916. else
  1917. {
  1918. fGotLocalPASTMapping = TRUE;
  1919. }
  1920. }
  1921. else
  1922. {
  1923. //
  1924. // No local PAST server.
  1925. //
  1926. }
  1927. //
  1928. // Check remote PAST server, too.
  1929. //
  1930. if (pDevice->GetPASTClientID(TRUE) != 0)
  1931. {
  1932. hr = this->AssignOrListenPASTPort(pRegisteredPort, TRUE);
  1933. if (hr != DPNH_OK)
  1934. {
  1935. if (hr != DPNHERR_PORTUNAVAILABLE)
  1936. {
  1937. DPFX(DPFPREP, 0, "Couldn't assign port mapping with remote PAST server (0x%lx)! Ignoring.", hr);
  1938. //
  1939. // We'll treat this as non-fatal, but we have to dump the
  1940. // server.
  1941. //
  1942. this->ClearDevicesPASTServer(pDevice, TRUE);
  1943. }
  1944. else
  1945. {
  1946. DPFX(DPFPREP, 1, "Remote PAST server indicated that the port was unavailable.");
  1947. pRegisteredPort->NotePASTPortUnavailable(TRUE);
  1948. }
  1949. hr = DPNH_OK;
  1950. }
  1951. else
  1952. {
  1953. fGotRemotePASTMapping = TRUE;
  1954. }
  1955. }
  1956. else
  1957. {
  1958. //
  1959. // No remote PAST server.
  1960. //
  1961. }
  1962. }
  1963. //
  1964. // Save the mapping in the global list (we have the lock).
  1965. //
  1966. pRegisteredPort->m_blGlobalList.InsertBefore(&this->m_blRegisteredPorts);
  1967. ReturnUserHandle:
  1968. //
  1969. // Remember that a port has been registered.
  1970. //
  1971. this->m_dwFlags |= NATHELPPASTOBJ_PORTREGISTERED;
  1972. //
  1973. // We're about to give the port to the user.
  1974. //
  1975. pRegisteredPort->AddUserRef();
  1976. //
  1977. // We're going to give the user a direct pointer to the object (disguised
  1978. // as an opaque DPNHHANDLE, of course).
  1979. //
  1980. (*phRegisteredPorts) = (DPNHHANDLE) pRegisteredPort;
  1981. this->DropLock();
  1982. fHaveLock = FALSE;
  1983. DPFX(DPFPREP, 5, "Returning registered port 0x%p (first private address = %u.%u.%u.%u:%u).",
  1984. pRegisteredPort,
  1985. ((SOCKADDR_IN*) aLocalAddresses)[0].sin_addr.S_un.S_un_b.s_b1,
  1986. ((SOCKADDR_IN*) aLocalAddresses)[0].sin_addr.S_un.S_un_b.s_b2,
  1987. ((SOCKADDR_IN*) aLocalAddresses)[0].sin_addr.S_un.S_un_b.s_b3,
  1988. ((SOCKADDR_IN*) aLocalAddresses)[0].sin_addr.S_un.S_un_b.s_b4,
  1989. NTOHS(((SOCKADDR_IN*) aLocalAddresses)[0].sin_port));
  1990. hr = DPNH_OK;
  1991. Exit:
  1992. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  1993. return hr;
  1994. Failure:
  1995. if (fGotRemotePASTMapping)
  1996. {
  1997. temphr = this->FreePASTPort(pRegisteredPort, TRUE);
  1998. if (temphr != DPNH_OK)
  1999. {
  2000. //
  2001. // We'll treat this as non-fatal, but we have to dump the server.
  2002. //
  2003. this->ClearDevicesPASTServer(pRegisteredPort->GetOwningDevice(), TRUE);
  2004. }
  2005. }
  2006. if (fGotLocalPASTMapping)
  2007. {
  2008. temphr = this->FreePASTPort(pRegisteredPort, FALSE);
  2009. if (temphr != DPNH_OK)
  2010. {
  2011. //
  2012. // We'll treat this as non-fatal, but we have to dump the server.
  2013. //
  2014. this->ClearDevicesPASTServer(pRegisteredPort->GetOwningDevice(), FALSE);
  2015. }
  2016. }
  2017. if (pRegisteredPort != NULL)
  2018. {
  2019. if (pDevice != NULL)
  2020. {
  2021. pRegisteredPort->ClearDeviceOwner();
  2022. }
  2023. pRegisteredPort->ClearPrivateAddresses();
  2024. delete pRegisteredPort;
  2025. }
  2026. if (fHaveLock)
  2027. {
  2028. this->DropLock();
  2029. fHaveLock = FALSE;
  2030. }
  2031. goto Exit;
  2032. } // CNATHelpPAST::RegisterPorts
  2033. #undef DPF_MODNAME
  2034. #define DPF_MODNAME "CNATHelpPAST::GetRegisteredAddresses"
  2035. //=============================================================================
  2036. // CNATHelpPAST::GetRegisteredAddresses
  2037. //-----------------------------------------------------------------------------
  2038. //
  2039. // Description: Returns the current public address mappings for a given
  2040. // registered port group. If there are no servers currently
  2041. // available, then DPNHERR_SERVERNOTAVAILABLE is returned. If the
  2042. // servers' public interfaces are not currently valid, then
  2043. // DPNHERR_NOMAPPING is returned, but appropriate values will
  2044. // still be placed in pdwAddressTypeFlags and
  2045. // pdwLeaseTimeRemaining.
  2046. //
  2047. // If the mapping was registered with the
  2048. // DPNHREGISTERPORTS_FIXEDPORTS flag, but at least one port is
  2049. // already in use on the gateway, then DPNHERR_PORTUNAVAILABLE is
  2050. // returned and appropriate flags will still be placed in
  2051. // pdwAddressTypeFlags.
  2052. //
  2053. // If the local machine has a cooperative firewall installed,
  2054. // the requested port is opened locally on the firewall before
  2055. // being mapped on the Internet gateway. Normally this function
  2056. // returns the public address on the Internet gateway address when
  2057. // both are present. Since some firewalls remap the port number
  2058. // when opening non-fixed ports, the
  2059. // DPNHGETREGISTEREDADDRESSES_LOCALFIREWALLREMAPONLY allows the
  2060. // caller to retrieve the locally remapped address, even if there
  2061. // is a mapping on an Internet gateway.
  2062. //
  2063. // Some gateway devices do not natively support ports that are
  2064. // not fixed, and may generate the DPNHERR_PORTUNAVAILABLE return
  2065. // code even when the DPNHREGISTERPORTS_FIXEDPORTS flag was not
  2066. // specified. The caller should de-register the port mapping
  2067. // handle, rebind the application to different ports, and call
  2068. // RegisterPorts again.
  2069. //
  2070. // If the buffer indicated by paPublicAddresses is too small,
  2071. // then the size required is returned in pdwPublicAddressesSize
  2072. // and DPNHERR_BUFFERTOOSMALL is returned. Otherwise the number of
  2073. // bytes written is returned in pdwPublicAddressesSize.
  2074. //
  2075. // Even though the addresses are returned as individual
  2076. // SOCKADDRs, all ports registered at the same time will share the
  2077. // same public address. Only the port components will vary.
  2078. //
  2079. // All buffers are optional and may be NULL, but if
  2080. // paPublicAddresses is specified, it must be accompanied by an
  2081. // appropriate size in pdwPublicAddressesSize.
  2082. //
  2083. // If GetCaps has not been previously called with the
  2084. // DPNHGETCAPS_UPDATESERVERSTATUS flag at least once, then the
  2085. // error code DPNHERR_UPDATESERVERSTATUS is returned.
  2086. //
  2087. // Arguments:
  2088. // DPNHHANDLE hRegisteredPorts - Handle for a specific binding returned by
  2089. // RegisterPorts.
  2090. // SOCKADDR * paPublicAddresses - Buffer to return assigned public realm
  2091. // address, or NULL if not desired.
  2092. // DWORD * pdwPublicAddressesSize - Pointer to size of paPublicAddresses
  2093. // buffer, or place to store size
  2094. // required/written. Cannot be NULL if
  2095. // paPublicAddresses is not NULL.
  2096. // DWORD * pdwAddressTypeFlags - Place to store flags describing the
  2097. // address types returned, or NULL if not
  2098. // desired.
  2099. // DWORD * pdwLeaseTimeRemaining - Place to store approximate number of
  2100. // milliseconds remaining in the port
  2101. // lease, or NULL if not desired. Call
  2102. // GetCaps to automatically extend leases
  2103. // about to expire.
  2104. // DWORD dwFlags - Unused, must be zero.
  2105. //
  2106. // Returns: HRESULT
  2107. // DPNH_OK - Information on the port mapping was found and
  2108. // the addresses were stored in
  2109. // paPublicAddresses.
  2110. // DPNHERR_BUFFERTOOSMALL - There was not enough room in the buffer to
  2111. // store the addresses.
  2112. // DPNHERR_GENERIC - An error occurred while retrieving the
  2113. // requested port mapping.
  2114. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  2115. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  2116. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  2117. // DPNHERR_INVALIDPOINTER - An invalid pointer was specified.
  2118. // DPNHERR_NOMAPPING - The server(s) do not have valid public
  2119. // interfaces.
  2120. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  2121. // DPNHERR_OUTOFMEMORY - There is not enough memory to get the
  2122. // addresses.
  2123. // DPNHERR_PORTUNAVAILABLE - At least one of the ports is not available on
  2124. // the server.
  2125. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  2126. // thread.
  2127. // DPNHERR_SERVERNOTAVAILABLE - No servers are currently present.
  2128. // DPNHERR_UPDATESERVERSTATUS - GetCaps has not been called with the
  2129. // DPNHGETCAPS_UPDATESERVERSTATUS flag yet.
  2130. //=============================================================================
  2131. STDMETHODIMP CNATHelpPAST::GetRegisteredAddresses(const DPNHHANDLE hRegisteredPorts,
  2132. SOCKADDR * const paPublicAddresses,
  2133. DWORD * const pdwPublicAddressesSize,
  2134. DWORD * const pdwAddressTypeFlags,
  2135. DWORD * const pdwLeaseTimeRemaining,
  2136. const DWORD dwFlags)
  2137. {
  2138. HRESULT hr;
  2139. CRegisteredPort * pRegisteredPort;
  2140. BOOL fHaveLock = FALSE;
  2141. BOOL fRegisteredWithServer = FALSE;
  2142. BOOL fFoundValidMapping = FALSE;
  2143. BOOL fPortIsUnavailable = FALSE;
  2144. DWORD dwSizeRequired;
  2145. DWORD dwAddressTypeFlags;
  2146. DWORD dwCurrentTime;
  2147. DWORD dwTempLeaseTimeRemaining;
  2148. DWORD dwLeaseTimeRemaining = -1;
  2149. CDevice * pDevice;
  2150. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, 0x%p, 0x%p, 0x%p, 0x%p, 0x%lx)",
  2151. this, hRegisteredPorts, paPublicAddresses, pdwPublicAddressesSize,
  2152. pdwAddressTypeFlags, pdwLeaseTimeRemaining, dwFlags);
  2153. //
  2154. // Validate the object.
  2155. //
  2156. if (! this->IsValidObject())
  2157. {
  2158. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  2159. hr = DPNHERR_INVALIDOBJECT;
  2160. goto Failure;
  2161. }
  2162. //
  2163. // Validate the parameters.
  2164. //
  2165. pRegisteredPort = (CRegisteredPort*) hRegisteredPorts;
  2166. if (! pRegisteredPort->IsValidObject())
  2167. {
  2168. DPFX(DPFPREP, 0, "Invalid registered port mapping handle specified!");
  2169. hr = DPNHERR_INVALIDPARAM;
  2170. goto Failure;
  2171. }
  2172. if (paPublicAddresses != NULL)
  2173. {
  2174. if ((pdwPublicAddressesSize == NULL) ||
  2175. (IsBadWritePtr(pdwPublicAddressesSize, sizeof(DWORD))))
  2176. {
  2177. DPFX(DPFPREP, 0, "When specifying a public addresses buffer, a valid size must be given!");
  2178. hr = DPNHERR_INVALIDPOINTER;
  2179. goto Failure;
  2180. }
  2181. if (IsBadWritePtr(paPublicAddresses, (*pdwPublicAddressesSize)))
  2182. {
  2183. DPFX(DPFPREP, 0, "The public addresses buffer is invalid!");
  2184. hr = DPNHERR_INVALIDPOINTER;
  2185. goto Failure;
  2186. }
  2187. }
  2188. else
  2189. {
  2190. if ((pdwPublicAddressesSize != NULL) &&
  2191. (IsBadWritePtr(pdwPublicAddressesSize, sizeof(DWORD))))
  2192. {
  2193. DPFX(DPFPREP, 0, "Invalid pointer for size of public addresses buffer!");
  2194. hr = DPNHERR_INVALIDPOINTER;
  2195. goto Failure;
  2196. }
  2197. }
  2198. if ((pdwAddressTypeFlags != NULL) &&
  2199. (IsBadWritePtr(pdwAddressTypeFlags, sizeof(DWORD))))
  2200. {
  2201. DPFX(DPFPREP, 0, "Invalid pointer for address type flags!");
  2202. hr = DPNHERR_INVALIDPOINTER;
  2203. goto Failure;
  2204. }
  2205. if ((pdwLeaseTimeRemaining != NULL) &&
  2206. (IsBadWritePtr(pdwLeaseTimeRemaining, sizeof(DWORD))))
  2207. {
  2208. DPFX(DPFPREP, 0, "Invalid pointer for lease time remaining!");
  2209. hr = DPNHERR_INVALIDPOINTER;
  2210. goto Failure;
  2211. }
  2212. if (dwFlags & ~DPNHGETREGISTEREDADDRESSES_LOCALFIREWALLREMAPONLY)
  2213. {
  2214. DPFX(DPFPREP, 0, "Invalid flags specified!");
  2215. hr = DPNHERR_INVALIDFLAGS;
  2216. goto Failure;
  2217. }
  2218. //
  2219. // Start the flags off with the information regarding TCP vs. UDP.
  2220. //
  2221. if (pRegisteredPort->IsTCP())
  2222. {
  2223. dwAddressTypeFlags = DPNHADDRESSTYPE_TCP;
  2224. }
  2225. else
  2226. {
  2227. dwAddressTypeFlags = 0;
  2228. }
  2229. //
  2230. // Add in other flags we know already.
  2231. //
  2232. if (pRegisteredPort->IsFixedPort())
  2233. {
  2234. dwAddressTypeFlags |= DPNHADDRESSTYPE_FIXEDPORTS;
  2235. }
  2236. if (pRegisteredPort->IsSharedPort())
  2237. {
  2238. dwAddressTypeFlags |= DPNHADDRESSTYPE_SHAREDPORTS;
  2239. }
  2240. //
  2241. // Attempt to take the lock, but be prepared for the re-entrancy error.
  2242. //
  2243. hr = this->TakeLock();
  2244. if (hr != DPNH_OK)
  2245. {
  2246. DPFX(DPFPREP, 0, "Could not lock object!");
  2247. goto Failure;
  2248. }
  2249. fHaveLock = TRUE;
  2250. //
  2251. // Make sure object is in right state.
  2252. //
  2253. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  2254. {
  2255. DPFX(DPFPREP, 0, "Object not initialized!");
  2256. hr = DPNHERR_NOTINITIALIZED;
  2257. goto Failure;
  2258. }
  2259. if (this->m_dwLastUpdateServerStatusTime == 0)
  2260. {
  2261. DPFX(DPFPREP, 0, "GetCaps has not been called with UPDATESERVERSTATUS flag yet!");
  2262. hr = DPNHERR_UPDATESERVERSTATUS;
  2263. goto Failure;
  2264. }
  2265. //
  2266. // Get a shortcut pointer to the device (may not exist).
  2267. //
  2268. pDevice = pRegisteredPort->GetOwningDevice();
  2269. //
  2270. // Get the current time for both the remote and local lease calculations.
  2271. //
  2272. dwCurrentTime = timeGetTime();
  2273. if (! (dwFlags & DPNHGETREGISTEREDADDRESSES_LOCALFIREWALLREMAPONLY))
  2274. {
  2275. //
  2276. // Check for a mapping on a remote PAST server.
  2277. //
  2278. if (pRegisteredPort->GetPASTBindID(TRUE) != 0)
  2279. {
  2280. DNASSERT(pDevice != NULL);
  2281. //
  2282. // There's a bind ID, so there must be a public address array.
  2283. //
  2284. DNASSERT(pRegisteredPort->HasPASTPublicAddressesArray(TRUE));
  2285. fRegisteredWithServer = TRUE;
  2286. //
  2287. // Make sure the remote PAST server is currently giving out a valid
  2288. // public address. If so, hand it out.
  2289. //
  2290. if (pDevice->IsPASTPublicAddressAvailable(TRUE))
  2291. {
  2292. if (pdwPublicAddressesSize != NULL)
  2293. {
  2294. dwSizeRequired = pRegisteredPort->GetAddressesSize();
  2295. if ((paPublicAddresses == NULL) ||
  2296. (dwSizeRequired > (*pdwPublicAddressesSize)))
  2297. {
  2298. //
  2299. // Not enough room in buffer, return the size required
  2300. // and the BUFFERTOOSMALL error code.
  2301. //
  2302. (*pdwPublicAddressesSize) = dwSizeRequired;
  2303. hr = DPNHERR_BUFFERTOOSMALL;
  2304. }
  2305. else
  2306. {
  2307. //
  2308. // Buffer was large enough, return the size written.
  2309. //
  2310. (*pdwPublicAddressesSize) = dwSizeRequired;
  2311. pRegisteredPort->CopyPASTPublicAddresses((SOCKADDR_IN*) paPublicAddresses,
  2312. TRUE);
  2313. }
  2314. }
  2315. else
  2316. {
  2317. //
  2318. // Not using address buffer.
  2319. //
  2320. }
  2321. fFoundValidMapping = TRUE;
  2322. }
  2323. else
  2324. {
  2325. DPFX(DPFPREP, 8, "The remote PAST server is not currently handing out valid public address mappings.");
  2326. }
  2327. //
  2328. // Add in the flag indicating that there's a remote ICS server.
  2329. //
  2330. dwAddressTypeFlags |= DPNHADDRESSTYPE_GATEWAY;
  2331. //
  2332. // Get the relative remote PAST server lease time remaining.
  2333. //
  2334. dwTempLeaseTimeRemaining = pRegisteredPort->GetPASTLeaseExpiration(TRUE) - dwCurrentTime;
  2335. if (((int) dwTempLeaseTimeRemaining) < 0)
  2336. {
  2337. DPFX(DPFPREP, 1, "Registered port mapping's remote PAST server lease has already expired, returning 0 for lease time remaining.");
  2338. dwLeaseTimeRemaining = 0;
  2339. }
  2340. else
  2341. {
  2342. //
  2343. // The values are relative, so we don't have to worry about
  2344. // wraparound.
  2345. //
  2346. //if (dwTempLeaseTimeRemaining < dwLeaseTimeRemaining)
  2347. //{
  2348. dwLeaseTimeRemaining = dwTempLeaseTimeRemaining;
  2349. //}
  2350. }
  2351. }
  2352. else
  2353. {
  2354. //
  2355. // No bind ID, no public address array.
  2356. //
  2357. DNASSERT(! pRegisteredPort->HasPASTPublicAddressesArray(TRUE));
  2358. if (pRegisteredPort->IsPASTPortUnavailable(TRUE))
  2359. {
  2360. DNASSERT(pDevice != NULL);
  2361. fRegisteredWithServer = TRUE;
  2362. fPortIsUnavailable = TRUE;
  2363. DPFX(DPFPREP, 8, "The remote PAST server indicates the port(s) are unavailable.");
  2364. //
  2365. // Add in the flag indicating that there's a remote ICS server.
  2366. //
  2367. dwAddressTypeFlags |= DPNHADDRESSTYPE_GATEWAY;
  2368. }
  2369. #ifdef DBG
  2370. else
  2371. {
  2372. //
  2373. // No remote PAST server or it's an unowned port.
  2374. //
  2375. if (pDevice != NULL)
  2376. {
  2377. DNASSERT(pDevice->GetPASTClientID(TRUE) == 0);
  2378. }
  2379. else
  2380. {
  2381. DNASSERT(pRegisteredPort->m_blDeviceList.IsListMember(&this->m_blUnownedPorts));
  2382. }
  2383. }
  2384. #endif // DBG
  2385. }
  2386. }
  2387. else
  2388. {
  2389. //
  2390. // We're not allowed to return the remote PAST mapping.
  2391. //
  2392. DPFX(DPFPREP, 8, "Ignoring any Internet gateway mappings, LOCALFIREWALLREMAPONLY was specified.");
  2393. }
  2394. //
  2395. // Finally, check for a mapping on a local PAST server.
  2396. //
  2397. if (pRegisteredPort->GetPASTBindID(FALSE) != 0)
  2398. {
  2399. DNASSERT(pDevice != NULL);
  2400. //
  2401. // There's a bind ID, so there must be a public address array.
  2402. //
  2403. DNASSERT(pRegisteredPort->HasPASTPublicAddressesArray(FALSE));
  2404. fRegisteredWithServer = TRUE;
  2405. //
  2406. // If we didn't already get a remote mapping, return this local one.
  2407. //
  2408. if (! fFoundValidMapping)
  2409. {
  2410. //
  2411. // Make sure the local PAST server is currently giving out a valid
  2412. // public address. If so, hand it out.
  2413. //
  2414. if (pDevice->IsPASTPublicAddressAvailable(FALSE))
  2415. {
  2416. if (pdwPublicAddressesSize != NULL)
  2417. {
  2418. dwSizeRequired = pRegisteredPort->GetAddressesSize();
  2419. if ((paPublicAddresses == NULL) ||
  2420. (dwSizeRequired > (*pdwPublicAddressesSize)))
  2421. {
  2422. //
  2423. // Not enough room in buffer, return the size required
  2424. // and the BUFFERTOOSMALL error code.
  2425. //
  2426. (*pdwPublicAddressesSize) = dwSizeRequired;
  2427. hr = DPNHERR_BUFFERTOOSMALL;
  2428. }
  2429. else
  2430. {
  2431. //
  2432. // Buffer was large enough, return the size written.
  2433. //
  2434. (*pdwPublicAddressesSize) = dwSizeRequired;
  2435. pRegisteredPort->CopyPASTPublicAddresses((SOCKADDR_IN*) paPublicAddresses,
  2436. FALSE);
  2437. }
  2438. }
  2439. else
  2440. {
  2441. //
  2442. // Not using address buffer.
  2443. //
  2444. }
  2445. fFoundValidMapping = TRUE;
  2446. }
  2447. else
  2448. {
  2449. DPFX(DPFPREP, 8, "The local PAST server is not currently handing out valid public address mappings.");
  2450. }
  2451. }
  2452. else
  2453. {
  2454. DPFX(DPFPREP, 6, "Ignoring possible local PAST server mapping due to remote PAST server mapping.");
  2455. }
  2456. //
  2457. // Add in the flag indicating whether this is a PFW only or ICS server.
  2458. //
  2459. if (pDevice->HasLocalPFWOnlyPASTServer())
  2460. {
  2461. dwAddressTypeFlags |= DPNHADDRESSTYPE_LOCALFIREWALL;
  2462. }
  2463. else
  2464. {
  2465. dwAddressTypeFlags |= DPNHADDRESSTYPE_GATEWAY | DPNHADDRESSTYPE_GATEWAYISLOCAL;
  2466. }
  2467. //
  2468. // Get the relative time remaining.
  2469. //
  2470. dwTempLeaseTimeRemaining = pRegisteredPort->GetPASTLeaseExpiration(FALSE) - dwCurrentTime;
  2471. if (((int) dwTempLeaseTimeRemaining) < 0)
  2472. {
  2473. DPFX(DPFPREP, 1, "Registered port mapping's local PAST server lease has already expired, returning 0 for lease time remaining.");
  2474. dwLeaseTimeRemaining = 0;
  2475. }
  2476. else
  2477. {
  2478. //
  2479. // If that time remaining is less than the remote PAST server lease
  2480. // time (if any), overwrite it with the shorter time. The values
  2481. // are relative, so we don't have to worry about wraparound.
  2482. //
  2483. if (dwTempLeaseTimeRemaining < dwLeaseTimeRemaining)
  2484. {
  2485. dwLeaseTimeRemaining = dwTempLeaseTimeRemaining;
  2486. }
  2487. }
  2488. }
  2489. else
  2490. {
  2491. //
  2492. // No bind ID, no public address array.
  2493. //
  2494. DNASSERT(! pRegisteredPort->HasPASTPublicAddressesArray(FALSE));
  2495. if (pRegisteredPort->IsPASTPortUnavailable(FALSE))
  2496. {
  2497. DNASSERT(pDevice != NULL);
  2498. fRegisteredWithServer = TRUE;
  2499. fPortIsUnavailable = TRUE;
  2500. DPFX(DPFPREP, 8, "The local PAST server indicates the port(s) are unavailable.");
  2501. //
  2502. // Add in the flag indicating whether this is a PFW only or ICS server.
  2503. //
  2504. if (pDevice->HasLocalPFWOnlyPASTServer())
  2505. {
  2506. dwAddressTypeFlags |= DPNHADDRESSTYPE_LOCALFIREWALL;
  2507. }
  2508. else
  2509. {
  2510. dwAddressTypeFlags |= DPNHADDRESSTYPE_GATEWAY | DPNHADDRESSTYPE_GATEWAYISLOCAL;
  2511. }
  2512. }
  2513. #ifdef DBG
  2514. else
  2515. {
  2516. //
  2517. // No local PAST server or it's an unowned port.
  2518. //
  2519. if (pDevice != NULL)
  2520. {
  2521. DNASSERT(pDevice->GetPASTClientID(FALSE) == 0);
  2522. }
  2523. else
  2524. {
  2525. DNASSERT(pRegisteredPort->m_blDeviceList.IsListMember(&this->m_blUnownedPorts));
  2526. }
  2527. }
  2528. #endif // DBG
  2529. }
  2530. this->DropLock();
  2531. fHaveLock = FALSE;
  2532. if (fRegisteredWithServer)
  2533. {
  2534. DNASSERT(dwAddressTypeFlags & (DPNHADDRESSTYPE_LOCALFIREWALL | DPNHADDRESSTYPE_GATEWAY));
  2535. if (! fFoundValidMapping)
  2536. {
  2537. if (fPortIsUnavailable)
  2538. {
  2539. //
  2540. // The servers indicated that the ports were already in use.
  2541. // Return PORTUNAVAILABLE.
  2542. //
  2543. DPFX(DPFPREP, 1, "The Internet gateway(s) could not map the port, returning PORTUNAVAILABLE.");
  2544. hr = DPNHERR_PORTUNAVAILABLE;
  2545. }
  2546. else
  2547. {
  2548. //
  2549. // The servers didn't have public addresses. Return NOMAPPING.
  2550. //
  2551. DPFX(DPFPREP, 1, "The Internet gateway(s) did not offer valid public addresses, returning NOMAPPING.");
  2552. hr = DPNHERR_NOMAPPING;
  2553. }
  2554. }
  2555. else
  2556. {
  2557. //
  2558. // One of the servers had a public address.
  2559. //
  2560. DNASSERT((hr == DPNH_OK) || (hr == DPNHERR_BUFFERTOOSMALL));
  2561. }
  2562. }
  2563. else
  2564. {
  2565. //
  2566. // The ports aren't registered, because there aren't any gateways.
  2567. // Return SERVERNOTAVAILABLE.
  2568. //
  2569. DPFX(DPFPREP, 1, "No Internet gateways, returning SERVERNOTAVAILABLE.");
  2570. hr = DPNHERR_SERVERNOTAVAILABLE;
  2571. }
  2572. //
  2573. // If the caller wants information on the type of these addresses, return
  2574. // the flags we detected.
  2575. //
  2576. if (pdwAddressTypeFlags != NULL)
  2577. {
  2578. (*pdwAddressTypeFlags) = dwAddressTypeFlags;
  2579. }
  2580. //
  2581. // Return the minimum lease time remaining that we already calculated, if
  2582. // the caller wants it.
  2583. //
  2584. if (pdwLeaseTimeRemaining != NULL)
  2585. {
  2586. (*pdwLeaseTimeRemaining) = dwLeaseTimeRemaining;
  2587. }
  2588. #ifdef DBG
  2589. //
  2590. // If the port is unavailable or there aren't any servers, we better not
  2591. // have a lease time.
  2592. //
  2593. if ((hr == DPNHERR_PORTUNAVAILABLE) ||
  2594. (hr == DPNHERR_SERVERNOTAVAILABLE))
  2595. {
  2596. DNASSERT(dwLeaseTimeRemaining == -1);
  2597. }
  2598. //
  2599. // If there aren't any servers, we better not have server flags.
  2600. //
  2601. if (hr == DPNHERR_SERVERNOTAVAILABLE)
  2602. {
  2603. DNASSERT(! (dwAddressTypeFlags & (DPNHADDRESSTYPE_LOCALFIREWALL | DPNHADDRESSTYPE_GATEWAY)));
  2604. }
  2605. #endif // DBG
  2606. DPFX(DPFPREP, 5, "Registered port 0x%p addr type flags = 0x%lx, lease time remaining = %i.",
  2607. pRegisteredPort, dwAddressTypeFlags, (int) dwLeaseTimeRemaining);
  2608. Exit:
  2609. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  2610. return hr;
  2611. Failure:
  2612. if (fHaveLock)
  2613. {
  2614. this->DropLock();
  2615. fHaveLock = FALSE;
  2616. }
  2617. goto Exit;
  2618. } // CNATHelpPAST::GetRegisteredAddresses
  2619. #undef DPF_MODNAME
  2620. #define DPF_MODNAME "CNATHelpPAST::DeregisterPorts"
  2621. //=============================================================================
  2622. // CNATHelpPAST::DeregisterPorts
  2623. //-----------------------------------------------------------------------------
  2624. //
  2625. // Description: Removes the lease record for the port group and informs the
  2626. // Internet gateway server that the binding is no longer needed.
  2627. // The port mapping handle must not be used after de-registering
  2628. // it.
  2629. //
  2630. // Arguments:
  2631. // DPNHHANDLE hRegisteredPorts - Handle for a specific binding returned by
  2632. // RegisterPorts.
  2633. // DWORD dwFlags - Unused, must be zero.
  2634. //
  2635. // Returns: HRESULT
  2636. // DPNH_OK - The binding was successfully released.
  2637. // DPNHERR_GENERIC - An error occurred that prevented the
  2638. // de-registration of the ports.
  2639. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  2640. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  2641. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  2642. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  2643. // DPNHERR_OUTOFMEMORY - There is not enough memory to de-register.
  2644. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  2645. // thread.
  2646. //=============================================================================
  2647. STDMETHODIMP CNATHelpPAST::DeregisterPorts(const DPNHHANDLE hRegisteredPorts,
  2648. const DWORD dwFlags)
  2649. {
  2650. HRESULT hr;
  2651. CRegisteredPort * pRegisteredPort;
  2652. BOOL fHaveLock = FALSE;
  2653. LONG lResult;
  2654. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, 0x%lx)",
  2655. this, hRegisteredPorts, dwFlags);
  2656. //
  2657. // Validate the object.
  2658. //
  2659. if (! this->IsValidObject())
  2660. {
  2661. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  2662. hr = DPNHERR_INVALIDOBJECT;
  2663. goto Failure;
  2664. }
  2665. //
  2666. // Validate the parameters.
  2667. //
  2668. pRegisteredPort = (CRegisteredPort*) hRegisteredPorts;
  2669. if (! pRegisteredPort->IsValidObject())
  2670. {
  2671. DPFX(DPFPREP, 0, "Invalid registered port mapping handle specified!");
  2672. hr = DPNHERR_INVALIDPARAM;
  2673. goto Failure;
  2674. }
  2675. if (dwFlags != 0)
  2676. {
  2677. DPFX(DPFPREP, 0, "Invalid flags specified!");
  2678. hr = DPNHERR_INVALIDFLAGS;
  2679. goto Failure;
  2680. }
  2681. //
  2682. // Attempt to take the lock, but be prepared for the re-entrancy error.
  2683. //
  2684. hr = this->TakeLock();
  2685. if (hr != DPNH_OK)
  2686. {
  2687. DPFX(DPFPREP, 0, "Could not lock object!");
  2688. goto Failure;
  2689. }
  2690. fHaveLock = TRUE;
  2691. //
  2692. // Make sure object is in right state.
  2693. //
  2694. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  2695. {
  2696. DPFX(DPFPREP, 0, "Object not initialized!");
  2697. hr = DPNHERR_NOTINITIALIZED;
  2698. goto Failure;
  2699. }
  2700. //
  2701. // If this isn't the last user reference on the registered port, don't
  2702. // unmap it yet.
  2703. //
  2704. lResult = pRegisteredPort->DecUserRef();
  2705. if (lResult != 0)
  2706. {
  2707. DPFX(DPFPREP, 1, "Still %i references left on registered port 0x%p, not unmapping.",
  2708. lResult, pRegisteredPort);
  2709. goto Exit;
  2710. }
  2711. //
  2712. // First, unmap from remote PAST server, if necessary.
  2713. //
  2714. if (pRegisteredPort->GetPASTBindID(TRUE) != 0)
  2715. {
  2716. DNASSERT(pRegisteredPort->GetOwningDevice() != NULL);
  2717. //
  2718. // Free the port.
  2719. //
  2720. hr = this->FreePASTPort(pRegisteredPort, TRUE);
  2721. if (hr != DPNH_OK)
  2722. {
  2723. DPFX(DPFPREP, 0, "Couldn't free port mapping with remote PAST server (0x%lx)! Ignoring.", hr);
  2724. //
  2725. // We'll treat this as non-fatal, but we have to dump the server.
  2726. //
  2727. this->ClearDevicesPASTServer(pRegisteredPort->GetOwningDevice(), TRUE);
  2728. hr = DPNH_OK;
  2729. }
  2730. }
  2731. //
  2732. // Then unmap from local PAST server, if necessary.
  2733. //
  2734. if (pRegisteredPort->GetPASTBindID(FALSE) != 0)
  2735. {
  2736. DNASSERT(pRegisteredPort->GetOwningDevice() != NULL);
  2737. //
  2738. // Free the port.
  2739. //
  2740. hr = this->FreePASTPort(pRegisteredPort, FALSE);
  2741. if (hr != DPNH_OK)
  2742. {
  2743. DPFX(DPFPREP, 0, "Couldn't free port mapping with local PAST server (0x%lx)! Ignoring.", hr);
  2744. //
  2745. // We'll treat this as non-fatal, but we have to dump the server.
  2746. //
  2747. this->ClearDevicesPASTServer(pRegisteredPort->GetOwningDevice(), FALSE);
  2748. hr = DPNH_OK;
  2749. }
  2750. }
  2751. //
  2752. // Pull the item out of the lists.
  2753. // We have the appropriate lock.
  2754. //
  2755. pRegisteredPort->m_blGlobalList.RemoveFromList();
  2756. if (pRegisteredPort->GetOwningDevice() != NULL)
  2757. {
  2758. pRegisteredPort->ClearDeviceOwner();
  2759. }
  2760. else
  2761. {
  2762. DNASSERT(pRegisteredPort->m_blDeviceList.IsListMember(&this->m_blUnownedPorts));
  2763. pRegisteredPort->m_blDeviceList.RemoveFromList();
  2764. }
  2765. pRegisteredPort->ClearPrivateAddresses();
  2766. delete pRegisteredPort;
  2767. Exit:
  2768. if (fHaveLock)
  2769. {
  2770. this->DropLock();
  2771. fHaveLock = FALSE;
  2772. }
  2773. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  2774. return hr;
  2775. Failure:
  2776. goto Exit;
  2777. } // CNATHelpPAST::DeregisterPorts
  2778. #undef DPF_MODNAME
  2779. #define DPF_MODNAME "CNATHelpPAST::QueryAddress"
  2780. //=============================================================================
  2781. // CNATHelpPAST::QueryAddress
  2782. //-----------------------------------------------------------------------------
  2783. //
  2784. // Description: Some Internet gateways do not loopback if an attempt is made
  2785. // to connect to an address behind (on the same private side of)
  2786. // the public interface. QueryAddress is used to determine a
  2787. // possible private alias for a given public address.
  2788. //
  2789. // In most cases, this function is called prior to connecting
  2790. // to a new address. pSourceAddress should contain the address of
  2791. // the socket that will perform the connect. Similar to
  2792. // RegisterPorts, the address may be INADDR_ANY, in which case the
  2793. // "best" server will be used. Since the server chosen may not be
  2794. // optimal for a particular application, it is recommended that a
  2795. // specific network interface be used instead of INADDR_ANY, when
  2796. // possible.
  2797. //
  2798. // If no mapping for that address has been made by the gateway,
  2799. // the error code DPNHERR_NOMAPPING is returned. When the
  2800. // DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED flag is used, an
  2801. // extra effort is made to determine whether the address is behind
  2802. // the same Internet gateway without being mapped on the gateway.
  2803. // If that is the case, DPNHERR_NOMAPPINGBUTPRIVATE is returned.
  2804. // DPNHERR_NOMAPPING is still returned for addresses that are
  2805. // neither mapped nor private.
  2806. //
  2807. // pQueryAddress may not be INADDR_ANY or INADDR_BROADCAST.
  2808. // The port component may be zero if and only if the
  2809. // DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED flag is used. If
  2810. // the port is zero, a specific mapping cannot be verified, and
  2811. // only the DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED aspect of
  2812. // the address is tested.
  2813. //
  2814. // The resulting address (or lack thereof) can be cached for
  2815. // quick future retrieval using the DPNHQUERYADDRESS_CACHEFOUND
  2816. // and DPNHQUERYADDRESS_CACHENOTFOUND flags. The cached mappings
  2817. // will expire in 1 minute, or whenever the server's address
  2818. // changes.
  2819. //
  2820. // If the given source address is not currently connected to an
  2821. // Internet gateway, then the error DPNHERR_SERVERNOTAVAILABLE is
  2822. // returned.
  2823. //
  2824. // If GetCaps has not been previously called with the
  2825. // DPNHGETCAPS_UPDATESERVERSTATUS flag at least once, then the
  2826. // error code DPNHERR_UPDATESERVERSTATUS is returned.
  2827. //
  2828. // Arguments:
  2829. // SOCKADDR * pSourceAddress - Address for network interface that is using
  2830. // the address in question.
  2831. // SOCKADDR * pQueryAddress - Address to look up.
  2832. // SOCKADDR * pResponseAddress - Place to store public address, if one exists.
  2833. // int iAddressesSize - Size of the SOCKADDR structure used for the
  2834. // pSourceAddress, pQueryAddress and
  2835. // pResponseAddress buffers.
  2836. // DWORD dwFlags - Flags to use when querying
  2837. // (DPNHQUERYADDRESS_xxx).
  2838. //
  2839. // Returns: HRESULT
  2840. // DPNH_OK - The address was found and its mapping was
  2841. // stored in pResponseAddress.
  2842. // DPNHERR_GENERIC - An error occurred that prevented mapping the
  2843. // requested address.
  2844. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  2845. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  2846. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  2847. // DPNHERR_INVALIDPOINTER - An invalid pointer was specified.
  2848. // DPNHERR_NOMAPPING - The server indicated that no mapping for the
  2849. // requested address was found.
  2850. // DPNHERR_NOMAPPINGBUTPRIVATE - The server indicated that no mapping was
  2851. // found, but it is a private address.
  2852. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  2853. // DPNHERR_OUTOFMEMORY - There is not enough memory to query.
  2854. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  2855. // thread.
  2856. // DPNHERR_SERVERNOTAVAILABLE - There are no servers to query.
  2857. // DPNHERR_UPDATESERVERSTATUS - GetCaps has not been called with the
  2858. // DPNHGETCAPS_UPDATESERVERSTATUS flag yet.
  2859. //=============================================================================
  2860. STDMETHODIMP CNATHelpPAST::QueryAddress(const SOCKADDR * const pSourceAddress,
  2861. const SOCKADDR * const pQueryAddress,
  2862. SOCKADDR * const pResponseAddress,
  2863. const int iAddressesSize,
  2864. const DWORD dwFlags)
  2865. {
  2866. HRESULT hr;
  2867. HRESULT temphr;
  2868. BOOL fHaveLock = FALSE;
  2869. CDevice * pDevice;
  2870. SOCKADDR_IN * psaddrinNextServerQueryAddress = NULL;
  2871. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, 0x%p, 0x%p, %i, 0x%lx)",
  2872. this, pSourceAddress, pQueryAddress, pResponseAddress, iAddressesSize,
  2873. dwFlags);
  2874. //
  2875. // Validate the object.
  2876. //
  2877. if (! this->IsValidObject())
  2878. {
  2879. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  2880. hr = DPNHERR_INVALIDOBJECT;
  2881. goto Failure;
  2882. }
  2883. //
  2884. // Validate the parameters.
  2885. //
  2886. if (pSourceAddress == NULL)
  2887. {
  2888. DPFX(DPFPREP, 0, "Invalid source address specified!");
  2889. hr = DPNHERR_INVALIDPOINTER;
  2890. goto Failure;
  2891. }
  2892. if (pQueryAddress == NULL)
  2893. {
  2894. DPFX(DPFPREP, 0, "Invalid query address specified!");
  2895. hr = DPNHERR_INVALIDPOINTER;
  2896. goto Failure;
  2897. }
  2898. if (pResponseAddress == NULL)
  2899. {
  2900. DPFX(DPFPREP, 0, "Invalid response address specified!");
  2901. hr = DPNHERR_INVALIDPOINTER;
  2902. goto Failure;
  2903. }
  2904. if (iAddressesSize < sizeof(SOCKADDR_IN))
  2905. {
  2906. DPFX(DPFPREP, 0, "The address buffers must be at least %i bytes!",
  2907. sizeof(SOCKADDR_IN));
  2908. hr = DPNHERR_INVALIDPARAM;
  2909. goto Failure;
  2910. }
  2911. if (IsBadReadPtr(pSourceAddress, sizeof(SOCKADDR_IN)))
  2912. {
  2913. DPFX(DPFPREP, 0, "Invalid source address buffer used!");
  2914. hr = DPNHERR_INVALIDPOINTER;
  2915. goto Failure;
  2916. }
  2917. if (IsBadReadPtr(pQueryAddress, sizeof(SOCKADDR_IN)))
  2918. {
  2919. DPFX(DPFPREP, 0, "Invalid query address buffer used!");
  2920. hr = DPNHERR_INVALIDPOINTER;
  2921. goto Failure;
  2922. }
  2923. if (IsBadWritePtr(pResponseAddress, sizeof(SOCKADDR_IN)))
  2924. {
  2925. DPFX(DPFPREP, 0, "Invalid response address buffer used!");
  2926. hr = DPNHERR_INVALIDPOINTER;
  2927. goto Failure;
  2928. }
  2929. if ((((SOCKADDR_IN*) pSourceAddress)->sin_family != AF_INET) ||
  2930. (((SOCKADDR_IN*) pQueryAddress)->sin_family != AF_INET))
  2931. {
  2932. DPFX(DPFPREP, 0, "Source or query address is not AF_INET, only IPv4 addresses are supported!");
  2933. hr = DPNHERR_INVALIDPARAM;
  2934. goto Failure;
  2935. }
  2936. if (((SOCKADDR_IN*) pSourceAddress)->sin_addr.S_un.S_addr == INADDR_BROADCAST)
  2937. {
  2938. DPFX(DPFPREP, 0, "Source address cannot be broadcast address!");
  2939. hr = DPNHERR_INVALIDPARAM;
  2940. goto Failure;
  2941. }
  2942. if ((((SOCKADDR_IN*) pQueryAddress)->sin_addr.S_un.S_addr == INADDR_ANY) ||
  2943. (((SOCKADDR_IN*) pQueryAddress)->sin_addr.S_un.S_addr == INADDR_BROADCAST))
  2944. {
  2945. //
  2946. // Don't use inet_ntoa because we may not be initialized yet.
  2947. //
  2948. DPFX(DPFPREP, 0, "Query address (%u.%u.%u.%u) is invalid, cannot be zero or broadcast!",
  2949. ((SOCKADDR_IN*) pQueryAddress)->sin_addr.S_un.S_un_b.s_b1,
  2950. ((SOCKADDR_IN*) pQueryAddress)->sin_addr.S_un.S_un_b.s_b2,
  2951. ((SOCKADDR_IN*) pQueryAddress)->sin_addr.S_un.S_un_b.s_b3,
  2952. ((SOCKADDR_IN*) pQueryAddress)->sin_addr.S_un.S_un_b.s_b4);
  2953. hr = DPNHERR_INVALIDPARAM;
  2954. goto Failure;
  2955. }
  2956. if (dwFlags & ~(DPNHQUERYADDRESS_TCP | DPNHQUERYADDRESS_CACHEFOUND | DPNHQUERYADDRESS_CACHENOTFOUND | DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED))
  2957. {
  2958. DPFX(DPFPREP, 0, "Invalid flags specified!");
  2959. hr = DPNHERR_INVALIDFLAGS;
  2960. goto Failure;
  2961. }
  2962. if ((((SOCKADDR_IN*) pQueryAddress)->sin_port == 0) &&
  2963. (! (dwFlags & DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED)))
  2964. {
  2965. DPFX(DPFPREP, 0, "Query address port cannot be zero unless CHECKFORPRIVATEBUTUNMAPPED is specified!");
  2966. hr = DPNHERR_INVALIDPARAM;
  2967. goto Failure;
  2968. }
  2969. //
  2970. // Attempt to take the lock, but be prepared for the re-entrancy error.
  2971. //
  2972. hr = this->TakeLock();
  2973. if (hr != DPNH_OK)
  2974. {
  2975. DPFX(DPFPREP, 0, "Could not lock object!");
  2976. goto Failure;
  2977. }
  2978. fHaveLock = TRUE;
  2979. //
  2980. // Make sure object is in right state.
  2981. //
  2982. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  2983. {
  2984. DPFX(DPFPREP, 0, "Object not initialized!");
  2985. hr = DPNHERR_NOTINITIALIZED;
  2986. goto Failure;
  2987. }
  2988. if (this->m_dwLastUpdateServerStatusTime == 0)
  2989. {
  2990. DPFX(DPFPREP, 0, "GetCaps has not been called with UPDATESERVERSTATUS flag yet!");
  2991. hr = DPNHERR_UPDATESERVERSTATUS;
  2992. goto Failure;
  2993. }
  2994. pDevice = this->FindMatchingDevice((SOCKADDR_IN*) pSourceAddress, TRUE);
  2995. if (pDevice == NULL)
  2996. {
  2997. DPFX(DPFPREP, 1, "Couldn't determine appropriate owning device for given source address, returning SERVERNOTAVAILABLE.");
  2998. hr = DPNHERR_SERVERNOTAVAILABLE;
  2999. goto Exit;
  3000. }
  3001. //
  3002. // Assume no servers are available. This will get overridden as
  3003. // appropriate.
  3004. //
  3005. hr = DPNHERR_SERVERNOTAVAILABLE;
  3006. //
  3007. // Start by querying the address passed in.
  3008. //
  3009. psaddrinNextServerQueryAddress = (SOCKADDR_IN*) pQueryAddress;
  3010. //
  3011. // If the port is zero, then we can't actually lookup a mapping. Just do
  3012. // the address locality check.
  3013. //
  3014. if (psaddrinNextServerQueryAddress->sin_port == 0)
  3015. {
  3016. //
  3017. // We should have caught this in parameter validation above, but I'm
  3018. // being paranoid.
  3019. //
  3020. DNASSERT(dwFlags & DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED);
  3021. //
  3022. // We don't cache these results, since there's no server (and thus, no
  3023. // network traffic) associated with it. No need to look anything up.
  3024. //
  3025. //
  3026. // If there aren't any servers, then no need to check.
  3027. //
  3028. if ((pDevice->GetPASTClientID(TRUE) == 0) &&
  3029. (pDevice->GetPASTClientID(FALSE) == 0))
  3030. {
  3031. DPFX(DPFPREP, 5, "No port queried and there aren't any gateways, returning SERVERNOTAVAILABLE.");
  3032. hr = DPNHERR_SERVERNOTAVAILABLE;
  3033. }
  3034. else
  3035. {
  3036. //
  3037. // There is an Internet gateway of some kind, our locality check
  3038. // would be meaningful.
  3039. //
  3040. if (this->IsAddressLocal(pDevice, psaddrinNextServerQueryAddress))
  3041. {
  3042. DPFX(DPFPREP, 5, "No port queried, but address appears to be local, returning NOMAPPINGBUTPRIVATE.");
  3043. hr = DPNHERR_NOMAPPINGBUTPRIVATE;
  3044. }
  3045. else
  3046. {
  3047. DPFX(DPFPREP, 5, "No port queried and address does not appear to be local, returning NOMAPPING.");
  3048. hr = DPNHERR_NOMAPPING;
  3049. }
  3050. }
  3051. //
  3052. // We've done all we can do.
  3053. //
  3054. goto Exit;
  3055. }
  3056. //
  3057. // First try to query the remote PAST server, if there is one.
  3058. //
  3059. if (pDevice->GetPASTClientID(TRUE) != 0)
  3060. {
  3061. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  3062. hr = this->InternalPASTQueryAddress(pDevice,
  3063. psaddrinNextServerQueryAddress,
  3064. (SOCKADDR_IN*) pResponseAddress,
  3065. dwFlags,
  3066. TRUE);
  3067. switch (hr)
  3068. {
  3069. case DPNH_OK:
  3070. {
  3071. //
  3072. // If there is a local PAST server, we want to query it for the
  3073. // public address we were just returned. This technically
  3074. // would allow us to chain more than one level of Internet
  3075. // gateways, however it really won't work. I'm just doing it
  3076. // because it doesn't hurt.
  3077. //
  3078. // Handing the same buffer to InternalPASTQueryAddress for both
  3079. // the query and response addresses is okay.
  3080. //
  3081. psaddrinNextServerQueryAddress = (SOCKADDR_IN*) pResponseAddress;
  3082. break;
  3083. }
  3084. case DPNHERR_NOMAPPING:
  3085. {
  3086. //
  3087. // There's no mapping, continue to the local PAST server query.
  3088. //
  3089. break;
  3090. }
  3091. case DPNHERR_NOMAPPINGBUTPRIVATE:
  3092. {
  3093. //
  3094. // There's no mapping although the address is private, continue
  3095. // to the local PAST server query.
  3096. //
  3097. break;
  3098. }
  3099. case DPNHERR_SERVERNOTRESPONDING:
  3100. {
  3101. //
  3102. // The server stopped responding, but treat that as non-fatal.
  3103. // It will be detected properly the next time GetCaps is
  3104. // called. We set the return code to DPNHERR_NOMAPPING in case
  3105. // there is no local PAST server to override the value.
  3106. //
  3107. DPFX(DPFPREP, 1, "Remote PAST server stopped responding while querying port mapping.");
  3108. hr = DPNHERR_NOMAPPING;
  3109. //
  3110. // Continue through to querying the local server.
  3111. //
  3112. break;
  3113. }
  3114. default:
  3115. {
  3116. DPFX(DPFPREP, 0, "Querying remote PAST server for port mapping failed!");
  3117. goto Failure;
  3118. break;
  3119. }
  3120. }
  3121. }
  3122. else
  3123. {
  3124. //
  3125. // No remote PAST server.
  3126. //
  3127. }
  3128. //
  3129. // Then try to query the local PAST server, if there is one.
  3130. //
  3131. if (pDevice->GetPASTClientID(FALSE) != 0)
  3132. {
  3133. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  3134. temphr = this->InternalPASTQueryAddress(pDevice,
  3135. psaddrinNextServerQueryAddress,
  3136. (SOCKADDR_IN*) pResponseAddress,
  3137. dwFlags,
  3138. FALSE);
  3139. switch (temphr)
  3140. {
  3141. case DPNH_OK:
  3142. {
  3143. //
  3144. // Success!
  3145. //
  3146. hr = DPNH_OK;
  3147. break;
  3148. }
  3149. case DPNHERR_NOMAPPING:
  3150. {
  3151. //
  3152. // There's no mapping. Overwrite the return value if we didn't
  3153. // have a remote PAST server to query.
  3154. //
  3155. if (hr == DPNHERR_SERVERNOTAVAILABLE)
  3156. {
  3157. hr = DPNHERR_NOMAPPING;
  3158. }
  3159. break;
  3160. }
  3161. case DPNHERR_NOMAPPINGBUTPRIVATE:
  3162. {
  3163. //
  3164. // There's no mapping although the address is private.
  3165. // Overwrite the return value if we didn't have a remote PAST
  3166. // server to query.
  3167. //
  3168. if (hr == DPNHERR_SERVERNOTAVAILABLE)
  3169. {
  3170. hr = DPNHERR_NOMAPPINGBUTPRIVATE;
  3171. }
  3172. break;
  3173. }
  3174. case DPNHERR_SERVERNOTRESPONDING:
  3175. {
  3176. //
  3177. // The server stopped responding, but treat that as non-fatal.
  3178. // It will be detected properly the next time GetCaps is
  3179. // called.
  3180. //
  3181. DPFX(DPFPREP, 1, "Local PAST server stopped responding while querying port mapping.");
  3182. //
  3183. // Overwrite the return value if we didn't have a remote PAST
  3184. // server to query.
  3185. //
  3186. if (hr == DPNHERR_SERVERNOTAVAILABLE)
  3187. {
  3188. hr = DPNHERR_NOMAPPING;
  3189. }
  3190. break;
  3191. }
  3192. default:
  3193. {
  3194. DPFX(DPFPREP, 0, "Querying local PAST server for port mapping failed!");
  3195. goto Failure;
  3196. break;
  3197. }
  3198. }
  3199. }
  3200. else
  3201. {
  3202. //
  3203. // No local PAST server.
  3204. //
  3205. }
  3206. //
  3207. // If we got here with hr still set to SERVERNOTAVAILABLE, that means
  3208. // there weren't any servers. The error code is appropriate, leave it
  3209. // alone.
  3210. //
  3211. #ifdef DBG
  3212. if (hr == DPNHERR_SERVERNOTAVAILABLE)
  3213. {
  3214. DPFX(DPFPREP, 1, "No Internet gateways, unable to query port mapping.");
  3215. }
  3216. #endif // DBG
  3217. Exit:
  3218. if (fHaveLock)
  3219. {
  3220. this->DropLock();
  3221. fHaveLock = FALSE;
  3222. }
  3223. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  3224. return hr;
  3225. Failure:
  3226. goto Exit;
  3227. } // CNATHelpPAST::QueryAddress
  3228. #undef DPF_MODNAME
  3229. #define DPF_MODNAME "CNATHelpPAST::SetAlertEvent"
  3230. //=============================================================================
  3231. // CNATHelpPAST::SetAlertEvent
  3232. //-----------------------------------------------------------------------------
  3233. //
  3234. // Description: This function allows the user to specify an event that will
  3235. // be set when some maintenance needs to be performed. The user
  3236. // should call GetCaps using the DPNHGETCAPS_UPDATESERVERSTATUS
  3237. // flag when the event is signalled.
  3238. //
  3239. // This function is not available on Windows 95 without WinSock
  3240. // 2, may only be called once, and cannot be used after
  3241. // SetAlertIOCompletionPort is called.
  3242. //
  3243. // Note that the event is used in addition to the regular
  3244. // polling of GetCaps, it simply allows the polling to be less
  3245. // frequent.
  3246. //
  3247. // Arguments:
  3248. // HANDLE hEvent - Handle to event to signal when GetCaps is to be called.
  3249. // DWORD dwFlags - Unused, must be zero.
  3250. //
  3251. // Returns: HRESULT
  3252. // DPNH_OK - The event was successfully registered.
  3253. // DPNHERR_GENERIC - An error occurred that prevented registering the
  3254. // event.
  3255. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  3256. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  3257. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  3258. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  3259. // DPNHERR_OUTOFMEMORY - There is not enough memory.
  3260. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  3261. // thread.
  3262. //=============================================================================
  3263. STDMETHODIMP CNATHelpPAST::SetAlertEvent(const HANDLE hEvent,
  3264. const DWORD dwFlags)
  3265. {
  3266. HRESULT hr;
  3267. BOOL fHaveLock = FALSE;
  3268. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, 0x%lx)", this, hEvent, dwFlags);
  3269. //
  3270. // Validate the object.
  3271. //
  3272. if (! this->IsValidObject())
  3273. {
  3274. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  3275. hr = DPNHERR_INVALIDOBJECT;
  3276. goto Failure;
  3277. }
  3278. //
  3279. // Validate the parameters.
  3280. //
  3281. if (hEvent == NULL)
  3282. {
  3283. DPFX(DPFPREP, 0, "Invalid event handle specified!");
  3284. hr = DPNHERR_INVALIDPARAM;
  3285. goto Failure;
  3286. }
  3287. if (dwFlags != 0)
  3288. {
  3289. DPFX(DPFPREP, 0, "Invalid flags specified!");
  3290. hr = DPNHERR_INVALIDFLAGS;
  3291. goto Failure;
  3292. }
  3293. //
  3294. // Attempt to take the lock, but be prepared for the re-entrancy error.
  3295. //
  3296. hr = this->TakeLock();
  3297. if (hr != DPNH_OK)
  3298. {
  3299. DPFX(DPFPREP, 0, "Could not lock object!");
  3300. goto Failure;
  3301. }
  3302. fHaveLock = TRUE;
  3303. //
  3304. // Make sure object is in right state.
  3305. //
  3306. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED))
  3307. {
  3308. DPFX(DPFPREP, 0, "Object not initialized!");
  3309. hr = DPNHERR_NOTINITIALIZED;
  3310. goto Failure;
  3311. }
  3312. if (this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1)
  3313. {
  3314. DPFX(DPFPREP, 0, "Cannot use alert mechanism on WinSock 1!");
  3315. hr = DPNHERR_GENERIC;
  3316. goto Failure;
  3317. }
  3318. if ((this->m_hAlertEvent != NULL) || (this->m_hAlertIOCompletionPort != NULL))
  3319. {
  3320. DPFX(DPFPREP, 0, "An alert event or I/O completion port has already been set!");
  3321. hr = DPNHERR_GENERIC;
  3322. goto Failure;
  3323. }
  3324. //
  3325. // Now save the event handle.
  3326. //
  3327. if (! DuplicateHandle(GetCurrentProcess(),
  3328. hEvent,
  3329. GetCurrentProcess(),
  3330. &this->m_hAlertEvent,
  3331. 0,
  3332. FALSE,
  3333. DUPLICATE_SAME_ACCESS))
  3334. {
  3335. #ifdef DBG
  3336. DWORD dwError;
  3337. dwError = GetLastError();
  3338. DPFX(DPFPREP, 0, "Couldn't duplicate event (error = %u)!", dwError);
  3339. #endif // DBG
  3340. DNASSERT(this->m_hAlertEvent == NULL);
  3341. hr = DPNHERR_INVALIDPARAM;
  3342. goto Failure;
  3343. }
  3344. //
  3345. // Create overlapped structure. Don't allocate it through DNMalloc,
  3346. // because we may have to leak it on purpose. We don't want those memory
  3347. // allocation asserts firing in that case.
  3348. //
  3349. this->m_polAddressListChange = (WSAOVERLAPPED*) HeapAlloc(GetProcessHeap(),
  3350. HEAP_ZERO_MEMORY,
  3351. sizeof(WSAOVERLAPPED));
  3352. if (this->m_polAddressListChange == NULL)
  3353. {
  3354. //
  3355. // Close the alert handle we set.
  3356. //
  3357. CloseHandle(this->m_hAlertEvent);
  3358. this->m_hAlertEvent = NULL;
  3359. hr = DPNHERR_OUTOFMEMORY;
  3360. goto Failure;
  3361. }
  3362. //
  3363. // Save the event in the address list change overlapped structure.
  3364. //
  3365. this->m_polAddressListChange->hEvent = this->m_hAlertEvent;
  3366. //
  3367. // Start getting notified of local address changes.
  3368. //
  3369. hr = this->RequestLocalAddressListChangeNotification();
  3370. if (hr != DPNH_OK)
  3371. {
  3372. DPFX(DPFPREP, 0, "Couldn't request local address list change notification!");
  3373. //
  3374. // Free the memory we allocated.
  3375. //
  3376. HeapFree(GetProcessHeap(), 0, this->m_polAddressListChange);
  3377. this->m_polAddressListChange = NULL;
  3378. //
  3379. // Close the alert handle we set.
  3380. //
  3381. CloseHandle(this->m_hAlertEvent);
  3382. this->m_hAlertEvent = NULL;
  3383. goto Failure;
  3384. }
  3385. Exit:
  3386. if (fHaveLock)
  3387. {
  3388. this->DropLock();
  3389. fHaveLock = FALSE;
  3390. }
  3391. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  3392. return hr;
  3393. Failure:
  3394. goto Exit;
  3395. } // CNATHelpPAST::SetAlertEvent
  3396. #undef DPF_MODNAME
  3397. #define DPF_MODNAME "CNATHelpPAST::SetAlertIOCompletionPort"
  3398. //=============================================================================
  3399. // CNATHelpPAST::SetAlertIOCompletionPort
  3400. //-----------------------------------------------------------------------------
  3401. //
  3402. // Description: This function allows the user to specify an I/O completion
  3403. // port that will receive notification when some maintenance needs
  3404. // to be performed. The user should call GetCaps using the
  3405. // DPNHGETCAPS_UPDATESERVERSTATUS flag when the packet with the
  3406. // given completion key is dequeued.
  3407. //
  3408. // This function is only available on Windows NT, may only be
  3409. // called once, and cannot be used after SetAlertEvent is called.
  3410. //
  3411. // Note that the completion port is used in addition to the
  3412. // regular polling of GetCaps, it simply allows the polling to be
  3413. // less frequent.
  3414. //
  3415. // Arguments:
  3416. // HANDLE hIOCompletionPort - Handle to I/O completion port which will
  3417. // be used to signal when GetCaps is to be
  3418. // called.
  3419. // DWORD dwCompletionKey - Key to use when indicating I/O
  3420. // completion.
  3421. // DWORD dwNumConcurrentThreads - Number of concurrent threads allowed to
  3422. // process, or zero for default.
  3423. // DWORD dwFlags - Unused, must be zero.
  3424. //
  3425. // Returns: HRESULT
  3426. // DPNH_OK - The I/O completion port was successfully
  3427. // registered.
  3428. // DPNHERR_GENERIC - An error occurred that prevented registering the
  3429. // I/O completion port.
  3430. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  3431. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  3432. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  3433. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  3434. // DPNHERR_OUTOFMEMORY - There is not enough memory.
  3435. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  3436. // thread.
  3437. //=============================================================================
  3438. STDMETHODIMP CNATHelpPAST::SetAlertIOCompletionPort(const HANDLE hIOCompletionPort,
  3439. const DWORD dwCompletionKey,
  3440. const DWORD dwNumConcurrentThreads,
  3441. const DWORD dwFlags)
  3442. {
  3443. HRESULT hr;
  3444. BOOL fHaveLock = FALSE;
  3445. HANDLE hIOCompletionPortResult;
  3446. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, 0x%lx, %u, 0x%lx)",
  3447. this, hIOCompletionPort, dwCompletionKey, dwNumConcurrentThreads, dwFlags);
  3448. //
  3449. // Validate the object.
  3450. //
  3451. if (! this->IsValidObject())
  3452. {
  3453. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  3454. hr = DPNHERR_INVALIDOBJECT;
  3455. goto Failure;
  3456. }
  3457. //
  3458. // Validate the parameters.
  3459. //
  3460. if (hIOCompletionPort == NULL)
  3461. {
  3462. DPFX(DPFPREP, 0, "Invalid I/O completion port handle specified!");
  3463. hr = DPNHERR_INVALIDPARAM;
  3464. goto Failure;
  3465. }
  3466. if (dwFlags != 0)
  3467. {
  3468. DPFX(DPFPREP, 0, "Invalid flags specified!");
  3469. hr = DPNHERR_INVALIDFLAGS;
  3470. goto Failure;
  3471. }
  3472. //
  3473. // Attempt to take the lock, but be prepared for the re-entrancy error.
  3474. //
  3475. hr = this->TakeLock();
  3476. if (hr != DPNH_OK)
  3477. {
  3478. DPFX(DPFPREP, 0, "Could not lock object!");
  3479. goto Failure;
  3480. }
  3481. fHaveLock = TRUE;
  3482. //
  3483. // Make sure object is in right state.
  3484. //
  3485. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED))
  3486. {
  3487. DPFX(DPFPREP, 0, "Object not initialized!");
  3488. hr = DPNHERR_NOTINITIALIZED;
  3489. goto Failure;
  3490. }
  3491. if (this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1)
  3492. {
  3493. DPFX(DPFPREP, 0, "Cannot use alert mechanism on WinSock 1!");
  3494. hr = DPNHERR_GENERIC;
  3495. goto Failure;
  3496. }
  3497. if ((this->m_hAlertEvent != NULL) || (this->m_hAlertIOCompletionPort != NULL))
  3498. {
  3499. DPFX(DPFPREP, 0, "An alert event or I/O completion port has already been set!");
  3500. hr = DPNHERR_GENERIC;
  3501. goto Failure;
  3502. }
  3503. //
  3504. // Now save the I/O completion port handle.
  3505. //
  3506. if (! DuplicateHandle(GetCurrentProcess(),
  3507. hIOCompletionPort,
  3508. GetCurrentProcess(),
  3509. &this->m_hAlertIOCompletionPort,
  3510. 0,
  3511. FALSE,
  3512. DUPLICATE_SAME_ACCESS))
  3513. {
  3514. #ifdef DBG
  3515. DWORD dwError;
  3516. dwError = GetLastError();
  3517. DPFX(DPFPREP, 0, "Couldn't duplicate I/O completion port (error = %u)!", dwError);
  3518. #endif // DBG
  3519. DNASSERT(this->m_hAlertIOCompletionPort == NULL);
  3520. hr = DPNHERR_INVALIDPARAM;
  3521. goto Failure;
  3522. }
  3523. this->m_dwAlertCompletionKey = dwCompletionKey;
  3524. //
  3525. // Associate our Ioctl socket with this IO completion port.
  3526. //
  3527. DNASSERT(this->m_sIoctls != INVALID_SOCKET);
  3528. hIOCompletionPortResult = CreateIoCompletionPort((HANDLE) this->m_sIoctls,
  3529. this->m_hAlertIOCompletionPort,
  3530. dwCompletionKey,
  3531. dwNumConcurrentThreads);
  3532. if (hIOCompletionPortResult == NULL)
  3533. {
  3534. #ifdef DBG
  3535. DWORD dwError;
  3536. dwError = GetLastError();
  3537. DPFX(DPFPREP, 0, "Couldn't associate I/O completion port with Ioctl socket (error = %u)!", dwError);
  3538. #endif // DBG
  3539. hr = DPNHERR_GENERIC;
  3540. goto Failure;
  3541. }
  3542. //
  3543. // We should have just gotten the same I/O completion port back.
  3544. //
  3545. DNASSERT(hIOCompletionPortResult == this->m_hAlertIOCompletionPort);
  3546. //
  3547. // Create overlapped structure. Don't allocate it through DNMalloc,
  3548. // because we may have to leak it on purpose. We don't want those memory
  3549. // allocation asserts firing in that case.
  3550. //
  3551. this->m_polAddressListChange = (WSAOVERLAPPED*) HeapAlloc(GetProcessHeap(),
  3552. HEAP_ZERO_MEMORY,
  3553. sizeof(WSAOVERLAPPED));
  3554. if (this->m_polAddressListChange == NULL)
  3555. {
  3556. //
  3557. // Close the alert IOCP we set.
  3558. //
  3559. CloseHandle(this->m_hAlertIOCompletionPort);
  3560. this->m_hAlertIOCompletionPort = NULL;
  3561. hr = DPNHERR_OUTOFMEMORY;
  3562. goto Failure;
  3563. }
  3564. //
  3565. // Start getting notified of local address changes.
  3566. //
  3567. hr = this->RequestLocalAddressListChangeNotification();
  3568. if (hr != DPNH_OK)
  3569. {
  3570. DPFX(DPFPREP, 0, "Couldn't request local address list change notification!");
  3571. //
  3572. // Free the memory we allocated.
  3573. //
  3574. HeapFree(GetProcessHeap(), 0, this->m_polAddressListChange);
  3575. this->m_polAddressListChange = NULL;
  3576. //
  3577. // Close the alert IOCP we set.
  3578. //
  3579. CloseHandle(this->m_hAlertIOCompletionPort);
  3580. this->m_hAlertIOCompletionPort = NULL;
  3581. goto Failure;
  3582. }
  3583. Exit:
  3584. if (fHaveLock)
  3585. {
  3586. this->DropLock();
  3587. fHaveLock = FALSE;
  3588. }
  3589. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  3590. return hr;
  3591. Failure:
  3592. goto Exit;
  3593. } // CNATHelpPAST::SetAlertIOCompletionPort
  3594. #undef DPF_MODNAME
  3595. #define DPF_MODNAME "CNATHelpPAST::ExtendRegisteredPortsLease"
  3596. //=============================================================================
  3597. // CNATHelpPAST::ExtendRegisteredPortsLease
  3598. //-----------------------------------------------------------------------------
  3599. //
  3600. // Description: Manually extends the lease of the given registered port
  3601. // mapping by the requested time. The periodic calling of GetCaps
  3602. // can take care of this for the user, this function is only
  3603. // necessary to change the lease extension time or for finer
  3604. // control of individual mappings.
  3605. //
  3606. // The user should specify a requested lease extension time
  3607. // that the server will attempt to honor. It will be added to any
  3608. // time remaining in the existing lease, and the new total can be
  3609. // retrieved by calling GetRegisteredAddresses.
  3610. //
  3611. // Arguments:
  3612. // DPNHHANDLE hRegisteredPorts - Handle for a specific binding returned by
  3613. // RegisterPorts.
  3614. // DWORD dwLeaseTime - Requested time, in milliseconds, to
  3615. // extend the lease. If 0, the previous
  3616. // requested lease time is used.
  3617. // DWORD dwFlags - Unused, must be zero.
  3618. //
  3619. // Returns: HRESULT
  3620. // DPNH_OK - The lease was successfully extended.
  3621. // DPNHERR_GENERIC - An error occurred that prevented the extending
  3622. // the lease.
  3623. // DPNHERR_INVALIDFLAGS - Invalid flags were specified.
  3624. // DPNHERR_INVALIDOBJECT - The interface object is invalid.
  3625. // DPNHERR_INVALIDPARAM - An invalid parameter was specified.
  3626. // DPNHERR_NOTINITIALIZED - Initialize has not been called.
  3627. // DPNHERR_OUTOFMEMORY - There is not enough memory to extend the lease.
  3628. // DPNHERR_REENTRANT - The interface has been re-entered on the same
  3629. // thread.
  3630. //=============================================================================
  3631. STDMETHODIMP CNATHelpPAST::ExtendRegisteredPortsLease(const DPNHHANDLE hRegisteredPorts,
  3632. const DWORD dwLeaseTime,
  3633. const DWORD dwFlags)
  3634. {
  3635. HRESULT hr;
  3636. CRegisteredPort * pRegisteredPort;
  3637. CDevice * pDevice;
  3638. BOOL fHaveLock = FALSE;
  3639. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, %u, 0x%lx)",
  3640. this, hRegisteredPorts, dwLeaseTime, dwFlags);
  3641. //
  3642. // Validate the object.
  3643. //
  3644. if (! this->IsValidObject())
  3645. {
  3646. DPFX(DPFPREP, 0, "Invalid DirectPlay NAT Help object!");
  3647. hr = DPNHERR_INVALIDOBJECT;
  3648. goto Failure;
  3649. }
  3650. //
  3651. // Validate the parameters.
  3652. //
  3653. pRegisteredPort = (CRegisteredPort*) hRegisteredPorts;
  3654. if (! pRegisteredPort->IsValidObject())
  3655. {
  3656. DPFX(DPFPREP, 0, "Invalid registered port mapping handle specified!");
  3657. hr = DPNHERR_INVALIDPARAM;
  3658. goto Failure;
  3659. }
  3660. if (dwFlags != 0)
  3661. {
  3662. DPFX(DPFPREP, 0, "Invalid flags specified!");
  3663. hr = DPNHERR_INVALIDFLAGS;
  3664. goto Failure;
  3665. }
  3666. //
  3667. // Attempt to take the lock, but be prepared for the re-entrancy error.
  3668. //
  3669. hr = this->TakeLock();
  3670. if (hr != DPNH_OK)
  3671. {
  3672. DPFX(DPFPREP, 0, "Could not lock object!");
  3673. goto Failure;
  3674. }
  3675. fHaveLock = TRUE;
  3676. //
  3677. // Make sure object is in right state.
  3678. //
  3679. if (! (this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED) )
  3680. {
  3681. DPFX(DPFPREP, 0, "Object not initialized!");
  3682. hr = DPNHERR_NOTINITIALIZED;
  3683. goto Failure;
  3684. }
  3685. //
  3686. // If they wanted to change the lease time, update it.
  3687. //
  3688. if (dwLeaseTime != 0)
  3689. {
  3690. pRegisteredPort->UpdateRequestedLeaseTime(dwLeaseTime);
  3691. }
  3692. pDevice = pRegisteredPort->GetOwningDevice();
  3693. //
  3694. // If the ports are mapped on a remote PAST servers, extend that lease.
  3695. //
  3696. if (pRegisteredPort->GetPASTBindID(TRUE) != 0)
  3697. {
  3698. DNASSERT(pDevice != NULL);
  3699. hr = this->ExtendPASTLease(pRegisteredPort, TRUE);
  3700. if (hr != DPNH_OK)
  3701. {
  3702. DPFX(DPFPREP, 0, "Couldn't extend port mapping lease on remote PAST server (0x%lx)! Ignoring.", hr);
  3703. //
  3704. // We'll treat this as non-fatal, but we have to dump the server.
  3705. //
  3706. this->ClearDevicesPASTServer(pDevice, TRUE);
  3707. hr = DPNH_OK;
  3708. }
  3709. }
  3710. else
  3711. {
  3712. DPFX(DPFPREP, 2, "Port mapping not registered with remote PAST server.");
  3713. }
  3714. //
  3715. // Next extend the mappings on the local PAST server, if possible.
  3716. //
  3717. if (pRegisteredPort->GetPASTBindID(FALSE) != 0)
  3718. {
  3719. DNASSERT(pDevice != NULL);
  3720. hr = this->ExtendPASTLease(pRegisteredPort, FALSE);
  3721. if (hr != DPNH_OK)
  3722. {
  3723. DPFX(DPFPREP, 0, "Couldn't extend port mapping lease on local PAST server (0x%lx)! Ignoring.", hr);
  3724. //
  3725. // We'll treat this as non-fatal, but we have to dump the server.
  3726. //
  3727. this->ClearDevicesPASTServer(pDevice, FALSE);
  3728. hr = DPNH_OK;
  3729. }
  3730. }
  3731. else
  3732. {
  3733. DPFX(DPFPREP, 2, "Port mapping not registered with local PAST server.");
  3734. }
  3735. this->DropLock();
  3736. fHaveLock = FALSE;
  3737. Exit:
  3738. DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
  3739. return hr;
  3740. Failure:
  3741. if (fHaveLock)
  3742. {
  3743. this->DropLock();
  3744. fHaveLock = FALSE;
  3745. }
  3746. goto Exit;
  3747. } // CNATHelpPAST::ExtendRegisteredPortsLease
  3748. #undef DPF_MODNAME
  3749. #define DPF_MODNAME "CNATHelpPAST::InitializeObject"
  3750. //=============================================================================
  3751. // CNATHelpPAST::InitializeObject
  3752. //-----------------------------------------------------------------------------
  3753. //
  3754. // Description: Sets up the object for use like the constructor, but may
  3755. // fail with OUTOFMEMORY. Should only be called by class factory
  3756. // creation routine.
  3757. //
  3758. // Arguments: None.
  3759. //
  3760. // Returns: HRESULT
  3761. // S_OK - Initialization was successful.
  3762. // E_OUTOFMEMORY - There is not enough memory to initialize.
  3763. //=============================================================================
  3764. HRESULT CNATHelpPAST::InitializeObject(void)
  3765. {
  3766. HRESULT hr;
  3767. DPFX(DPFPREP, 5, "(0x%p) Enter", this);
  3768. DNASSERT(this->IsValidObject());
  3769. //
  3770. // Create the lock.
  3771. //
  3772. if (! DNInitializeCriticalSection(&this->m_csLock))
  3773. {
  3774. hr = E_OUTOFMEMORY;
  3775. goto Failure;
  3776. }
  3777. //
  3778. // Don't allow critical section reentry.
  3779. //
  3780. DebugSetCriticalSectionRecursionCount(&this->m_csLock, 0);
  3781. hr = S_OK;
  3782. Exit:
  3783. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  3784. return hr;
  3785. Failure:
  3786. goto Exit;
  3787. } // CNATHelpPAST::InitializeObject
  3788. #undef DPF_MODNAME
  3789. #define DPF_MODNAME "CNATHelpPAST::UninitializeObject"
  3790. //=============================================================================
  3791. // CNATHelpPAST::UninitializeObject
  3792. //-----------------------------------------------------------------------------
  3793. //
  3794. // Description: Cleans up the object like the destructor, mostly to balance
  3795. // InitializeObject.
  3796. //
  3797. // Arguments: None.
  3798. //
  3799. // Returns: None.
  3800. //=============================================================================
  3801. void CNATHelpPAST::UninitializeObject(void)
  3802. {
  3803. DPFX(DPFPREP, 5, "(0x%p) Enter", this);
  3804. DNASSERT(this->IsValidObject());
  3805. DNDeleteCriticalSection(&this->m_csLock);
  3806. DPFX(DPFPREP, 5, "(0x%p) Leave", this);
  3807. } // CNATHelpPAST::UninitializeObject
  3808. #undef DPF_MODNAME
  3809. #define DPF_MODNAME "CNATHelpPAST::TakeLock"
  3810. //=============================================================================
  3811. // CNATHelpPAST::TakeLock
  3812. //-----------------------------------------------------------------------------
  3813. //
  3814. // Description: Takes the main object lock.
  3815. //
  3816. // Arguments: None.
  3817. //
  3818. // Returns: DPNH_OK if lock was taken successfully, DPNHERR_REENTRANT if lock
  3819. // was re-entered.
  3820. //=============================================================================
  3821. HRESULT CNATHelpPAST::TakeLock(void)
  3822. {
  3823. HRESULT hr = DPNH_OK;
  3824. #ifdef DBG
  3825. DWORD dwStartTime;
  3826. dwStartTime = timeGetTime();
  3827. #endif // DBG
  3828. DNEnterCriticalSection(&this->m_csLock);
  3829. //
  3830. // If this same thread is already holding the lock, then bail.
  3831. //
  3832. if (this->m_dwLockThreadID == GetCurrentThreadId())
  3833. {
  3834. DPFX(DPFPREP, 0, "Thread re-entering!");
  3835. goto Failure;
  3836. }
  3837. #ifdef DBG
  3838. DPFX(DPFPREP, 8, "Took main object lock, elapsed time = %u ms.",
  3839. (timeGetTime() - dwStartTime));
  3840. #endif // DBG
  3841. //
  3842. // Save this thread's ID so we know who's holding the lock.
  3843. //
  3844. this->m_dwLockThreadID = GetCurrentThreadId();
  3845. Exit:
  3846. return hr;
  3847. Failure:
  3848. //
  3849. // We're reentering. Drop the lock and return the failure.
  3850. //
  3851. DNLeaveCriticalSection(&this->m_csLock);
  3852. hr = DPNHERR_REENTRANT;
  3853. goto Exit;
  3854. } // CNATHelpPAST::TakeLock
  3855. #undef DPF_MODNAME
  3856. #define DPF_MODNAME "CNATHelpPAST::DropLock"
  3857. //=============================================================================
  3858. // CNATHelpPAST::DropLock
  3859. //-----------------------------------------------------------------------------
  3860. //
  3861. // Description: Drops the main object lock.
  3862. //
  3863. // Arguments: None.
  3864. //
  3865. // Returns: None.
  3866. //=============================================================================
  3867. void CNATHelpPAST::DropLock(void)
  3868. {
  3869. DNASSERT(this->m_dwLockThreadID == GetCurrentThreadId());
  3870. this->m_dwLockThreadID = 0;
  3871. DNLeaveCriticalSection(&this->m_csLock);
  3872. DPFX(DPFPREP, 8, "Dropped main object lock.");
  3873. } // CNATHelpPAST::DropLock
  3874. #undef DPF_MODNAME
  3875. #define DPF_MODNAME "CNATHelpPAST::LoadWinSockFunctionPointers"
  3876. //=============================================================================
  3877. // CNATHelpPAST::LoadWinSockFunctionPointers
  3878. //-----------------------------------------------------------------------------
  3879. //
  3880. // Description: Loads pointers to all the functions that we use in WinSock.
  3881. //
  3882. // The object lock is assumed to be held.
  3883. //
  3884. // Arguments: None.
  3885. //
  3886. // Returns: HRESULT
  3887. // DPNH_OK - Loading was successful.
  3888. // DPNHERR_GENERIC - An error occurred.
  3889. //=============================================================================
  3890. HRESULT CNATHelpPAST::LoadWinSockFunctionPointers(void)
  3891. {
  3892. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3893. #ifdef DBG
  3894. #define PRINTERRORIFDEBUG(name) \
  3895. {\
  3896. dwError = GetLastError();\
  3897. DPFX(DPFPREP, 0, "Couldn't get \"%hs\" function! 0x%lx", name, dwError);\
  3898. }
  3899. #else
  3900. #define PRINTERRORIFDEBUG(name)
  3901. #endif // DBG
  3902. #define LOADWINSOCKFUNCTION(var, proctype, name) \
  3903. {\
  3904. var = (##proctype) GetProcAddress(this->m_hWinSockDLL, name);\
  3905. if (var == NULL)\
  3906. {\
  3907. PRINTERRORIFDEBUG(name);\
  3908. hr = DPNHERR_GENERIC;\
  3909. goto Failure;\
  3910. }\
  3911. }
  3912. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3913. HRESULT hr = DPNH_OK;
  3914. #ifdef DBG
  3915. DWORD dwError;
  3916. #endif // DBG
  3917. LOADWINSOCKFUNCTION(this->m_pfnWSAStartup, LPFN_WSASTARTUP, "WSAStartup");
  3918. LOADWINSOCKFUNCTION(this->m_pfnWSACleanup, LPFN_WSACLEANUP, "WSACleanup");
  3919. LOADWINSOCKFUNCTION(this->m_pfnWSAGetLastError, LPFN_WSAGETLASTERROR, "WSAGetLastError");
  3920. LOADWINSOCKFUNCTION(this->m_pfnsocket, LPFN_SOCKET, "socket");
  3921. LOADWINSOCKFUNCTION(this->m_pfnclosesocket, LPFN_CLOSESOCKET, "closesocket");
  3922. LOADWINSOCKFUNCTION(this->m_pfnbind, LPFN_BIND, "bind");
  3923. LOADWINSOCKFUNCTION(this->m_pfnsetsockopt, LPFN_SETSOCKOPT, "setsockopt");
  3924. LOADWINSOCKFUNCTION(this->m_pfngetsockname, LPFN_GETSOCKNAME, "getsockname");
  3925. LOADWINSOCKFUNCTION(this->m_pfnselect, LPFN_SELECT, "select");
  3926. LOADWINSOCKFUNCTION(this->m_pfn__WSAFDIsSet, LPFN___WSAFDISSET, "__WSAFDIsSet");
  3927. LOADWINSOCKFUNCTION(this->m_pfnrecvfrom, LPFN_RECVFROM, "recvfrom");
  3928. LOADWINSOCKFUNCTION(this->m_pfnsendto, LPFN_SENDTO, "sendto");
  3929. LOADWINSOCKFUNCTION(this->m_pfngethostname, LPFN_GETHOSTNAME, "gethostname");
  3930. LOADWINSOCKFUNCTION(this->m_pfngethostbyname, LPFN_GETHOSTBYNAME, "gethostbyname");
  3931. LOADWINSOCKFUNCTION(this->m_pfninet_addr, LPFN_INET_ADDR, "inet_addr");
  3932. if (! (this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1))
  3933. {
  3934. LOADWINSOCKFUNCTION(this->m_pfnWSASocketA, LPFN_WSASOCKETA, "WSASocketA");
  3935. LOADWINSOCKFUNCTION(this->m_pfnWSAIoctl, LPFN_WSAIOCTL, "WSAIoctl");
  3936. LOADWINSOCKFUNCTION(this->m_pfnWSAGetOverlappedResult, LPFN_WSAGETOVERLAPPEDRESULT, "WSAGetOverlappedResult");
  3937. }
  3938. Exit:
  3939. return hr;
  3940. Failure:
  3941. hr = DPNHERR_GENERIC;
  3942. goto Exit;
  3943. } // CNATHelpPAST::LoadWinSockFunctionPointers
  3944. #undef DPF_MODNAME
  3945. #define DPF_MODNAME "CNATHelpPAST::CheckForNewDevices"
  3946. //=============================================================================
  3947. // CNATHelpPAST::CheckForNewDevices
  3948. //-----------------------------------------------------------------------------
  3949. //
  3950. // Description: Detects new IP capable devices that have been added and
  3951. // removes old ones no longer available.
  3952. //
  3953. // The object lock is assumed to be held.
  3954. //
  3955. // Arguments:
  3956. // BOOL * pfFoundNewDevices Pointer to boolean to set to TRUE if new
  3957. // devices were added, or NULL if don't care.
  3958. //
  3959. // Returns: HRESULT
  3960. // DPNH_OK - The check was successful.
  3961. // DPNHERR_GENERIC - An error occurred.
  3962. //=============================================================================
  3963. HRESULT CNATHelpPAST::CheckForNewDevices(BOOL * const pfFoundNewDevices)
  3964. {
  3965. HRESULT hr = DPNH_OK;
  3966. DWORD dwError;
  3967. int iReturn;
  3968. char szName[1000];
  3969. PHOSTENT phostent;
  3970. IN_ADDR ** ppinaddr;
  3971. DWORD dwAddressesSize = 0;
  3972. DWORD dwNumAddresses = 0;
  3973. IN_ADDR * painaddrAddresses = NULL;
  3974. CBilink * pBilinkDevice;
  3975. CDevice * pDevice = NULL; // NULL it for PREfix, even though fDeviceCreated guards it
  3976. BOOL fDeviceCreated = FALSE;
  3977. BOOL fFound;
  3978. CBilink * pBilinkRegPort;
  3979. CRegisteredPort * pRegisteredPort;
  3980. SOCKET sTemp = INVALID_SOCKET;
  3981. SOCKADDR_IN saddrinTemp;
  3982. //int iAddressSize;
  3983. BOOL fTemp;
  3984. DWORD dwTemp;
  3985. SOCKET_ADDRESS * paSocketAddresses;
  3986. DPFX(DPFPREP, 5, "(0x%p) Enter", this);
  3987. //
  3988. // Handle any address list change Ioctl completions that may have gotten us
  3989. // here.
  3990. //
  3991. if ((this->m_hAlertEvent != NULL) ||
  3992. (this->m_hAlertIOCompletionPort != NULL))
  3993. {
  3994. DNASSERT(this->m_sIoctls != INVALID_SOCKET);
  3995. DNASSERT(this->m_polAddressListChange != NULL);
  3996. if (this->m_pfnWSAGetOverlappedResult(this->m_sIoctls, //
  3997. this->m_polAddressListChange, //
  3998. &dwTemp, // ignore bytes transferred
  3999. FALSE, // don't wait
  4000. &dwTemp)) // ignore flags
  4001. {
  4002. DPFX(DPFPREP, 1, "Received address list change notification.");
  4003. //
  4004. // Overlapped result completed. Reissue it.
  4005. //
  4006. hr = this->RequestLocalAddressListChangeNotification();
  4007. if (hr != DPNH_OK)
  4008. {
  4009. DPFX(DPFPREP, 0, "Couldn't request local address list change notification!");
  4010. goto Failure;
  4011. }
  4012. }
  4013. else
  4014. {
  4015. //
  4016. // Figure out what error it was.
  4017. //
  4018. dwError = this->m_pfnWSAGetLastError();
  4019. switch (dwError)
  4020. {
  4021. case WSA_IO_INCOMPLETE:
  4022. {
  4023. //
  4024. // It hasn't completed yet.
  4025. //
  4026. break;
  4027. }
  4028. case ERROR_OPERATION_ABORTED:
  4029. {
  4030. //
  4031. // The thread that we originally submitted the Ioctl on
  4032. // went away and so the OS kindly cancelled the operation
  4033. // on us. How nice. Well, let's try resubmitting it.
  4034. //
  4035. DPFX(DPFPREP, 1, "Thread that submitted previous address list change notification went away, rerequesting.");
  4036. hr = this->RequestLocalAddressListChangeNotification();
  4037. if (hr != DPNH_OK)
  4038. {
  4039. DPFX(DPFPREP, 0, "Couldn't request local address list change notification!");
  4040. goto Failure;
  4041. }
  4042. break;
  4043. }
  4044. default:
  4045. {
  4046. DPFX(DPFPREP, 0, "Couldn't get overlapped result, error = %u! Ignoring.", dwError);
  4047. break;
  4048. }
  4049. } // end switch (on error)
  4050. }
  4051. }
  4052. //
  4053. // If we're on WinSock 2, let's try getting the address list with
  4054. // an Ioctl.
  4055. //
  4056. if (! (this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1))
  4057. {
  4058. DNASSERT(this->m_sIoctls != INVALID_SOCKET);
  4059. DNASSERT(this->m_pfnWSAIoctl != NULL);
  4060. //
  4061. // Keep trying to get the address list until we have a large enough
  4062. // buffer. We use the IN_ADDR array pointer simply because it's
  4063. // already there. We know that IN_ADDRs are smaller than
  4064. // SOCKET_ADDRESSes, so we can reuse the same buffer.
  4065. //
  4066. do
  4067. {
  4068. iReturn = this->m_pfnWSAIoctl(this->m_sIoctls, // use the special Ioctl socket
  4069. SIO_ADDRESS_LIST_QUERY, //
  4070. NULL, // no input data
  4071. 0, // no input data
  4072. painaddrAddresses, // output buffer
  4073. dwAddressesSize, // output buffer size
  4074. &dwTemp, // bytes needed
  4075. NULL, // no overlapped structure
  4076. NULL); // no completion routine
  4077. if (iReturn != 0)
  4078. {
  4079. dwError = this->m_pfnWSAGetLastError();
  4080. //
  4081. // Free the previous buffer, no matter what error it was.
  4082. //
  4083. if (painaddrAddresses != NULL)
  4084. {
  4085. DNFree(painaddrAddresses);
  4086. painaddrAddresses = NULL;
  4087. }
  4088. if (dwError != WSAEFAULT)
  4089. {
  4090. DPFX(DPFPREP, 0, "Retrieving address list failed (err = %u)!", dwError);
  4091. //
  4092. // We'll try the old-fashioned WinSock 1 way.
  4093. //
  4094. break;
  4095. }
  4096. //
  4097. // Be absolutely sure WinSock isn't causing us trouble.
  4098. //
  4099. if (dwTemp < sizeof(SOCKET_ADDRESS_LIST))
  4100. {
  4101. DPFX(DPFPREP, 0, "Received an invalid buffer size (%u < %u)!",
  4102. dwTemp, sizeof(SOCKET_ADDRESS_LIST));
  4103. //
  4104. // We'll try the old-fashioned WinSock 1 way.
  4105. //
  4106. break;
  4107. }
  4108. //
  4109. // The buffer wasn't large enough. Try again.
  4110. //
  4111. painaddrAddresses = (IN_ADDR*) DNMalloc(dwTemp);
  4112. if (painaddrAddresses == NULL)
  4113. {
  4114. hr = DPNHERR_OUTOFMEMORY;
  4115. goto Failure;
  4116. }
  4117. dwAddressesSize = dwTemp;
  4118. }
  4119. else
  4120. {
  4121. //
  4122. // Success! We're going to being sneaky and reuse the buffer.
  4123. // We know that the SOCKET_ADDRESS_LIST returned will be larger
  4124. // than an array of IN_ADDRs, so we can save a malloc.
  4125. //
  4126. // But first, be absolutely sure WinSock isn't causing us
  4127. // trouble.
  4128. //
  4129. if (painaddrAddresses == NULL)
  4130. {
  4131. DPFX(DPFPREP, 0, "WinSock returned success with a NULL buffer!");
  4132. //
  4133. // We'll try the old-fashioned WinSock 1 way.
  4134. //
  4135. break;
  4136. }
  4137. dwNumAddresses = ((SOCKET_ADDRESS_LIST*) painaddrAddresses)->iAddressCount;
  4138. dwAddressesSize = 0;
  4139. //
  4140. // Make sure there are addresses.
  4141. //
  4142. if (dwNumAddresses > 0)
  4143. {
  4144. DPFX(DPFPREP, 7, "WinSock 2 Ioctl returned %u addresses:", dwNumAddresses);
  4145. paSocketAddresses = ((SOCKET_ADDRESS_LIST*) painaddrAddresses)->Address;
  4146. for(dwTemp = 0; dwTemp < dwNumAddresses; dwTemp++)
  4147. {
  4148. DNASSERT(paSocketAddresses[dwTemp].iSockaddrLength == sizeof(SOCKADDR_IN));
  4149. DNASSERT(paSocketAddresses[dwTemp].lpSockaddr != NULL);
  4150. DNASSERT(paSocketAddresses[dwTemp].lpSockaddr->sa_family == AF_INET);
  4151. //
  4152. // Ignore 0.0.0.0 addresses.
  4153. //
  4154. if (((SOCKADDR_IN*) (paSocketAddresses[dwTemp].lpSockaddr))->sin_addr.S_un.S_addr != INADDR_NONE)
  4155. {
  4156. //
  4157. // Move the IN_ADDR component of this address
  4158. // toward the front of the buffer, into it's
  4159. // correct place in the array.
  4160. //
  4161. painaddrAddresses[dwTemp].S_un.S_addr = ((SOCKADDR_IN*) (paSocketAddresses[dwTemp].lpSockaddr))->sin_addr.S_un.S_addr;
  4162. DPFX(DPFPREP, 7, "\t%u- %u.%u.%u.%u",
  4163. dwTemp,
  4164. painaddrAddresses[dwTemp].S_un.S_un_b.s_b1,
  4165. painaddrAddresses[dwTemp].S_un.S_un_b.s_b2,
  4166. painaddrAddresses[dwTemp].S_un.S_un_b.s_b3,
  4167. painaddrAddresses[dwTemp].S_un.S_un_b.s_b4);
  4168. }
  4169. else
  4170. {
  4171. DPFX(DPFPREP, 1, "\t%u- Ignoring 0.0.0.0 address.", dwTemp);
  4172. dwAddressesSize++;
  4173. //
  4174. // The code should handle this fine, but why is
  4175. // WinSock doing this to us?
  4176. //
  4177. DNASSERT(FALSE);
  4178. }
  4179. }
  4180. //
  4181. // Subtract out any invalid addresses that we skipped.
  4182. //
  4183. dwNumAddresses -= dwAddressesSize;
  4184. if (dwNumAddresses == 0)
  4185. {
  4186. DPFX(DPFPREP, 1, "WinSock 2 reported only invalid addresses, hoping WinSock 1 method picks up the loopback address.");
  4187. DNFree(painaddrAddresses);
  4188. painaddrAddresses = NULL;
  4189. }
  4190. }
  4191. else
  4192. {
  4193. DPFX(DPFPREP, 1, "WinSock 2 Ioctl did not report any valid addresses, hoping WinSock 1 method picks up the loopback address.");
  4194. DNFree(painaddrAddresses);
  4195. painaddrAddresses = NULL;
  4196. }
  4197. //
  4198. // Get out of the loop.
  4199. //
  4200. break;
  4201. }
  4202. }
  4203. while (TRUE);
  4204. }
  4205. //
  4206. // Get the list of all available addresses from the WinSock 1 API if we
  4207. // don't already have them.
  4208. //
  4209. if (painaddrAddresses == NULL)
  4210. {
  4211. if (this->m_pfngethostname(szName, 1000) != 0)
  4212. {
  4213. #ifdef DBG
  4214. dwError = this->m_pfnWSAGetLastError();
  4215. DPFX(DPFPREP, 0, "Couldn't get host name, error = %u!", dwError);
  4216. #endif // DBG
  4217. hr = DPNHERR_GENERIC;
  4218. goto Failure;
  4219. }
  4220. phostent = this->m_pfngethostbyname(szName);
  4221. if (phostent == NULL)
  4222. {
  4223. #ifdef DBG
  4224. dwError = this->m_pfnWSAGetLastError();
  4225. DPFX(DPFPREP, 0, "Couldn't retrieve addresses, error = %u!", dwError);
  4226. #endif // DBG
  4227. hr = DPNHERR_GENERIC;
  4228. goto Failure;
  4229. }
  4230. //
  4231. // WinSock says that you need to copy this data before you make any
  4232. // other API calls. So first we count the number of entries we need to
  4233. // copy.
  4234. //
  4235. ppinaddr = (IN_ADDR**) phostent->h_addr_list;
  4236. while ((*ppinaddr) != NULL)
  4237. {
  4238. //
  4239. // Ignore 0.0.0.0 addresses.
  4240. //
  4241. if ((*ppinaddr)->S_un.S_addr != INADDR_NONE)
  4242. {
  4243. dwNumAddresses++;
  4244. }
  4245. else
  4246. {
  4247. DPFX(DPFPREP, 1, "Ignoring 0.0.0.0 address.");
  4248. //
  4249. // The code should handle this fine, but why is WinSock doing
  4250. // this to us?
  4251. //
  4252. DNASSERT(FALSE);
  4253. }
  4254. ppinaddr++;
  4255. }
  4256. //
  4257. // If there aren't any addresses, we must fail. WinSock 1 ought to
  4258. // report the loopback address at least.
  4259. //
  4260. if (dwNumAddresses == 0)
  4261. {
  4262. DPFX(DPFPREP, 0, "WinSock 1 did not report any valid addresses!");
  4263. hr = DPNHERR_GENERIC;
  4264. goto Failure;
  4265. }
  4266. DPFX(DPFPREP, 7, "WinSock 1 method returned %u valid addresses:", dwNumAddresses);
  4267. painaddrAddresses = (IN_ADDR*) DNMalloc(dwNumAddresses * sizeof(IN_ADDR));
  4268. if (painaddrAddresses == NULL)
  4269. {
  4270. hr = DPNHERR_OUTOFMEMORY;
  4271. goto Failure;
  4272. }
  4273. //
  4274. // Now copy all the addresses.
  4275. //
  4276. ppinaddr = (IN_ADDR**) phostent->h_addr_list;
  4277. dwTemp = 0;
  4278. while ((*ppinaddr) != NULL)
  4279. {
  4280. //
  4281. // Ignore 0.0.0.0 addresses again.
  4282. //
  4283. if ((*ppinaddr)->S_un.S_addr != INADDR_NONE)
  4284. {
  4285. painaddrAddresses[dwTemp].S_un.S_addr = (*ppinaddr)->S_un.S_addr;
  4286. DPFX(DPFPREP, 7, "\t%u- %u.%u.%u.%u",
  4287. dwTemp,
  4288. painaddrAddresses[dwTemp].S_un.S_un_b.s_b1,
  4289. painaddrAddresses[dwTemp].S_un.S_un_b.s_b2,
  4290. painaddrAddresses[dwTemp].S_un.S_un_b.s_b3,
  4291. painaddrAddresses[dwTemp].S_un.S_un_b.s_b4);
  4292. dwTemp++;
  4293. }
  4294. ppinaddr++;
  4295. }
  4296. DNASSERT(dwTemp == dwNumAddresses);
  4297. }
  4298. else
  4299. {
  4300. //
  4301. // Already have addresses array.
  4302. //
  4303. }
  4304. //
  4305. // Make sure that all of the devices we currently know about are still
  4306. // around.
  4307. //
  4308. pBilinkDevice = this->m_blDevices.GetNext();
  4309. while (pBilinkDevice != &this->m_blDevices)
  4310. {
  4311. pDevice = DEVICE_FROM_BILINK(pBilinkDevice);
  4312. pBilinkDevice = pBilinkDevice->GetNext();
  4313. fFound = FALSE;
  4314. for(dwTemp = 0; dwTemp < dwNumAddresses; dwTemp++)
  4315. {
  4316. if (painaddrAddresses[dwTemp].S_un.S_addr == pDevice->GetLocalAddressV4())
  4317. {
  4318. fFound = TRUE;
  4319. break;
  4320. }
  4321. }
  4322. if (fFound)
  4323. {
  4324. //
  4325. // It may be time for this device to use a different port...
  4326. //
  4327. dwTemp = pDevice->GetFirstPASTDiscoveryTime();
  4328. if ((dwTemp != 0) && ((GETTIMESTAMP() - dwTemp) > g_dwReusePortTime))
  4329. {
  4330. ZeroMemory(&saddrinTemp, sizeof(saddrinTemp));
  4331. saddrinTemp.sin_family = AF_INET;
  4332. saddrinTemp.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  4333. sTemp = this->CreatePASTSocket(&saddrinTemp);
  4334. if (sTemp != INVALID_SOCKET)
  4335. {
  4336. //
  4337. // Sanity check that we didn't lose the device address.
  4338. //
  4339. DNASSERT(saddrinTemp.sin_addr.S_un.S_addr == pDevice->GetLocalAddressV4());
  4340. DPFX(DPFPREP, 4, "Device 0x%p PAST socket 0x%p (%u.%u.%u.%u:%u) created to replace existing one.",
  4341. pDevice,
  4342. sTemp,
  4343. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  4344. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  4345. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  4346. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  4347. NTOHS(saddrinTemp.sin_port));
  4348. pDevice->SetFirstPASTDiscoveryTime(0);
  4349. //
  4350. // Close the existing socket.
  4351. //
  4352. this->m_pfnclosesocket(pDevice->GetPASTSocket());
  4353. //
  4354. // Transfer ownership of the new socket to the device.
  4355. //
  4356. pDevice->SetPASTSocket(sTemp);
  4357. sTemp = INVALID_SOCKET;
  4358. DPFX(DPFPREP, 8, "Device 0x%p got re-assigned PAST socket 0x%p.",
  4359. pDevice, pDevice->GetPASTSocket());
  4360. }
  4361. else
  4362. {
  4363. DPFX(DPFPREP, 0, "Couldn't create a replacement PAST socket for device 0x%p! Using existing one.",
  4364. pDevice);
  4365. }
  4366. }
  4367. }
  4368. else
  4369. {
  4370. //
  4371. // Didn't find this device in the returned list, forget about
  4372. // it.
  4373. //
  4374. #ifdef DBG
  4375. {
  4376. IN_ADDR inaddrTemp;
  4377. inaddrTemp.S_un.S_addr = pDevice->GetLocalAddressV4();
  4378. DPFX(DPFPREP, 1, "Device 0x%p no longer exists, removing (address was %u.%u.%u.%u).",
  4379. pDevice,
  4380. inaddrTemp.S_un.S_un_b.s_b1,
  4381. inaddrTemp.S_un.S_un_b.s_b2,
  4382. inaddrTemp.S_un.S_un_b.s_b3,
  4383. inaddrTemp.S_un.S_un_b.s_b4);
  4384. }
  4385. this->m_dwNumDeviceRemoves++;
  4386. #endif // DBG
  4387. //
  4388. // Override the minimum UpdateServerStatus interval so that we can
  4389. // get information on any local public address changes due to the
  4390. // possible loss of a server on this interface.
  4391. //
  4392. this->m_dwFlags |= NATHELPPASTOBJ_DEVICECHANGED;
  4393. //
  4394. // Since there was a change in the network, go back to polling
  4395. // relatively quickly.
  4396. //
  4397. this->ResetNextPollInterval();
  4398. //
  4399. // Forcefully mark the PAST servers as disconnected.
  4400. //
  4401. if (pDevice->GetPASTClientID(TRUE) != 0)
  4402. {
  4403. this->ClearDevicesPASTServer(pDevice, TRUE);
  4404. }
  4405. if (pDevice->GetPASTClientID(FALSE) != 0)
  4406. {
  4407. this->ClearDevicesPASTServer(pDevice, FALSE);
  4408. }
  4409. //
  4410. // Mark all ports that were registered to this device as unowned
  4411. // by putting them into the wildcard list.
  4412. //
  4413. pBilinkRegPort = pDevice->m_blOwnedRegPorts.GetNext();
  4414. while (pBilinkRegPort != &pDevice->m_blOwnedRegPorts)
  4415. {
  4416. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilinkRegPort);
  4417. pBilinkRegPort = pBilinkRegPort->GetNext();
  4418. DPFX(DPFPREP, 1, "Registered port 0x%p's device went away, marking as unowned.",
  4419. pRegisteredPort);
  4420. DNASSERT(pRegisteredPort->GetPASTBindID(TRUE) == 0);
  4421. DNASSERT(pRegisteredPort->GetPASTBindID(FALSE) == 0);
  4422. DNASSERT(! pRegisteredPort->HasPASTPublicAddressesArray(TRUE));
  4423. DNASSERT(! pRegisteredPort->HasPASTPublicAddressesArray(FALSE));
  4424. DNASSERT(! pRegisteredPort->IsPASTPortUnavailable(TRUE));
  4425. DNASSERT(! pRegisteredPort->IsPASTPortUnavailable(FALSE));
  4426. pRegisteredPort->ClearDeviceOwner();
  4427. pRegisteredPort->m_blDeviceList.RemoveFromList();
  4428. pRegisteredPort->m_blDeviceList.InsertBefore(&this->m_blUnownedPorts);
  4429. //
  4430. // The user doesn't directly need to be informed. If the ports
  4431. // previously had public addresses, the ADDRESSESCHANGED flag
  4432. // would have already been set by ClearDevicesPASTServer. If
  4433. // they didn't have ports with public addresses, then the user
  4434. // won't see any difference and thus ADDRESSESCHANGED wouldn't
  4435. // need to be set.
  4436. //
  4437. }
  4438. pDevice->m_blList.RemoveFromList();
  4439. //
  4440. // Close the sockets.
  4441. //
  4442. this->m_pfnclosesocket(pDevice->GetPASTSocket());
  4443. pDevice->SetPASTSocket(INVALID_SOCKET);
  4444. delete pDevice;
  4445. }
  4446. }
  4447. //
  4448. // Search for all returned devices in our existing list, and add new
  4449. // entries for each one that we didn't already know about.
  4450. //
  4451. for(dwTemp = 0; dwTemp < dwNumAddresses; dwTemp++)
  4452. {
  4453. fFound = FALSE;
  4454. pBilinkDevice = this->m_blDevices.GetNext();
  4455. while (pBilinkDevice != &this->m_blDevices)
  4456. {
  4457. pDevice = DEVICE_FROM_BILINK(pBilinkDevice);
  4458. pBilinkDevice = pBilinkDevice->GetNext();
  4459. if (pDevice->GetLocalAddressV4() == painaddrAddresses[dwTemp].S_un.S_addr)
  4460. {
  4461. fFound = TRUE;
  4462. break;
  4463. }
  4464. }
  4465. if (! fFound)
  4466. {
  4467. //
  4468. // We didn't know about this device. Create a new object.
  4469. //
  4470. pDevice = new CDevice(painaddrAddresses[dwTemp].S_un.S_addr);
  4471. if (pDevice == NULL)
  4472. {
  4473. hr = DPNHERR_OUTOFMEMORY;
  4474. goto Failure;
  4475. }
  4476. fDeviceCreated = TRUE;
  4477. #ifdef DBG
  4478. DPFX(DPFPREP, 1, "Found new device %u.%u.%u.%u, (object = 0x%p).",
  4479. painaddrAddresses[dwTemp].S_un.S_un_b.s_b1,
  4480. painaddrAddresses[dwTemp].S_un.S_un_b.s_b2,
  4481. painaddrAddresses[dwTemp].S_un.S_un_b.s_b3,
  4482. painaddrAddresses[dwTemp].S_un.S_un_b.s_b4,
  4483. pDevice);
  4484. this->m_dwNumDeviceAdds++;
  4485. #endif // DBG
  4486. //
  4487. // Override the minimum UpdateServerStatus interval so that we can
  4488. // get information on this new device.
  4489. //
  4490. this->m_dwFlags |= NATHELPPASTOBJ_DEVICECHANGED;
  4491. //
  4492. // Since there was a change in the network, go back to polling
  4493. // relatively quickly.
  4494. //
  4495. this->ResetNextPollInterval();
  4496. //
  4497. // Create the PAST socket.
  4498. //
  4499. ZeroMemory(&saddrinTemp, sizeof(saddrinTemp));
  4500. saddrinTemp.sin_family = AF_INET;
  4501. saddrinTemp.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  4502. sTemp = this->CreatePASTSocket(&saddrinTemp);
  4503. if (sTemp == INVALID_SOCKET)
  4504. {
  4505. DPFX(DPFPREP, 0, "Couldn't create PAST socket! Ignoring address (and destroying device 0x%p).",
  4506. pDevice);
  4507. //
  4508. // Get rid of the device.
  4509. //
  4510. delete pDevice;
  4511. pDevice = NULL;
  4512. //
  4513. // Forget about device in case of failure later.
  4514. //
  4515. fDeviceCreated = FALSE;
  4516. //
  4517. // Move to next address.
  4518. //
  4519. continue;
  4520. }
  4521. //
  4522. // Sanity check that we didn't lose the device address.
  4523. //
  4524. DNASSERT(saddrinTemp.sin_addr.S_un.S_addr == pDevice->GetLocalAddressV4());
  4525. DPFX(DPFPREP, 4, "Device 0x%p PAST socket 0x%p (%u.%u.%u.%u:%u) created.",
  4526. pDevice,
  4527. sTemp,
  4528. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  4529. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  4530. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  4531. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  4532. NTOHS(saddrinTemp.sin_port));
  4533. //
  4534. // Transfer ownership of the socket to the device.
  4535. //
  4536. pDevice->SetPASTSocket(sTemp);
  4537. sTemp = INVALID_SOCKET;
  4538. DPFX(DPFPREP, 8, "Device 0x%p got assigned PAST socket 0x%p.",
  4539. pDevice, pDevice->GetPASTSocket());
  4540. //
  4541. // Add the device to our known list.
  4542. //
  4543. pDevice->m_blList.InsertBefore(&this->m_blDevices);
  4544. //
  4545. // Inform the caller if they care.
  4546. //
  4547. if (pfFoundNewDevices != NULL)
  4548. {
  4549. (*pfFoundNewDevices) = TRUE;
  4550. }
  4551. //
  4552. // Forget about device in case of failure later.
  4553. //
  4554. fDeviceCreated = FALSE;
  4555. }
  4556. }
  4557. //
  4558. // If we got some very weird failures and ended up here without any
  4559. // devices, complain to management (or the caller of this function, that's
  4560. // probably more convenient).
  4561. //
  4562. if (this->m_blDevices.IsEmpty())
  4563. {
  4564. DPFX(DPFPREP, 0, "No usable devices, cannot proceed!", 0);
  4565. DNASSERTX(! "No usable devices!", 2);
  4566. hr = DPNHERR_GENERIC;
  4567. goto Failure;
  4568. }
  4569. Exit:
  4570. if (painaddrAddresses != NULL)
  4571. {
  4572. DNFree(painaddrAddresses);
  4573. painaddrAddresses = NULL;
  4574. }
  4575. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  4576. return hr;
  4577. Failure:
  4578. if (sTemp != INVALID_SOCKET)
  4579. {
  4580. this->m_pfnclosesocket(sTemp);
  4581. sTemp = INVALID_SOCKET;
  4582. }
  4583. if (fDeviceCreated)
  4584. {
  4585. delete pDevice;
  4586. }
  4587. goto Exit;
  4588. } // CNATHelpPAST::CheckForNewDevices
  4589. #undef DPF_MODNAME
  4590. #define DPF_MODNAME "CNATHelpPAST::CheckForLocalPASTServerAndRegister"
  4591. //=============================================================================
  4592. // CNATHelpPAST::CheckForLocalPASTServerAndRegister
  4593. //-----------------------------------------------------------------------------
  4594. //
  4595. // Description: Checks for a local PAST server on the given device. If one
  4596. // is found, a new client is registered.
  4597. //
  4598. // The object lock is assumed to be held.
  4599. //
  4600. // Arguments:
  4601. // CDevice * pDevice - Pointer to device to check.
  4602. //
  4603. // Returns: HRESULT
  4604. // DPNH_OK - The check was successful (may not be a server,
  4605. // though).
  4606. // DPNHERR_GENERIC - An error occurred.
  4607. //=============================================================================
  4608. HRESULT CNATHelpPAST::CheckForLocalPASTServerAndRegister(CDevice * const pDevice)
  4609. {
  4610. HRESULT hr = DPNH_OK;
  4611. DWORD dwError;
  4612. SOCKET sTemp = INVALID_SOCKET;
  4613. SOCKADDR_IN saddrinTemp;
  4614. BOOL fAddressAlreadyChanged;
  4615. DWORD dwOriginalNextPollInterval;
  4616. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p)", this, pDevice);
  4617. //
  4618. // Open a datagram socket on this device.
  4619. //
  4620. sTemp = this->m_pfnsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  4621. if (sTemp == INVALID_SOCKET)
  4622. {
  4623. #ifdef DBG
  4624. dwError = this->m_pfnWSAGetLastError();
  4625. DPFX(DPFPREP, 0, "Couldn't create datagram socket, error = %u!", dwError);
  4626. #endif // DBG
  4627. hr = DPNHERR_GENERIC;
  4628. goto Failure;
  4629. }
  4630. //
  4631. // Try binding it to the PAST port first to see if there's a local PAST
  4632. // server on the device.
  4633. //
  4634. // We could just go ahead and try to register with a server, but if one
  4635. // doesn't exist, the registration code would block during the timeout. By
  4636. // simply checking if the port is in use, we can avoid that timeout. The
  4637. // only slight cost is if two PASTHelps happened to be trying this at the
  4638. // exact same time, one could be tricked by the other into thinking that
  4639. // the port was in use. In that case, it would falsely try to register...
  4640. // but then timeout. Not a big deal, that's treated as non-fatal below.
  4641. //
  4642. ZeroMemory(&saddrinTemp, sizeof(saddrinTemp));
  4643. saddrinTemp.sin_family = AF_INET;
  4644. saddrinTemp.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  4645. saddrinTemp.sin_port = HTONS(PAST_HOST_PORT);
  4646. if (this->m_pfnbind(sTemp,
  4647. (SOCKADDR *) (&saddrinTemp),
  4648. sizeof(saddrinTemp)) != 0)
  4649. {
  4650. //
  4651. // The bind failed. We'll print the exact error, but assume it was
  4652. // because the port was in use.
  4653. //
  4654. #ifdef DBG
  4655. dwError = this->m_pfnWSAGetLastError();
  4656. DPFX(DPFPREP, 1, "Couldn't bind datagram socket %u.%u.%u.%u:%u to PAST server port, assuming because there's a local PAST server (error = %u).",
  4657. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  4658. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  4659. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  4660. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  4661. NTOHS(saddrinTemp.sin_port),
  4662. dwError);
  4663. #endif // DBG
  4664. //
  4665. // Save the current poll interval in case we need to restore it.
  4666. //
  4667. dwOriginalNextPollInterval = this->m_dwNextPollInterval;
  4668. //
  4669. // We should register with this local PAST server right now.
  4670. // This might reset the poll interval.
  4671. //
  4672. hr = this->RegisterWithLocalPASTServer(pDevice);
  4673. if (hr != DPNH_OK)
  4674. {
  4675. if (hr == DPNHERR_SERVERNOTRESPONDING)
  4676. {
  4677. //
  4678. // If the server isn't responding, we'll treat it as non-fatal,
  4679. // but obviously we can't use the server.
  4680. //
  4681. DPFX(DPFPREP, 1, "Local PAST server does not respond to registrations, ignoring.");
  4682. }
  4683. else
  4684. {
  4685. //
  4686. // Some other failure. Annoying, but ignore it.
  4687. //
  4688. DPFX(DPFPREP, 0, "Couldn't register with local PAST server (err = 0x%lx)! Ignoring.",
  4689. hr);
  4690. }
  4691. hr = DPNH_OK;
  4692. //
  4693. // Drop through.
  4694. //
  4695. }
  4696. else
  4697. {
  4698. fAddressAlreadyChanged = (this->m_dwFlags & NATHELPPASTOBJ_ADDRESSESCHANGED) ? TRUE : FALSE;
  4699. //
  4700. // We need to bind a temporary port to detect ICS vs. FW-only.
  4701. // UpdatePASTPublicAddressValidity does this in addition to
  4702. // checking public address validity like the function name
  4703. // says.
  4704. //
  4705. hr = this->UpdatePASTPublicAddressValidity(pDevice, FALSE);
  4706. if (hr != DPNH_OK)
  4707. {
  4708. DPFX(DPFPREP, 0, "Couldn't update new local PAST server public address validity!", hr);
  4709. goto Failure;
  4710. }
  4711. //
  4712. // If we encountered an error that caused the PAST server to be
  4713. // removed, then we shouldn't (and can't) try registering any
  4714. // existing ports.
  4715. //
  4716. // Otherwise, make sure we're allowed to work with the type of PAST
  4717. // server found. If we aren't de-register. If we are, bind any
  4718. // ports already associated with this device.
  4719. //
  4720. if ((pDevice->GetPASTClientID(FALSE) == 0) ||
  4721. ((pDevice->HasLocalICSPASTServer()) && (! (this->m_dwFlags & NATHELPPASTOBJ_USEPASTICS))) ||
  4722. ((pDevice->HasLocalPFWOnlyPASTServer()) && (! (this->m_dwFlags & NATHELPPASTOBJ_USEPASTPFW))))
  4723. {
  4724. if (pDevice->GetPASTClientID(FALSE) != 0)
  4725. {
  4726. DPFX(DPFPREP, 2, "Not allowed to use local %s PAST server, de-registering.",
  4727. ((pDevice->HasLocalICSPASTServer()) ? _T("ICS") : _T("PFW only")));
  4728. hr = this->DeregisterWithPASTServer(pDevice, FALSE);
  4729. if (hr != DPNH_OK)
  4730. {
  4731. DPFX(DPFPREP, 0, "Couldn't de-register with local PAST server (err = 0x%lx)! Ignoring.",
  4732. hr);
  4733. //
  4734. // Consider ourselves de-registered.
  4735. //
  4736. pDevice->SetPASTClientID(0, FALSE);
  4737. //
  4738. // Continue anyway...
  4739. //
  4740. hr = DPNH_OK;
  4741. }
  4742. this->ClearAllPASTServerRegisteredPorts(pDevice, FALSE);
  4743. this->RemoveAllPASTCachedMappings(pDevice, FALSE);
  4744. pDevice->NoteNoPASTPublicAddressAvailable(FALSE);
  4745. pDevice->NoteNoLocalPASTServer();
  4746. }
  4747. else
  4748. {
  4749. DPFX(DPFPREP, 1, "Local PAST server was removed while trying to update public address validity.");
  4750. }
  4751. //
  4752. // Prevent the user from thinking the addresses changed unless
  4753. // something else caused the address change notification.
  4754. //
  4755. if (! fAddressAlreadyChanged)
  4756. {
  4757. this->m_dwFlags &= ~NATHELPPASTOBJ_ADDRESSESCHANGED;
  4758. }
  4759. //
  4760. // Go back to the previous poll interval.
  4761. //
  4762. this->m_dwNextPollInterval = dwOriginalNextPollInterval;
  4763. }
  4764. else
  4765. {
  4766. if (! pDevice->m_blOwnedRegPorts.IsEmpty())
  4767. {
  4768. DPFX(DPFPREP, 2, "Local PAST server now available, registering existing ports.");
  4769. hr = this->RegisterAllPortsWithPAST(pDevice, FALSE);
  4770. if (hr != DPNH_OK)
  4771. {
  4772. DPFX(DPFPREP, 0, "Couldn't register existing ports with new local PAST server!", hr);
  4773. goto Failure;
  4774. }
  4775. #ifdef DBG
  4776. //
  4777. // If we didn't encounter an error that caused the PAST
  4778. // server to be removed, then the
  4779. // NATHELPPASTOBJ_ADDRESSESCHANGED flag must have been set
  4780. // by the AssignOrListenPorts function.
  4781. //
  4782. if (pDevice->GetPASTClientID(TRUE) != 0)
  4783. {
  4784. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_ADDRESSESCHANGED);
  4785. }
  4786. else
  4787. {
  4788. DPFX(DPFPREP, 1, "Local PAST server was removed while trying to register existing ports.");
  4789. }
  4790. #endif // DBG
  4791. }
  4792. else
  4793. {
  4794. DPFX(DPFPREP, 2, "Local PAST server now available, but no previously registered ports.");
  4795. }
  4796. }
  4797. } // end else (successfully registered with local PAST server)
  4798. }
  4799. else
  4800. {
  4801. //
  4802. // The bind succeeded. Doesn't look like there's a local PAST server.
  4803. //
  4804. DPFX(DPFPREP, 7, "Bound datagram socket %u.%u.%u.%u:%u, no local PAST server present.",
  4805. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  4806. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  4807. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  4808. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  4809. NTOHS(saddrinTemp.sin_port));
  4810. }
  4811. Exit:
  4812. if (sTemp != INVALID_SOCKET)
  4813. {
  4814. this->m_pfnclosesocket(sTemp);
  4815. }
  4816. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  4817. return hr;
  4818. Failure:
  4819. goto Exit;
  4820. } // CNATHelpPAST::CheckForLocalPASTServerAndRegister
  4821. #undef DPF_MODNAME
  4822. #define DPF_MODNAME "CNATHelpPAST::RemoveAllItems"
  4823. //=============================================================================
  4824. // CNATHelpPAST::RemoveAllItems
  4825. //-----------------------------------------------------------------------------
  4826. //
  4827. // Description: Removes all devices (de-registering with Internet gateways
  4828. // if necessary). This removes all registered port mapping
  4829. // objects, as well.
  4830. //
  4831. // The object lock is assumed to be held.
  4832. //
  4833. // Arguments: None.
  4834. //
  4835. // Returns: None.
  4836. //=============================================================================
  4837. void CNATHelpPAST::RemoveAllItems(void)
  4838. {
  4839. HRESULT hr;
  4840. CBilink * pBilinkDevice;
  4841. CDevice * pDevice;
  4842. CBilink * pBilinkRegisteredPort;
  4843. CRegisteredPort * pRegisteredPort;
  4844. DPFX(DPFPREP, 7, "(0x%p) Enter", this);
  4845. pBilinkDevice = this->m_blDevices.GetNext();
  4846. while (pBilinkDevice != &this->m_blDevices)
  4847. {
  4848. pDevice = DEVICE_FROM_BILINK(pBilinkDevice);
  4849. pBilinkDevice = pBilinkDevice->GetNext();
  4850. DPFX(DPFPREP, 5, "Destroying device 0x%p.",
  4851. pDevice);
  4852. pDevice->m_blList.RemoveFromList();
  4853. //
  4854. // De-register from remote PAST server if necessary.
  4855. //
  4856. if (pDevice->GetPASTClientID(TRUE) != 0)
  4857. {
  4858. hr = this->DeregisterWithPASTServer(pDevice, TRUE);
  4859. if (hr != DPNH_OK)
  4860. {
  4861. DPFX(DPFPREP, 0, "Couldn't de-register with remote PAST server (err = 0x%lx)! Ignoring.",
  4862. hr);
  4863. //
  4864. // Consider ourselves de-registered.
  4865. //
  4866. pDevice->SetPASTClientID(0, TRUE);
  4867. //
  4868. // Continue anyway, so we can finish cleaning up the object.
  4869. //
  4870. }
  4871. this->ClearAllPASTServerRegisteredPorts(pDevice, TRUE);
  4872. this->RemoveAllPASTCachedMappings(pDevice, TRUE);
  4873. pDevice->NoteNoPASTPublicAddressAvailable(TRUE);
  4874. }
  4875. //
  4876. // De-register from local PAST server if necessary.
  4877. //
  4878. if (pDevice->GetPASTClientID(FALSE) != 0)
  4879. {
  4880. hr = this->DeregisterWithPASTServer(pDevice, FALSE);
  4881. if (hr != DPNH_OK)
  4882. {
  4883. DPFX(DPFPREP, 0, "Couldn't de-register with local PAST server (err = 0x%lx)! Ignoring.",
  4884. hr);
  4885. //
  4886. // Consider ourselves de-registered.
  4887. //
  4888. pDevice->SetPASTClientID(0, FALSE);
  4889. //
  4890. // Continue anyway, so we can finish cleaning up the object.
  4891. //
  4892. }
  4893. this->ClearAllPASTServerRegisteredPorts(pDevice, FALSE);
  4894. this->RemoveAllPASTCachedMappings(pDevice, FALSE);
  4895. pDevice->NoteNoPASTPublicAddressAvailable(FALSE);
  4896. }
  4897. //
  4898. // All of the device's registered ports are implicitly freed.
  4899. //
  4900. pBilinkRegisteredPort = pDevice->m_blOwnedRegPorts.GetNext();
  4901. while (pBilinkRegisteredPort != &pDevice->m_blOwnedRegPorts)
  4902. {
  4903. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilinkRegisteredPort);
  4904. pBilinkRegisteredPort = pBilinkRegisteredPort->GetNext();
  4905. DPFX(DPFPREP, 5, "Destroying registered port 0x%p (under device 0x%p).",
  4906. pRegisteredPort, pDevice);
  4907. pRegisteredPort->ClearDeviceOwner();
  4908. pRegisteredPort->m_blGlobalList.RemoveFromList();
  4909. if (pRegisteredPort->GetPASTBindID(TRUE) != 0)
  4910. {
  4911. pRegisteredPort->SetPASTBindID(0, TRUE);
  4912. pRegisteredPort->ClearPASTPublicAddresses(TRUE);
  4913. DNASSERT(this->m_dwNumLeases > 0);
  4914. this->m_dwNumLeases--;
  4915. DPFX(DPFPREP, 7, "Remote PAST lease for 0x%p cleared, total num leases = %u.",
  4916. pRegisteredPort, this->m_dwNumLeases);
  4917. }
  4918. if (pRegisteredPort->GetPASTBindID(FALSE) != 0)
  4919. {
  4920. pRegisteredPort->SetPASTBindID(0, FALSE);
  4921. pRegisteredPort->ClearPASTPublicAddresses(FALSE);
  4922. DNASSERT(this->m_dwNumLeases > 0);
  4923. this->m_dwNumLeases--;
  4924. DPFX(DPFPREP, 7, "Local PAST lease for 0x%p cleared, total num leases = %u.",
  4925. pRegisteredPort, this->m_dwNumLeases);
  4926. }
  4927. pRegisteredPort->ClearPrivateAddresses();
  4928. //
  4929. // The user implicitly released this port.
  4930. //
  4931. pRegisteredPort->ClearAllUserRefs();
  4932. delete pRegisteredPort;
  4933. }
  4934. //
  4935. // Close the socket.
  4936. //
  4937. this->m_pfnclosesocket(pDevice->GetPASTSocket());
  4938. pDevice->SetPASTSocket(INVALID_SOCKET);
  4939. //
  4940. // Now we can dump the device object.
  4941. //
  4942. delete pDevice;
  4943. }
  4944. //
  4945. // Removing all the devices normally removes all the registered ports, but
  4946. // there may still be more wildcard ports that were never associated with
  4947. // any device.
  4948. //
  4949. pBilinkRegisteredPort = this->m_blUnownedPorts.GetNext();
  4950. while (pBilinkRegisteredPort != &this->m_blUnownedPorts)
  4951. {
  4952. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilinkRegisteredPort);
  4953. pBilinkRegisteredPort = pBilinkRegisteredPort->GetNext();
  4954. DPFX(DPFPREP, 5, "Destroying unowned registered port 0x%p.",
  4955. pRegisteredPort);
  4956. pRegisteredPort->m_blDeviceList.RemoveFromList();
  4957. pRegisteredPort->m_blGlobalList.RemoveFromList();
  4958. pRegisteredPort->ClearPrivateAddresses();
  4959. DNASSERT(pRegisteredPort->GetPASTBindID(TRUE) == 0);
  4960. DNASSERT(pRegisteredPort->GetPASTBindID(FALSE) == 0);
  4961. //
  4962. // The user implicitly released this port.
  4963. //
  4964. pRegisteredPort->ClearAllUserRefs();
  4965. delete pRegisteredPort;
  4966. }
  4967. DNASSERT(this->m_blRegisteredPorts.IsEmpty());
  4968. DPFX(DPFPREP, 7, "(0x%p) Leave", this);
  4969. } // CNATHelpPAST::RemoveAllItems
  4970. #undef DPF_MODNAME
  4971. #define DPF_MODNAME "CNATHelpPAST::FindMatchingDevice"
  4972. //=============================================================================
  4973. // CNATHelpPAST::FindMatchingDevice
  4974. //-----------------------------------------------------------------------------
  4975. //
  4976. // Description: Searches the list of devices for the object matching the
  4977. // given address, or NULL if one could not be found.
  4978. //
  4979. // If fMatchRegPort is TRUE, the list of registered ports
  4980. // associated with devices is searched first for an exact match to
  4981. // the address passed in.
  4982. //
  4983. // The object lock is assumed to be held.
  4984. //
  4985. // Arguments:
  4986. // SOCKADDR_IN * psaddrinMatch - Pointer to address to look up.
  4987. // BOOL fMatchRegPort - Whether existing registered ports should
  4988. // be checked for an exact match first.
  4989. //
  4990. // Returns: CDevice
  4991. // NULL if no match, valid object otherwise.
  4992. //=============================================================================
  4993. CDevice * CNATHelpPAST::FindMatchingDevice(const SOCKADDR_IN * const psaddrinMatch,
  4994. const BOOL fMatchRegPort)
  4995. {
  4996. HRESULT hr;
  4997. BOOL fUpdatedDeviceList = FALSE;
  4998. CDevice * pDeviceRemoteICSServer = NULL;
  4999. CDevice * pDeviceLocalICSServer = NULL;
  5000. CDevice * pDeviceLocalPFWOnlyServer = NULL;
  5001. SOCKADDR_IN * psaddrinTemp;
  5002. CBilink * pBilink;
  5003. CRegisteredPort * pRegisteredPort;
  5004. CDevice * pDevice;
  5005. DWORD dwTemp;
  5006. do
  5007. {
  5008. //
  5009. // First, make sure there are devices to choose from.
  5010. //
  5011. if (this->m_blDevices.IsEmpty())
  5012. {
  5013. DPFX(DPFPREP, 0, "No devices, can't match address %u.%u.%u.%u!",
  5014. psaddrinMatch->sin_addr.S_un.S_un_b.s_b1,
  5015. psaddrinMatch->sin_addr.S_un.S_un_b.s_b2,
  5016. psaddrinMatch->sin_addr.S_un.S_un_b.s_b3,
  5017. psaddrinMatch->sin_addr.S_un.S_un_b.s_b4);
  5018. pDevice = NULL;
  5019. goto Exit;
  5020. }
  5021. //
  5022. // It's possible that the address we're trying to match is an already
  5023. // registered port. Look through all owned port mappings for this
  5024. // address, if we're allowed.
  5025. //
  5026. if (fMatchRegPort)
  5027. {
  5028. pBilink = this->m_blRegisteredPorts.GetNext();
  5029. while (pBilink != &this->m_blRegisteredPorts)
  5030. {
  5031. pRegisteredPort = REGPORT_FROM_GLOBAL_BILINK(pBilink);
  5032. //
  5033. // Only check this registered port if it has an owning device.
  5034. //
  5035. pDevice = pRegisteredPort->GetOwningDevice();
  5036. if (pDevice != NULL)
  5037. {
  5038. //
  5039. // Check each port in the array.
  5040. //
  5041. psaddrinTemp = pRegisteredPort->GetPrivateAddressesArray();
  5042. for(dwTemp = 0; dwTemp < pRegisteredPort->GetNumAddresses(); dwTemp++)
  5043. {
  5044. //
  5045. // If the address matches, we have a winner.
  5046. //
  5047. if ((psaddrinTemp[dwTemp].sin_addr.S_un.S_addr == psaddrinMatch->sin_addr.S_un.S_addr) &&
  5048. (psaddrinTemp[dwTemp].sin_port == psaddrinMatch->sin_port))
  5049. {
  5050. DPFX(DPFPREP, 7, "Registered port 0x%p index %u matches address %u.%u.%u.%u:%u, returning owning device 0x%p.",
  5051. pRegisteredPort,
  5052. dwTemp,
  5053. psaddrinMatch->sin_addr.S_un.S_un_b.s_b1,
  5054. psaddrinMatch->sin_addr.S_un.S_un_b.s_b2,
  5055. psaddrinMatch->sin_addr.S_un.S_un_b.s_b3,
  5056. psaddrinMatch->sin_addr.S_un.S_un_b.s_b4,
  5057. NTOHS(psaddrinMatch->sin_port),
  5058. pDevice);
  5059. goto Exit;
  5060. }
  5061. }
  5062. }
  5063. pBilink = pBilink->GetNext();
  5064. }
  5065. }
  5066. //
  5067. // Darn, the address is not already registered. Well, match it up with
  5068. // a device as best as possible.
  5069. //
  5070. pBilink = this->m_blDevices.GetNext();
  5071. do
  5072. {
  5073. pDevice = DEVICE_FROM_BILINK(pBilink);
  5074. if ((pDevice->GetLocalAddressV4() == psaddrinMatch->sin_addr.S_un.S_addr))
  5075. {
  5076. DPFX(DPFPREP, 7, "Device 0x%p matches address %u.%u.%u.%u.",
  5077. pDevice,
  5078. psaddrinMatch->sin_addr.S_un.S_un_b.s_b1,
  5079. psaddrinMatch->sin_addr.S_un.S_un_b.s_b2,
  5080. psaddrinMatch->sin_addr.S_un.S_un_b.s_b3,
  5081. psaddrinMatch->sin_addr.S_un.S_un_b.s_b4);
  5082. goto Exit;
  5083. }
  5084. //
  5085. // Remember this device if it has the first remote ICS server we've
  5086. // seen.
  5087. //
  5088. if ((pDevice->GetPASTClientID(TRUE) != 0) &&
  5089. (pDeviceRemoteICSServer == NULL))
  5090. {
  5091. pDeviceRemoteICSServer = pDevice;
  5092. }
  5093. //
  5094. // Remember this device if it has the first local ICS or firewall
  5095. // only server we've seen.
  5096. //
  5097. if (pDevice->GetPASTClientID(FALSE) != 0)
  5098. {
  5099. if ((pDevice->HasLocalICSPASTServer()) &&
  5100. (pDeviceLocalICSServer == NULL))
  5101. {
  5102. pDeviceLocalICSServer = pDevice;
  5103. }
  5104. else if ((pDevice->HasLocalPFWOnlyPASTServer()) &&
  5105. (pDeviceLocalPFWOnlyServer == NULL))
  5106. {
  5107. pDeviceLocalPFWOnlyServer = pDevice;
  5108. }
  5109. }
  5110. DPFX(DPFPREP, 7, "Device 0x%p does not match address %u.%u.%u.%u.",
  5111. pDevice,
  5112. psaddrinMatch->sin_addr.S_un.S_un_b.s_b1,
  5113. psaddrinMatch->sin_addr.S_un.S_un_b.s_b2,
  5114. psaddrinMatch->sin_addr.S_un.S_un_b.s_b3,
  5115. psaddrinMatch->sin_addr.S_un.S_un_b.s_b4);
  5116. pBilink = pBilink->GetNext();
  5117. }
  5118. while (pBilink != &this->m_blDevices);
  5119. //
  5120. // If we got here, there's no matching device. It might be because the
  5121. // caller detected an address change faster than we did. Try updating
  5122. // our device list and searching again (if we haven't already).
  5123. //
  5124. if (fUpdatedDeviceList)
  5125. {
  5126. break;
  5127. }
  5128. //
  5129. // Don't bother updating the list to match INADDR_ANY, we know that
  5130. // will never match anything.
  5131. //
  5132. if (psaddrinMatch->sin_addr.S_un.S_addr == INADDR_ANY)
  5133. {
  5134. DPFX(DPFPREP, 7, "Couldn't find matching device for INADDR_ANY, as expected.");
  5135. break;
  5136. }
  5137. DPFX(DPFPREP, 7, "Couldn't find matching device for %u.%u.%u.%u, updating device list and searching again.",
  5138. psaddrinMatch->sin_addr.S_un.S_un_b.s_b1,
  5139. psaddrinMatch->sin_addr.S_un.S_un_b.s_b2,
  5140. psaddrinMatch->sin_addr.S_un.S_un_b.s_b3,
  5141. psaddrinMatch->sin_addr.S_un.S_un_b.s_b4);
  5142. hr = this->CheckForNewDevices(&fUpdatedDeviceList);
  5143. if (hr != DPNH_OK)
  5144. {
  5145. DPFX(DPFPREP, 0, "Couldn't check for new devices (0x%lx), continuing.",
  5146. hr);
  5147. //
  5148. // Hmm, we have to treat it as non-fatal. Don't search again,
  5149. // though.
  5150. //
  5151. break;
  5152. }
  5153. //
  5154. // If we didn't actually get any new devices, don't bother searching
  5155. // again.
  5156. //
  5157. if (! fUpdatedDeviceList)
  5158. {
  5159. break;
  5160. }
  5161. //
  5162. // fUpdatedDeviceList is set to TRUE so we'll only loop one more time.
  5163. //
  5164. }
  5165. while (TRUE);
  5166. //
  5167. // If we got here, there's still no matching device. If it's the wildcard
  5168. // value, that's to be expected, but we need to pick a device in the
  5169. // following order:
  5170. // 1. device has an Internet gateway
  5171. // 2. device has a firewall
  5172. // If none of those exists or it's not the wildcard value, we have to give
  5173. // up.
  5174. //
  5175. if (psaddrinMatch->sin_addr.S_un.S_addr == INADDR_ANY)
  5176. {
  5177. if (pDeviceRemoteICSServer != NULL)
  5178. {
  5179. pDevice = pDeviceRemoteICSServer;
  5180. DPFX(DPFPREP, 1, "Picking device 0x%p with remote ICS server to match INADDR_ANY.",
  5181. pDevice);
  5182. }
  5183. else if (pDeviceLocalICSServer != NULL)
  5184. {
  5185. pDevice = pDeviceLocalICSServer;
  5186. DPFX(DPFPREP, 1, "Picking device 0x%p with local ICS server to match INADDR_ANY.",
  5187. pDevice);
  5188. }
  5189. else if (pDeviceLocalPFWOnlyServer != NULL)
  5190. {
  5191. pDevice = pDeviceLocalPFWOnlyServer;
  5192. DPFX(DPFPREP, 1, "Picking device 0x%p with local PFW-only server to match INADDR_ANY.",
  5193. pDevice);
  5194. }
  5195. else
  5196. {
  5197. pDevice = NULL;
  5198. DPFX(DPFPREP, 1, "No suitable device to match INADDR_ANY.");
  5199. }
  5200. }
  5201. else
  5202. {
  5203. pDevice = NULL;
  5204. DPFX(DPFPREP, 7, "No devices match address %u.%u.%u.%u.",
  5205. psaddrinMatch->sin_addr.S_un.S_un_b.s_b1,
  5206. psaddrinMatch->sin_addr.S_un.S_un_b.s_b2,
  5207. psaddrinMatch->sin_addr.S_un.S_un_b.s_b3,
  5208. psaddrinMatch->sin_addr.S_un.S_un_b.s_b4);
  5209. }
  5210. Exit:
  5211. return pDevice;
  5212. } // CNATHelpPAST::FindMatchingDevice
  5213. #undef DPF_MODNAME
  5214. #define DPF_MODNAME "CNATHelpPAST::RegisterWithLocalPASTServer"
  5215. //=============================================================================
  5216. // CNATHelpPAST::RegisterWithLocalPASTServer
  5217. //-----------------------------------------------------------------------------
  5218. //
  5219. // Description: Attempts to register with a local PAST server.
  5220. //
  5221. // The object lock is assumed to be held.
  5222. //
  5223. // Arguments:
  5224. // CDevice * pDevice - Device to use when registering.
  5225. //
  5226. // Returns: HRESULT
  5227. // DPNH_OK - The registration attempt completed
  5228. // without error.
  5229. // DPNHERR_SERVERNOTRESPONDING - No server responded to the registration
  5230. // attempt.
  5231. // DPNHERR_GENERIC - An error occurred.
  5232. //=============================================================================
  5233. HRESULT CNATHelpPAST::RegisterWithLocalPASTServer(CDevice * const pDevice)
  5234. {
  5235. HRESULT hr;
  5236. SOCKADDR_IN saddrinServerAddress;
  5237. DWORD dwMsgID;
  5238. PAST_MSG_REGISTER RegisterReq;
  5239. PAST_RESPONSE_INFO RespInfo;
  5240. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p)", this, pDevice);
  5241. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  5242. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  5243. //
  5244. // Create a SOCKADDR to address the PAST service.
  5245. //
  5246. // Also initialize the message sequencing. Each message response pair is
  5247. // numbered sequentially to allow differentiation from retries over UDP.
  5248. //
  5249. // And finally, reset the current retry timeout (even though it doesn't
  5250. // affect this special case Register message).
  5251. //
  5252. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  5253. saddrinServerAddress.sin_family = AF_INET;
  5254. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  5255. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  5256. DNASSERT(pDevice->GetPASTClientID(FALSE) == 0);
  5257. pDevice->ResetLocalPASTMsgIDAndRetryTimeout(DEFAULT_INITIAL_PAST_RETRY_TIMEOUT);
  5258. dwMsgID = pDevice->GetNextLocalPASTMsgID();
  5259. DNASSERT(dwMsgID == 0);
  5260. //
  5261. // Remember the current time, if this is the first thing we've sent from
  5262. // this port.
  5263. //
  5264. if (pDevice->GetFirstPASTDiscoveryTime() == 0)
  5265. {
  5266. pDevice->SetFirstPASTDiscoveryTime(GETTIMESTAMP());
  5267. }
  5268. //
  5269. // Build the request message.
  5270. //
  5271. ZeroMemory(&RegisterReq, sizeof(RegisterReq));
  5272. RegisterReq.version = PAST_VERSION;
  5273. RegisterReq.command = PAST_MSGID_REGISTER_REQUEST;
  5274. RegisterReq.msgid.code = PAST_PARAMID_MESSAGEID;
  5275. RegisterReq.msgid.len = sizeof(RegisterReq.msgid) - sizeof(PAST_PARAM);
  5276. RegisterReq.msgid.msgid = dwMsgID;
  5277. //
  5278. // Send the message and get the reply.
  5279. //
  5280. hr = this->ExchangeAndParsePAST(pDevice->GetPASTSocket(),
  5281. (SOCKADDR*) (&saddrinServerAddress),
  5282. sizeof(saddrinServerAddress),
  5283. (char *) &RegisterReq,
  5284. sizeof(RegisterReq),
  5285. dwMsgID,
  5286. NULL,
  5287. &RespInfo);
  5288. if (hr != DPNH_OK)
  5289. {
  5290. //
  5291. // If exchanging the registration attempt failed, see if it was because
  5292. // the server wasn't responding.
  5293. //
  5294. if (hr != DPNHERR_SERVERNOTRESPONDING)
  5295. {
  5296. DPFX(DPFPREP, 0, "Registering with a PAST server failed!");
  5297. goto Failure;
  5298. }
  5299. //
  5300. // Server non-existence is considered non-fatal, but it still means
  5301. // we're done here.
  5302. //
  5303. DPFX(DPFPREP, 1, "No PAST server responded, registration was not successful.");
  5304. goto Exit;
  5305. }
  5306. if (RespInfo.cMsgType != PAST_MSGID_REGISTER_RESPONSE)
  5307. {
  5308. DPFX(DPFPREP, 0, "Unexpected response type %u, failing registration!", RespInfo.cMsgType);
  5309. hr = DPNHERR_GENERIC;
  5310. goto Failure;
  5311. }
  5312. //
  5313. // If we got here, then we successfully registered with a server.
  5314. //
  5315. pDevice->SetPASTClientID(RespInfo.dwClientID, FALSE);
  5316. Exit:
  5317. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  5318. return hr;
  5319. Failure:
  5320. goto Exit;
  5321. } // CNATHelpPAST::RegisterWithLocalPASTServer
  5322. #undef DPF_MODNAME
  5323. #define DPF_MODNAME "CNATHelpPAST::DeregisterWithPASTServer"
  5324. //=============================================================================
  5325. // CNATHelpPAST::DeregisterWithPASTServer
  5326. //-----------------------------------------------------------------------------
  5327. //
  5328. // Description: Attempts to deregister with the PAST server (local or
  5329. // remote, as determined by fRemote).
  5330. //
  5331. // All port assignments are implicitly freed.
  5332. //
  5333. // The object lock is assumed to be held.
  5334. //
  5335. // Arguments:
  5336. // CDevice * pDevice - Device to use when deregistering.
  5337. // BOOL fRemote - TRUE if should attempt to deregister with remote
  5338. // server, FALSE if deregistering with local server.
  5339. //
  5340. // Returns: HRESULT
  5341. // DPNH_OK - The deregistration completed successfully.
  5342. // DPNHERR_GENERIC - An error occurred.
  5343. //=============================================================================
  5344. HRESULT CNATHelpPAST::DeregisterWithPASTServer(CDevice * const pDevice,
  5345. const BOOL fRemote)
  5346. {
  5347. HRESULT hr = DPNH_OK;
  5348. SOCKADDR_IN saddrinServerAddress;
  5349. DWORD dwClientID;
  5350. DWORD dwMsgID;
  5351. DWORD * ptuRetry;
  5352. PAST_MSG_DEREGISTER_REQUEST DeregisterReq;
  5353. PAST_RESPONSE_INFO RespInfo;
  5354. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)", this, pDevice, fRemote);
  5355. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  5356. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  5357. //
  5358. // Create a SOCKADDR to address the PAST service, and get the appropriate
  5359. // client ID, initial retry timeout, and next message ID to use.
  5360. //
  5361. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  5362. saddrinServerAddress.sin_family = AF_INET;
  5363. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  5364. if (fRemote)
  5365. {
  5366. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  5367. dwMsgID = pDevice->GetNextRemotePASTMsgID();
  5368. ptuRetry = pDevice->GetRemotePASTRetryTimeoutPtr();
  5369. }
  5370. else
  5371. {
  5372. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  5373. dwMsgID = pDevice->GetNextLocalPASTMsgID();
  5374. ptuRetry = pDevice->GetLocalPASTRetryTimeoutPtr();
  5375. }
  5376. dwClientID = pDevice->GetPASTClientID(fRemote);
  5377. DNASSERT(dwClientID != 0);
  5378. //
  5379. // Build the request message.
  5380. //
  5381. ZeroMemory(&DeregisterReq, sizeof(DeregisterReq));
  5382. DeregisterReq.version = PAST_VERSION;
  5383. DeregisterReq.command = PAST_MSGID_DEREGISTER_REQUEST;
  5384. DeregisterReq.clientid.code = PAST_PARAMID_CLIENTID;
  5385. DeregisterReq.clientid.len = sizeof(DeregisterReq.clientid) - sizeof(PAST_PARAM);
  5386. DeregisterReq.clientid.clientid = dwClientID;
  5387. DeregisterReq.msgid.code = PAST_PARAMID_MESSAGEID;
  5388. DeregisterReq.msgid.len = sizeof(DeregisterReq.msgid) - sizeof(PAST_PARAM);
  5389. DeregisterReq.msgid.msgid = dwMsgID;
  5390. //
  5391. // Send the message and get the reply.
  5392. //
  5393. hr = this->ExchangeAndParsePAST(pDevice->GetPASTSocket(),
  5394. (SOCKADDR*) (&saddrinServerAddress),
  5395. sizeof(saddrinServerAddress),
  5396. (char *) &DeregisterReq,
  5397. sizeof(DeregisterReq),
  5398. dwMsgID,
  5399. ptuRetry,
  5400. &RespInfo);
  5401. if (hr != DPNH_OK)
  5402. {
  5403. if (hr != DPNHERR_SERVERNOTRESPONDING)
  5404. {
  5405. DPFX(DPFPREP, 0, "De-registering with server failed!");
  5406. goto Failure;
  5407. }
  5408. //
  5409. // Server stopped responding, but who cares, we were de-registering
  5410. // anyway.
  5411. //
  5412. DPFX(DPFPREP, 1, "Server stopped responding while de-registering! Ignoring.");
  5413. hr = DPNH_OK;
  5414. }
  5415. else
  5416. {
  5417. if (RespInfo.cMsgType != PAST_MSGID_DEREGISTER_RESPONSE)
  5418. {
  5419. DPFX(DPFPREP, 0, "Got unexpected response type %u, failed de-registering!", RespInfo.cMsgType);
  5420. hr = DPNHERR_GENERIC;
  5421. goto Failure;
  5422. }
  5423. }
  5424. pDevice->SetPASTClientID(0, fRemote);
  5425. Exit:
  5426. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  5427. return hr;
  5428. Failure:
  5429. goto Exit;
  5430. } // CNATHelpPAST::DeregisterWithPASTServer
  5431. #undef DPF_MODNAME
  5432. #define DPF_MODNAME "CNATHelpPAST::ExtendAllExpiringLeases"
  5433. //=============================================================================
  5434. // CNATHelpPAST::ExtendAllExpiringLeases
  5435. //-----------------------------------------------------------------------------
  5436. //
  5437. // Description: Renews any port leases that are close to expiring (within 2
  5438. // minutes of expiration time).
  5439. //
  5440. // The object lock is assumed to be held.
  5441. //
  5442. // Arguments: None.
  5443. //
  5444. // Returns: HRESULT
  5445. // DPNH_OK - Lease extension was successful.
  5446. // DPNHERR_GENERIC - An error occurred.
  5447. //=============================================================================
  5448. HRESULT CNATHelpPAST::ExtendAllExpiringLeases(void)
  5449. {
  5450. HRESULT hr = DPNH_OK;
  5451. CBilink * pBilink;
  5452. CRegisteredPort * pRegisteredPort;
  5453. CDevice * pDevice;
  5454. DWORD dwLeaseTimeRemaining;
  5455. DPFX(DPFPREP, 5, "Enter");
  5456. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  5457. //
  5458. // Walk the list of all registered ports and check for leases that need to
  5459. // be extended.
  5460. // The lock is already held.
  5461. //
  5462. pBilink = this->m_blRegisteredPorts.GetNext();
  5463. while (pBilink != (&this->m_blRegisteredPorts))
  5464. {
  5465. pRegisteredPort = REGPORT_FROM_GLOBAL_BILINK(pBilink);
  5466. pDevice = pRegisteredPort->GetOwningDevice();
  5467. //
  5468. // If the port is registered remotely, extend that lease, if necessary.
  5469. //
  5470. if (pRegisteredPort->GetPASTBindID(TRUE) != 0)
  5471. {
  5472. DNASSERT(pDevice != NULL);
  5473. dwLeaseTimeRemaining = pRegisteredPort->GetPASTLeaseExpiration(TRUE) - timeGetTime();
  5474. if (dwLeaseTimeRemaining < LEASE_RENEW_TIME)
  5475. {
  5476. hr = this->ExtendPASTLease(pRegisteredPort, TRUE);
  5477. if (hr != DPNH_OK)
  5478. {
  5479. DPFX(DPFPREP, 0, "Couldn't extend port mapping lease on remote PAST server (0x%lx)! Ignoring.", hr);
  5480. //
  5481. // We'll treat this as non-fatal, but we have to dump the server.
  5482. //
  5483. this->ClearDevicesPASTServer(pDevice, TRUE);
  5484. hr = DPNH_OK;
  5485. }
  5486. }
  5487. }
  5488. //
  5489. // If the port is registered locally, extend that lease, if necessary.
  5490. //
  5491. if (pRegisteredPort->GetPASTBindID(FALSE) != 0)
  5492. {
  5493. DNASSERT(pDevice != NULL);
  5494. dwLeaseTimeRemaining = pRegisteredPort->GetPASTLeaseExpiration(FALSE) - timeGetTime();
  5495. if (dwLeaseTimeRemaining < LEASE_RENEW_TIME)
  5496. {
  5497. hr = this->ExtendPASTLease(pRegisteredPort, FALSE);
  5498. if (hr != DPNH_OK)
  5499. {
  5500. DPFX(DPFPREP, 0, "Couldn't extend port mapping lease on local PAST server (0x%lx)! Ignoring.", hr);
  5501. //
  5502. // We'll treat this as non-fatal, but we have to dump the server.
  5503. //
  5504. this->ClearDevicesPASTServer(pDevice, FALSE);
  5505. hr = DPNH_OK;
  5506. }
  5507. }
  5508. }
  5509. pBilink = pBilink->GetNext();
  5510. }
  5511. DNASSERT(hr == DPNH_OK);
  5512. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  5513. return hr;
  5514. } // CNATHelpPAST::ExtendAllExpiringLeases
  5515. #undef DPF_MODNAME
  5516. #define DPF_MODNAME "CNATHelpPAST::UpdateServerStatus"
  5517. //=============================================================================
  5518. // CNATHelpPAST::UpdateServerStatus
  5519. //-----------------------------------------------------------------------------
  5520. //
  5521. // Description: Checks to see if any Internet gateways have stopped
  5522. // responding or are now available.
  5523. //
  5524. // The object lock is assumed to be held.
  5525. //
  5526. // Arguments: None.
  5527. //
  5528. // Returns: HRESULT
  5529. // DPNH_OK - The update was successful.
  5530. // DPNHERR_GENERIC - An error occurred.
  5531. //=============================================================================
  5532. HRESULT CNATHelpPAST::UpdateServerStatus(void)
  5533. {
  5534. HRESULT hr = DPNH_OK;
  5535. CBilink blNoRemotePASTList;
  5536. DWORD dwMinUpdateServerStatusInterval;
  5537. DWORD dwCurrentTime;
  5538. CBilink * pBilink;
  5539. CDevice * pDevice;
  5540. CDevice * pDeviceRemoteICSServer = NULL;
  5541. CDevice * pDeviceLocalICSServer = NULL;
  5542. CDevice * pDeviceLocalPFWOnlyServer = NULL;
  5543. BOOL fSendRemoteGatewayDiscovery;
  5544. DPFX(DPFPREP, 5, "Enter");
  5545. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  5546. blNoRemotePASTList.Initialize();
  5547. //
  5548. // Cache the current value of the global. This should be atomic so no need
  5549. // to take the globals lock.
  5550. //
  5551. dwMinUpdateServerStatusInterval = g_dwMinUpdateServerStatusInterval;
  5552. //
  5553. // Capture the current time.
  5554. //
  5555. dwCurrentTime = timeGetTime();
  5556. //
  5557. // If this isn't the first time to update server status, but it hasn't been
  5558. // very long since we last checked, don't. This will prevent unnecessary
  5559. // network traffic if GetCaps is called frequently (in response to many
  5560. // alert events, for example).
  5561. //
  5562. // However, if we just found a new device, update the status anyway.
  5563. //
  5564. //
  5565. if (this->m_dwLastUpdateServerStatusTime != 0)
  5566. {
  5567. if ((dwCurrentTime - this->m_dwLastUpdateServerStatusTime) < dwMinUpdateServerStatusInterval)
  5568. {
  5569. if (! (this->m_dwFlags & NATHELPPASTOBJ_DEVICECHANGED))
  5570. {
  5571. DPFX(DPFPREP, 5, "Server status was just updated at %u, not updating again (time = %u, min interval = %u).",
  5572. this->m_dwLastUpdateServerStatusTime,
  5573. dwCurrentTime,
  5574. dwMinUpdateServerStatusInterval);
  5575. //
  5576. // hr == DPNH_OK
  5577. //
  5578. goto Exit;
  5579. }
  5580. DPFX(DPFPREP, 5, "Server status was just updated at %u (time = %u, min interval = %u), but there was a device change that may affect things.",
  5581. this->m_dwLastUpdateServerStatusTime,
  5582. dwCurrentTime,
  5583. dwMinUpdateServerStatusInterval);
  5584. //
  5585. // Continue...
  5586. //
  5587. }
  5588. //
  5589. // If we're allowed to keep polling for remote gateways after startup,
  5590. // do so. Otherwise, only do it if a device has changed or a port has
  5591. // been registered since our last check.
  5592. //
  5593. if ((g_fKeepPollingForRemoteGateway) ||
  5594. (this->m_dwFlags & NATHELPPASTOBJ_DEVICECHANGED) ||
  5595. (this->m_dwFlags & NATHELPPASTOBJ_PORTREGISTERED))
  5596. {
  5597. fSendRemoteGatewayDiscovery = TRUE;
  5598. }
  5599. else
  5600. {
  5601. fSendRemoteGatewayDiscovery = FALSE;
  5602. }
  5603. }
  5604. else
  5605. {
  5606. //
  5607. // We always poll for new remote gateways during startup.
  5608. //
  5609. fSendRemoteGatewayDiscovery = TRUE;
  5610. }
  5611. //
  5612. // Prevent the timer from landing exactly on 0.
  5613. //
  5614. if (dwCurrentTime == 0)
  5615. {
  5616. dwCurrentTime = 1;
  5617. }
  5618. this->m_dwLastUpdateServerStatusTime = dwCurrentTime;
  5619. //
  5620. // Turn off the 'device changed' and 'port registered' flags, if they were
  5621. // on.
  5622. //
  5623. this->m_dwFlags &= ~(NATHELPPASTOBJ_DEVICECHANGED | NATHELPPASTOBJ_PORTREGISTERED);
  5624. //
  5625. // Loop through all the devices.
  5626. //
  5627. pBilink = this->m_blDevices.GetNext();
  5628. while (pBilink != &this->m_blDevices)
  5629. {
  5630. pDevice = DEVICE_FROM_BILINK(pBilink);
  5631. //
  5632. // This might be a new device, so register any ports with this address
  5633. // that were previously unowned (because this device's address was
  5634. // unknown at the time).
  5635. //
  5636. hr = this->RegisterPreviouslyUnownedPortsWithDevice(pDevice, FALSE);
  5637. if (hr != DPNH_OK)
  5638. {
  5639. DPFX(DPFPREP, 0, "Couldn't register previously unowned ports with device 0x%p!.",
  5640. pDevice);
  5641. goto Failure;
  5642. }
  5643. if (pDevice->GetPASTClientID(FALSE) == 0)
  5644. {
  5645. //
  5646. // The device did not previously have a local PAST server. See if
  5647. // one came online.
  5648. //
  5649. DNASSERT((pDevice->GetPASTCachedMaps(FALSE))->IsEmpty());
  5650. hr = this->CheckForLocalPASTServerAndRegister(pDevice);
  5651. if (hr != DPNH_OK)
  5652. {
  5653. DPFX(DPFPREP, 0, "Couldn't check for local PAST server (and register with it) on device 0x%p!",
  5654. pDevice);
  5655. goto Failure;
  5656. }
  5657. if (pDevice->GetPASTClientID(FALSE) != 0)
  5658. {
  5659. //
  5660. // Wow, a local PAST server is now available.
  5661. //
  5662. //
  5663. // Remember the device if it has the first local ICS or PFW
  5664. // PAST server we've seen.
  5665. //
  5666. if ((pDevice->HasLocalICSPASTServer()) &&
  5667. (pDeviceLocalICSServer == NULL))
  5668. {
  5669. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_USEPASTICS);
  5670. pDeviceLocalICSServer = pDevice;
  5671. }
  5672. else if ((pDevice->HasLocalPFWOnlyPASTServer()) &&
  5673. (pDeviceLocalPFWOnlyServer == NULL))
  5674. {
  5675. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_USEPASTPFW);
  5676. pDeviceLocalPFWOnlyServer = pDevice;
  5677. }
  5678. //
  5679. // We don't need to register all the existing mappings
  5680. // associated with the device that the user has already
  5681. // requested. CheckForLocalPASTServerAndRegister took care of
  5682. // that for us.
  5683. //
  5684. }
  5685. else
  5686. {
  5687. DPFX(DPFPREP, 7, "Still no local PAST server on device 0x%p.",
  5688. pDevice);
  5689. }
  5690. }
  5691. else
  5692. {
  5693. //
  5694. // The device previously had a local PAST server.
  5695. //
  5696. //
  5697. // Make sure the server is still alive and see whether it's handing
  5698. // out valid public addresses or not.
  5699. //
  5700. hr = this->UpdatePASTPublicAddressValidity(pDevice, FALSE);
  5701. if (hr != DPNH_OK)
  5702. {
  5703. DPFX(DPFPREP, 0, "Couldn't update local PAST server public address validity on device 0x%p!",
  5704. pDevice);
  5705. goto Failure;
  5706. }
  5707. //
  5708. // If there's still a PAST server, remember the device if it's the
  5709. // first local ICS or PFW PAST server we've seen.
  5710. //
  5711. if (pDevice->GetPASTClientID(FALSE) != 0)
  5712. {
  5713. if ((pDevice->HasLocalICSPASTServer()) &&
  5714. (pDeviceLocalICSServer == NULL))
  5715. {
  5716. pDeviceLocalICSServer = pDevice;
  5717. }
  5718. else if ((pDevice->HasLocalPFWOnlyPASTServer()) &&
  5719. (pDeviceLocalPFWOnlyServer == NULL))
  5720. {
  5721. pDeviceLocalPFWOnlyServer = pDevice;
  5722. }
  5723. }
  5724. }
  5725. if (this->m_dwFlags & NATHELPPASTOBJ_USEPASTICS)
  5726. {
  5727. if (pDevice->GetPASTClientID(TRUE) == 0)
  5728. {
  5729. //
  5730. // The device did not previously have a remote PAST server.
  5731. // Remember it so we can check if one came online below,
  5732. // unless we're not allowed to perform remote gateway
  5733. // discovery.
  5734. //
  5735. DNASSERT((pDevice->GetPASTCachedMaps(TRUE))->IsEmpty());
  5736. if (fSendRemoteGatewayDiscovery)
  5737. {
  5738. pDevice->m_blTempList.InsertBefore(&blNoRemotePASTList);
  5739. }
  5740. }
  5741. else
  5742. {
  5743. //
  5744. // The device previously had a remote PAST server.
  5745. //
  5746. //
  5747. // Make sure the server is still alive and see whether it's
  5748. // handing out valid public addresses or not.
  5749. //
  5750. hr = this->UpdatePASTPublicAddressValidity(pDevice, TRUE);
  5751. if (hr != DPNH_OK)
  5752. {
  5753. DPFX(DPFPREP, 0, "Couldn't update remote PAST server public address validity on device 0x%p!",
  5754. pDevice);
  5755. goto Failure;
  5756. }
  5757. //
  5758. // If there's still a PAST server, remember the device if it's
  5759. // the first remote PAST server we've seen.
  5760. //
  5761. if ((pDevice->GetPASTClientID(TRUE) != 0) &&
  5762. (pDeviceRemoteICSServer == NULL))
  5763. {
  5764. pDeviceRemoteICSServer = pDevice;
  5765. }
  5766. }
  5767. }
  5768. else
  5769. {
  5770. //
  5771. // Not using PAST for ICS NAT traversal.
  5772. //
  5773. }
  5774. pBilink = pBilink->GetNext();
  5775. }
  5776. //
  5777. // Update any devices that don't currently have remote PAST servers.
  5778. //
  5779. if (! blNoRemotePASTList.IsEmpty())
  5780. {
  5781. DNASSERT(fSendRemoteGatewayDiscovery);
  5782. hr = this->RegisterMultipleDevicesWithRemotePAST(&blNoRemotePASTList,
  5783. &pDeviceRemoteICSServer);
  5784. if (hr != S_OK)
  5785. {
  5786. DPFX(DPFPREP, 0, "Couldn't register multiple devices with remote PAST servers!");
  5787. goto Failure;
  5788. }
  5789. }
  5790. //
  5791. // Some new servers may have come online. If so, we can now map wildcard
  5792. // ports that were registered previously. Figure out which device that is.
  5793. //
  5794. if (pDeviceRemoteICSServer != NULL)
  5795. {
  5796. pDevice = pDeviceRemoteICSServer;
  5797. }
  5798. else if (pDeviceLocalICSServer != NULL)
  5799. {
  5800. pDevice = pDeviceLocalICSServer;
  5801. }
  5802. else if (pDeviceLocalPFWOnlyServer != NULL)
  5803. {
  5804. pDevice = pDeviceLocalPFWOnlyServer;
  5805. }
  5806. else
  5807. {
  5808. pDevice = NULL;
  5809. }
  5810. if (pDevice != NULL)
  5811. {
  5812. //
  5813. // Register any wildcard ports that are unowned with this best device.
  5814. //
  5815. hr = this->RegisterPreviouslyUnownedPortsWithDevice(pDevice, TRUE);
  5816. if (hr != DPNH_OK)
  5817. {
  5818. DPFX(DPFPREP, 0, "Couldn't register unowned wildcard ports with device 0x%p!.",
  5819. pDevice);
  5820. goto Failure;
  5821. }
  5822. }
  5823. #ifdef DBG
  5824. else
  5825. {
  5826. DPFX(DPFPREP, 7, "No devices have a remote or local PAST server.");
  5827. }
  5828. #endif // DBG
  5829. DPFX(DPFPREP, 7, "Spent %u ms updating server status, starting at %u.",
  5830. (timeGetTime() - dwCurrentTime), dwCurrentTime);
  5831. Exit:
  5832. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  5833. return hr;
  5834. Failure:
  5835. //
  5836. // Remove any items still in the temp list.
  5837. //
  5838. pBilink = blNoRemotePASTList.GetNext();
  5839. while (pBilink != &blNoRemotePASTList)
  5840. {
  5841. pDevice = DEVICE_FROM_TEMP_BILINK(pBilink);
  5842. pBilink = pBilink->GetNext();
  5843. pDevice->m_blTempList.RemoveFromList();
  5844. }
  5845. goto Exit;
  5846. } // CNATHelpPAST::UpdateServerStatus
  5847. #undef DPF_MODNAME
  5848. #define DPF_MODNAME "CNATHelpPAST::AssignOrListenPASTPort"
  5849. //=============================================================================
  5850. // CNATHelpPAST::AssignOrListenPASTPort
  5851. //-----------------------------------------------------------------------------
  5852. //
  5853. // Description: Attempts to assign a port mapping with the PAST server.
  5854. // This may detect a change in server address.
  5855. //
  5856. // The object lock is assumed to be held.
  5857. //
  5858. // Arguments:
  5859. // CRegisteredPort * pRegisteredPort - Pointer to port object mapping to
  5860. // assign.
  5861. // BOOL fRemote - TRUE if should assign with remote
  5862. // server, FALSE if assign with local
  5863. // server.
  5864. //
  5865. // Returns: HRESULT
  5866. // DPNH_OK - The assignment was successful.
  5867. // DPNHERR_GENERIC - An error occurred.
  5868. // DPNHERR_PORTUNAVAILABLE - The server could not bind one of the
  5869. // ports.
  5870. // DPNHERR_SERVERNOTRESPONDING - The server did not respond to the
  5871. // message.
  5872. //=============================================================================
  5873. HRESULT CNATHelpPAST::AssignOrListenPASTPort(CRegisteredPort * const pRegisteredPort,
  5874. const BOOL fRemote)
  5875. {
  5876. HRESULT hr = DPNH_OK;
  5877. CDevice * pDevice;
  5878. SOCKADDR_IN saddrinServerAddress;
  5879. DWORD dwClientID;
  5880. DWORD dwMsgID;
  5881. DWORD * ptuRetry;
  5882. BOOL fListenRequest;
  5883. BOOL fSharedUDPListener;
  5884. CHAR cNumPorts;
  5885. DWORD dwLeaseTimeInSecs;
  5886. SOCKADDR_IN * pasaddrinAddressesToAssign;
  5887. DWORD dwMsgSize;
  5888. PVOID pvRequest = NULL;
  5889. PBYTE pbCurrent;
  5890. CHAR cTemp;
  5891. PAST_RESPONSE_INFO RespInfo;
  5892. CBilink * pBilink;
  5893. CRegisteredPort * pTempRegisteredPort;
  5894. BOOL fResult;
  5895. BOOL fFirstLease;
  5896. HRESULT temphr;
  5897. #ifdef DBG
  5898. DWORD dwError;
  5899. #endif // DBG
  5900. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)",
  5901. this, pRegisteredPort, fRemote);
  5902. DNASSERT(pRegisteredPort != NULL);
  5903. pDevice = pRegisteredPort->GetOwningDevice();
  5904. DNASSERT(pDevice != NULL);
  5905. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  5906. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  5907. //
  5908. // Create a SOCKADDR to address the PAST service, and get the appropriate
  5909. // client ID, initial retry timeout, and next message ID to use.
  5910. //
  5911. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  5912. saddrinServerAddress.sin_family = AF_INET;
  5913. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  5914. if (fRemote)
  5915. {
  5916. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  5917. dwMsgID = pDevice->GetNextRemotePASTMsgID();
  5918. ptuRetry = pDevice->GetRemotePASTRetryTimeoutPtr();
  5919. }
  5920. else
  5921. {
  5922. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  5923. dwMsgID = pDevice->GetNextLocalPASTMsgID();
  5924. ptuRetry = pDevice->GetLocalPASTRetryTimeoutPtr();
  5925. }
  5926. dwClientID = pDevice->GetPASTClientID(fRemote);
  5927. DNASSERT(dwClientID != 0);
  5928. fListenRequest = pRegisteredPort->IsFixedPort();
  5929. fSharedUDPListener = pRegisteredPort->IsSharedPort();
  5930. pasaddrinAddressesToAssign = pRegisteredPort->GetPrivateAddressesArray();
  5931. cNumPorts = (CHAR) pRegisteredPort->GetNumAddresses(); // the possible loss of data is okay, capped at DPNH_MAX_SIMULTANEOUS_PORTS anyway
  5932. DNASSERT(cNumPorts > 0);
  5933. dwLeaseTimeInSecs = pRegisteredPort->GetRequestedLeaseTime() / 1000;
  5934. //
  5935. // If this is a remote attempt and it was already mapped with a local
  5936. // Personal Firewall PAST server, be sure to use those addresses. The
  5937. // PFW PAST server will give different port values, and if there's a NAT
  5938. // upstream we need to map the ports that are actually reachable
  5939. // externally. Yes, you could consider it user error to have a firewall
  5940. // enabled when you're behind a NAT: why wouldn't they just enable firewall
  5941. // behavior on the NAT? However, we'll support that.
  5942. //
  5943. if ((fRemote) &&
  5944. (pDevice->HasLocalPFWOnlyPASTServer()) &&
  5945. (pDevice->IsPASTPublicAddressAvailable(FALSE)) &&
  5946. (! pRegisteredPort->IsPASTPortUnavailable(FALSE)))
  5947. {
  5948. DNASSERT(pDevice->GetPASTClientID(FALSE) != 0);
  5949. DNASSERT(pRegisteredPort->GetPASTBindID(FALSE) != 0);
  5950. DPFX(DPFPREP, 2, "Using public addresses previously returned by local Personal Firewall-only PAST server.");
  5951. pasaddrinAddressesToAssign = pRegisteredPort->GetPASTPublicAddressesArray(FALSE);
  5952. }
  5953. DNASSERT(pasaddrinAddressesToAssign != NULL);
  5954. DPFX(DPFPREP, 7, "Sending %s%sfor %u ports (first = %u.%u.%u.%u:%u), requesting %u second lease.",
  5955. ((fListenRequest) ? _T("LISTEN_REQUEST") : _T("ASSIGN_REQUEST_RSAP_IP")),
  5956. ((fSharedUDPListener) ? _T(" (with SHARED UDP LISTENER vendor code) ") : _T(" ")),
  5957. cNumPorts,
  5958. pasaddrinAddressesToAssign[0].sin_addr.S_un.S_un_b.s_b1,
  5959. pasaddrinAddressesToAssign[0].sin_addr.S_un.S_un_b.s_b2,
  5960. pasaddrinAddressesToAssign[0].sin_addr.S_un.S_un_b.s_b3,
  5961. pasaddrinAddressesToAssign[0].sin_addr.S_un.S_un_b.s_b4,
  5962. NTOHS(pasaddrinAddressesToAssign[0].sin_port),
  5963. dwLeaseTimeInSecs);
  5964. //
  5965. // Build the request message. We take advantage of the fact that both the
  5966. // ASSIGN_REQUEST, LISTEN_REQUEST, and SHAREDLISTEN_REQUEST messages look
  5967. // almost identical, except SHAREDLISTEN_REQUESTs have an extra vendor
  5968. // option.
  5969. //
  5970. dwMsgSize = (sizeof(PAST_MSG_ASSIGNORLISTEN_REQUEST) + ((cNumPorts - 1) * sizeof(WORD) * 2));
  5971. if (! fSharedUDPListener)
  5972. {
  5973. dwMsgSize -= sizeof(PAST_PARAM_MSVENDOR_CODE);
  5974. }
  5975. pvRequest = DNMalloc(dwMsgSize);
  5976. if (pvRequest == NULL)
  5977. {
  5978. hr = DPNHERR_OUTOFMEMORY;
  5979. goto Failure;
  5980. }
  5981. pbCurrent = (PBYTE) pvRequest;
  5982. (*pbCurrent++) = PAST_VERSION;
  5983. (*pbCurrent++) = (fListenRequest) ? PAST_MSGID_LISTEN_REQUEST : PAST_MSGID_ASSIGN_REQUEST_RSAP_IP;
  5984. ((PAST_PARAM_CLIENTID*) pbCurrent)->code = PAST_PARAMID_CLIENTID;
  5985. ((PAST_PARAM_CLIENTID*) pbCurrent)->len = sizeof(PAST_PARAM_CLIENTID) - sizeof(PAST_PARAM);
  5986. ((PAST_PARAM_CLIENTID*) pbCurrent)->clientid = dwClientID;
  5987. pbCurrent += sizeof (PAST_PARAM_CLIENTID);
  5988. //
  5989. // Local Address (will be returned by PAST server, use don't-care value).
  5990. //
  5991. ((PAST_PARAM_ADDRESS*) pbCurrent)->code = PAST_PARAMID_ADDRESS;
  5992. ((PAST_PARAM_ADDRESS*) pbCurrent)->len = sizeof(PAST_PARAM_ADDRESS) - sizeof(PAST_PARAM);
  5993. ((PAST_PARAM_ADDRESS*) pbCurrent)->version = PAST_ADDRESSTYPE_IPV4;
  5994. ((PAST_PARAM_ADDRESS*) pbCurrent)->addr = PAST_ANY_ADDRESS;
  5995. pbCurrent += sizeof (PAST_PARAM_ADDRESS);
  5996. //
  5997. // Local Port, this is the port the user has opened for which we are
  5998. // assigning a global alias.
  5999. //
  6000. // NOTE: Ports appeared to be transferred in x86 format, contrary to the
  6001. // spec, which says network byte order.
  6002. //
  6003. (*pbCurrent++) = PAST_PARAMID_PORTS;
  6004. *((WORD*) pbCurrent) = sizeof(CHAR) + (sizeof(WORD) * cNumPorts);
  6005. pbCurrent += 2;
  6006. (*pbCurrent++) = cNumPorts;
  6007. for(cTemp = 0; cTemp < cNumPorts; cTemp++)
  6008. {
  6009. *((WORD*) pbCurrent) = NTOHS(pasaddrinAddressesToAssign[cTemp].sin_port);
  6010. pbCurrent += 2;
  6011. }
  6012. //
  6013. // Remote Address (not used with our flow control policy and reserved for
  6014. // future use, use don't-care value)
  6015. //
  6016. ((PAST_PARAM_ADDRESS*) pbCurrent)->code = PAST_PARAMID_ADDRESS;
  6017. ((PAST_PARAM_ADDRESS*) pbCurrent)->len = sizeof(PAST_PARAM_ADDRESS) - sizeof(PAST_PARAM);
  6018. ((PAST_PARAM_ADDRESS*) pbCurrent)->version = PAST_ADDRESSTYPE_IPV4;
  6019. ((PAST_PARAM_ADDRESS*) pbCurrent)->addr = PAST_ANY_ADDRESS;
  6020. pbCurrent += sizeof (PAST_PARAM_ADDRESS);
  6021. (*pbCurrent++) = PAST_PARAMID_PORTS;
  6022. *((WORD*) pbCurrent) = sizeof(CHAR) + (sizeof(WORD) * cNumPorts);
  6023. pbCurrent += 2;
  6024. (*pbCurrent++) = cNumPorts;
  6025. //for(cTemp = 0; cTemp < cNumPorts; cTemp++)
  6026. //{
  6027. // *((WORD*) pbCurrent) = NTOHS(PAST_ANY_PORT);
  6028. // pbCurrent += 2;
  6029. //}
  6030. pbCurrent += cNumPorts * sizeof(WORD);
  6031. //
  6032. // The following parameters are optional according to PAST spec.
  6033. //
  6034. //
  6035. // Lease code, ask for what the user wants, but they shouldn't count on
  6036. // getting that.
  6037. //
  6038. ((PAST_PARAM_LEASE*) pbCurrent)->code = PAST_PARAMID_LEASE;
  6039. ((PAST_PARAM_LEASE*) pbCurrent)->len = sizeof(PAST_PARAM_LEASE) - sizeof(PAST_PARAM);
  6040. ((PAST_PARAM_LEASE*) pbCurrent)->leasetime = dwLeaseTimeInSecs;
  6041. pbCurrent += sizeof (PAST_PARAM_LEASE);
  6042. //
  6043. // Tunnel Type is IP-IP (PAST currently ignores it, actually).
  6044. //
  6045. ((PAST_PARAM_TUNNELTYPE*) pbCurrent)->code = PAST_PARAMID_TUNNELTYPE;
  6046. ((PAST_PARAM_TUNNELTYPE*) pbCurrent)->len = sizeof(PAST_PARAM_TUNNELTYPE) - sizeof(PAST_PARAM);
  6047. ((PAST_PARAM_TUNNELTYPE*) pbCurrent)->tunneltype = PAST_TUNNEL_IP_IP;
  6048. pbCurrent += sizeof (PAST_PARAM_TUNNELTYPE);
  6049. //
  6050. // Message ID is optional, but we use it since we use UDP for a transport
  6051. // it is required.
  6052. //
  6053. ((PAST_PARAM_MESSAGEID*) pbCurrent)->code = PAST_PARAMID_MESSAGEID;
  6054. ((PAST_PARAM_MESSAGEID*) pbCurrent)->len = sizeof(PAST_PARAM_MESSAGEID) - sizeof(PAST_PARAM);
  6055. ((PAST_PARAM_MESSAGEID*) pbCurrent)->msgid = dwMsgID;
  6056. pbCurrent += sizeof (PAST_PARAM_MESSAGEID);
  6057. //
  6058. // The following parameters are vendor specific options.
  6059. //
  6060. //
  6061. // Specify port type MS vendor option.
  6062. //
  6063. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->code = PAST_PARAMID_VENDOR;
  6064. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->len = sizeof(PAST_PARAM_MSVENDOR_CODE) - sizeof(PAST_PARAM);
  6065. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->vendorid = PAST_MS_VENDOR_ID;
  6066. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->option = (pRegisteredPort->IsTCP()) ? PAST_VC_MS_TCP_PORT : PAST_VC_MS_UDP_PORT;
  6067. pbCurrent += sizeof (PAST_PARAM_MSVENDOR_CODE);
  6068. //
  6069. // Specify no-tunneling MS vendor option.
  6070. //
  6071. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->code = PAST_PARAMID_VENDOR;
  6072. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->len = sizeof(PAST_PARAM_MSVENDOR_CODE) - sizeof(PAST_PARAM);
  6073. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->vendorid = PAST_MS_VENDOR_ID;
  6074. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->option = PAST_VC_MS_NO_TUNNEL;
  6075. pbCurrent += sizeof (PAST_PARAM_MSVENDOR_CODE);
  6076. //
  6077. // A shared UDP port listen type has an extra vendor option.
  6078. //
  6079. if (fSharedUDPListener)
  6080. {
  6081. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->code = PAST_PARAMID_VENDOR;
  6082. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->len = sizeof(PAST_PARAM_MSVENDOR_CODE) - sizeof(PAST_PARAM);
  6083. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->vendorid = PAST_MS_VENDOR_ID;
  6084. ((PAST_PARAM_MSVENDOR_CODE*) pbCurrent)->option = PAST_VC_MS_SHARED_UDP_LISTENER;
  6085. pbCurrent += sizeof (PAST_PARAM_MSVENDOR_CODE);
  6086. }
  6087. //
  6088. // Send the message and get the reply.
  6089. //
  6090. hr = this->ExchangeAndParsePAST(pDevice->GetPASTSocket(),
  6091. (SOCKADDR*) (&saddrinServerAddress),
  6092. sizeof(saddrinServerAddress),
  6093. (char *) pvRequest,
  6094. dwMsgSize,
  6095. dwMsgID,
  6096. ptuRetry,
  6097. &RespInfo);
  6098. if (hr != DPNH_OK)
  6099. {
  6100. DPFX(DPFPREP, 0, "Sending Assign/Listen Port request to server failed (err = 0x%lx)!", hr);
  6101. goto Failure;
  6102. }
  6103. if ((RespInfo.cMsgType == PAST_MSGID_ERROR_RESPONSE) &&
  6104. (RespInfo.wError == PASTERR_PORTUNAVAILABLE))
  6105. {
  6106. DPFX(DPFPREP, 1, "Couldn't assign/listen, port was unavailable.");
  6107. hr = DPNHERR_PORTUNAVAILABLE;
  6108. goto Failure;
  6109. }
  6110. if (((fListenRequest) && (RespInfo.cMsgType != PAST_MSGID_LISTEN_RESPONSE)) ||
  6111. ((! fListenRequest) && (RespInfo.cMsgType != PAST_MSGID_ASSIGN_RESPONSE_RSAP_IP)))
  6112. {
  6113. DPFX(DPFPREP, 0, "Got unexpected response type %u, failed assign/listen!", RespInfo.cMsgType);
  6114. hr = DPNHERR_GENERIC;
  6115. goto Failure;
  6116. }
  6117. //
  6118. // Make sure the port count is valid.
  6119. //
  6120. if (RespInfo.cNumLocalPorts != cNumPorts)
  6121. {
  6122. DPFX(DPFPREP, 0, "PAST server returned an invalid number of local ports with success message (%u != %u)! Assuming port unavailable.",
  6123. RespInfo.cNumLocalPorts, cNumPorts);
  6124. DNASSERTX(! "Why is PAST server returning bogus number of ports?", 2);
  6125. hr = DPNHERR_PORTUNAVAILABLE;
  6126. goto Failure;
  6127. }
  6128. //
  6129. // Store the public address for the registered port, even if it's the
  6130. // no-public-address address (0.0.0.0).
  6131. //
  6132. hr = pRegisteredPort->SetPASTPublicV4Addresses(RespInfo.dwLocalAddressV4,
  6133. RespInfo.awLocalPorts,
  6134. RespInfo.cNumLocalPorts,
  6135. fRemote);
  6136. if (hr != DPNH_OK)
  6137. {
  6138. DPFX(DPFPREP, 0, "Couldn't set requested mapping's public addresses!");
  6139. goto Failure;
  6140. }
  6141. //
  6142. // Remember the bind ID, actual lease time (convert back to milliseconds),
  6143. // and address we were given.
  6144. //
  6145. pRegisteredPort->SetPASTBindID(RespInfo.dwBindID, fRemote);
  6146. pRegisteredPort->SetPASTLeaseExpiration((timeGetTime() + (RespInfo.dwLeaseTime * 1000)),
  6147. fRemote);
  6148. //
  6149. // Note whether this was the first lease or not.
  6150. //
  6151. fFirstLease = (this->m_dwNumLeases == 0) ? TRUE : FALSE;
  6152. this->m_dwNumLeases++;
  6153. DPFX(DPFPREP, 7, "%s PAST lease for 0x%p added, total num leases = %u.",
  6154. ((fRemote) ? _T("Remote") : _T("Local")), pRegisteredPort, this->m_dwNumLeases);
  6155. //
  6156. // We have different behavior whether the address is valid or not.
  6157. //
  6158. if (RespInfo.dwLocalAddressV4 == 0)
  6159. {
  6160. DPFX(DPFPREP, 1, "PAST server gave 0x%p an invalid address mapping for %u seconds (expires at %u).",
  6161. pRegisteredPort, RespInfo.dwLeaseTime,
  6162. pRegisteredPort->GetPASTLeaseExpiration(fRemote));
  6163. //
  6164. // If the mapping's IP address was zero, then we can't go handing it
  6165. // around.
  6166. //
  6167. // Further, if any other ports were registered with the server, their
  6168. // addresses are now all bogus as well, since it is assumed that the
  6169. // server will always hand out the same address for all assignments.
  6170. //
  6171. if (pDevice->IsPASTPublicAddressAvailable(fRemote))
  6172. {
  6173. pDevice->NoteNoPASTPublicAddressAvailable(fRemote);
  6174. //
  6175. // Since there was a change in the network, go back to polling
  6176. // relatively quickly.
  6177. //
  6178. this->ResetNextPollInterval();
  6179. //
  6180. // Any cached mappings could now be invalid. Force future
  6181. // re-queries to hit the network.
  6182. //
  6183. this->RemoveAllPASTCachedMappings(pDevice, fRemote);
  6184. //
  6185. // Loop through the existing registered port mappings and clear the
  6186. // addresses.
  6187. // We have the appropriate lock.
  6188. //
  6189. pBilink = pDevice->m_blOwnedRegPorts.GetNext();
  6190. while (pBilink != &pDevice->m_blOwnedRegPorts)
  6191. {
  6192. pTempRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  6193. if (pTempRegisteredPort != pRegisteredPort)
  6194. {
  6195. if (pTempRegisteredPort->GetPASTBindID(fRemote) != 0)
  6196. {
  6197. DPFX(DPFPREP, 3, "Existing registered port mapping 0x%p is no longer valid.",
  6198. pTempRegisteredPort);
  6199. DNASSERT(! pTempRegisteredPort->IsPASTPortUnavailable(fRemote));
  6200. DNASSERT(pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6201. DNASSERT(pTempRegisteredPort->IsFirstPASTPublicV4AddressDifferent(0, fRemote));
  6202. //
  6203. // Sorry, the address is gone.
  6204. //
  6205. pTempRegisteredPort->UpdatePASTPublicV4Addresses(RespInfo.dwLocalAddressV4,
  6206. fRemote);
  6207. //
  6208. // The user should call GetCaps to detect the address
  6209. // change. Note that GetRegisteredAddresses will already be
  6210. // returning NOMAPPING now, though.
  6211. //
  6212. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  6213. }
  6214. else
  6215. {
  6216. DNASSERT(! pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6217. }
  6218. }
  6219. else
  6220. {
  6221. //
  6222. // Skip the port we just registered.
  6223. //
  6224. }
  6225. pBilink = pBilink->GetNext();
  6226. }
  6227. }
  6228. #ifdef DBG
  6229. else
  6230. {
  6231. DPFX(DPFPREP, 7, "Still no public address for any ports.");
  6232. //
  6233. // Loop through the existing registered port mappings and make sure
  6234. // they don't have addresses (debug only).
  6235. // We have the appropriate lock.
  6236. //
  6237. pBilink = pDevice->m_blOwnedRegPorts.GetNext();
  6238. while (pBilink != &pDevice->m_blOwnedRegPorts)
  6239. {
  6240. pTempRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  6241. if (pTempRegisteredPort->IsPASTPortUnavailable(fRemote))
  6242. {
  6243. DNASSERT(pTempRegisteredPort->GetPASTBindID(fRemote) == 0);
  6244. DNASSERT(! pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6245. }
  6246. else
  6247. {
  6248. //
  6249. // Can't assert these things because we may not have tried
  6250. // mapping this port yet.
  6251. //
  6252. /*
  6253. DNASSERT(pTempRegisteredPort->GetPASTBindID(fRemote) != 0);
  6254. DNASSERT(pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6255. DNASSERT(! (pTempRegisteredPort->IsFirstPASTPublicV4AddressDifferent(RespInfo.dwLocalAddressV4, fRemote)));
  6256. */
  6257. }
  6258. pBilink = pBilink->GetNext();
  6259. }
  6260. }
  6261. #endif // DBG
  6262. }
  6263. else
  6264. {
  6265. DPFX(DPFPREP, 2, "PAST server gave 0x%p a valid address mapping for %u seconds (expires at %u).",
  6266. pRegisteredPort, RespInfo.dwLeaseTime,
  6267. pRegisteredPort->GetPASTLeaseExpiration(fRemote));
  6268. //
  6269. // The server may have previously been handing back invalid mappings.
  6270. // If any other ports were registered with the server that didn't get
  6271. // mapped, those addresses are now valid as well, since it is assumed
  6272. // that the server will will always hand out the same address for all
  6273. // assignments.
  6274. //
  6275. if (! pDevice->IsPASTPublicAddressAvailable(fRemote))
  6276. {
  6277. pDevice->NotePASTPublicAddressAvailable(fRemote);
  6278. //
  6279. // Since there was a change in the network, go back to polling
  6280. // relatively quickly.
  6281. //
  6282. this->ResetNextPollInterval();
  6283. //
  6284. // Any cached mappings could now be invalid. Force future
  6285. // re-queries to hit the network.
  6286. //
  6287. this->RemoveAllPASTCachedMappings(pDevice, fRemote);
  6288. //
  6289. // Loop through the existing registered port mappings and set the
  6290. // addresses.
  6291. // We have the appropriate lock.
  6292. //
  6293. pBilink = pDevice->m_blOwnedRegPorts.GetNext();
  6294. while (pBilink != &pDevice->m_blOwnedRegPorts)
  6295. {
  6296. pTempRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  6297. if (pTempRegisteredPort != pRegisteredPort)
  6298. {
  6299. if (pTempRegisteredPort->GetPASTBindID(fRemote) != 0)
  6300. {
  6301. DPFX(DPFPREP, 3, "Existing registered port mapping 0x%p now has an address.",
  6302. pTempRegisteredPort);
  6303. DNASSERT(! pTempRegisteredPort->IsPASTPortUnavailable(fRemote));
  6304. DNASSERT(pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6305. //
  6306. // Woohoo, there's an address now.
  6307. //
  6308. pTempRegisteredPort->UpdatePASTPublicV4Addresses(RespInfo.dwLocalAddressV4,
  6309. fRemote);
  6310. //
  6311. // The user should call GetCaps to detect the address
  6312. // change. Note that GetRegisteredAddresses will already be
  6313. // returning the new addresses now, though.
  6314. //
  6315. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  6316. }
  6317. else
  6318. {
  6319. DNASSERT(! pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6320. }
  6321. }
  6322. else
  6323. {
  6324. //
  6325. // Skip the port we just registered.
  6326. //
  6327. }
  6328. pBilink = pBilink->GetNext();
  6329. }
  6330. }
  6331. else
  6332. {
  6333. //
  6334. // We assume that the server will always hand out the same address
  6335. // to every mapping. Double check that if there's something in the
  6336. // list already then it has the same IP address. If not, the
  6337. // address has changed. Loop through the existing registered port
  6338. // mappings and convert them to use the same address as was just
  6339. // handed out.
  6340. // We have the appropriate lock.
  6341. //
  6342. pBilink = pDevice->m_blOwnedRegPorts.GetNext();
  6343. while (pBilink != &pDevice->m_blOwnedRegPorts)
  6344. {
  6345. pTempRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  6346. if (pTempRegisteredPort != pRegisteredPort)
  6347. {
  6348. if (pTempRegisteredPort->GetPASTBindID(fRemote) != 0)
  6349. {
  6350. DNASSERT(! pTempRegisteredPort->IsPASTPortUnavailable(fRemote));
  6351. DNASSERT(pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6352. DNASSERT(pTempRegisteredPort->IsFirstPASTPublicV4AddressDifferent(0, fRemote));
  6353. if (pTempRegisteredPort->IsFirstPASTPublicV4AddressDifferent(RespInfo.dwLocalAddressV4, fRemote))
  6354. {
  6355. DPFX(DPFPREP, 3, "Existing registered port mapping 0x%p differs from address just returned from PAST server.",
  6356. pTempRegisteredPort);
  6357. pTempRegisteredPort->UpdatePASTPublicV4Addresses(RespInfo.dwLocalAddressV4, fRemote);
  6358. //
  6359. // The user should call GetCaps to detect the address
  6360. // change. Note that GetRegisteredAddresses will already be
  6361. // returning the new addresses now, though.
  6362. //
  6363. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  6364. }
  6365. else
  6366. {
  6367. //
  6368. // Address is same.
  6369. //
  6370. }
  6371. }
  6372. else
  6373. {
  6374. DNASSERT(! pTempRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  6375. }
  6376. }
  6377. else
  6378. {
  6379. //
  6380. // Skip the port we just registered.
  6381. //
  6382. }
  6383. pBilink = pBilink->GetNext();
  6384. }
  6385. }
  6386. }
  6387. //
  6388. // Remember this expiration time if it's the one that's going to expire
  6389. // soonest.
  6390. //
  6391. if ((fFirstLease) ||
  6392. ((int) (pRegisteredPort->GetPASTLeaseExpiration(fRemote) - this->m_dwEarliestLeaseExpirationTime) < 0))
  6393. {
  6394. if (fFirstLease)
  6395. {
  6396. DPFX(DPFPREP, 1, "Registered port 0x%p's %s PAST lease is the first lease (expires at %u).",
  6397. pRegisteredPort,
  6398. ((fRemote) ? _T("remote") : _T("local")),
  6399. pRegisteredPort->GetPASTLeaseExpiration(fRemote));
  6400. }
  6401. else
  6402. {
  6403. DPFX(DPFPREP, 1, "Registered port 0x%p's %s PAST lease expires at %u which is earlier than the next earliest lease expiration (%u).",
  6404. pRegisteredPort,
  6405. ((fRemote) ? _T("remote") : _T("local")),
  6406. pRegisteredPort->GetPASTLeaseExpiration(fRemote),
  6407. this->m_dwEarliestLeaseExpirationTime);
  6408. }
  6409. this->m_dwEarliestLeaseExpirationTime = pRegisteredPort->GetPASTLeaseExpiration(fRemote);
  6410. //
  6411. // Ping the event if there is one so that the user's GetCaps interval
  6412. // doesn't miss this new, shorter lease.
  6413. //
  6414. if (this->m_hAlertEvent != NULL)
  6415. {
  6416. fResult = SetEvent(this->m_hAlertEvent);
  6417. #ifdef DBG
  6418. if (! fResult)
  6419. {
  6420. dwError = GetLastError();
  6421. DPFX(DPFPREP, 0, "Couldn't set alert event 0x%p! err = %u",
  6422. this->m_hAlertEvent, dwError);
  6423. //
  6424. // Ignore failure...
  6425. //
  6426. }
  6427. #endif // DBG
  6428. }
  6429. //
  6430. // Ping the I/O completion port if there is one so that the user's
  6431. // GetCaps interval doesn't miss this new, shorter lease.
  6432. //
  6433. if (this->m_hAlertIOCompletionPort != NULL)
  6434. {
  6435. fResult = PostQueuedCompletionStatus(this->m_hAlertIOCompletionPort,
  6436. 0,
  6437. this->m_dwAlertCompletionKey,
  6438. NULL);
  6439. #ifdef DBG
  6440. if (! fResult)
  6441. {
  6442. dwError = GetLastError();
  6443. DPFX(DPFPREP, 0, "Couldn't queue key %u on alert IO completion port 0x%p! err = %u",
  6444. this->m_dwAlertCompletionKey,
  6445. this->m_hAlertIOCompletionPort,
  6446. dwError);
  6447. //
  6448. // Ignore failure...
  6449. //
  6450. }
  6451. #endif // DBG
  6452. }
  6453. }
  6454. Exit:
  6455. if (pvRequest != NULL)
  6456. {
  6457. DNFree(pvRequest);
  6458. pvRequest = NULL;
  6459. }
  6460. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  6461. return hr;
  6462. Failure:
  6463. //
  6464. // If we registered the port, de-register it.
  6465. //
  6466. if (pRegisteredPort->GetPASTBindID(fRemote) != 0)
  6467. {
  6468. temphr = this->FreePASTPort(pRegisteredPort, fRemote);
  6469. if (temphr != DPNH_OK)
  6470. {
  6471. //
  6472. // We'll treat this as non-fatal, but we have to dump the server.
  6473. //
  6474. this->ClearDevicesPASTServer(pRegisteredPort->GetOwningDevice(), fRemote);
  6475. }
  6476. }
  6477. goto Exit;
  6478. } // CNATHelpPAST::AssignOrListenPASTPort
  6479. #undef DPF_MODNAME
  6480. #define DPF_MODNAME "CNATHelpPAST::FreePASTPort"
  6481. //=============================================================================
  6482. // CNATHelpPAST::FreePASTPort
  6483. //-----------------------------------------------------------------------------
  6484. //
  6485. // Description: Release a port mapping with the PAST server.
  6486. //
  6487. // The object lock is assumed to be held.
  6488. //
  6489. // Arguments:
  6490. // CRegisteredPort * pRegisteredPort - Pointer to port object mapping to
  6491. // release.
  6492. // BOOL fRemote - TRUE if should free from remote
  6493. // server, FALSE if freeing from local
  6494. // server.
  6495. //
  6496. // Returns: HRESULT
  6497. // DPNH_OK - The release was successful.
  6498. // DPNHERR_GENERIC - An error occurred.
  6499. // DPNHERR_SERVERNOTRESPONDING - The server did not respond to the
  6500. // message.
  6501. //=============================================================================
  6502. HRESULT CNATHelpPAST::FreePASTPort(CRegisteredPort * const pRegisteredPort,
  6503. const BOOL fRemote)
  6504. {
  6505. HRESULT hr = DPNH_OK;
  6506. CDevice * pDevice;
  6507. SOCKADDR_IN saddrinServerAddress;
  6508. DWORD dwClientID;
  6509. DWORD dwMsgID;
  6510. DWORD * ptuRetry;
  6511. PAST_MSG_FREE_REQUEST FreeReq;
  6512. PAST_RESPONSE_INFO RespInfo;
  6513. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)",
  6514. this, pRegisteredPort, fRemote);
  6515. DNASSERT(pRegisteredPort != NULL);
  6516. pDevice = pRegisteredPort->GetOwningDevice();
  6517. DNASSERT(pDevice != NULL);
  6518. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  6519. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  6520. //
  6521. // Create a SOCKADDR to address the PAST service, and get the appropriate
  6522. // client ID, initial retry timeout, and next message ID to use.
  6523. //
  6524. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  6525. saddrinServerAddress.sin_family = AF_INET;
  6526. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  6527. if (fRemote)
  6528. {
  6529. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  6530. dwMsgID = pDevice->GetNextRemotePASTMsgID();
  6531. ptuRetry = pDevice->GetRemotePASTRetryTimeoutPtr();
  6532. }
  6533. else
  6534. {
  6535. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  6536. dwMsgID = pDevice->GetNextLocalPASTMsgID();
  6537. ptuRetry = pDevice->GetLocalPASTRetryTimeoutPtr();
  6538. }
  6539. dwClientID = pDevice->GetPASTClientID(fRemote);
  6540. DNASSERT(dwClientID != 0);
  6541. //
  6542. // Build the request message.
  6543. //
  6544. ZeroMemory(&FreeReq, sizeof(FreeReq));
  6545. FreeReq.version = PAST_VERSION;
  6546. FreeReq.command = PAST_MSGID_FREE_REQUEST;
  6547. FreeReq.clientid.code = PAST_PARAMID_CLIENTID;
  6548. FreeReq.clientid.len = sizeof(FreeReq.clientid) - sizeof(PAST_PARAM);
  6549. FreeReq.clientid.clientid = dwClientID;
  6550. FreeReq.bindid.code = PAST_PARAMID_BINDID;
  6551. FreeReq.bindid.len = sizeof(FreeReq.bindid) - sizeof(PAST_PARAM);
  6552. FreeReq.bindid.bindid = pRegisteredPort->GetPASTBindID(fRemote);
  6553. FreeReq.msgid.code = PAST_PARAMID_MESSAGEID;
  6554. FreeReq.msgid.len = sizeof(FreeReq.msgid) - sizeof(PAST_PARAM);
  6555. FreeReq.msgid.msgid = dwMsgID;
  6556. //
  6557. // Send the message and get the reply.
  6558. //
  6559. hr = this->ExchangeAndParsePAST(pDevice->GetPASTSocket(),
  6560. (SOCKADDR*) (&saddrinServerAddress),
  6561. sizeof(saddrinServerAddress),
  6562. (char *) &FreeReq,
  6563. sizeof(FreeReq),
  6564. dwMsgID,
  6565. ptuRetry,
  6566. &RespInfo);
  6567. if (hr != DPNH_OK)
  6568. {
  6569. DPFX(DPFPREP, 0, "Freeing port mapping failed!");
  6570. goto Failure;
  6571. }
  6572. if (RespInfo.cMsgType != PAST_MSGID_FREE_RESPONSE)
  6573. {
  6574. DPFX(DPFPREP, 0, "Got unexpected response type %u, failed freeing port mapping!", RespInfo.cMsgType);
  6575. hr = DPNHERR_GENERIC;
  6576. goto Failure;
  6577. }
  6578. pRegisteredPort->SetPASTBindID(0, fRemote);
  6579. pRegisteredPort->ClearPASTPublicAddresses(fRemote);
  6580. //
  6581. // One more lease is gone.
  6582. //
  6583. DNASSERT(this->m_dwNumLeases > 0);
  6584. this->m_dwNumLeases--;
  6585. DPFX(DPFPREP, 7, "%s PAST lease for 0x%p removed, total num leases = %u.",
  6586. ((fRemote) ? _T("Remote") : _T("Local")), pRegisteredPort, this->m_dwNumLeases);
  6587. Exit:
  6588. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  6589. return hr;
  6590. Failure:
  6591. goto Exit;
  6592. } // CNATHelpPAST::FreePASTPort
  6593. #undef DPF_MODNAME
  6594. #define DPF_MODNAME "CNATHelpPAST::InternalPASTQueryAddress"
  6595. //=============================================================================
  6596. // CNATHelpPAST::InternalPASTQueryAddress
  6597. //-----------------------------------------------------------------------------
  6598. //
  6599. // Description: Queries a port mapping with the PAST server.
  6600. //
  6601. // The object lock is assumed to be held.
  6602. //
  6603. // Arguments:
  6604. // CDevice * pDevice - Pointer to device whose PAST
  6605. // server should be queried.
  6606. // SOCKADDR_IN * psaddrinQueryAddress - Address to look up.
  6607. // SOCKADDR_IN * psaddrinResponseAddress - Place to store public address, if
  6608. // one exists.
  6609. // DWORD dwFlags - Flags to use when querying.
  6610. // BOOL fRemote - TRUE if querying remote, FALSE
  6611. // querying local server.
  6612. //
  6613. // Returns: HRESULT
  6614. // DPNH_OK - The query was successful.
  6615. // DPNHERR_GENERIC - An error occurred.
  6616. // DPNHERR_NOMAPPING - The server did not have a mapping for the
  6617. // given address.
  6618. // DPNHERR_NOMAPPINGBUTPRIVATE - The server indicated that no mapping
  6619. // exists, but the address is private.
  6620. // DPNHERR_SERVERNOTRESPONDING - The server did not respond to the
  6621. // message.
  6622. //=============================================================================
  6623. HRESULT CNATHelpPAST::InternalPASTQueryAddress(CDevice * const pDevice,
  6624. const SOCKADDR_IN * const psaddrinQueryAddress,
  6625. SOCKADDR_IN * const psaddrinResponseAddress,
  6626. const DWORD dwFlags,
  6627. const BOOL fRemote)
  6628. {
  6629. HRESULT hr;
  6630. CBilink * pblCachedMaps;
  6631. DWORD dwCurrentTime;
  6632. CBilink * pBilink;
  6633. CCacheMap * pCacheMap;
  6634. SOCKADDR_IN saddrinServerAddress;
  6635. DWORD dwClientID;
  6636. DWORD dwMsgID;
  6637. DWORD * ptuRetry;
  6638. PAST_MSG_QUERY_REQUEST_PORTS QueryReq;
  6639. PAST_RESPONSE_INFO RespInfo;
  6640. DWORD dwCacheMapFlags;
  6641. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, 0x%p, 0x%p, 0x%lx, %i)",
  6642. this, pDevice, psaddrinQueryAddress, psaddrinResponseAddress,
  6643. dwFlags, fRemote);
  6644. DNASSERT(pDevice != NULL);
  6645. DNASSERT(psaddrinQueryAddress != NULL);
  6646. DNASSERT(psaddrinResponseAddress != NULL);
  6647. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  6648. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  6649. DPFX(DPFPREP, 7, "Querying for address %u.%u.%u.%u:%u %s.",
  6650. psaddrinQueryAddress->sin_addr.S_un.S_un_b.s_b1,
  6651. psaddrinQueryAddress->sin_addr.S_un.S_un_b.s_b2,
  6652. psaddrinQueryAddress->sin_addr.S_un.S_un_b.s_b3,
  6653. psaddrinQueryAddress->sin_addr.S_un.S_un_b.s_b4,
  6654. NTOHS(psaddrinQueryAddress->sin_port),
  6655. ((dwFlags & DPNHQUERYADDRESS_TCP) ? _T("TCP") : _T("UDP")));
  6656. //
  6657. // First, check if we've looked this address up recently and already have
  6658. // the result cached.
  6659. // The lock is already held.
  6660. //
  6661. pblCachedMaps = pDevice->GetPASTCachedMaps(fRemote);
  6662. dwCurrentTime = timeGetTime();
  6663. pBilink = pblCachedMaps->GetNext();
  6664. while (pBilink != pblCachedMaps)
  6665. {
  6666. pCacheMap = CACHEMAP_FROM_BILINK(pBilink);
  6667. pBilink = pBilink->GetNext();
  6668. //
  6669. // Make sure this cached mapping hasn't expired.
  6670. //
  6671. if ((int) (pCacheMap->GetExpirationTime() - dwCurrentTime) < 0)
  6672. {
  6673. DPFX(DPFPREP, 5, "Cached mapping 0x%p has expired.", pCacheMap);
  6674. pCacheMap->m_blList.RemoveFromList();
  6675. delete pCacheMap;
  6676. }
  6677. else
  6678. {
  6679. //
  6680. // If this mapping is for the right address and type of address,
  6681. // then we've already got our answer.
  6682. //
  6683. if (pCacheMap->DoesMatchQuery(psaddrinQueryAddress, dwFlags))
  6684. {
  6685. if (pCacheMap->IsNotFound())
  6686. {
  6687. if ((dwFlags & DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED) &&
  6688. (pCacheMap->IsPrivateButUnmapped()))
  6689. {
  6690. DPFX(DPFPREP, 5, "Address was already determined to not have a mapping but still be private.");
  6691. hr = DPNHERR_NOMAPPINGBUTPRIVATE;
  6692. }
  6693. else
  6694. {
  6695. DPFX(DPFPREP, 5, "Address was already determined to not have a mapping.");
  6696. hr = DPNHERR_NOMAPPING;
  6697. }
  6698. }
  6699. else
  6700. {
  6701. pCacheMap->GetResponseAddressV4(psaddrinResponseAddress);
  6702. DPFX(DPFPREP, 5, "Address was already determined to have a mapping.");
  6703. hr = DPNH_OK;
  6704. }
  6705. goto Exit;
  6706. }
  6707. }
  6708. }
  6709. dwCacheMapFlags = QUERYFLAGSMASK(dwFlags);
  6710. //
  6711. // If we're here, we haven't already cached the answer.
  6712. //
  6713. // Create a SOCKADDR to address the PAST service, and get the appropriate
  6714. // client ID, initial retry timeout, and next message ID to use.
  6715. //
  6716. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  6717. saddrinServerAddress.sin_family = AF_INET;
  6718. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  6719. if (fRemote)
  6720. {
  6721. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  6722. dwMsgID = pDevice->GetNextRemotePASTMsgID();
  6723. ptuRetry = pDevice->GetRemotePASTRetryTimeoutPtr();
  6724. }
  6725. else
  6726. {
  6727. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  6728. dwMsgID = pDevice->GetNextLocalPASTMsgID();
  6729. ptuRetry = pDevice->GetLocalPASTRetryTimeoutPtr();
  6730. }
  6731. dwClientID = pDevice->GetPASTClientID(fRemote);
  6732. DNASSERT(dwClientID != 0);
  6733. //
  6734. // Build the request message for asking the server.
  6735. //
  6736. ZeroMemory(&QueryReq, sizeof(QueryReq));
  6737. QueryReq.version = PAST_VERSION;
  6738. QueryReq.command = PAST_MSGID_QUERY_REQUEST;
  6739. QueryReq.clientid.code = PAST_PARAMID_CLIENTID;
  6740. QueryReq.clientid.len = sizeof(QueryReq.clientid) - sizeof(PAST_PARAM);
  6741. QueryReq.clientid.clientid = dwClientID;
  6742. QueryReq.address.code = PAST_PARAMID_ADDRESS;
  6743. QueryReq.address.len = sizeof(QueryReq.address) - sizeof(PAST_PARAM);
  6744. QueryReq.address.version = PAST_ADDRESSTYPE_IPV4;
  6745. QueryReq.address.addr = psaddrinQueryAddress->sin_addr.s_addr;
  6746. //
  6747. // NOTE: Ports appeared to be transferred in x86 format, contrary to
  6748. // the spec, which says network byte order.
  6749. //
  6750. QueryReq.port.code = PAST_PARAMID_PORTS;
  6751. QueryReq.port.len = sizeof(QueryReq.port) - sizeof(PAST_PARAM);
  6752. QueryReq.port.nports = 1;
  6753. QueryReq.port.port = NTOHS(psaddrinQueryAddress->sin_port);
  6754. QueryReq.porttype.code = PAST_PARAMID_VENDOR;
  6755. QueryReq.porttype.len = sizeof(QueryReq.porttype) - sizeof(PAST_PARAM);
  6756. QueryReq.porttype.vendorid = PAST_MS_VENDOR_ID;
  6757. QueryReq.porttype.option = (dwFlags & DPNHQUERYADDRESS_TCP) ? PAST_VC_MS_TCP_PORT : PAST_VC_MS_UDP_PORT;
  6758. QueryReq.querytype.code = PAST_PARAMID_VENDOR;
  6759. QueryReq.querytype.len = sizeof(QueryReq.querytype) - sizeof(PAST_PARAM);
  6760. QueryReq.querytype.vendorid = PAST_MS_VENDOR_ID;
  6761. QueryReq.querytype.option = PAST_VC_MS_QUERY_MAPPING;
  6762. QueryReq.msgid.code = PAST_PARAMID_MESSAGEID;
  6763. QueryReq.msgid.len = sizeof(QueryReq.msgid) - sizeof(PAST_PARAM);
  6764. QueryReq.msgid.msgid = dwMsgID;
  6765. //
  6766. // Send the message and get the reply.
  6767. //
  6768. hr = this->ExchangeAndParsePAST(pDevice->GetPASTSocket(),
  6769. (SOCKADDR*) (&saddrinServerAddress),
  6770. sizeof(saddrinServerAddress),
  6771. (char *) &QueryReq,
  6772. sizeof(QueryReq),
  6773. dwMsgID,
  6774. ptuRetry,
  6775. &RespInfo);
  6776. if (hr != DPNH_OK)
  6777. {
  6778. DPFX(DPFPREP, 0, "Querying port mapping failed!");
  6779. goto Failure;
  6780. }
  6781. if (RespInfo.cMsgType != PAST_MSGID_QUERY_RESPONSE)
  6782. {
  6783. //
  6784. // We got something, but it's not the right response. Try determining
  6785. // if the address is local, if allowed.
  6786. //
  6787. if (dwFlags & DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED)
  6788. {
  6789. //
  6790. // If Personal Firewall is enabled, don't bother checking if the
  6791. // address is local. Anything on the other side of the firewall is
  6792. // considered non-local.
  6793. //
  6794. if ((pDevice->GetPASTClientID(FALSE) == 0) ||
  6795. (! pDevice->HasLocalPFWOnlyPASTServer()))
  6796. {
  6797. if (this->IsAddressLocal(pDevice, psaddrinQueryAddress))
  6798. {
  6799. DPFX(DPFPREP, 5, "Address appears to be local, returning NOMAPPINGBUTPRIVATE.");
  6800. dwCacheMapFlags |= CACHEMAPOBJ_PRIVATEBUTUNMAPPED;
  6801. hr = DPNHERR_NOMAPPINGBUTPRIVATE;
  6802. }
  6803. else
  6804. {
  6805. DPFX(DPFPREP, 5, "Address does not appear to be local, returning NOMAPPING.");
  6806. hr = DPNHERR_NOMAPPING;
  6807. }
  6808. }
  6809. else
  6810. {
  6811. DPFX(DPFPREP, 5, "Device 0x%p has Personal Firewall enabled, not checking address locality and returning NOMAPPING.");
  6812. hr = DPNHERR_NOMAPPING;
  6813. }
  6814. }
  6815. else
  6816. {
  6817. DPFX(DPFPREP, 1, "Got non-success response type %u while querying port mapping, assuming does not exist.", RespInfo.cMsgType);
  6818. hr = DPNHERR_NOMAPPING;
  6819. }
  6820. //
  6821. // Cache the fact that we could not determine a mapping for that
  6822. // address, if allowed.
  6823. //
  6824. if (dwFlags & DPNHQUERYADDRESS_CACHENOTFOUND)
  6825. {
  6826. pCacheMap = new CCacheMap(psaddrinQueryAddress,
  6827. (GETTIMESTAMP() + g_dwCacheLifeNotFound),
  6828. (dwCacheMapFlags | CACHEMAPOBJ_NOTFOUND));
  6829. if (pCacheMap == NULL)
  6830. {
  6831. hr = DPNHERR_OUTOFMEMORY;
  6832. goto Failure;
  6833. }
  6834. pCacheMap->m_blList.InsertBefore(pblCachedMaps);
  6835. }
  6836. goto Failure;
  6837. }
  6838. //
  6839. // Make sure the port count is valid.
  6840. //
  6841. if (RespInfo.cNumLocalPorts != 1)
  6842. {
  6843. DPFX(DPFPREP, 0, "PAST server returned an invalid number of local ports with success message (%u)! Assuming no mapping.",
  6844. RespInfo.cNumLocalPorts);
  6845. DNASSERTX(! "Why is PAST server returning bogus number of ports?", 2);
  6846. hr = DPNHERR_NOMAPPING;
  6847. goto Failure;
  6848. }
  6849. //
  6850. // Convert the loopback address to the device address.
  6851. //
  6852. if (RespInfo.dwLocalAddressV4 == NETWORKBYTEORDER_INADDR_LOOPBACK)
  6853. {
  6854. RespInfo.dwLocalAddressV4 = pDevice->GetLocalAddressV4();
  6855. DPFX(DPFPREP, 1, "Converted loopback address to device address (%u.%u.%u.%u).",
  6856. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b1,
  6857. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b2,
  6858. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b3,
  6859. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b4);
  6860. }
  6861. //
  6862. // Ensure that we're not getting something bogus. Use saddrinServerAddress
  6863. // as a temporary variable.
  6864. //
  6865. saddrinServerAddress.sin_addr.S_un.S_addr = RespInfo.dwLocalAddressV4;
  6866. if ((RespInfo.dwLocalAddressV4 == 0) ||
  6867. (RespInfo.awLocalPorts[0] == 0) ||
  6868. (! this->IsAddressLocal(pDevice, &saddrinServerAddress)))
  6869. {
  6870. DPFX(DPFPREP, 0, "PAST server returned an invalid private address (%u.%u.%u.%u:%u)! Assuming no mapping.",
  6871. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b1,
  6872. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b2,
  6873. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b3,
  6874. ((IN_ADDR*) (&RespInfo.dwLocalAddressV4))->S_un.S_un_b.s_b4,
  6875. NTOHS(RespInfo.awLocalPorts[0]));
  6876. DNASSERTX(! "Why is PAST server returning invalid private address?", 2);
  6877. hr = DPNHERR_NOMAPPING;
  6878. goto Failure;
  6879. }
  6880. //
  6881. // Return the address mapping to our caller.
  6882. //
  6883. ZeroMemory(psaddrinResponseAddress, sizeof(SOCKADDR_IN));
  6884. psaddrinResponseAddress->sin_family = AF_INET;
  6885. psaddrinResponseAddress->sin_addr.s_addr = RespInfo.dwLocalAddressV4;
  6886. psaddrinResponseAddress->sin_port = RespInfo.awLocalPorts[0];
  6887. //
  6888. // Cache the fact that we found a mapping for that address, if allowed.
  6889. //
  6890. if (dwFlags & DPNHQUERYADDRESS_CACHEFOUND)
  6891. {
  6892. pCacheMap = new CCacheMap(psaddrinQueryAddress,
  6893. (GETTIMESTAMP() + g_dwCacheLifeFound),
  6894. dwCacheMapFlags);
  6895. if (pCacheMap == NULL)
  6896. {
  6897. hr = DPNHERR_OUTOFMEMORY;
  6898. goto Failure;
  6899. }
  6900. pCacheMap->SetResponseAddressV4(RespInfo.dwLocalAddressV4,
  6901. RespInfo.awLocalPorts[0]);
  6902. pCacheMap->m_blList.InsertBefore(pblCachedMaps);
  6903. }
  6904. Exit:
  6905. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  6906. return hr;
  6907. Failure:
  6908. goto Exit;
  6909. } // CNATHelpPAST::InternalPASTQueryAddress
  6910. #undef DPF_MODNAME
  6911. #define DPF_MODNAME "CNATHelpPAST::ExtendPASTLease"
  6912. //=============================================================================
  6913. // CNATHelpPAST::ExtendPASTLease
  6914. //-----------------------------------------------------------------------------
  6915. //
  6916. // Description: Asks the PAST server to extend a port mapping lease.
  6917. //
  6918. // The object lock is assumed to be held.
  6919. //
  6920. // Arguments:
  6921. // CRegisteredPort * pRegisteredPort - Pointer to port object mapping to
  6922. // extend.
  6923. // BOOL fRemote - TRUE if extending on remote server,
  6924. // FALSE if extending on local server.
  6925. //
  6926. // Returns: HRESULT
  6927. // DPNH_OK - The extension was successful.
  6928. // DPNHERR_GENERIC - An error occurred.
  6929. // DPNHERR_SERVERNOTRESPONDING - The server did not respond to the
  6930. // message.
  6931. //=============================================================================
  6932. HRESULT CNATHelpPAST::ExtendPASTLease(CRegisteredPort * const pRegisteredPort,
  6933. const BOOL fRemote)
  6934. {
  6935. HRESULT hr = DPNH_OK;
  6936. CDevice * pDevice;
  6937. SOCKADDR_IN saddrinServerAddress;
  6938. DWORD dwClientID;
  6939. DWORD dwMsgID;
  6940. DWORD * ptuRetry;
  6941. PAST_MSG_EXTEND_REQUEST ExtendReq;
  6942. PAST_RESPONSE_INFO RespInfo;
  6943. BOOL fResult;
  6944. #ifdef DBG
  6945. DWORD dwError;
  6946. #endif // DBG
  6947. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)",
  6948. this, pRegisteredPort, fRemote);
  6949. DNASSERT(pRegisteredPort != NULL);
  6950. pDevice = pRegisteredPort->GetOwningDevice();
  6951. DNASSERT(pDevice != NULL);
  6952. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  6953. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  6954. //
  6955. // Create a SOCKADDR to address the PAST service, and get the appropriate
  6956. // client ID, initial retry timeout, and next message ID to use.
  6957. //
  6958. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  6959. saddrinServerAddress.sin_family = AF_INET;
  6960. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  6961. if (fRemote)
  6962. {
  6963. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  6964. dwMsgID = pDevice->GetNextRemotePASTMsgID();
  6965. ptuRetry = pDevice->GetRemotePASTRetryTimeoutPtr();
  6966. }
  6967. else
  6968. {
  6969. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  6970. dwMsgID = pDevice->GetNextLocalPASTMsgID();
  6971. ptuRetry = pDevice->GetLocalPASTRetryTimeoutPtr();
  6972. }
  6973. dwClientID = pDevice->GetPASTClientID(fRemote);
  6974. DNASSERT(dwClientID != 0);
  6975. //
  6976. // Build the request message.
  6977. //
  6978. ZeroMemory(&ExtendReq, sizeof(ExtendReq));
  6979. ExtendReq.version = PAST_VERSION;
  6980. ExtendReq.command = PAST_MSGID_EXTEND_REQUEST;
  6981. ExtendReq.clientid.code = PAST_PARAMID_CLIENTID;
  6982. ExtendReq.clientid.len = sizeof(ExtendReq.clientid) - sizeof(PAST_PARAM);
  6983. ExtendReq.clientid.clientid = dwClientID;
  6984. ExtendReq.bindid.code = PAST_PARAMID_BINDID;
  6985. ExtendReq.bindid.len = sizeof(DWORD);
  6986. ExtendReq.bindid.bindid = pRegisteredPort->GetPASTBindID(fRemote);
  6987. //
  6988. // Lease code, ask for what the user wants, but they shouldn't count on
  6989. // getting that.
  6990. // Convert the request (in milliseconds) to PAST's time unit (in seconds).
  6991. //
  6992. ExtendReq.lease.code = PAST_PARAMID_LEASE;
  6993. ExtendReq.lease.len = sizeof(ExtendReq.lease) - sizeof(PAST_PARAM);
  6994. ExtendReq.lease.leasetime = pRegisteredPort->GetRequestedLeaseTime() / 1000;
  6995. ExtendReq.msgid.code = PAST_PARAMID_MESSAGEID;
  6996. ExtendReq.msgid.len = sizeof(ExtendReq.msgid) - sizeof(PAST_PARAM);
  6997. ExtendReq.msgid.msgid = dwMsgID;
  6998. //
  6999. // Send the message and get the reply.
  7000. //
  7001. hr = this->ExchangeAndParsePAST(pDevice->GetPASTSocket(),
  7002. (SOCKADDR*) (&saddrinServerAddress),
  7003. sizeof(saddrinServerAddress),
  7004. (char *) &ExtendReq,
  7005. sizeof(ExtendReq),
  7006. dwMsgID,
  7007. ptuRetry,
  7008. &RespInfo);
  7009. if (hr != DPNH_OK)
  7010. {
  7011. DPFX(DPFPREP, 0, "Sending port lease extension request to server failed!");
  7012. goto Failure;
  7013. }
  7014. if (RespInfo.cMsgType != PAST_MSGID_EXTEND_RESPONSE)
  7015. {
  7016. DPFX(DPFPREP, 0, "Got unexpected response type %u, failed port lease extension!", RespInfo.cMsgType);
  7017. hr = DPNHERR_GENERIC;
  7018. goto Failure;
  7019. }
  7020. //
  7021. // Note the lease time extension (which is in seconds). It had better be
  7022. // longer than our auto-extension rate. We use it to extend the current
  7023. // lease expiration (which is in milliseconds).
  7024. //
  7025. DNASSERT((RespInfo.dwLeaseTime * 1000) > LEASE_RENEW_TIME);
  7026. pRegisteredPort->SetPASTLeaseExpiration((timeGetTime() + (RespInfo.dwLeaseTime * 1000)),
  7027. fRemote);
  7028. DPFX(DPFPREP, 8, "Extended lease (registered port = 0x%p) to %u seconds from now, expires at %u.",
  7029. pRegisteredPort, RespInfo.dwLeaseTime,
  7030. pRegisteredPort->GetPASTLeaseExpiration(fRemote));
  7031. //
  7032. // Remember this expiration time if it's the one that's going to expire
  7033. // soonest.
  7034. //
  7035. DNASSERT(this->m_dwNumLeases > 0);
  7036. if ((int) (pRegisteredPort->GetPASTLeaseExpiration(fRemote) - this->m_dwEarliestLeaseExpirationTime) < 0)
  7037. {
  7038. DPFX(DPFPREP, 1, "Registered port 0x%p's %s PAST lease expires at %u which is earlier than the next earliest lease expiration (%u).",
  7039. pRegisteredPort,
  7040. ((fRemote) ? _T("remote") : _T("local")),
  7041. pRegisteredPort->GetPASTLeaseExpiration(fRemote),
  7042. this->m_dwEarliestLeaseExpirationTime);
  7043. this->m_dwEarliestLeaseExpirationTime = pRegisteredPort->GetPASTLeaseExpiration(fRemote);
  7044. //
  7045. // Ping the event if there is one so that the user's GetCaps interval
  7046. // doesn't miss this new, shorter lease.
  7047. //
  7048. if (this->m_hAlertEvent != NULL)
  7049. {
  7050. fResult = SetEvent(this->m_hAlertEvent);
  7051. #ifdef DBG
  7052. if (! fResult)
  7053. {
  7054. dwError = GetLastError();
  7055. DPFX(DPFPREP, 0, "Couldn't set alert event 0x%p! err = %u",
  7056. this->m_hAlertEvent, dwError);
  7057. //
  7058. // Ignore failure...
  7059. //
  7060. }
  7061. #endif // DBG
  7062. }
  7063. //
  7064. // Ping the I/O completion port if there is one so that the user's
  7065. // GetCaps interval doesn't miss this new, shorter lease.
  7066. //
  7067. if (this->m_hAlertIOCompletionPort != NULL)
  7068. {
  7069. fResult = PostQueuedCompletionStatus(this->m_hAlertIOCompletionPort,
  7070. 0,
  7071. this->m_dwAlertCompletionKey,
  7072. NULL);
  7073. #ifdef DBG
  7074. if (! fResult)
  7075. {
  7076. dwError = GetLastError();
  7077. DPFX(DPFPREP, 0, "Couldn't queue key %u on alert IO completion port 0x%p! err = %u",
  7078. this->m_dwAlertCompletionKey,
  7079. this->m_hAlertIOCompletionPort,
  7080. dwError);
  7081. //
  7082. // Ignore failure...
  7083. //
  7084. }
  7085. #endif // DBG
  7086. }
  7087. }
  7088. Exit:
  7089. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  7090. return hr;
  7091. Failure:
  7092. goto Exit;
  7093. } // CNATHelpPAST::ExtendPASTLease
  7094. #undef DPF_MODNAME
  7095. #define DPF_MODNAME "CNATHelpPAST::UpdatePASTPublicAddressValidity"
  7096. //=============================================================================
  7097. // CNATHelpPAST::UpdatePASTPublicAddressValidity
  7098. //-----------------------------------------------------------------------------
  7099. //
  7100. // Description: Checks to see if the given device's PAST server is handing
  7101. // out valid public addresses or not.
  7102. //
  7103. // The PAST server information might be cleared if a failure
  7104. // occurs.
  7105. //
  7106. // The object lock is assumed to be held.
  7107. //
  7108. // Arguments:
  7109. // CDevice * pDevice - Pointer to device that should be checked.
  7110. // BOOL fRemote - Whether the local or remote PAST server should be
  7111. // checked.
  7112. //
  7113. // Returns: HRESULT
  7114. // DPNH_OK - The update was successful.
  7115. // DPNHERR_GENERIC - An error occurred.
  7116. //=============================================================================
  7117. HRESULT CNATHelpPAST::UpdatePASTPublicAddressValidity(CDevice * const pDevice,
  7118. const BOOL fRemote)
  7119. {
  7120. HRESULT hr;
  7121. SOCKADDR_IN saddrinTemp;
  7122. CRegisteredPort * pTempRegisteredPort = NULL;
  7123. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)",
  7124. this, pDevice, fRemote);
  7125. //
  7126. // Create a temporary port mapping object. We mark it as "local PAST port
  7127. // unavailable" when checking remove PAST servers because we have not and
  7128. // will not attempt to map the local port when there is a local PAST
  7129. // server. Since AssignOrListenPASTPort assumes the local port will have
  7130. // been mapped first, we need to prevent it from trying to use that address
  7131. // and crashing.
  7132. //
  7133. pTempRegisteredPort = new CRegisteredPort(FAKE_PORT_LEASE_TIME,
  7134. ((fRemote) ? REGPORTOBJ_PORTUNAVAILABLE_PAST_LOCAL : 0));
  7135. if (pTempRegisteredPort == NULL)
  7136. {
  7137. hr = DPNHERR_OUTOFMEMORY;
  7138. goto Failure;
  7139. }
  7140. pTempRegisteredPort->MakeDeviceOwner(pDevice);
  7141. //
  7142. // Pick an arbitrary port value to map. In this case, we should just use
  7143. // the socket we're using for Ioctl communication, since that port is
  7144. // guaranteed to be unique by WinSock (so no multi-PASTHelp-instance race
  7145. // conditions like if we had used a hardcoded temporary port).
  7146. // One difference: the Ioctl socket is bound to INADDR_ANY, but we'll use
  7147. // the specific device address so our ICS vs. PFW-only address comparison
  7148. // below works correctly. This shouldn't make a difference, since a port
  7149. // in use by INADDR_ANY should be the same as the same port in use on each
  7150. // of the adapters.
  7151. //
  7152. ZeroMemory(&saddrinTemp, sizeof(saddrinTemp));
  7153. saddrinTemp.sin_family = AF_INET;
  7154. saddrinTemp.sin_addr.S_un.S_addr = pDevice->GetLocalAddressV4();
  7155. saddrinTemp.sin_port = this->m_wIoctlSocketPort;
  7156. //
  7157. // Assign it the communication socket's address.
  7158. //
  7159. hr = pTempRegisteredPort->SetPrivateAddresses(&saddrinTemp, 1);
  7160. if (hr != DPNH_OK)
  7161. {
  7162. DPFX(DPFPREP, 0, "Couldn't set temporary private addresses!");
  7163. goto Failure;
  7164. }
  7165. DPFX(DPFPREP, 7, "Temporarily assigning port %u.%u.%u.%u:%u to check server status.",
  7166. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  7167. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  7168. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  7169. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  7170. NTOHS(this->m_wIoctlSocketPort));
  7171. //
  7172. // Attempt to map it. AssignOrListenPASTPort will handle the actual logic
  7173. // of changing addresses.
  7174. //
  7175. hr = this->AssignOrListenPASTPort(pTempRegisteredPort, fRemote);
  7176. if (hr != DPNH_OK)
  7177. {
  7178. DPFX(DPFPREP, 0, "Couldn't assign temporary port mapping with server (0x%lx)! Ignoring.", hr);
  7179. //
  7180. // We'll treat this as non-fatal, but we'll dump the server.
  7181. //
  7182. this->ClearDevicesPASTServer(pDevice, fRemote);
  7183. hr = DPNH_OK;
  7184. }
  7185. else
  7186. {
  7187. //
  7188. // If we're checking the local server, determine whether it's a local ICS
  7189. // server or it's Personal Firewall only.
  7190. //
  7191. if (! fRemote)
  7192. {
  7193. //
  7194. // If public address is the same, it's PFW only, if it's different,
  7195. // it's ICS (although that could be PFWed, too). If there's no
  7196. // public address, then we can't really tell. It should be safe to
  7197. // assume that it's ICS, since this device must have an address or
  7198. // else it wouldn't exist.
  7199. //
  7200. if ((! pDevice->IsPASTPublicAddressAvailable(FALSE)) ||
  7201. (pTempRegisteredPort->IsFirstPASTPublicV4AddressDifferent(saddrinTemp.sin_addr.S_un.S_addr, FALSE)))
  7202. {
  7203. #ifdef DBG
  7204. if (! pDevice->IsPASTPublicAddressAvailable(FALSE))
  7205. {
  7206. DPFX(DPFPREP, 2, "Device %u.%u.%u.%u (object = 0x%p) doesn't have public address, assuming ICS.",
  7207. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  7208. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  7209. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  7210. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  7211. pDevice);
  7212. }
  7213. else
  7214. {
  7215. SOCKADDR_IN * pasaddrinPublic;
  7216. pasaddrinPublic = pTempRegisteredPort->GetPASTPublicAddressesArray(FALSE);
  7217. DPFX(DPFPREP, 2, "Device %u.%u.%u.%u (object = 0x%p) has different public address (%u.%u.%u.%u), appears to be ICS.",
  7218. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  7219. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  7220. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  7221. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  7222. pDevice,
  7223. pasaddrinPublic[0].sin_addr.S_un.S_un_b.s_b1,
  7224. pasaddrinPublic[0].sin_addr.S_un.S_un_b.s_b2,
  7225. pasaddrinPublic[0].sin_addr.S_un.S_un_b.s_b3,
  7226. pasaddrinPublic[0].sin_addr.S_un.S_un_b.s_b4);
  7227. }
  7228. #endif // DBG
  7229. pDevice->NoteLocalPASTServerIsICS();
  7230. }
  7231. else
  7232. {
  7233. DPFX(DPFPREP, 2, "Device %u.%u.%u.%u (object = 0x%p) has same public address, appears to be firewall only.",
  7234. saddrinTemp.sin_addr.S_un.S_un_b.s_b1,
  7235. saddrinTemp.sin_addr.S_un.S_un_b.s_b2,
  7236. saddrinTemp.sin_addr.S_un.S_un_b.s_b3,
  7237. saddrinTemp.sin_addr.S_un.S_un_b.s_b4,
  7238. pDevice);
  7239. pDevice->NoteLocalPASTServerIsPFWOnly();
  7240. }
  7241. }
  7242. else
  7243. {
  7244. //
  7245. // A remote PAST server.
  7246. //
  7247. }
  7248. //
  7249. // Free the temporary port, because we don't need it.
  7250. //
  7251. hr = this->FreePASTPort(pTempRegisteredPort, fRemote);
  7252. if (hr != DPNH_OK)
  7253. {
  7254. DPFX(DPFPREP, 0, "Couldn't free temporary port mapping (0x%lx)!", hr);
  7255. //
  7256. // We'll treat this as non-fatal, but we have to drop the PAST
  7257. // server.
  7258. //
  7259. this->ClearDevicesPASTServer(pDevice, fRemote);
  7260. hr = DPNH_OK;
  7261. }
  7262. }
  7263. //
  7264. // If we're here we either never mapped the temporary port, explicitly
  7265. // freed the port, or deregistered (which implies freeing the port). So
  7266. // we're done with the object.
  7267. //
  7268. pTempRegisteredPort->ClearDeviceOwner();
  7269. pTempRegisteredPort->ClearPrivateAddresses();
  7270. delete pTempRegisteredPort;
  7271. pTempRegisteredPort = NULL;
  7272. Exit:
  7273. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  7274. return hr;
  7275. Failure:
  7276. if (pTempRegisteredPort != NULL)
  7277. {
  7278. delete pTempRegisteredPort;
  7279. }
  7280. goto Exit;
  7281. } // CNATHelpPAST::UpdatePASTPublicAddressValidity
  7282. #undef DPF_MODNAME
  7283. #define DPF_MODNAME "CNATHelpPAST::RegisterAllPortsWithPAST"
  7284. //=============================================================================
  7285. // CNATHelpPAST::RegisterAllPortsWithPAST
  7286. //-----------------------------------------------------------------------------
  7287. //
  7288. // Description: Registers all ports owned by the given device with the PAST
  7289. // server.
  7290. //
  7291. // The object lock is assumed to be held.
  7292. //
  7293. // Arguments:
  7294. // CDevice * pDevice - Pointer to device whose ports should be registered.
  7295. // BOOL fRemote - TRUE if registering on remote server, FALSE if
  7296. // registering on local server.
  7297. //
  7298. // Returns: HRESULT
  7299. // DPNH_OK - The extension was successful.
  7300. // DPNHERR_GENERIC - An error occurred.
  7301. //=============================================================================
  7302. HRESULT CNATHelpPAST::RegisterAllPortsWithPAST(CDevice * const pDevice,
  7303. const BOOL fRemote)
  7304. {
  7305. HRESULT hr = DPNH_OK;
  7306. CBilink * pBilink;
  7307. CRegisteredPort * pRegisteredPort;
  7308. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)",
  7309. this, pDevice, fRemote);
  7310. DNASSERT(pDevice != NULL);
  7311. DNASSERT(pDevice->GetPASTSocket() != INVALID_SOCKET);
  7312. pBilink = pDevice->m_blOwnedRegPorts.GetNext();
  7313. while (pBilink != &pDevice->m_blOwnedRegPorts)
  7314. {
  7315. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  7316. DNASSERT(pRegisteredPort->GetPASTBindID(fRemote) == 0);
  7317. hr = this->AssignOrListenPASTPort(pRegisteredPort, fRemote);
  7318. if (hr != DPNH_OK)
  7319. {
  7320. if (hr != DPNHERR_PORTUNAVAILABLE)
  7321. {
  7322. DPFX(DPFPREP, 0, "Couldn't assign port mapping with server (0x%lx)! Ignoring.", hr);
  7323. //
  7324. // We'll treat this as non-fatal, but we have to dump the
  7325. // server and bail out of here.
  7326. //
  7327. this->ClearDevicesPASTServer(pDevice, fRemote);
  7328. hr = DPNH_OK;
  7329. goto Exit;
  7330. }
  7331. //
  7332. // Uh oh, the server couldn't register one of the ports! We don't
  7333. // have a way of directly informing the user now. We'll have to
  7334. // mark the port and continue.
  7335. //
  7336. DPFX(DPFPREP, 1, "Server indicated that the port was unavailable.");
  7337. pRegisteredPort->NotePASTPortUnavailable(fRemote);
  7338. hr = DPNH_OK;
  7339. }
  7340. else
  7341. {
  7342. //
  7343. // Hey, this now has an address.
  7344. //
  7345. DPFX(DPFPREP, 2, "Previously registered port 0x%p now has a %s PAST server public address.",
  7346. pRegisteredPort, ((fRemote) ? _T("remote") : _T("local")));
  7347. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  7348. }
  7349. pBilink = pBilink->GetNext();
  7350. }
  7351. Exit:
  7352. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  7353. return hr;
  7354. } // CNATHelpPAST::RegisterAllPortsWithPAST
  7355. #undef DPF_MODNAME
  7356. #define DPF_MODNAME "CNATHelpPAST::RegisterPreviouslyUnownedPortsWithDevice"
  7357. //=============================================================================
  7358. // CNATHelpPAST::RegisterPreviouslyUnownedPortsWithDevice
  7359. //-----------------------------------------------------------------------------
  7360. //
  7361. // Description: Associates unknown ports with the given device, and
  7362. // registers them with the device's PAST server(s).
  7363. //
  7364. // If fWildcardToo is FALSE, only previously unowned ports that
  7365. // match the device's address are associated. If TRUE, unowned
  7366. // INADDR_ANY ports are associated as well.
  7367. //
  7368. // The object lock is assumed to be held.
  7369. //
  7370. // Arguments:
  7371. // CDevice * pDevice - Pointer to device to take ownership of ports.
  7372. // BOOL fAll - Whether all ports should be associated.
  7373. //
  7374. // Returns: HRESULT
  7375. // DPNH_OK - The extension was successful.
  7376. // DPNHERR_GENERIC - An error occurred.
  7377. //=============================================================================
  7378. HRESULT CNATHelpPAST::RegisterPreviouslyUnownedPortsWithDevice(CDevice * const pDevice,
  7379. const BOOL fWildcardToo)
  7380. {
  7381. HRESULT hr = DPNH_OK;
  7382. CBilink * pBilink;
  7383. CRegisteredPort * pRegisteredPort;
  7384. SOCKADDR_IN * pasaddrinPrivate;
  7385. #ifdef DBG
  7386. BOOL fAssignedPort = FALSE;
  7387. IN_ADDR inaddrTemp;
  7388. #endif // DBG
  7389. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i)",
  7390. this, pDevice, fWildcardToo);
  7391. //
  7392. // Loop through all unowned ports, assign them to the device if
  7393. // appropriate, then register them.
  7394. //
  7395. pBilink = this->m_blUnownedPorts.GetNext();
  7396. while (pBilink != &this->m_blUnownedPorts)
  7397. {
  7398. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  7399. pBilink = pBilink->GetNext();
  7400. //
  7401. // The registered port must match the device's address in order to
  7402. // associate them. If wildcards are allowed, then INADDR_ANY
  7403. // registrations can be associated, too.
  7404. //
  7405. //
  7406. // All addresses should be same (if there are more than one), so just
  7407. // compare the first one in the array.
  7408. //
  7409. pasaddrinPrivate = pRegisteredPort->GetPrivateAddressesArray();
  7410. if (pasaddrinPrivate[0].sin_addr.S_un.S_addr != pDevice->GetLocalAddressV4())
  7411. {
  7412. if (pasaddrinPrivate[0].sin_addr.S_un.S_addr != INADDR_ANY)
  7413. {
  7414. DPFX(DPFPREP, 7, "Unowned registered port 0x%p private address %u.%u.%u.%u doesn't match device 0x%p's, skipping.",
  7415. pRegisteredPort,
  7416. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b1,
  7417. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b2,
  7418. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b3,
  7419. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b4,
  7420. pDevice);
  7421. continue;
  7422. }
  7423. #ifdef DBG
  7424. inaddrTemp.S_un.S_addr = pDevice->GetLocalAddressV4();
  7425. #endif // DBG
  7426. if (! fWildcardToo)
  7427. {
  7428. #ifdef DBG
  7429. DPFX(DPFPREP, 7, "Unowned registered port 0x%p (INADDR_ANY) not allowed to be associated with device 0x%p (address %u.%u.%u.%u), skipping.",
  7430. pRegisteredPort,
  7431. pDevice,
  7432. inaddrTemp.S_un.S_un_b.s_b1,
  7433. inaddrTemp.S_un.S_un_b.s_b2,
  7434. inaddrTemp.S_un.S_un_b.s_b3,
  7435. inaddrTemp.S_un.S_un_b.s_b4);
  7436. #endif // DBG
  7437. continue;
  7438. }
  7439. #ifdef DBG
  7440. DPFX(DPFPREP, 7, "Unowned registered port 0x%p (INADDR_ANY) becoming associated with device 0x%p (address %u.%u.%u.%u).",
  7441. pRegisteredPort,
  7442. pDevice,
  7443. inaddrTemp.S_un.S_un_b.s_b1,
  7444. inaddrTemp.S_un.S_un_b.s_b2,
  7445. inaddrTemp.S_un.S_un_b.s_b3,
  7446. inaddrTemp.S_un.S_un_b.s_b4);
  7447. #endif // DBG
  7448. }
  7449. else
  7450. {
  7451. DPFX(DPFPREP, 7, "Unowned registered port 0x%p private address %u.%u.%u.%u matches device 0x%p's, associating.",
  7452. pRegisteredPort,
  7453. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b1,
  7454. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b2,
  7455. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b3,
  7456. pasaddrinPrivate[0].sin_addr.S_un.S_un_b.s_b4,
  7457. pDevice);
  7458. //
  7459. // The way it's currently implemented, all non-wildcard ports
  7460. // should be registered before we even try to register the wildcard
  7461. // ones.
  7462. //
  7463. DNASSERT(! fWildcardToo);
  7464. }
  7465. //
  7466. // If we made it here, we can associate the port with the device.
  7467. //
  7468. pRegisteredPort->m_blDeviceList.RemoveFromList();
  7469. pRegisteredPort->MakeDeviceOwner(pDevice);
  7470. //
  7471. // Attempt to automatically map it with the (new) local server, if
  7472. // present.
  7473. //
  7474. if (pDevice->GetPASTClientID(FALSE) != 0)
  7475. {
  7476. hr = this->AssignOrListenPASTPort(pRegisteredPort, FALSE);
  7477. if (hr != DPNH_OK)
  7478. {
  7479. if (hr != DPNHERR_PORTUNAVAILABLE)
  7480. {
  7481. DPFX(DPFPREP, 0, "Couldn't assign port mapping 0x%p with local server (0x%lx)! Ignoring.",
  7482. pRegisteredPort, hr);
  7483. //
  7484. // We'll treat this as non-fatal, but we have to dump the
  7485. // server.
  7486. //
  7487. this->ClearDevicesPASTServer(pDevice, FALSE);
  7488. }
  7489. else
  7490. {
  7491. //
  7492. // Uh oh, the server couldn't register one of the ports!
  7493. // We don't have a way of directly informing the user now.
  7494. // We'll have to mark the port and continue.
  7495. //
  7496. DPFX(DPFPREP, 1, "Local PAST server indicated that the port (0x%p) was unavailable.",
  7497. pRegisteredPort);
  7498. pRegisteredPort->NotePASTPortUnavailable(FALSE);
  7499. }
  7500. hr = DPNH_OK;
  7501. }
  7502. else
  7503. {
  7504. //
  7505. // Ta da, user needs to note address mapping changes.
  7506. //
  7507. DPFX(DPFPREP, 1, "Previously unowned port 0x%p now bound to device object 0x%p and mapped locally.",
  7508. pRegisteredPort, pDevice);
  7509. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  7510. #ifdef DBG
  7511. fAssignedPort = TRUE;
  7512. #endif // DBG
  7513. }
  7514. }
  7515. //
  7516. // Attempt to automatically map it with the (new) remote PAST server,
  7517. // if present.
  7518. //
  7519. if (pDevice->GetPASTClientID(TRUE) != 0)
  7520. {
  7521. hr = this->AssignOrListenPASTPort(pRegisteredPort, TRUE);
  7522. if (hr != DPNH_OK)
  7523. {
  7524. if (hr != DPNHERR_PORTUNAVAILABLE)
  7525. {
  7526. DPFX(DPFPREP, 0, "Couldn't assign port mapping 0x%p with remote PAST server (0x%lx)! Ignoring.",
  7527. pRegisteredPort, hr);
  7528. //
  7529. // We'll treat this as non-fatal, but we have to dump the
  7530. // server.
  7531. //
  7532. this->ClearDevicesPASTServer(pDevice, TRUE);
  7533. }
  7534. else
  7535. {
  7536. //
  7537. // Uh oh, the server couldn't register one of the ports!
  7538. // We don't have a way of directly informing the user now.
  7539. // We'll have to mark the port and continue.
  7540. //
  7541. DPFX(DPFPREP, 1, "Remote PAST server indicated that the port (0x%p) was unavailable.",
  7542. pRegisteredPort);
  7543. pRegisteredPort->NotePASTPortUnavailable(TRUE);
  7544. }
  7545. hr = DPNH_OK;
  7546. }
  7547. else
  7548. {
  7549. //
  7550. // Ta da, user needs to note address mapping changes.
  7551. //
  7552. DPFX(DPFPREP, 1, "Previously unowned port 0x%p now bound to device object 0x%p and mapped remotely.",
  7553. pRegisteredPort, pDevice);
  7554. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  7555. #ifdef DBG
  7556. fAssignedPort = TRUE;
  7557. #endif // DBG
  7558. }
  7559. }
  7560. }
  7561. #ifdef DBG
  7562. if (! fAssignedPort)
  7563. {
  7564. DPFX(DPFPREP, 1, "No unowned ports were bound to device object 0x%p.",
  7565. pDevice);
  7566. }
  7567. #endif // DBG
  7568. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  7569. return hr;
  7570. } // CNATHelpPAST::RegisterPreviouslyUnownedPortsWithDevice
  7571. #undef DPF_MODNAME
  7572. #define DPF_MODNAME "CNATHelpPAST::ExchangeAndParsePAST"
  7573. //=============================================================================
  7574. // CNATHelpPAST::ExchangeAndParsePAST
  7575. //-----------------------------------------------------------------------------
  7576. //
  7577. // Description: Sends a message to the PAST server and waits for a response,
  7578. // which is parsed into a PAST_RESPONSE_INFO buffer. The message
  7579. // will be continually retried at the current retry interval
  7580. // unless ptuRetry == NULL, which indicates that this is the
  7581. // initial message looking for a server, in which case it will be
  7582. // tried twice over a second. If there is no response,
  7583. // DPNHERR_SERVERNOTRESPONDING is returned.
  7584. //
  7585. // Since there is almost no scenario where we don't immediately
  7586. // need to know the response, there is no point in doing this
  7587. // asynchronously. The assumption is that a PAST server is
  7588. // sufficiently local that long retries are not necessary.
  7589. //
  7590. // Arguments:
  7591. // SOCKET sSocket - Socket to use when sending.
  7592. // SOCKADDR * psaddrServerAddress - Pointer to address of server.
  7593. // int iAddressesSize - Size of psaddrServerAddress and
  7594. // psaddrRecvAddress.
  7595. // char * pcRequestBuffer - Pointer to request message to send.
  7596. // int iRequestBufferSize - Size of request message.
  7597. // DWORD dwMsgID - ID of the message being sent (to
  7598. // correlate responses).
  7599. // DWORD * ptuRetry - Pointer to current retry time value
  7600. // (may be modified), or NULL if this is
  7601. // an initial registration (a different
  7602. // timer strategy is used).
  7603. // PAST_RESPONSE_INFO * pRespInfo - Pointer to structure that will be filled
  7604. // in with values from the server's
  7605. // response message.
  7606. //
  7607. // Returns: HRESULT
  7608. // DPNH_OK - The request and response were
  7609. // successfully exchanged.
  7610. // DPNHERR_GENERIC - An error occurred.
  7611. // DPNHERR_SERVERNOTRESPONDING - The server did not respond to the message.
  7612. //=============================================================================
  7613. HRESULT CNATHelpPAST::ExchangeAndParsePAST(const SOCKET sSocket,
  7614. const SOCKADDR * const psaddrServerAddress,
  7615. const int iAddressesSize,
  7616. const char * const pcRequestBuffer,
  7617. const int iRequestBufferSize,
  7618. const DWORD dwMsgID,
  7619. DWORD * const ptuRetry,
  7620. PAST_RESPONSE_INFO * const pRespInfo)
  7621. {
  7622. HRESULT hr = DPNH_OK;
  7623. char acRespBuffer[PAST_RESPONSE_BUFFER_SIZE];
  7624. timeval tv;
  7625. FD_SET fdsRead;
  7626. DWORD dwTriesRemaining;
  7627. int iReturn;
  7628. SOCKADDR_IN saddrinReceive;
  7629. int iRecvAddressSize = iAddressesSize;
  7630. DWORD dwError;
  7631. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, 0x%p, %i, 0x%p, %i, %u, 0x%p, 0x%p)",
  7632. this, sSocket, psaddrServerAddress, iAddressesSize, pcRequestBuffer,
  7633. iRequestBufferSize, dwMsgID, ptuRetry, pRespInfo);
  7634. DNASSERT(sSocket != INVALID_SOCKET);
  7635. DNASSERT(psaddrServerAddress != NULL);
  7636. DNASSERT(iAddressesSize == sizeof(SOCKADDR_IN));
  7637. DNASSERT(pcRequestBuffer != NULL);
  7638. DNASSERT(iRequestBufferSize != 0);
  7639. DNASSERT(pRespInfo != NULL);
  7640. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  7641. ZeroMemory(pRespInfo, sizeof(*pRespInfo));
  7642. #ifdef DBG
  7643. ZeroMemory(acRespBuffer, sizeof(acRespBuffer));
  7644. #endif // DBG
  7645. if (ptuRetry == NULL)
  7646. {
  7647. //
  7648. // On initial registration requests we try twice with a 250ms total
  7649. // timeout.
  7650. //
  7651. tv.tv_usec = PAST_CONNECT_RETRY_INTERVAL_US;
  7652. tv.tv_sec = 0;
  7653. dwTriesRemaining = MAX_NUM_PAST_TRIES_CONNECT;
  7654. }
  7655. else
  7656. {
  7657. //
  7658. // All normal traffic uses the current retry interval and a default
  7659. // number of tries.
  7660. //
  7661. tv.tv_usec = (*ptuRetry);
  7662. tv.tv_sec = 0;
  7663. dwTriesRemaining = MAX_NUM_PAST_TRIES;
  7664. }
  7665. FD_ZERO(&fdsRead);
  7666. FD_SET(sSocket, &fdsRead);
  7667. //
  7668. // First clear out any extraneous responses from previous communication.
  7669. //
  7670. while (this->m_pfnselect(0, &fdsRead, NULL, NULL, &s_tv0) != 0)
  7671. {
  7672. iReturn = this->m_pfnrecvfrom(sSocket,
  7673. acRespBuffer,
  7674. sizeof(acRespBuffer),
  7675. 0,
  7676. (SOCKADDR*) (&saddrinReceive),
  7677. &iRecvAddressSize);
  7678. if ((iReturn == 0) || (iReturn == SOCKET_ERROR))
  7679. {
  7680. dwError = this->m_pfnWSAGetLastError();
  7681. //
  7682. // WSAENOBUFS means WinSock is out of memory.
  7683. //
  7684. if (dwError == WSAENOBUFS)
  7685. {
  7686. DPFX(DPFPREP, 0, "WinSock returned WSAENOBUFS while clearing incoming queue!");
  7687. hr = DPNHERR_OUTOFMEMORY;
  7688. goto Failure;
  7689. }
  7690. //
  7691. // Ignore WSAECONNRESET, that's just WinSock's way of telling us
  7692. // that the target actively refused a previous message we tried to
  7693. // send. Since we don't know which send WinSock means, we can't do
  7694. // a whole lot about it.
  7695. //
  7696. if (dwError != WSAECONNRESET)
  7697. {
  7698. DPFX(DPFPREP, 0, "Got sockets error %u trying to receive (clearing incoming queue)!", dwError);
  7699. hr = DPNHERR_GENERIC;
  7700. goto Failure;
  7701. }
  7702. DPFX(DPFPREP, 2, "Ignoring CONNRESET while clearing incoming queue.");
  7703. }
  7704. else
  7705. {
  7706. //
  7707. // If we got here, that means there's a message.
  7708. //
  7709. #ifdef DBG
  7710. DPFX(DPFPREP, 2, "Found extra response from previous PAST request (sent by %u.%u.%u.%u:%u), parsing for fun.",
  7711. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  7712. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  7713. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  7714. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  7715. NTOHS(saddrinReceive.sin_port));
  7716. //
  7717. // For grins, let's see what this message is. Ignore errors.
  7718. //
  7719. this->ParsePASTMessage(acRespBuffer, iReturn, pRespInfo);
  7720. ZeroMemory(pRespInfo, sizeof(*pRespInfo));
  7721. #endif // DBG
  7722. if (ptuRetry != NULL)
  7723. {
  7724. //
  7725. // Don't re-try so quickly, since responses to our retries are
  7726. // lagging.
  7727. //
  7728. if ((*ptuRetry) < MAX_PAST_RETRY_TIME_US)
  7729. {
  7730. (*ptuRetry) *= 2;
  7731. DPFX(DPFPREP, 8, "Backing initial retry timer off to %u usec.",
  7732. (*ptuRetry));
  7733. }
  7734. }
  7735. }
  7736. DNASSERT(iRecvAddressSize == iAddressesSize);
  7737. FD_ZERO(&fdsRead);
  7738. FD_SET(sSocket, &fdsRead);
  7739. }
  7740. //
  7741. // Now do the exchange, get a response to the request (does retries too).
  7742. //
  7743. do
  7744. {
  7745. DPFX(DPFPREP, 7, "Sending PAST request type %u (%i bytes, msg id = %u) to server (%u.%u.%u.%u:%u).",
  7746. ((PPAST_MSG) pcRequestBuffer)->msgtype, iRequestBufferSize, dwMsgID,
  7747. ((SOCKADDR_IN*) psaddrServerAddress)->sin_addr.S_un.S_un_b.s_b1,
  7748. ((SOCKADDR_IN*) psaddrServerAddress)->sin_addr.S_un.S_un_b.s_b2,
  7749. ((SOCKADDR_IN*) psaddrServerAddress)->sin_addr.S_un.S_un_b.s_b3,
  7750. ((SOCKADDR_IN*) psaddrServerAddress)->sin_addr.S_un.S_un_b.s_b4,
  7751. NTOHS(((SOCKADDR_IN*) psaddrServerAddress)->sin_port));
  7752. //
  7753. // First, send off the request.
  7754. //
  7755. iReturn = this->m_pfnsendto(sSocket,
  7756. pcRequestBuffer,
  7757. iRequestBufferSize,
  7758. 0,
  7759. psaddrServerAddress,
  7760. iAddressesSize);
  7761. if (iReturn == SOCKET_ERROR)
  7762. {
  7763. #ifdef DBG
  7764. dwError = this->m_pfnWSAGetLastError();
  7765. DPFX(DPFPREP, 0, "Got sockets error %u when sending to PAST gateway!", dwError);
  7766. #endif // DBG
  7767. //
  7768. // It's possible that we caught WinSock at a bad time,
  7769. // particularly with WSAEADDRNOTAVAIL (10049), which seems to
  7770. // occur if the address is going away (and we haven't detected
  7771. // it in CheckForNewDevices yet).
  7772. //
  7773. // Break out of the receive loop, which should result in the
  7774. // DPNHERR_SERVERNOTRESPONDING error.
  7775. //
  7776. break;
  7777. }
  7778. if (iReturn != iRequestBufferSize)
  7779. {
  7780. DPFX(DPFPREP, 0, "Didn't send entire datagram (%i != %i)?!", iReturn, iRequestBufferSize);
  7781. DNASSERT(FALSE);
  7782. hr = DPNHERR_GENERIC;
  7783. goto Failure;
  7784. }
  7785. //
  7786. // Now see if we get a response.
  7787. //
  7788. Wait:
  7789. FD_ZERO(&fdsRead);
  7790. FD_SET(sSocket, &fdsRead);
  7791. iReturn = this->m_pfnselect(0, &fdsRead, NULL, NULL, &tv);
  7792. if (iReturn == SOCKET_ERROR)
  7793. {
  7794. #ifdef DBG
  7795. dwError = this->m_pfnWSAGetLastError();
  7796. DPFX(DPFPREP, 0, "Got sockets error %u trying to select on PAST socket!", dwError);
  7797. #endif // DBG
  7798. hr = DPNHERR_GENERIC;
  7799. goto Failure;
  7800. }
  7801. //
  7802. // If our socket was signalled, there's data to read.
  7803. //
  7804. //if (FD_ISSET(sSocket, &fdsRead))
  7805. if (this->m_pfn__WSAFDIsSet(sSocket, &fdsRead))
  7806. {
  7807. iReturn = this->m_pfnrecvfrom(sSocket,
  7808. acRespBuffer,
  7809. sizeof(acRespBuffer),
  7810. 0,
  7811. (SOCKADDR*) (&saddrinReceive),
  7812. &iRecvAddressSize);
  7813. if ((iReturn == 0) || (iReturn == SOCKET_ERROR))
  7814. {
  7815. dwError = this->m_pfnWSAGetLastError();
  7816. //
  7817. // If we get WSAECONNRESET here, we can probably assume that
  7818. // it's because of the message we just sent. That means that
  7819. // there's no PAST server on the gateway.
  7820. //
  7821. if (dwError == WSAECONNRESET)
  7822. {
  7823. if (ptuRetry == NULL)
  7824. {
  7825. DPFX(DPFPREP, 2, "Got CONNRESET while waiting for initial registration response, assuming no PAST server.");
  7826. }
  7827. else
  7828. {
  7829. DPFX(DPFPREP, 0, "Got CONNRESET while waiting for PAST server response!");
  7830. }
  7831. //
  7832. // Break out of the loop, it should result in the
  7833. // DPNHERR_SERVERNOTRESPONDING error code.
  7834. //
  7835. break;
  7836. }
  7837. //
  7838. // WSAENOBUFS means WinSock is out of memory.
  7839. //
  7840. if (dwError == WSAENOBUFS)
  7841. {
  7842. DPFX(DPFPREP, 0, "WinSock returned WSAENOBUFS when waiting for response!");
  7843. hr = DPNHERR_OUTOFMEMORY;
  7844. }
  7845. else
  7846. {
  7847. DPFX(DPFPREP, 0, "Got sockets error %u trying to receive (waiting for response)!", dwError);
  7848. hr = DPNHERR_GENERIC;
  7849. }
  7850. goto Failure;
  7851. }
  7852. //
  7853. // We got some data.
  7854. //
  7855. DNASSERT(iRecvAddressSize == iAddressesSize);
  7856. hr = this->ParsePASTMessage(acRespBuffer, iReturn, pRespInfo);
  7857. if (hr != DPNH_OK)
  7858. {
  7859. //
  7860. // We couldn't handle the response, try again (without touching
  7861. // the remaining tries or backoff timer).
  7862. //
  7863. DPFX(DPFPREP, 0, "Failed parsing message from %u.%u.%u.%u:%u (err = %lx), ignoring.",
  7864. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  7865. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  7866. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  7867. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  7868. NTOHS(saddrinReceive.sin_port),
  7869. hr);
  7870. goto Wait;
  7871. }
  7872. if (saddrinReceive.sin_addr.S_un.S_addr != ((SOCKADDR_IN*) psaddrServerAddress)->sin_addr.S_un.S_addr)
  7873. {
  7874. //
  7875. // This message is not from the server to which we sent the
  7876. // request. Ignore it.
  7877. //
  7878. DPFX(DPFPREP, 0, "Got message from unexpected source (%u.%u.%u.%u:%u), ignoring %i byte message.",
  7879. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  7880. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  7881. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  7882. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  7883. NTOHS(saddrinReceive.sin_port),
  7884. iReturn);
  7885. goto Wait;
  7886. }
  7887. if (pRespInfo->dwMsgID != dwMsgID)
  7888. {
  7889. //
  7890. // We got a response to a different message, try again
  7891. // (without touching the remaining tries or backoff timer).
  7892. //
  7893. DPFX(DPFPREP, 0, "Got messageid %u, expecting messageid %u, ignoring %i byte message.",
  7894. pRespInfo->dwMsgID, dwMsgID, iReturn);
  7895. goto Wait;
  7896. }
  7897. //
  7898. // If we got here, then it looks like we got the response we want.
  7899. // We're done.
  7900. //
  7901. DPFX(DPFPREP, 8, "Received expected messageid %u from %u.%u.%u.%u:%u, it's %i bytes.",
  7902. pRespInfo->dwMsgID,
  7903. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  7904. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  7905. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  7906. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  7907. NTOHS(saddrinReceive.sin_port),
  7908. iReturn);
  7909. goto Exit;
  7910. }
  7911. //
  7912. // The initial registration attempt is a special case since we don't
  7913. // know if the server exists or not. Once we're registered, we expect
  7914. // the server to be available, so we'll retry more times and
  7915. // temporarily back off further each time.
  7916. //
  7917. if (ptuRetry != NULL)
  7918. {
  7919. tv.tv_usec *= 2; // exponential backoff.
  7920. DPFX(DPFPREP, 7, "Didn't get response, increasing temporary timeout value to %u.", tv.tv_usec);
  7921. }
  7922. dwTriesRemaining--;
  7923. }
  7924. while (dwTriesRemaining > 0);
  7925. //
  7926. // If we got here, it means we didn't get a response.
  7927. //
  7928. hr = DPNHERR_SERVERNOTRESPONDING;
  7929. //goto Failure;
  7930. Exit:
  7931. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  7932. return hr;
  7933. Failure:
  7934. goto Exit;
  7935. } // CNATHelpPAST::ExchangeAndParsePAST
  7936. #undef DPF_MODNAME
  7937. #define DPF_MODNAME "CNATHelpPAST::RegisterMultipleDevicesWithRemotePAST"
  7938. //=============================================================================
  7939. // CNATHelpPAST::RegisterMultipleDevicesWithRemotePAST
  7940. //-----------------------------------------------------------------------------
  7941. //
  7942. // Description: Sends a registration message to the remote PAST server for
  7943. // all the devices in the temporary pSourceList simultaneously
  7944. // and waits for replies. A pointer to the first device that
  7945. // successfully registers with a remote PAST server will be placed
  7946. // in ppFirstDeviceWithRemoteServer. All devices will be removed
  7947. // removed from pSourceList.
  7948. //
  7949. // The object lock is assumed to be held.
  7950. //
  7951. // Arguments:
  7952. // CBilink * pSourceList - Temporary bilink with all
  7953. // devices to check. Will be
  7954. // emptied.
  7955. // CDevice ** ppFirstDeviceWithRemoteServer - Place to store first device
  7956. // which successfully
  7957. // registers with a remote
  7958. // PAST server
  7959. //
  7960. // Returns: HRESULT
  7961. // DPNH_OK - The devices were successfully handled.
  7962. // DPNHERR_GENERIC - An error occurred.
  7963. //=============================================================================
  7964. HRESULT CNATHelpPAST::RegisterMultipleDevicesWithRemotePAST(CBilink * pSourceList,
  7965. CDevice ** ppFirstDeviceWithRemoteServer)
  7966. {
  7967. HRESULT hr;
  7968. CBilink * pBilink;
  7969. CDevice * pDevice;
  7970. CBilink * pBilinkSameGateway;
  7971. CDevice * pDeviceSameGateway;
  7972. char acRespBuffer[PAST_RESPONSE_BUFFER_SIZE];
  7973. timeval tv;
  7974. FD_SET fdsRead;
  7975. int iReturn;
  7976. PAST_MSG_REGISTER RegisterReq;
  7977. SOCKADDR_IN saddrinServerAddress;
  7978. int iRecvAddressSize = sizeof(SOCKADDR_IN);
  7979. PAST_RESPONSE_INFO RespInfo;
  7980. DWORD dwError;
  7981. DWORD dwTry;
  7982. DWORD dwFinishTime;
  7983. DWORD dwTimeRemaining;
  7984. SOCKADDR_IN saddrinReceive;
  7985. DPFX(DPFPREP, 5, "(0x%p) Parameters (0x%p, 0x%p)",
  7986. this, pSourceList, ppFirstDeviceWithRemoteServer);
  7987. DNASSERT(this->m_dwFlags & NATHELPPASTOBJ_INITIALIZED);
  7988. #ifdef DBG
  7989. ZeroMemory(acRespBuffer, sizeof(acRespBuffer));
  7990. #endif // DBG
  7991. //
  7992. // Loop through each device.
  7993. //
  7994. pBilink = pSourceList->GetNext();
  7995. while (pBilink != pSourceList)
  7996. {
  7997. pDevice = DEVICE_FROM_TEMP_BILINK(pBilink);
  7998. pBilink = pBilink->GetNext();
  7999. DNASSERT(pDevice->GetPASTClientID(TRUE) == 0);
  8000. //
  8001. // Create the temporary set.
  8002. //
  8003. FD_ZERO(&fdsRead);
  8004. FD_SET(pDevice->GetPASTSocket(), &fdsRead);
  8005. //
  8006. // Try to get the device's gateway's address. This might return FALSE
  8007. // if the device does not have a gateway. In that case, we will ignore
  8008. // the device. Otherwise the address should be filled in with the
  8009. // gateway or broadcast address.
  8010. //
  8011. if (! this->GetAddressToReachGateway(pDevice,
  8012. &saddrinServerAddress.sin_addr))
  8013. {
  8014. DPFX(DPFPREP, 2, "Device 0x%p should not attempt to reach a gateway.",
  8015. pDevice);
  8016. //
  8017. // Take it out of the list, but continue.
  8018. //
  8019. pDevice->m_blTempList.RemoveFromList();
  8020. }
  8021. else
  8022. {
  8023. //
  8024. // Store the address with the device for use below.
  8025. //
  8026. pDevice->SetRemotePASTServerAddressV4(saddrinServerAddress.sin_addr.S_un.S_addr);
  8027. //
  8028. // Clear out any extraneous responses from previous communication.
  8029. //
  8030. while (this->m_pfnselect(0, &fdsRead, NULL, NULL, &s_tv0) != 0)
  8031. {
  8032. iReturn = this->m_pfnrecvfrom(pDevice->GetPASTSocket(),
  8033. acRespBuffer,
  8034. sizeof(acRespBuffer),
  8035. 0,
  8036. (SOCKADDR*) (&saddrinReceive),
  8037. &iRecvAddressSize);
  8038. if ((iReturn == 0) || (iReturn == SOCKET_ERROR))
  8039. {
  8040. dwError = this->m_pfnWSAGetLastError();
  8041. //
  8042. // Ignore WSAECONNRESET, that's just WinSock's way of
  8043. // telling us that the target actively refused a previous
  8044. // message we tried to send. Since we don't know which
  8045. // send WinSock means, we can't do a whole lot about it.
  8046. //
  8047. if (dwError != WSAECONNRESET)
  8048. {
  8049. DPFX(DPFPREP, 0, "Got sockets error %u on device 0x%p trying to receive (clearing incoming queue)! Ignoring.",
  8050. dwError, pDevice);
  8051. //
  8052. // Take it out of the list, but continue.
  8053. //
  8054. pDevice->m_blTempList.RemoveFromList();
  8055. }
  8056. else
  8057. {
  8058. DPFX(DPFPREP, 2, "Ignoring CONNRESET on device 0x%p while clearing incoming queue.",
  8059. pDevice);
  8060. }
  8061. }
  8062. else
  8063. {
  8064. //
  8065. // If we got here, that means there's a message.
  8066. //
  8067. #ifdef DBG
  8068. DPFX(DPFPREP, 2, "Found extra response from previous PAST request on device 0x%p (sent by %u.%u.%u.%u:%u), parsing for fun.",
  8069. pDevice,
  8070. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  8071. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  8072. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  8073. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  8074. NTOHS(saddrinReceive.sin_port));
  8075. //
  8076. // For grins, let's see what this message is. Ignore
  8077. // errors.
  8078. //
  8079. ZeroMemory(&RespInfo, sizeof(RespInfo));
  8080. this->ParsePASTMessage(acRespBuffer, iReturn, &RespInfo);
  8081. #endif // DBG
  8082. }
  8083. DNASSERT(iRecvAddressSize == sizeof(saddrinServerAddress));
  8084. FD_ZERO(&fdsRead);
  8085. FD_SET(pDevice->GetPASTSocket(), &fdsRead);
  8086. }
  8087. } // end else (device can try to reach gateway)
  8088. }
  8089. //
  8090. // If there aren't any devices that aren't registered, we're done.
  8091. //
  8092. if (pSourceList->IsEmpty())
  8093. {
  8094. DPFX(DPFPREP, 8, "No devices remaining to be checked.");
  8095. hr = DPNH_OK;
  8096. goto Exit;
  8097. }
  8098. //
  8099. // Build the registration request message.
  8100. //
  8101. ZeroMemory(&RegisterReq, sizeof(RegisterReq));
  8102. RegisterReq.version = PAST_VERSION;
  8103. RegisterReq.command = PAST_MSGID_REGISTER_REQUEST;
  8104. RegisterReq.msgid.code = PAST_PARAMID_MESSAGEID;
  8105. RegisterReq.msgid.len = sizeof(RegisterReq.msgid) - sizeof(PAST_PARAM);
  8106. //RegisterReq.msgid.msgid = 0; // it always starts at 0 for registration
  8107. ZeroMemory(&saddrinServerAddress, sizeof(saddrinServerAddress));
  8108. saddrinServerAddress.sin_family = AF_INET;
  8109. //saddrinServerAddress.sin_addr = ? // filled in below
  8110. saddrinServerAddress.sin_port = HTONS(PAST_HOST_PORT);
  8111. //
  8112. // Now actually try to register with all the ports. Keep looping until
  8113. // either all devices are registered or we exceed the number of tries.
  8114. //
  8115. for(dwTry = 0; dwTry < MAX_NUM_PAST_TRIES_CONNECT; dwTry++)
  8116. {
  8117. //
  8118. // Send the message for all devices that aren't registered yet.
  8119. //
  8120. pBilink = pSourceList->GetNext();
  8121. while (pBilink != pSourceList)
  8122. {
  8123. pDevice = DEVICE_FROM_TEMP_BILINK(pBilink);
  8124. pBilink = pBilink->GetNext();
  8125. //
  8126. // Remember the current time, if this is the first thing we've sent
  8127. // from this port.
  8128. //
  8129. if (pDevice->GetFirstPASTDiscoveryTime() == 0)
  8130. {
  8131. pDevice->SetFirstPASTDiscoveryTime(GETTIMESTAMP());
  8132. }
  8133. //
  8134. // Retrieve the gateway address we detected above.
  8135. //
  8136. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  8137. //
  8138. // Try sending the registration message.
  8139. //
  8140. DPFX(DPFPREP, 7, "Device 0x%p sending PAST registration request (type %u, %i bytes) to server (%u.%u.%u.%u:%u).",
  8141. pDevice, RegisterReq.command, sizeof(RegisterReq),
  8142. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b1,
  8143. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b2,
  8144. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b3,
  8145. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b4,
  8146. NTOHS(saddrinServerAddress.sin_port));
  8147. iReturn = this->m_pfnsendto(pDevice->GetPASTSocket(),
  8148. (char*) (&RegisterReq),
  8149. sizeof(RegisterReq),
  8150. 0,
  8151. (SOCKADDR*) (&saddrinServerAddress),
  8152. sizeof(saddrinServerAddress));
  8153. if (iReturn == SOCKET_ERROR)
  8154. {
  8155. #ifdef DBG
  8156. dwError = this->m_pfnWSAGetLastError();
  8157. DPFX(DPFPREP, 0, "Device 0x%p got sockets error %u when sending to PAST gateway!",
  8158. pDevice, dwError);
  8159. #endif // DBG
  8160. //
  8161. // It's possible that we caught WinSock at a bad time,
  8162. // particularly with WSAEADDRNOTAVAIL (10049), which seems to
  8163. // occur if the address is going away (and we haven't detected
  8164. // it in CheckForNewDevices yet).
  8165. //
  8166. // Ignore the error, we can survive. Take the out of the list,
  8167. // but continue.
  8168. //
  8169. pDevice->m_blTempList.RemoveFromList();
  8170. //
  8171. // If there aren't any more devices, we can bail.
  8172. //
  8173. if (pSourceList->IsEmpty())
  8174. {
  8175. DPFX(DPFPREP, 1, "Last device got sendto error, exiting gracefully.");
  8176. hr = DPNH_OK;
  8177. goto Exit;
  8178. }
  8179. }
  8180. else
  8181. {
  8182. if (iReturn != sizeof(RegisterReq))
  8183. {
  8184. DPFX(DPFPREP, 0, "Didn't send entire datagram (%i != %i)?!",
  8185. iReturn, sizeof(RegisterReq));
  8186. DNASSERT(FALSE);
  8187. hr = DPNHERR_GENERIC;
  8188. goto Failure;
  8189. }
  8190. }
  8191. }
  8192. //
  8193. // Remember how long to wait for replies to this send attempt.
  8194. //
  8195. dwFinishTime = timeGetTime() + PAST_CONNECT_RETRY_INTERVAL_MS;
  8196. dwTimeRemaining = PAST_CONNECT_RETRY_INTERVAL_MS;
  8197. //
  8198. // Keep looping until all devices are registered or we timeout.
  8199. //
  8200. do
  8201. {
  8202. //
  8203. // Rebuild the socket set.
  8204. //
  8205. FD_ZERO(&fdsRead);
  8206. pBilink = pSourceList->GetNext();
  8207. while (pBilink != pSourceList)
  8208. {
  8209. pDevice = DEVICE_FROM_TEMP_BILINK(pBilink);
  8210. DNASSERT(pDevice->GetPASTClientID(TRUE) == 0);
  8211. FD_SET(pDevice->GetPASTSocket(), &fdsRead);
  8212. //
  8213. // Move to next device
  8214. //
  8215. pBilink = pBilink->GetNext();
  8216. }
  8217. tv.tv_usec = dwTimeRemaining * 1000;
  8218. tv.tv_sec = 0;
  8219. //
  8220. // Wait for data to come in on any of the sockets.
  8221. //
  8222. iReturn = this->m_pfnselect(0, &fdsRead, NULL, NULL, &tv);
  8223. if (iReturn == SOCKET_ERROR)
  8224. {
  8225. #ifdef DBG
  8226. dwError = this->m_pfnWSAGetLastError();
  8227. DPFX(DPFPREP, 0, "Got sockets error %u trying to select on PAST sockets!", dwError);
  8228. #endif // DBG
  8229. hr = DPNHERR_GENERIC;
  8230. goto Failure;
  8231. }
  8232. //
  8233. // Stop looping if we timed out; it's time to repeat the message
  8234. // (or exit, if no more tries left).
  8235. //
  8236. if (iReturn == 0)
  8237. {
  8238. DPFX(DPFPREP, 7, "No more sockets have data, try = %u of %u.",
  8239. (dwTry + 1), MAX_NUM_PAST_TRIES_CONNECT);
  8240. break;
  8241. }
  8242. //
  8243. // If we're here, data came in on at least one of the sockets.
  8244. // Read it and parse it.
  8245. //
  8246. pBilink = pSourceList->GetNext();
  8247. while (pBilink != pSourceList)
  8248. {
  8249. pDevice = DEVICE_FROM_TEMP_BILINK(pBilink);
  8250. pBilink = pBilink->GetNext();
  8251. //
  8252. // If this device's socket is set there's data to read.
  8253. //
  8254. //if (FD_ISSET(pDevice->GetPASTSocket(), &fdsRead))
  8255. if (this->m_pfn__WSAFDIsSet(pDevice->GetPASTSocket(), &fdsRead))
  8256. {
  8257. iReturn = this->m_pfnrecvfrom(pDevice->GetPASTSocket(),
  8258. acRespBuffer,
  8259. sizeof(acRespBuffer),
  8260. 0,
  8261. (SOCKADDR*) (&saddrinReceive),
  8262. &iRecvAddressSize);
  8263. if ((iReturn == 0) || (iReturn == SOCKET_ERROR))
  8264. {
  8265. #ifdef DBG
  8266. dwError = this->m_pfnWSAGetLastError();
  8267. //
  8268. // If we get WSAECONNRESET here, we can probably assume
  8269. // that it's because of the message we just sent. That
  8270. // means that there's no PAST server on the gateway.
  8271. //
  8272. if (dwError == WSAECONNRESET)
  8273. {
  8274. DPFX(DPFPREP, 2, "Got CONNRESET while waiting for registration response on device 0x%p, assuming no PAST server.",
  8275. pDevice);
  8276. }
  8277. else
  8278. {
  8279. DPFX(DPFPREP, 0, "Got sockets error %u trying to receive on device 0x%p (waiting for response)! Ignoring",
  8280. dwError);
  8281. }
  8282. #endif // DBG
  8283. //
  8284. // Take it out of the list, but continue.
  8285. //
  8286. pDevice->m_blTempList.RemoveFromList();
  8287. //
  8288. // We can also be smart and remove any other devices
  8289. // with the same gateway because they will have the
  8290. // same problem; WinSock might not even give another
  8291. // notification for the other sockets. Don't try this
  8292. // trick for the broadcast address, though.
  8293. //
  8294. if (pDevice->GetRemotePASTServerAddressV4() != INADDR_BROADCAST)
  8295. {
  8296. pBilinkSameGateway = pSourceList->GetNext();
  8297. while (pBilinkSameGateway != pSourceList)
  8298. {
  8299. pDeviceSameGateway = DEVICE_FROM_TEMP_BILINK(pBilinkSameGateway);
  8300. pBilinkSameGateway = pBilinkSameGateway->GetNext();
  8301. if (pDeviceSameGateway->GetRemotePASTServerAddressV4() == pDevice->GetRemotePASTServerAddressV4())
  8302. {
  8303. #ifdef DBG
  8304. saddrinServerAddress.sin_addr.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  8305. DPFX(DPFPREP, 3, "Removing device 0x%p, because it shares gateway %u.%u.%u.%u with device 0x%p.",
  8306. pDeviceSameGateway,
  8307. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b1,
  8308. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b2,
  8309. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b3,
  8310. saddrinServerAddress.sin_addr.S_un.S_un_b.s_b4,
  8311. pDevice);
  8312. #endif // DBG
  8313. //
  8314. // Before we remove this similar device,
  8315. // make sure we don't screw up the list of
  8316. // remaining devices. Otherwise, that
  8317. // outer list traversal may get caught in
  8318. // an infinite loop.
  8319. //
  8320. if ((&pDeviceSameGateway->m_blTempList) == pBilink)
  8321. {
  8322. pBilink = pBilink->GetNext();
  8323. }
  8324. pDeviceSameGateway->m_blTempList.RemoveFromList();
  8325. }
  8326. }
  8327. }
  8328. else
  8329. {
  8330. //
  8331. // Sent to broadcast address, can't optimize.
  8332. //
  8333. }
  8334. //
  8335. // If there aren't any more devices, we can bail.
  8336. //
  8337. if (pSourceList->IsEmpty())
  8338. {
  8339. DPFX(DPFPREP, 1, "Last device got recvfrom error, exiting gracefully.");
  8340. hr = DPNH_OK;
  8341. goto Exit;
  8342. }
  8343. }
  8344. else
  8345. {
  8346. //
  8347. // We got some data.
  8348. //
  8349. DNASSERT(iRecvAddressSize == sizeof(saddrinServerAddress));
  8350. ZeroMemory(&RespInfo, sizeof(RespInfo));
  8351. hr = this->ParsePASTMessage(acRespBuffer, iReturn, &RespInfo);
  8352. if (hr != DPNH_OK)
  8353. {
  8354. //
  8355. // We couldn't handle the response, try again.
  8356. //
  8357. DPFX(DPFPREP, 0, "Failed parsing message (err = %lx), ignoring.",
  8358. hr);
  8359. }
  8360. else
  8361. {
  8362. if (RespInfo.dwMsgID != 0)
  8363. {
  8364. //
  8365. // We got a response to a different message,
  8366. // try again.
  8367. //
  8368. DPFX(DPFPREP, 0, "Got messageid %u, expecting messageid 0, ignoring.",
  8369. RespInfo.dwMsgID);
  8370. }
  8371. else
  8372. {
  8373. if (RespInfo.cMsgType != PAST_MSGID_REGISTER_RESPONSE)
  8374. {
  8375. //
  8376. // We got an unxpected response type, try
  8377. // again.
  8378. //
  8379. DPFX(DPFPREP, 0, "Got message type %u, expecting %u, ignoring.",
  8380. RespInfo.cMsgType, PAST_MSGID_REGISTER_RESPONSE);
  8381. }
  8382. else
  8383. {
  8384. //
  8385. // If we got here, then it looks like we
  8386. // got the response we want.
  8387. //
  8388. //
  8389. // If we were broadcasting, accept the
  8390. // first response we receive. Otherwise,
  8391. // throw out the message if it's not from
  8392. // the address we expect.
  8393. //
  8394. if (saddrinServerAddress.sin_addr.S_un.S_addr == INADDR_BROADCAST)
  8395. {
  8396. DPFX(DPFPREP, 4, "Accepting response from PAST server %u.%u.%u.%u:%u.",
  8397. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  8398. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  8399. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  8400. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  8401. NTOHS(saddrinReceive.sin_port));
  8402. pDevice->SetRemotePASTServerAddressV4(saddrinReceive.sin_addr.S_un.S_addr);
  8403. }
  8404. if (pDevice->GetRemotePASTServerAddressV4() == saddrinReceive.sin_addr.S_un.S_addr)
  8405. {
  8406. pDevice->SetPASTClientID(RespInfo.dwClientID, TRUE);
  8407. //
  8408. // Move to the next message ID.
  8409. //
  8410. pDevice->ResetRemotePASTMsgIDAndRetryTimeout(DEFAULT_INITIAL_PAST_RETRY_TIMEOUT);
  8411. pDevice->GetNextRemotePASTMsgID();
  8412. //
  8413. // Pull this device from the list of
  8414. // remaining devices.
  8415. //
  8416. pDevice->m_blTempList.RemoveFromList();
  8417. //
  8418. // Register all the existing mappings
  8419. // associated with the device that the
  8420. // user has already requested.
  8421. //
  8422. if (! pDevice->m_blOwnedRegPorts.IsEmpty())
  8423. {
  8424. hr = this->RegisterAllPortsWithPAST(pDevice, TRUE);
  8425. if (hr != DPNH_OK)
  8426. {
  8427. DPFX(DPFPREP, 0, "Couldn't register all existing ports with remote PAST server!");
  8428. goto Failure;
  8429. }
  8430. #ifdef DBG
  8431. //
  8432. // If we didn't encounter an error
  8433. // that caused the PAST server to
  8434. // be removed, then the
  8435. // NATHELPPASTOBJ_ADDRESSESCHANGED
  8436. // flag must have been set by the
  8437. // AssignOrListenPorts function.
  8438. //
  8439. if (pDevice->GetPASTClientID(TRUE) != 0)
  8440. {
  8441. if (! (this->m_dwFlags & NATHELPPASTOBJ_ADDRESSESCHANGED))
  8442. {
  8443. DPFX(DPFPREP, 1, "Successfully registered with remote PAST server, but no addresses changed; all ports should be unavailable.");
  8444. }
  8445. }
  8446. else
  8447. {
  8448. DPFX(DPFPREP, 1, "Remote PAST server was removed while trying to register existing ports.");
  8449. }
  8450. #endif // DBG
  8451. }
  8452. else
  8453. {
  8454. BOOL fAddressAlreadyChanged;
  8455. DPFX(DPFPREP, 2, "Remote PAST server now available for device 0x%p, but no ports are currently registered.",
  8456. pDevice);
  8457. fAddressAlreadyChanged = (this->m_dwFlags & NATHELPPASTOBJ_ADDRESSESCHANGED) ? TRUE : FALSE;
  8458. //
  8459. // Forcefully check if there's a
  8460. // public address available.
  8461. //
  8462. hr = this->UpdatePASTPublicAddressValidity(pDevice, TRUE);
  8463. if (hr != DPNH_OK)
  8464. {
  8465. DPFX(DPFPREP, 0, "Couldn't update remote PAST server address validity!");
  8466. goto Failure;
  8467. }
  8468. //
  8469. // Prevent the user from thinking
  8470. // the addresses changed unless
  8471. // something else already caused
  8472. // the address change notification.
  8473. //
  8474. if (! fAddressAlreadyChanged)
  8475. {
  8476. this->m_dwFlags &= ~NATHELPPASTOBJ_ADDRESSESCHANGED;
  8477. }
  8478. }
  8479. //
  8480. // Store this device, if it's the first
  8481. // one that successfully registered.
  8482. //
  8483. if ((*ppFirstDeviceWithRemoteServer) == NULL)
  8484. {
  8485. DPFX(DPFPREP, 7, "Saving device 0x%p that was just registered with new remote PAST server.",
  8486. pDevice);
  8487. (*ppFirstDeviceWithRemoteServer) = pDevice;
  8488. }
  8489. else
  8490. {
  8491. DPFX(DPFPREP, 7, "Already have device with remote PAST server 0x%p, not storing newly registered 0x%p.",
  8492. (*ppFirstDeviceWithRemoteServer), pDevice);
  8493. }
  8494. //
  8495. // If there aren't any more devices, we
  8496. // can bail.
  8497. //
  8498. if (pSourceList->IsEmpty())
  8499. {
  8500. DPFX(DPFPREP, 7, "Last device (0x%p) got registered with remote PAST server.",
  8501. pDevice);
  8502. hr = DPNH_OK;
  8503. goto Exit;
  8504. }
  8505. }
  8506. else
  8507. {
  8508. DPFX(DPFPREP, 0, "Ignoring correctly formed message from %u.%u.%u.%u:%u!",
  8509. saddrinReceive.sin_addr.S_un.S_un_b.s_b1,
  8510. saddrinReceive.sin_addr.S_un.S_un_b.s_b2,
  8511. saddrinReceive.sin_addr.S_un.S_un_b.s_b3,
  8512. saddrinReceive.sin_addr.S_un.S_un_b.s_b4,
  8513. NTOHS(saddrinReceive.sin_port));
  8514. }
  8515. } // end else (got correct message type)
  8516. } // end else (got correct message ID)
  8517. } // end else (failed parsing message)
  8518. } // end else (successfully received data)
  8519. }
  8520. else
  8521. {
  8522. //
  8523. // Socket did not receive any data.
  8524. //
  8525. }
  8526. }
  8527. //
  8528. // Calculate how much time remains. If that went negative, loop
  8529. // one extra time (with a timeout of 0). We will bail after the
  8530. // select if no data arrived while we were processing the last
  8531. // round of data.
  8532. //
  8533. dwTimeRemaining = dwFinishTime - timeGetTime();
  8534. if ((int) dwTimeRemaining < 0)
  8535. {
  8536. dwTimeRemaining = 0;
  8537. }
  8538. }
  8539. while (TRUE);
  8540. //
  8541. // Go to next attempt
  8542. //
  8543. }
  8544. //
  8545. // If we're here some devices still do not have remote PAST servers.
  8546. // There should still be items in the temp source list.
  8547. //
  8548. DNASSERT(! pSourceList->IsEmpty());
  8549. //
  8550. // Remove any remaining items from the temp source list.
  8551. //
  8552. pBilink = pSourceList->GetNext();
  8553. while (pBilink != pSourceList)
  8554. {
  8555. pDevice = DEVICE_FROM_TEMP_BILINK(pBilink);
  8556. pBilink = pBilink->GetNext();
  8557. pDevice->m_blTempList.RemoveFromList();
  8558. }
  8559. hr = DPNH_OK;
  8560. Exit:
  8561. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  8562. return hr;
  8563. Failure:
  8564. goto Exit;
  8565. } // CNATHelpPAST::RegisterMultipleDevicesWithRemotePAST
  8566. #undef DPF_MODNAME
  8567. #define DPF_MODNAME "CNATHelpPAST::ParsePASTMessage"
  8568. //=============================================================================
  8569. // CNATHelpPAST::ParsePASTMessage
  8570. //-----------------------------------------------------------------------------
  8571. //
  8572. // Description: Parses a PAST message and extracts the codes into fields in
  8573. // a standardized structure.
  8574. //
  8575. // This is not completely general, as we know that we will only
  8576. // operate with v4 addresses and our commands will never deal with
  8577. // more than 1 address/port at a time. PAST allows for multiple
  8578. // ports to be allocated in a single request, but we do not take
  8579. // advantage of this feature. If you need to handle such multiple
  8580. // address requests and responses, then you will need to change
  8581. // this function.
  8582. //
  8583. // Arguments:
  8584. // char * pcMsg - Pointer to buffer containing a PAST
  8585. // request or response message.
  8586. // int iMsgSize - Size of message buffer in bytes.
  8587. // PAST_RESPONSE_INFO * pRespInfo - Pointer to structure that is filled with
  8588. // the parameters from the PAST message.
  8589. //
  8590. // Returns: HRESULT
  8591. // DPNH_OK - Parsing was successful.
  8592. // DPNHERR_INVALIDPARAM - An invalid buffer was given.
  8593. // DPNHERR_GENERIC - An error occurred.
  8594. //=============================================================================
  8595. HRESULT CNATHelpPAST::ParsePASTMessage(const char * const pcMsg,
  8596. const int iMsgSize,
  8597. PAST_RESPONSE_INFO * const pRespInfo)
  8598. {
  8599. HRESULT hr = DPNH_OK;
  8600. BOOL fGotlAddress = FALSE;
  8601. BOOL fGotlPort = FALSE;
  8602. PPAST_PARAM pParam;
  8603. PPAST_PARAM pNextParam;
  8604. const char * pcEnd;
  8605. char * pcData;
  8606. char cTemp;
  8607. #ifdef DBG
  8608. char szPortList[(DPNH_MAX_SIMULTANEOUS_PORTS * 7) + 1]; // "nnnnn, " + NULL termination
  8609. char * pszTemp;
  8610. #endif // DBG
  8611. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p, %i, 0x%p)",
  8612. this, pcMsg, iMsgSize, pRespInfo);
  8613. if (iMsgSize < 2)
  8614. {
  8615. DPFX(DPFPREP, 0, "Buffer too small to be valid PAST message (%i bytes)!", iMsgSize);
  8616. DNASSERTX(! "Buffer too small to be valid PAST message!", 2);
  8617. hr = DPNHERR_INVALIDPARAM;
  8618. goto Failure;
  8619. }
  8620. pRespInfo->cVersion = ((PPAST_MSG) pcMsg)->version;
  8621. pRespInfo->cMsgType = ((PPAST_MSG) pcMsg)->msgtype;
  8622. DPFX(DPFPREP, 3, "version %u msgtype %u", pRespInfo->cVersion, pRespInfo->cMsgType);
  8623. pParam = (PPAST_PARAM) (pcMsg + sizeof(PAST_MSG));
  8624. pcEnd = pcMsg + iMsgSize;
  8625. while ((char *) (pParam + 1) < pcEnd)
  8626. {
  8627. pcData = (char *) (pParam + 1);
  8628. pNextParam = (PPAST_PARAM) (pcData + pParam->len);
  8629. if ((pParam->len > (iMsgSize - sizeof(PAST_MSG) - sizeof(PAST_PARAM))) ||
  8630. ((char *) pNextParam > pcEnd))
  8631. {
  8632. break;
  8633. }
  8634. switch (pParam->code)
  8635. {
  8636. case PAST_PARAMID_ADDRESS:
  8637. {
  8638. if (pParam->len >= 1)
  8639. {
  8640. //
  8641. // Addresses are type[1]|addr[?]
  8642. //
  8643. if ((*pcData) != PAST_ADDRESSTYPE_IPV4)
  8644. {
  8645. DPFX(DPFPREP, 0, "Got unexpected PAST address code type %u!", (*pcData));
  8646. hr = DPNHERR_GENERIC;
  8647. goto Failure;
  8648. }
  8649. //
  8650. // Validate the size of the address parameter.
  8651. //
  8652. if (pParam->len == 5)
  8653. {
  8654. if (! fGotlAddress)
  8655. {
  8656. CopyMemory(&pRespInfo->dwLocalAddressV4, pcData + 1, 4);
  8657. DPFX(DPFPREP, 3, "Got local address %u.%u.%u.%u.",
  8658. ((IN_ADDR *) (&pRespInfo->dwLocalAddressV4))->S_un.S_un_b.s_b1,
  8659. ((IN_ADDR *) (&pRespInfo->dwLocalAddressV4))->S_un.S_un_b.s_b2,
  8660. ((IN_ADDR *) (&pRespInfo->dwLocalAddressV4))->S_un.S_un_b.s_b3,
  8661. ((IN_ADDR *) (&pRespInfo->dwLocalAddressV4))->S_un.S_un_b.s_b4);
  8662. if ((pRespInfo->dwLocalAddressV4 == INADDR_BROADCAST) ||
  8663. (IS_CLASSD_IPV4_ADDRESS(pRespInfo->dwLocalAddressV4)))
  8664. {
  8665. DPFX(DPFPREP, 1, "Ignoring invalid local address and using INADDR_ANY instead.");
  8666. pRespInfo->dwLocalAddressV4 = 0;
  8667. }
  8668. fGotlAddress = TRUE;
  8669. }
  8670. else
  8671. {
  8672. fGotlPort = TRUE; // just in case there wasn't a local port
  8673. CopyMemory(&pRespInfo->dwRemoteAddressV4, pcData + 1, 4);
  8674. DPFX(DPFPREP, 3, "Got remote address %u.%u.%u.%u.",
  8675. ((IN_ADDR *) (&pRespInfo->dwRemoteAddressV4))->S_un.S_un_b.s_b1,
  8676. ((IN_ADDR *) (&pRespInfo->dwRemoteAddressV4))->S_un.S_un_b.s_b2,
  8677. ((IN_ADDR *) (&pRespInfo->dwRemoteAddressV4))->S_un.S_un_b.s_b3,
  8678. ((IN_ADDR *) (&pRespInfo->dwRemoteAddressV4))->S_un.S_un_b.s_b4);
  8679. if ((pRespInfo->dwRemoteAddressV4 == INADDR_BROADCAST) ||
  8680. (IS_CLASSD_IPV4_ADDRESS(pRespInfo->dwRemoteAddressV4)))
  8681. {
  8682. DPFX(DPFPREP, 7, "Ignoring invalid remote address and using INADDR_ANY instead.");
  8683. pRespInfo->dwRemoteAddressV4 = 0;
  8684. }
  8685. }
  8686. }
  8687. else
  8688. {
  8689. DPFX(DPFPREP, 0, "Ignoring address parameter with invalid length (%u)!",
  8690. pParam->len);
  8691. }
  8692. }
  8693. else
  8694. {
  8695. DPFX(DPFPREP, 1, "Ignoring 0 byte address parameter.");
  8696. }
  8697. break;
  8698. }
  8699. case PAST_PARAMID_PORTS:
  8700. {
  8701. if (pParam->len >= 1)
  8702. {
  8703. //
  8704. // Validate the port count.
  8705. //
  8706. if ((*pcData) == 0)
  8707. {
  8708. DPFX(DPFPREP, 1, "Ignoring %u byte port parameter with 0 ports.",
  8709. pParam->len);
  8710. break;
  8711. }
  8712. //
  8713. // Validate the size of the parameter.
  8714. //
  8715. if (pParam->len < (((*pcData) * sizeof (WORD)) + 1))
  8716. {
  8717. DPFX(DPFPREP, 0, "Port parameter is %u bytes, but is reporting %u ports! Ignoring.",
  8718. pParam->len, (*pcData));
  8719. break;
  8720. }
  8721. //
  8722. // NOTE: Ports appeared to be transferred in x86 format,
  8723. // contrary to the spec, which says network byte order.
  8724. //
  8725. //
  8726. // Ports are Count[1]|Port[2]....Port[2]
  8727. //
  8728. if (! fGotlPort)
  8729. {
  8730. pRespInfo->cNumLocalPorts = (*pcData);
  8731. if (pRespInfo->cNumLocalPorts > DPNH_MAX_SIMULTANEOUS_PORTS)
  8732. {
  8733. DPFX(DPFPREP, 0, "Got %u local ports, only using first %u:",
  8734. pRespInfo->cNumLocalPorts, DPNH_MAX_SIMULTANEOUS_PORTS);
  8735. pRespInfo->cNumLocalPorts = DPNH_MAX_SIMULTANEOUS_PORTS;
  8736. }
  8737. else
  8738. {
  8739. DPFX(DPFPREP, 3, "Got %u local ports:",
  8740. pRespInfo->cNumLocalPorts);
  8741. }
  8742. //
  8743. // Copy the port array.
  8744. //
  8745. CopyMemory(pRespInfo->awLocalPorts, (pcData + 1),
  8746. (pRespInfo->cNumLocalPorts * sizeof (WORD)));
  8747. //
  8748. // Unfortunately we want the array to have ports in
  8749. // network byte order for real. Loop through each port
  8750. // and switch them.
  8751. //
  8752. #ifdef DBG
  8753. szPortList[0] = '\0'; // initialize
  8754. pszTemp = szPortList;
  8755. #endif // DBG
  8756. for(cTemp = 0; cTemp < pRespInfo->cNumLocalPorts; cTemp++)
  8757. {
  8758. #ifdef DBG
  8759. pszTemp += wsprintfA(pszTemp, "%u, ", pRespInfo->awLocalPorts[cTemp]);
  8760. #endif // DBG
  8761. pRespInfo->awLocalPorts[cTemp] = HTONS(pRespInfo->awLocalPorts[cTemp]);
  8762. }
  8763. #ifdef DBG
  8764. szPortList[strlen(szPortList) - 2] = '\0'; // chop off trailing ", "
  8765. DPFX(DPFPREP, 3, " {%hs}", szPortList);
  8766. #endif // DBG
  8767. fGotlPort = TRUE;
  8768. }
  8769. else
  8770. {
  8771. if (pRespInfo->cNumRemotePorts > 0)
  8772. {
  8773. DPFX(DPFPREP, 0, "Already received %u remote ports, ignoring %u more.",
  8774. pRespInfo->cNumRemotePorts, (*pcData));
  8775. }
  8776. else
  8777. {
  8778. pRespInfo->cNumRemotePorts = (*pcData);
  8779. if (pRespInfo->cNumRemotePorts > DPNH_MAX_SIMULTANEOUS_PORTS)
  8780. {
  8781. DPFX(DPFPREP, 0, "Got %u remote ports, only using first %u:",
  8782. pRespInfo->cNumRemotePorts, DPNH_MAX_SIMULTANEOUS_PORTS);
  8783. pRespInfo->cNumRemotePorts = DPNH_MAX_SIMULTANEOUS_PORTS;
  8784. }
  8785. else
  8786. {
  8787. DPFX(DPFPREP, 3, "Got %u remote ports:",
  8788. pRespInfo->cNumRemotePorts);
  8789. }
  8790. //
  8791. // Copy the port array.
  8792. //
  8793. CopyMemory(pRespInfo->awRemotePorts, (pcData + 1),
  8794. (pRespInfo->cNumRemotePorts * sizeof (WORD)));
  8795. //
  8796. // Unfortunately we want the array to have ports in
  8797. // network byte order for real. Loop through each
  8798. // port and switch them.
  8799. //
  8800. #ifdef DBG
  8801. szPortList[0] = '\0'; // initialize
  8802. pszTemp = szPortList;
  8803. #endif // DBG
  8804. for(cTemp = 0; cTemp < pRespInfo->cNumRemotePorts; cTemp++)
  8805. {
  8806. #ifdef DBG
  8807. pszTemp += wsprintfA(pszTemp, "%u, ", pRespInfo->awRemotePorts[cTemp]);
  8808. #endif // DBG
  8809. pRespInfo->awRemotePorts[cTemp] = HTONS(pRespInfo->awRemotePorts[cTemp]);
  8810. }
  8811. #ifdef DBG
  8812. szPortList[strlen(szPortList) - 2] = '\0'; // chop off trailing ", "
  8813. DPFX(DPFPREP, 3, " {%hs}", szPortList);
  8814. #endif // DBG
  8815. }
  8816. }
  8817. }
  8818. else
  8819. {
  8820. DPFX(DPFPREP, 1, "Ignoring 0 byte port parameter.");
  8821. }
  8822. break;
  8823. }
  8824. case PAST_PARAMID_LEASE:
  8825. {
  8826. if (pParam->len == 4)
  8827. {
  8828. CopyMemory(&pRespInfo->dwLeaseTime, pcData, 4);
  8829. DPFX(DPFPREP, 3, "Got lease of %u seconds.", pRespInfo->dwLeaseTime);
  8830. }
  8831. else
  8832. {
  8833. if (pParam->len == 0)
  8834. {
  8835. DPFX(DPFPREP, 1, "Ignoring empty lease parameter.");
  8836. }
  8837. else
  8838. {
  8839. DPFX(DPFPREP, 0, "Ignoring lease parameter with invalid length (%u)!",
  8840. pParam->len);
  8841. }
  8842. }
  8843. break;
  8844. }
  8845. case PAST_PARAMID_CLIENTID:
  8846. {
  8847. if (pParam->len == 4)
  8848. {
  8849. CopyMemory(&pRespInfo->dwClientID, pcData, 4);
  8850. DPFX(DPFPREP, 3, "Got client ID %u.", pRespInfo->dwClientID);
  8851. }
  8852. else
  8853. {
  8854. if (pParam->len == 0)
  8855. {
  8856. DPFX(DPFPREP, 1, "Ignoring empty client ID parameter.");
  8857. }
  8858. else
  8859. {
  8860. DPFX(DPFPREP, 0, "Ignoring client ID parameter with invalid length (%u)!",
  8861. pParam->len);
  8862. }
  8863. }
  8864. break;
  8865. }
  8866. case PAST_PARAMID_BINDID:
  8867. {
  8868. if (pParam->len == 4)
  8869. {
  8870. CopyMemory(&pRespInfo->dwBindID, pcData, 4);
  8871. DPFX(DPFPREP, 3, "Got bind ID %u.", pRespInfo->dwBindID);
  8872. }
  8873. else
  8874. {
  8875. if (pParam->len == 0)
  8876. {
  8877. DPFX(DPFPREP, 1, "Ignoring empty bind ID parameter.");
  8878. }
  8879. else
  8880. {
  8881. DPFX(DPFPREP, 0, "Ignoring bind ID parameter with invalid length (%u)!",
  8882. pParam->len);
  8883. }
  8884. }
  8885. break;
  8886. }
  8887. case PAST_PARAMID_MESSAGEID:
  8888. {
  8889. if (pParam->len == 4)
  8890. {
  8891. CopyMemory(&pRespInfo->dwMsgID, pcData, 4);
  8892. DPFX(DPFPREP, 3, "Got message ID %u.", pRespInfo->dwMsgID);
  8893. }
  8894. else
  8895. {
  8896. if (pParam->len == 0)
  8897. {
  8898. DPFX(DPFPREP, 1, "Ignoring empty message ID parameter.");
  8899. }
  8900. else
  8901. {
  8902. DPFX(DPFPREP, 0, "Ignoring message ID parameter with invalid length (%u)!",
  8903. pParam->len);
  8904. }
  8905. }
  8906. break;
  8907. }
  8908. case PAST_PARAMID_TUNNELTYPE:
  8909. {
  8910. if (pParam->len == 1)
  8911. {
  8912. DPFX(DPFPREP, 3, "Got tunnel type %u, ignoring.", (*pcData));
  8913. }
  8914. else
  8915. {
  8916. if (pParam->len == 0)
  8917. {
  8918. DPFX(DPFPREP, 1, "Ignoring empty tunnel type parameter.");
  8919. }
  8920. else
  8921. {
  8922. DPFX(DPFPREP, 0, "Ignoring tunnel type parameter with invalid length (%u)!",
  8923. pParam->len);
  8924. }
  8925. }
  8926. break;
  8927. }
  8928. case PAST_PARAMID_PASTMETHOD:
  8929. {
  8930. if (pParam->len == 1)
  8931. {
  8932. DPFX(DPFPREP, 3, "Got PAST method %u, ignoring.", (*pcData));
  8933. }
  8934. else
  8935. {
  8936. if (pParam->len == 0)
  8937. {
  8938. DPFX(DPFPREP, 1, "Ignoring empty PAST method parameter.");
  8939. }
  8940. else
  8941. {
  8942. DPFX(DPFPREP, 0, "Ignoring PAST method parameter with invalid length (%u)!",
  8943. pParam->len);
  8944. }
  8945. }
  8946. break;
  8947. }
  8948. case PAST_PARAMID_ERROR:
  8949. {
  8950. if (pParam->len == 2)
  8951. {
  8952. #ifdef DBG
  8953. char * pszErrorString;
  8954. #endif // DBG
  8955. CopyMemory(&pRespInfo->wError, pcData, 2);
  8956. #ifdef DBG
  8957. switch (pRespInfo->wError)
  8958. {
  8959. case PASTERR_UNKNOWNERROR:
  8960. {
  8961. pszErrorString = "UNKNOWNERROR";
  8962. break;
  8963. }
  8964. case PASTERR_BADBINDID:
  8965. {
  8966. pszErrorString = "BADBINDID";
  8967. break;
  8968. }
  8969. case PASTERR_BADCLIENTID:
  8970. {
  8971. pszErrorString = "BADCLIENTID";
  8972. break;
  8973. }
  8974. case PASTERR_MISSINGPARAM:
  8975. {
  8976. pszErrorString = "MISSINGPARAM";
  8977. break;
  8978. }
  8979. case PASTERR_DUPLICATEPARAM:
  8980. {
  8981. pszErrorString = "DUPLICATEPARAM";
  8982. break;
  8983. }
  8984. case PASTERR_ILLEGALPARAM:
  8985. {
  8986. pszErrorString = "ILLEGALPARAM";
  8987. break;
  8988. }
  8989. case PASTERR_ILLEGALMESSAGE:
  8990. {
  8991. pszErrorString = "ILLEGALMESSAGE";
  8992. break;
  8993. }
  8994. case PASTERR_REGISTERFIRST:
  8995. {
  8996. pszErrorString = "REGISTERFIRST";
  8997. break;
  8998. }
  8999. case PASTERR_BADMESSAGEID:
  9000. {
  9001. pszErrorString = "BADMESSAGEID";
  9002. break;
  9003. }
  9004. case PASTERR_ALREADYREGISTERED:
  9005. {
  9006. pszErrorString = "ALREADYREGISTERED";
  9007. break;
  9008. }
  9009. case PASTERR_ALREADYUNREGISTERED:
  9010. {
  9011. pszErrorString = "ALREADYUNREGISTERED";
  9012. break;
  9013. }
  9014. case PASTERR_BADTUNNELTYPE:
  9015. {
  9016. pszErrorString = "BADTUNNELTYPE";
  9017. break;
  9018. }
  9019. case PASTERR_ADDRUNAVAILABLE:
  9020. {
  9021. pszErrorString = "ADDRUNAVAILABLE";
  9022. break;
  9023. }
  9024. case PASTERR_PORTUNAVAILABLE:
  9025. {
  9026. pszErrorString = "PORTUNAVAILABLE";
  9027. break;
  9028. }
  9029. default:
  9030. {
  9031. pszErrorString = "? unknown ?";
  9032. break;
  9033. }
  9034. }
  9035. DPFX(DPFPREP, 1, "Got PAST error %u, %hs.",
  9036. pRespInfo->wError, pszErrorString);
  9037. #endif // DBG
  9038. }
  9039. else
  9040. {
  9041. if (pParam->len == 0)
  9042. {
  9043. DPFX(DPFPREP, 1, "Ignoring empty PAST error parameter.");
  9044. }
  9045. else
  9046. {
  9047. DPFX(DPFPREP, 0, "Ignoring PAST error parameter with invalid length (%u)!",
  9048. pParam->len);
  9049. }
  9050. }
  9051. break;
  9052. }
  9053. case PAST_PARAMID_FLOWPOLICY:
  9054. {
  9055. if (pParam->len == 2)
  9056. {
  9057. DPFX(DPFPREP, 3, "Got PAST flow policy local %u, remote %u; ignoring.",
  9058. (*pcData), *(pcData + 1));
  9059. }
  9060. else
  9061. {
  9062. if (pParam->len == 0)
  9063. {
  9064. DPFX(DPFPREP, 1, "Ignoring empty flow policy parameter.");
  9065. }
  9066. else
  9067. {
  9068. DPFX(DPFPREP, 0, "Ignoring flow policy parameter with invalid length (%u)!",
  9069. pParam->len);
  9070. }
  9071. }
  9072. break;
  9073. }
  9074. case PAST_PARAMID_VENDOR:
  9075. {
  9076. DPFX(DPFPREP, 1, "Got %u byte vendor code parameter, ignoring.",
  9077. pParam->len);
  9078. break;
  9079. }
  9080. default:
  9081. {
  9082. DPFX(DPFPREP, 0, "Got %u byte unknown parameter code %u, ignoring.",
  9083. pParam->len, pParam->code);
  9084. break;
  9085. }
  9086. }
  9087. pParam = pNextParam;
  9088. }
  9089. Failure:
  9090. //Exit:
  9091. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  9092. return hr;
  9093. } // CNATHelpPAST::ParsePASTMessage
  9094. #undef DPF_MODNAME
  9095. #define DPF_MODNAME "CNATHelpPAST::RequestLocalAddressListChangeNotification"
  9096. //=============================================================================
  9097. // CNATHelpPAST::RequestLocalAddressListChangeNotification
  9098. //-----------------------------------------------------------------------------
  9099. //
  9100. // Description: Attempts to request asynchronous notification (via the
  9101. // user's alert event or I/O completion port) when the local
  9102. // address list changes.
  9103. //
  9104. // The object lock is assumed to be held.
  9105. //
  9106. // Arguments: None.
  9107. //
  9108. // Returns: HRESULT
  9109. // DPNH_OK - The notification request was successfully submitted.
  9110. // DPNHERR_GENERIC - An error occurred.
  9111. //=============================================================================
  9112. HRESULT CNATHelpPAST::RequestLocalAddressListChangeNotification(void)
  9113. {
  9114. HRESULT hr;
  9115. DWORD dwTemp;
  9116. int iReturn;
  9117. DPFX(DPFPREP, 5, "(0x%p) Enter", this);
  9118. DNASSERT(! (this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1));
  9119. DNASSERT(this->m_sIoctls != INVALID_SOCKET);
  9120. DNASSERT(this->m_pfnWSAIoctl != NULL);
  9121. DNASSERT((this->m_hAlertEvent != NULL) || (this->m_hAlertIOCompletionPort != NULL));
  9122. DNASSERT(this->m_polAddressListChange != NULL);
  9123. do
  9124. {
  9125. iReturn = this->m_pfnWSAIoctl(this->m_sIoctls, // use the special Ioctl socket
  9126. SIO_ADDRESS_LIST_CHANGE, //
  9127. NULL, // no input data
  9128. 0, // no input data
  9129. NULL, // no output data
  9130. 0, // no output data
  9131. &dwTemp, // ignore bytes returned
  9132. this->m_polAddressListChange, // overlapped structure
  9133. NULL); // no completion routine
  9134. if (iReturn != 0)
  9135. {
  9136. dwTemp = this->m_pfnWSAGetLastError();
  9137. if (dwTemp != WSA_IO_PENDING)
  9138. {
  9139. DPFX(DPFPREP, 0, "Submitting address list change notification request failed (err = %u)!", dwTemp);
  9140. hr = DPNHERR_GENERIC;
  9141. goto Failure;
  9142. }
  9143. //
  9144. // Pending is what we want, we're set.
  9145. //
  9146. hr = DPNH_OK;
  9147. break;
  9148. }
  9149. //
  9150. // Address list changed right away?
  9151. //
  9152. DPFX(DPFPREP, 1, "Address list changed right away somehow, submitting again.");
  9153. }
  9154. while (TRUE);
  9155. Exit:
  9156. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
  9157. return hr;
  9158. Failure:
  9159. goto Exit;
  9160. } // CNATHelpPAST::RequestLocalAddressListChangeNotification
  9161. #undef DPF_MODNAME
  9162. #define DPF_MODNAME "CNATHelpPAST::CreatePASTSocket"
  9163. //=============================================================================
  9164. // CNATHelpPAST::CreatePASTSocket
  9165. //-----------------------------------------------------------------------------
  9166. //
  9167. // Description: Creates a PAST communication socket bound to a new random
  9168. // port on the specified IP interface. Completely random (but
  9169. // non-reserved) port numbers are chosen first, but if those ports
  9170. // are in use, WinSock is allowed to choose. The port actually
  9171. // selected will be returned in psaddrinAddress.
  9172. //
  9173. // Arguments:
  9174. // SOCKADDR_IN * psaddrinAddress - Pointer to base address to use when
  9175. // binding. The port will be modified.
  9176. //
  9177. // Returns: SOCKET
  9178. //=============================================================================
  9179. SOCKET CNATHelpPAST::CreatePASTSocket(SOCKADDR_IN * const psaddrinAddress)
  9180. {
  9181. SOCKET sTemp;
  9182. DWORD dwTry;
  9183. int iTemp;
  9184. BOOL fTemp;
  9185. #ifdef DBG
  9186. DWORD dwError;
  9187. #endif // DBG
  9188. DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p)", this, psaddrinAddress);
  9189. //
  9190. // Create the socket.
  9191. //
  9192. sTemp = this->m_pfnsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  9193. if (sTemp == INVALID_SOCKET)
  9194. {
  9195. #ifdef DBG
  9196. dwError = this->m_pfnWSAGetLastError();
  9197. DPFX(DPFPREP, 0, "Couldn't create datagram socket, error = %u!", dwError);
  9198. #endif // DBG
  9199. goto Failure;
  9200. }
  9201. //
  9202. // Try binding the socket to a completely random port a few times.
  9203. //
  9204. for(dwTry = 0; dwTry < MAX_NUM_RANDOM_PORT_TRIES; dwTry++)
  9205. {
  9206. //
  9207. // Pick a completely random port. For the moment, the value is stored
  9208. // in host byte order while we make sure it's not a reserved value.
  9209. //
  9210. do
  9211. {
  9212. psaddrinAddress->sin_port = (WORD) GetGlobalRand();
  9213. }
  9214. while ((psaddrinAddress->sin_port <= MAX_RESERVED_PORT) ||
  9215. (psaddrinAddress->sin_port == 1900) || // SSDP
  9216. (psaddrinAddress->sin_port == 2234) || // PAST
  9217. (psaddrinAddress->sin_port == 6073) || // DPNSVR
  9218. (psaddrinAddress->sin_port == 47624)); // DPLAYSVR
  9219. //
  9220. // Now try binding to the port (in network byte order).
  9221. //
  9222. psaddrinAddress->sin_port = HTONS(psaddrinAddress->sin_port);
  9223. if (this->m_pfnbind(sTemp, (SOCKADDR*) psaddrinAddress, sizeof(SOCKADDR_IN)) == 0)
  9224. {
  9225. //
  9226. // We successfully bound to the port.
  9227. //
  9228. break;
  9229. }
  9230. //
  9231. // Assume that the port is in use.
  9232. //
  9233. #ifdef DBG
  9234. dwError = this->m_pfnWSAGetLastError();
  9235. DPFX(DPFPREP, 2, "Couldn't bind to port %u (err = %u), continuing.",
  9236. NTOHS(psaddrinAddress->sin_port), dwError);
  9237. #endif // DBG
  9238. psaddrinAddress->sin_port = 0;
  9239. }
  9240. //
  9241. // If we ran out of completely random port attempts, just let WinSock
  9242. // choose it.
  9243. //
  9244. if (psaddrinAddress->sin_port == 0)
  9245. {
  9246. if (this->m_pfnbind(sTemp, (SOCKADDR*) psaddrinAddress, sizeof(SOCKADDR_IN)) != 0)
  9247. {
  9248. #ifdef DBG
  9249. dwError = this->m_pfnWSAGetLastError();
  9250. DPFX(DPFPREP, 0, "Failed binding to any port (err = %u)!",
  9251. dwError);
  9252. #endif // DBG
  9253. goto Failure;
  9254. }
  9255. //
  9256. // Find out what port WinSock chose.
  9257. //
  9258. iTemp = sizeof(SOCKADDR_IN);
  9259. if (this->m_pfngetsockname(sTemp,
  9260. (SOCKADDR *) psaddrinAddress,
  9261. &iTemp) != 0)
  9262. {
  9263. #ifdef DBG
  9264. dwError = this->m_pfnWSAGetLastError();
  9265. DPFX(DPFPREP, 0, "Couldn't get the socket's address, error = %u!",
  9266. dwError);
  9267. #endif // DBG
  9268. goto Failure;
  9269. }
  9270. DNASSERT(psaddrinAddress->sin_port != 0);
  9271. }
  9272. //
  9273. // Set the unicast TTL, if requested. Use the appropriate constant for the
  9274. // the version of WinSock we're using.
  9275. //
  9276. if (g_iUnicastTTL != 0)
  9277. {
  9278. iTemp = this->m_pfnsetsockopt(sTemp,
  9279. IPPROTO_IP,
  9280. #ifdef DPNBUILD_NOWINSOCK2
  9281. IP_TTL,
  9282. #else // ! DPNBUILD_NOWINSOCK2
  9283. ((this->m_dwFlags & NATHELPPASTOBJ_WINSOCK1) ? IP_TTL_WINSOCK1 : IP_TTL),
  9284. #endif // ! DPNBUILD_NOWINSOCK2
  9285. (char *) (&g_iUnicastTTL),
  9286. sizeof(g_iUnicastTTL));
  9287. if (iTemp != 0)
  9288. {
  9289. #ifdef DBG
  9290. dwError = this->m_pfnWSAGetLastError();
  9291. DPFX(DPFPREP, 0, "Couldn't set unicast TTL socket option, error = %u! Ignoring.",
  9292. dwError);
  9293. #endif // DBG
  9294. //
  9295. // Continue...
  9296. //
  9297. }
  9298. }
  9299. //
  9300. // Set the socket up to allow broadcasts in case we can't determine the
  9301. // gateway.
  9302. //
  9303. fTemp = TRUE;
  9304. if (this->m_pfnsetsockopt(sTemp,
  9305. SOL_SOCKET,
  9306. SO_BROADCAST,
  9307. (char *) (&fTemp),
  9308. sizeof(fTemp)) != 0)
  9309. {
  9310. #ifdef DBG
  9311. dwError = this->m_pfnWSAGetLastError();
  9312. DPFX(DPFPREP, 0, "Couldn't set broadcast socket option, error = %u!", dwError);
  9313. #endif // DBG
  9314. goto Failure;
  9315. }
  9316. Exit:
  9317. DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%x]", this, sTemp);
  9318. return sTemp;
  9319. Failure:
  9320. if (sTemp != INVALID_SOCKET)
  9321. {
  9322. this->m_pfnclosesocket(sTemp);
  9323. sTemp = INVALID_SOCKET;
  9324. }
  9325. goto Exit;
  9326. } // CNATHelpPAST::CreatePASTSocket
  9327. #undef DPF_MODNAME
  9328. #define DPF_MODNAME "CNATHelpPAST::GetAddressToReachGateway"
  9329. //=============================================================================
  9330. // CNATHelpPAST::GetAddressToReachGateway
  9331. //-----------------------------------------------------------------------------
  9332. //
  9333. // Description: Retrieves the address of the gateway for the given device,
  9334. // or the broadcast address if unable to be determined.
  9335. //
  9336. // This will return TRUE if the gateway's address was found, or
  9337. // the IPHLPAPI DLL could not be used (Win95). FALSE is returned
  9338. // if IPHLPAPI reported that there was no gateway (ICS private
  9339. // side adapter).
  9340. //
  9341. // Arguments:
  9342. // CDevice * pDevice - Pointer to device whose gateway should be retrieved.
  9343. // IN_ADDR * pinaddr - Place to store gateway or broadcast address.
  9344. //
  9345. // Returns: BOOL
  9346. // TRUE - Gateway address was found or had to use broadcast.
  9347. // FALSE - There is no gateway, do not attempt to use the address.
  9348. //=============================================================================
  9349. BOOL CNATHelpPAST::GetAddressToReachGateway(CDevice * const pDevice,
  9350. IN_ADDR * const pinaddr)
  9351. {
  9352. DWORD dwError;
  9353. BOOL fResult = TRUE;
  9354. ULONG ulSize;
  9355. PIP_ADAPTER_INFO pAdaptersBuffer = NULL;
  9356. PIP_ADAPTER_INFO pAdapterInfo;
  9357. PIP_ADDR_STRING pIPAddrString;
  9358. DWORD dwAdapterIndex;
  9359. PMIB_IPFORWARDTABLE pIPForwardTableBuffer = NULL;
  9360. DWORD dwTemp;
  9361. PMIB_IPFORWARDROW pIPForwardRow;
  9362. //
  9363. // Fill in the default address. This should be atomic, so don't worry
  9364. // about locking the globals.
  9365. //
  9366. pinaddr->S_un.S_addr = g_dwDefaultGatewayV4;
  9367. #ifdef DBG
  9368. pDevice->ClearGatewayFlags();
  9369. #endif // DBG
  9370. //
  9371. // If this is the loopback address, then don't bother looking for a
  9372. // gateway, we won't find one.
  9373. //
  9374. if (pDevice->GetLocalAddressV4() == NETWORKBYTEORDER_INADDR_LOOPBACK)
  9375. {
  9376. DPFX(DPFPREP, 8, "No gateway for loopback address (device = 0x%p).",
  9377. pDevice);
  9378. //
  9379. // No gateway.
  9380. //
  9381. #ifdef DBG
  9382. pDevice->NoteNoGateway();
  9383. #endif // DBG
  9384. fResult = FALSE;
  9385. goto Exit;
  9386. }
  9387. //
  9388. // If we didn't load the IP helper DLL, we can't do our fancy gateway
  9389. // tricks.
  9390. //
  9391. if (this->m_hIpHlpApiDLL == NULL)
  9392. {
  9393. DPFX(DPFPREP, 4, "Didn't load \"iphlpapi.dll\", returning default address for device 0x%p.",
  9394. pDevice);
  9395. goto Exit;
  9396. }
  9397. //
  9398. // Keep trying to get the list of adapters until we get ERROR_SUCCESS or a
  9399. // legitimate error (other than ERROR_BUFFER_OVERFLOW or
  9400. // ERROR_INSUFFICIENT_BUFFER).
  9401. //
  9402. ulSize = 0;
  9403. do
  9404. {
  9405. dwError = this->m_pfnGetAdaptersInfo(pAdaptersBuffer, &ulSize);
  9406. if (dwError == ERROR_SUCCESS)
  9407. {
  9408. //
  9409. // We succeeded, we should be set. But make sure there are
  9410. // adapters for us to use.
  9411. //
  9412. if (ulSize < sizeof(IP_ADAPTER_INFO))
  9413. {
  9414. DPFX(DPFPREP, 0, "Getting adapters info succeeded but didn't return any valid adapters (%u < %u), returning default address for device 0x%p.",
  9415. ulSize, sizeof(IP_ADAPTER_INFO), pDevice);
  9416. goto Exit;
  9417. }
  9418. break;
  9419. }
  9420. if ((dwError != ERROR_BUFFER_OVERFLOW) &&
  9421. (dwError != ERROR_INSUFFICIENT_BUFFER))
  9422. {
  9423. DPFX(DPFPREP, 0, "Unable to get adapters info (error = 0x%lx), returning default address for device 0x%p.",
  9424. dwError, pDevice);
  9425. goto Exit;
  9426. }
  9427. //
  9428. // We need more adapter space. Make sure there are adapters for us to
  9429. // use.
  9430. //
  9431. if (ulSize < sizeof(IP_ADAPTER_INFO))
  9432. {
  9433. DPFX(DPFPREP, 0, "Getting adapters info didn't return any valid adapters (%u < %u), returning default address for device 0x%p.",
  9434. ulSize, sizeof(IP_ADAPTER_INFO), pDevice);
  9435. goto Exit;
  9436. }
  9437. //
  9438. // If we previously had a buffer, free it.
  9439. //
  9440. if (pAdaptersBuffer != NULL)
  9441. {
  9442. DNFree(pAdaptersBuffer);
  9443. }
  9444. //
  9445. // Allocate the buffer.
  9446. //
  9447. pAdaptersBuffer = (PIP_ADAPTER_INFO) DNMalloc(ulSize);
  9448. if (pAdaptersBuffer == NULL)
  9449. {
  9450. DPFX(DPFPREP, 0, "Unable to allocate memory for adapters info, returning default address for device 0x%p.",
  9451. pDevice);
  9452. goto Exit;
  9453. }
  9454. }
  9455. while (TRUE);
  9456. //
  9457. // Now find the device in the adapter list returned. Loop through all
  9458. // adapters.
  9459. //
  9460. pAdapterInfo = pAdaptersBuffer;
  9461. while (pAdapterInfo != NULL)
  9462. {
  9463. //
  9464. // Loop through all addresses for this adapter looking for the one for
  9465. // the device we have bound.
  9466. //
  9467. pIPAddrString = &pAdapterInfo->IpAddressList;
  9468. while (pIPAddrString != NULL)
  9469. {
  9470. if (this->m_pfninet_addr(pIPAddrString->IpAddress.String) == pDevice->GetLocalAddressV4())
  9471. {
  9472. pinaddr->S_un.S_addr = this->m_pfninet_addr(pAdapterInfo->GatewayList.IpAddress.String);
  9473. if ((pinaddr->S_un.S_addr == INADDR_ANY) ||
  9474. (pinaddr->S_un.S_addr == INADDR_NONE))
  9475. {
  9476. DPFX(DPFPREP, 8, "Found address for device 0x%p under adapter index %u (\"%hs\") but there is no gateway.",
  9477. pDevice, pAdapterInfo->Index, pAdapterInfo->Description,
  9478. pAdapterInfo->GatewayList.IpAddress.String);
  9479. //
  9480. // Although this isn't reporting a gateway, we may still
  9481. // want to use this adapter. That's because this could be
  9482. // a multihomed machine with multiple NICs on the same
  9483. // network, where this one isn't the "default" adapter.
  9484. // So save the index so we can search for it later.
  9485. //
  9486. dwAdapterIndex = pAdapterInfo->Index;
  9487. goto CheckRouteTable;
  9488. }
  9489. //
  9490. // Make sure the address doesn't match the local device.
  9491. //
  9492. if (pinaddr->S_un.S_addr == pDevice->GetLocalAddressV4())
  9493. {
  9494. DPFX(DPFPREP, 1, "Gateway address for device 0x%p (adapter index %u, \"%hs\") matches device IP address %hs! Forcing no gateway.",
  9495. pDevice, pAdapterInfo->Index, pAdapterInfo->Description,
  9496. pAdapterInfo->GatewayList.IpAddress.String);
  9497. //
  9498. // Pretend there's no gateway, since the one we received is
  9499. // bogus.
  9500. //
  9501. #ifdef DBG
  9502. pDevice->NoteNoGateway();
  9503. #endif // DBG
  9504. fResult = FALSE;
  9505. }
  9506. else
  9507. {
  9508. DPFX(DPFPREP, 7, "Found address for device 0x%p under adapter index %u (\"%hs\"), gateway = %hs.",
  9509. pDevice, pAdapterInfo->Index, pAdapterInfo->Description,
  9510. pAdapterInfo->GatewayList.IpAddress.String);
  9511. #ifdef DBG
  9512. pDevice->NotePrimaryDevice();
  9513. #endif // DBG
  9514. }
  9515. goto Exit;
  9516. }
  9517. pIPAddrString = pIPAddrString->Next;
  9518. }
  9519. if (! fResult)
  9520. {
  9521. break;
  9522. }
  9523. pAdapterInfo = pAdapterInfo->Next;
  9524. }
  9525. //
  9526. // If we got here, then we didn't find the address. fResult will still be
  9527. // TRUE.
  9528. //
  9529. DPFX(DPFPREP, 0, "Did not find adapter with matching address, returning default address for device 0x%p.",
  9530. pDevice);
  9531. goto Exit;
  9532. CheckRouteTable:
  9533. //
  9534. // The adapter info structure said that the device doesn't have a gateway.
  9535. // However for some reason the gateway is only reported for the "default"
  9536. // device when multiple NICs can reach the same network. Check the routing
  9537. // table to determine if there's a gateway for secondary devices.
  9538. //
  9539. //
  9540. // Keep trying to get the routing table until we get ERROR_SUCCESS or a
  9541. // legitimate error (other than ERROR_BUFFER_OVERFLOW or
  9542. // ERROR_INSUFFICIENT_BUFFER).
  9543. //
  9544. ulSize = 0;
  9545. do
  9546. {
  9547. dwError = this->m_pfnGetIpForwardTable(pIPForwardTableBuffer, &ulSize, TRUE);
  9548. if (dwError == ERROR_SUCCESS)
  9549. {
  9550. //
  9551. // We succeeded, we should be set. But make sure the size is
  9552. // valid.
  9553. //
  9554. if (ulSize < sizeof(MIB_IPFORWARDTABLE))
  9555. {
  9556. DPFX(DPFPREP, 0, "Getting IP forward table succeeded but didn't return a valid buffer (%u < %u), returning \"no gateway\" indication for device 0x%p.",
  9557. ulSize, sizeof(MIB_IPFORWARDTABLE), pDevice);
  9558. fResult = FALSE;
  9559. goto Exit;
  9560. }
  9561. break;
  9562. }
  9563. if ((dwError != ERROR_BUFFER_OVERFLOW) &&
  9564. (dwError != ERROR_INSUFFICIENT_BUFFER))
  9565. {
  9566. DPFX(DPFPREP, 0, "Unable to get IP forward table (error = 0x%lx), returning \"no gateway\" indication for device 0x%p.",
  9567. dwError, pDevice);
  9568. fResult = FALSE;
  9569. goto Exit;
  9570. }
  9571. //
  9572. // We need more table space. Make sure there are adapters for us to
  9573. // use.
  9574. //
  9575. if (ulSize < sizeof(MIB_IPFORWARDTABLE))
  9576. {
  9577. DPFX(DPFPREP, 0, "Getting IP forward table didn't return any valid adapters (%u < %u), returning \"no gateway\" indication for device 0x%p.",
  9578. ulSize, sizeof(MIB_IPFORWARDTABLE), pDevice);
  9579. fResult = FALSE;
  9580. goto Exit;
  9581. }
  9582. //
  9583. // If we previously had a buffer, free it.
  9584. //
  9585. if (pIPForwardTableBuffer != NULL)
  9586. {
  9587. DNFree(pIPForwardTableBuffer);
  9588. }
  9589. //
  9590. // Allocate the buffer.
  9591. //
  9592. pIPForwardTableBuffer = (PMIB_IPFORWARDTABLE) DNMalloc(ulSize);
  9593. if (pIPForwardTableBuffer == NULL)
  9594. {
  9595. DPFX(DPFPREP, 0, "Unable to allocate memory for IP forward table, returning \"no gateway\" indication for device 0x%p.",
  9596. pDevice);
  9597. fResult = FALSE;
  9598. goto Exit;
  9599. }
  9600. }
  9601. while (TRUE);
  9602. //
  9603. // Now find the interface. Note that we don't look it up as a destination
  9604. // address. Instead, we look for it as the interface to use for a 0.0.0.0
  9605. // network destination.
  9606. //
  9607. // We're looking for a route entry:
  9608. //
  9609. // Network Destination Netmask Gateway Interface Metric
  9610. // 0.0.0.0 0.0.0.0 xxx.xxx.xxx.xxx yyy.yyy.yyy.yyy 1
  9611. //
  9612. // We have yyy.yyy.yyy.yyy, we're trying to get xxx.xxx.xxx.xxx
  9613. //
  9614. pIPForwardRow = pIPForwardTableBuffer->table;
  9615. for(dwTemp = 0; dwTemp < pIPForwardTableBuffer->dwNumEntries; dwTemp++)
  9616. {
  9617. //
  9618. // Is this a 0.0.0.0 network destination?
  9619. //
  9620. if (pIPForwardRow->dwForwardDest == INADDR_ANY)
  9621. {
  9622. DNASSERT(pIPForwardRow->dwForwardMask == INADDR_ANY);
  9623. //
  9624. // Is this the right interface?
  9625. //
  9626. if (pIPForwardRow->dwForwardIfIndex == dwAdapterIndex)
  9627. {
  9628. if (pIPForwardRow->dwForwardNextHop == INADDR_ANY)
  9629. {
  9630. DPFX(DPFPREP, 8, "Found route table entry, but it didn't have a gateway (device = 0x%p).",
  9631. pDevice);
  9632. //
  9633. // No gateway.
  9634. //
  9635. #ifdef DBG
  9636. pDevice->NoteNoGateway();
  9637. #endif // DBG
  9638. fResult = FALSE;
  9639. }
  9640. else
  9641. {
  9642. //
  9643. // Make sure the address doesn't match the local device.
  9644. //
  9645. if (pinaddr->S_un.S_addr == pDevice->GetLocalAddressV4())
  9646. {
  9647. DPFX(DPFPREP, 1, "Route table gateway for device 0x%p matches device's IP address %u.%u.%u.%u! Forcing no gateway.",
  9648. pDevice,
  9649. pinaddr->S_un.S_un_b.s_b1,
  9650. pinaddr->S_un.S_un_b.s_b2,
  9651. pinaddr->S_un.S_un_b.s_b3,
  9652. pinaddr->S_un.S_un_b.s_b4);
  9653. //
  9654. // Pretend there's no gateway, since the one we
  9655. // received is bogus.
  9656. //
  9657. #ifdef DBG
  9658. pDevice->NoteNoGateway();
  9659. #endif // DBG
  9660. fResult = FALSE;
  9661. }
  9662. else
  9663. {
  9664. pinaddr->S_un.S_addr = pIPForwardRow->dwForwardNextHop;
  9665. DPFX(DPFPREP, 8, "Found route table entry, gateway = %u.%u.%u.%u (device = 0x%p).",
  9666. pinaddr->S_un.S_un_b.s_b1,
  9667. pinaddr->S_un.S_un_b.s_b2,
  9668. pinaddr->S_un.S_un_b.s_b3,
  9669. pinaddr->S_un.S_un_b.s_b4,
  9670. pDevice);
  9671. //
  9672. // We found a gateway after all, fResult == TRUE.
  9673. //
  9674. #ifdef DBG
  9675. pDevice->NoteSecondaryDevice();
  9676. #endif // DBG
  9677. }
  9678. }
  9679. //
  9680. // We're done here.
  9681. //
  9682. goto Exit;
  9683. }
  9684. }
  9685. //
  9686. // Move to next row.
  9687. //
  9688. pIPForwardRow++;
  9689. }
  9690. //
  9691. // If we got here, then we couldn't find an appropriate entry in the
  9692. // routing table.
  9693. //
  9694. DPFX(DPFPREP, 1, "Did not find adapter in routing table, returning \"no gateway\" indication for device 0x%p.",
  9695. pDevice);
  9696. #ifdef DBG
  9697. pDevice->NoteNoGateway();
  9698. #endif // DBG
  9699. fResult = FALSE;
  9700. Exit:
  9701. if (pAdaptersBuffer != NULL)
  9702. {
  9703. DNFree(pAdaptersBuffer);
  9704. pAdaptersBuffer = NULL;
  9705. }
  9706. if (pIPForwardTableBuffer != NULL)
  9707. {
  9708. DNFree(pIPForwardTableBuffer);
  9709. pIPForwardTableBuffer = NULL;
  9710. }
  9711. return fResult;
  9712. } // CNATHelpPAST::GetAddressToReachGateway
  9713. #undef DPF_MODNAME
  9714. #define DPF_MODNAME "CNATHelpPAST::IsAddressLocal"
  9715. //=============================================================================
  9716. // CNATHelpPAST::IsAddressLocal
  9717. //-----------------------------------------------------------------------------
  9718. //
  9719. // Description: Returns TRUE if the given address is local to the given
  9720. // device; that is, if the device can send to the address directly
  9721. // without having to go through the gateway.
  9722. //
  9723. // Note that if IPHLPAPI is not available (Win95), this
  9724. // function will make an educated guess using a reasonable subnet
  9725. // mask.
  9726. //
  9727. // Arguments:
  9728. // CDevice * pDevice - Pointer to device to use.
  9729. // SOCKADDR_IN * psaddrinAddress - Address whose locality is in question.
  9730. //
  9731. // Returns: BOOL
  9732. // TRUE - Address is behind the same gateway as the device.
  9733. // FALSE - Address is not behind the same gateway as the device.
  9734. //=============================================================================
  9735. BOOL CNATHelpPAST::IsAddressLocal(CDevice * const pDevice,
  9736. const SOCKADDR_IN * const psaddrinAddress)
  9737. {
  9738. DWORD dwError;
  9739. BOOL fResult;
  9740. MIB_IPFORWARDROW IPForwardRow;
  9741. DWORD dwSubnetMaskV4;
  9742. //
  9743. // If the address to query matches the device's local address exactly, then
  9744. // of course it's local.
  9745. //
  9746. if (psaddrinAddress->sin_addr.S_un.S_addr == pDevice->GetLocalAddressV4())
  9747. {
  9748. DPFX(DPFPREP, 6, "The address %u.%u.%u.%u matches device 0x%p's local address exactly.",
  9749. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9750. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9751. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9752. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4,
  9753. pDevice);
  9754. fResult = TRUE;
  9755. goto Exit;
  9756. }
  9757. //
  9758. // If it's a multicast address, then it should not be considered local.
  9759. //
  9760. if (IS_CLASSD_IPV4_ADDRESS(psaddrinAddress->sin_addr.S_un.S_addr))
  9761. {
  9762. DPFX(DPFPREP, 6, "Address %u.%u.%u.%u is multicast, not considered local for device 0x%p.",
  9763. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9764. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9765. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9766. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4,
  9767. pDevice);
  9768. fResult = FALSE;
  9769. goto Exit;
  9770. }
  9771. //
  9772. // If we didn't load the IP helper DLL, we will have to guess.
  9773. //
  9774. if (this->m_hIpHlpApiDLL == NULL)
  9775. {
  9776. goto EducatedGuess;
  9777. }
  9778. //
  9779. // Figure out what IPHLPAPI says about how to get there.
  9780. //
  9781. ZeroMemory(&IPForwardRow, sizeof(IPForwardRow));
  9782. dwError = this->m_pfnGetBestRoute(psaddrinAddress->sin_addr.S_un.S_addr,
  9783. pDevice->GetLocalAddressV4(),
  9784. &IPForwardRow);
  9785. if (dwError != ERROR_SUCCESS)
  9786. {
  9787. DPFX(DPFPREP, 0, "Unable to get best route to %u.%u.%u.%u via device 0x%p (error = 0x%lx)! Using subnet mask.",
  9788. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9789. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9790. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9791. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4,
  9792. pDevice,
  9793. dwError);
  9794. goto EducatedGuess;
  9795. }
  9796. //
  9797. // Key off what IPHLPAPI returned.
  9798. //
  9799. switch (IPForwardRow.dwForwardType)
  9800. {
  9801. case 1:
  9802. {
  9803. //
  9804. // Other.
  9805. //
  9806. DPFX(DPFPREP, 6, "The route from device 0x%p to %u.%u.%u.%u is unknown.",
  9807. pDevice,
  9808. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9809. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9810. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9811. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4);
  9812. fResult = FALSE;
  9813. break;
  9814. }
  9815. case 2:
  9816. {
  9817. //
  9818. // The route is invalid.
  9819. //
  9820. DPFX(DPFPREP, 6, "The route from device 0x%p to %u.%u.%u.%u is invalid.",
  9821. pDevice,
  9822. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9823. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9824. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9825. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4);
  9826. fResult = FALSE;
  9827. break;
  9828. }
  9829. case 3:
  9830. {
  9831. //
  9832. // The next hop is the final destination (local route).
  9833. // Unfortunately, on multi-NIC machines querying an address
  9834. // reachable by another device returns success... not sure why, but
  9835. // if that's the case we need to further qualify this result. We
  9836. // do that by making sure the next hop address is actually the
  9837. // device with which we're querying.
  9838. //
  9839. if (IPForwardRow.dwForwardNextHop == pDevice->GetLocalAddressV4())
  9840. {
  9841. DPFX(DPFPREP, 6, "Device 0x%p can reach %u.%u.%u.%u directly, it's local.",
  9842. pDevice,
  9843. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9844. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9845. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9846. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4);
  9847. fResult = TRUE;
  9848. }
  9849. else
  9850. {
  9851. DPFX(DPFPREP, 6, "Device 0x%p can reach %u.%u.%u.%u but it would be routed via another device (%u.%u.%u.%u).",
  9852. pDevice,
  9853. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9854. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9855. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9856. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4,
  9857. ((IN_ADDR*) (&IPForwardRow.dwForwardNextHop))->S_un.S_un_b.s_b1,
  9858. ((IN_ADDR*) (&IPForwardRow.dwForwardNextHop))->S_un.S_un_b.s_b2,
  9859. ((IN_ADDR*) (&IPForwardRow.dwForwardNextHop))->S_un.S_un_b.s_b3,
  9860. ((IN_ADDR*) (&IPForwardRow.dwForwardNextHop))->S_un.S_un_b.s_b4);
  9861. fResult = FALSE;
  9862. }
  9863. break;
  9864. }
  9865. case 4:
  9866. {
  9867. //
  9868. // The next hop is not the final destination (remote route).
  9869. //
  9870. DPFX(DPFPREP, 6, "Device 0x%p cannot reach %u.%u.%u.%u directly.",
  9871. pDevice,
  9872. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9873. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9874. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9875. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4);
  9876. fResult = FALSE;
  9877. break;
  9878. }
  9879. default:
  9880. {
  9881. //
  9882. // What?
  9883. //
  9884. DPFX(DPFPREP, 0, "Unexpected forward type %u for device 0x%p and address %u.%u.%u.%u!",
  9885. IPForwardRow.dwForwardType, pDevice,
  9886. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9887. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9888. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9889. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4);
  9890. fResult = FALSE;
  9891. break;
  9892. }
  9893. }
  9894. goto Exit;
  9895. EducatedGuess:
  9896. //
  9897. // This should be atomic, so don't worry about locking.
  9898. //
  9899. dwSubnetMaskV4 = g_dwSubnetMaskV4;
  9900. if ((pDevice->GetLocalAddressV4() & dwSubnetMaskV4) == (psaddrinAddress->sin_addr.S_un.S_addr & dwSubnetMaskV4))
  9901. {
  9902. DPFX(DPFPREP, 4, "Didn't load \"iphlpapi.dll\", guessing that device 0x%p can reach %u.%u.%u.%u (using subnet mask %u.%u.%u.%u).",
  9903. pDevice,
  9904. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9905. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9906. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9907. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4,
  9908. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b1,
  9909. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b2,
  9910. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b3,
  9911. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b4);
  9912. fResult = TRUE;
  9913. }
  9914. else
  9915. {
  9916. DPFX(DPFPREP, 4, "Didn't load \"iphlpapi.dll\", guessing that device 0x%p cannot reach %u.%u.%u.%u (using subnet mask %u.%u.%u.%u).",
  9917. pDevice,
  9918. psaddrinAddress->sin_addr.S_un.S_un_b.s_b1,
  9919. psaddrinAddress->sin_addr.S_un.S_un_b.s_b2,
  9920. psaddrinAddress->sin_addr.S_un.S_un_b.s_b3,
  9921. psaddrinAddress->sin_addr.S_un.S_un_b.s_b4,
  9922. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b1,
  9923. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b2,
  9924. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b3,
  9925. ((IN_ADDR*) (&dwSubnetMaskV4))->S_un.S_un_b.s_b4);
  9926. fResult = FALSE;
  9927. }
  9928. Exit:
  9929. return fResult;
  9930. } // CNATHelpPAST::IsAddressLocal
  9931. #undef DPF_MODNAME
  9932. #define DPF_MODNAME "CNATHelpPAST::ClearDevicesPASTServer"
  9933. //=============================================================================
  9934. // CNATHelpPAST::ClearDevicesPASTServer
  9935. //-----------------------------------------------------------------------------
  9936. //
  9937. // Description: Forcefully simulates de-registration with a PAST server
  9938. /// without actually going to the network. This clears all bind
  9939. // IDs, public addresses, and cached mappings for a given device's
  9940. // local or remote server, and should only be called after the
  9941. // server appears to have died.
  9942. //
  9943. // The object lock is assumed to be held.
  9944. //
  9945. // Arguments:
  9946. // CDevice * pDevice - Pointer to device whose ports should be unbound.
  9947. // BOOL fRemote - TRUE if clearing remote PAST server, FALSE if
  9948. // clearing local PAST server.
  9949. //
  9950. // Returns: None.
  9951. //=============================================================================
  9952. void CNATHelpPAST::ClearDevicesPASTServer(CDevice * const pDevice,
  9953. const BOOL fRemote)
  9954. {
  9955. #ifdef DBG
  9956. DNASSERT(pDevice->GetPASTClientID(fRemote) != 0);
  9957. DPFX(DPFPREP, 1, "Clearing PAST server, device = 0x%p, remote = %i",
  9958. pDevice, fRemote);
  9959. pDevice->IncrementPASTServerFailures(fRemote);
  9960. this->m_dwNumServerFailures++;
  9961. #endif // DBG
  9962. if (! fRemote)
  9963. {
  9964. pDevice->NoteNoLocalPASTServer();
  9965. }
  9966. pDevice->SetPASTClientID(0, fRemote);
  9967. this->ClearAllPASTServerRegisteredPorts(pDevice, fRemote);
  9968. pDevice->NoteNoPASTPublicAddressAvailable(fRemote);
  9969. this->RemoveAllPASTCachedMappings(pDevice, fRemote);
  9970. //
  9971. // Since there was a change in the network, go back to polling relatively
  9972. // quickly.
  9973. //
  9974. this->ResetNextPollInterval();
  9975. } // CNATHelpPAST::ClearDevicesPASTServer
  9976. #undef DPF_MODNAME
  9977. #define DPF_MODNAME "CNATHelpPAST::ClearAllPASTServerRegisteredPorts"
  9978. //=============================================================================
  9979. // CNATHelpPAST::ClearAllPASTServerRegisteredPorts
  9980. //-----------------------------------------------------------------------------
  9981. //
  9982. // Description: Clears all bind IDs and public addresses for a given
  9983. // device's local or remote PAST server. This should only be
  9984. // called after the PAST server dies because the registered ports
  9985. // remain associated with the device.
  9986. //
  9987. // The object lock is assumed to be held.
  9988. //
  9989. // Arguments:
  9990. // CDevice * pDevice - Pointer to device whose ports should be unbound.
  9991. // BOOL fRemote - TRUE if clearing remote server, FALSE if clearing
  9992. // local server.
  9993. //
  9994. // Returns: None.
  9995. //=============================================================================
  9996. void CNATHelpPAST::ClearAllPASTServerRegisteredPorts(CDevice * const pDevice,
  9997. const BOOL fRemote)
  9998. {
  9999. CBilink * pBilink;
  10000. CRegisteredPort * pRegisteredPort;
  10001. DPFX(DPFPREP, 7, "(0x%p) Parameters: (0x%p, %i)", this, pDevice, fRemote);
  10002. pBilink = pDevice->m_blOwnedRegPorts.GetNext();
  10003. while (pBilink != &pDevice->m_blOwnedRegPorts)
  10004. {
  10005. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilink);
  10006. if (pRegisteredPort->GetPASTBindID(fRemote) != 0)
  10007. {
  10008. DNASSERT(pRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  10009. DNASSERT(! pRegisteredPort->IsPASTPortUnavailable(fRemote));
  10010. if (pDevice->IsPASTPublicAddressAvailable(fRemote))
  10011. {
  10012. DPFX(DPFPREP, 1, "Registered port 0x%p losing %s PAST public address.",
  10013. pRegisteredPort, ((fRemote) ? _T("remote") : _T("local")));
  10014. //
  10015. // Let the user know next time GetCaps is called.
  10016. //
  10017. this->m_dwFlags |= NATHELPPASTOBJ_ADDRESSESCHANGED;
  10018. }
  10019. else
  10020. {
  10021. DPFX(DPFPREP, 1, "Registered port 0x%p losing %s PAST binding, but it didn't have a public address.",
  10022. pRegisteredPort, ((fRemote) ? _T("remote") : _T("local")));
  10023. }
  10024. pRegisteredPort->ClearPASTPublicAddresses(fRemote);
  10025. pRegisteredPort->SetPASTBindID(0, fRemote);
  10026. DNASSERT(this->m_dwNumLeases > 0);
  10027. this->m_dwNumLeases--;
  10028. DPFX(DPFPREP, 7, "%s PAST lease for 0x%p cleared, total num leases = %u.",
  10029. ((fRemote) ? _T("Remote") : _T("Local")), pRegisteredPort, this->m_dwNumLeases);
  10030. }
  10031. else
  10032. {
  10033. DNASSERT(! pRegisteredPort->HasPASTPublicAddressesArray(fRemote));
  10034. //
  10035. // Port no longer unavailable (if it had been).
  10036. //
  10037. pRegisteredPort->NoteNotPASTPortUnavailable(fRemote);
  10038. }
  10039. pBilink = pBilink->GetNext();
  10040. }
  10041. DPFX(DPFPREP, 7, "(0x%p) Leave", this);
  10042. } // CNATHelpPAST::ClearAllPASTServerRegisteredPorts
  10043. #undef DPF_MODNAME
  10044. #define DPF_MODNAME "CNATHelpPAST::ExpireOldCachedMappings"
  10045. //=============================================================================
  10046. // CNATHelpPAST::ExpireOldCachedMappings
  10047. //-----------------------------------------------------------------------------
  10048. //
  10049. // Description: Removes any cached mappings for any device which has
  10050. // expired.
  10051. //
  10052. // The object lock is assumed to be held.
  10053. //
  10054. // Arguments: None.
  10055. //
  10056. // Returns: None.
  10057. //=============================================================================
  10058. void CNATHelpPAST::ExpireOldCachedMappings(void)
  10059. {
  10060. DWORD dwCurrentTime;
  10061. CBilink * pBilinkDevice;
  10062. CDevice * pDevice;
  10063. CBilink * pCachedMaps;
  10064. CBilink * pBilinkCacheMap;
  10065. CCacheMap * pCacheMap;
  10066. DPFX(DPFPREP, 7, "(0x%p) Enter", this);
  10067. dwCurrentTime = timeGetTime();
  10068. //
  10069. // Check the PAST cached mappings.
  10070. //
  10071. pBilinkDevice = this->m_blDevices.GetNext();
  10072. while (pBilinkDevice != &this->m_blDevices)
  10073. {
  10074. pDevice = DEVICE_FROM_BILINK(pBilinkDevice);
  10075. //
  10076. // Check the remote PAST server mappings.
  10077. //
  10078. pCachedMaps = pDevice->GetPASTCachedMaps(TRUE);
  10079. pBilinkCacheMap = pCachedMaps->GetNext();
  10080. while (pBilinkCacheMap != pCachedMaps)
  10081. {
  10082. pCacheMap = CACHEMAP_FROM_BILINK(pBilinkCacheMap);
  10083. pBilinkCacheMap = pBilinkCacheMap->GetNext();
  10084. if ((int) (pCacheMap->GetExpirationTime() - dwCurrentTime) < 0)
  10085. {
  10086. DPFX(DPFPREP, 5, "Remote PAST server cached mapping 0x%p has expired.", pCacheMap);
  10087. pCacheMap->m_blList.RemoveFromList();
  10088. delete pCacheMap;
  10089. }
  10090. }
  10091. //
  10092. // Check the local PAST server mappings.
  10093. //
  10094. pCachedMaps = pDevice->GetPASTCachedMaps(FALSE);
  10095. pBilinkCacheMap = pCachedMaps->GetNext();
  10096. while (pBilinkCacheMap != pCachedMaps)
  10097. {
  10098. pCacheMap = CACHEMAP_FROM_BILINK(pBilinkCacheMap);
  10099. pBilinkCacheMap = pBilinkCacheMap->GetNext();
  10100. if ((int) (pCacheMap->GetExpirationTime() - dwCurrentTime) < 0)
  10101. {
  10102. DPFX(DPFPREP, 5, "Local PAST server cached mapping 0x%p has expired.", pCacheMap);
  10103. pCacheMap->m_blList.RemoveFromList();
  10104. delete pCacheMap;
  10105. }
  10106. }
  10107. pBilinkDevice = pBilinkDevice->GetNext();
  10108. }
  10109. DPFX(DPFPREP, 7, "(0x%p) Leave", this);
  10110. } // CNATHelpPAST::ExpireOldCachedMappings
  10111. #undef DPF_MODNAME
  10112. #define DPF_MODNAME "CNATHelpPAST::RemoveAllPASTCachedMappings"
  10113. //=============================================================================
  10114. // CNATHelpPAST::RemoveAllPASTCachedMappings
  10115. //-----------------------------------------------------------------------------
  10116. //
  10117. // Description: Removes all cached mappings for a given device's local or
  10118. // remote PAST server.
  10119. //
  10120. // The object lock is assumed to be held.
  10121. //
  10122. // Arguments:
  10123. // CDevice * pDevice - Pointer to device whose cache should be emptied.
  10124. // BOOL fRemote - TRUE if emptying remote server, FALSE if emptying
  10125. // local server.
  10126. //
  10127. // Returns: None.
  10128. //=============================================================================
  10129. void CNATHelpPAST::RemoveAllPASTCachedMappings(CDevice * const pDevice,
  10130. const BOOL fRemote)
  10131. {
  10132. CBilink * pCachedMaps;
  10133. CBilink * pBilink;
  10134. CCacheMap * pCacheMap;
  10135. pCachedMaps = pDevice->GetPASTCachedMaps(fRemote);
  10136. pBilink = pCachedMaps->GetNext();
  10137. while (pBilink != pCachedMaps)
  10138. {
  10139. pCacheMap = CACHEMAP_FROM_BILINK(pBilink);
  10140. pBilink = pBilink->GetNext();
  10141. DPFX(DPFPREP, 5, "Removing cached mapping 0x%p.", pCacheMap);
  10142. pCacheMap->m_blList.RemoveFromList();
  10143. delete pCacheMap;
  10144. }
  10145. } // CNATHelpPAST::RemoveAllPASTCachedMappings
  10146. #ifdef DBG
  10147. #undef DPF_MODNAME
  10148. #define DPF_MODNAME "CNATHelpPAST::DebugPrintCurrentStatus"
  10149. //=============================================================================
  10150. // CNATHelpPAST::DebugPrintCurrentStatus
  10151. //-----------------------------------------------------------------------------
  10152. //
  10153. // Description: Prints all the devices and mappings to the debug log
  10154. // routines.
  10155. //
  10156. // The object lock is assumed to be held.
  10157. //
  10158. // Arguments: None.
  10159. //
  10160. // Returns: None.
  10161. //=============================================================================
  10162. void CNATHelpPAST::DebugPrintCurrentStatus(void)
  10163. {
  10164. CBilink * pBilinkDevice;
  10165. CBilink * pBilinkRegisteredPort;
  10166. CDevice * pDevice;
  10167. CRegisteredPort * pRegisteredPort;
  10168. IN_ADDR inaddrTemp;
  10169. DWORD dwTemp;
  10170. SOCKADDR_IN * pasaddrinPrivate;
  10171. SOCKADDR_IN * pasaddrinRemotePASTPublic;
  10172. SOCKADDR_IN * pasaddrinLocalPASTPublic;
  10173. DPFX(DPFPREP, 3, "Object flags = 0x%08x", this->m_dwFlags);
  10174. pBilinkDevice = this->m_blDevices.GetNext();
  10175. while (pBilinkDevice != &this->m_blDevices)
  10176. {
  10177. pDevice = DEVICE_FROM_BILINK(pBilinkDevice);
  10178. inaddrTemp.S_un.S_addr = pDevice->GetLocalAddressV4();
  10179. DPFX(DPFPREP, 3, "Device 0x%p (%u.%u.%u.%u):",
  10180. pDevice,
  10181. inaddrTemp.S_un.S_un_b.s_b1,
  10182. inaddrTemp.S_un.S_un_b.s_b2,
  10183. inaddrTemp.S_un.S_un_b.s_b3,
  10184. inaddrTemp.S_un.S_un_b.s_b4);
  10185. //
  10186. // Print the gateway information. We may not have detected it yet,
  10187. // that's okay.
  10188. //
  10189. if (pDevice->IsPrimaryDevice())
  10190. {
  10191. DPFX(DPFPREP, 3, " Primary device.");
  10192. }
  10193. else if (pDevice->IsSecondaryDevice())
  10194. {
  10195. DPFX(DPFPREP, 3, " Secondary device.");
  10196. }
  10197. else if (pDevice->HasNoGateway())
  10198. {
  10199. DPFX(DPFPREP, 3, " Has no gateway.");
  10200. }
  10201. else
  10202. {
  10203. DPFX(DPFPREP, 3, " No gateway information known.");
  10204. }
  10205. if (pDevice->GetPASTClientID(TRUE) != 0)
  10206. {
  10207. inaddrTemp.S_un.S_addr = pDevice->GetRemotePASTServerAddressV4();
  10208. DPFX(DPFPREP, 3, " Remote ICS PAST server %u.%u.%u.%u, client ID is %u.",
  10209. inaddrTemp.S_un.S_un_b.s_b1,
  10210. inaddrTemp.S_un.S_un_b.s_b2,
  10211. inaddrTemp.S_un.S_un_b.s_b3,
  10212. inaddrTemp.S_un.S_un_b.s_b4,
  10213. pDevice->GetPASTClientID(TRUE));
  10214. }
  10215. if (pDevice->HasLocalICSPASTServer())
  10216. {
  10217. DPFX(DPFPREP, 3, " Local ICS PAST server, client ID is %u.",
  10218. pDevice->GetPASTClientID(FALSE));
  10219. }
  10220. if (pDevice->HasLocalPFWOnlyPASTServer())
  10221. {
  10222. DPFX(DPFPREP, 3, " Local PFW-only PAST server, client ID is %u.",
  10223. pDevice->GetPASTClientID(FALSE));
  10224. }
  10225. if (pDevice->m_blOwnedRegPorts.IsEmpty())
  10226. {
  10227. DPFX(DPFPREP, 3, " No registered port mappings.");
  10228. }
  10229. else
  10230. {
  10231. DPFX(DPFPREP, 3, " Registered port mappings:");
  10232. pBilinkRegisteredPort = pDevice->m_blOwnedRegPorts.GetNext();
  10233. while (pBilinkRegisteredPort != &pDevice->m_blOwnedRegPorts)
  10234. {
  10235. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilinkRegisteredPort);
  10236. pasaddrinPrivate = pRegisteredPort->GetPrivateAddressesArray();
  10237. if ((pDevice->GetPASTClientID(TRUE) != 0) &&
  10238. (pDevice->IsPASTPublicAddressAvailable(TRUE)) &&
  10239. (! pRegisteredPort->IsPASTPortUnavailable(TRUE)))
  10240. {
  10241. if (pRegisteredPort->HasPASTPublicAddressesArray(TRUE))
  10242. {
  10243. pasaddrinRemotePASTPublic = pRegisteredPort->GetPASTPublicAddressesArray(TRUE);
  10244. }
  10245. else
  10246. {
  10247. pasaddrinRemotePASTPublic = NULL;
  10248. }
  10249. }
  10250. else
  10251. {
  10252. pasaddrinRemotePASTPublic = NULL;
  10253. }
  10254. if ((pDevice->GetPASTClientID(FALSE) != 0) &&
  10255. (pDevice->IsPASTPublicAddressAvailable(FALSE)) &&
  10256. (! pRegisteredPort->IsPASTPortUnavailable(FALSE)))
  10257. {
  10258. if (pRegisteredPort->HasPASTPublicAddressesArray(FALSE))
  10259. {
  10260. pasaddrinLocalPASTPublic = pRegisteredPort->GetPASTPublicAddressesArray(FALSE);
  10261. }
  10262. else
  10263. {
  10264. pasaddrinLocalPASTPublic = NULL;
  10265. }
  10266. }
  10267. else
  10268. {
  10269. pasaddrinLocalPASTPublic = NULL;
  10270. }
  10271. DPFX(DPFPREP, 3, " Registered port 0x%p:",
  10272. pRegisteredPort);
  10273. for(dwTemp = 0; dwTemp < pRegisteredPort->GetNumAddresses(); dwTemp++)
  10274. {
  10275. //
  10276. // Print private address.
  10277. //
  10278. DPFX(DPFPREP, 3, " %u-\tPrivate = %u.%u.%u.%u:%u",
  10279. dwTemp,
  10280. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b1,
  10281. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b2,
  10282. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b3,
  10283. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b4,
  10284. NTOHS(pasaddrinPrivate[dwTemp].sin_port));
  10285. //
  10286. // Print flags.
  10287. //
  10288. DPFX(DPFPREP, 3, " \tFlags = 0x%lx",
  10289. pRegisteredPort->GetFlags());
  10290. //
  10291. // Print remote PAST information.
  10292. //
  10293. if (pasaddrinRemotePASTPublic != NULL)
  10294. {
  10295. DPFX(DPFPREP, 3, " \tRemote PAST = %u.%u.%u.%u:%u, lease %u expires at %u",
  10296. pasaddrinRemotePASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b1,
  10297. pasaddrinRemotePASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b2,
  10298. pasaddrinRemotePASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b3,
  10299. pasaddrinRemotePASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b4,
  10300. NTOHS(pasaddrinRemotePASTPublic[dwTemp].sin_port),
  10301. pRegisteredPort->GetPASTBindID(TRUE),
  10302. pRegisteredPort->GetPASTLeaseExpiration(TRUE));
  10303. }
  10304. else if (pRegisteredPort->GetPASTBindID(TRUE) != 0)
  10305. {
  10306. //
  10307. // We should have caught address availability up above.
  10308. //
  10309. DNASSERT(! pDevice->IsPASTPublicAddressAvailable(TRUE));
  10310. DPFX(DPFPREP, 3, " \tRemote PAST = no public address (lease %u expires at %u)",
  10311. pRegisteredPort->GetPASTBindID(TRUE),
  10312. pRegisteredPort->GetPASTLeaseExpiration(TRUE));
  10313. }
  10314. else if (pRegisteredPort->IsPASTPortUnavailable(TRUE))
  10315. {
  10316. DPFX(DPFPREP, 3, " \tRemote PAST = port unavailable");
  10317. }
  10318. else if (pDevice->GetPASTClientID(TRUE) != 0)
  10319. {
  10320. DPFX(DPFPREP, 3, " \tRemote PAST = not registered");
  10321. }
  10322. else
  10323. {
  10324. //
  10325. // No remote PAST server.
  10326. //
  10327. }
  10328. //
  10329. // Print local PAST information.
  10330. //
  10331. if (pasaddrinLocalPASTPublic != NULL)
  10332. {
  10333. DPFX(DPFPREP, 3, " \tLocal PAST = %u.%u.%u.%u:%u, lease %u expires at %u",
  10334. pasaddrinLocalPASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b1,
  10335. pasaddrinLocalPASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b2,
  10336. pasaddrinLocalPASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b3,
  10337. pasaddrinLocalPASTPublic[dwTemp].sin_addr.S_un.S_un_b.s_b4,
  10338. NTOHS(pasaddrinLocalPASTPublic[dwTemp].sin_port),
  10339. pRegisteredPort->GetPASTBindID(FALSE),
  10340. pRegisteredPort->GetPASTLeaseExpiration(FALSE));
  10341. }
  10342. else if (pRegisteredPort->GetPASTBindID(FALSE) != 0)
  10343. {
  10344. //
  10345. // We should have caught address availability up above.
  10346. //
  10347. DNASSERT(! pDevice->IsPASTPublicAddressAvailable(FALSE));
  10348. DPFX(DPFPREP, 3, " \tLocal PAST = no public address (lease %u expires at %u)",
  10349. pRegisteredPort->GetPASTBindID(FALSE),
  10350. pRegisteredPort->GetPASTLeaseExpiration(FALSE));
  10351. }
  10352. else if (pRegisteredPort->IsPASTPortUnavailable(FALSE))
  10353. {
  10354. DPFX(DPFPREP, 3, " \tLocal PAST = port unavailable");
  10355. }
  10356. else if (pDevice->GetPASTClientID(TRUE) != 0)
  10357. {
  10358. DPFX(DPFPREP, 3, " \tLocal PAST = not registered");
  10359. }
  10360. else
  10361. {
  10362. //
  10363. // No local PAST server.
  10364. //
  10365. }
  10366. }
  10367. pBilinkRegisteredPort = pBilinkRegisteredPort->GetNext();
  10368. }
  10369. }
  10370. pBilinkDevice = pBilinkDevice->GetNext();
  10371. }
  10372. if (this->m_blUnownedPorts.IsEmpty())
  10373. {
  10374. DPFX(DPFPREP, 3, "No unowned registered port mappings.");
  10375. }
  10376. else
  10377. {
  10378. DPFX(DPFPREP, 3, "Unowned registered port mappings:");
  10379. pBilinkRegisteredPort = this->m_blUnownedPorts.GetNext();
  10380. while (pBilinkRegisteredPort != &this->m_blUnownedPorts)
  10381. {
  10382. pRegisteredPort = REGPORT_FROM_DEVICE_BILINK(pBilinkRegisteredPort);
  10383. pasaddrinPrivate = pRegisteredPort->GetPrivateAddressesArray();
  10384. DNASSERT(pRegisteredPort->GetOwningDevice() == NULL);
  10385. DNASSERT(! (pRegisteredPort->HasPASTPublicAddressesArray(TRUE)));
  10386. DNASSERT(! (pRegisteredPort->HasPASTPublicAddressesArray(FALSE)));
  10387. DNASSERT(pRegisteredPort->GetPASTBindID(TRUE) == 0);
  10388. DNASSERT(pRegisteredPort->GetPASTBindID(FALSE) == 0);
  10389. DPFX(DPFPREP, 3, " Registered port 0x%p:", pRegisteredPort);
  10390. for(dwTemp = 0; dwTemp < pRegisteredPort->GetNumAddresses(); dwTemp++)
  10391. {
  10392. //
  10393. // Print private address.
  10394. //
  10395. DPFX(DPFPREP, 3, " %u-\tPrivate = %u.%u.%u.%u:%u",
  10396. dwTemp,
  10397. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b1,
  10398. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b2,
  10399. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b3,
  10400. pasaddrinPrivate[dwTemp].sin_addr.S_un.S_un_b.s_b4,
  10401. NTOHS(pasaddrinPrivate[dwTemp].sin_port));
  10402. //
  10403. // Print flags.
  10404. //
  10405. DPFX(DPFPREP, 3, " \tFlags = 0x%lx",
  10406. pRegisteredPort->GetFlags());
  10407. }
  10408. pBilinkRegisteredPort = pBilinkRegisteredPort->GetNext();
  10409. }
  10410. }
  10411. } // CNATHelpPAST::DebugPrintCurrentStatus
  10412. #endif // DBG