Leaked source code of windows server 2003
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.

8294 lines
247 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Endpoint.cpp
  6. * Content: Winsock endpoint base class
  7. *
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 01/20/1999 jtk Created
  13. * 05/12/1999 jtk Derived from modem endpoint class
  14. * 01/10/2000 rmt Updated to build with Millenium build process
  15. * 03/22/2000 jtk Updated with changes to interface names
  16. * 03/12/2001 mjn Prevent enum responses from being indicated up after completion
  17. * 10/08/2001 vanceo Add multicast endpoint code
  18. ***************************************************************************/
  19. #include "dnwsocki.h"
  20. //**********************************************************************
  21. // Constant definitions
  22. //**********************************************************************
  23. #ifndef DPNBUILD_NOMULTICAST
  24. //#define MADCAP_LEASE_TIME 300 // ask for 5 minutes, in seconds
  25. #define MADCAP_LEASE_TIME 3600 // ask for 1 hour, in seconds
  26. #endif // ! DPNBUILD_NOMULTICAST
  27. //**********************************************************************
  28. // Macro definitions
  29. //**********************************************************************
  30. //**********************************************************************
  31. // Structure definitions
  32. //**********************************************************************
  33. #ifndef DPNBUILD_ONLYONEADAPTER
  34. typedef struct _MULTIPLEXEDADAPTERASSOCIATION
  35. {
  36. CSPData * pSPData; // pointer to current SP interface for verification
  37. CBilink * pBilink; // pointer to list of endpoints for commands multiplexed over more than one adapter
  38. DWORD dwEndpointID; // identifier of endpoint referred to in bilink
  39. } MULTIPLEXEDADAPTERASSOCIATION, * PMULTIPLEXEDADAPTERASSOCIATION;
  40. #endif // ! DPNBUILD_ONLYONEADAPTER
  41. //
  42. // It's possible (although not advised) that this structure would get
  43. // passed to a different platform, so we need to ensure that it always
  44. // looks the same.
  45. //
  46. #pragma pack(push, 1)
  47. typedef struct _PROXIEDRESPONSEORIGINALADDRESS
  48. {
  49. DWORD dwSocketPortID; // unique identifier for socketport originally sending packet
  50. DWORD dwOriginalTargetAddressV4; // the IPv4 address to which the packet was originally sent, in network byte order
  51. WORD wOriginalTargetPort; // the port to which the packet was originally sent, in network byte order
  52. } PROXIEDRESPONSEORIGINALADDRESS, * PPROXIEDRESPONSEORIGINALADDRESS;
  53. #pragma pack(pop)
  54. //**********************************************************************
  55. // Variable definitions
  56. //**********************************************************************
  57. //**********************************************************************
  58. // Function prototypes
  59. //**********************************************************************
  60. //**********************************************************************
  61. // Function definitions
  62. //**********************************************************************
  63. //**********************************************************************
  64. // ------------------------------
  65. // CEndpoint::Open - open endpoint for use
  66. //
  67. // Entry: Type of endpoint
  68. // Pointer to address to of remote machine
  69. // Pointer to socket address of remote machine
  70. //
  71. // Exit: Error code
  72. //
  73. // Note: Any call to Open() will require an associated call to Close().
  74. // ------------------------------
  75. #undef DPF_MODNAME
  76. #define DPF_MODNAME "CEndpoint::Open"
  77. HRESULT CEndpoint::Open( const ENDPOINT_TYPE EndpointType,
  78. IDirectPlay8Address *const pDP8Address,
  79. PVOID pvSessionData,
  80. DWORD dwSessionDataSize,
  81. const CSocketAddress *const pSocketAddress
  82. )
  83. {
  84. HRESULT hr;
  85. #ifdef DPNBUILD_XNETSECURITY
  86. SPSESSIONDATA_XNET * pSessionDataXNet;
  87. ULONGLONG * pullKeyID;
  88. int iError;
  89. #endif // DPNBUILD_XNETSECURITY
  90. DPFX(DPFPREP, 6, "(0x%p) Parameters (%u, 0x%p, 0x%p, %u, 0x%p)",
  91. this, EndpointType, pDP8Address, pvSessionData, dwSessionDataSize, pSocketAddress);
  92. #ifdef DBG
  93. DNASSERT( m_fEndpointOpen == FALSE );
  94. #endif // DBG
  95. //
  96. // initialize
  97. //
  98. hr = DPN_OK;
  99. DEBUG_ONLY( m_fEndpointOpen = TRUE );
  100. DNASSERT( m_EndpointType == ENDPOINT_TYPE_UNKNOWN );
  101. m_EndpointType = EndpointType;
  102. if (pvSessionData != NULL)
  103. {
  104. DNASSERT(dwSessionDataSize > sizeof(DWORD));
  105. #ifdef DPNBUILD_XNETSECURITY
  106. //
  107. // Connect on listen endpoints are given the key ID already, it's
  108. // cast as the session data.
  109. //
  110. if (EndpointType == ENDPOINT_TYPE_CONNECT_ON_LISTEN)
  111. {
  112. DNASSERT(dwSessionDataSize == sizeof(m_ullKeyID));
  113. memcpy(&m_ullKeyID, pvSessionData, sizeof(m_ullKeyID));
  114. #ifdef XBOX_ON_DESKTOP
  115. //
  116. // A security association is implicitly created by the secure transport.
  117. // Normally that would be taken care of by the time we got the data
  118. // that triggered this connection. But when we're emulating the secure
  119. // transport, we need to do it manually.
  120. //
  121. iError = XNetPrivCreateAssociation((XNKID*) (&m_ullKeyID), pSocketAddress);
  122. if (iError != 0)
  123. {
  124. DPFX(DPFPREP, 0, "Unable to create implicit security association (err = %i)!",
  125. iError);
  126. hr = DPNERR_OUTOFMEMORY;
  127. goto Failure;
  128. }
  129. else
  130. {
  131. DPFX(DPFPREP, 2, "Successfully created implicit security association.");
  132. }
  133. #endif // XBOX_ON_DESKTOP
  134. m_fXNetSecurity = TRUE;
  135. pullKeyID = &m_ullKeyID;
  136. }
  137. else
  138. {
  139. pSessionDataXNet = (SPSESSIONDATA_XNET*) pvSessionData;
  140. if ((pSessionDataXNet->dwInfo == SPSESSIONDATAINFO_XNET) &&
  141. (dwSessionDataSize == sizeof(SPSESSIONDATA_XNET)))
  142. {
  143. //
  144. // Save the key and key ID.
  145. //
  146. memcpy(&m_guidKey, &pSessionDataXNet->guidKey, sizeof(m_guidKey));
  147. memcpy(&m_ullKeyID, &pSessionDataXNet->ullKeyID, sizeof(m_ullKeyID));
  148. //
  149. // Register the key. It may have already been registered by another endpoint
  150. // so we use a refcount wrapper function to handle that case.
  151. //
  152. DBG_CASSERT(sizeof(ULONGLONG) == sizeof(XNKID));
  153. DBG_CASSERT(sizeof(GUID) == sizeof(XNKEY));
  154. iError = RegisterRefcountXnKey((XNKID*) (&m_ullKeyID), (XNKEY*) (&m_guidKey));
  155. if (iError != 0)
  156. {
  157. DPFX(DPFPREP, 0, "Unable to register secure transport key (err = %i)!",
  158. iError);
  159. hr = DPNERR_OUTOFMEMORY;
  160. goto Failure;
  161. }
  162. else
  163. {
  164. DPFX(DPFPREP, 2, "Successfully registered secure transport key.");
  165. }
  166. m_fXNetSecurity = TRUE;
  167. pullKeyID = &m_ullKeyID;
  168. }
  169. else
  170. {
  171. DPFX(DPFPREP, 0, "Unrecognized secure transport information (size %u, type 0x%08x), ignoring.",
  172. dwSessionDataSize, pSessionDataXNet->dwInfo);
  173. DNASSERT(! m_fXNetSecurity);
  174. pullKeyID = NULL;
  175. }
  176. }
  177. #endif // DPNBUILD_XNETSECURITY
  178. }
  179. else
  180. {
  181. DNASSERT(dwSessionDataSize == 0);
  182. #ifdef DPNBUILD_XNETSECURITY
  183. DNASSERT(! m_fXNetSecurity);
  184. pullKeyID = NULL;
  185. #endif // DPNBUILD_XNETSECURITY
  186. }
  187. //
  188. // determine the endpoint type so we know how to handle the input parameters
  189. //
  190. switch ( EndpointType )
  191. {
  192. case ENDPOINT_TYPE_ENUM:
  193. {
  194. DNASSERT( pSocketAddress == NULL );
  195. DNASSERT( pDP8Address != NULL );
  196. DNASSERT( m_pRemoteMachineAddress != NULL );
  197. //
  198. // Preset thread count
  199. //
  200. m_dwThreadCount = 0;
  201. hr = m_pRemoteMachineAddress->SocketAddressFromDP8Address( pDP8Address,
  202. #ifdef DPNBUILD_XNETSECURITY
  203. pullKeyID,
  204. #endif // DPNBUILD_XNETSECURITY
  205. #ifndef DPNBUILD_ONLYONETHREAD
  206. FALSE,
  207. #endif // DPNBUILD_ONLYONETHREAD
  208. SP_ADDRESS_TYPE_HOST );
  209. if ( hr != DPN_OK )
  210. {
  211. if (hr == DPNERR_INCOMPLETEADDRESS)
  212. {
  213. DPFX(DPFPREP, 1, "Enum endpoint DP8Address is incomplete." );
  214. }
  215. #ifndef DPNBUILD_ONLYONETHREAD
  216. else if (hr == DPNERR_TIMEDOUT)
  217. {
  218. DPFX(DPFPREP, 1, "Enum endpoint DP8Address requires name resolution." );
  219. //
  220. // It's not really a failure, we'll keep what we've done so
  221. // far and just return the special value.
  222. //
  223. goto Exit;
  224. }
  225. #endif // ! DPNBUILD_ONLYONETHREAD
  226. else
  227. {
  228. DPFX(DPFPREP, 0, "Problem converting DP8Address to IP address in Open (enum)!" );
  229. DisplayDNError( 0, hr );
  230. }
  231. goto Failure;
  232. }
  233. //
  234. // Make sure its valid and not banned.
  235. //
  236. if (! m_pRemoteMachineAddress->IsValidUnicastAddress(TRUE))
  237. {
  238. DPFX(DPFPREP, 0, "Host address is invalid!");
  239. hr = DPNERR_INVALIDHOSTADDRESS;
  240. goto Failure;
  241. }
  242. #ifndef DPNBUILD_NOREGISTRY
  243. if (m_pRemoteMachineAddress->IsBannedAddress())
  244. {
  245. DPFX(DPFPREP, 0, "Host address is banned!");
  246. hr = DPNERR_NOTALLOWED;
  247. goto Failure;
  248. }
  249. #endif // ! DPNBUILD_NOREGISTRY
  250. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_ONLYONETHREAD)))
  251. //
  252. // If NAT traversal is allowed, we may need to load and start
  253. // NAT Help, which can block. Alert our caller so he/she knows
  254. // to submit a blocking job.
  255. //
  256. if ( GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE )
  257. {
  258. hr = DPNERR_TIMEDOUT;
  259. }
  260. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_ONLYONETHREAD
  261. break;
  262. }
  263. //
  264. // standard endpoint creation, attempt to parse the input address
  265. //
  266. case ENDPOINT_TYPE_CONNECT:
  267. #ifndef DPNBUILD_NOMULTICAST
  268. case ENDPOINT_TYPE_MULTICAST_SEND:
  269. case ENDPOINT_TYPE_MULTICAST_RECEIVE:
  270. #endif // ! DPNBUILD_NOMULTICAST
  271. {
  272. DNASSERT( pSocketAddress == NULL );
  273. DNASSERT( pDP8Address != NULL );
  274. DNASSERT( m_pRemoteMachineAddress != NULL );
  275. #ifndef DPNBUILD_NOMULTICAST
  276. if (EndpointType == ENDPOINT_TYPE_MULTICAST_SEND)
  277. {
  278. hr = m_pRemoteMachineAddress->SocketAddressFromMulticastDP8Address( pDP8Address,
  279. #ifdef DPNBUILD_XNETSECURITY
  280. pullKeyID,
  281. #endif // DPNBUILD_XNETSECURITY
  282. &m_guidMulticastScope );
  283. }
  284. else
  285. #endif // ! DPNBUILD_NOMULTICAST
  286. {
  287. hr = m_pRemoteMachineAddress->SocketAddressFromDP8Address( pDP8Address,
  288. #ifdef DPNBUILD_XNETSECURITY
  289. pullKeyID,
  290. #endif // DPNBUILD_XNETSECURITY
  291. #ifndef DPNBUILD_ONLYONETHREAD
  292. FALSE,
  293. #endif // DPNBUILD_ONLYONETHREAD
  294. SP_ADDRESS_TYPE_HOST );
  295. }
  296. if ( hr != DPN_OK )
  297. {
  298. if ( hr == DPNERR_INCOMPLETEADDRESS )
  299. {
  300. DPFX(DPFPREP, 1, "Connect endpoint DP8Address is incomplete." );
  301. }
  302. #ifndef DPNBUILD_ONLYONETHREAD
  303. else if (hr == DPNERR_TIMEDOUT)
  304. {
  305. DPFX(DPFPREP, 1, "Connect endpoint DP8Address requires name resolution." );
  306. DNASSERT(EndpointType == ENDPOINT_TYPE_CONNECT);
  307. //
  308. // It's not really a failure, we'll keep what we've done so
  309. // far and just return the special value.
  310. //
  311. goto Exit;
  312. }
  313. #endif // ! DPNBUILD_ONLYONETHREAD
  314. else
  315. {
  316. DPFX(DPFPREP, 0, "Problem converting DP8Address to IP address in Open (connect)!" );
  317. DisplayDNError( 0, hr );
  318. }
  319. goto Failure;
  320. }
  321. //
  322. // Make sure its valid and not banned.
  323. //
  324. if (! m_pRemoteMachineAddress->IsValidUnicastAddress(FALSE))
  325. {
  326. DPFX(DPFPREP, 0, "Host address is invalid!");
  327. hr = DPNERR_INVALIDHOSTADDRESS;
  328. goto Failure;
  329. }
  330. #ifndef DPNBUILD_NOREGISTRY
  331. if (m_pRemoteMachineAddress->IsBannedAddress())
  332. {
  333. DPFX(DPFPREP, 0, "Host address is banned!");
  334. hr = DPNERR_NOTALLOWED;
  335. goto Failure;
  336. }
  337. #endif // ! DPNBUILD_NOREGISTRY
  338. //
  339. // Make sure the user isn't trying to connect to the DPNSVR port.
  340. //
  341. if ( m_pRemoteMachineAddress->GetPort() == HTONS(DPNA_DPNSVR_PORT) )
  342. {
  343. DPFX(DPFPREP, 0, "Attempting to connect to DPNSVR reserved port!" );
  344. hr = DPNERR_INVALIDHOSTADDRESS;
  345. goto Failure;
  346. }
  347. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_ONLYONETHREAD)))
  348. #ifndef DPNBUILD_NOMULTICAST
  349. if (EndpointType == ENDPOINT_TYPE_CONNECT)
  350. #endif // ! DPNBUILD_NOMULTICAST
  351. {
  352. //
  353. // If NAT traversal is allowed, we may need to load and start
  354. // NAT Help, which can block. Alert our caller so he/she knows
  355. // to submit a blocking job.
  356. //
  357. if ( GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE )
  358. {
  359. hr = DPNERR_TIMEDOUT;
  360. }
  361. }
  362. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_ONLYONETHREAD
  363. break;
  364. }
  365. //
  366. // listen, there should be no input DNAddress
  367. //
  368. case ENDPOINT_TYPE_LISTEN:
  369. {
  370. DNASSERT( pSocketAddress == NULL );
  371. DNASSERT( pDP8Address == NULL );
  372. DNASSERT( m_pRemoteMachineAddress != NULL );
  373. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_ONLYONETHREAD)))
  374. //
  375. // If NAT traversal is allowed, we may need to load and start
  376. // NAT Help, which can block. Alert our caller so he/she knows
  377. // to submit a blocking job.
  378. //
  379. if ( GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE )
  380. {
  381. hr = DPNERR_TIMEDOUT;
  382. }
  383. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_ONLYONETHREAD
  384. break;
  385. }
  386. //
  387. // new endpoint spawned from a listen, copy the input address and
  388. // note that this endpoint is really just a connection
  389. //
  390. case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
  391. {
  392. DNASSERT( pSocketAddress != NULL );
  393. DNASSERT( pDP8Address == NULL );
  394. DNASSERT( m_pRemoteMachineAddress != NULL );
  395. m_pRemoteMachineAddress->CopyAddressSettings( pSocketAddress );
  396. m_State = ENDPOINT_STATE_ATTEMPTING_CONNECT;
  397. break;
  398. }
  399. #ifndef DPNBUILD_NOMULTICAST
  400. //
  401. // multicast listen, there should be a remote multicast address
  402. //
  403. case ENDPOINT_TYPE_MULTICAST_LISTEN:
  404. {
  405. DNASSERT( pSocketAddress == NULL );
  406. DNASSERT( pDP8Address != NULL );
  407. DNASSERT( m_pRemoteMachineAddress != NULL );
  408. hr = m_pRemoteMachineAddress->SocketAddressFromMulticastDP8Address( pDP8Address,
  409. #ifdef DPNBUILD_XNETSECURITY
  410. pullKeyID,
  411. #endif // DPNBUILD_XNETSECURITY
  412. &m_guidMulticastScope );
  413. if ( hr != DPN_OK )
  414. {
  415. DPFX(DPFPREP, 0, "Problem converting DP8Address to IP address in Open (multicast listen)!" );
  416. DisplayDNError( 0, hr );
  417. goto Failure;
  418. }
  419. break;
  420. }
  421. #endif // ! DPNBUILD_NOMULTICAST
  422. //
  423. // unknown type
  424. //
  425. default:
  426. {
  427. DNASSERT( FALSE );
  428. hr = DPNERR_GENERIC;
  429. break;
  430. }
  431. }
  432. Exit:
  433. DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr);
  434. return hr;
  435. Failure:
  436. goto Exit;
  437. }
  438. //**********************************************************************
  439. //**********************************************************************
  440. // ------------------------------
  441. // CEndpoint::Close - close an endpoint
  442. //
  443. // Entry: Error code for active command
  444. //
  445. // Exit: Error code
  446. //
  447. // Note: This code does not disconnect an endpoint from its associated
  448. // socket port. That is the responsibility of the code that is
  449. // calling this function. This function assumes that this endpoint
  450. // is locked.
  451. // ------------------------------
  452. #undef DPF_MODNAME
  453. #define DPF_MODNAME "CEndpoint::Close"
  454. void CEndpoint::Close( const HRESULT hActiveCommandResult )
  455. {
  456. DPFX(DPFPREP, 6, "(0x%p) Parameters (0x%lx)", this, hActiveCommandResult);
  457. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  458. #ifndef DPNBUILD_ONLYONEADAPTER
  459. SetEndpointID( 0 );
  460. #endif // ! DPNBUILD_ONLYONEADAPTER
  461. //
  462. // This can fire in legitimate cases. For example, if a listen is cancelled
  463. // at the exact moment it is completing with a failure.
  464. //
  465. //DNASSERT( m_fEndpointOpen != FALSE );
  466. //
  467. // is there an active command?
  468. //
  469. if ( CommandPending() != FALSE )
  470. {
  471. //
  472. // cancel any active dialogs
  473. // if there are no dialogs, cancel the active command
  474. //
  475. #ifndef DPNBUILD_NOSPUI
  476. if ( GetActiveDialogHandle() != NULL )
  477. {
  478. StopSettingsDialog( GetActiveDialogHandle() );
  479. }
  480. #endif // !DPNBUILD_NOSPUI
  481. SetPendingCommandResult( hActiveCommandResult );
  482. }
  483. else
  484. {
  485. //
  486. // there should be no active dialog if there isn't an active command
  487. //
  488. #ifndef DPNBUILD_NOSPUI
  489. DNASSERT( GetActiveDialogHandle() == NULL );
  490. #endif // !DPNBUILD_NOSPUI
  491. }
  492. #ifdef DPNBUILD_XNETSECURITY
  493. if (m_fXNetSecurity)
  494. {
  495. int iResult;
  496. iResult = UnregisterRefcountXnKey((XNKID*) (&m_ullKeyID));
  497. DNASSERT(iResult == 0);
  498. m_fXNetSecurity = FALSE;
  499. }
  500. #endif // DPNBUILD_XNETSECURITY
  501. DEBUG_ONLY( m_fEndpointOpen = FALSE );
  502. DPFX(DPFPREP, 6, "(0x%p) Leaving", this);
  503. return;
  504. }
  505. //**********************************************************************
  506. //**********************************************************************
  507. // ------------------------------
  508. // CEndpoint::ChangeLoopbackAlias - change the loopback alias to a real address
  509. //
  510. // Entry: Pointer to real address to use
  511. //
  512. // Exit: Nothing
  513. // ------------------------------
  514. #undef DPF_MODNAME
  515. #define DPF_MODNAME "CEndpoint::ChangeLoopbackAlias"
  516. void CEndpoint::ChangeLoopbackAlias( const CSocketAddress *const pSocketAddress ) const
  517. {
  518. DNASSERT( m_pRemoteMachineAddress != NULL );
  519. m_pRemoteMachineAddress->ChangeLoopBackToLocalAddress( pSocketAddress );
  520. }
  521. //**********************************************************************
  522. #if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
  523. //**********************************************************************
  524. // ------------------------------
  525. // CEndpoint::MungeProxiedAddress - modify this endpoint's remote address with proxied response information, if any
  526. //
  527. // Entry: Pointer to socketport about to be bound
  528. // Pointer to remote host address
  529. // Whether its an enum or not
  530. //
  531. // Exit: Nothing
  532. // ------------------------------
  533. #undef DPF_MODNAME
  534. #define DPF_MODNAME "CEndpoint::MungeProxiedAddress"
  535. void CEndpoint::MungeProxiedAddress( const CSocketPort * const pSocketPort,
  536. IDirectPlay8Address *const pHostAddress,
  537. const BOOL fEnum )
  538. {
  539. HRESULT hrTemp;
  540. PROXIEDRESPONSEORIGINALADDRESS proa;
  541. DWORD dwComponentSize;
  542. DWORD dwComponentType;
  543. BYTE * pbZeroExpandedStruct;
  544. DWORD dwZeroExpands;
  545. BYTE * pbStructAsBytes;
  546. BYTE * pbValue;
  547. DNASSERT((GetType() == ENDPOINT_TYPE_CONNECT) || (GetType() == ENDPOINT_TYPE_ENUM));
  548. DNASSERT(m_pRemoteMachineAddress != NULL);
  549. DNASSERT(pSocketPort != NULL);
  550. DNASSERT(pSocketPort->GetNetworkAddress() != NULL);
  551. DNASSERT(pHostAddress != NULL);
  552. //
  553. // Proxying can only occur for IP, so bail if it's IPX.
  554. //
  555. if (pSocketPort->GetNetworkAddress()->GetFamily() != AF_INET)
  556. {
  557. //
  558. // Not IP socketport. Bail.
  559. //
  560. return;
  561. }
  562. #pragma TODO(vanceo, "Investigate for IPv6")
  563. //
  564. // See if the proxied response address component exists.
  565. //
  566. dwComponentSize = 0;
  567. dwComponentType = 0;
  568. hrTemp = IDirectPlay8Address_GetComponentByName( pHostAddress, // interface
  569. DPNA_PRIVATEKEY_PROXIED_RESPONSE_ORIGINAL_ADDRESS, // tag
  570. NULL, // component buffer
  571. &dwComponentSize, // component size
  572. &dwComponentType // component type
  573. );
  574. if (hrTemp != DPNERR_BUFFERTOOSMALL)
  575. {
  576. //
  577. // The component doesn't exist (or something else really weird
  578. // happened). Bail.
  579. //
  580. return;
  581. }
  582. memset(&proa, 0, sizeof(proa));
  583. //
  584. // If the component type indicates the data is "binary", this is the original
  585. // address and we're good to go. Same with ANSI strings; but the
  586. // addressing library currently will never return that I don't believe.
  587. // If it's a "Unicode string", the data probably got washed through the
  588. // GetURL/BuildFromURL functions (via Duplicate most likely).
  589. // The funky part is, every time through the wringer, each byte gets expanded
  590. // into a word (i.e. char -> WCHAR). So when we retrieve it, it's actually not
  591. // a valid Unicode string, but a goofy expanded byte blob. See below.
  592. // In all cases, the size of the buffer should be a multiple of the size of the
  593. // PROXIEDRESPONSEORIGINALADDRESS structure.
  594. //
  595. if ((dwComponentSize < sizeof(proa)) || ((dwComponentSize % sizeof(proa)) != 0))
  596. {
  597. //
  598. // The component isn't the right size. Bail.
  599. //
  600. DPFX(DPFPREP, 0, "Private proxied response original address value is not a valid size (%u is not a multiple of %u)! Ignoring.",
  601. dwComponentSize, sizeof(proa));
  602. return;
  603. }
  604. pbZeroExpandedStruct = (BYTE*) DNMalloc(dwComponentSize);
  605. if (pbZeroExpandedStruct == NULL)
  606. {
  607. //
  608. // Out of memory. We have to bail.
  609. //
  610. return;
  611. }
  612. //
  613. // Retrieve the actual data.
  614. //
  615. hrTemp = IDirectPlay8Address_GetComponentByName( pHostAddress, // interface
  616. DPNA_PRIVATEKEY_PROXIED_RESPONSE_ORIGINAL_ADDRESS, // tag
  617. pbZeroExpandedStruct, // component buffer
  618. &dwComponentSize, // component size
  619. &dwComponentType // component type
  620. );
  621. if (hrTemp != DPN_OK)
  622. {
  623. DPFX(DPFPREP, 0, "Failed retrieving private proxied response original address value (err = 0x%lx)!",
  624. hrTemp);
  625. DNFree(pbZeroExpandedStruct);
  626. pbZeroExpandedStruct = NULL;
  627. return;
  628. }
  629. //
  630. // Loop through the returned buffer and pop out the relevant bytes.
  631. //
  632. // 0xBB 0xAA became 0xBB 0x00 0xAA, 0x00,
  633. // 0xBB 0x00 0xAA, 0x00 became 0xBB 0x00 0x00 0x00 0xAA 0x00 0x00 0x00,
  634. // etc.
  635. //
  636. dwZeroExpands = dwComponentSize / sizeof(proa);
  637. DNASSERT(dwZeroExpands > 0);
  638. DPFX(DPFPREP, 3, "Got %u byte expanded private proxied response original address key value (%u to 1 correspondence).",
  639. dwComponentSize, dwZeroExpands);
  640. pbStructAsBytes = (BYTE*) (&proa);
  641. pbValue = pbZeroExpandedStruct;
  642. while (dwComponentSize > 0)
  643. {
  644. (*pbStructAsBytes) = (*pbValue);
  645. pbStructAsBytes++;
  646. pbValue += dwZeroExpands;
  647. dwComponentSize -= dwZeroExpands;
  648. }
  649. DNFree(pbZeroExpandedStruct);
  650. pbZeroExpandedStruct = NULL;
  651. //
  652. // Once here, we've successfully read the proxied response original
  653. // address structure.
  654. //
  655. // We could have regkey to always set the target socketaddress back
  656. // to the original but the logic that picks the port could give the
  657. // wrong one and it's not necessary for the scenario we're
  658. // specifically trying to enable (ISA Server proxy). See
  659. // CSocketPort::ProcessReceivedData.
  660. if (proa.dwSocketPortID != pSocketPort->GetSocketPortID())
  661. {
  662. SOCKADDR_IN * psaddrinTemp;
  663. //
  664. // Since we're not using the exact same socket as what sent the
  665. // enum that generated the redirected response, the proxy may
  666. // have since removed the mapping. Sending to the redirect
  667. // address will probably not work, so let's try going back to
  668. // the original address we were enumerating (and having the
  669. // proxy generate a new mapping).
  670. //
  671. //
  672. // Update the target.
  673. //
  674. psaddrinTemp = (SOCKADDR_IN*) m_pRemoteMachineAddress->GetWritableAddress();
  675. psaddrinTemp->sin_addr.S_un.S_addr = proa.dwOriginalTargetAddressV4;
  676. psaddrinTemp->sin_port = proa.wOriginalTargetPort;
  677. DPFX(DPFPREP, 2, "Socketport 0x%p is different from the one that received redirected response, using original target address %u.%u.%u.%u:%u",
  678. pSocketPort,
  679. psaddrinTemp->sin_addr.S_un.S_un_b.s_b1,
  680. psaddrinTemp->sin_addr.S_un.S_un_b.s_b2,
  681. psaddrinTemp->sin_addr.S_un.S_un_b.s_b3,
  682. psaddrinTemp->sin_addr.S_un.S_un_b.s_b4,
  683. NTOHS(psaddrinTemp->sin_port));
  684. DNASSERT(psaddrinTemp->sin_addr.S_un.S_addr != INADDR_ANY);
  685. DNASSERT(psaddrinTemp->sin_addr.S_un.S_addr != INADDR_BROADCAST);
  686. //
  687. //
  688. // There's a wrinkle involved here. If the enum was originally
  689. // for the DPNSVR port, but we're now trying to connect, trying
  690. // to connect to the DPNSVR port won't work. So we have to...
  691. // uh... guess the port. So my logic will be: assume the remote
  692. // port is the same as the local one. I figure, if the app is
  693. // using a custom port here, it probably was set on the other
  694. // side. If it was an arbitrary port, we used a deterministic
  695. // algorithm to pick it, and it probably was done on the other
  696. // side, too. The three cases where this won't work:
  697. // 1) when the server binds to a specific port but clients let
  698. // DPlay pick. But if that side knew the server port ahead
  699. // of time, this side probably doesn't need to enumerate
  700. // the DPNSVR port, it should just enum the game port.
  701. // 2) when the other side let DPlay pick the port, but it was
  702. // behind a NAT and thus the external port is something
  703. // other than our default range. Since it's behind a NAT,
  704. // the remote user almost certainly communicated the public
  705. // IP to this user, it should also be mentioning the port,
  706. // and again, we can avoid the DPNSVR port.
  707. // 3) when DPlay was allowed to choose a port, but this machine
  708. // and the remote one had differing ports already in use
  709. // (i.e. this machine has no DPlay apps running and picked
  710. // 2302, but the remote machine has another DPlay app
  711. // occupying port 2302 so we're actually want to get to
  712. // 2303. Obviously, only workaround here is to keep that
  713. // enum running so that we skip here and drop into the
  714. // 'else' case instead.
  715. //
  716. if ((proa.wOriginalTargetPort == HTONS(DPNA_DPNSVR_PORT)) && (! fEnum))
  717. {
  718. psaddrinTemp->sin_port = pSocketPort->GetNetworkAddress()->GetPort();
  719. DPFX(DPFPREP, 1, "Original enum target was for DPNSVR port, attempting to connect to port %u instead.",
  720. NTOHS(psaddrinTemp->sin_port));
  721. }
  722. }
  723. else
  724. {
  725. //
  726. // Keep the redirected response address as the target, it's the
  727. // one the proxy probably intends us to use, see above comment).
  728. //
  729. // One additional problem - although we have the original target
  730. // we tried, it's conceivable that the proxy timed out the
  731. // mapping for the receive address and it would be no longer
  732. // valid. The only way that would be possible with the current
  733. // DirectPlay core API is if the user got one of the redirected
  734. // enum responses, then the enum hit its retry limit and went to
  735. // the "wait for response" idle state and stayed that way such
  736. // that the the user started this enum/connect after the proxy
  737. // timeout but before the idle time expired. Alternatively, if
  738. // he/she cancelled the enum before trying this enum/connect,
  739. // the above socketport ID check would fail unless a
  740. // simultaneous operation had kept the socketport open during
  741. // that time. These scenarios don't seem that common, and I
  742. // don't expect a proxy timeout to be much shorter than 30-60
  743. // seconds anyway, so I think these are tolerable shortcomings.
  744. //
  745. DPFX(DPFPREP, 2, "Socketport 0x%p is the same, keeping redirected response address.",
  746. pSocketPort);
  747. }
  748. }
  749. //**********************************************************************
  750. #endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
  751. //**********************************************************************
  752. // ------------------------------
  753. // CEndpoint::CopyConnectData - copy data for connect command
  754. //
  755. // Entry: Pointer to job information
  756. //
  757. // Exit: Error code
  758. //
  759. // Note: Device address needs to be preserved for later use.
  760. // ------------------------------
  761. #undef DPF_MODNAME
  762. #define DPF_MODNAME "CEndpoint::CopyConnectData"
  763. HRESULT CEndpoint::CopyConnectData( const SPCONNECTDATA *const pConnectData )
  764. {
  765. HRESULT hr;
  766. ENDPOINT_COMMAND_PARAMETERS *pCommandParameters;
  767. DNASSERT( pConnectData != NULL );
  768. DNASSERT( pConnectData->hCommand != NULL );
  769. DNASSERT( pConnectData->dwCommandDescriptor != NULL_DESCRIPTOR );
  770. DNASSERT( m_pActiveCommandData == FALSE );
  771. //
  772. // initialize
  773. //
  774. hr = DPN_OK;
  775. pCommandParameters = NULL;
  776. pCommandParameters = (ENDPOINT_COMMAND_PARAMETERS*)g_EndpointCommandParametersPool.Get();
  777. if ( pCommandParameters != NULL )
  778. {
  779. SetCommandParameters( pCommandParameters );
  780. DBG_CASSERT( sizeof( pCommandParameters->PendingCommandData.ConnectData ) == sizeof( *pConnectData ) );
  781. memcpy( &pCommandParameters->PendingCommandData, pConnectData, sizeof( pCommandParameters->PendingCommandData.ConnectData ) );
  782. pCommandParameters->PendingCommandData.ConnectData.pAddressHost = pConnectData->pAddressHost;
  783. IDirectPlay8Address_AddRef( pConnectData->pAddressHost );
  784. pCommandParameters->PendingCommandData.ConnectData.pAddressDeviceInfo = pConnectData->pAddressDeviceInfo;
  785. IDirectPlay8Address_AddRef( pConnectData->pAddressDeviceInfo );
  786. m_pActiveCommandData = static_cast<CCommandData*>( pCommandParameters->PendingCommandData.ConnectData.hCommand );
  787. m_pActiveCommandData->SetUserContext( pCommandParameters->PendingCommandData.ConnectData.pvContext );
  788. m_State = ENDPOINT_STATE_ATTEMPTING_CONNECT;
  789. DNASSERT( hr == DPN_OK );
  790. }
  791. else
  792. {
  793. hr = DPNERR_OUTOFMEMORY;
  794. }
  795. return hr;
  796. };
  797. //**********************************************************************
  798. //**********************************************************************
  799. // ------------------------------
  800. // CEndpoint::ConnectJobCallback - asynchronous callback wrapper from work thread
  801. //
  802. // Entry: Pointer to job information
  803. //
  804. // Exit: Nothing
  805. // ------------------------------
  806. #undef DPF_MODNAME
  807. #define DPF_MODNAME "CEndpoint::ConnectJobCallback"
  808. void CEndpoint::ConnectJobCallback( void * const pvContext, void * const pvTimerData, const UINT uiTimerUnique )
  809. {
  810. HRESULT hr;
  811. CEndpoint *pThisEndpoint;
  812. // initialize
  813. DNASSERT( pvContext != NULL );
  814. pThisEndpoint = static_cast<CEndpoint*>( pvContext );
  815. DNASSERT( pThisEndpoint->m_pActiveCommandData != NULL );
  816. DNASSERT( pThisEndpoint->GetCommandParameters() != NULL );
  817. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.hCommand == pThisEndpoint->m_pActiveCommandData );
  818. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.dwCommandDescriptor != NULL_DESCRIPTOR );
  819. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pAddressHost != NULL );
  820. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pAddressDeviceInfo != NULL );
  821. hr = pThisEndpoint->CompleteConnect();
  822. if ( hr != DPN_OK )
  823. {
  824. DPFX(DPFPREP, 0, "Problem completing connect in job callback!" );
  825. DisplayDNError( 0, hr );
  826. goto Exit;
  827. }
  828. //
  829. // Don't do anything here because it's possible that this object was returned
  830. // to the pool!!!
  831. //
  832. Exit:
  833. pThisEndpoint->DecRef();
  834. return;
  835. }
  836. //**********************************************************************
  837. //**********************************************************************
  838. // ------------------------------
  839. // CEndpoint::CompleteConnect - complete connection
  840. //
  841. // Entry: Nothing
  842. //
  843. // Exit: Error code
  844. // ------------------------------
  845. #undef DPF_MODNAME
  846. #define DPF_MODNAME "CEndpoint::CompleteConnect"
  847. HRESULT CEndpoint::CompleteConnect( void )
  848. {
  849. HRESULT hr;
  850. HRESULT hTempResult;
  851. SPIE_CONNECT ConnectIndicationData;
  852. BOOL fEndpointBound;
  853. SPIE_CONNECTADDRESSINFO ConnectAddressInfo;
  854. IDirectPlay8Address * pHostAddress;
  855. IDirectPlay8Address * pDeviceAddress;
  856. GATEWAY_BIND_TYPE GatewayBindType;
  857. DWORD dwConnectFlags;
  858. CEndpoint * pTempEndpoint;
  859. CSocketData * pSocketData;
  860. BOOL fLockedSocketData;
  861. #ifndef DPNBUILD_ONLYONEADAPTER
  862. MULTIPLEXEDADAPTERASSOCIATION maa;
  863. DWORD dwComponentSize;
  864. DWORD dwComponentType;
  865. CBilink * pBilinkAll;
  866. CBilink blIndicate;
  867. CBilink blFail;
  868. #ifndef DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  869. CSocketPort * pSocketPort;
  870. CSocketAddress * pSocketAddress;
  871. SOCKADDR_IN * psaddrinTemp;
  872. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  873. CEndpoint * pPublicEndpoint;
  874. CSocketPort * pPublicSocketPort;
  875. SOCKADDR saddrPublic;
  876. DWORD dwPublicAddressesSize;
  877. CBilink * pBilinkPublic;
  878. DWORD dwAddressTypeFlags;
  879. DWORD dwTemp;
  880. #endif // ! DPNBUILD_NONATHELP amd ! DPNBUILD_NOLOCALNAT
  881. #endif // ! DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  882. #endif // ! DPNBUILD_ONLYONEADAPTER
  883. DNASSERT( GetCommandParameters() != NULL );
  884. DNASSERT( m_State == ENDPOINT_STATE_ATTEMPTING_CONNECT );
  885. DNASSERT( m_pActiveCommandData != NULL );
  886. DPFX(DPFPREP, 6, "(0x%p) Enter", this);
  887. //
  888. // initialize
  889. //
  890. hr = DPN_OK;
  891. fEndpointBound = FALSE;
  892. memset( &ConnectAddressInfo, 0x00, sizeof( ConnectAddressInfo ) );
  893. #ifndef DPNBUILD_ONLYONEADAPTER
  894. blIndicate.Initialize();
  895. blFail.Initialize();
  896. #endif // ! DPNBUILD_ONLYONEADAPTER
  897. pSocketData = NULL;
  898. fLockedSocketData = FALSE;
  899. DNASSERT( GetCommandParameters()->PendingCommandData.ConnectData.hCommand == m_pActiveCommandData );
  900. DNASSERT( GetCommandParameters()->PendingCommandData.ConnectData.dwCommandDescriptor != NULL_DESCRIPTOR );
  901. DNASSERT( GetCommandParameters()->GatewayBindType == GATEWAY_BIND_TYPE_UNKNOWN) ;
  902. //
  903. // Transfer address references to our local pointers. These will be released
  904. // at the end of this function, but we'll keep the pointers in the pending command
  905. // data so CSPData::BindEndpoint can still access them.
  906. //
  907. pHostAddress = GetCommandParameters()->PendingCommandData.ConnectData.pAddressHost;
  908. DNASSERT( pHostAddress != NULL );
  909. pDeviceAddress = GetCommandParameters()->PendingCommandData.ConnectData.pAddressDeviceInfo;
  910. DNASSERT( pDeviceAddress != NULL );
  911. //
  912. // Retrieve other parts of the command parameters for convenience.
  913. //
  914. GatewayBindType = GetCommandParameters()->GatewayBindType;
  915. dwConnectFlags = GetCommandParameters()->PendingCommandData.ConnectData.dwFlags;
  916. //
  917. // check for user cancelling command
  918. //
  919. m_pActiveCommandData->Lock();
  920. #ifdef DPNBUILD_NOMULTICAST
  921. DNASSERT( m_pActiveCommandData->GetType() == COMMAND_TYPE_CONNECT );
  922. #else // ! DPNBUILD_NOMULTICAST
  923. DNASSERT( (m_pActiveCommandData->GetType() == COMMAND_TYPE_CONNECT) || (m_pActiveCommandData->GetType() == COMMAND_TYPE_MULTICAST_SEND) || (m_pActiveCommandData->GetType() == COMMAND_TYPE_MULTICAST_RECEIVE) );
  924. #endif // ! DPNBUILD_NOMULTICAST
  925. switch ( m_pActiveCommandData->GetState() )
  926. {
  927. //
  928. // command was pending, that's fine
  929. //
  930. case COMMAND_STATE_PENDING:
  931. {
  932. DNASSERT( hr == DPN_OK );
  933. break;
  934. }
  935. //
  936. // command was previously uninterruptable (probably because the connect UI
  937. // was displayed), mark it as pending
  938. //
  939. case COMMAND_STATE_INPROGRESS_CANNOT_CANCEL:
  940. {
  941. m_pActiveCommandData->SetState( COMMAND_STATE_PENDING );
  942. DNASSERT( hr == DPN_OK );
  943. break;
  944. }
  945. //
  946. // command has been cancelled
  947. //
  948. case COMMAND_STATE_CANCELLING:
  949. {
  950. hr = DPNERR_USERCANCEL;
  951. DPFX(DPFPREP, 0, "User cancelled connect!" );
  952. break;
  953. }
  954. #ifndef DPNBUILD_ONLYONETHREAD
  955. //
  956. // blocking operation failed
  957. //
  958. case COMMAND_STATE_FAILING:
  959. {
  960. hr = m_hrPendingCommandResult;
  961. DNASSERT(hr != DPN_OK);
  962. DPFX(DPFPREP, 0, "Connect blocking operation failed!" );
  963. break;
  964. }
  965. #endif // ! DPNBUILD_ONLYONETHREAD
  966. //
  967. // other state
  968. //
  969. default:
  970. {
  971. DNASSERT( FALSE );
  972. break;
  973. }
  974. }
  975. m_pActiveCommandData->Unlock();
  976. if ( hr != DPN_OK )
  977. {
  978. goto Failure;
  979. }
  980. //
  981. // Bind the endpoint. Note that the GATEWAY_BIND_TYPE actually used
  982. // (GetGatewayBindType()) may differ from GatewayBindType.
  983. //
  984. hr = m_pSPData->BindEndpoint( this, pDeviceAddress, NULL, GatewayBindType );
  985. if ( hr != DPN_OK )
  986. {
  987. DPFX(DPFPREP, 0, "Failed to bind endpoint (err = 0x%lx)!", hr );
  988. DisplayDNError( 0, hr );
  989. //
  990. // We failed, but we'll continue through to indicate the address info and
  991. // add it to the multiplex list.
  992. //
  993. ConnectAddressInfo.pHostAddress = GetRemoteHostDP8Address();
  994. if ( ConnectAddressInfo.pHostAddress == NULL )
  995. {
  996. hr = DPNERR_OUTOFMEMORY;
  997. goto Failure;
  998. }
  999. //
  1000. // Just regurgitate the device address we were given initially.
  1001. //
  1002. IDirectPlay8Address_AddRef(pDeviceAddress);
  1003. ConnectAddressInfo.pDeviceAddress = pDeviceAddress;
  1004. ConnectAddressInfo.hCommandStatus = hr;
  1005. ConnectAddressInfo.pCommandContext = m_pActiveCommandData->GetUserContext();
  1006. SetPendingCommandResult( hr );
  1007. hr = DPN_OK;
  1008. //
  1009. // Note that the endpoint is not bound!
  1010. //
  1011. DNASSERT(GetSocketPort() == NULL);
  1012. }
  1013. else
  1014. {
  1015. fEndpointBound = TRUE;
  1016. //
  1017. // attempt to indicate addressing to a higher layer
  1018. //
  1019. #ifdef DPNBUILD_XNETSECURITY
  1020. ConnectAddressInfo.pDeviceAddress = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, NULL, GetGatewayBindType() );
  1021. #else // ! DPNBUILD_XNETSECURITY
  1022. ConnectAddressInfo.pDeviceAddress = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, GetGatewayBindType() );
  1023. #endif // ! DPNBUILD_XNETSECURITY
  1024. ConnectAddressInfo.pHostAddress = GetRemoteHostDP8Address();
  1025. ConnectAddressInfo.hCommandStatus = DPN_OK;
  1026. ConnectAddressInfo.pCommandContext = m_pActiveCommandData->GetUserContext();
  1027. if ( ( ConnectAddressInfo.pHostAddress == NULL ) ||
  1028. ( ConnectAddressInfo.pDeviceAddress == NULL ) )
  1029. {
  1030. hr = DPNERR_OUTOFMEMORY;
  1031. goto Failure;
  1032. }
  1033. }
  1034. //
  1035. // Retrieve the socket data. Bind endpoint should have created the object or
  1036. // returned a failure, so we won't handle the error case here.
  1037. //
  1038. pSocketData = m_pSPData->GetSocketDataRef();
  1039. DNASSERT(pSocketData != NULL);
  1040. #ifndef DPNBUILD_ONLYONEADAPTER
  1041. //
  1042. // We can run into problems with "multiplexed" device attempts when you are on
  1043. // a NAT machine. The core will try connecting on multiple adapters, but since
  1044. // we are on the network boundary, each adapter can see and get responses from
  1045. // both networks. This causes problems with peer-to-peer sessions when the
  1046. // "wrong" adapter gets selected (because it receives a response first). To
  1047. // prevent that, we are going to internally remember the association between
  1048. // the multiplexed Connects so we can decide on the fly whether to indicate a
  1049. // response or not. Obviously this workaround/decision logic relies on having
  1050. // internal knowledge of what the upper layer would be doing...
  1051. //
  1052. // So either build or add to the linked list of multiplexed Connects.
  1053. // Technically this is only necessary for IP, since IPX can't have NATs, but
  1054. // what's the harm in having a little extra info?
  1055. //
  1056. dwComponentSize = sizeof(maa);
  1057. dwComponentType = 0;
  1058. hTempResult = IDirectPlay8Address_GetComponentByName( pDeviceAddress, // interface
  1059. DPNA_PRIVATEKEY_MULTIPLEXED_ADAPTER_ASSOCIATION, // tag
  1060. &maa, // component buffer
  1061. &dwComponentSize, // component size
  1062. &dwComponentType // component type
  1063. );
  1064. if (( hTempResult == DPN_OK ) && ( dwComponentSize == sizeof(MULTIPLEXEDADAPTERASSOCIATION) ) && ( dwComponentType == DPNA_DATATYPE_BINARY ))
  1065. {
  1066. //
  1067. // We found the right component type. See if it matches the right
  1068. // CSPData object.
  1069. //
  1070. if ( maa.pSPData == m_pSPData )
  1071. {
  1072. pSocketData->Lock();
  1073. //fLockedSocketData = TRUE;
  1074. pTempEndpoint = CONTAINING_OBJECT(maa.pBilink, CEndpoint, m_blMultiplex);
  1075. //
  1076. // Make sure the endpoint is still around/valid.
  1077. //
  1078. // THIS MAY CRASH IF OBJECT POOLING IS DISABLED!
  1079. //
  1080. if ( pTempEndpoint->GetEndpointID() == maa.dwEndpointID )
  1081. {
  1082. DPFX(DPFPREP, 3, "Found correctly formed private multiplexed adapter association key, linking endpoint 0x%p with earlier connects (prev endpoint = 0x%p).",
  1083. this, pTempEndpoint);
  1084. DNASSERT( pTempEndpoint->GetType() == ENDPOINT_TYPE_CONNECT );
  1085. DNASSERT( pTempEndpoint->GetState() != ENDPOINT_STATE_UNINITIALIZED );
  1086. //
  1087. // Actually link to the other endpoints.
  1088. //
  1089. m_blMultiplex.InsertAfter(maa.pBilink);
  1090. }
  1091. else
  1092. {
  1093. DPFX(DPFPREP, 1, "Found private multiplexed adapter association key, but prev endpoint 0x%p ID doesn't match (%u != %u), cannot link endpoint 0x%p and hoping this connect gets cancelled, too.",
  1094. pTempEndpoint, pTempEndpoint->GetEndpointID(), maa.dwEndpointID, this);
  1095. }
  1096. pSocketData->Unlock();
  1097. //fLockedSocketData = FALSE;
  1098. }
  1099. else
  1100. {
  1101. //
  1102. // We are the only ones who should know about this key, so if it
  1103. // got there either someone is trying to imitate our address format,
  1104. // or someone is passing around device addresses returned by
  1105. // xxxADDRESSINFO to a different interface or over the network.
  1106. // None of those situations make a whole lot of sense, but we'll
  1107. // just ignore it.
  1108. //
  1109. DPFX(DPFPREP, 0, "Multiplexed adapter association key exists, but 0x%p doesn't match expected 0x%p, is someone trying to get cute with device address 0x%p?!",
  1110. maa.pSPData, m_pSPData, pDeviceAddress );
  1111. }
  1112. }
  1113. else
  1114. {
  1115. //
  1116. // Either the key is not there, it's the wrong size (too big for our
  1117. // buffer and returned BUFFERTOOSMALL somehow), it's not a binary
  1118. // component, or something else bad happened. Assume that this is the
  1119. // first device.
  1120. //
  1121. DPFX(DPFPREP, 8, "Could not get appropriate private multiplexed adapter association key, error = 0x%lx, component size = %u, type = %u, continuing.",
  1122. hTempResult, dwComponentSize, dwComponentType);
  1123. }
  1124. //
  1125. // Add the multiplex information to the device address for future use if
  1126. // necessary.
  1127. // Ignore failure, we can still survive without it, we just might have the
  1128. // race conditions for responses on NAT machines.
  1129. //
  1130. // NOTE: There is an inherent design problem here! We're adding a pointer to
  1131. // an endpoint (well, a field within the endpoint structure) inside the address.
  1132. // If this endpoint goes away but the upper layer reuses the address at a later
  1133. // time, this memory will be bogus! We will assume that the endpoint will not
  1134. // go away while this modified device address object is in existence.
  1135. //
  1136. if ( dwConnectFlags & DPNSPF_ADDITIONALMULTIPLEXADAPTERS )
  1137. {
  1138. maa.pSPData = m_pSPData;
  1139. maa.pBilink = &m_blMultiplex;
  1140. maa.dwEndpointID = GetEndpointID();
  1141. DPFX(DPFPREP, 7, "Additional multiplex adapters on the way, adding SPData 0x%p and bilink 0x%p to address.",
  1142. maa.pSPData, maa.pBilink);
  1143. hTempResult = IDirectPlay8Address_AddComponent( ConnectAddressInfo.pDeviceAddress, // interface
  1144. DPNA_PRIVATEKEY_MULTIPLEXED_ADAPTER_ASSOCIATION, // tag
  1145. &maa, // component data
  1146. sizeof(maa), // component data size
  1147. DPNA_DATATYPE_BINARY // component data type
  1148. );
  1149. if ( hTempResult != DPN_OK )
  1150. {
  1151. DPFX(DPFPREP, 0, "Couldn't add private multiplexed adapter association component (err = 0x%lx)! Ignoring.", hTempResult);
  1152. }
  1153. //
  1154. // Mark the command as "in-progress" so that the cancel thread knows it needs
  1155. // to do the completion itself.
  1156. // If the command has already been marked for cancellation, then we have to
  1157. // do that now.
  1158. //
  1159. m_pActiveCommandData->Lock();
  1160. if ( m_pActiveCommandData->GetState() == COMMAND_STATE_CANCELLING )
  1161. {
  1162. m_pActiveCommandData->Unlock();
  1163. DPFX(DPFPREP, 1, "Connect 0x%p (endpoint 0x%p) has already been cancelled, bailing.",
  1164. m_pActiveCommandData, this);
  1165. //
  1166. // Complete the connect with USERCANCEL.
  1167. //
  1168. hr = DPNERR_USERCANCEL;
  1169. goto Failure;
  1170. }
  1171. m_pActiveCommandData->SetState( COMMAND_STATE_INPROGRESS );
  1172. m_pActiveCommandData->Unlock();
  1173. }
  1174. #endif // ! DPNBUILD_ONLYONEADAPTER
  1175. //
  1176. // Now tell the user about the address info that we ended up using, if we
  1177. // successfully bound the endpoint, or give them a heads up for a failure
  1178. // (see BindEndpoint failure case above).
  1179. //
  1180. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_CONNECTADDRESSINFO 0x%p to interface 0x%p.",
  1181. this, &ConnectAddressInfo, m_pSPData->DP8SPCallbackInterface());
  1182. DumpAddress( 8, _T("\t Host:"), ConnectAddressInfo.pHostAddress );
  1183. DumpAddress( 8, _T("\t Device:"), ConnectAddressInfo.pDeviceAddress );
  1184. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  1185. hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
  1186. SPEV_CONNECTADDRESSINFO, // event type
  1187. &ConnectAddressInfo // pointer to data
  1188. );
  1189. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_CONNECTADDRESSINFO [0x%lx].",
  1190. this, hTempResult);
  1191. DNASSERT( hTempResult == DPN_OK );
  1192. //
  1193. // If there aren't more multiplex adapter commands on the way, then signal
  1194. // the connection and complete the command for all connections, including
  1195. // this one.
  1196. //
  1197. #ifndef DPNBUILD_ONLYONEADAPTER
  1198. if ( dwConnectFlags & DPNSPF_ADDITIONALMULTIPLEXADAPTERS )
  1199. {
  1200. //
  1201. // Not last multiplexed adapter. All the work needed to be done for these
  1202. // endpoints at this time has already been done.
  1203. //
  1204. DPFX(DPFPREP, 6, "Endpoint 0x%p is not the last multiplexed adapter, not completing connect yet.",
  1205. this);
  1206. }
  1207. else
  1208. #endif // ! DPNBUILD_ONLYONEADAPTER
  1209. {
  1210. DPFX(DPFPREP, 7, "Completing all connects (including multiplexed).");
  1211. pSocketData->Lock();
  1212. fLockedSocketData = TRUE;
  1213. #ifndef DPNBUILD_ONLYONEADAPTER
  1214. //
  1215. // Attach a root node to the list of adapters.
  1216. //
  1217. blIndicate.InsertAfter(&(m_blMultiplex));
  1218. //
  1219. // Move this adapter to the failed list if it did fail to bind.
  1220. //
  1221. if (! fEndpointBound)
  1222. {
  1223. m_blMultiplex.RemoveFromList();
  1224. m_blMultiplex.InsertBefore(&blFail);
  1225. }
  1226. #ifndef DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  1227. //
  1228. // Loop through all the remaining adapters in the list.
  1229. //
  1230. pBilinkAll = blIndicate.GetNext();
  1231. while (pBilinkAll != &blIndicate)
  1232. {
  1233. pTempEndpoint = CONTAINING_OBJECT(pBilinkAll, CEndpoint, m_blMultiplex);
  1234. DNASSERT(pBilinkAll->GetNext() != pBilinkAll);
  1235. //
  1236. // THIS MUST BE CLEANED UP PROPERLY WITH AN INTERFACE CHANGE!
  1237. //
  1238. // The endpoint may have been returned to the pool and its associated
  1239. // socketport pointer may have become NULL, or now be pointing to
  1240. // something that's no longer valid. So we try to handle NULL
  1241. // pointers. Obviously this is indicative of poor design, but it's
  1242. // not possible to change this the correct way at this time.
  1243. //
  1244. //
  1245. // If this is a NAT machine, then some adapters may be better than others
  1246. // for reaching the desired address. Particularly, it's better to use a
  1247. // private adapter, which can directly reach the private network & be
  1248. // mapped on the public network, than to use the public adapter. It's not
  1249. // fun to join a private game from an ICS machine while dialed up, have
  1250. // your Internet connection go down, and lose the connection to the
  1251. // private game which didn't (shouldn't) involve the Internet at all. So
  1252. // if we detect a public adapter when we have a perfectly good private
  1253. // adapter, we'll fail connect attempts on the public one.
  1254. //
  1255. //
  1256. // Cast to get rid of the const. Don't worry, we won't actually change it.
  1257. //
  1258. pSocketAddress = (CSocketAddress*) pTempEndpoint->GetRemoteAddressPointer();
  1259. psaddrinTemp = (SOCKADDR_IN*) pSocketAddress->GetAddress();
  1260. pSocketPort = pTempEndpoint->GetSocketPort();
  1261. //
  1262. // If this item doesn't have a socketport, then it must have failed to bind.
  1263. // We need to clean it up ourselves.
  1264. //
  1265. if (pSocketPort == NULL)
  1266. {
  1267. DPFX(DPFPREP, 3, "Endpoint 0x%p failed earlier, now completing.",
  1268. pTempEndpoint);
  1269. //
  1270. // Get the next associated endpoint before we pull the current entry
  1271. // from the list.
  1272. //
  1273. pBilinkAll = pBilinkAll->GetNext();
  1274. //
  1275. // Pull it out of the multiplex association list and move
  1276. // it to the "early completion" list.
  1277. //
  1278. pTempEndpoint->RemoveFromMultiplexList();
  1279. pTempEndpoint->m_blMultiplex.InsertBefore(&blFail);
  1280. //
  1281. // Move to next iteration of loop.
  1282. //
  1283. continue;
  1284. }
  1285. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  1286. //
  1287. // Detect if we've been given conflicting address families for our target
  1288. // and our bound socket (see CSocketPort::BindEndpoint).
  1289. //
  1290. DNASSERT(pSocketPort->GetNetworkAddress() != NULL);
  1291. if ( pSocketAddress->GetFamily() != pSocketPort->GetNetworkAddress()->GetFamily() )
  1292. {
  1293. DPFX(DPFPREP, 3, "Endpoint 0x%p (family %u) is targeting a different address family (%u), completing.",
  1294. pTempEndpoint, pSocketPort->GetNetworkAddress()->GetFamily(), pSocketAddress->GetFamily());
  1295. //
  1296. // Get the next associated endpoint before we pull the current entry
  1297. // from the list.
  1298. //
  1299. pBilinkAll = pBilinkAll->GetNext();
  1300. //
  1301. // Give the endpoint a meaningful error.
  1302. //
  1303. pTempEndpoint->SetPendingCommandResult(DPNERR_INVALIDDEVICEADDRESS);
  1304. //
  1305. // Pull it out of the multiplex association list and move
  1306. // it to the "early completion" list.
  1307. //
  1308. pTempEndpoint->RemoveFromMultiplexList();
  1309. pTempEndpoint->m_blMultiplex.InsertBefore(&blFail);
  1310. //
  1311. // Move to next iteration of loop.
  1312. //
  1313. continue;
  1314. }
  1315. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  1316. #ifndef DPNBUILD_NOIPV6
  1317. //
  1318. // Now handle some special IPv6 logic.
  1319. //
  1320. if (pSocketAddress->GetFamily() == AF_INET6)
  1321. {
  1322. SOCKADDR_IN6 * psaddrinDevice;
  1323. SOCKADDR_IN6 * psaddrinRemote;
  1324. psaddrinDevice = (SOCKADDR_IN6*) pSocketPort->GetNetworkAddress()->GetAddress();
  1325. psaddrinRemote = (SOCKADDR_IN6*) pSocketAddress->GetAddress();
  1326. if (! IN6_IS_ADDR_MULTICAST(&psaddrinRemote->sin6_addr))
  1327. {
  1328. BOOL fDifferentScope;
  1329. //
  1330. // If this endpoint is targeting something which has a different address,
  1331. // prefix scope, fail it.
  1332. //
  1333. fDifferentScope = FALSE;
  1334. if (IN6_IS_ADDR_LINKLOCAL(&psaddrinDevice->sin6_addr))
  1335. {
  1336. if (! IN6_IS_ADDR_LINKLOCAL(&psaddrinRemote->sin6_addr))
  1337. {
  1338. fDifferentScope = TRUE;
  1339. }
  1340. }
  1341. else if (IN6_IS_ADDR_SITELOCAL(&psaddrinDevice->sin6_addr))
  1342. {
  1343. if (! IN6_IS_ADDR_SITELOCAL(&psaddrinRemote->sin6_addr))
  1344. {
  1345. fDifferentScope = TRUE;
  1346. }
  1347. }
  1348. else
  1349. {
  1350. if ((IN6_IS_ADDR_LINKLOCAL(&psaddrinRemote->sin6_addr)) ||
  1351. (IN6_IS_ADDR_SITELOCAL(&psaddrinRemote->sin6_addr)))
  1352. {
  1353. fDifferentScope = TRUE;
  1354. }
  1355. }
  1356. if (fDifferentScope)
  1357. {
  1358. DPFX(DPFPREP, 3, "Endpoint 0x%p is targeting address with different link-local/site-local/global scope, completing.",
  1359. pTempEndpoint);
  1360. //
  1361. // Get the next associated endpoint before we pull the current entry
  1362. // from the list.
  1363. //
  1364. pBilinkAll = pBilinkAll->GetNext();
  1365. //
  1366. // Give the endpoint a meaningful error.
  1367. //
  1368. pTempEndpoint->SetPendingCommandResult(DPNERR_INVALIDHOSTADDRESS);
  1369. //
  1370. // Pull it out of the multiplex association list and move
  1371. // it to the "early completion" list.
  1372. //
  1373. pTempEndpoint->RemoveFromMultiplexList();
  1374. pTempEndpoint->m_blMultiplex.InsertBefore(&blFail);
  1375. //
  1376. // Move to next iteration of loop.
  1377. //
  1378. continue;
  1379. }
  1380. }
  1381. else
  1382. {
  1383. #ifndef DPNBUILD_NOMULTICAST
  1384. //
  1385. // Connects to multicast addresses should not be allowed!
  1386. //
  1387. DNASSERT(FALSE);
  1388. #endif // ! DPNBUILD_NOMULTICAST
  1389. }
  1390. }
  1391. #endif // ! DPNBUILD_NOIPV6
  1392. //
  1393. // See if this is an IP connect.
  1394. //
  1395. if (( pSocketAddress != NULL) &&
  1396. ( pSocketAddress->GetFamily() == AF_INET ))
  1397. {
  1398. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  1399. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  1400. {
  1401. if (pSocketPort->GetNATHelpPort(dwTemp) != NULL)
  1402. {
  1403. DNASSERT( g_papNATHelpObjects[dwTemp] != NULL );
  1404. dwPublicAddressesSize = sizeof(saddrPublic);
  1405. dwAddressTypeFlags = 0;
  1406. hTempResult = IDirectPlayNATHelp_GetRegisteredAddresses(g_papNATHelpObjects[dwTemp],
  1407. pSocketPort->GetNATHelpPort(dwTemp),
  1408. &saddrPublic,
  1409. &dwPublicAddressesSize,
  1410. &dwAddressTypeFlags,
  1411. NULL,
  1412. 0);
  1413. if ((hTempResult != DPNH_OK) || (! (dwAddressTypeFlags & DPNHADDRESSTYPE_GATEWAYISLOCAL)))
  1414. {
  1415. DPFX(DPFPREP, 7, "Socketport 0x%p is not locally mapped on gateway with NAT Help index %u (err = 0x%lx, flags = 0x%lx).",
  1416. pSocketPort, dwTemp, hTempResult, dwAddressTypeFlags);
  1417. }
  1418. else
  1419. {
  1420. //
  1421. // There is a local NAT.
  1422. //
  1423. DPFX(DPFPREP, 7, "Socketport 0x%p is locally mapped on gateway with NAT Help index %u (flags = 0x%lx), public address:",
  1424. pSocketPort, dwTemp, dwAddressTypeFlags);
  1425. DumpSocketAddress(7, &saddrPublic, AF_INET);
  1426. //
  1427. // Find the multiplexed connect on the public adapter that
  1428. // we need to fail, as described above.
  1429. //
  1430. pBilinkPublic = blIndicate.GetNext();
  1431. while (pBilinkPublic != &blIndicate)
  1432. {
  1433. pPublicEndpoint = CONTAINING_OBJECT(pBilinkPublic, CEndpoint, m_blMultiplex);
  1434. DNASSERT(pBilinkPublic->GetNext() != pBilinkPublic);
  1435. //
  1436. // Don't bother checking the endpoint whose public
  1437. // address we're seeking.
  1438. //
  1439. if (pPublicEndpoint != pTempEndpoint)
  1440. {
  1441. pPublicSocketPort = pPublicEndpoint->GetSocketPort();
  1442. if ( pPublicSocketPort != NULL )
  1443. {
  1444. //
  1445. // Cast to get rid of the const. Don't worry, we won't
  1446. // actually change it.
  1447. //
  1448. pSocketAddress = (CSocketAddress*) pPublicSocketPort->GetNetworkAddress();
  1449. if ( pSocketAddress != NULL )
  1450. {
  1451. if ( pSocketAddress->CompareToBaseAddress( &saddrPublic ) == 0)
  1452. {
  1453. DPFX(DPFPREP, 3, "Endpoint 0x%p is multiplexed onto public adapter for endpoint 0x%p (current endpoint = 0x%p), failing public connect.",
  1454. pTempEndpoint, pPublicEndpoint, this);
  1455. //
  1456. // Pull it out of the multiplex association list and move
  1457. // it to the "fail" list.
  1458. //
  1459. pPublicEndpoint->RemoveFromMultiplexList();
  1460. pPublicEndpoint->m_blMultiplex.InsertBefore(&blFail);
  1461. break;
  1462. }
  1463. //
  1464. // Otherwise, continue searching.
  1465. //
  1466. DPFX(DPFPREP, 8, "Endpoint 0x%p is multiplexed onto different adapter:",
  1467. pPublicEndpoint);
  1468. DumpSocketAddress(8, pSocketAddress->GetWritableAddress(), pSocketAddress->GetFamily());
  1469. }
  1470. else
  1471. {
  1472. DPFX(DPFPREP, 1, "Public endpoint 0x%p's socket port 0x%p is going away, skipping.",
  1473. pPublicEndpoint, pPublicSocketPort);
  1474. }
  1475. }
  1476. else
  1477. {
  1478. DPFX(DPFPREP, 1, "Public endpoint 0x%p is going away, skipping.",
  1479. pPublicEndpoint);
  1480. }
  1481. }
  1482. else
  1483. {
  1484. //
  1485. // The same endpoint as the one whose
  1486. // public address we're seeking.
  1487. //
  1488. }
  1489. pBilinkPublic = pBilinkPublic->GetNext();
  1490. }
  1491. //
  1492. // No need to search for any more NAT Help registrations.
  1493. //
  1494. break;
  1495. } // end else (is mapped locally on Internet gateway)
  1496. }
  1497. else
  1498. {
  1499. //
  1500. // No DirectPlay NAT Helper registration in this slot.
  1501. //
  1502. }
  1503. } // end for (each DirectPlay NAT Helper)
  1504. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  1505. //
  1506. // NOTE: We should fail connects for non-optimal adapters even
  1507. // when it's multiadapter but not a PAST/UPnP enabled NAT (see
  1508. // ProcessEnumResponseData for WSAIoctl usage related to this).
  1509. // We do not currently do this. There can still be race conditions
  1510. // for connects where the response for the "wrong" device arrives
  1511. // first.
  1512. //
  1513. }
  1514. else
  1515. {
  1516. //
  1517. // Not IP address, or possibly the endpoint is shutting down.
  1518. //
  1519. DPFX(DPFPREP, 1, "Found non-IPv4 endpoint (possibly closing) (endpoint = 0x%p, socket address = 0x%p, socketport = 0x%p), not checking for local NAT mapping.",
  1520. pTempEndpoint, pSocketAddress, pSocketPort);
  1521. }
  1522. //
  1523. // Go to the next associated endpoint. Although it's possible for
  1524. // entries to have been removed from the list, the current entry
  1525. // could not have been, so we're safe.
  1526. //
  1527. pBilinkAll = pBilinkAll->GetNext();
  1528. }
  1529. #endif // ! DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  1530. #endif // ! DPNBUILD_ONLYONEADAPTER
  1531. //
  1532. // Now loop through the remaining endpoints and indicate their
  1533. // connections.
  1534. //
  1535. #ifdef DPNBUILD_ONLYONEADAPTER
  1536. if (fEndpointBound)
  1537. {
  1538. pTempEndpoint = this;
  1539. #else // ! DPNBUILD_ONLYONEADAPTER
  1540. while (! blIndicate.IsEmpty())
  1541. {
  1542. pBilinkAll = blIndicate.GetNext();
  1543. pTempEndpoint = CONTAINING_OBJECT(pBilinkAll, CEndpoint, m_blMultiplex);
  1544. DNASSERT(pBilinkAll->GetNext() != pBilinkAll);
  1545. #endif // ! DPNBUILD_ONLYONEADAPTER
  1546. //
  1547. // See notes above about NULL handling.
  1548. //
  1549. if (pTempEndpoint->m_pActiveCommandData != NULL)
  1550. {
  1551. #ifndef DPNBUILD_ONLYONEADAPTER
  1552. //
  1553. // Pull it from the "indicate" list.
  1554. //
  1555. pTempEndpoint->RemoveFromMultiplexList();
  1556. #endif // ! DPNBUILD_ONLYONEADAPTER
  1557. pTempEndpoint->m_pActiveCommandData->Lock();
  1558. if ( pTempEndpoint->m_pActiveCommandData->GetState() == COMMAND_STATE_CANCELLING )
  1559. {
  1560. pTempEndpoint->m_pActiveCommandData->Unlock();
  1561. DPFX(DPFPREP, 3, "Connect 0x%p is cancelled, not indicating endpoint 0x%p.",
  1562. pTempEndpoint->m_pActiveCommandData, pTempEndpoint);
  1563. #ifdef DPNBUILD_ONLYONEADAPTER
  1564. #else // ! DPNBUILD_ONLYONEADAPTER
  1565. //
  1566. // Put it on the list of connects to fail.
  1567. //
  1568. pTempEndpoint->m_blMultiplex.InsertBefore(&blFail);
  1569. #endif // ! DPNBUILD_ONLYONEADAPTER
  1570. }
  1571. else
  1572. {
  1573. //
  1574. // Mark the connect as uncancellable, since we're about to indicate
  1575. // the connection.
  1576. //
  1577. pTempEndpoint->m_pActiveCommandData->SetState( COMMAND_STATE_INPROGRESS_CANNOT_CANCEL );
  1578. pTempEndpoint->m_pActiveCommandData->Unlock();
  1579. //
  1580. // Get a reference to keep the endpoint and command around while we
  1581. // drop the socketport list lock.
  1582. // Reuse fLockedSocketData to assert that we can add a command ref.
  1583. //
  1584. fLockedSocketData = pTempEndpoint->AddCommandRef();
  1585. DNASSERT(fLockedSocketData);
  1586. //
  1587. // Drop the socket data lock. It's safe since we pulled everything we
  1588. // need off of the list that needs protection.
  1589. //
  1590. pSocketData->Unlock();
  1591. fLockedSocketData = FALSE;
  1592. //
  1593. // Inform user of connection. Assume that the user will accept and
  1594. // everything will succeed so we can set the user context for the
  1595. // endpoint. If the connection fails, clear the user endpoint
  1596. // context.
  1597. //
  1598. memset( &ConnectIndicationData, 0x00, sizeof( ConnectIndicationData ) );
  1599. DBG_CASSERT( sizeof( ConnectIndicationData.hEndpoint ) == sizeof( this ) );
  1600. ConnectIndicationData.hEndpoint = (HANDLE) pTempEndpoint;
  1601. DNASSERT( pTempEndpoint->GetCommandParameters() != NULL );
  1602. ConnectIndicationData.pCommandContext = pTempEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pvContext;
  1603. pTempEndpoint->SetUserEndpointContext( NULL );
  1604. hTempResult = pTempEndpoint->SignalConnect( &ConnectIndicationData );
  1605. if ( hTempResult != DPN_OK )
  1606. {
  1607. DNASSERT( hTempResult == DPNERR_ABORTED );
  1608. DPFX(DPFPREP, 1, "User refused connect in CompleteConnect (err = 0x%lx), completing connect with USERCANCEL.",
  1609. hTempResult );
  1610. DisplayDNError( 1, hTempResult );
  1611. pTempEndpoint->SetUserEndpointContext( NULL );
  1612. //
  1613. // Retake the socket data lock so we can modify list linkage.
  1614. //
  1615. pSocketData->Lock();
  1616. fLockedSocketData = TRUE;
  1617. #ifdef DPNBUILD_ONLYONEADAPTER
  1618. //
  1619. // Remember that we're failing.
  1620. //
  1621. fEndpointBound = FALSE;
  1622. #else // ! DPNBUILD_ONLYONEADAPTER
  1623. //
  1624. // Put it on the list of connects to fail.
  1625. //
  1626. pTempEndpoint->m_blMultiplex.InsertBefore(&blFail);
  1627. #endif // ! DPNBUILD_ONLYONEADAPTER
  1628. //
  1629. // Mark the connect as cancelled so that we complete with
  1630. // the right error code.
  1631. //
  1632. pTempEndpoint->m_pActiveCommandData->Lock();
  1633. DNASSERT( pTempEndpoint->m_pActiveCommandData->GetState() == COMMAND_STATE_INPROGRESS_CANNOT_CANCEL );
  1634. pTempEndpoint->m_pActiveCommandData->SetState( COMMAND_STATE_CANCELLING );
  1635. pTempEndpoint->m_pActiveCommandData->Unlock();
  1636. //
  1637. // Drop the reference.
  1638. // Note: SocketPort lock is still held, but since the command was
  1639. // marked as uncancellable, this should not cause the endpoint to
  1640. // get unbound yet, and thus we shouldn't reenter the
  1641. // socketportdata lock.
  1642. //
  1643. pTempEndpoint->DecCommandRef();
  1644. }
  1645. else
  1646. {
  1647. //
  1648. // We're done and everyone's happy, complete the command.
  1649. // This will clear all of our internal command data.
  1650. //
  1651. pTempEndpoint->CompletePendingCommand( hTempResult );
  1652. DNASSERT( pTempEndpoint->GetCommandParameters() == NULL );
  1653. DNASSERT( pTempEndpoint->m_pActiveCommandData == NULL );
  1654. //
  1655. // Drop the reference (may result in endpoint unbinding).
  1656. //
  1657. pTempEndpoint->DecCommandRef();
  1658. //
  1659. // Retake the socket data lock in preparation for the next item.
  1660. //
  1661. pSocketData->Lock();
  1662. fLockedSocketData = TRUE;
  1663. }
  1664. }
  1665. }
  1666. else
  1667. {
  1668. DPFX(DPFPREP, 1, "Endpoint 0x%p's active command data is NULL, skipping.",
  1669. pTempEndpoint);
  1670. }
  1671. //
  1672. // Go to the next associated endpoint.
  1673. //
  1674. }
  1675. //
  1676. // Finally loop through all the connects that need to fail and do
  1677. // just that.
  1678. //
  1679. #ifdef DPNBUILD_ONLYONEADAPTER
  1680. if (! fEndpointBound)
  1681. {
  1682. pTempEndpoint = this;
  1683. #else // ! DPNBUILD_ONLYONEADAPTER
  1684. while (! blFail.IsEmpty())
  1685. {
  1686. pBilinkAll = blFail.GetNext();
  1687. pTempEndpoint = CONTAINING_OBJECT(pBilinkAll, CEndpoint, m_blMultiplex);
  1688. DNASSERT(pBilinkAll->GetNext() != pBilinkAll);
  1689. //
  1690. // Pull it from the "fail" list.
  1691. //
  1692. pTempEndpoint->RemoveFromMultiplexList();
  1693. #endif // ! DPNBUILD_ONLYONEADAPTER
  1694. //
  1695. // Get a reference to keep the endpoint around while we drop the
  1696. // socketport list lock.
  1697. //
  1698. pTempEndpoint->AddRef();
  1699. //
  1700. // Drop the socket data lock. It's safe since we pulled everything we
  1701. // need off of the list that needs protection.
  1702. //
  1703. pSocketData->Unlock();
  1704. fLockedSocketData = FALSE;
  1705. //
  1706. // See notes above about NULL handling.
  1707. //
  1708. if (pTempEndpoint->m_pActiveCommandData != NULL)
  1709. {
  1710. //
  1711. // Complete it (by closing this endpoint). Be considerate about the error
  1712. // code expected by our caller.
  1713. //
  1714. pTempEndpoint->m_pActiveCommandData->Lock();
  1715. if ( pTempEndpoint->m_pActiveCommandData->GetState() == COMMAND_STATE_CANCELLING )
  1716. {
  1717. pTempEndpoint->m_pActiveCommandData->Unlock();
  1718. DPFX(DPFPREP, 3, "Connect 0x%p command (endpoint 0x%p) is already cancelled.",
  1719. pTempEndpoint->m_pActiveCommandData, pTempEndpoint);
  1720. hTempResult = DPNERR_USERCANCEL;
  1721. }
  1722. else
  1723. {
  1724. //
  1725. // Mark the connect as uncancellable, since we're about to complete
  1726. // it with a failure.
  1727. //
  1728. if ( pTempEndpoint->m_pActiveCommandData->GetState() != COMMAND_STATE_INPROGRESS_CANNOT_CANCEL )
  1729. {
  1730. pTempEndpoint->m_pActiveCommandData->SetState( COMMAND_STATE_INPROGRESS_CANNOT_CANCEL );
  1731. }
  1732. //
  1733. // Retrieve the current command result.
  1734. //
  1735. hTempResult = pTempEndpoint->PendingCommandResult();
  1736. pTempEndpoint->m_pActiveCommandData->Unlock();
  1737. //
  1738. // If the command didn't have a descriptive error, assume it was
  1739. // not previously set (i.e. wasn't overridden by BindEndpoint above),
  1740. // and use NOCONNECTION instead.
  1741. //
  1742. if ( hTempResult == DPNERR_GENERIC )
  1743. {
  1744. hTempResult = DPNERR_NOCONNECTION;
  1745. }
  1746. DPFX(DPFPREP, 6, "Completing endpoint 0x%p connect (command 0x%p) with error 0x%lx.",
  1747. pTempEndpoint, pTempEndpoint->m_pActiveCommandData, hTempResult);
  1748. }
  1749. pTempEndpoint->Lock();
  1750. switch ( pTempEndpoint->GetState() )
  1751. {
  1752. case ENDPOINT_STATE_UNINITIALIZED:
  1753. {
  1754. DPFX(DPFPREP, 3, "Endpoint 0x%p is already completely closed.",
  1755. pTempEndpoint);
  1756. pTempEndpoint->Unlock();
  1757. break;
  1758. }
  1759. case ENDPOINT_STATE_ATTEMPTING_CONNECT:
  1760. case ENDPOINT_STATE_CONNECT_CONNECTED:
  1761. {
  1762. pTempEndpoint->SetState(ENDPOINT_STATE_DISCONNECTING);
  1763. pTempEndpoint->Unlock();
  1764. pTempEndpoint->Close( hTempResult );
  1765. pTempEndpoint->m_pSPData->CloseEndpointHandle( pTempEndpoint );
  1766. break;
  1767. }
  1768. case ENDPOINT_STATE_DISCONNECTING:
  1769. {
  1770. DPFX(DPFPREP, 3, "Endpoint 0x%p already disconnecting, not closing.",
  1771. pTempEndpoint);
  1772. pTempEndpoint->Unlock();
  1773. break;
  1774. }
  1775. default:
  1776. {
  1777. DPFX(DPFPREP, 0, "Endpoint 0x%p is invalid state %u!",
  1778. pTempEndpoint, pTempEndpoint->GetState());
  1779. DNASSERT(FALSE);
  1780. pTempEndpoint->Unlock();
  1781. break;
  1782. }
  1783. }
  1784. }
  1785. else
  1786. {
  1787. DPFX(DPFPREP, 1, "Endpoint 0x%p's active command data is NULL, skipping.",
  1788. pTempEndpoint);
  1789. }
  1790. //
  1791. // Drop the reference we used with the socketport list lock dropped.
  1792. //
  1793. pTempEndpoint->DecRef();
  1794. //
  1795. // Retake the socket data lock and go to next item.
  1796. //
  1797. pSocketData->Lock();
  1798. fLockedSocketData = TRUE;
  1799. }
  1800. pSocketData->Unlock();
  1801. fLockedSocketData = FALSE;
  1802. }
  1803. Exit:
  1804. if ( pSocketData != NULL )
  1805. {
  1806. pSocketData->Release();
  1807. pSocketData = NULL;
  1808. }
  1809. if ( ConnectAddressInfo.pHostAddress != NULL )
  1810. {
  1811. IDirectPlay8Address_Release( ConnectAddressInfo.pHostAddress );
  1812. ConnectAddressInfo.pHostAddress = NULL;
  1813. }
  1814. if ( ConnectAddressInfo.pDeviceAddress != NULL )
  1815. {
  1816. IDirectPlay8Address_Release( ConnectAddressInfo.pDeviceAddress );
  1817. ConnectAddressInfo.pDeviceAddress = NULL;
  1818. }
  1819. DNASSERT( pDeviceAddress != NULL );
  1820. IDirectPlay8Address_Release( pDeviceAddress );
  1821. DNASSERT( pHostAddress != NULL );
  1822. IDirectPlay8Address_Release( pHostAddress );
  1823. DNASSERT( !fLockedSocketData );
  1824. #ifndef DPNBUILD_ONLYONEADAPTER
  1825. DNASSERT(blIndicate.IsEmpty());
  1826. DNASSERT(blFail.IsEmpty());
  1827. #endif // ! DPNBUILD_ONLYONEADAPTER
  1828. DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr);
  1829. return hr;
  1830. Failure:
  1831. //
  1832. // If we still have the socket data lock, drop it.
  1833. //
  1834. if ( fLockedSocketData )
  1835. {
  1836. pSocketData->Unlock();
  1837. fLockedSocketData = FALSE;
  1838. }
  1839. //
  1840. // we've failed to complete the connect, clean up and return this endpoint
  1841. // to the pool
  1842. //
  1843. Close( hr );
  1844. m_pSPData->CloseEndpointHandle( this );
  1845. goto Exit;
  1846. }
  1847. //**********************************************************************
  1848. #ifndef DPNBUILD_ONLYONETHREAD
  1849. //**********************************************************************
  1850. // ------------------------------
  1851. // CEndpoint::ConnectBlockingJobWrapper - asynchronous callback wrapper for blocking job
  1852. //
  1853. // Entry: Pointer to job information
  1854. //
  1855. // Exit: Nothing
  1856. // ------------------------------
  1857. #undef DPF_MODNAME
  1858. #define DPF_MODNAME "CEndpoint::ConnectBlockingJobWrapper"
  1859. void CEndpoint::ConnectBlockingJobWrapper( void * const pvContext )
  1860. {
  1861. CEndpoint *pThisEndpoint;
  1862. // initialize
  1863. DNASSERT( pvContext != NULL );
  1864. pThisEndpoint = static_cast<CEndpoint*>( pvContext );
  1865. DNASSERT( pThisEndpoint->m_pActiveCommandData != NULL );
  1866. DNASSERT( pThisEndpoint->GetCommandParameters() != NULL );
  1867. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.hCommand == pThisEndpoint->m_pActiveCommandData );
  1868. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.dwCommandDescriptor != NULL_DESCRIPTOR );
  1869. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pAddressHost != NULL );
  1870. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pAddressDeviceInfo != NULL );
  1871. pThisEndpoint->ConnectBlockingJob();
  1872. }
  1873. //**********************************************************************
  1874. //**********************************************************************
  1875. // ------------------------------
  1876. // CEndpoint::ConnectBlockingJob - complete connect blocking job
  1877. //
  1878. // Entry: Nothing
  1879. //
  1880. // Exit: Nothing
  1881. //
  1882. // Note: Calling this function may result in the deletion of 'this', don't
  1883. // do anything else with this object after calling!!!!
  1884. // ------------------------------
  1885. #undef DPF_MODNAME
  1886. #define DPF_MODNAME "CEndpoint::ConnectBlockingJob"
  1887. void CEndpoint::ConnectBlockingJob( void )
  1888. {
  1889. HRESULT hr;
  1890. //
  1891. // Try to resolve the host name. It's possible we already did this
  1892. // when we first opened the endpoint, and we only need to resolve
  1893. // the hostname, but it's simpler to just do it all again anyway.
  1894. //
  1895. hr = m_pRemoteMachineAddress->SocketAddressFromDP8Address( GetCommandParameters()->PendingCommandData.ConnectData.pAddressHost,
  1896. #ifdef DPNBUILD_XNETSECURITY
  1897. ((m_fSecureTransport) ? &m_ullKeyID : NULL),
  1898. #endif // DPNBUILD_XNETSECURITY
  1899. TRUE,
  1900. SP_ADDRESS_TYPE_HOST );
  1901. if ( hr != DPN_OK )
  1902. {
  1903. DPFX(DPFPREP, 0, "Couldn't get valid address!" );
  1904. DisplayDNError( 0, hr );
  1905. goto Failure;
  1906. }
  1907. //
  1908. // Make sure its valid and not banned.
  1909. //
  1910. if (! m_pRemoteMachineAddress->IsValidUnicastAddress(FALSE))
  1911. {
  1912. DPFX(DPFPREP, 0, "Host address is invalid!");
  1913. hr = DPNERR_INVALIDHOSTADDRESS;
  1914. goto Failure;
  1915. }
  1916. #ifndef DPNBUILD_NOREGISTRY
  1917. if (m_pRemoteMachineAddress->IsBannedAddress())
  1918. {
  1919. DPFX(DPFPREP, 0, "Host address is banned!");
  1920. hr = DPNERR_NOTALLOWED;
  1921. goto Failure;
  1922. }
  1923. #endif // ! DPNBUILD_NOREGISTRY
  1924. //
  1925. // Make sure the user isn't trying to connect to the DPNSVR port.
  1926. //
  1927. if ( m_pRemoteMachineAddress->GetPort() == HTONS(DPNA_DPNSVR_PORT) )
  1928. {
  1929. DPFX(DPFPREP, 0, "Attempting to connect to DPNSVR reserved port!" );
  1930. hr = DPNERR_INVALIDHOSTADDRESS;
  1931. goto Failure;
  1932. }
  1933. #ifndef DPNBUILD_NONATHELP
  1934. //
  1935. // Try to get NAT help loaded, if it isn't already and we're allowed.
  1936. //
  1937. if (GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE)
  1938. {
  1939. DPFX(DPFPREP, 7, "Ensuring that NAT help is loaded.");
  1940. m_pSPData->GetThreadPool()->EnsureNATHelpLoaded();
  1941. }
  1942. #endif // ! DPNBUILD_NONATHELP
  1943. Exit:
  1944. //
  1945. // Submit the job for completion (for real). We want it to occur on
  1946. // a thread pool thread so that the user has gotten notified about the
  1947. // thread prior to getting a callback on it. We do it in even the failure
  1948. // case.
  1949. //
  1950. // NOTE: If this fails, we will rely on the caller that triggered the original
  1951. // operation to cancel the command at some point, probably when he
  1952. // decides the operation is taking too long.
  1953. //
  1954. #ifdef DPNBUILD_ONLYONEPROCESSOR
  1955. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::ConnectJobCallback,
  1956. this );
  1957. #else // ! DPNBUILD_ONLYONEPROCESSOR
  1958. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
  1959. CEndpoint::ConnectJobCallback,
  1960. this );
  1961. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1962. if ( hr != DPN_OK )
  1963. {
  1964. DPFX(DPFPREP, 0, "Failed to queue delayed connect completion! Operation must be cancelled." );
  1965. DisplayDNError( 0, hr );
  1966. //
  1967. // Leave endpoint reference, see notes above.
  1968. //
  1969. }
  1970. return;
  1971. Failure:
  1972. //
  1973. // Attempt to attach the failure code to the command. If the user was
  1974. // already cancelling this command, we will just leave the command alone.
  1975. //
  1976. m_pActiveCommandData->Lock();
  1977. if (m_pActiveCommandData->GetState() != COMMAND_STATE_CANCELLING)
  1978. {
  1979. DNASSERT(m_pActiveCommandData->GetState() == COMMAND_STATE_PENDING);
  1980. m_pActiveCommandData->SetState(COMMAND_STATE_FAILING);
  1981. m_hrPendingCommandResult = hr;
  1982. }
  1983. else
  1984. {
  1985. DPFX(DPFPREP, 0, "User cancelled command, ignoring failure result 0x%lx.",
  1986. hr);
  1987. }
  1988. m_pActiveCommandData->Unlock();
  1989. goto Exit;
  1990. }
  1991. //**********************************************************************
  1992. #endif // ! DPNBUILD_ONLYONETHREAD
  1993. //**********************************************************************
  1994. // ------------------------------
  1995. // CEndpoint::Disconnect - disconnect an endpoint
  1996. //
  1997. // Entry: Nothing
  1998. //
  1999. // Exit: Error code
  2000. //
  2001. // Notes: This function assumes that the endpoint is locked. If this
  2002. // function completes successfully (returns DPN_OK), the endpoint
  2003. // is no longer locked (it was returned to the pool).
  2004. // ------------------------------
  2005. #undef DPF_MODNAME
  2006. #define DPF_MODNAME "CEndpoint::Disconnect"
  2007. HRESULT CEndpoint::Disconnect( void )
  2008. {
  2009. HRESULT hr;
  2010. DPFX(DPFPREP, 6, "(0x%p) Enter", this);
  2011. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  2012. //
  2013. // initialize
  2014. //
  2015. hr = DPNERR_PENDING;
  2016. Lock();
  2017. switch ( GetState() )
  2018. {
  2019. //
  2020. // connected endpoint
  2021. //
  2022. case ENDPOINT_STATE_CONNECT_CONNECTED:
  2023. {
  2024. DNASSERT( GetCommandParameters() == NULL );
  2025. DNASSERT( m_pActiveCommandData == NULL );
  2026. SetState( ENDPOINT_STATE_DISCONNECTING );
  2027. AddRef();
  2028. //
  2029. // Unlock this endpoint before calling to a higher level. The endpoint
  2030. // has already been labeled as DISCONNECTING so nothing will happen to it.
  2031. //
  2032. Unlock();
  2033. //
  2034. // Need to release the reference that was added for the connection at this
  2035. // point or the endpoint will never be returned to the pool.
  2036. //
  2037. DecRef();
  2038. //
  2039. // release reference from just after setting state
  2040. //
  2041. Close( DPN_OK );
  2042. DecCommandRef();
  2043. DecRef();
  2044. break;
  2045. }
  2046. //
  2047. // some other endpoint state
  2048. //
  2049. default:
  2050. {
  2051. hr = DPNERR_INVALIDENDPOINT;
  2052. DPFX(DPFPREP, 0, "Attempted to disconnect endpoint that's not connected!" );
  2053. switch ( m_State )
  2054. {
  2055. case ENDPOINT_STATE_UNINITIALIZED:
  2056. {
  2057. DPFX(DPFPREP, 0, "ENDPOINT_STATE_UNINITIALIZED" );
  2058. break;
  2059. }
  2060. case ENDPOINT_STATE_ATTEMPTING_CONNECT:
  2061. {
  2062. DPFX(DPFPREP, 0, "ENDPOINT_STATE_ATTEMPTING_CONNECT" );
  2063. break;
  2064. }
  2065. case ENDPOINT_STATE_ATTEMPTING_LISTEN:
  2066. {
  2067. DPFX(DPFPREP, 0, "ENDPOINT_STATE_ATTEMPTING_LISTEN" );
  2068. break;
  2069. }
  2070. case ENDPOINT_STATE_ENUM:
  2071. {
  2072. DPFX(DPFPREP, 0, "ENDPOINT_STATE_ENUM" );
  2073. break;
  2074. }
  2075. case ENDPOINT_STATE_DISCONNECTING:
  2076. {
  2077. DPFX(DPFPREP, 0, "ENDPOINT_STATE_DISCONNECTING" );
  2078. break;
  2079. }
  2080. case ENDPOINT_STATE_WAITING_TO_COMPLETE:
  2081. {
  2082. DPFX(DPFPREP, 0, "ENDPOINT_STATE_WAITING_TO_COMPLETE" );
  2083. break;
  2084. }
  2085. default:
  2086. {
  2087. DNASSERT( FALSE );
  2088. break;
  2089. }
  2090. }
  2091. Unlock();
  2092. DNASSERT( FALSE );
  2093. goto Failure;
  2094. break;
  2095. }
  2096. }
  2097. Exit:
  2098. DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr);
  2099. return hr;
  2100. Failure:
  2101. // nothing to do
  2102. goto Exit;
  2103. }
  2104. //**********************************************************************
  2105. //**********************************************************************
  2106. // ------------------------------
  2107. // CEndpoint::StopEnumCommand - stop a running enum command
  2108. //
  2109. // Entry: Command result
  2110. //
  2111. // Exit: Nothing
  2112. //
  2113. // Notes: This function assumes that the endpoint is locked. If this
  2114. // function completes successfully (returns DPN_OK), the endpoint
  2115. // is no longer locked (it was returned to the pool).
  2116. // ------------------------------
  2117. #undef DPF_MODNAME
  2118. #define DPF_MODNAME "CEndpoint::StopEnumCommand"
  2119. void CEndpoint::StopEnumCommand( const HRESULT hCommandResult )
  2120. {
  2121. Lock();
  2122. #ifndef DPNBUILD_NOSPUI
  2123. if ( GetActiveDialogHandle() != NULL )
  2124. {
  2125. StopSettingsDialog( GetActiveDialogHandle() );
  2126. Unlock();
  2127. }
  2128. else
  2129. #endif // !DPNBUILD_NOSPUI
  2130. {
  2131. BOOL fStoppedJob;
  2132. //
  2133. // Don't hold the lock when cancelling a timer job because the
  2134. // job might be in progress and attempting to use this endpoint!
  2135. //
  2136. Unlock();
  2137. fStoppedJob = m_pSPData->GetThreadPool()->StopTimerJob( m_pActiveCommandData, hCommandResult );
  2138. if ( ! fStoppedJob )
  2139. {
  2140. //
  2141. // Either the endpoint just completed or it had never been started.
  2142. // Check the state to determine which of those scenarios happened.
  2143. //
  2144. Lock();
  2145. if ( GetState() == ENDPOINT_STATE_ATTEMPTING_ENUM )
  2146. {
  2147. //
  2148. // This is a multiplexed enum that is getting cancelled. We
  2149. // need to complete it.
  2150. //
  2151. Unlock();
  2152. DPFX(DPFPREP, 1, "Endpoint 0x%p completing unstarted multiplexed enum (context/command 0x%p) with result 0x%lx.",
  2153. this, m_pActiveCommandData, hCommandResult);
  2154. EnumComplete( hCommandResult );
  2155. }
  2156. else
  2157. {
  2158. Unlock();
  2159. //
  2160. // The enum is in progress, it should detect that it needs to
  2161. // be cancelled. We don't need to do any work here.
  2162. //
  2163. DPFX(DPFPREP, 1, "Endpoint 0x%p unable to stop timer job (context/command 0x%p, state = %u, result would have been 0x%lx).",
  2164. this, m_pActiveCommandData, GetState(), hCommandResult);
  2165. }
  2166. }
  2167. }
  2168. }
  2169. //**********************************************************************
  2170. //**********************************************************************
  2171. // ------------------------------
  2172. // CEndpoint::CopyListenData - copy data for listen command
  2173. //
  2174. // Entry: Pointer to job information
  2175. // Pointer to device address
  2176. //
  2177. // Exit: Error code
  2178. //
  2179. // Note: Device address needs to be preserved for later use.
  2180. // ------------------------------
  2181. #undef DPF_MODNAME
  2182. #define DPF_MODNAME "CEndpoint::CopyListenData"
  2183. HRESULT CEndpoint::CopyListenData( const SPLISTENDATA *const pListenData, IDirectPlay8Address *const pDeviceAddress )
  2184. {
  2185. HRESULT hr;
  2186. ENDPOINT_COMMAND_PARAMETERS *pCommandParameters;
  2187. DNASSERT( pListenData != NULL );
  2188. DNASSERT( pDeviceAddress != NULL );
  2189. DNASSERT( pListenData->hCommand != NULL );
  2190. DNASSERT( pListenData->dwCommandDescriptor != NULL_DESCRIPTOR );
  2191. DNASSERT( m_pActiveCommandData == NULL );
  2192. DNASSERT( m_fListenStatusNeedsToBeIndicated == FALSE );
  2193. //
  2194. // initialize
  2195. //
  2196. hr = DPN_OK;
  2197. pCommandParameters = NULL;
  2198. pCommandParameters = (ENDPOINT_COMMAND_PARAMETERS*)g_EndpointCommandParametersPool.Get();
  2199. if ( pCommandParameters != NULL )
  2200. {
  2201. SetCommandParameters( pCommandParameters );
  2202. DBG_CASSERT( sizeof( pCommandParameters->PendingCommandData.ListenData ) == sizeof( *pListenData ) );
  2203. memcpy( &pCommandParameters->PendingCommandData.ListenData, pListenData, sizeof( pCommandParameters->PendingCommandData.ListenData ) );
  2204. pCommandParameters->PendingCommandData.ListenData.pAddressDeviceInfo = pDeviceAddress;
  2205. IDirectPlay8Address_AddRef( pDeviceAddress );
  2206. m_fListenStatusNeedsToBeIndicated = TRUE;
  2207. m_pActiveCommandData = static_cast<CCommandData*>( pCommandParameters->PendingCommandData.ListenData.hCommand );
  2208. m_State = ENDPOINT_STATE_ATTEMPTING_LISTEN;
  2209. DNASSERT( hr == DPN_OK );
  2210. }
  2211. else
  2212. {
  2213. hr = DPNERR_OUTOFMEMORY;
  2214. }
  2215. return hr;
  2216. }
  2217. //**********************************************************************
  2218. //**********************************************************************
  2219. // ------------------------------
  2220. // CEndpoint::ListenJobCallback - asynchronous callback wrapper for work thread
  2221. //
  2222. // Entry: Pointer to job information
  2223. //
  2224. // Exit: Nothing
  2225. // ------------------------------
  2226. #undef DPF_MODNAME
  2227. #define DPF_MODNAME "CEndpoint::ListenJobCallback"
  2228. void CEndpoint::ListenJobCallback( void * const pvContext, void * const pvTimerData, const UINT uiTimerUnique )
  2229. {
  2230. HRESULT hr;
  2231. CEndpoint *pThisEndpoint;
  2232. // initialize
  2233. DNASSERT( pvContext != NULL );
  2234. pThisEndpoint = static_cast<CEndpoint*>( pvContext );
  2235. DNASSERT( pThisEndpoint->m_pActiveCommandData != NULL );
  2236. DNASSERT( pThisEndpoint->GetCommandParameters() != NULL );
  2237. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ListenData.hCommand == pThisEndpoint->m_pActiveCommandData );
  2238. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ListenData.dwCommandDescriptor != NULL_DESCRIPTOR );
  2239. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ListenData.pAddressDeviceInfo != NULL );
  2240. hr = pThisEndpoint->CompleteListen();
  2241. if ( hr != DPN_OK )
  2242. {
  2243. DPFX(DPFPREP, 0, "Problem completing listen in job callback!" );
  2244. DisplayDNError( 0, hr );
  2245. goto Exit;
  2246. }
  2247. Exit:
  2248. pThisEndpoint->DecRef();
  2249. return;
  2250. }
  2251. //**********************************************************************
  2252. //**********************************************************************
  2253. // ------------------------------
  2254. // CEndpoint::CompleteListen - complete listen process
  2255. //
  2256. // Entry: Nothing
  2257. //
  2258. // Exit: Error code
  2259. //
  2260. // Note: Calling this function may result in the deletion of 'this', don't
  2261. // do anything else with this object after calling!!!!
  2262. // ------------------------------
  2263. #undef DPF_MODNAME
  2264. #define DPF_MODNAME "CEndpoint::CompleteListen"
  2265. HRESULT CEndpoint::CompleteListen( void )
  2266. {
  2267. HRESULT hr;
  2268. HRESULT hTempResult;
  2269. SPIE_LISTENSTATUS ListenStatus;
  2270. BOOL fEndpointLocked;
  2271. SPIE_LISTENADDRESSINFO ListenAddressInfo;
  2272. IDirectPlay8Address * pDeviceAddress;
  2273. ENDPOINT_COMMAND_PARAMETERS * pCommandParameters;
  2274. DPFX(DPFPREP, 6, "(0x%p) Enter", this);
  2275. DNASSERT( GetCommandParameters() != NULL );
  2276. //
  2277. // initialize
  2278. //
  2279. hr = DPN_OK;
  2280. fEndpointLocked = FALSE;
  2281. memset( &ListenStatus, 0x00, sizeof( ListenStatus ) );
  2282. memset( &ListenAddressInfo, 0x00, sizeof( ListenAddressInfo ) );
  2283. pCommandParameters = GetCommandParameters();
  2284. //
  2285. // Transfer address reference to the local pointer. This will be released at the
  2286. // end of this function, but we'll keep the pointer in the pending command data so
  2287. // CSPData::BindEndpoint can still access it.
  2288. //
  2289. pDeviceAddress = pCommandParameters->PendingCommandData.ListenData.pAddressDeviceInfo;
  2290. DNASSERT( pDeviceAddress != NULL );
  2291. DNASSERT( m_State == ENDPOINT_STATE_ATTEMPTING_LISTEN );
  2292. DNASSERT( m_pActiveCommandData != NULL );
  2293. DNASSERT( pCommandParameters->PendingCommandData.ListenData.hCommand == m_pActiveCommandData );
  2294. DNASSERT( pCommandParameters->PendingCommandData.ListenData.dwCommandDescriptor != NULL_DESCRIPTOR );
  2295. #ifdef DBG
  2296. if (pCommandParameters->PendingCommandData.ListenData.dwFlags & DPNSPF_BINDLISTENTOGATEWAY)
  2297. {
  2298. DNASSERT( pCommandParameters->GatewayBindType == GATEWAY_BIND_TYPE_SPECIFIC_SHARED );
  2299. }
  2300. else
  2301. {
  2302. DNASSERT( pCommandParameters->GatewayBindType == GATEWAY_BIND_TYPE_UNKNOWN );
  2303. }
  2304. #endif // DBG
  2305. //
  2306. // check for user cancelling command
  2307. //
  2308. m_pActiveCommandData->Lock();
  2309. #ifdef DPNBUILD_NOMULTICAST
  2310. DNASSERT( m_pActiveCommandData->GetType() == COMMAND_TYPE_LISTEN );
  2311. #else // ! DPNBUILD_NOMULTICAST
  2312. DNASSERT( (m_pActiveCommandData->GetType() == COMMAND_TYPE_LISTEN) || (m_pActiveCommandData->GetType() == COMMAND_TYPE_MULTICAST_LISTEN) );
  2313. #endif // ! DPNBUILD_NOMULTICAST
  2314. switch ( m_pActiveCommandData->GetState() )
  2315. {
  2316. //
  2317. // command is pending, mark as in-progress
  2318. //
  2319. case COMMAND_STATE_PENDING:
  2320. {
  2321. m_pActiveCommandData->SetState( COMMAND_STATE_INPROGRESS );
  2322. Lock();
  2323. fEndpointLocked = TRUE;
  2324. DNASSERT( hr == DPN_OK );
  2325. break;
  2326. }
  2327. //
  2328. // command has been cancelled
  2329. //
  2330. case COMMAND_STATE_CANCELLING:
  2331. {
  2332. hr = DPNERR_USERCANCEL;
  2333. DPFX(DPFPREP, 0, "User cancelled listen!" );
  2334. break;
  2335. }
  2336. #ifndef DPNBUILD_ONLYONETHREAD
  2337. //
  2338. // blocking operation failed
  2339. //
  2340. case COMMAND_STATE_FAILING:
  2341. {
  2342. hr = m_hrPendingCommandResult;
  2343. DNASSERT(hr != DPN_OK);
  2344. DPFX(DPFPREP, 0, "Listen blocking operation failed!" );
  2345. break;
  2346. }
  2347. #endif // ! DPNBUILD_ONLYONETHREAD
  2348. //
  2349. // other state
  2350. //
  2351. default:
  2352. {
  2353. break;
  2354. }
  2355. }
  2356. m_pActiveCommandData->Unlock();
  2357. if ( hr != DPN_OK )
  2358. {
  2359. goto Failure;
  2360. }
  2361. //
  2362. // note that this endpoint is officially listening before adding it to the
  2363. // socket port because it may get used immediately.
  2364. // Also note that the GATEWAY_BIND_TYPE actually used
  2365. // (GetGatewayBindType()) may differ from
  2366. // pCommandParameters->GatewayBindType.
  2367. //
  2368. m_State = ENDPOINT_STATE_LISTEN;
  2369. hr = m_pSPData->BindEndpoint( this, pDeviceAddress, NULL, pCommandParameters->GatewayBindType );
  2370. if ( hr != DPN_OK )
  2371. {
  2372. DPFX(DPFPREP, 0, "Failed to bind endpoint!" );
  2373. DisplayDNError( 0, hr );
  2374. goto Failure;
  2375. }
  2376. //
  2377. // attempt to indicate addressing to a higher layer
  2378. //
  2379. #ifdef DPNBUILD_XNETSECURITY
  2380. ListenAddressInfo.pDeviceAddress = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, NULL, GetGatewayBindType() );
  2381. #else // ! DPNBUILD_XNETSECURITY
  2382. ListenAddressInfo.pDeviceAddress = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, GetGatewayBindType() );
  2383. #endif // ! DPNBUILD_XNETSECURITY
  2384. if ( ListenAddressInfo.pDeviceAddress == NULL )
  2385. {
  2386. hr = DPNERR_OUTOFMEMORY;
  2387. goto Failure;
  2388. }
  2389. #ifndef DPNBUILD_NOMULTICAST
  2390. //
  2391. // For multicast listens, we also need to include the multicast address
  2392. // being used.
  2393. //
  2394. if ( GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN )
  2395. {
  2396. const SOCKADDR_IN * psaddrinTemp;
  2397. TCHAR tszMulticastAddress[16]; // nnn.nnn.nnn.nnn + NULL termination
  2398. DNASSERT( GetRemoteAddressPointer()->GetFamily() == AF_INET );
  2399. psaddrinTemp = (const SOCKADDR_IN *) GetRemoteAddressPointer()->GetAddress();
  2400. wsprintf(tszMulticastAddress, _T("%u.%u.%u.%u"),
  2401. psaddrinTemp->sin_addr.S_un.S_un_b.s_b1,
  2402. psaddrinTemp->sin_addr.S_un.S_un_b.s_b2,
  2403. psaddrinTemp->sin_addr.S_un.S_un_b.s_b3,
  2404. psaddrinTemp->sin_addr.S_un.S_un_b.s_b4);
  2405. //
  2406. // Add the host name component to the device address.
  2407. //
  2408. #ifdef UNICODE
  2409. hr = IDirectPlay8Address_AddComponent( ListenAddressInfo.pDeviceAddress,
  2410. DPNA_KEY_HOSTNAME,
  2411. tszMulticastAddress,
  2412. ((_tcslen(tszMulticastAddress) + 1) * sizeof(TCHAR)),
  2413. DPNA_DATATYPE_STRING );
  2414. #else // ! UNICODE
  2415. hr = IDirectPlay8Address_AddComponent( ListenAddressInfo.pDeviceAddress,
  2416. DPNA_KEY_HOSTNAME,
  2417. tszMulticastAddress,
  2418. ((_tcslen(tszMulticastAddress) + 1) * sizeof(TCHAR)),
  2419. DPNA_DATATYPE_STRING_ANSI );
  2420. #endif // ! UNICODE
  2421. if (hr != DPN_OK)
  2422. {
  2423. DPFX(DPFPREP, 0, "Failed to add hostname component to device address!" );
  2424. DisplayDNError( 0, hr );
  2425. goto Failure;
  2426. }
  2427. }
  2428. #endif // ! DPNBUILD_NOMULTICAST
  2429. //
  2430. // Listens are not affected by the same multiplexed adapter problems (see
  2431. // CompleteConnect and CompleteEnumQuery), so we don't need that workaround
  2432. // code.
  2433. //
  2434. Unlock();
  2435. fEndpointLocked = FALSE;
  2436. Exit:
  2437. //
  2438. // report the listen address info and status
  2439. //
  2440. if ( m_fListenStatusNeedsToBeIndicated != FALSE )
  2441. {
  2442. m_fListenStatusNeedsToBeIndicated = FALSE;
  2443. //
  2444. // If we don't currently have a device address object, just use the one passed
  2445. // in to the Listen call.
  2446. //
  2447. if (ListenAddressInfo.pDeviceAddress == NULL)
  2448. {
  2449. IDirectPlay8Address_AddRef( pCommandParameters->PendingCommandData.ListenData.pAddressDeviceInfo );
  2450. ListenAddressInfo.pDeviceAddress = pCommandParameters->PendingCommandData.ListenData.pAddressDeviceInfo;
  2451. }
  2452. ListenAddressInfo.hCommandStatus = hr;
  2453. ListenAddressInfo.pCommandContext = pCommandParameters->PendingCommandData.ListenData.pvContext;
  2454. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_LISTENADDRESSINFO 0x%p to interface 0x%p.",
  2455. this, &ListenAddressInfo, m_pSPData->DP8SPCallbackInterface());
  2456. DumpAddress( 8, _T("\t Device:"), ListenAddressInfo.pDeviceAddress );
  2457. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  2458. hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
  2459. SPEV_LISTENADDRESSINFO, // event type
  2460. &ListenAddressInfo // pointer to data
  2461. );
  2462. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_LISTENADDRESSINFO [0x%lx].",
  2463. this, hTempResult);
  2464. DNASSERT( hTempResult == DPN_OK );
  2465. ListenStatus.hResult = hr;
  2466. DNASSERT( m_pActiveCommandData == pCommandParameters->PendingCommandData.ListenData.hCommand );
  2467. ListenStatus.hCommand = pCommandParameters->PendingCommandData.ListenData.hCommand;
  2468. ListenStatus.pUserContext = pCommandParameters->PendingCommandData.ListenData.pvContext;
  2469. ListenStatus.hEndpoint = (HANDLE) this;
  2470. //
  2471. // if the listen binding failed, there's no socket port to dereference so
  2472. // return GUID_NULL as set by the memset.
  2473. //
  2474. if ( GetSocketPort() != NULL )
  2475. {
  2476. GetSocketPort()->GetNetworkAddress()->GuidFromInternalAddressWithoutPort( &ListenStatus.ListenAdapter );
  2477. }
  2478. //
  2479. // it's possible that this endpoint was cleaned up so its internal pointers to the
  2480. // COM and data interfaces may have been wiped, use the cached pointer
  2481. //
  2482. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_LISTENSTATUS 0x%p to interface 0x%p.",
  2483. this, &ListenStatus, m_pSPData->DP8SPCallbackInterface());
  2484. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  2485. hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DPlay callback interface
  2486. SPEV_LISTENSTATUS, // data type
  2487. &ListenStatus // pointer to data
  2488. );
  2489. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_LISTENSTATUS [0x%lx].",
  2490. this, hTempResult);
  2491. DNASSERT( hTempResult == DPN_OK );
  2492. //
  2493. // if we succeeded, start allowing enumerations to be handled
  2494. //
  2495. if ( GetSocketPort() != NULL )
  2496. {
  2497. SetEnumsAllowedOnListen( TRUE, FALSE );
  2498. }
  2499. }
  2500. if ( ListenAddressInfo.pDeviceAddress != NULL )
  2501. {
  2502. IDirectPlay8Address_Release( ListenAddressInfo.pDeviceAddress );
  2503. ListenAddressInfo.pDeviceAddress = NULL;
  2504. }
  2505. DNASSERT( pDeviceAddress != NULL );
  2506. IDirectPlay8Address_Release( pDeviceAddress );
  2507. DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr);
  2508. return hr;
  2509. Failure:
  2510. //
  2511. // we've failed to complete the listen, clean up and return this
  2512. // endpoint to the pool
  2513. //
  2514. if ( fEndpointLocked != FALSE )
  2515. {
  2516. Unlock();
  2517. fEndpointLocked = FALSE;
  2518. }
  2519. Close( hr );
  2520. m_pSPData->CloseEndpointHandle( this );
  2521. goto Exit;
  2522. }
  2523. //**********************************************************************
  2524. #ifndef DPNBUILD_ONLYONETHREAD
  2525. //**********************************************************************
  2526. // ------------------------------
  2527. // CEndpoint::ListenBlockingJobWrapper - asynchronous callback wrapper for blocking job
  2528. //
  2529. // Entry: Pointer to job information
  2530. //
  2531. // Exit: Nothing
  2532. // ------------------------------
  2533. #undef DPF_MODNAME
  2534. #define DPF_MODNAME "CEndpoint::ListenBlockingJobWrapper"
  2535. void CEndpoint::ListenBlockingJobWrapper( void * const pvContext )
  2536. {
  2537. CEndpoint *pThisEndpoint;
  2538. // initialize
  2539. DNASSERT( pvContext != NULL );
  2540. pThisEndpoint = static_cast<CEndpoint*>( pvContext );
  2541. DNASSERT( pThisEndpoint->m_pActiveCommandData != NULL );
  2542. DNASSERT( pThisEndpoint->GetCommandParameters() != NULL );
  2543. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ListenData.hCommand == pThisEndpoint->m_pActiveCommandData );
  2544. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ListenData.dwCommandDescriptor != NULL_DESCRIPTOR );
  2545. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.ListenData.pAddressDeviceInfo != NULL );
  2546. pThisEndpoint->ListenBlockingJob();
  2547. }
  2548. //**********************************************************************
  2549. //**********************************************************************
  2550. // ------------------------------
  2551. // CEndpoint::ListenBlockingJob - complete listen blocking job
  2552. //
  2553. // Entry: Nothing
  2554. //
  2555. // Exit: Nothing
  2556. //
  2557. // Note: Calling this function may result in the deletion of 'this', don't
  2558. // do anything else with this object after calling!!!!
  2559. // ------------------------------
  2560. #undef DPF_MODNAME
  2561. #define DPF_MODNAME "CEndpoint::ListenBlockingJob"
  2562. void CEndpoint::ListenBlockingJob( void )
  2563. {
  2564. HRESULT hr;
  2565. #ifndef DPNBUILD_NONATHELP
  2566. //
  2567. // Try to get NAT help loaded, if it isn't already and we're allowed.
  2568. //
  2569. if (GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE)
  2570. {
  2571. DPFX(DPFPREP, 7, "Ensuring that NAT help is loaded.");
  2572. m_pSPData->GetThreadPool()->EnsureNATHelpLoaded();
  2573. }
  2574. #endif // ! DPNBUILD_NONATHELP
  2575. //
  2576. // Submit the job for completion (for real). We want it to occur on
  2577. // a thread pool thread so that the user has gotten notified about the
  2578. // thread prior to getting a callback on it.
  2579. //
  2580. // NOTE: If this fails, we will rely on the caller that triggered the original
  2581. // operation to cancel the command at some point, probably when he
  2582. // decides the operation is taking too long. We leave the endpoint
  2583. // reference.
  2584. //
  2585. #ifdef DPNBUILD_ONLYONEPROCESSOR
  2586. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::ListenJobCallback,
  2587. this );
  2588. #else // ! DPNBUILD_ONLYONEPROCESSOR
  2589. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
  2590. CEndpoint::ListenJobCallback,
  2591. this );
  2592. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  2593. if ( hr != DPN_OK )
  2594. {
  2595. DPFX(DPFPREP, 0, "Failed to queue delayed listen completion! Operation must be cancelled." );
  2596. DisplayDNError( 0, hr );
  2597. //
  2598. // Leave endpoint reference, see notes above.
  2599. //
  2600. }
  2601. }
  2602. //**********************************************************************
  2603. #endif // ! DPNBUILD_ONLYONETHREAD
  2604. //**********************************************************************
  2605. // ------------------------------
  2606. // CEndpoint::CopyEnumQueryData - copy data for enum query command
  2607. //
  2608. // Entry: Pointer to command data
  2609. //
  2610. // Exit: Error code
  2611. //
  2612. // Note: Device address needs to be preserved for later use.
  2613. // ------------------------------
  2614. #undef DPF_MODNAME
  2615. #define DPF_MODNAME "CEndpoint::CopyEnumQueryData"
  2616. HRESULT CEndpoint::CopyEnumQueryData( const SPENUMQUERYDATA *const pEnumQueryData )
  2617. {
  2618. HRESULT hr;
  2619. ENDPOINT_COMMAND_PARAMETERS *pCommandParameters;
  2620. DNASSERT( pEnumQueryData != NULL );
  2621. DNASSERT( pEnumQueryData->hCommand != NULL );
  2622. DNASSERT( pEnumQueryData->dwCommandDescriptor != NULL_DESCRIPTOR );
  2623. DNASSERT( m_pActiveCommandData == NULL );
  2624. //
  2625. // initialize
  2626. //
  2627. hr = DPN_OK;
  2628. pCommandParameters = NULL;
  2629. pCommandParameters = (ENDPOINT_COMMAND_PARAMETERS*)g_EndpointCommandParametersPool.Get();
  2630. if ( pCommandParameters != NULL )
  2631. {
  2632. SetCommandParameters( pCommandParameters );
  2633. DBG_CASSERT( sizeof( pCommandParameters->PendingCommandData.EnumQueryData ) == sizeof( *pEnumQueryData ) );
  2634. memcpy( &pCommandParameters->PendingCommandData.EnumQueryData, pEnumQueryData, sizeof( pCommandParameters->PendingCommandData.EnumQueryData ) );
  2635. pCommandParameters->PendingCommandData.EnumQueryData.pAddressHost = pEnumQueryData->pAddressHost;
  2636. IDirectPlay8Address_AddRef( pEnumQueryData->pAddressHost );
  2637. pCommandParameters->PendingCommandData.EnumQueryData.pAddressDeviceInfo = pEnumQueryData->pAddressDeviceInfo;
  2638. IDirectPlay8Address_AddRef( pEnumQueryData->pAddressDeviceInfo );
  2639. m_pActiveCommandData = static_cast<CCommandData*>( pCommandParameters->PendingCommandData.EnumQueryData.hCommand );
  2640. m_pActiveCommandData->SetUserContext( pEnumQueryData->pvContext );
  2641. m_State = ENDPOINT_STATE_ATTEMPTING_ENUM;
  2642. DNASSERT( hr == DPN_OK );
  2643. }
  2644. else
  2645. {
  2646. hr = DPNERR_OUTOFMEMORY;
  2647. }
  2648. return hr;
  2649. }
  2650. //**********************************************************************
  2651. //**********************************************************************
  2652. // ------------------------------
  2653. // CEndpoint::EnumQueryJobCallback - asynchronous callback wrapper for work thread
  2654. //
  2655. // Entry: Pointer to job information
  2656. //
  2657. // Exit: Nothing
  2658. // ------------------------------
  2659. #undef DPF_MODNAME
  2660. #define DPF_MODNAME "CEndpoint::EnumQueryJobCallback"
  2661. void CEndpoint::EnumQueryJobCallback( void * const pvContext, void * const pvTimerData, const UINT uiTimerUnique )
  2662. {
  2663. HRESULT hr;
  2664. CEndpoint *pThisEndpoint;
  2665. // initialize
  2666. DNASSERT( pvContext != NULL );
  2667. pThisEndpoint = static_cast<CEndpoint*>( pvContext );
  2668. DNASSERT( pThisEndpoint->m_pActiveCommandData != NULL );
  2669. DNASSERT( pThisEndpoint->GetCommandParameters() != NULL );
  2670. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.hCommand == pThisEndpoint->m_pActiveCommandData );
  2671. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwCommandDescriptor != NULL_DESCRIPTOR );
  2672. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost != NULL );
  2673. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressDeviceInfo != NULL );
  2674. hr = pThisEndpoint->CompleteEnumQuery();
  2675. if ( hr != DPN_OK )
  2676. {
  2677. DPFX(DPFPREP, 0, "Problem completing enum query in job callback!" );
  2678. DisplayDNError( 0, hr );
  2679. goto Exit;
  2680. }
  2681. //
  2682. // Don't do anything here because it's possible that this object was returned to the pool!!!!
  2683. //
  2684. Exit:
  2685. pThisEndpoint->DecRef();
  2686. return;
  2687. }
  2688. //**********************************************************************
  2689. //**********************************************************************
  2690. // ------------------------------
  2691. // CEndpoint::CompleteEnumQuery - complete enum query process
  2692. //
  2693. // Entry: Nothing
  2694. //
  2695. // Exit: Error code
  2696. //
  2697. // Note: Calling this function may result in the deletion of 'this', don't
  2698. // do anything else with this object after calling!!!!
  2699. // ------------------------------
  2700. #undef DPF_MODNAME
  2701. #define DPF_MODNAME "CEndpoint::CompleteEnumQuery"
  2702. HRESULT CEndpoint::CompleteEnumQuery( void )
  2703. {
  2704. HRESULT hr;
  2705. HRESULT hTempResult;
  2706. BOOL fEndpointLocked;
  2707. BOOL fEndpointBound;
  2708. UINT_PTR uRetryCount;
  2709. BOOL fRetryForever;
  2710. DWORD dwRetryInterval;
  2711. BOOL fWaitForever;
  2712. DWORD dwIdleTimeout;
  2713. SPIE_ENUMADDRESSINFO EnumAddressInfo;
  2714. IDirectPlay8Address * pHostAddress;
  2715. IDirectPlay8Address * pDeviceAddress;
  2716. GATEWAY_BIND_TYPE GatewayBindType;
  2717. DWORD dwEnumQueryFlags;
  2718. CEndpoint * pTempEndpoint;
  2719. CSocketData * pSocketData;
  2720. BOOL fLockedSocketData;
  2721. #ifndef DPNBUILD_ONLYONEADAPTER
  2722. MULTIPLEXEDADAPTERASSOCIATION maa;
  2723. DWORD dwComponentSize;
  2724. DWORD dwComponentType;
  2725. CBilink * pBilinkEnd;
  2726. CBilink * pBilinkAll;
  2727. CBilink * pBilinkNext;
  2728. CBilink blInitiate;
  2729. CBilink blCompleteEarly;
  2730. #ifndef DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  2731. CSocketPort * pSocketPort;
  2732. CSocketAddress * pSocketAddress;
  2733. SOCKADDR_IN * psaddrinTemp;
  2734. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  2735. SOCKADDR saddrPublic;
  2736. CBilink * pBilinkPublic;
  2737. CEndpoint * pPublicEndpoint;
  2738. CSocketPort * pPublicSocketPort;
  2739. DWORD dwTemp;
  2740. DWORD dwPublicAddressesSize;
  2741. DWORD dwAddressTypeFlags;
  2742. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  2743. #endif // ! DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  2744. #endif // ! DPNBUILD_ONLYONEADAPTER
  2745. DNASSERT( GetCommandParameters() != NULL );
  2746. DPFX(DPFPREP, 6, "(0x%p) Enter", this);
  2747. //
  2748. // initialize
  2749. //
  2750. hr = DPN_OK;
  2751. fEndpointLocked = FALSE;
  2752. fEndpointBound = FALSE;
  2753. dwIdleTimeout = 0;
  2754. memset( &EnumAddressInfo, 0x00, sizeof( EnumAddressInfo ) );
  2755. DNASSERT( GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost != NULL );
  2756. //
  2757. // Transfer address references to our local pointers. These will be released
  2758. // at the end of this function, but we'll keep the pointers in the pending command
  2759. // data so CSPData::BindEndpoint can still access them.
  2760. //
  2761. pHostAddress = GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost;
  2762. DNASSERT( pHostAddress != NULL );
  2763. pDeviceAddress = GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressDeviceInfo;
  2764. DNASSERT( pDeviceAddress != NULL );
  2765. //
  2766. // Retrieve other parts of the command parameters for convenience.
  2767. //
  2768. GatewayBindType = GetCommandParameters()->GatewayBindType;
  2769. dwEnumQueryFlags = GetCommandParameters()->PendingCommandData.EnumQueryData.dwFlags;
  2770. #ifndef DPNBUILD_ONLYONEADAPTER
  2771. blInitiate.Initialize();
  2772. blCompleteEarly.Initialize();
  2773. #endif // ! DPNBUILD_ONLYONEADAPTER
  2774. pSocketData = NULL;
  2775. fLockedSocketData = FALSE;
  2776. DNASSERT( m_pSPData != NULL );
  2777. DNASSERT( m_State == ENDPOINT_STATE_ATTEMPTING_ENUM );
  2778. DNASSERT( m_pActiveCommandData != NULL );
  2779. DNASSERT( GetCommandParameters()->PendingCommandData.EnumQueryData.hCommand == m_pActiveCommandData );
  2780. DNASSERT( GetCommandParameters()->PendingCommandData.EnumQueryData.dwCommandDescriptor != NULL_DESCRIPTOR );
  2781. DNASSERT( GatewayBindType == GATEWAY_BIND_TYPE_UNKNOWN );
  2782. //
  2783. // Since this endpoint will be passed off to the timer thread, add a reference
  2784. // for the thread. If the handoff fails, DecRef()
  2785. //
  2786. AddRef();
  2787. //
  2788. // check for user cancelling command
  2789. //
  2790. m_pActiveCommandData->Lock();
  2791. DNASSERT( m_pActiveCommandData->GetType() == COMMAND_TYPE_ENUM_QUERY );
  2792. switch ( m_pActiveCommandData->GetState() )
  2793. {
  2794. //
  2795. // command is still pending, that's good
  2796. //
  2797. case COMMAND_STATE_PENDING:
  2798. {
  2799. Lock();
  2800. fEndpointLocked = TRUE;
  2801. DNASSERT( hr == DPN_OK );
  2802. break;
  2803. }
  2804. //
  2805. // command has been cancelled
  2806. //
  2807. case COMMAND_STATE_CANCELLING:
  2808. {
  2809. hr = DPNERR_USERCANCEL;
  2810. DPFX(DPFPREP, 0, "User cancelled enum query!" );
  2811. break;
  2812. }
  2813. #ifndef DPNBUILD_ONLYONETHREAD
  2814. //
  2815. // blocking operation failed
  2816. //
  2817. case COMMAND_STATE_FAILING:
  2818. {
  2819. hr = m_hrPendingCommandResult;
  2820. DNASSERT(hr != DPN_OK);
  2821. DPFX(DPFPREP, 0, "Enum query blocking operation failed!" );
  2822. break;
  2823. }
  2824. #endif // ! DPNBUILD_ONLYONETHREAD
  2825. //
  2826. // command is in progress (probably came here from a dialog), mark it
  2827. // as pending
  2828. //
  2829. case COMMAND_STATE_INPROGRESS:
  2830. {
  2831. m_pActiveCommandData->SetState( COMMAND_STATE_PENDING );
  2832. Lock();
  2833. fEndpointLocked = TRUE;
  2834. DNASSERT( hr == DPN_OK );
  2835. break;
  2836. }
  2837. //
  2838. // other state
  2839. //
  2840. default:
  2841. {
  2842. DNASSERT( FALSE );
  2843. break;
  2844. }
  2845. }
  2846. m_pActiveCommandData->Unlock();
  2847. if ( hr != DPN_OK )
  2848. {
  2849. goto Failure;
  2850. }
  2851. //
  2852. // Note that the GATEWAY_BIND_TYPE actually used (GetGatewayBindType())
  2853. // may differ from GatewayBindType.
  2854. //
  2855. hr = m_pSPData->BindEndpoint( this, pDeviceAddress, NULL, GatewayBindType );
  2856. if ( hr != DPN_OK )
  2857. {
  2858. DPFX(DPFPREP, 0, "Failed to bind endpoint (err = 0x%lx)!", hr );
  2859. DisplayDNError( 0, hr );
  2860. //
  2861. // We failed, but we'll continue through to indicate the address info and
  2862. // add it to the multiplex list.
  2863. //
  2864. EnumAddressInfo.pHostAddress = GetRemoteHostDP8Address();
  2865. if ( EnumAddressInfo.pHostAddress == NULL )
  2866. {
  2867. hr = DPNERR_OUTOFMEMORY;
  2868. goto Failure;
  2869. }
  2870. //
  2871. // Just regurgitate the device address we were given initially.
  2872. //
  2873. IDirectPlay8Address_AddRef(pDeviceAddress);
  2874. EnumAddressInfo.pDeviceAddress = pDeviceAddress;
  2875. EnumAddressInfo.hCommandStatus = hr;
  2876. EnumAddressInfo.pCommandContext = m_pActiveCommandData->GetUserContext();
  2877. SetPendingCommandResult( hr );
  2878. hr = DPN_OK;
  2879. //
  2880. // Note that the endpoint is not bound!
  2881. //
  2882. DNASSERT(GetSocketPort() == NULL);
  2883. }
  2884. else
  2885. {
  2886. fEndpointBound = TRUE;
  2887. #ifdef DPNBUILD_XNETSECURITY
  2888. EnumAddressInfo.pDeviceAddress = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, NULL, GetGatewayBindType() );
  2889. #else // ! DPNBUILD_XNETSECURITY
  2890. EnumAddressInfo.pDeviceAddress = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, GetGatewayBindType() );
  2891. #endif // ! DPNBUILD_XNETSECURITY
  2892. EnumAddressInfo.pHostAddress = GetRemoteHostDP8Address();
  2893. EnumAddressInfo.hCommandStatus = DPN_OK;
  2894. EnumAddressInfo.pCommandContext = m_pActiveCommandData->GetUserContext();
  2895. if ( ( EnumAddressInfo.pHostAddress == NULL ) ||
  2896. ( EnumAddressInfo.pDeviceAddress == NULL ) )
  2897. {
  2898. hr = DPNERR_OUTOFMEMORY;
  2899. goto Failure;
  2900. }
  2901. }
  2902. //
  2903. // Retrieve the socket data. Bind endpoint should have created the object or
  2904. // returned a failure, so we won't handle the error case here.
  2905. //
  2906. pSocketData = m_pSPData->GetSocketDataRef();
  2907. DNASSERT(pSocketData != NULL);
  2908. #ifndef DPNBUILD_ONLYONEADAPTER
  2909. //
  2910. // We can run into problems with "multiplexed" device attempts when you are on
  2911. // a NAT machine. The core will try enuming on multiple adapters, but since
  2912. // we are on the network boundary, each adapter can see and get responses from
  2913. // both networks. This causes problems with peer-to-peer sessions when the
  2914. // "wrong" adapter gets selected (because it receives a response first). To
  2915. // prevent that, we are going to internally remember the association between
  2916. // the multiplexed Enums so we can decide on the fly whether to indicate a
  2917. // response or not. Obviously this workaround/decision logic relies on having
  2918. // internal knowledge of what the upper layer would be doing...
  2919. //
  2920. // So either build or add to the linked list of multiplexed Enums.
  2921. // Technically this is only necessary for IP, since IPX can't have NATs, but
  2922. // what's the harm in having a little extra info?
  2923. //
  2924. dwComponentSize = sizeof(maa);
  2925. dwComponentType = 0;
  2926. hTempResult = IDirectPlay8Address_GetComponentByName( pDeviceAddress, // interface
  2927. DPNA_PRIVATEKEY_MULTIPLEXED_ADAPTER_ASSOCIATION, // tag
  2928. &maa, // component buffer
  2929. &dwComponentSize, // component size
  2930. &dwComponentType // component type
  2931. );
  2932. if (( hTempResult == DPN_OK ) && ( dwComponentSize == sizeof(MULTIPLEXEDADAPTERASSOCIATION) ) && ( dwComponentType == DPNA_DATATYPE_BINARY ))
  2933. {
  2934. //
  2935. // We found the right component type. See if it matches the right
  2936. // CSPData object.
  2937. //
  2938. if ( maa.pSPData == m_pSPData )
  2939. {
  2940. pSocketData->Lock();
  2941. //fLockedSocketData = TRUE;
  2942. pTempEndpoint = CONTAINING_OBJECT(maa.pBilink, CEndpoint, m_blMultiplex);
  2943. //
  2944. // Make sure the endpoint is still around/valid.
  2945. //
  2946. // THIS MAY CRASH IF OBJECT POOLING IS DISABLED!
  2947. //
  2948. if ( pTempEndpoint->GetEndpointID() == maa.dwEndpointID )
  2949. {
  2950. DPFX(DPFPREP, 3, "Found correctly formed private multiplexed adapter association key, linking endpoint 0x%p with earlier enums (prev endpoint = 0x%p).",
  2951. this, pTempEndpoint);
  2952. DNASSERT( pTempEndpoint->GetType() == ENDPOINT_TYPE_ENUM );
  2953. DNASSERT( pTempEndpoint->GetState() != ENDPOINT_STATE_UNINITIALIZED );
  2954. //
  2955. // Actually link to the other endpoints.
  2956. //
  2957. m_blMultiplex.InsertAfter(maa.pBilink);
  2958. }
  2959. else
  2960. {
  2961. DPFX(DPFPREP, 1, "Found private multiplexed adapter association key, but prev endpoint 0x%p ID doesn't match (%u != %u), cannot link endpoint 0x%p and hoping this enum gets cancelled, too.",
  2962. pTempEndpoint, pTempEndpoint->GetEndpointID(), maa.dwEndpointID, this);
  2963. }
  2964. pSocketData->Unlock();
  2965. //fLockedSocketData = FALSE;
  2966. }
  2967. else
  2968. {
  2969. //
  2970. // We are the only ones who should know about this key, so if it
  2971. // got there either someone is trying to imitate our address format,
  2972. // or someone is passing around device addresses returned by
  2973. // xxxADDRESSINFO to a different interface or over the network.
  2974. // None of those situations make a whole lot of sense, but we'll
  2975. // just ignore it.
  2976. //
  2977. DPFX(DPFPREP, 0, "Multiplexed adapter association key exists, but 0x%p doesn't match expected 0x%p, is someone trying to get cute with device address 0x%p?!",
  2978. maa.pSPData, m_pSPData, pDeviceAddress );
  2979. }
  2980. }
  2981. else
  2982. {
  2983. //
  2984. // Either the key is not there, it's the wrong size (too big for our
  2985. // buffer and returned BUFFERTOOSMALL somehow), it's not a binary
  2986. // component, or something else bad happened. Assume that this is the
  2987. // first device.
  2988. //
  2989. DPFX(DPFPREP, 8, "Could not get appropriate private multiplexed adapter association key, error = 0x%lx, component size = %u, type = %u, continuing.",
  2990. hTempResult, dwComponentSize, dwComponentType);
  2991. }
  2992. //
  2993. // Add the multiplex information to the device address for future use if
  2994. // necessary.
  2995. // Ignore failure, we can still survive without it, we just might have the
  2996. // race conditions for responses on NAT machines.
  2997. //
  2998. // NOTE: There is an inherent design problem here! We're adding a pointer to
  2999. // an endpoint (well, a field within the endpoint structure) inside the address.
  3000. // If this endpoint goes away but the upper layer reuses the address at a later
  3001. // time, this memory will be bogus! We will assume that the endpoint will not
  3002. // go away while this modified device address object is in existence.
  3003. //
  3004. if ( dwEnumQueryFlags & DPNSPF_ADDITIONALMULTIPLEXADAPTERS )
  3005. {
  3006. maa.pSPData = m_pSPData;
  3007. maa.pBilink = &m_blMultiplex;
  3008. maa.dwEndpointID = GetEndpointID();
  3009. DPFX(DPFPREP, 7, "Additional multiplex adapters on the way, adding SPData 0x%p and bilink 0x%p to address.",
  3010. maa.pSPData, maa.pBilink);
  3011. hTempResult = IDirectPlay8Address_AddComponent( EnumAddressInfo.pDeviceAddress, // interface
  3012. DPNA_PRIVATEKEY_MULTIPLEXED_ADAPTER_ASSOCIATION, // tag
  3013. &maa, // component data
  3014. sizeof(maa), // component data size
  3015. DPNA_DATATYPE_BINARY // component data type
  3016. );
  3017. if ( hTempResult != DPN_OK )
  3018. {
  3019. DPFX(DPFPREP, 0, "Couldn't add private multiplexed adapter association component (err = 0x%lx)! Ignoring.", hTempResult);
  3020. }
  3021. //
  3022. // Mark the command as "in-progress" so that the cancel thread knows it needs
  3023. // to do the completion itself.
  3024. // If the command has already been marked for cancellation, then we have to
  3025. // do that now.
  3026. //
  3027. m_pActiveCommandData->Lock();
  3028. if ( m_pActiveCommandData->GetState() == COMMAND_STATE_CANCELLING )
  3029. {
  3030. m_pActiveCommandData->Unlock();
  3031. DPFX(DPFPREP, 1, "Enum query 0x%p (endpoint 0x%p) has already been cancelled, bailing.",
  3032. m_pActiveCommandData, this);
  3033. //
  3034. // Complete the enum with USERCANCEL.
  3035. //
  3036. hr = DPNERR_USERCANCEL;
  3037. goto Failure;
  3038. }
  3039. m_pActiveCommandData->SetState( COMMAND_STATE_INPROGRESS );
  3040. m_pActiveCommandData->Unlock();
  3041. }
  3042. #endif // ! DPNBUILD_ONLYONEADAPTER
  3043. if ( fEndpointLocked != FALSE )
  3044. {
  3045. Unlock();
  3046. fEndpointLocked = FALSE;
  3047. }
  3048. //
  3049. // Now tell the user about the address info that we ended up using, if we
  3050. // successfully bound the endpoint, or give them a heads up for a failure
  3051. // (see BindEndpoint failure case above).
  3052. //
  3053. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_ENUMADDRESSINFO 0x%p to interface 0x%p.",
  3054. this, &EnumAddressInfo, m_pSPData->DP8SPCallbackInterface());
  3055. DumpAddress( 8, _T("\t Host:"), EnumAddressInfo.pHostAddress );
  3056. DumpAddress( 8, _T("\t Device:"), EnumAddressInfo.pDeviceAddress );
  3057. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  3058. hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
  3059. SPEV_ENUMADDRESSINFO, // event type
  3060. &EnumAddressInfo // pointer to data
  3061. );
  3062. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_ENUMADDRESSINFO [0x%lx].",
  3063. this, hTempResult);
  3064. DNASSERT( hTempResult == DPN_OK );
  3065. //
  3066. // If there aren't more multiplex adapter commands on the way, then submit the timer
  3067. // jobs for all of the multiplex commands, including this one.
  3068. //
  3069. #ifndef DPNBUILD_ONLYONEADAPTER
  3070. if ( dwEnumQueryFlags & DPNSPF_ADDITIONALMULTIPLEXADAPTERS )
  3071. {
  3072. //
  3073. // Not last multiplexed adapter. All the work needed to be done for these
  3074. // endpoints at this time has already been done.
  3075. //
  3076. DPFX(DPFPREP, 6, "Endpoint 0x%p is not the last multiplexed adapter, not submitting enum timer job yet.",
  3077. this);
  3078. }
  3079. else
  3080. #endif // ! DPNBUILD_ONLYONEADAPTER
  3081. {
  3082. DPFX(DPFPREP, 7, "Completing/starting all enum queries (including multiplexed).");
  3083. pSocketData->Lock();
  3084. fLockedSocketData = TRUE;
  3085. #ifndef DPNBUILD_ONLYONEADAPTER
  3086. //
  3087. // Attach a root node to the list of adapters.
  3088. //
  3089. blInitiate.InsertAfter(&(m_blMultiplex));
  3090. //
  3091. // Move this adapter to the failed list if it did fail to bind.
  3092. //
  3093. if (! fEndpointBound)
  3094. {
  3095. m_blMultiplex.RemoveFromList();
  3096. m_blMultiplex.InsertBefore(&blCompleteEarly);
  3097. }
  3098. #ifndef DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  3099. //
  3100. // Loop through all the remaining adapters in the list.
  3101. //
  3102. pBilinkAll = blInitiate.GetNext();
  3103. while (pBilinkAll != &blInitiate)
  3104. {
  3105. pTempEndpoint = CONTAINING_OBJECT(pBilinkAll, CEndpoint, m_blMultiplex);
  3106. DNASSERT(pBilinkAll->GetNext() != pBilinkAll);
  3107. pBilinkNext = pBilinkAll->GetNext();
  3108. //
  3109. // THIS MUST BE CLEANED UP PROPERLY WITH AN INTERFACE CHANGE!
  3110. //
  3111. // The endpoint may have been returned to the pool and its associated
  3112. // socketport pointer may have become NULL, or now be pointing to
  3113. // something that's no longer valid. So we try to handle NULL
  3114. // pointers. Obviously this is indicative of poor design, but it's
  3115. // not possible to change this the correct way at this time.
  3116. //
  3117. //
  3118. // If the enum is directed (not the broadcast address), and this is a NAT
  3119. // machine, then some adapters may be better than others for reaching the
  3120. // desired address. Particularly, it's better to use a private adapter,
  3121. // which can directly reach the private network & be mapped on the public
  3122. // network, than to use the public adapter. It's not fun to join a private
  3123. // game from an ICS machine while dialed up, have your Internet connection
  3124. // go down, and lose the connection to the private game which didn't
  3125. // (shouldn't) involve the Internet at all. So if we detect a public
  3126. // adapter when we have a perfectly good private adapter, we'll prematurely
  3127. // complete enumerations on the public one.
  3128. //
  3129. //
  3130. // Cast to get rid of the const. Don't worry, we won't actually change it.
  3131. //
  3132. pSocketAddress = (CSocketAddress*) pTempEndpoint->GetRemoteAddressPointer();
  3133. psaddrinTemp = (SOCKADDR_IN*) pSocketAddress->GetAddress();
  3134. pSocketPort = pTempEndpoint->GetSocketPort();
  3135. //
  3136. // If this item doesn't have a socketport, then it must have failed to bind.
  3137. // We need to clean it up ourselves.
  3138. //
  3139. if (pSocketPort == NULL)
  3140. {
  3141. DPFX(DPFPREP, 3, "Endpoint 0x%p failed earlier, now completing.",
  3142. pTempEndpoint);
  3143. //
  3144. // Get the next associated endpoint before we pull the current entry
  3145. // from the list.
  3146. //
  3147. pBilinkAll = pBilinkAll->GetNext();
  3148. //
  3149. // Pull it out of the multiplex association list and move
  3150. // it to the "early completion" list.
  3151. //
  3152. pTempEndpoint->RemoveFromMultiplexList();
  3153. pTempEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3154. //
  3155. // Move to next iteration of loop.
  3156. //
  3157. continue;
  3158. }
  3159. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  3160. //
  3161. // Detect if we've been given conflicting address families for our target
  3162. // and our bound socket (see CSocketPort::BindEndpoint).
  3163. //
  3164. DNASSERT(pSocketPort->GetNetworkAddress() != NULL);
  3165. if ( pSocketAddress->GetFamily() != pSocketPort->GetNetworkAddress()->GetFamily() )
  3166. {
  3167. DPFX(DPFPREP, 3, "Endpoint 0x%p (family %u) is targeting a different address family (%u), completing.",
  3168. pTempEndpoint, pSocketPort->GetNetworkAddress()->GetFamily(), pSocketAddress->GetFamily());
  3169. //
  3170. // Get the next associated endpoint before we pull the current entry
  3171. // from the list.
  3172. //
  3173. pBilinkAll = pBilinkAll->GetNext();
  3174. //
  3175. // Give the endpoint a meaningful error.
  3176. //
  3177. pTempEndpoint->SetPendingCommandResult(DPNERR_INVALIDDEVICEADDRESS);
  3178. //
  3179. // Pull it out of the multiplex association list and move
  3180. // it to the "early completion" list.
  3181. //
  3182. pTempEndpoint->RemoveFromMultiplexList();
  3183. pTempEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3184. //
  3185. // Move to next iteration of loop.
  3186. //
  3187. continue;
  3188. }
  3189. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  3190. #ifndef DPNBUILD_NOIPV6
  3191. //
  3192. // Now handle some special IPv6 logic.
  3193. //
  3194. if (pSocketAddress->GetFamily() == AF_INET6)
  3195. {
  3196. SOCKADDR_IN6 * psaddrinDevice;
  3197. SOCKADDR_IN6 * psaddrinRemote;
  3198. psaddrinDevice = (SOCKADDR_IN6*) pSocketPort->GetNetworkAddress()->GetAddress();
  3199. psaddrinRemote = (SOCKADDR_IN6*) pSocketAddress->GetAddress();
  3200. //
  3201. // If any non-link local IPv6 endpoints are targeting the IPv6 multicast enum
  3202. // address, just fail them.
  3203. //
  3204. if (IN6_IS_ADDR_MULTICAST(&psaddrinRemote->sin6_addr))
  3205. {
  3206. //
  3207. // Right now, only the specific enum multicast address is allowed.
  3208. //
  3209. DNASSERT(IN6_ADDR_EQUAL(&psaddrinRemote->sin6_addr, &c_in6addrEnumMulticast));
  3210. if (! IN6_IS_ADDR_LINKLOCAL(&psaddrinDevice->sin6_addr))
  3211. {
  3212. DPFX(DPFPREP, 3, "Endpoint 0x%p is targeting multicast enum address but is not link-local IPv6 device, completing.",
  3213. pTempEndpoint);
  3214. //
  3215. // Get the next associated endpoint before we pull the current entry
  3216. // from the list.
  3217. //
  3218. pBilinkAll = pBilinkAll->GetNext();
  3219. //
  3220. // Give the endpoint a meaningful error.
  3221. //
  3222. pTempEndpoint->SetPendingCommandResult(DPNERR_INVALIDHOSTADDRESS);
  3223. //
  3224. // Pull it out of the multiplex association list and move
  3225. // it to the "early completion" list.
  3226. //
  3227. pTempEndpoint->RemoveFromMultiplexList();
  3228. pTempEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3229. //
  3230. // Move to next iteration of loop.
  3231. //
  3232. continue;
  3233. }
  3234. }
  3235. else
  3236. {
  3237. BOOL fDifferentScope;
  3238. //
  3239. // If this endpoint is targeting something which has a different address,
  3240. // prefix scope, fail it.
  3241. //
  3242. fDifferentScope = FALSE;
  3243. if (IN6_IS_ADDR_LINKLOCAL(&psaddrinDevice->sin6_addr))
  3244. {
  3245. if (! IN6_IS_ADDR_LINKLOCAL(&psaddrinRemote->sin6_addr))
  3246. {
  3247. fDifferentScope = TRUE;
  3248. }
  3249. }
  3250. else if (IN6_IS_ADDR_SITELOCAL(&psaddrinDevice->sin6_addr))
  3251. {
  3252. if (! IN6_IS_ADDR_SITELOCAL(&psaddrinRemote->sin6_addr))
  3253. {
  3254. fDifferentScope = TRUE;
  3255. }
  3256. }
  3257. else
  3258. {
  3259. if ((IN6_IS_ADDR_LINKLOCAL(&psaddrinRemote->sin6_addr)) ||
  3260. (IN6_IS_ADDR_SITELOCAL(&psaddrinRemote->sin6_addr)))
  3261. {
  3262. fDifferentScope = TRUE;
  3263. }
  3264. }
  3265. if (fDifferentScope)
  3266. {
  3267. DPFX(DPFPREP, 3, "Endpoint 0x%p is targeting address with different link-local/site-local/global scope, completing.",
  3268. pTempEndpoint);
  3269. //
  3270. // Get the next associated endpoint before we pull the current entry
  3271. // from the list.
  3272. //
  3273. pBilinkAll = pBilinkAll->GetNext();
  3274. //
  3275. // Give the endpoint a meaningful error.
  3276. //
  3277. pTempEndpoint->SetPendingCommandResult(DPNERR_INVALIDHOSTADDRESS);
  3278. //
  3279. // Pull it out of the multiplex association list and move
  3280. // it to the "early completion" list.
  3281. //
  3282. pTempEndpoint->RemoveFromMultiplexList();
  3283. pTempEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3284. //
  3285. // Move to next iteration of loop.
  3286. //
  3287. continue;
  3288. }
  3289. }
  3290. }
  3291. #endif // ! DPNBUILD_NOIPV6
  3292. //
  3293. // See if this is a directed IP enum.
  3294. //
  3295. if ( ( pSocketAddress != NULL ) &&
  3296. ( pSocketAddress->GetFamily() == AF_INET ) &&
  3297. ( psaddrinTemp->sin_addr.S_un.S_addr != INADDR_BROADCAST ) )
  3298. {
  3299. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  3300. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  3301. {
  3302. if (pSocketPort->GetNATHelpPort(dwTemp) != NULL)
  3303. {
  3304. DNASSERT( g_papNATHelpObjects[dwTemp] != NULL );
  3305. dwPublicAddressesSize = sizeof(saddrPublic);
  3306. dwAddressTypeFlags = 0;
  3307. hTempResult = IDirectPlayNATHelp_GetRegisteredAddresses(g_papNATHelpObjects[dwTemp],
  3308. pSocketPort->GetNATHelpPort(dwTemp),
  3309. &saddrPublic,
  3310. &dwPublicAddressesSize,
  3311. &dwAddressTypeFlags,
  3312. NULL,
  3313. 0);
  3314. if ((hTempResult != DPNH_OK) || (! (dwAddressTypeFlags & DPNHADDRESSTYPE_GATEWAYISLOCAL)))
  3315. {
  3316. DPFX(DPFPREP, 7, "Socketport 0x%p is not locally mapped on gateway with NAT Help index %u (err = 0x%lx, flags = 0x%lx).",
  3317. pSocketPort, dwTemp, hTempResult, dwAddressTypeFlags);
  3318. }
  3319. else
  3320. {
  3321. //
  3322. // There is a local NAT.
  3323. //
  3324. DPFX(DPFPREP, 7, "Socketport 0x%p is locally mapped on gateway with NAT Help index %u (flags = 0x%lx), public address:",
  3325. pSocketPort, dwTemp, dwAddressTypeFlags);
  3326. DumpSocketAddress(7, &saddrPublic, AF_INET);
  3327. //
  3328. // Find the multiplexed enum on the public adapter that
  3329. // we need to complete early, as described above.
  3330. //
  3331. pBilinkPublic = blInitiate.GetNext();
  3332. while (pBilinkPublic != &blInitiate)
  3333. {
  3334. pPublicEndpoint = CONTAINING_OBJECT(pBilinkPublic, CEndpoint, m_blMultiplex);
  3335. DNASSERT(pBilinkPublic->GetNext() != pBilinkPublic);
  3336. //
  3337. // Don't bother checking the endpoint whose public
  3338. // address we're seeking.
  3339. //
  3340. if (pPublicEndpoint != pTempEndpoint)
  3341. {
  3342. pPublicSocketPort = pPublicEndpoint->GetSocketPort();
  3343. if ( pPublicSocketPort != NULL )
  3344. {
  3345. //
  3346. // Cast to get rid of the const. Don't worry, we won't
  3347. // actually change it.
  3348. //
  3349. pSocketAddress = (CSocketAddress*) pPublicSocketPort->GetNetworkAddress();
  3350. if ( pSocketAddress != NULL )
  3351. {
  3352. if ( pSocketAddress->CompareToBaseAddress( &saddrPublic ) == 0)
  3353. {
  3354. DPFX(DPFPREP, 3, "Endpoint 0x%p is multiplexed onto public adapter for endpoint 0x%p (current endpoint = 0x%p), completing public enum.",
  3355. pTempEndpoint, pPublicEndpoint, this);
  3356. //
  3357. // Pull it out of the multiplex association list and move
  3358. // it to the "early completion" list.
  3359. //
  3360. pPublicEndpoint->RemoveFromMultiplexList();
  3361. pPublicEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3362. break;
  3363. }
  3364. //
  3365. // Otherwise, continue searching.
  3366. //
  3367. DPFX(DPFPREP, 8, "Endpoint 0x%p is multiplexed onto different adapter:",
  3368. pPublicEndpoint);
  3369. DumpSocketAddress(8, pSocketAddress->GetWritableAddress(), pSocketAddress->GetFamily());
  3370. }
  3371. else
  3372. {
  3373. DPFX(DPFPREP, 1, "Public endpoint 0x%p's socket port 0x%p is going away, skipping.",
  3374. pPublicEndpoint, pPublicSocketPort);
  3375. }
  3376. }
  3377. else
  3378. {
  3379. DPFX(DPFPREP, 1, "Public endpoint 0x%p is going away, skipping.",
  3380. pPublicEndpoint);
  3381. }
  3382. }
  3383. else
  3384. {
  3385. //
  3386. // The same endpoint as the one whose
  3387. // public address we're seeking.
  3388. //
  3389. }
  3390. pBilinkPublic = pBilinkPublic->GetNext();
  3391. }
  3392. //
  3393. // No need to search for any more NAT Help registrations.
  3394. //
  3395. break;
  3396. } // end else (is mapped locally on Internet gateway)
  3397. }
  3398. else
  3399. {
  3400. //
  3401. // No DirectPlay NAT Helper registration in this slot.
  3402. //
  3403. }
  3404. } // end for (each DirectPlay NAT Helper)
  3405. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  3406. //
  3407. // NOTE: We should complete enums for non-optimal adapters even
  3408. // when it's multiadapter but not a PAST/UPnP enabled NAT (see
  3409. // ProcessEnumResponseData for WSAIoctl usage related to this).
  3410. // We do not currently do this. There can still be race conditions
  3411. // for directed enums where the response for the "wrong" device
  3412. // arrives first.
  3413. //
  3414. }
  3415. else
  3416. {
  3417. //
  3418. // Not IP address, or enum being sent to the broadcast address,
  3419. // or possibly the endpoint is shutting down.
  3420. //
  3421. DPFX(DPFPREP, 1, "Found non-IPv4 endpoint (possibly closing) or enum IP endpoint bound to broadcast address (endpoint = 0x%p, socket address = 0x%p, socketport = 0x%p), not checking for local NAT mapping.",
  3422. pTempEndpoint, pSocketAddress, pSocketPort);
  3423. }
  3424. //
  3425. // Go to the next associated endpoint. Although it's possible for
  3426. // entries to have been removed from the list, the current entry
  3427. // could not have been, so we're safe.
  3428. //
  3429. pBilinkAll = pBilinkAll->GetNext();
  3430. }
  3431. #endif // ! DPNBUILD_NOICSADAPTERSELECTIONLOGIC
  3432. #endif // ! DPNBUILD_ONLYONEADAPTER
  3433. #ifdef DPNBUILD_ONLYONEADAPTER
  3434. if (fEndpointBound)
  3435. {
  3436. //
  3437. // Indentation used for consistency even though there's no
  3438. // brace that warrants it.
  3439. //
  3440. pTempEndpoint = this;
  3441. #else // ! DPNBUILD_ONLYONEADAPTER
  3442. //
  3443. // Because we walk the list of associated multiplex enums when we receive
  3444. // responses, and that list walker does not expect to see a root node, we
  3445. // need to make sure that's gone before we drop the lock. Get a pointer
  3446. // to the first and last items remaining in the list before we do that (if
  3447. // there are entries).
  3448. //
  3449. if (! blInitiate.IsEmpty())
  3450. {
  3451. pBilinkAll = blInitiate.GetNext();
  3452. pBilinkEnd = blInitiate.GetPrev();
  3453. blInitiate.RemoveFromList();
  3454. //
  3455. // Now loop through the remaining endpoints and kick off their enum jobs.
  3456. //
  3457. // Unlike Connects, we will not remove the Enums from the list since we
  3458. // need to filter out broadcasts received on the "wrong" adapter (see
  3459. // ProcessEnumResponseData).
  3460. //
  3461. do
  3462. {
  3463. pTempEndpoint = CONTAINING_OBJECT(pBilinkAll, CEndpoint, m_blMultiplex);
  3464. pBilinkNext = pBilinkAll->GetNext();
  3465. #endif // ! DPNBUILD_ONLYONEADAPTER
  3466. //
  3467. // See notes above about NULL handling.
  3468. //
  3469. if ( pTempEndpoint->m_pActiveCommandData != NULL )
  3470. {
  3471. //
  3472. // The endpoint's command may be cancelled already. So we take the
  3473. // command lock now, and abort the enum if it's no longer necessary.
  3474. //
  3475. pTempEndpoint->m_pActiveCommandData->Lock();
  3476. if ( pTempEndpoint->m_pActiveCommandData->GetState() == COMMAND_STATE_CANCELLING )
  3477. {
  3478. //
  3479. // If the command has been cancelled, pull this endpoint out of the multiplex
  3480. // association list and move it to the "early completion" list.
  3481. //
  3482. pTempEndpoint->m_pActiveCommandData->Unlock();
  3483. DPFX(DPFPREP, 1, "Endpoint 0x%p's enum command (0x%p) has been cancelled, moving to early completion list.",
  3484. pTempEndpoint, pTempEndpoint->m_pActiveCommandData);
  3485. #ifdef DPNBUILD_ONLYONEADAPTER
  3486. //
  3487. // Remember that we're not starting the enum.
  3488. //
  3489. fEndpointBound = FALSE;
  3490. #else // ! DPNBUILD_ONLYONEADAPTER
  3491. pTempEndpoint->RemoveFromMultiplexList();
  3492. pTempEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3493. #endif // ! DPNBUILD_ONLYONEADAPTER
  3494. }
  3495. else
  3496. {
  3497. //
  3498. // The command has not been cancelled.
  3499. //
  3500. // This is very hairy, but we drop the socketport data lock and
  3501. // keep the command data lock. Dropping the socketport data
  3502. // lock should prevent deadlocks with the enum completing inside
  3503. // the timer lock, and keeping the command data lock should
  3504. // prevent people from cancelling the endpoint's command.
  3505. //
  3506. // However, once we drop the command lock, we do want the
  3507. // command to be cancellable, so set the state appropriately now.
  3508. //
  3509. pTempEndpoint->m_pActiveCommandData->SetState( COMMAND_STATE_INPROGRESS );
  3510. //
  3511. // We also need to notify potential cancellers that the command is
  3512. // in a different COMMAND_STATE_INPROGRESS now. Now they
  3513. // must try to stop the timer as well.
  3514. //
  3515. pTempEndpoint->Lock();
  3516. DNASSERT( pTempEndpoint->m_State == ENDPOINT_STATE_ATTEMPTING_ENUM );
  3517. pTempEndpoint->m_State = ENDPOINT_STATE_ENUM;
  3518. pTempEndpoint->Unlock();
  3519. pSocketData->Unlock();
  3520. fLockedSocketData = FALSE;
  3521. //
  3522. // check retry count to determine if we're enumerating forever
  3523. //
  3524. switch ( pTempEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwRetryCount )
  3525. {
  3526. //
  3527. // let SP determine retry count
  3528. //
  3529. case 0:
  3530. {
  3531. uRetryCount = DEFAULT_ENUM_RETRY_COUNT;
  3532. fRetryForever = FALSE;
  3533. break;
  3534. }
  3535. //
  3536. // retry forever
  3537. //
  3538. case INFINITE:
  3539. {
  3540. uRetryCount = 1;
  3541. fRetryForever = TRUE;
  3542. break;
  3543. }
  3544. //
  3545. // other
  3546. //
  3547. default:
  3548. {
  3549. uRetryCount = pTempEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwRetryCount;
  3550. fRetryForever = FALSE;
  3551. break;
  3552. }
  3553. }
  3554. //
  3555. // check interval for default
  3556. //
  3557. if ( pTempEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwRetryInterval == 0 )
  3558. {
  3559. dwRetryInterval = DEFAULT_ENUM_RETRY_INTERVAL;
  3560. }
  3561. else
  3562. {
  3563. dwRetryInterval = pTempEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwRetryInterval;
  3564. }
  3565. //
  3566. // check timeout to see if we're enumerating forever
  3567. //
  3568. switch ( pTempEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwTimeout )
  3569. {
  3570. //
  3571. // wait forever
  3572. //
  3573. case INFINITE:
  3574. {
  3575. fWaitForever = TRUE;
  3576. dwIdleTimeout = -1;
  3577. break;
  3578. }
  3579. //
  3580. // possible default
  3581. //
  3582. case 0:
  3583. {
  3584. fWaitForever = FALSE;
  3585. dwIdleTimeout = DEFAULT_ENUM_TIMEOUT;
  3586. break;
  3587. }
  3588. //
  3589. // other
  3590. //
  3591. default:
  3592. {
  3593. fWaitForever = FALSE;
  3594. dwIdleTimeout = pTempEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwTimeout;
  3595. break;
  3596. }
  3597. }
  3598. //
  3599. // initialize array to compute round-trip times
  3600. //
  3601. memset( pTempEndpoint->GetCommandParameters()->dwEnumSendTimes, 0x00, sizeof( pTempEndpoint->GetCommandParameters()->dwEnumSendTimes ) );
  3602. pTempEndpoint->GetCommandParameters()->dwEnumSendIndex = 0;
  3603. DPFX(DPFPREP, 6, "Submitting enum timer job for endpoint 0x%p, retry count = %u, retry forever = %i, retry interval = %u, wait forever = %i, idle timeout = %u, context = 0x%p.",
  3604. pTempEndpoint,
  3605. uRetryCount,
  3606. fRetryForever,
  3607. dwRetryInterval,
  3608. fWaitForever,
  3609. dwIdleTimeout,
  3610. pTempEndpoint->m_pActiveCommandData);
  3611. if ( pTempEndpoint->m_pSPData != NULL )
  3612. {
  3613. #ifdef DPNBUILD_ONLYONEPROCESSOR
  3614. hTempResult = pTempEndpoint->m_pSPData->GetThreadPool()->SubmitTimerJob( TRUE, // perform immediately
  3615. uRetryCount, // number of times to retry command
  3616. fRetryForever, // retry forever
  3617. dwRetryInterval, // retry interval
  3618. fWaitForever, // wait forever after all enums sent
  3619. dwIdleTimeout, // timeout to wait after command complete
  3620. CEndpoint::EnumTimerCallback, // function called when timer event fires
  3621. CEndpoint::EnumCompleteWrapper, // function called when timer event expires
  3622. pTempEndpoint->m_pActiveCommandData ); // context
  3623. #else // ! DPNBUILD_ONLYONEPROCESSOR
  3624. DNASSERT(pTempEndpoint->m_pSocketPort != NULL);
  3625. hTempResult = pTempEndpoint->m_pSPData->GetThreadPool()->SubmitTimerJob( pTempEndpoint->m_pSocketPort->GetCPU(), // CPU
  3626. TRUE, // perform immediately
  3627. uRetryCount, // number of times to retry command
  3628. fRetryForever, // retry forever
  3629. dwRetryInterval, // retry interval
  3630. fWaitForever, // wait forever after all enums sent
  3631. dwIdleTimeout, // timeout to wait after command complete
  3632. CEndpoint::EnumTimerCallback, // function called when timer event fires
  3633. CEndpoint::EnumCompleteWrapper, // function called when timer event expires
  3634. pTempEndpoint->m_pActiveCommandData ); // context
  3635. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3636. }
  3637. else
  3638. {
  3639. DPFX(DPFPREP, 1, "Endpoint 0x%p's SP data is NULL, not submitting timer job.",
  3640. pTempEndpoint);
  3641. }
  3642. //
  3643. // Drop active command data lock now that we've finished submission.
  3644. //
  3645. pTempEndpoint->m_pActiveCommandData->Unlock();
  3646. //
  3647. // Retake the socketport data lock so we can continue to work with the
  3648. // list.
  3649. //
  3650. pSocketData->Lock();
  3651. fLockedSocketData = TRUE;
  3652. if ( hTempResult != DPN_OK )
  3653. {
  3654. DPFX(DPFPREP, 0, "Failed to spool enum job for endpoint 0x%p onto work thread (err = 0x%lx)! Moving to early completion list.",
  3655. pTempEndpoint, hTempResult);
  3656. DisplayDNError( 0, hTempResult );
  3657. #ifdef DPNBUILD_ONLYONEADAPTER
  3658. //
  3659. // Remember that we didn't start the enum.
  3660. //
  3661. fEndpointBound = FALSE;
  3662. #else // ! DPNBUILD_ONLYONEADAPTER
  3663. //
  3664. // Move it to the "early completion" list.
  3665. //
  3666. pTempEndpoint->RemoveFromMultiplexList();
  3667. pTempEndpoint->m_blMultiplex.InsertBefore(&blCompleteEarly);
  3668. #endif // ! DPNBUILD_ONLYONEADAPTER
  3669. }
  3670. }
  3671. }
  3672. else
  3673. {
  3674. DPFX(DPFPREP, 1, "Endpoint 0x%p's active command data is NULL, skipping.",
  3675. pTempEndpoint);
  3676. }
  3677. #ifndef DPNBUILD_ONLYONEADAPTER
  3678. //
  3679. // If we've looped back around to the beginning, we're done.
  3680. //
  3681. if (pBilinkAll == pBilinkEnd)
  3682. {
  3683. break;
  3684. }
  3685. //
  3686. // Go to the next associated endpoint.
  3687. //
  3688. pBilinkAll = pBilinkNext;
  3689. }
  3690. while (TRUE);
  3691. #endif // ! DPNBUILD_ONLYONEADAPTER
  3692. }
  3693. else
  3694. {
  3695. DPFX(DPFPREP, 1, "No remaining enums to initiate.");
  3696. }
  3697. //
  3698. // Finally loop through all the enums that need to complete early and
  3699. // do just that.
  3700. //
  3701. #ifdef DPNBUILD_ONLYONEADAPTER
  3702. if (! fEndpointBound)
  3703. {
  3704. pTempEndpoint = this;
  3705. #else // ! DPNBUILD_ONLYONEADAPTER
  3706. while (! blCompleteEarly.IsEmpty())
  3707. {
  3708. pBilinkAll = blCompleteEarly.GetNext();
  3709. pTempEndpoint = CONTAINING_OBJECT(pBilinkAll, CEndpoint, m_blMultiplex);
  3710. DNASSERT(pBilinkAll->GetNext() != pBilinkAll);
  3711. //
  3712. // Pull it from the "complete early" list.
  3713. //
  3714. pTempEndpoint->RemoveFromMultiplexList();
  3715. #endif // ! DPNBUILD_ONLYONEADAPTER
  3716. //
  3717. // Drop the socket data lock. It's safe since we pulled everything we
  3718. // we need off of the list that needs protection.
  3719. //
  3720. pSocketData->Unlock();
  3721. fLockedSocketData = FALSE;
  3722. //
  3723. // See notes above about NULL handling.
  3724. //
  3725. if ( pTempEndpoint->m_pActiveCommandData != NULL )
  3726. {
  3727. //
  3728. // Complete it with the appropriate error code.
  3729. //
  3730. pTempEndpoint->m_pActiveCommandData->Lock();
  3731. if ( pTempEndpoint->m_pActiveCommandData->GetState() == COMMAND_STATE_CANCELLING )
  3732. {
  3733. DPFX(DPFPREP, 6, "Completing endpoint 0x%p enum with USERCANCEL.", pTempEndpoint);
  3734. hTempResult = DPNERR_USERCANCEL;
  3735. }
  3736. else
  3737. {
  3738. //
  3739. // Retrieve the current command result.
  3740. // If the command didn't have a descriptive error, assume it was
  3741. // not previously set (i.e. wasn't overridden by BindEndpoint above),
  3742. // and use NOCONNECTION instead.
  3743. //
  3744. hTempResult = pTempEndpoint->PendingCommandResult();
  3745. if ( hTempResult == DPNERR_GENERIC )
  3746. {
  3747. hTempResult = DPNERR_NOCONNECTION;
  3748. }
  3749. DPFX(DPFPREP, 6, "Completing endpoint 0x%p enum query (command 0x%p) with error 0x%lx.",
  3750. pTempEndpoint, pTempEndpoint->m_pActiveCommandData, hTempResult);
  3751. }
  3752. pTempEndpoint->m_pActiveCommandData->Unlock();
  3753. pTempEndpoint->EnumComplete( hTempResult );
  3754. }
  3755. else
  3756. {
  3757. DPFX(DPFPREP, 1, "Endpoint 0x%p's active command data is NULL, skipping.",
  3758. pTempEndpoint);
  3759. }
  3760. //
  3761. // Retake the socket data lock and go to next item.
  3762. //
  3763. pSocketData->Lock();
  3764. fLockedSocketData = TRUE;
  3765. }
  3766. pSocketData->Unlock();
  3767. fLockedSocketData = FALSE;
  3768. }
  3769. Exit:
  3770. if ( pSocketData != NULL )
  3771. {
  3772. pSocketData->Release();
  3773. pSocketData = NULL;
  3774. }
  3775. if ( EnumAddressInfo.pHostAddress != NULL )
  3776. {
  3777. IDirectPlay8Address_Release( EnumAddressInfo.pHostAddress );
  3778. EnumAddressInfo.pHostAddress = NULL;
  3779. }
  3780. if ( EnumAddressInfo.pDeviceAddress != NULL )
  3781. {
  3782. IDirectPlay8Address_Release( EnumAddressInfo.pDeviceAddress );
  3783. EnumAddressInfo.pDeviceAddress = NULL;
  3784. }
  3785. DNASSERT( pDeviceAddress != NULL );
  3786. IDirectPlay8Address_Release( pDeviceAddress );
  3787. DNASSERT( pHostAddress != NULL );
  3788. IDirectPlay8Address_Release( pHostAddress );
  3789. DNASSERT( !fLockedSocketData );
  3790. #ifndef DPNBUILD_ONLYONEADAPTER
  3791. DNASSERT(blCompleteEarly.IsEmpty());
  3792. DNASSERT(blInitiate.IsEmpty());
  3793. #endif // ! DPNBUILD_ONLYONEADAPTER
  3794. DPFX(DPFPREP, 6, "(0x%p) Returning [0x%lx]", this, hr);
  3795. return hr;
  3796. Failure:
  3797. //
  3798. // If we still have the socket data lock, drop it.
  3799. //
  3800. if ( fLockedSocketData )
  3801. {
  3802. pSocketData->Unlock();
  3803. fLockedSocketData = FALSE;
  3804. }
  3805. //
  3806. // we've failed to complete the enum query, clean up and return this
  3807. // endpoint to the pool
  3808. //
  3809. if ( fEndpointLocked != FALSE )
  3810. {
  3811. Unlock();
  3812. fEndpointLocked = FALSE;
  3813. }
  3814. Close( hr );
  3815. m_pSPData->CloseEndpointHandle( this );
  3816. //
  3817. // remove timer thread reference
  3818. //
  3819. DecRef();
  3820. goto Exit;
  3821. }
  3822. //**********************************************************************
  3823. #ifndef DPNBUILD_ONLYONETHREAD
  3824. //**********************************************************************
  3825. // ------------------------------
  3826. // CEndpoint::EnumQueryBlockingJobWrapper - asynchronous callback wrapper for blocking job
  3827. //
  3828. // Entry: Pointer to job information
  3829. //
  3830. // Exit: Nothing
  3831. // ------------------------------
  3832. #undef DPF_MODNAME
  3833. #define DPF_MODNAME "CEndpoint::EnumQueryBlockingJobWrapper"
  3834. void CEndpoint::EnumQueryBlockingJobWrapper( void * const pvContext )
  3835. {
  3836. CEndpoint *pThisEndpoint;
  3837. // initialize
  3838. DNASSERT( pvContext != NULL );
  3839. pThisEndpoint = static_cast<CEndpoint*>( pvContext );
  3840. DNASSERT( pThisEndpoint->m_pActiveCommandData != NULL );
  3841. DNASSERT( pThisEndpoint->GetCommandParameters() != NULL );
  3842. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.hCommand == pThisEndpoint->m_pActiveCommandData );
  3843. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.dwCommandDescriptor != NULL_DESCRIPTOR );
  3844. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost != NULL );
  3845. DNASSERT( pThisEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressDeviceInfo != NULL );
  3846. pThisEndpoint->EnumQueryBlockingJob();
  3847. }
  3848. //**********************************************************************
  3849. //**********************************************************************
  3850. // ------------------------------
  3851. // CEndpoint::EnumQueryBlockingJob - complete enum query blocking job
  3852. //
  3853. // Entry: Nothing
  3854. //
  3855. // Exit: Nothing
  3856. //
  3857. // Note: Calling this function may result in the deletion of 'this', don't
  3858. // do anything else with this object after calling!!!!
  3859. // ------------------------------
  3860. #undef DPF_MODNAME
  3861. #define DPF_MODNAME "CEndpoint::EnumQueryBlockingJob"
  3862. void CEndpoint::EnumQueryBlockingJob( void )
  3863. {
  3864. HRESULT hr;
  3865. //
  3866. // Try to resolve the host name. It's possible we already did this
  3867. // when we first opened the endpoint, and we only need to resolve
  3868. // the hostname, but it's simpler to just do it all again anyway.
  3869. //
  3870. hr = m_pRemoteMachineAddress->SocketAddressFromDP8Address( GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost,
  3871. #ifdef DPNBUILD_XNETSECURITY
  3872. ((m_fSecureTransport) ? &m_ullKeyID : NULL),
  3873. #endif // DPNBUILD_XNETSECURITY
  3874. TRUE,
  3875. SP_ADDRESS_TYPE_HOST );
  3876. if ( hr != DPN_OK )
  3877. {
  3878. if ( hr != DPNERR_INCOMPLETEADDRESS )
  3879. {
  3880. DPFX(DPFPREP, 0, "Couldn't get valid address!" );
  3881. DisplayDNError( 0, hr );
  3882. goto Failure;
  3883. }
  3884. //
  3885. // we're OK, reset the destination address to broadcast
  3886. //
  3887. DNASSERT(! (GetCommandParameters()->PendingCommandData.EnumQueryData.dwFlags & DPNSPF_NOBROADCASTFALLBACK));
  3888. ReinitializeWithBroadcast();
  3889. }
  3890. //
  3891. // Make sure its valid and not banned.
  3892. //
  3893. if (! m_pRemoteMachineAddress->IsValidUnicastAddress(TRUE))
  3894. {
  3895. DPFX(DPFPREP, 0, "Host address is invalid!");
  3896. hr = DPNERR_INVALIDHOSTADDRESS;
  3897. goto Failure;
  3898. }
  3899. #ifndef DPNBUILD_NOREGISTRY
  3900. if (m_pRemoteMachineAddress->IsBannedAddress())
  3901. {
  3902. DPFX(DPFPREP, 0, "Host address is banned!");
  3903. hr = DPNERR_NOTALLOWED;
  3904. goto Failure;
  3905. }
  3906. #endif // ! DPNBUILD_NOREGISTRY
  3907. #ifndef DPNBUILD_NONATHELP
  3908. //
  3909. // Try to get NAT help loaded, if it isn't already and we're allowed.
  3910. //
  3911. if (GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE)
  3912. {
  3913. DPFX(DPFPREP, 7, "Ensuring that NAT help is loaded.");
  3914. m_pSPData->GetThreadPool()->EnsureNATHelpLoaded();
  3915. }
  3916. #endif // ! DPNBUILD_NONATHELP
  3917. Exit:
  3918. //
  3919. // Submit the job for completion (for real). We want it to occur on
  3920. // a thread pool thread so that the user has gotten notified about the
  3921. // thread prior to getting a callback on it. We do it in even the failure
  3922. // case.
  3923. //
  3924. // NOTE: If this fails, we will rely on the caller that triggered the original
  3925. // operation to cancel the command at some point, probably when he
  3926. // decides the operation is taking too long.
  3927. //
  3928. #ifdef DPNBUILD_ONLYONEPROCESSOR
  3929. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::EnumQueryJobCallback,
  3930. this );
  3931. #else // ! DPNBUILD_ONLYONEPROCESSOR
  3932. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
  3933. CEndpoint::EnumQueryJobCallback,
  3934. this );
  3935. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  3936. if ( hr != DPN_OK )
  3937. {
  3938. DPFX(DPFPREP, 0, "Failed to queue delayed enum query completion! Operation must be cancelled." );
  3939. DisplayDNError( 0, hr );
  3940. //
  3941. // Leave endpoint reference, see notes above.
  3942. //
  3943. }
  3944. return;
  3945. Failure:
  3946. //
  3947. // Attempt to attach the failure code to the command. If the user was
  3948. // already cancelling this command, we will just leave the command alone.
  3949. //
  3950. m_pActiveCommandData->Lock();
  3951. if (m_pActiveCommandData->GetState() != COMMAND_STATE_CANCELLING)
  3952. {
  3953. DNASSERT(m_pActiveCommandData->GetState() == COMMAND_STATE_PENDING);
  3954. m_pActiveCommandData->SetState(COMMAND_STATE_FAILING);
  3955. m_hrPendingCommandResult = hr;
  3956. }
  3957. else
  3958. {
  3959. DPFX(DPFPREP, 0, "User cancelled command, ignoring failure result 0x%lx.",
  3960. hr);
  3961. }
  3962. m_pActiveCommandData->Unlock();
  3963. goto Exit;
  3964. }
  3965. //**********************************************************************
  3966. #endif // ! DPNBUILD_ONLYONETHREAD
  3967. //**********************************************************************
  3968. // ------------------------------
  3969. // CEndpoint::EnumCompleteWrapper - wrapper when enum has completed
  3970. //
  3971. // Entry: Error code from enum command
  3972. // Pointer to context
  3973. //
  3974. // Exit: Nothing
  3975. // ------------------------------
  3976. #undef DPF_MODNAME
  3977. #define DPF_MODNAME "CEndpoint::EnumCompleteWrapper"
  3978. void CEndpoint::EnumCompleteWrapper( const HRESULT hResult, void *const pContext )
  3979. {
  3980. CCommandData *pCommandData;
  3981. DNASSERT( pContext != NULL );
  3982. pCommandData = static_cast<CCommandData*>( pContext );
  3983. pCommandData->GetEndpoint()->EnumComplete( hResult );
  3984. }
  3985. //**********************************************************************
  3986. //**********************************************************************
  3987. // ------------------------------
  3988. // CEndpoint::EnumComplete - enum has completed
  3989. //
  3990. // Entry: Error code from enum command
  3991. //
  3992. // Exit: Nothing
  3993. // ------------------------------
  3994. #undef DPF_MODNAME
  3995. #define DPF_MODNAME "CEndpoint::EnumComplete"
  3996. void CEndpoint::EnumComplete( const HRESULT hResult )
  3997. {
  3998. BOOL fProcessCompletion;
  3999. BOOL fReleaseEndpoint;
  4000. DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%lx)", this, hResult);
  4001. fProcessCompletion = FALSE;
  4002. fReleaseEndpoint = FALSE;
  4003. Lock();
  4004. switch ( m_State )
  4005. {
  4006. //
  4007. // starting up
  4008. //
  4009. case ENDPOINT_STATE_ATTEMPTING_ENUM:
  4010. {
  4011. DPFX(DPFPREP, 5, "Endpoint 0x%p has not started actual enum yet.", this);
  4012. DNASSERT( m_dwThreadCount == 0 );
  4013. SetState( ENDPOINT_STATE_DISCONNECTING );
  4014. fReleaseEndpoint = TRUE;
  4015. fProcessCompletion = TRUE;
  4016. break;
  4017. }
  4018. //
  4019. // enumerating, note that this endpoint is disconnecting
  4020. //
  4021. case ENDPOINT_STATE_ENUM:
  4022. {
  4023. //
  4024. // If there are threads using this endpoint,
  4025. // queue the completion
  4026. //
  4027. if (m_dwThreadCount)
  4028. {
  4029. DPFX(DPFPREP, 5, "Endpoint 0x%p waiting on %u threads before completing.",
  4030. this, m_dwThreadCount);
  4031. SetState( ENDPOINT_STATE_WAITING_TO_COMPLETE );
  4032. }
  4033. else
  4034. {
  4035. DPFX(DPFPREP, 5, "Endpoint 0x%p disconnecting.", this);
  4036. SetState( ENDPOINT_STATE_DISCONNECTING );
  4037. fReleaseEndpoint = TRUE;
  4038. }
  4039. //
  4040. // Prevent more responses from finding this endpoint
  4041. //
  4042. fProcessCompletion = TRUE;
  4043. break;
  4044. }
  4045. //
  4046. // endpoint needs to have a completion indicated
  4047. //
  4048. case ENDPOINT_STATE_WAITING_TO_COMPLETE:
  4049. {
  4050. if (m_dwThreadCount == 0)
  4051. {
  4052. DPFX(DPFPREP, 5, "Endpoint 0x%p now able to disconnect.", this);
  4053. SetState( ENDPOINT_STATE_DISCONNECTING );
  4054. fReleaseEndpoint = TRUE;
  4055. }
  4056. else
  4057. {
  4058. DPFX(DPFPREP, 5, "Endpoint 0x%p still waiting on %u threads before completing.",
  4059. this, m_dwThreadCount);
  4060. }
  4061. break;
  4062. }
  4063. //
  4064. // disconnecting (command was probably cancelled)
  4065. //
  4066. case ENDPOINT_STATE_DISCONNECTING:
  4067. {
  4068. DPFX(DPFPREP, 4, "Endpoint 0x%p already disconnecting.", this);
  4069. DNASSERT( m_dwThreadCount == 0 );
  4070. break;
  4071. }
  4072. //
  4073. // there's a problem
  4074. //
  4075. default:
  4076. {
  4077. DNASSERT( FALSE );
  4078. break;
  4079. }
  4080. }
  4081. Unlock();
  4082. if (fProcessCompletion)
  4083. {
  4084. GetCommandParameters()->dwEnumSendIndex = 0;
  4085. Close( hResult );
  4086. m_pSPData->CloseEndpointHandle( this );
  4087. }
  4088. if (fReleaseEndpoint)
  4089. {
  4090. DecRef();
  4091. }
  4092. DPFX(DPFPREP, 6, "(0x%p) Leave", this);
  4093. return;
  4094. }
  4095. //**********************************************************************
  4096. //**********************************************************************
  4097. // ------------------------------
  4098. // CEndpoint::CleanUpCommand - clean up this endpoint and unbind from CSocketPort
  4099. //
  4100. // Entry: Nothing
  4101. //
  4102. // Exit: Nothing
  4103. // ------------------------------
  4104. #undef DPF_MODNAME
  4105. #define DPF_MODNAME "CEndpoint::SetEnumsAllowedOnListen"
  4106. void CEndpoint::SetEnumsAllowedOnListen( const BOOL fAllowed, const BOOL fOverwritePrevious )
  4107. {
  4108. ENUMSALLOWEDSTATE NewEnumsAllowedState;
  4109. #ifndef DPNBUILD_NOIPV6
  4110. const CSocketAddress * pSocketAddress;
  4111. IPV6_MREQ mreq;
  4112. int iError;
  4113. #endif // ! DPNBUILD_NOIPV6
  4114. NewEnumsAllowedState = (fAllowed) ? ENUMSALLOWED : ENUMSDISALLOWED;
  4115. Lock();
  4116. if ( m_EnumsAllowedState == NewEnumsAllowedState )
  4117. {
  4118. DPFX(DPFPREP, 6, "(0x%p) Enums already %slowed.", this, ((fAllowed) ? _T("al") : _T("disal")));
  4119. }
  4120. else if ((fOverwritePrevious) ||
  4121. (m_EnumsAllowedState == ENUMSNOTREADY))
  4122. {
  4123. DPFX(DPFPREP, 7, "(0x%p) %slowing enums.", this, ((fAllowed) ? _T("Al") : _T("Disal")));
  4124. #ifndef DPNBUILD_NOIPV6
  4125. //
  4126. // If this is a link-local IPv6 socket, join or leave the multicast group used to
  4127. // receive enums.
  4128. //
  4129. if (m_pSocketPort != NULL)
  4130. {
  4131. pSocketAddress = m_pSocketPort->GetNetworkAddress();
  4132. DNASSERT(pSocketAddress != NULL);
  4133. if ((pSocketAddress->GetFamily() == AF_INET6) &&
  4134. (IN6_IS_ADDR_LINKLOCAL(&(((SOCKADDR_IN6*) pSocketAddress->GetAddress())->sin6_addr))))
  4135. {
  4136. DNASSERT(((SOCKADDR_IN6*) pSocketAddress->GetAddress())->sin6_scope_id != 0);
  4137. mreq.ipv6mr_interface = ((SOCKADDR_IN6*) pSocketAddress->GetAddress())->sin6_scope_id;
  4138. memcpy(&mreq.ipv6mr_multiaddr, &c_in6addrEnumMulticast, sizeof(mreq.ipv6mr_multiaddr));
  4139. iError = setsockopt(m_pSocketPort->GetSocket(),
  4140. IPPROTO_IPV6,
  4141. ((fAllowed) ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP),
  4142. (char*) (&mreq),
  4143. sizeof(mreq));
  4144. #ifdef DBG
  4145. if (iError != 0)
  4146. {
  4147. iError = WSAGetLastError();
  4148. DPFX(DPFPREP, 0, "Couldn't %s link local multicast group (err = %i)!",
  4149. ((fAllowed) ? _T("join") : _T("leave")), iError);
  4150. }
  4151. #endif // DBG
  4152. }
  4153. }
  4154. #endif // ! DPNBUILD_NOIPV6
  4155. m_EnumsAllowedState = NewEnumsAllowedState;
  4156. }
  4157. else
  4158. {
  4159. DPFX(DPFPREP, 7, "(0x%p) Enums-allowed state unchanged, still %slowing enums.", this, ((fAllowed) ? _T("al") : _T("disal")));
  4160. }
  4161. Unlock();
  4162. }
  4163. //**********************************************************************
  4164. //**********************************************************************
  4165. // ------------------------------
  4166. // CEndpoint::CleanUpCommand - clean up this endpoint and unbind from CSocketPort
  4167. //
  4168. // Entry: Nothing
  4169. //
  4170. // Exit: Nothing
  4171. // ------------------------------
  4172. #undef DPF_MODNAME
  4173. #define DPF_MODNAME "CEndpoint::CleanupCommand"
  4174. void CEndpoint::CleanUpCommand( void )
  4175. {
  4176. DPFX(DPFPREP, 6, "(0x%p) Enter", this);
  4177. //
  4178. // If we're closing a listen normally, make sure no enums come
  4179. // in from here on out.
  4180. //
  4181. if ( ( GetType() == ENDPOINT_TYPE_LISTEN ) &&
  4182. ( ! m_fListenStatusNeedsToBeIndicated ) )
  4183. {
  4184. SetEnumsAllowedOnListen( FALSE, TRUE );
  4185. }
  4186. //
  4187. // There is an 'EndpointRef' that the endpoint holds against the
  4188. // socket port since it was created and always must be released.
  4189. // If the endpoint was bound it needs to be unbound.
  4190. //
  4191. if ( GetSocketPort() != NULL )
  4192. {
  4193. DNASSERT( m_pSPData != NULL );
  4194. m_pSPData->UnbindEndpoint( this );
  4195. }
  4196. #ifndef DPNBUILD_ONLYONEADAPTER
  4197. else
  4198. {
  4199. //
  4200. // Ensure that this endpoint is no longer in the multiplex list
  4201. // (could happen if canceling a failed Connect/EnumQuery).
  4202. //
  4203. if (( m_pSPData != NULL ) && ( m_pSPData->GetSocketData() != NULL ))
  4204. {
  4205. m_pSPData->GetSocketData()->Lock();
  4206. RemoveFromMultiplexList();
  4207. m_pSPData->GetSocketData()->Unlock();
  4208. }
  4209. }
  4210. #endif // ! DPNBUILD_ONLYONEADAPTER
  4211. //
  4212. // If we're bailing here it's because the UI didn't complete. There is no
  4213. // adapter guid to return because one may have not been specified. Return
  4214. // a bogus endpoint handle so it can't be queried for addressing data.
  4215. //
  4216. if ( m_fListenStatusNeedsToBeIndicated != FALSE )
  4217. {
  4218. HRESULT hTempResult;
  4219. SPIE_LISTENADDRESSINFO ListenAddressInfo;
  4220. SPIE_LISTENSTATUS ListenStatus;
  4221. m_fListenStatusNeedsToBeIndicated = FALSE;
  4222. memset( &ListenAddressInfo, 0x00, sizeof( ListenAddressInfo ) );
  4223. //
  4224. // We don't have a bound socket at this point, so just return the original
  4225. // device address specified.
  4226. //
  4227. DNASSERT(GetCommandParameters() != NULL);
  4228. DNASSERT(GetCommandParameters()->PendingCommandData.ListenData.pAddressDeviceInfo != NULL);
  4229. ListenAddressInfo.pDeviceAddress = GetCommandParameters()->PendingCommandData.ListenData.pAddressDeviceInfo;
  4230. ListenAddressInfo.hCommandStatus = PendingCommandResult();
  4231. ListenAddressInfo.pCommandContext = m_pActiveCommandData->GetUserContext();
  4232. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_LISTENADDRESSINFO 0x%p to interface 0x%p.",
  4233. this, &ListenAddressInfo, m_pSPData->DP8SPCallbackInterface());
  4234. DumpAddress( 8, _T("\t Device:"), ListenAddressInfo.pDeviceAddress );
  4235. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  4236. hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
  4237. SPEV_LISTENADDRESSINFO, // event type
  4238. &ListenAddressInfo // pointer to data
  4239. );
  4240. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_LISTENADDRESSINFO [0x%lx].",
  4241. this, hTempResult);
  4242. DNASSERT( hTempResult == DPN_OK );
  4243. memset( &ListenStatus, 0x00, sizeof( ListenStatus ) );
  4244. ListenStatus.hCommand = m_pActiveCommandData;
  4245. ListenStatus.hEndpoint = INVALID_HANDLE_VALUE;
  4246. ListenStatus.hResult = PendingCommandResult();
  4247. memset( &ListenStatus.ListenAdapter, 0x00, sizeof( ListenStatus.ListenAdapter ) );
  4248. ListenStatus.pUserContext = m_pActiveCommandData->GetUserContext();
  4249. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_LISTENSTATUS 0x%p to interface 0x%p.",
  4250. this, &ListenStatus, m_pSPData->DP8SPCallbackInterface());
  4251. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  4252. hTempResult = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DPlay callbacks
  4253. SPEV_LISTENSTATUS, // data type
  4254. &ListenStatus // pointer to data
  4255. );
  4256. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_LISTENSTATUS [0x%lx].",
  4257. this, hTempResult);
  4258. DNASSERT( hTempResult == DPN_OK );
  4259. }
  4260. m_State = ENDPOINT_STATE_UNINITIALIZED;
  4261. DPFX(DPFPREP, 6, "(0x%p) Leave", this);
  4262. }
  4263. //**********************************************************************
  4264. //**********************************************************************
  4265. // ------------------------------
  4266. // CEndpoint::ProcessEnumData - process received enum data
  4267. //
  4268. // Entry: Pointer to received buffer
  4269. // Associated enum key
  4270. // Pointer to return address
  4271. //
  4272. // Exit: Nothing
  4273. //
  4274. // Note: This function assumes that the endpoint has been locked.
  4275. // ------------------------------
  4276. #undef DPF_MODNAME
  4277. #define DPF_MODNAME "CEndpoint::ProcessEnumData"
  4278. void CEndpoint::ProcessEnumData( SPRECEIVEDBUFFER *const pBuffer, const DWORD dwEnumKey, const CSocketAddress *const pReturnSocketAddress )
  4279. {
  4280. DNASSERT( pBuffer != NULL );
  4281. DNASSERT( pBuffer->pNext == NULL);
  4282. DNASSERT( pBuffer->BufferDesc.dwBufferSize > 0);
  4283. DNASSERT( pReturnSocketAddress != NULL );
  4284. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  4285. //
  4286. // find out what state the endpoint is in before processing data
  4287. //
  4288. switch ( m_State )
  4289. {
  4290. //
  4291. // we're listening, this is the only way to detect enums
  4292. //
  4293. case ENDPOINT_STATE_LISTEN:
  4294. {
  4295. ENDPOINT_ENUM_QUERY_CONTEXT QueryContext;
  4296. HRESULT hr;
  4297. //
  4298. // initialize
  4299. //
  4300. DNASSERT( m_pActiveCommandData != NULL );
  4301. DEBUG_ONLY( memset( &QueryContext, 0x00, sizeof( QueryContext ) ) );
  4302. //
  4303. // set callback data
  4304. //
  4305. QueryContext.hEndpoint = (HANDLE) this;
  4306. QueryContext.dwEnumKey = dwEnumKey;
  4307. QueryContext.pReturnAddress = (CSocketAddress*) pReturnSocketAddress;
  4308. QueryContext.EnumQueryData.pReceivedData = pBuffer;
  4309. QueryContext.EnumQueryData.pUserContext = m_pActiveCommandData->GetUserContext();
  4310. //
  4311. // attempt to build a DNAddress for the user, if we can't allocate
  4312. // the memory ignore this enum
  4313. //
  4314. #ifdef DPNBUILD_XNETSECURITY
  4315. QueryContext.EnumQueryData.pAddressSender = pReturnSocketAddress->DP8AddressFromSocketAddress( NULL, NULL, SP_ADDRESS_TYPE_READ_HOST );
  4316. QueryContext.EnumQueryData.pAddressDevice = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, NULL, GetGatewayBindType() );
  4317. #else // ! DPNBUILD_XNETSECURITY
  4318. QueryContext.EnumQueryData.pAddressSender = pReturnSocketAddress->DP8AddressFromSocketAddress( SP_ADDRESS_TYPE_READ_HOST );
  4319. QueryContext.EnumQueryData.pAddressDevice = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, GetGatewayBindType() );
  4320. #endif // ! DPNBUILD_XNETSECURITY
  4321. if ( ( QueryContext.EnumQueryData.pAddressSender != NULL ) &&
  4322. ( QueryContext.EnumQueryData.pAddressDevice != NULL ) )
  4323. {
  4324. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_ENUMQUERY 0x%p to interface 0x%p.",
  4325. this, &QueryContext.EnumQueryData, m_pSPData->DP8SPCallbackInterface());
  4326. DumpAddress( 8, _T("\t Sender:"), QueryContext.EnumQueryData.pAddressSender );
  4327. DumpAddress( 8, _T("\t Device:"), QueryContext.EnumQueryData.pAddressDevice );
  4328. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  4329. hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DirectNet interface
  4330. SPEV_ENUMQUERY, // data type
  4331. &QueryContext.EnumQueryData // pointer to data
  4332. );
  4333. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_ENUMQUERY [0x%lx].", this, hr);
  4334. if ( hr != DPN_OK )
  4335. {
  4336. DPFX(DPFPREP, 0, "User returned unexpected error from enum query indication!" );
  4337. DisplayDNError( 0, hr );
  4338. DNASSERT( FALSE );
  4339. }
  4340. }
  4341. if ( QueryContext.EnumQueryData.pAddressSender != NULL )
  4342. {
  4343. IDirectPlay8Address_Release( QueryContext.EnumQueryData.pAddressSender );
  4344. QueryContext.EnumQueryData.pAddressSender = NULL;
  4345. }
  4346. if ( QueryContext.EnumQueryData.pAddressDevice != NULL )
  4347. {
  4348. IDirectPlay8Address_Release( QueryContext.EnumQueryData.pAddressDevice );
  4349. QueryContext.EnumQueryData.pAddressDevice = NULL;
  4350. }
  4351. break;
  4352. }
  4353. //
  4354. // we're disconnecting, ignore this message
  4355. //
  4356. case ENDPOINT_STATE_DISCONNECTING:
  4357. {
  4358. break;
  4359. }
  4360. //
  4361. // other state
  4362. //
  4363. default:
  4364. {
  4365. DNASSERT( FALSE );
  4366. break;
  4367. }
  4368. }
  4369. }
  4370. //**********************************************************************
  4371. //**********************************************************************
  4372. // ------------------------------
  4373. // CEndpoint::ProcessEnumResponseData - process received enum response data
  4374. //
  4375. // Entry: Pointer to received data
  4376. // Pointer to address of sender
  4377. //
  4378. // Exit: Nothing
  4379. //
  4380. // Note: This function assumes that the endpoint has been locked.
  4381. // ------------------------------
  4382. #undef DPF_MODNAME
  4383. #define DPF_MODNAME "CEndpoint::ProcessEnumResponseData"
  4384. void CEndpoint::ProcessEnumResponseData( SPRECEIVEDBUFFER *const pBuffer,
  4385. const CSocketAddress *const pReturnSocketAddress,
  4386. #ifdef DPNBUILD_XNETSECURITY
  4387. const XNADDR *const pxnaddrReturn,
  4388. #endif // DPNBUILD_XNETSECURITY
  4389. const UINT_PTR uRTTIndex )
  4390. {
  4391. HRESULT hrTemp;
  4392. BOOL fAddedThreadCount = FALSE;
  4393. SPIE_QUERYRESPONSE QueryResponseData;
  4394. DNASSERT( pBuffer != NULL );
  4395. DNASSERT( pReturnSocketAddress != NULL );
  4396. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  4397. //
  4398. // Initialize.
  4399. //
  4400. memset( &QueryResponseData, 0x00, sizeof( QueryResponseData ) );
  4401. DPFX(DPFPREP, 8, "Socketport 0x%p, endpoint 0x%p receiving enum RTT index 0x%x/%u.",
  4402. GetSocketPort(), this, uRTTIndex, uRTTIndex);
  4403. #ifdef DPNBUILD_XNETSECURITY
  4404. //
  4405. // Ignore insecure replies if enumerating securely.
  4406. //
  4407. if ((IsUsingXNetSecurity()) && (pxnaddrReturn == NULL))
  4408. {
  4409. DPFX(DPFPREP, 3, "Secure transport endpoint 0x%p ignoring insecure enum response.",
  4410. this);
  4411. }
  4412. else
  4413. #endif // DPNBUILD_XNETSECURITY
  4414. {
  4415. Lock();
  4416. switch( m_State )
  4417. {
  4418. case ENDPOINT_STATE_ENUM:
  4419. {
  4420. //
  4421. // Valid endpoint - increment the thread count to prevent premature completion
  4422. //
  4423. AddRefThreadCount();
  4424. fAddedThreadCount = TRUE;
  4425. //
  4426. // Attempt to build a sender DPlay8Addresses for the user.
  4427. // If this fails, we'll ignore the enum.
  4428. //
  4429. #ifdef DPNBUILD_XNETSECURITY
  4430. QueryResponseData.pAddressSender = pReturnSocketAddress->DP8AddressFromSocketAddress( NULL,
  4431. pxnaddrReturn,
  4432. SP_ADDRESS_TYPE_READ_HOST );
  4433. #else // ! DPNBUILD_XNETSECURITY
  4434. QueryResponseData.pAddressSender = pReturnSocketAddress->DP8AddressFromSocketAddress( SP_ADDRESS_TYPE_READ_HOST );
  4435. #endif // ! DPNBUILD_XNETSECURITY
  4436. break;
  4437. }
  4438. case ENDPOINT_STATE_ATTEMPTING_ENUM:
  4439. case ENDPOINT_STATE_WAITING_TO_COMPLETE:
  4440. case ENDPOINT_STATE_DISCONNECTING:
  4441. {
  4442. //
  4443. // Endpoint is waiting to complete or is disconnecting - ignore data
  4444. //
  4445. DPFX(DPFPREP, 2, "Endpoint 0x%p in state %u, ignoring enum response.",
  4446. this, m_State);
  4447. break;
  4448. }
  4449. default:
  4450. {
  4451. //
  4452. // What's going on ?
  4453. //
  4454. DNASSERT( !"Invalid endpoint state" );
  4455. break;
  4456. }
  4457. }
  4458. Unlock();
  4459. }
  4460. //
  4461. // If this is a multiplexed IP broadcast enum, we may want to drop the response
  4462. // because there may be a more appropriate adapter (NAT private side adapter)
  4463. // that should also be getting responses.
  4464. // Also, if this is a directed IP enum, we should note whether this response
  4465. // got proxied or not.
  4466. //
  4467. #ifdef DPNBUILD_XNETSECURITY
  4468. if ( ( QueryResponseData.pAddressSender != NULL ) &&
  4469. ( pxnaddrReturn == NULL ) )
  4470. #else // ! DPNBUILD_XNETSECURITY
  4471. if ( QueryResponseData.pAddressSender != NULL )
  4472. #endif // ! DPNBUILD_XNETSECURITY
  4473. {
  4474. CSocketData * pSocketData;
  4475. CSocketAddress * pSocketAddress;
  4476. const SOCKADDR_IN * psaddrinOriginalTarget;
  4477. const SOCKADDR_IN * psaddrinResponseSource;
  4478. CSocketPort * pSocketPort;
  4479. #ifndef DPNBUILD_ONLYONEADAPTER
  4480. BOOL fFoundMatchingEndpoint;
  4481. #ifndef DPNBUILD_NOWINSOCK2
  4482. DWORD dwBytesReturned;
  4483. #endif // DPNBUILD_NOWINSOCK2
  4484. #if ((! defined(DPNBUILD_NOWINSOCK2)) || ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT))))
  4485. SOCKADDR saddrTemp;
  4486. #endif // ! DPNBUILD_NOWINSOCK2 or (! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT)
  4487. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  4488. CSocketPort * pTempSocketPort;
  4489. CBilink * pBilink;
  4490. DWORD dwTemp;
  4491. CEndpoint * pTempEndpoint;
  4492. DWORD dwPublicAddressesSize;
  4493. DWORD dwAddressTypeFlags;
  4494. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  4495. #endif // ! DPNBUILD_ONLYONEADAPTER
  4496. //
  4497. // In order for there to be a bound and usable endpoint, we must have created
  4498. // the socket data. Therefore we won't handle the error case. We also don't
  4499. // take a reference because the socket data should not go away until the socket
  4500. // port and SP data objects are released.
  4501. //
  4502. pSocketData = m_pSPData->GetSocketData();
  4503. DNASSERT( pSocketData != NULL );
  4504. //
  4505. // Find out where and how this enum was originally sent.
  4506. //
  4507. pSocketAddress = (CSocketAddress*) GetRemoteAddressPointer();
  4508. DNASSERT( pSocketAddress != NULL );
  4509. //
  4510. // See if this is a response to and IP enum, either broadcast on multiple
  4511. // adapters or directed, so we can have special NAT/proxy behavior.
  4512. //
  4513. #if ((! defined(DPNBUILD_NOIPX)) || (! defined(DPNBUILD_NOIPV6)))
  4514. if ( pSocketAddress->GetFamily() != AF_INET )
  4515. {
  4516. //
  4517. // Not IP address.
  4518. //
  4519. DPFX(DPFPREP, 8, "Non-IPv4 endpoint (0x%p), not checking for local NAT mapping or proxy.",
  4520. this);
  4521. }
  4522. else
  4523. #endif // ! DPNBUILD_NOIPX or ! DPNBUILD_NOIPV6
  4524. {
  4525. psaddrinOriginalTarget = (const SOCKADDR_IN *) pSocketAddress->GetAddress();
  4526. pSocketPort = GetSocketPort();
  4527. DNASSERT( pSocketPort != NULL );
  4528. if ( psaddrinOriginalTarget->sin_addr.S_un.S_addr == INADDR_BROADCAST )
  4529. {
  4530. #ifndef DPNBUILD_ONLYONEADAPTER
  4531. //
  4532. // Lock the list while we look at the entries.
  4533. //
  4534. pSocketData->Lock();
  4535. if (! m_blMultiplex.IsEmpty())
  4536. {
  4537. //
  4538. // It's a broadcast IP enum on multiple adapters.
  4539. //
  4540. //
  4541. // Cast to get rid of the const. Don't worry, we won't actually
  4542. // change it.
  4543. //
  4544. pSocketAddress = (CSocketAddress*) pSocketPort->GetNetworkAddress();
  4545. DNASSERT( pSocketAddress != NULL );
  4546. fFoundMatchingEndpoint = FALSE;
  4547. #if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_NOLOCALNAT)))
  4548. //
  4549. // Loop through all other associated multiplexed endpoints to see
  4550. // if one is more appropriate to receive responses from this
  4551. // endpoint. See CompleteEnumQuery.
  4552. //
  4553. pBilink = m_blMultiplex.GetNext();
  4554. do
  4555. {
  4556. pTempEndpoint = CONTAINING_OBJECT(pBilink, CEndpoint, m_blMultiplex);
  4557. DNASSERT( pTempEndpoint != this );
  4558. DNASSERT( pTempEndpoint->GetType() == ENDPOINT_TYPE_ENUM );
  4559. DNASSERT( pTempEndpoint->GetState() != ENDPOINT_STATE_UNINITIALIZED );
  4560. DNASSERT( pTempEndpoint->GetCommandParameters() != NULL );
  4561. DNASSERT( pTempEndpoint->m_pActiveCommandData != NULL );
  4562. //
  4563. // Although the endpoint may be in the list (and because we have the
  4564. // socket data lock, it won't get pulled out while we're looking at it),
  4565. // the endpoint may already be disconnecting. If its m_pSocketPort is
  4566. // NULL we should just ignore this temporary endpoint since its going
  4567. // away (plus we sorta need its socket port pointer).
  4568. //
  4569. pTempSocketPort = pTempEndpoint->GetSocketPort();
  4570. if (pTempSocketPort != NULL)
  4571. {
  4572. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  4573. {
  4574. if (pTempSocketPort->GetNATHelpPort(dwTemp) != NULL)
  4575. {
  4576. DNASSERT( g_papNATHelpObjects[dwTemp] != NULL );
  4577. dwPublicAddressesSize = sizeof(saddrTemp);
  4578. dwAddressTypeFlags = 0;
  4579. hrTemp = IDirectPlayNATHelp_GetRegisteredAddresses(g_papNATHelpObjects[dwTemp],
  4580. pTempSocketPort->GetNATHelpPort(dwTemp),
  4581. &saddrTemp,
  4582. &dwPublicAddressesSize,
  4583. &dwAddressTypeFlags,
  4584. NULL,
  4585. 0);
  4586. if ((hrTemp != DPNH_OK) || (! (dwAddressTypeFlags & DPNHADDRESSTYPE_GATEWAYISLOCAL)))
  4587. {
  4588. DPFX(DPFPREP, 7, "Socketport 0x%p is not locally mapped on gateway with NAT Help index %u (err = 0x%lx, flags = 0x%lx).",
  4589. pTempSocketPort, dwTemp, hrTemp, dwAddressTypeFlags);
  4590. }
  4591. else
  4592. {
  4593. //
  4594. // There is a local NAT.
  4595. //
  4596. DPFX(DPFPREP, 7, "Socketport 0x%p is locally mapped on gateway with NAT Help index %u (flags = 0x%lx), public address:",
  4597. pTempSocketPort, dwTemp, dwAddressTypeFlags);
  4598. DumpSocketAddress(7, &saddrTemp, AF_INET);
  4599. //
  4600. // Are we receiving via an endpoint on the public
  4601. // adapter for that locally NATted endpoint?
  4602. //
  4603. if ( pSocketAddress->CompareToBaseAddress( &saddrTemp ) == 0)
  4604. {
  4605. //
  4606. // If this response came from a private address,
  4607. // then it would be better if the private adapter
  4608. // handled it instead.
  4609. //
  4610. hrTemp = IDirectPlayNATHelp_QueryAddress(g_papNATHelpObjects[dwTemp],
  4611. pTempSocketPort->GetNetworkAddress()->GetAddress(),
  4612. pReturnSocketAddress->GetAddress(),
  4613. &saddrTemp,
  4614. sizeof(saddrTemp),
  4615. (DPNHQUERYADDRESS_CACHEFOUND | DPNHQUERYADDRESS_CACHENOTFOUND | DPNHQUERYADDRESS_CHECKFORPRIVATEBUTUNMAPPED));
  4616. if ((hrTemp == DPNH_OK) || (hrTemp == DPNHERR_NOMAPPINGBUTPRIVATE))
  4617. {
  4618. //
  4619. // The address is private. Drop this response,
  4620. // and assume the private adapter will get one
  4621. //
  4622. DPFX(DPFPREP, 3, "Got enum response via public endpoint 0x%p that should be handled by associated private endpoint 0x%p instead, dropping.",
  4623. this, pTempEndpoint);
  4624. //
  4625. // Clear the sender address so that we don't
  4626. // indicate this enum.
  4627. //
  4628. IDirectPlay8Address_Release( QueryResponseData.pAddressSender );
  4629. QueryResponseData.pAddressSender = NULL;
  4630. }
  4631. else
  4632. {
  4633. //
  4634. // The address does not appear to be private. Let the
  4635. // response through.
  4636. //
  4637. DPFX(DPFPREP, 3, "Receiving enum response via public endpoint 0x%p but associated private endpoint 0x%p does not see sender as local (err = 0x%lx).",
  4638. this, pTempEndpoint, hrTemp);
  4639. }
  4640. //
  4641. // No need to search for any more private-side
  4642. // endpoints.
  4643. //
  4644. fFoundMatchingEndpoint = TRUE;
  4645. }
  4646. else
  4647. {
  4648. DPFX(DPFPREP, 8, "Receiving enum response via endpoint 0x%p, which is not on the public adapter for associated multiplex endpoint 0x%p.",
  4649. this, pTempEndpoint);
  4650. }
  4651. //
  4652. // No need to search for any more NAT Help
  4653. // registrations.
  4654. //
  4655. break;
  4656. } // end else (is mapped locally on Internet gateway)
  4657. }
  4658. else
  4659. {
  4660. //
  4661. // No DirectPlay NAT Helper registration in this slot.
  4662. //
  4663. }
  4664. } // end for (each DirectPlay NAT Helper)
  4665. //
  4666. // If we found a matching private adapter, we can stop
  4667. // searching.
  4668. //
  4669. if (fFoundMatchingEndpoint)
  4670. {
  4671. break;
  4672. }
  4673. }
  4674. else
  4675. {
  4676. DNASSERT(pTempEndpoint->GetState() == ENDPOINT_STATE_DISCONNECTING);
  4677. }
  4678. //
  4679. // Otherwise, go to the next endpoint.
  4680. //
  4681. pBilink = pBilink->GetNext();
  4682. }
  4683. while (pBilink != &m_blMultiplex);
  4684. #endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_NOLOCALNAT
  4685. //
  4686. // Drop the lock now that we're done with the list.
  4687. //
  4688. pSocketData->Unlock();
  4689. //
  4690. // If we didn't already find a matching endpoint, see if
  4691. // WinSock reports this as the best route for the response.
  4692. //
  4693. if (! fFoundMatchingEndpoint)
  4694. {
  4695. DNASSERT(pSocketPort == GetSocketPort());
  4696. #ifndef DPNBUILD_NOWINSOCK2
  4697. #ifndef DPNBUILD_ONLYWINSOCK2
  4698. if (GetWinsockVersion() == 2)
  4699. #endif // ! DPNBUILD_ONLYWINSOCK2
  4700. {
  4701. if (p_WSAIoctl(pSocketPort->GetSocket(),
  4702. SIO_ROUTING_INTERFACE_QUERY,
  4703. (PVOID) pReturnSocketAddress->GetAddress(),
  4704. pReturnSocketAddress->GetAddressSize(),
  4705. &saddrTemp,
  4706. sizeof(saddrTemp),
  4707. &dwBytesReturned,
  4708. NULL,
  4709. NULL) == 0)
  4710. {
  4711. if (( ((SOCKADDR_IN*) (&saddrTemp))->sin_addr.S_un.S_addr != IP_LOOPBACK_ADDRESS ) &&
  4712. ( pSocketPort->GetNetworkAddress()->CompareToBaseAddress( &saddrTemp ) != 0))
  4713. {
  4714. //
  4715. // The response would be better off arriving
  4716. // on a different interface.
  4717. //
  4718. DPFX(DPFPREP, 3, "Got enum response via endpoint 0x%p (socketport 0x%p) that should be handled by the socketport for %hs instead, dropping.",
  4719. this, pSocketPort, inet_ntoa(((SOCKADDR_IN*) (&saddrTemp))->sin_addr));
  4720. //
  4721. // Clear the sender address so that we don't
  4722. // indicate this enum.
  4723. //
  4724. IDirectPlay8Address_Release( QueryResponseData.pAddressSender );
  4725. QueryResponseData.pAddressSender = NULL;
  4726. }
  4727. else
  4728. {
  4729. //
  4730. // The response arrived on the interface with
  4731. // the best route.
  4732. //
  4733. DPFX(DPFPREP, 3, "Receiving enum response via endpoint 0x%p (socketport 0x%p) that appears to be the best route (%hs).",
  4734. this, pSocketPort, inet_ntoa(((SOCKADDR_IN*) (&saddrTemp))->sin_addr));
  4735. }
  4736. }
  4737. #ifdef DBG
  4738. else
  4739. {
  4740. DWORD dwError;
  4741. const SOCKADDR_IN * psaddrinTemp;
  4742. dwError = WSAGetLastError();
  4743. psaddrinTemp = (const SOCKADDR_IN *) pReturnSocketAddress->GetAddress();
  4744. DPFX(DPFPREP, 0, "Couldn't query routing interface for %hs (err = %u)! Assuming endpoint 0x%p (socketport 0x%p) is best route.",
  4745. inet_ntoa(psaddrinTemp->sin_addr),
  4746. dwError, this, pSocketPort);
  4747. }
  4748. #endif // DBG
  4749. }
  4750. #endif // DPNBUILD_NOWINSOCK2
  4751. } // end if (didn't find matching endpoint)
  4752. }
  4753. else
  4754. {
  4755. //
  4756. // IP broadcast enum, but no multiplexed adapters.
  4757. //
  4758. //
  4759. // Drop the lock we only needed it to look for multiplexed
  4760. // adapters.
  4761. //
  4762. pSocketData->Unlock();
  4763. DPFX(DPFPREP, 8, "IP broadcast enum endpoint (0x%p) is not multiplexed, not checking for local NAT mapping.",
  4764. this);
  4765. }
  4766. #endif // ! DPNBUILD_ONLYONEADAPTER
  4767. }
  4768. else
  4769. {
  4770. psaddrinResponseSource = (const SOCKADDR_IN *) pReturnSocketAddress->GetAddress();
  4771. //
  4772. // It's an IP enum that wasn't sent to the broadcast address.
  4773. // If the enum was sent to a specific port (not the DPNSVR
  4774. // port) but we're getting a response from a different IP
  4775. // address or port, then someone along the way is proxying/
  4776. // NATting the data. Store the original target in the
  4777. // address, since it might come in handy depending on what
  4778. // the user tries to do with that address.
  4779. //
  4780. if ((psaddrinResponseSource->sin_addr.S_un.S_addr != psaddrinOriginalTarget->sin_addr.S_un.S_addr) ||
  4781. ((psaddrinResponseSource->sin_port != psaddrinOriginalTarget->sin_port) &&
  4782. (psaddrinOriginalTarget->sin_port != HTONS(DPNA_DPNSVR_PORT))))
  4783. {
  4784. #if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
  4785. if (
  4786. #ifndef DPNBUILD_NOWINSOCK2
  4787. (pSocketPort->IsUsingProxyWinSockLSP())
  4788. #endif // ! DPNBUILD_NOWINSOCK2
  4789. #if ((! defined(DPNBUILD_NOWINSOCK2)) && (! defined(DPNBUILD_NOREGISTRY)))
  4790. ||
  4791. #endif // ! DPNBUILD_NOWINSOCK2 and ! DPNBUILD_NOREGISTRY
  4792. #ifndef DPNBUILD_NOREGISTRY
  4793. (g_fTreatAllResponsesAsProxied)
  4794. #endif // ! DPNBUILD_NOREGISTRY
  4795. )
  4796. {
  4797. PROXIEDRESPONSEORIGINALADDRESS proa;
  4798. DPFX(DPFPREP, 3, "Endpoint 0x%p (proxied socketport 0x%p) receiving enum response from different IP address and/or port.",
  4799. this, pSocketPort);
  4800. memset(&proa, 0, sizeof(proa));
  4801. proa.dwSocketPortID = pSocketPort->GetSocketPortID();
  4802. proa.dwOriginalTargetAddressV4 = psaddrinOriginalTarget->sin_addr.S_un.S_addr;
  4803. proa.wOriginalTargetPort = psaddrinOriginalTarget->sin_port;
  4804. //
  4805. // Add the component, but ignore failure, we might be able
  4806. // to survive without it.
  4807. //
  4808. hrTemp = IDirectPlay8Address_AddComponent( QueryResponseData.pAddressSender, // interface
  4809. DPNA_PRIVATEKEY_PROXIED_RESPONSE_ORIGINAL_ADDRESS, // tag
  4810. &proa, // component data
  4811. sizeof(proa), // component data size
  4812. DPNA_DATATYPE_BINARY // component data type
  4813. );
  4814. if ( hrTemp != DPN_OK )
  4815. {
  4816. DPFX(DPFPREP, 0, "Couldn't add private proxied response original address component (err = 0x%lx)! Ignoring.",
  4817. hrTemp);
  4818. }
  4819. }
  4820. else
  4821. #endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
  4822. {
  4823. DPFX(DPFPREP, 3, "Endpoint 0x%p receiving enum response from different IP address and/or port, but socketport 0x%p not considered proxied, indicating as is.",
  4824. this, pSocketPort);
  4825. }
  4826. }
  4827. else
  4828. {
  4829. //
  4830. // The IP address and port to which enum was originally
  4831. // sent is the same as where this response came from, or
  4832. // the port differs but the enum was originally sent to
  4833. // the DPNSVR port, so it _should_ differ.
  4834. //
  4835. }
  4836. }
  4837. }
  4838. }
  4839. if ( QueryResponseData.pAddressSender != NULL )
  4840. {
  4841. DNASSERT( m_pActiveCommandData != NULL );
  4842. //
  4843. // set message data
  4844. //
  4845. DNASSERT( GetCommandParameters() != NULL );
  4846. QueryResponseData.pReceivedData = pBuffer;
  4847. QueryResponseData.dwRoundTripTime = GETTIMESTAMP() - GetCommandParameters()->dwEnumSendTimes[ uRTTIndex ];
  4848. QueryResponseData.pUserContext = m_pActiveCommandData->GetUserContext();
  4849. //
  4850. // If we can't allocate the device address object, ignore this
  4851. // enum.
  4852. //
  4853. #ifdef DPNBUILD_XNETSECURITY
  4854. QueryResponseData.pAddressDevice = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, NULL, GetGatewayBindType() );
  4855. #else // ! DPNBUILD_XNETSECURITY
  4856. QueryResponseData.pAddressDevice = GetSocketPort()->GetDP8BoundNetworkAddress( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT, GetGatewayBindType() );
  4857. #endif // ! DPNBUILD_XNETSECURITY
  4858. if ( QueryResponseData.pAddressDevice != NULL )
  4859. {
  4860. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_QUERYRESPONSE 0x%p to interface 0x%p.",
  4861. this, &QueryResponseData, m_pSPData->DP8SPCallbackInterface());
  4862. DumpAddress( 8, _T("\t Sender:"), QueryResponseData.pAddressSender );
  4863. DumpAddress( 8, _T("\t Device:"), QueryResponseData.pAddressDevice );
  4864. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  4865. hrTemp = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to DirectNet interface
  4866. SPEV_QUERYRESPONSE, // data type
  4867. &QueryResponseData // pointer to data
  4868. );
  4869. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_QUERYRESPONSE [0x%lx].", this, hrTemp);
  4870. if ( hrTemp != DPN_OK )
  4871. {
  4872. DPFX(DPFPREP, 0, "User returned unknown error when indicating query response!" );
  4873. DisplayDNError( 0, hrTemp );
  4874. DNASSERT( FALSE );
  4875. }
  4876. IDirectPlay8Address_Release( QueryResponseData.pAddressDevice );
  4877. QueryResponseData.pAddressDevice = NULL;
  4878. }
  4879. IDirectPlay8Address_Release( QueryResponseData.pAddressSender );
  4880. QueryResponseData.pAddressSender = NULL;
  4881. }
  4882. if (fAddedThreadCount)
  4883. {
  4884. DWORD dwThreadCount;
  4885. BOOL fNeedToComplete;
  4886. //
  4887. // Decrement thread count and complete if required
  4888. //
  4889. fNeedToComplete = FALSE;
  4890. Lock();
  4891. dwThreadCount = DecRefThreadCount();
  4892. if ((m_State == ENDPOINT_STATE_WAITING_TO_COMPLETE) && (dwThreadCount == 0))
  4893. {
  4894. fNeedToComplete = TRUE;
  4895. }
  4896. Unlock();
  4897. if (fNeedToComplete)
  4898. {
  4899. EnumComplete( DPN_OK );
  4900. }
  4901. }
  4902. DNASSERT( QueryResponseData.pAddressSender == NULL );
  4903. DNASSERT( QueryResponseData.pAddressDevice == NULL );
  4904. }
  4905. //**********************************************************************
  4906. //**********************************************************************
  4907. // ------------------------------
  4908. // CEndpoint::ProcessUserData - process received user data
  4909. //
  4910. // Entry: Pointer to received data
  4911. //
  4912. // Exit: Nothing
  4913. // ------------------------------
  4914. #undef DPF_MODNAME
  4915. #define DPF_MODNAME "CEndpoint::ProcessUserData"
  4916. void CEndpoint::ProcessUserData( CReadIOData *const pReadData )
  4917. {
  4918. DNASSERT( pReadData != NULL );
  4919. Lock();
  4920. switch ( m_State )
  4921. {
  4922. //
  4923. // endpoint is connected
  4924. //
  4925. case ENDPOINT_STATE_CONNECT_CONNECTED:
  4926. {
  4927. HRESULT hr;
  4928. SPIE_DATA UserData;
  4929. //
  4930. // Although the endpoint is marked as connected, it's possible that
  4931. // we haven't stored the user context yet. Make sure we've done
  4932. // that.
  4933. //
  4934. if ( ! m_fConnectSignalled )
  4935. {
  4936. DPFX(DPFPREP, 1, "(0x%p) Thread indicating connect has not stored user context yet, dropping read data 0x%p.",
  4937. this, pReadData);
  4938. Unlock();
  4939. break;
  4940. }
  4941. //
  4942. // we're connected report the user data
  4943. //
  4944. DEBUG_ONLY( memset( &UserData, 0x00, sizeof( UserData ) ) );
  4945. UserData.pEndpointContext = GetUserEndpointContext();
  4946. Unlock();
  4947. UserData.hEndpoint = (HANDLE) this;
  4948. UserData.pReceivedData = pReadData->ReceivedBuffer();
  4949. //
  4950. // it's possible that the user will want to keep the data, add a
  4951. // reference to keep it from going away
  4952. //
  4953. pReadData->AddRef();
  4954. DEBUG_ONLY( DNASSERT( pReadData->m_fRetainedByHigherLayer == FALSE ) );
  4955. DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = TRUE );
  4956. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_DATA 0x%p to interface 0x%p.",
  4957. this, &UserData, m_pSPData->DP8SPCallbackInterface());
  4958. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  4959. hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to interface
  4960. SPEV_DATA, // user data was received
  4961. &UserData // pointer to data
  4962. );
  4963. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_DATA [0x%lx].", this, hr);
  4964. switch ( hr )
  4965. {
  4966. //
  4967. // user didn't keep the data, remove the reference added above
  4968. //
  4969. case DPN_OK:
  4970. {
  4971. DNASSERT( pReadData != NULL );
  4972. DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = FALSE );
  4973. pReadData->DecRef();
  4974. break;
  4975. }
  4976. //
  4977. // The user kept the data buffer, they will return it later.
  4978. // Leave the reference to prevent this buffer from being returned
  4979. // to the pool.
  4980. //
  4981. case DPNERR_PENDING:
  4982. {
  4983. break;
  4984. }
  4985. //
  4986. // Unknown return. Remove the reference added above.
  4987. //
  4988. default:
  4989. {
  4990. DNASSERT( pReadData != NULL );
  4991. DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = FALSE );
  4992. pReadData->DecRef();
  4993. DPFX(DPFPREP, 0, "User returned unknown error when indicating user data (err = 0x%lx)!", hr );
  4994. DisplayDNError( 0, hr );
  4995. DNASSERT( FALSE );
  4996. break;
  4997. }
  4998. }
  4999. break;
  5000. }
  5001. //
  5002. // Endpoint hasn't finished connecting yet, ignore data.
  5003. //
  5004. case ENDPOINT_STATE_ATTEMPTING_CONNECT:
  5005. {
  5006. DPFX(DPFPREP, 3, "Endpoint 0x%p still connecting, dropping read data 0x%p.",
  5007. this, pReadData);
  5008. Unlock();
  5009. break;
  5010. }
  5011. //
  5012. // Endpoint disconnecting, ignore data.
  5013. //
  5014. case ENDPOINT_STATE_DISCONNECTING:
  5015. {
  5016. DPFX(DPFPREP, 3, "Endpoint 0x%p disconnecting, dropping read data 0x%p.",
  5017. this, pReadData);
  5018. Unlock();
  5019. break;
  5020. }
  5021. //
  5022. // other state
  5023. //
  5024. default:
  5025. {
  5026. DNASSERT( FALSE );
  5027. Unlock();
  5028. break;
  5029. }
  5030. }
  5031. return;
  5032. }
  5033. //**********************************************************************
  5034. //**********************************************************************
  5035. // ------------------------------
  5036. // CEndpoint::ProcessUserDataOnListen - process received user data on a listen
  5037. // port that may result in a new connection
  5038. //
  5039. // Entry: Pointer to received data
  5040. // Pointer to socket address that data was received from
  5041. //
  5042. // Exit: Nothing
  5043. // ------------------------------
  5044. #undef DPF_MODNAME
  5045. #define DPF_MODNAME "CEndpoint::ProcessUserDataOnListen"
  5046. void CEndpoint::ProcessUserDataOnListen( CReadIOData *const pReadData, const CSocketAddress *const pSocketAddress )
  5047. {
  5048. HRESULT hr;
  5049. CEndpoint * pNewEndpoint;
  5050. SPIE_DATA_UNCONNECTED DataUnconnected;
  5051. BYTE abUnconnectedReplyBuffer[MAX_SEND_FRAME_SIZE];
  5052. SPIE_CONNECT ConnectData;
  5053. BOOL fGotCommandRef;
  5054. DNASSERT( pReadData != NULL );
  5055. DNASSERT( pSocketAddress != NULL );
  5056. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  5057. //
  5058. // initialize
  5059. //
  5060. pNewEndpoint = NULL;
  5061. switch ( m_State )
  5062. {
  5063. //
  5064. // this endpoint is still listening
  5065. //
  5066. case ENDPOINT_STATE_LISTEN:
  5067. {
  5068. break;
  5069. }
  5070. //
  5071. // we're unable to process this user data, exti
  5072. //
  5073. case ENDPOINT_STATE_DISCONNECTING:
  5074. {
  5075. DPFX(DPFPREP, 7, "Endpoint 0x%p disconnecting, ignoring data.", this );
  5076. goto Exit;
  5077. break;
  5078. }
  5079. //
  5080. // other state
  5081. //
  5082. default:
  5083. {
  5084. DNASSERT( FALSE );
  5085. break;
  5086. }
  5087. }
  5088. #ifndef DPNBUILD_NOMULTICAST
  5089. //
  5090. // Multicast listens don't auto-create new endpoints for unrecognized
  5091. // senders. If the user requested that he/she wanted to hear data
  5092. // from unknown senders, then indicate the data, otherwise drop it.
  5093. //
  5094. if ( GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN )
  5095. {
  5096. DNASSERT( m_pActiveCommandData != NULL );
  5097. DNASSERT( GetCommandParameters() != NULL );
  5098. if ( GetCommandParameters()->PendingCommandData.ListenData.dwFlags & DPNSPF_LISTEN_ALLOWUNKNOWNSENDERS )
  5099. {
  5100. DPFX(DPFPREP, 7, "Endpoint 0x%p receiving data from unknown multicast sender.", this );
  5101. ProcessMcastDataFromUnknownSender( pReadData, pSocketAddress );
  5102. }
  5103. else
  5104. {
  5105. DPFX(DPFPREP, 7, "Endpoint 0x%p ignoring data from unknown multicast sender.", this );
  5106. }
  5107. goto Exit;
  5108. }
  5109. #endif // ! DPNBUILD_NOMULTICAST
  5110. //
  5111. // Give the user a chance to process and reply to this data without
  5112. // allocating any endpoints.
  5113. //
  5114. DEBUG_ONLY( memset( &DataUnconnected, 0x00, sizeof( DataUnconnected ) ) );
  5115. DataUnconnected.pvListenCommandContext = m_pActiveCommandData->GetUserContext();
  5116. DataUnconnected.pReceivedData = pReadData->ReceivedBuffer();
  5117. DataUnconnected.dwSenderAddressHash = CSocketAddress::HashFunction( (PVOID) pSocketAddress, 31 ); // hash the address to a full DWORD
  5118. DataUnconnected.pvReplyBuffer = abUnconnectedReplyBuffer;
  5119. DataUnconnected.dwReplyBufferSize = sizeof(abUnconnectedReplyBuffer);
  5120. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_DATA_UNCONNECTED 0x%p to interface 0x%p.",
  5121. this, &DataUnconnected, m_pSPData->DP8SPCallbackInterface());
  5122. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  5123. hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to interface
  5124. SPEV_DATA_UNCONNECTED, // unconnected user data was received
  5125. &DataUnconnected // pointer to data
  5126. );
  5127. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_DATA_UNCONNECTED [0x%lx].", this, hr);
  5128. if ( hr != DPN_OK )
  5129. {
  5130. #pragma TODO(vanceo, "A more explicit return, like DPNSUCCESS_REPLY?")
  5131. if ( hr == DPNSUCCESS_PENDING )
  5132. {
  5133. BUFFERDESC ReplyBufferDesc;
  5134. //
  5135. // The user wants to reply to the sender without committing a connection for it.
  5136. //
  5137. DNASSERT( DataUnconnected.pvReplyBuffer == abUnconnectedReplyBuffer );
  5138. DNASSERT( DataUnconnected.dwReplyBufferSize != 0 );
  5139. DNASSERT( DataUnconnected.dwReplyBufferSize <= sizeof(abUnconnectedReplyBuffer) );
  5140. ReplyBufferDesc.dwBufferSize = DataUnconnected.dwReplyBufferSize;
  5141. ReplyBufferDesc.pBufferData = abUnconnectedReplyBuffer;
  5142. DPFX(DPFPREP, 7, "Replying to unconnected data.");
  5143. #ifdef DPNBUILD_ASYNCSPSENDS
  5144. m_pSocketPort->SendData( &ReplyBufferDesc, 1, pSocketAddress, NULL );
  5145. #else // ! DPNBUILD_ASYNCSPSENDS
  5146. m_pSocketPort->SendData( &ReplyBufferDesc, 1, pSocketAddress );
  5147. #endif // ! DPNBUILD_ASYNCSPSENDS
  5148. }
  5149. else
  5150. {
  5151. //
  5152. // The user does not care about this data.
  5153. //
  5154. DPFX(DPFPREP, 7, "Ignoring unconnected data (user returned 0x%lx).", hr );
  5155. DNASSERT( ( hr == DPNERR_ABORTED ) || ( hr == DPNERR_OUTOFMEMORY ) );
  5156. }
  5157. goto Exit;
  5158. }
  5159. DPFX(DPFPREP, 7, "Endpoint 0x%p reporting connect on a listen.", this );
  5160. //
  5161. // get a new endpoint from the pool
  5162. //
  5163. pNewEndpoint = m_pSPData->GetNewEndpoint();
  5164. if ( pNewEndpoint == NULL )
  5165. {
  5166. hr = DPNERR_OUTOFMEMORY;
  5167. DPFX(DPFPREP, 0, "Could not create new endpoint for new connection on listen!" );
  5168. goto Failure;
  5169. }
  5170. #ifndef DPNBUILD_NONATHELP
  5171. pNewEndpoint->SetUserTraversalMode( GetUserTraversalMode() );
  5172. #endif // ! DPNBUILD_NONATHELP
  5173. //
  5174. // We are adding this endpoint to the hash table and indicating it up
  5175. // to the user, so it's possible that it could be disconnected (and thus
  5176. // removed from the table) while we're still in here. We need to
  5177. // hold an additional reference for the duration of this function to
  5178. // prevent it from disappearing while we're still indicating data.
  5179. //
  5180. fGotCommandRef = pNewEndpoint->AddCommandRef();
  5181. DNASSERT( fGotCommandRef );
  5182. //
  5183. // open this endpoint as a new connection, since the new endpoint
  5184. // is related to 'this' endpoint, copy local information
  5185. //
  5186. hr = pNewEndpoint->Open( ENDPOINT_TYPE_CONNECT_ON_LISTEN,
  5187. NULL,
  5188. #ifdef DPNBUILD_XNETSECURITY
  5189. ((IsUsingXNetSecurity()) ? (&m_ullKeyID) : NULL), // Open has a special session data case for CONNECT_ON_LISTEN endpoints
  5190. ((IsUsingXNetSecurity()) ? (sizeof(m_ullKeyID)) : 0),
  5191. #else // ! DPNBUILD_XNETSECURITY
  5192. NULL,
  5193. 0,
  5194. #endif // ! DPNBUILD_XNETSECURITY
  5195. pSocketAddress
  5196. );
  5197. if ( hr != DPN_OK )
  5198. {
  5199. DPFX(DPFPREP, 0, "Problem initializing new endpoint when indicating connect on listen!" );
  5200. DisplayDNError( 0, hr );
  5201. goto Failure;
  5202. }
  5203. hr = m_pSPData->BindEndpoint( pNewEndpoint, NULL, GetSocketPort()->GetNetworkAddress(), GATEWAY_BIND_TYPE_NONE );
  5204. if ( hr != DPN_OK )
  5205. {
  5206. DPFX(DPFPREP, 0, "Failed to bind new endpoint for connect on listen!" );
  5207. DisplayDNError( 0, hr );
  5208. goto Failure;
  5209. }
  5210. //
  5211. // Indicate connect on this endpoint.
  5212. //
  5213. DEBUG_ONLY( memset( &ConnectData, 0x00, sizeof( ConnectData ) ) );
  5214. DBG_CASSERT( sizeof( ConnectData.hEndpoint ) == sizeof( pNewEndpoint ) );
  5215. ConnectData.hEndpoint = (HANDLE) pNewEndpoint;
  5216. DNASSERT( m_pActiveCommandData != NULL );
  5217. DNASSERT( GetCommandParameters() != NULL );
  5218. ConnectData.pCommandContext = GetCommandParameters()->PendingCommandData.ListenData.pvContext;
  5219. DNASSERT( pNewEndpoint->GetUserEndpointContext() == NULL );
  5220. hr = pNewEndpoint->SignalConnect( &ConnectData );
  5221. switch ( hr )
  5222. {
  5223. //
  5224. // user accepted new connection
  5225. //
  5226. case DPN_OK:
  5227. {
  5228. //
  5229. // fall through to code below
  5230. //
  5231. break;
  5232. }
  5233. //
  5234. // user refused new connection
  5235. //
  5236. case DPNERR_ABORTED:
  5237. {
  5238. DNASSERT( pNewEndpoint->GetUserEndpointContext() == NULL );
  5239. DPFX(DPFPREP, 8, "User refused new connection!" );
  5240. goto Failure;
  5241. break;
  5242. }
  5243. //
  5244. // other
  5245. //
  5246. default:
  5247. {
  5248. DPFX(DPFPREP, 0, "Unknown return when indicating connect event on new connect from listen!" );
  5249. DisplayDNError( 0, hr );
  5250. DNASSERT( FALSE );
  5251. break;
  5252. }
  5253. }
  5254. //
  5255. // note that a connection has been established and send the data received
  5256. // through this new endpoint
  5257. //
  5258. pNewEndpoint->ProcessUserData( pReadData );
  5259. //
  5260. // Remove the reference we added just after creating the endpoint.
  5261. //
  5262. pNewEndpoint->DecCommandRef();
  5263. //pNewEndpoint = NULL;
  5264. Exit:
  5265. return;
  5266. Failure:
  5267. if ( pNewEndpoint != NULL )
  5268. {
  5269. //
  5270. // closing endpoint decrements reference count and may return it to the pool
  5271. //
  5272. pNewEndpoint->Close( hr );
  5273. m_pSPData->CloseEndpointHandle( pNewEndpoint );
  5274. pNewEndpoint->DecCommandRef(); // remove reference added just after creating endpoint
  5275. //pNewEndpoint = NULL;
  5276. }
  5277. goto Exit;
  5278. }
  5279. //**********************************************************************
  5280. #ifndef DPNBUILD_NOMULTICAST
  5281. //**********************************************************************
  5282. // ------------------------------
  5283. // CEndpoint::ProcessMcastDataFromUnknownSender - process received user data from an unknown multicast sender
  5284. //
  5285. // Entry: Pointer to received data
  5286. // Pointer to socket address that data was received from
  5287. //
  5288. // Exit: Nothing
  5289. // ------------------------------
  5290. #undef DPF_MODNAME
  5291. #define DPF_MODNAME "CEndpoint::ProcessMcastDataFromUnknownSender"
  5292. void CEndpoint::ProcessMcastDataFromUnknownSender( CReadIOData *const pReadData, const CSocketAddress *const pSocketAddress )
  5293. {
  5294. HRESULT hr;
  5295. IDirectPlay8Address * pSenderAddress;
  5296. SPIE_DATA_UNKNOWNSENDER UserData;
  5297. DNASSERT( pReadData != NULL );
  5298. DNASSERT( pSocketAddress != NULL );
  5299. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  5300. pSenderAddress = pSocketAddress->DP8AddressFromSocketAddress( SP_ADDRESS_TYPE_READ_HOST );
  5301. if (pSenderAddress == NULL)
  5302. {
  5303. DPFX(DPFPREP, 0, "Couldn't convert socket address to DP8Address, ignoring data.");
  5304. return;
  5305. }
  5306. //
  5307. // it's possible that the user wants to keep the data, add a
  5308. // reference to keep it from going away
  5309. //
  5310. pReadData->AddRef();
  5311. DEBUG_ONLY( DNASSERT( pReadData->m_fRetainedByHigherLayer == FALSE ) );
  5312. DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = TRUE );
  5313. //
  5314. // we're connected report the user data
  5315. //
  5316. DEBUG_ONLY( memset( &UserData, 0x00, sizeof( UserData ) ) );
  5317. UserData.pSenderAddress = pSenderAddress;
  5318. UserData.pvListenCommandContext = m_pActiveCommandData->GetUserContext();
  5319. UserData.pReceivedData = pReadData->ReceivedBuffer();
  5320. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_DATA_UNKNOWNSENDER 0x%p to interface 0x%p.",
  5321. this, &UserData, m_pSPData->DP8SPCallbackInterface());
  5322. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  5323. hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // pointer to interface
  5324. SPEV_DATA_UNKNOWNSENDER, // user data was received
  5325. &UserData // pointer to data
  5326. );
  5327. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_DATA_UNKNOWNSENDER [0x%lx].", this, hr);
  5328. switch ( hr )
  5329. {
  5330. //
  5331. // user didn't keep the data, remove the reference added above
  5332. //
  5333. case DPN_OK:
  5334. {
  5335. DNASSERT( pReadData != NULL );
  5336. DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = FALSE );
  5337. pReadData->DecRef();
  5338. break;
  5339. }
  5340. //
  5341. // The user kept the data buffer, they will return it later.
  5342. // Leave the reference to prevent this buffer from being returned
  5343. // to the pool.
  5344. //
  5345. case DPNERR_PENDING:
  5346. {
  5347. break;
  5348. }
  5349. //
  5350. // Unknown return. Remove the reference added above.
  5351. //
  5352. default:
  5353. {
  5354. DNASSERT( pReadData != NULL );
  5355. DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = FALSE );
  5356. pReadData->DecRef();
  5357. DPFX(DPFPREP, 0, "User returned unknown error when indicating user data (err = 0x%lx)!", hr );
  5358. DisplayDNError( 0, hr );
  5359. DNASSERT( FALSE );
  5360. break;
  5361. }
  5362. }
  5363. IDirectPlay8Address_Release(pSenderAddress);
  5364. pSenderAddress = NULL;
  5365. return;
  5366. }
  5367. //**********************************************************************
  5368. #endif // ! DPNBUILD_NOMULTICAST
  5369. //**********************************************************************
  5370. // ------------------------------
  5371. // CEndpoint::EnumTimerCallback - timed callback to send enum data
  5372. //
  5373. // Entry: Pointer to context
  5374. //
  5375. // Exit: Nothing
  5376. // ------------------------------
  5377. #undef DPF_MODNAME
  5378. #define DPF_MODNAME "CEndpoint::EnumTimerCallback"
  5379. void CEndpoint::EnumTimerCallback( void *const pContext )
  5380. {
  5381. CCommandData *pCommandData;
  5382. CEndpoint *pThisObject;
  5383. BUFFERDESC *pBuffers;
  5384. BUFFERDESC aBuffers[3];
  5385. UINT_PTR uiBufferCount;
  5386. WORD wEnumKey;
  5387. PREPEND_BUFFER PrependBuffer;
  5388. DNASSERT( pContext != NULL );
  5389. //
  5390. // initialize
  5391. //
  5392. pCommandData = static_cast<CCommandData*>( pContext );
  5393. pThisObject = pCommandData->GetEndpoint();
  5394. pThisObject->Lock();
  5395. switch ( pThisObject->m_State )
  5396. {
  5397. //
  5398. // we're enumerating (as expected)
  5399. //
  5400. case ENDPOINT_STATE_ENUM:
  5401. {
  5402. break;
  5403. }
  5404. //
  5405. // this endpoint is disconnecting, bail!
  5406. //
  5407. case ENDPOINT_STATE_WAITING_TO_COMPLETE:
  5408. case ENDPOINT_STATE_DISCONNECTING:
  5409. {
  5410. pThisObject->Unlock();
  5411. goto Exit;
  5412. break;
  5413. }
  5414. //
  5415. // there's a problem
  5416. //
  5417. default:
  5418. {
  5419. DNASSERT( FALSE );
  5420. break;
  5421. }
  5422. }
  5423. pThisObject->Unlock();
  5424. pThisObject->GetCommandParameters()->dwEnumSendIndex++;
  5425. pThisObject->GetCommandParameters()->dwEnumSendTimes[ ( pThisObject->GetCommandParameters()->dwEnumSendIndex & ENUM_RTT_MASK ) ] = GETTIMESTAMP();
  5426. DPFX(DPFPREP, 8, "Socketport 0x%p, endpoint 0x%p sending enum RTT index 0x%x/%u.",
  5427. pThisObject->GetSocketPort(),
  5428. pThisObject,
  5429. ( pThisObject->GetCommandParameters()->dwEnumSendIndex & ENUM_RTT_MASK ),
  5430. ( pThisObject->GetCommandParameters()->dwEnumSendIndex & ENUM_RTT_MASK ));
  5431. pBuffers = pThisObject->GetCommandParameters()->PendingCommandData.EnumQueryData.pBuffers;
  5432. uiBufferCount = pThisObject->GetCommandParameters()->PendingCommandData.EnumQueryData.dwBufferCount;
  5433. wEnumKey = pThisObject->GetEnumKey()->GetKey();
  5434. wEnumKey |= (WORD) ( pThisObject->GetCommandParameters()->dwEnumSendIndex & ENUM_RTT_MASK );
  5435. PrependBuffer.EnumDataHeader.bSPLeadByte = SP_HEADER_LEAD_BYTE;
  5436. PrependBuffer.EnumDataHeader.bSPCommandByte = ENUM_DATA_KIND;
  5437. PrependBuffer.EnumDataHeader.wEnumPayload = wEnumKey;
  5438. aBuffers[0].pBufferData = reinterpret_cast<BYTE*>( &PrependBuffer.EnumDataHeader );
  5439. aBuffers[0].dwBufferSize = sizeof( PrependBuffer.EnumDataHeader );
  5440. DNASSERT(uiBufferCount <= 2);
  5441. memcpy(&aBuffers[1], pBuffers, (uiBufferCount * sizeof(BUFFERDESC)));
  5442. uiBufferCount++;
  5443. #ifdef DPNBUILD_ASYNCSPSENDS
  5444. pThisObject->GetSocketPort()->SendData( aBuffers, uiBufferCount, pThisObject->GetRemoteAddressPointer(), NULL );
  5445. #else // ! DPNBUILD_ASYNCSPSENDS
  5446. pThisObject->GetSocketPort()->SendData( aBuffers, uiBufferCount, pThisObject->GetRemoteAddressPointer() );
  5447. #endif // ! DPNBUILD_ASYNCSPSENDS
  5448. Exit:
  5449. return;
  5450. }
  5451. //**********************************************************************
  5452. //**********************************************************************
  5453. // ------------------------------
  5454. // CEndpoint::SignalConnect - note connection
  5455. //
  5456. // Entry: Pointer to connect data
  5457. //
  5458. // Exit: Error code
  5459. // ------------------------------
  5460. #undef DPF_MODNAME
  5461. #define DPF_MODNAME "CEndpoint::SignalConnect"
  5462. HRESULT CEndpoint::SignalConnect( SPIE_CONNECT *const pConnectData )
  5463. {
  5464. HRESULT hr;
  5465. DNASSERT( pConnectData != NULL );
  5466. DNASSERT( pConnectData->hEndpoint == (HANDLE) this );
  5467. AssertCriticalSectionIsTakenByThisThread( &m_Lock, FALSE );
  5468. //
  5469. // Lock while we check state.
  5470. //
  5471. Lock();
  5472. //
  5473. // initialize
  5474. //
  5475. hr = DPN_OK;
  5476. switch ( m_State )
  5477. {
  5478. //
  5479. // disconnecting, nothing to do
  5480. //
  5481. case ENDPOINT_STATE_DISCONNECTING:
  5482. {
  5483. DPFX(DPFPREP, 1, "Endpoint 0x%p disconnecting, not indicating event.",
  5484. this);
  5485. //
  5486. // Drop the lock.
  5487. //
  5488. Unlock();
  5489. hr = DPNERR_USERCANCEL;
  5490. break;
  5491. }
  5492. //
  5493. // we're attempting to connect
  5494. //
  5495. case ENDPOINT_STATE_ATTEMPTING_CONNECT:
  5496. {
  5497. DNASSERT( m_fConnectSignalled == FALSE );
  5498. //
  5499. // Set the state as connected.
  5500. //
  5501. m_State = ENDPOINT_STATE_CONNECT_CONNECTED;
  5502. //
  5503. // Add a reference for the user.
  5504. //
  5505. AddRef();
  5506. //
  5507. // Drop the lock.
  5508. //
  5509. Unlock();
  5510. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_CONNECT 0x%p to interface 0x%p.",
  5511. this, pConnectData, m_pSPData->DP8SPCallbackInterface());
  5512. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  5513. hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
  5514. SPEV_CONNECT, // event type
  5515. pConnectData // pointer to data
  5516. );
  5517. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_CONNECT [0x%lx].", this, hr);
  5518. switch ( hr )
  5519. {
  5520. //
  5521. // connection accepted
  5522. //
  5523. case DPN_OK:
  5524. {
  5525. //
  5526. // note that we're connected, unless we're already trying to
  5527. // disconnect.
  5528. //
  5529. Lock();
  5530. SetUserEndpointContext( pConnectData->pEndpointContext );
  5531. m_fConnectSignalled = TRUE;
  5532. if (m_State == ENDPOINT_STATE_DISCONNECTING)
  5533. {
  5534. //
  5535. // Although the endpoint is disconnecting, whatever caused the
  5536. // disconnect will release the reference added before we indicated
  5537. // the connect.
  5538. //
  5539. DPFX(DPFPREP, 1, "Endpoint 0x%p already disconnecting.", this);
  5540. }
  5541. else
  5542. {
  5543. DNASSERT(m_State == ENDPOINT_STATE_CONNECT_CONNECTED);
  5544. //
  5545. // The reference added before we indicated the connect will be
  5546. // removed when the endpoint is disconnected.
  5547. //
  5548. }
  5549. Unlock();
  5550. break;
  5551. }
  5552. //
  5553. // user aborted connection attempt, nothing to do, just pass
  5554. // the result on
  5555. //
  5556. case DPNERR_ABORTED:
  5557. {
  5558. DNASSERT( GetUserEndpointContext() == NULL );
  5559. //
  5560. // Remove the user reference.
  5561. //
  5562. DecRef();
  5563. break;
  5564. }
  5565. default:
  5566. {
  5567. DNASSERT( FALSE );
  5568. //
  5569. // Remove the user reference.
  5570. //
  5571. DecRef();
  5572. break;
  5573. }
  5574. }
  5575. break;
  5576. }
  5577. //
  5578. // states where we shouldn't be getting called
  5579. //
  5580. default:
  5581. {
  5582. DNASSERT( FALSE );
  5583. //
  5584. // Drop the lock.
  5585. //
  5586. Unlock();
  5587. break;
  5588. }
  5589. }
  5590. return hr;
  5591. }
  5592. //**********************************************************************
  5593. //**********************************************************************
  5594. // ------------------------------
  5595. // CEndpoint::SignalDisconnect - note disconnection
  5596. //
  5597. // Entry: Nothing
  5598. //
  5599. // Exit: Nothing
  5600. //
  5601. // Note: This function assumes that this endpoint's data is locked!
  5602. // ------------------------------
  5603. #undef DPF_MODNAME
  5604. #define DPF_MODNAME "CEndpoint::SignalDisconnect"
  5605. void CEndpoint::SignalDisconnect( void )
  5606. {
  5607. HRESULT hr;
  5608. SPIE_DISCONNECT DisconnectData;
  5609. // tell user that we're disconnecting
  5610. DNASSERT( m_fConnectSignalled != FALSE );
  5611. DBG_CASSERT( sizeof( DisconnectData.hEndpoint ) == sizeof( this ) );
  5612. DisconnectData.hEndpoint = (HANDLE) this;
  5613. DisconnectData.pEndpointContext = GetUserEndpointContext();
  5614. m_fConnectSignalled = FALSE;
  5615. DPFX(DPFPREP, 2, "Endpoint 0x%p indicating SPEV_DISCONNECT 0x%p to interface 0x%p.",
  5616. this, &DisconnectData, m_pSPData->DP8SPCallbackInterface());
  5617. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  5618. hr = IDP8SPCallback_IndicateEvent( m_pSPData->DP8SPCallbackInterface(), // interface
  5619. SPEV_DISCONNECT, // event type
  5620. &DisconnectData // pointer to data
  5621. );
  5622. DPFX(DPFPREP, 2, "Endpoint 0x%p returning from SPEV_DISCONNECT [0x%lx].", this, hr);
  5623. if ( hr != DPN_OK )
  5624. {
  5625. DPFX(DPFPREP, 0, "Problem with SignalDisconnect!" );
  5626. DisplayDNError( 0, hr );
  5627. DNASSERT( FALSE );
  5628. }
  5629. return;
  5630. }
  5631. //**********************************************************************
  5632. //**********************************************************************
  5633. // ------------------------------
  5634. // CEndpoint::CompletePendingCommand - complete a pending command
  5635. //
  5636. // Entry: Error code returned for command
  5637. //
  5638. // Exit: Nothing
  5639. // ------------------------------
  5640. #undef DPF_MODNAME
  5641. #define DPF_MODNAME "CEndpoint::CompletePendingCommand"
  5642. void CEndpoint::CompletePendingCommand( const HRESULT hCommandResult )
  5643. {
  5644. HRESULT hr;
  5645. ENDPOINT_COMMAND_PARAMETERS * pCommandParameters;
  5646. CCommandData * pActiveCommandData;
  5647. DNASSERT( GetCommandParameters() != NULL );
  5648. DNASSERT( m_pActiveCommandData != NULL );
  5649. pCommandParameters = GetCommandParameters();
  5650. SetCommandParameters( NULL );
  5651. pActiveCommandData = m_pActiveCommandData;
  5652. m_pActiveCommandData = NULL;
  5653. DPFX(DPFPREP, 5, "Endpoint 0x%p completing command 0x%p (result = 0x%lx, user context = 0x%p) to interface 0x%p.",
  5654. this, pActiveCommandData, hCommandResult,
  5655. pActiveCommandData->GetUserContext(),
  5656. m_pSPData->DP8SPCallbackInterface());
  5657. // NOTE: Enum commands may have timer data lock held
  5658. hr = IDP8SPCallback_CommandComplete( m_pSPData->DP8SPCallbackInterface(), // pointer to callbacks
  5659. pActiveCommandData, // command handle
  5660. hCommandResult, // return
  5661. pActiveCommandData->GetUserContext() // user cookie
  5662. );
  5663. DPFX(DPFPREP, 5, "Endpoint 0x%p returning from command complete [0x%lx].", this, hr);
  5664. memset( pCommandParameters, 0x00, sizeof( *pCommandParameters ) );
  5665. g_EndpointCommandParametersPool.Release( pCommandParameters );
  5666. pActiveCommandData->DecRef();
  5667. pActiveCommandData = NULL;
  5668. }
  5669. //**********************************************************************
  5670. //**********************************************************************
  5671. // ------------------------------
  5672. // CEndpoint::PoolAllocFunction - function called when item is created in pool
  5673. //
  5674. // Entry: Pointer to context
  5675. //
  5676. // Exit: Boolean indicating success
  5677. // TRUE = success
  5678. // FALSE = failure
  5679. // ------------------------------
  5680. #undef DPF_MODNAME
  5681. #define DPF_MODNAME "CEndpoint::PoolAllocFunction"
  5682. BOOL CEndpoint::PoolAllocFunction( void* pvItem, void* pvContext )
  5683. {
  5684. DNASSERT( pvContext != NULL );
  5685. CEndpoint* pEndpoint = (CEndpoint*) pvItem;
  5686. const CSPData * pSPData = (CSPData*) pvContext;
  5687. pEndpoint->m_Sig[0] = 'I';
  5688. pEndpoint->m_Sig[1] = 'P';
  5689. pEndpoint->m_Sig[2] = 'E';
  5690. pEndpoint->m_Sig[3] = 'P';
  5691. pEndpoint->m_State = ENDPOINT_STATE_UNINITIALIZED;
  5692. pEndpoint->m_fConnectSignalled = FALSE;
  5693. pEndpoint->m_EndpointType = ENDPOINT_TYPE_UNKNOWN;
  5694. pEndpoint->m_pSPData = NULL;
  5695. pEndpoint->m_pSocketPort = NULL;
  5696. pEndpoint->m_GatewayBindType = GATEWAY_BIND_TYPE_UNKNOWN;
  5697. pEndpoint->m_pUserEndpointContext = NULL;
  5698. pEndpoint->m_fListenStatusNeedsToBeIndicated = FALSE;
  5699. pEndpoint->m_EnumsAllowedState = ENUMSNOTREADY;
  5700. pEndpoint->m_lRefCount = 0;
  5701. #ifdef DPNBUILD_ONLYONETHREAD
  5702. pEndpoint->m_lCommandRefCount = 0;
  5703. #else // ! DPNBUILD_ONLYONETHREAD
  5704. memset(&pEndpoint->m_CommandRefCount, 0, sizeof(pEndpoint->m_CommandRefCount));
  5705. #endif // ! DPNBUILD_ONLYONETHREAD
  5706. pEndpoint->m_pCommandParameters = NULL;
  5707. pEndpoint->m_pActiveCommandData = NULL;
  5708. pEndpoint->m_dwThreadCount = 0;
  5709. #ifndef DPNBUILD_ONLYONEADAPTER
  5710. pEndpoint->m_dwEndpointID = 0;
  5711. #endif // ! DPNBUILD_ONLYONEADAPTER
  5712. #ifndef DPNBUILD_NOMULTICAST
  5713. #ifdef WINNT
  5714. pEndpoint->m_fMADCAPTimerJobSubmitted = FALSE;
  5715. #endif // WINNT
  5716. #endif // ! DPNBUILD_NOMULTICAST
  5717. #ifndef DPNBUILD_NOSPUI
  5718. pEndpoint->m_hActiveSettingsDialog = NULL;
  5719. memset( pEndpoint->m_TempHostName, 0x00, sizeof( pEndpoint->m_TempHostName ) );
  5720. #endif // ! DPNBUILD_NOSPUI
  5721. #ifndef DPNBUILD_ONLYONEADAPTER
  5722. pEndpoint->m_blMultiplex.Initialize();
  5723. #endif // ! DPNBUILD_ONLYONEADAPTER
  5724. pEndpoint->m_blSocketPortList.Initialize();
  5725. DEBUG_ONLY( pEndpoint->m_fEndpointOpen = FALSE );
  5726. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  5727. pEndpoint->m_pRemoteMachineAddress = (CSocketAddress*)g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
  5728. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  5729. pEndpoint->m_pRemoteMachineAddress = (CSocketAddress*)g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) pSPData->GetType()));
  5730. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  5731. if (pEndpoint->m_pRemoteMachineAddress == NULL)
  5732. {
  5733. DPFX(DPFPREP, 0, "Failed to allocate Address for new endpoint!" );
  5734. goto Failure;
  5735. }
  5736. //
  5737. // attempt to initialize the internal critical section
  5738. //
  5739. if ( DNInitializeCriticalSection( &pEndpoint->m_Lock ) == FALSE )
  5740. {
  5741. DPFX(DPFPREP, 0, "Problem initializing critical section for this endpoint!" );
  5742. goto Failure;
  5743. }
  5744. DebugSetCriticalSectionRecursionCount( &pEndpoint->m_Lock, 0 );
  5745. DebugSetCriticalSectionGroup( &pEndpoint->m_Lock, &g_blDPNWSockCritSecsHeld ); // separate dpnwsock CSes from the rest of DPlay's CSes
  5746. return TRUE;
  5747. Failure:
  5748. return FALSE;
  5749. }
  5750. //**********************************************************************
  5751. //**********************************************************************
  5752. // ------------------------------
  5753. // CEndpoint::PoolInitFunction - function called when item is removed from pool
  5754. //
  5755. // Entry: Pointer to context
  5756. //
  5757. // Exit: Boolean indicating success
  5758. // TRUE = success
  5759. // FALSE = failure
  5760. // ------------------------------
  5761. #undef DPF_MODNAME
  5762. #define DPF_MODNAME "CEndpoint::PoolInitFunction"
  5763. void CEndpoint::PoolInitFunction( void* pvItem, void* pvContext )
  5764. {
  5765. CEndpoint* pEndpoint = (CEndpoint*) pvItem;
  5766. CSPData * pSPData = (CSPData*) pvContext;
  5767. DPFX(DPFPREP, 8, "This = 0x%p, context = 0x%p", pvItem, pvContext);
  5768. DNASSERT( pSPData != NULL );
  5769. DNASSERT( pEndpoint->m_pSPData == NULL );
  5770. pEndpoint->m_pSPData = pSPData;
  5771. pEndpoint->m_pSPData->ObjectAddRef();
  5772. pEndpoint->m_dwNumReceives = 0;
  5773. pEndpoint->m_hrPendingCommandResult = DPNERR_GENERIC;
  5774. #ifndef DPNBUILD_ONLYONEADAPTER
  5775. //
  5776. // NOTE: This doesn't work properly on Windows 95. From MSDN:
  5777. // "the return value is positive, but it is not necessarily equal to the result."
  5778. // All endpoints will probably get an ID of 1 on that platform.
  5779. //
  5780. pEndpoint->m_dwEndpointID = (DWORD) DNInterlockedIncrement((LONG*) (&g_dwCurrentEndpointID));
  5781. #endif // ! DPNBUILD_ONLYONEADAPTER
  5782. #ifdef DPNBUILD_XNETSECURITY
  5783. pEndpoint->m_fXNetSecurity = FALSE;
  5784. #endif // DPNBUILD_XNETSECURITY
  5785. DNASSERT( pEndpoint->m_fListenStatusNeedsToBeIndicated == FALSE );
  5786. DNASSERT( pEndpoint->m_EnumsAllowedState == ENUMSNOTREADY );
  5787. #ifndef DPNBUILD_ONLYONEADAPTER
  5788. DNASSERT( pEndpoint->m_blMultiplex.IsEmpty() );
  5789. #endif // ! DPNBUILD_ONLYONEADAPTER
  5790. DNASSERT( pEndpoint->m_blSocketPortList.IsEmpty() );
  5791. DNASSERT( pEndpoint->m_pCommandParameters == NULL );
  5792. DNASSERT( pEndpoint->m_pRemoteMachineAddress != NULL );
  5793. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  5794. pEndpoint->m_pRemoteMachineAddress->SetFamilyProtocolAndSize(pSPData->GetType());
  5795. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  5796. DNASSERT( pEndpoint->m_lRefCount == 0 );
  5797. pEndpoint->m_lRefCount = 1;
  5798. #ifdef DPNBUILD_ONLYONETHREAD
  5799. DNASSERT( pEndpoint->m_lCommandRefCount == 0 );
  5800. pEndpoint->m_lCommandRefCount = 1;
  5801. #else // ! DPNBUILD_ONLYONETHREAD
  5802. DNASSERT( pEndpoint->m_CommandRefCount.wRefCount == 0 );
  5803. pEndpoint->m_CommandRefCount.wRefCount = 1;
  5804. #endif // ! DPNBUILD_ONLYONETHREAD
  5805. }
  5806. //**********************************************************************
  5807. //**********************************************************************
  5808. // ------------------------------
  5809. // CEndpoint::PoolReleaseFunction - function called when item is returning
  5810. // to the pool
  5811. //
  5812. // Entry: Nothing
  5813. //
  5814. // Exit: Nothing
  5815. // ------------------------------
  5816. #undef DPF_MODNAME
  5817. #define DPF_MODNAME "CEndpoint::PoolReleaseFunction"
  5818. void CEndpoint::PoolReleaseFunction( void* pvItem )
  5819. {
  5820. DPFX(DPFPREP, 8, "This = 0x%p", pvItem);
  5821. CEndpoint* pEndpoint = (CEndpoint*)pvItem;
  5822. DNASSERT( pEndpoint->m_lRefCount == 0 );
  5823. #ifndef DPNBUILD_NOMULTICAST
  5824. #ifdef WINNT
  5825. if (pEndpoint->m_fMADCAPTimerJobSubmitted)
  5826. {
  5827. pEndpoint->m_pSPData->GetThreadPool()->StopTimerJob( pEndpoint, DPNERR_USERCANCEL );
  5828. pEndpoint->m_fMADCAPTimerJobSubmitted = FALSE;
  5829. }
  5830. #endif // WINNT
  5831. #endif // ! DPNBUILD_NOMULTICAST
  5832. #ifndef DPNBUILD_ONLYONEADAPTER
  5833. pEndpoint->SetEndpointID( 0 );
  5834. #endif // ! DPNBUILD_ONLYONEADAPTER
  5835. if ( pEndpoint->CommandPending() != FALSE )
  5836. {
  5837. pEndpoint->CompletePendingCommand( pEndpoint->PendingCommandResult() );
  5838. }
  5839. if ( pEndpoint->ConnectHasBeenSignalled() != FALSE )
  5840. {
  5841. pEndpoint->SignalDisconnect();
  5842. }
  5843. DNASSERT( pEndpoint->ConnectHasBeenSignalled() == FALSE );
  5844. pEndpoint->SetUserEndpointContext( NULL );
  5845. #ifdef DBG
  5846. DNASSERT( pEndpoint->m_fEndpointOpen == FALSE );
  5847. #endif // DBG
  5848. pEndpoint->m_EndpointType = ENDPOINT_TYPE_UNKNOWN;
  5849. DNASSERT( pEndpoint->m_fConnectSignalled == FALSE );
  5850. DNASSERT( pEndpoint->m_State == ENDPOINT_STATE_UNINITIALIZED );
  5851. DNASSERT( pEndpoint->m_EndpointType == ENDPOINT_TYPE_UNKNOWN );
  5852. DNASSERT( pEndpoint->m_pRemoteMachineAddress != NULL );
  5853. DNASSERT( pEndpoint->m_pSPData != NULL );
  5854. pEndpoint->m_pSPData->ObjectDecRef();
  5855. pEndpoint->m_pSPData = NULL;
  5856. DNASSERT( pEndpoint->GetSocketPort() == NULL );
  5857. DNASSERT( pEndpoint->m_pUserEndpointContext == NULL );
  5858. #ifndef DPNBUILD_NOSPUI
  5859. DNASSERT( pEndpoint->m_hActiveSettingsDialog == NULL );
  5860. #endif // ! DPNBUILD_NOSPUI
  5861. DNASSERT( pEndpoint->GetCommandParameters() == NULL );
  5862. DNASSERT( pEndpoint->m_fListenStatusNeedsToBeIndicated == FALSE );
  5863. DNASSERT( ! pEndpoint->IsEnumAllowedOnListen() );
  5864. pEndpoint->m_EnumsAllowedState = ENUMSNOTREADY;
  5865. #ifndef DPNBUILD_ONLYONEADAPTER
  5866. DNASSERT( pEndpoint->m_blMultiplex.IsEmpty() );
  5867. #endif // ! DPNBUILD_ONLYONEADAPTER
  5868. DNASSERT( pEndpoint->m_blSocketPortList.IsEmpty() );
  5869. }
  5870. //**********************************************************************
  5871. //**********************************************************************
  5872. // ------------------------------
  5873. // CEndpoint::PoolDeallocFunction - function called when item is deallocated
  5874. // from the pool
  5875. //
  5876. // Entry: Nothing
  5877. //
  5878. // Exit: Nothing
  5879. // ------------------------------
  5880. #undef DPF_MODNAME
  5881. #define DPF_MODNAME "CEndpoint::PoolDeallocFunction"
  5882. void CEndpoint::PoolDeallocFunction( void* pvItem )
  5883. {
  5884. CEndpoint* pEndpoint = (CEndpoint*)pvItem;
  5885. // This class
  5886. #ifndef DPNBUILD_NOSPUI
  5887. DNASSERT( pEndpoint->m_hActiveSettingsDialog == NULL );
  5888. #endif // !DPNBUILD_NOSPUI
  5889. #ifndef DPNBUILD_NOMULTICAST
  5890. #ifdef WINNT
  5891. DNASSERT(! pEndpoint->m_fMADCAPTimerJobSubmitted);
  5892. #endif // WINNT
  5893. #endif // ! DPNBUILD_NOMULTICAST
  5894. DNASSERT(pEndpoint->m_pRemoteMachineAddress != NULL);
  5895. g_SocketAddressPool.Release(pEndpoint->m_pRemoteMachineAddress);
  5896. pEndpoint->m_pRemoteMachineAddress = NULL;
  5897. DNDeleteCriticalSection( &pEndpoint->m_Lock );
  5898. DNASSERT( pEndpoint->m_pSPData == NULL );
  5899. // Base class
  5900. DNASSERT( pEndpoint->m_State == ENDPOINT_STATE_UNINITIALIZED );
  5901. DNASSERT( pEndpoint->m_fConnectSignalled == FALSE );
  5902. DNASSERT( pEndpoint->m_EndpointType == ENDPOINT_TYPE_UNKNOWN );
  5903. DNASSERT( pEndpoint->m_pRemoteMachineAddress == NULL );
  5904. DNASSERT( pEndpoint->m_pSPData == NULL );
  5905. DNASSERT( pEndpoint->m_pSocketPort == NULL );
  5906. DNASSERT( pEndpoint->m_GatewayBindType == GATEWAY_BIND_TYPE_UNKNOWN );
  5907. DNASSERT( pEndpoint->m_pUserEndpointContext == NULL );
  5908. #ifndef DPNBUILD_NOSPUI
  5909. DNASSERT( pEndpoint->GetActiveDialogHandle() == NULL );
  5910. #endif // !DPNBUILD_NOSPUI
  5911. DNASSERT( pEndpoint->m_fListenStatusNeedsToBeIndicated == FALSE );
  5912. DNASSERT( pEndpoint->m_EnumsAllowedState == ENUMSNOTREADY );
  5913. #ifndef DPNBUILD_ONLYONEADAPTER
  5914. DNASSERT( pEndpoint->m_blMultiplex.IsEmpty() );
  5915. #endif // ! DPNBUILD_ONLYONEADAPTER
  5916. #ifdef DPNBUILD_ONLYONETHREAD
  5917. DNASSERT( pEndpoint->m_lCommandRefCount == 0 );
  5918. #else // ! DPNBUILD_ONLYONETHREAD
  5919. DNASSERT( pEndpoint->m_CommandRefCount.wRefCount == 0 );
  5920. #endif // ! DPNBUILD_ONLYONETHREAD
  5921. DNASSERT( pEndpoint->m_pCommandParameters == NULL );
  5922. DNASSERT( pEndpoint->m_pActiveCommandData == NULL );
  5923. #ifdef DBG
  5924. DNASSERT( pEndpoint->m_fEndpointOpen == FALSE );
  5925. #endif // DBG
  5926. DNASSERT( pEndpoint->m_lRefCount == 0 );
  5927. }
  5928. //**********************************************************************
  5929. #ifndef DPNBUILD_NOSPUI
  5930. //**********************************************************************
  5931. // ------------------------------
  5932. // CEndpoint::ShowSettingsDialog - show dialog for settings
  5933. //
  5934. // Entry: Pointer to thread pool
  5935. //
  5936. // Exit: Error code
  5937. // ------------------------------
  5938. #undef DPF_MODNAME
  5939. #define DPF_MODNAME "CEndpoint::ShowSettingsDialog"
  5940. HRESULT CEndpoint::ShowSettingsDialog( CThreadPool *const pThreadPool )
  5941. {
  5942. HRESULT hr;
  5943. DNASSERT( pThreadPool != NULL );
  5944. DNASSERT( GetActiveDialogHandle() == NULL );
  5945. //
  5946. // initialize
  5947. //
  5948. hr = DPN_OK;
  5949. AddRef();
  5950. hr = pThreadPool->SpawnDialogThread( DisplayIPHostNameSettingsDialog, this );
  5951. if ( hr != DPN_OK )
  5952. {
  5953. DPFX(DPFPREP, 0, "Failed to start IP hostname dialog!" );
  5954. DisplayDNError( 0, hr );
  5955. goto Failure;
  5956. }
  5957. Exit:
  5958. return hr;
  5959. Failure:
  5960. DecRef();
  5961. goto Exit;
  5962. }
  5963. //**********************************************************************
  5964. //**********************************************************************
  5965. // ------------------------------
  5966. // CEndpoint::SettingsDialogComplete - dialog has completed
  5967. //
  5968. // Entry: Error code for dialog
  5969. //
  5970. // Exit: Nothing
  5971. // ------------------------------
  5972. #undef DPF_MODNAME
  5973. #define DPF_MODNAME "CEndpoint::SettingsDialogComplete"
  5974. void CEndpoint::SettingsDialogComplete( const HRESULT hDialogResult )
  5975. {
  5976. HRESULT hr;
  5977. IDirectPlay8Address *pBaseAddress;
  5978. WCHAR WCharHostName[ sizeof( m_TempHostName ) + 1 ];
  5979. DWORD dwWCharHostNameSize;
  5980. TCHAR *pPortString;
  5981. TCHAR *pLastPortChar;
  5982. DWORD dwPort;
  5983. DWORD dwNumPortSeparatorsFound;
  5984. #ifndef DPNBUILD_NOIPV6
  5985. BOOL fNonIPv6AddrCharFound;
  5986. #endif // ! DPNBUILD_NOIPV6
  5987. //
  5988. // initialize
  5989. //
  5990. hr = hDialogResult;
  5991. pBaseAddress = NULL;
  5992. pPortString = NULL;
  5993. dwPort = 0;
  5994. dwNumPortSeparatorsFound = 0;
  5995. #ifndef DPNBUILD_NOIPV6
  5996. fNonIPv6AddrCharFound = FALSE;
  5997. #endif // ! DPNBUILD_NOIPV6
  5998. //
  5999. // dialog failed, fail the user's command
  6000. //
  6001. if ( hr != DPN_OK )
  6002. {
  6003. if ( hr != DPNERR_USERCANCEL)
  6004. {
  6005. DPFX(DPFPREP, 0, "Failing endpoint hostname dialog for endpoint 0x%p!", this );
  6006. DisplayErrorCode( 0, hr );
  6007. }
  6008. else
  6009. {
  6010. DPFX(DPFPREP, 1, "Cancelling endpoint hostname dialog for endpoint 0x%p.", this );
  6011. }
  6012. goto Failure;
  6013. }
  6014. //
  6015. // The dialog completed OK, rebuild remote address and complete command
  6016. //
  6017. DPFX(DPFPREP, 1, "Dialog completed successfully, got host name \"%s\" for endpoint 0x%p.",
  6018. m_TempHostName, this);
  6019. //
  6020. // get the base DNADDRESS
  6021. //
  6022. pBaseAddress = m_pRemoteMachineAddress->DP8AddressFromSocketAddress( SP_ADDRESS_TYPE_HOST );
  6023. if ( pBaseAddress == NULL )
  6024. {
  6025. hr = DPNERR_OUTOFMEMORY;
  6026. DPFX(DPFPREP, 0, "SettingsDialogComplete: Failed to get base address when completing IP hostname dialog!" );
  6027. goto Failure;
  6028. }
  6029. //
  6030. // If there is a port separator in the string, replace it with a NULL
  6031. // to terminate the hostname and advance the port start index past the
  6032. // separator. Only indicate the presence of a port if the character
  6033. // following the port separator is numeric, except in the IPv6 case.
  6034. // IPv6 address can contain colons, too, so we will only remember the
  6035. // last colon we saw, and whether we found any characters that aren't
  6036. // allowed to be in an IPv6 address.
  6037. //
  6038. pPortString = m_TempHostName;
  6039. while ( *pPortString != 0 )
  6040. {
  6041. if (*pPortString == TEXT(':'))
  6042. {
  6043. pLastPortChar = pPortString;
  6044. dwNumPortSeparatorsFound++;
  6045. #ifdef DPNBUILD_NOIPV6
  6046. break;
  6047. #endif // DPNBUILD_NOIPV6
  6048. }
  6049. #ifndef DPNBUILD_NOIPV6
  6050. else
  6051. {
  6052. if ((*pPortString >= TEXT('0') && (*pPortString <= TEXT('9'))) ||
  6053. (*pPortString >= TEXT('a') && (*pPortString <= TEXT('f'))) ||
  6054. (*pPortString >= TEXT('A') && (*pPortString <= TEXT('F'))) ||
  6055. (*pPortString == TEXT('.'))) // the ':' character is covered above
  6056. {
  6057. //
  6058. // It's a valid IPv6 character.
  6059. //
  6060. }
  6061. else
  6062. {
  6063. fNonIPv6AddrCharFound = TRUE;
  6064. }
  6065. }
  6066. #endif // ! DPNBUILD_NOIPV6
  6067. pPortString = CharNext( pPortString );
  6068. }
  6069. //
  6070. // If a port was found, attempt to convert it from text. If the resulting
  6071. // port is zero, treat as if the port wasn't found.
  6072. //
  6073. if ( dwNumPortSeparatorsFound > 0 )
  6074. {
  6075. //
  6076. // IPv6 addresses must have at least 2 colons, and can only contain
  6077. // a specific set of characters. But if we met that criteria, we can't
  6078. // tell whether a port was specified or not. We will have to assume
  6079. // it was not.
  6080. //
  6081. #ifndef DPNBUILD_NOIPV6
  6082. if ((dwNumPortSeparatorsFound > 1) && (! fNonIPv6AddrCharFound))
  6083. {
  6084. DPFX(DPFPREP, 1, "Found %u port-separator and 0 invalid characters, assuming IPv6 address without a port.",
  6085. dwNumPortSeparatorsFound );
  6086. dwNumPortSeparatorsFound = 0;
  6087. }
  6088. else
  6089. #endif // ! DPNBUILD_NOIPV6
  6090. {
  6091. *pLastPortChar = 0; // terminate hostname string at separator character
  6092. pPortString = pLastPortChar + 1;
  6093. while ( *pPortString != 0 )
  6094. {
  6095. if ( ( *pPortString < TEXT('0') ) ||
  6096. ( *pPortString > TEXT('9') ) )
  6097. {
  6098. hr = DPNERR_ADDRESSING;
  6099. DPFX(DPFPREP, 0, "Invalid characters when parsing port from UI!" );
  6100. goto Failure;
  6101. }
  6102. dwPort *= 10;
  6103. dwPort += *pPortString - TEXT('0');
  6104. if ( dwPort > WORD_MAX )
  6105. {
  6106. hr = DPNERR_ADDRESSING;
  6107. DPFX(DPFPREP, 0, "Invalid value when parsing port from UI!" );
  6108. goto Failure;
  6109. }
  6110. pPortString = CharNext( pPortString );
  6111. }
  6112. DNASSERT( dwPort < WORD_MAX );
  6113. if ( dwPort == 0 )
  6114. {
  6115. dwNumPortSeparatorsFound = 0;
  6116. }
  6117. }
  6118. }
  6119. //
  6120. // Add the new 'HOSTNAME' parameter to the address. If the hostname is blank
  6121. // and this is an enum, copy the broadcast hostname. If the hostname is blank
  6122. // on a connect, fail!
  6123. //
  6124. if ( m_TempHostName[ 0 ] == 0 )
  6125. {
  6126. if ( GetType() == ENDPOINT_TYPE_ENUM )
  6127. {
  6128. //
  6129. // PREfast doesn't like unvalidated sizes for memcpys, so just double
  6130. // check that it's reasonable.
  6131. //
  6132. #ifndef DPNBUILD_NOIPV6
  6133. if (g_iIPAddressFamily == PF_INET6)
  6134. {
  6135. DBG_CASSERT((sizeof(WCharHostName) / sizeof(WCHAR)) >= INET6_ADDRSTRLEN);
  6136. DNIpv6AddressToStringW(&c_in6addrEnumMulticast, WCharHostName);
  6137. dwWCharHostNameSize = (wcslen(WCharHostName) + 1) * sizeof(WCHAR);
  6138. }
  6139. else
  6140. #endif // ! DPNBUILD_NOIPV6
  6141. {
  6142. if ( g_dwIPBroadcastAddressSize < sizeof( WCharHostName ) )
  6143. {
  6144. memcpy( WCharHostName, g_IPBroadcastAddress, g_dwIPBroadcastAddressSize );
  6145. dwWCharHostNameSize = g_dwIPBroadcastAddressSize;
  6146. }
  6147. else
  6148. {
  6149. DNASSERT( FALSE );
  6150. hr = DPNERR_GENERIC;
  6151. goto Failure;
  6152. }
  6153. }
  6154. }
  6155. else
  6156. {
  6157. hr = DPNERR_ADDRESSING;
  6158. DNASSERT( GetType() == ENDPOINT_TYPE_CONNECT );
  6159. DPFX(DPFPREP, 0, "No hostname in dialog!" );
  6160. goto Failure;
  6161. }
  6162. }
  6163. else
  6164. {
  6165. #ifdef UNICODE
  6166. dwWCharHostNameSize = (wcslen(m_TempHostName) + 1) * sizeof(WCHAR);
  6167. memcpy( WCharHostName, m_TempHostName, dwWCharHostNameSize );
  6168. #else
  6169. dwWCharHostNameSize = LENGTHOF( WCharHostName );
  6170. hr = STR_AnsiToWide( m_TempHostName, -1, WCharHostName, &dwWCharHostNameSize );
  6171. DNASSERT( hr == DPN_OK );
  6172. dwWCharHostNameSize *= sizeof( WCHAR );
  6173. #endif // UNICODE
  6174. }
  6175. hr = IDirectPlay8Address_AddComponent( pBaseAddress, DPNA_KEY_HOSTNAME, WCharHostName, dwWCharHostNameSize, DPNA_DATATYPE_STRING );
  6176. if ( hr != DPN_OK )
  6177. {
  6178. DPFX(DPFPREP, 0, "SettingsDialogComplete: Failed to add hostname to address!" );
  6179. goto Failure;
  6180. }
  6181. //
  6182. // if there was a specified port, add it to the address
  6183. //
  6184. if ( dwNumPortSeparatorsFound > 0 )
  6185. {
  6186. hr = IDirectPlay8Address_AddComponent( pBaseAddress,
  6187. DPNA_KEY_PORT,
  6188. &dwPort,
  6189. sizeof( dwPort ),
  6190. DPNA_DATATYPE_DWORD
  6191. );
  6192. if ( hr != DPN_OK )
  6193. {
  6194. DPFX(DPFPREP, 0, "Failed to add user specified port from the UI!" );
  6195. DisplayDNError( 0, hr );
  6196. goto Failure;
  6197. }
  6198. }
  6199. else
  6200. {
  6201. //
  6202. // There was no port specified. If this is a connect, then we don't
  6203. // have enough information (we can't try connecting to the DPNSVR
  6204. // port).
  6205. //
  6206. if ( GetType() == ENDPOINT_TYPE_CONNECT )
  6207. {
  6208. hr = DPNERR_ADDRESSING;
  6209. DPFX(DPFPREP, 0, "No port specified in dialog!" );
  6210. goto Failure;
  6211. }
  6212. else
  6213. {
  6214. DNASSERT( GetType() == ENDPOINT_TYPE_ENUM );
  6215. }
  6216. }
  6217. //
  6218. // set the address
  6219. //
  6220. hr = m_pRemoteMachineAddress->SocketAddressFromDP8Address( pBaseAddress,
  6221. #ifdef DPNBUILD_XNETSECURITY
  6222. NULL,
  6223. #endif // DPNBUILD_XNETSECURITY
  6224. #ifndef DPNBUILD_ONLYONETHREAD
  6225. TRUE,
  6226. #endif // DPNBUILD_ONLYONETHREAD
  6227. SP_ADDRESS_TYPE_HOST );
  6228. if ( hr != DPN_OK )
  6229. {
  6230. DPFX(DPFPREP, 0, "Failed to rebuild address when completing IP hostname dialog!" );
  6231. goto Failure;
  6232. }
  6233. //
  6234. // Make sure its valid and not banned.
  6235. //
  6236. if (! m_pRemoteMachineAddress->IsValidUnicastAddress((GetType() == ENDPOINT_TYPE_ENUM) ? TRUE : FALSE))
  6237. {
  6238. DPFX(DPFPREP, 0, "Host address is invalid!");
  6239. hr = DPNERR_INVALIDHOSTADDRESS;
  6240. goto Failure;
  6241. }
  6242. #ifndef DPNBUILD_NOREGISTRY
  6243. if (m_pRemoteMachineAddress->IsBannedAddress())
  6244. {
  6245. DPFX(DPFPREP, 0, "Host address is banned!");
  6246. hr = DPNERR_NOTALLOWED;
  6247. goto Failure;
  6248. }
  6249. #endif // ! DPNBUILD_NOREGISTRY
  6250. #ifndef DPNBUILD_NONATHELP
  6251. //
  6252. // Try to get NAT help loaded, if it isn't already and we're allowed.
  6253. //
  6254. if (GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE)
  6255. {
  6256. DPFX(DPFPREP, 7, "Ensuring that NAT help is loaded.");
  6257. m_pSPData->GetThreadPool()->EnsureNATHelpLoaded();
  6258. }
  6259. #endif // ! DPNBUILD_NONATHELP
  6260. AddRef();
  6261. //
  6262. // Since any asynchronous I/O posted on a thread is quit when the thread
  6263. // exits, it's necessary for the completion of this operation to happen
  6264. // on one of the thread pool threads.
  6265. //
  6266. switch ( GetType() )
  6267. {
  6268. case ENDPOINT_TYPE_ENUM:
  6269. {
  6270. #ifdef DPNBUILD_ONLYONEPROCESSOR
  6271. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::EnumQueryJobCallback,
  6272. this );
  6273. #else // ! DPNBUILD_ONLYONEPROCESSOR
  6274. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
  6275. CEndpoint::EnumQueryJobCallback,
  6276. this );
  6277. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  6278. if ( hr != DPN_OK )
  6279. {
  6280. DecRef();
  6281. DPFX(DPFPREP, 0, "Failed to set enum query!" );
  6282. DisplayDNError( 0, hr );
  6283. goto Failure;
  6284. }
  6285. break;
  6286. }
  6287. case ENDPOINT_TYPE_CONNECT:
  6288. {
  6289. #ifdef DPNBUILD_ONLYONEPROCESSOR
  6290. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::ConnectJobCallback,
  6291. this );
  6292. #else // ! DPNBUILD_ONLYONEPROCESSOR
  6293. hr = m_pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
  6294. CEndpoint::ConnectJobCallback,
  6295. this );
  6296. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  6297. if ( hr != DPN_OK )
  6298. {
  6299. DecRef();
  6300. DPFX(DPFPREP, 0, "Failed to set enum query!" );
  6301. DisplayDNError( 0, hr );
  6302. goto Failure;
  6303. }
  6304. break;
  6305. }
  6306. //
  6307. // unknown!
  6308. //
  6309. default:
  6310. {
  6311. DNASSERT( FALSE );
  6312. hr = DPNERR_GENERIC;
  6313. goto Failure;
  6314. break;
  6315. }
  6316. }
  6317. Exit:
  6318. //
  6319. // clear the handle to the dialog, it's the canceler's responsibility to clean up
  6320. // now (or we already have).
  6321. //
  6322. Lock();
  6323. SetActiveDialogHandle( NULL );
  6324. Unlock();
  6325. if ( pBaseAddress != NULL )
  6326. {
  6327. IDirectPlay8Address_Release( pBaseAddress );
  6328. pBaseAddress = NULL;
  6329. }
  6330. if ( pBaseAddress != NULL )
  6331. {
  6332. DNFree( pBaseAddress );
  6333. pBaseAddress = NULL;
  6334. }
  6335. DecRef();
  6336. return;
  6337. Failure:
  6338. //
  6339. // cleanup and close this endpoint
  6340. //
  6341. switch ( GetType() )
  6342. {
  6343. case ENDPOINT_TYPE_CONNECT:
  6344. {
  6345. CleanupConnect();
  6346. break;
  6347. }
  6348. case ENDPOINT_TYPE_ENUM:
  6349. {
  6350. CleanupEnumQuery();
  6351. break;
  6352. }
  6353. //
  6354. // other state (note that LISTEN doesn't have a dialog)
  6355. //
  6356. default:
  6357. {
  6358. DNASSERT( FALSE );
  6359. break;
  6360. }
  6361. }
  6362. //
  6363. // note that Close will attempt to close the window again
  6364. //
  6365. Close( hr );
  6366. m_pSPData->CloseEndpointHandle( this );
  6367. goto Exit;
  6368. }
  6369. //**********************************************************************
  6370. //**********************************************************************
  6371. // ------------------------------
  6372. // CEndpoint::StopSettingsDialog - stop an active settings dialog
  6373. //
  6374. // Entry: Handle of dialog to close
  6375. //
  6376. // Exit: Nothing
  6377. // ------------------------------
  6378. #undef DPF_MODNAME
  6379. #define DPF_MODNAME "CEndpoint::StopSettingsDialog"
  6380. void CEndpoint::StopSettingsDialog( const HWND hDlg)
  6381. {
  6382. StopIPHostNameSettingsDialog( hDlg );
  6383. }
  6384. //**********************************************************************
  6385. #endif // !DPNBUILD_NOSPUI
  6386. #ifdef DPNBUILD_ASYNCSPSENDS
  6387. //**********************************************************************
  6388. // ------------------------------
  6389. // CEndpoint::CompleteAsyncSend - async send completion callback
  6390. //
  6391. // Entry: Pointer to callback context
  6392. // Pointer to timer data
  6393. // Pointer to timer uniqueness value
  6394. //
  6395. // Exit: None
  6396. // ------------------------------
  6397. #undef DPF_MODNAME
  6398. #define DPF_MODNAME "CEndpoint::CompleteAsyncSend"
  6399. void CEndpoint::CompleteAsyncSend( void * const pvContext,
  6400. void * const pvTimerData,
  6401. const UINT uiTimerUnique )
  6402. {
  6403. HRESULT hr;
  6404. CCommandData * pCommand;
  6405. CEndpoint * pThisEndpoint;
  6406. //
  6407. // The context is the pointer to the command data.
  6408. //
  6409. pCommand = (CCommandData*) pvContext;
  6410. pThisEndpoint = pCommand->GetEndpoint();
  6411. DNASSERT(pThisEndpoint->IsValid());
  6412. #pragma TODO(vanceo, "Would be nice to print out result returned by Winsock")
  6413. DPFX(DPFPREP, 8, "Endpoint 0x%p completing command 0x%p (result = DPN_OK, user context = 0x%p) to interface 0x%p.",
  6414. pThisEndpoint, pCommand,
  6415. pCommand->GetUserContext(),
  6416. pThisEndpoint->m_pSPData->DP8SPCallbackInterface());
  6417. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blDPNWSockCritSecsHeld);
  6418. hr = IDP8SPCallback_CommandComplete( pThisEndpoint->m_pSPData->DP8SPCallbackInterface(), // pointer to callbacks
  6419. pCommand, // command handle
  6420. DPN_OK, // return
  6421. pCommand->GetUserContext() // user cookie
  6422. );
  6423. DPFX(DPFPREP, 8, "Endpoint 0x%p returning from command complete [0x%lx].", pThisEndpoint, hr);
  6424. pThisEndpoint->DecCommandRef();
  6425. pCommand->DecRef();
  6426. pCommand = NULL;
  6427. }
  6428. //**********************************************************************
  6429. #endif // DPNBUILD_ASYNCSPSENDS
  6430. #ifndef DPNBUILD_NOMULTICAST
  6431. //**********************************************************************
  6432. // ------------------------------
  6433. // CEndpoint::EnableMulticastReceive - Enables this endpoint for receiving multicast traffic
  6434. //
  6435. // Entry: Pointer to socketport
  6436. //
  6437. // Exit: HRESULT indicating success
  6438. // ------------------------------
  6439. #undef DPF_MODNAME
  6440. #define DPF_MODNAME "CEndpoint::EnableMulticastReceive"
  6441. HRESULT CEndpoint::EnableMulticastReceive( CSocketPort * const pSocketPort )
  6442. {
  6443. HRESULT hr;
  6444. #ifdef DBG
  6445. DWORD dwError;
  6446. #endif // DBG
  6447. const CSocketAddress * pSocketAddressDevice;
  6448. CSocketAddress * pSocketAddressRemote;
  6449. const SOCKADDR_IN * psaddrinDevice;
  6450. SOCKADDR_IN * psaddrinRemote;
  6451. int iSocketOption;
  6452. ip_mreq MulticastRequest;
  6453. #ifdef WINNT
  6454. PMCAST_SCOPE_ENTRY paScopes = NULL;
  6455. #endif // WINNT
  6456. DPFX(DPFPREP, 7, "(0x%p) Parameters: (0x%p)", this, pSocketPort);
  6457. DNASSERT(GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN);
  6458. //
  6459. // Get the socket port and socket addresses to be used.
  6460. //
  6461. DNASSERT(pSocketPort != NULL);
  6462. DNASSERT(pSocketPort->GetSocket() != INVALID_SOCKET);
  6463. pSocketAddressDevice = pSocketPort->GetNetworkAddress();
  6464. DNASSERT(pSocketAddressDevice != NULL);
  6465. DNASSERT(pSocketAddressDevice->GetFamily() == AF_INET);
  6466. psaddrinDevice = (const SOCKADDR_IN *) pSocketAddressDevice->GetAddress();
  6467. DNASSERT(psaddrinDevice->sin_addr.S_un.S_addr != INADDR_ANY);
  6468. DNASSERT(psaddrinDevice->sin_port != ANY_PORT);
  6469. pSocketAddressRemote = GetWritableRemoteAddressPointer();
  6470. DNASSERT(pSocketAddressRemote != NULL);
  6471. DNASSERT(pSocketAddressRemote->GetFamily() == AF_INET);
  6472. psaddrinRemote = (SOCKADDR_IN*) pSocketAddressRemote->GetWritableAddress();
  6473. //
  6474. // If we don't have a multicast IP address yet, select one.
  6475. //
  6476. if (psaddrinRemote->sin_addr.S_un.S_addr == INADDR_ANY)
  6477. {
  6478. #pragma TODO(vanceo, "Reinvestigate address selection randomness")
  6479. #define GLOBALSCOPE_MULTICAST_PREFIX 238
  6480. //
  6481. // Given the scope identifier the caller gave us (or the default local
  6482. // scope), use info for that built-in scope, or look for a MADCAP match
  6483. // and generate an appropriate address (if possible).
  6484. //
  6485. if (memcmp(&m_guidMulticastScope, &GUID_DP8MULTICASTSCOPE_GLOBAL, sizeof(m_guidMulticastScope)) == 0)
  6486. {
  6487. //
  6488. // We need to use a global scope address. We will use our
  6489. // arbitrary prefix that does not seem to collide with any IANA
  6490. // registered global addresses.
  6491. //
  6492. // We'll get a pseudo-random number to use for the remainder of the
  6493. // address by selecting part of the current time.
  6494. //
  6495. psaddrinRemote->sin_addr.S_un.S_addr = GETTIMESTAMP();
  6496. psaddrinRemote->sin_addr.S_un.S_un_b.s_b1 = GLOBALSCOPE_MULTICAST_PREFIX;
  6497. }
  6498. #ifdef WINNT
  6499. else if ((memcmp(&m_guidMulticastScope, &GUID_DP8MULTICASTSCOPE_PRIVATE, sizeof(m_guidMulticastScope)) == 0) ||
  6500. (memcmp(&m_guidMulticastScope, &GUID_DP8MULTICASTSCOPE_LOCAL, sizeof(m_guidMulticastScope)) == 0) ||
  6501. (! m_pSPData->GetThreadPool()->IsMadcapLoaded()))
  6502. #else // ! WINNT
  6503. else
  6504. #endif // ! WINNT
  6505. {
  6506. //
  6507. // We want to use a local scope address. The MADCAP spec
  6508. // recommends 239.255.0.0/16.
  6509. //
  6510. // We'll get a pseudo-random number to use for the remainder of the
  6511. // address by selecting part of the current time.
  6512. //
  6513. psaddrinRemote->sin_addr.S_un.S_un_w.s_w1 = 0xFFEF; // = FF EF = EF FF byte reversed = 239.255
  6514. psaddrinRemote->sin_addr.S_un.S_un_w.s_w2 = (WORD) GETTIMESTAMP();
  6515. }
  6516. #ifdef WINNT
  6517. else
  6518. {
  6519. #ifndef DBG
  6520. DWORD dwError;
  6521. #endif // ! DBG
  6522. DWORD dwScopesSize = 0;
  6523. DWORD dwNumScopeEntries;
  6524. DWORD dwTemp;
  6525. GUID guidComparison;
  6526. MCAST_LEASE_REQUEST McastLeaseRequest;
  6527. DWORD dwMADCAPRetryTime;
  6528. //
  6529. // Determine how much room we need to hold the list of scopes.
  6530. //
  6531. dwError = McastEnumerateScopes(pSocketAddressRemote->GetFamily(),
  6532. TRUE,
  6533. NULL,
  6534. &dwScopesSize,
  6535. &dwNumScopeEntries);
  6536. if ((dwError != ERROR_SUCCESS) && (dwError != ERROR_MORE_DATA))
  6537. {
  6538. DPFX(DPFPREP, 0, "Enumerating scopes for size required didn't return expected error (err = %u)!",
  6539. dwError);
  6540. hr = DPNERR_GENERIC;
  6541. goto Failure;
  6542. }
  6543. if (dwScopesSize < sizeof(MCAST_SCOPE_ENTRY))
  6544. {
  6545. DPFX(DPFPREP, 0, "Size required for scope buffer is invalid (%u < %u)!",
  6546. dwScopesSize, sizeof(MCAST_SCOPE_ENTRY));
  6547. hr = DPNERR_GENERIC;
  6548. goto Failure;
  6549. }
  6550. paScopes = (PMCAST_SCOPE_ENTRY) DNMalloc(dwScopesSize);
  6551. if (paScopes == NULL)
  6552. {
  6553. DPFX(DPFPREP, 0, "Couldn't allocate memory for scope list!");
  6554. hr = DPNERR_OUTOFMEMORY;
  6555. goto Failure;
  6556. }
  6557. //
  6558. // Retrieve the list of scopes.
  6559. //
  6560. dwError = McastEnumerateScopes(pSocketAddressRemote->GetFamily(),
  6561. FALSE,
  6562. paScopes,
  6563. &dwScopesSize,
  6564. &dwNumScopeEntries);
  6565. if (dwError != ERROR_SUCCESS)
  6566. {
  6567. DPFX(DPFPREP, 0, "Failed enumerating scopes (err = %u)!",
  6568. dwError);
  6569. hr = DPNERR_GENERIC;
  6570. goto Failure;
  6571. }
  6572. //
  6573. // Look for the scope we were given.
  6574. //
  6575. for(dwTemp = 0; dwTemp < dwNumScopeEntries; dwTemp++)
  6576. {
  6577. //
  6578. // Encrypt this scope context and TTL as a GUID for comparison.
  6579. //
  6580. #ifdef DPNBUILD_NOIPV6
  6581. CSocketAddress::CreateScopeGuid(&(paScopes[dwTemp].ScopeCtx),
  6582. #else // ! DPNBUILD_NOIPV6
  6583. CSocketAddress::CreateScopeGuid(pSocketAddressRemote->GetFamily(),
  6584. &(paScopes[dwTemp].ScopeCtx),
  6585. #endif // ! DPNBUILD_NOIPV6
  6586. (BYTE) (paScopes[dwTemp].TTL),
  6587. &guidComparison);
  6588. if (memcmp(&guidComparison, &m_guidMulticastScope, sizeof(m_guidMulticastScope)) == 0)
  6589. {
  6590. DPFX(DPFPREP, 3, "Found scope \"%ls - TTL %u\".",
  6591. paScopes[dwTemp].ScopeDesc.Buffer, paScopes[dwTemp].TTL);
  6592. break;
  6593. }
  6594. DPFX(DPFPREP, 7, "Didn't match scope \"%ls - TTL %u\".",
  6595. paScopes[dwTemp].ScopeDesc.Buffer, paScopes[dwTemp].TTL);
  6596. }
  6597. //
  6598. // If we didn't find the scope, then we will fail because we're
  6599. // not sure what the user wanted.
  6600. //
  6601. if (dwTemp >= dwNumScopeEntries)
  6602. {
  6603. DPFX(DPFPREP, 0, "Unrecognized scope GUID {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}!",
  6604. m_guidMulticastScope.Data1,
  6605. m_guidMulticastScope.Data2,
  6606. m_guidMulticastScope.Data3,
  6607. m_guidMulticastScope.Data4[0],
  6608. m_guidMulticastScope.Data4[1],
  6609. m_guidMulticastScope.Data4[2],
  6610. m_guidMulticastScope.Data4[3],
  6611. m_guidMulticastScope.Data4[4],
  6612. m_guidMulticastScope.Data4[5],
  6613. m_guidMulticastScope.Data4[6],
  6614. m_guidMulticastScope.Data4[7]);
  6615. hr = DPNERR_INVALIDHOSTADDRESS;
  6616. goto Failure;
  6617. }
  6618. //
  6619. // If we're here, then we found a MADCAP scope context to use.
  6620. // Request an address.
  6621. //
  6622. memset(&McastLeaseRequest, 0, sizeof(McastLeaseRequest));
  6623. //McastLeaseRequest.LeaseStartTime = 0; // have the lease start now
  6624. //McastLeaseRequest.MaxLeaseStartTime = McastLeaseRequest.LeaseStartTime;
  6625. McastLeaseRequest.LeaseDuration = MADCAP_LEASE_TIME;
  6626. McastLeaseRequest.MinLeaseDuration = McastLeaseRequest.LeaseDuration;
  6627. //McastLeaseRequest.ServerAddress = 0; // unknown at this time, leave set to 0
  6628. McastLeaseRequest.MinAddrCount = 1;
  6629. McastLeaseRequest.AddrCount = 1;
  6630. //McastLeaseRequest.pAddrBuf = NULL; // not requesting a specific address
  6631. memset(&m_McastLeaseResponse, 0, sizeof(m_McastLeaseResponse));
  6632. m_McastLeaseResponse.AddrCount = 1;
  6633. m_McastLeaseResponse.pAddrBuf = (PBYTE) (&psaddrinRemote->sin_addr.S_un.S_addr);
  6634. dwError = McastRequestAddress(pSocketAddressRemote->GetFamily(),
  6635. &g_mcClientUid,
  6636. &(paScopes[dwTemp].ScopeCtx),
  6637. &McastLeaseRequest,
  6638. &m_McastLeaseResponse);
  6639. if (dwError != ERROR_SUCCESS)
  6640. {
  6641. if (dwError == ERROR_ACCESS_DENIED)
  6642. {
  6643. DPFX(DPFPREP, 0, "Couldn't request multicast address, access was denied!");
  6644. hr = DPNERR_NOTALLOWED;
  6645. }
  6646. else
  6647. {
  6648. DPFX(DPFPREP, 0, "Failed requesting multicast addresses (err = %u)!",
  6649. dwError);
  6650. hr = DPNERR_GENERIC;
  6651. }
  6652. goto Failure;
  6653. }
  6654. if ((m_McastLeaseResponse.AddrCount != 1) || (psaddrinRemote->sin_addr.S_un.S_addr == INADDR_ANY))
  6655. {
  6656. DPFX(DPFPREP, 0, "McastRequestAddress didn't return valid response (addrcount = %u, address = %hs)!",
  6657. m_McastLeaseResponse.AddrCount, inet_ntoa(psaddrinRemote->sin_addr));
  6658. hr = DPNERR_GENERIC;
  6659. goto Failure;
  6660. }
  6661. //
  6662. // If we're here, we successfully leased a multicast address.
  6663. //
  6664. DNFree(paScopes);
  6665. paScopes = NULL;
  6666. //
  6667. // Kick off a timer to renew the lease when appropriate.
  6668. //
  6669. // Assume that LeaseStartTime is now, so we can easily calculate the lease duration.
  6670. DNASSERT(m_McastLeaseResponse.LeaseStartTime != 0);
  6671. DNASSERT(m_McastLeaseResponse.LeaseEndTime != 0);
  6672. DNASSERT((m_McastLeaseResponse.LeaseEndTime - m_McastLeaseResponse.LeaseStartTime) > 0);
  6673. dwMADCAPRetryTime = (m_McastLeaseResponse.LeaseEndTime - m_McastLeaseResponse.LeaseStartTime) * 1000;
  6674. DPFX(DPFPREP, 7, "Submitting MADCAP refresh timer (for every %u ms) for thread pool 0x%p.",
  6675. dwMADCAPRetryTime, m_pSPData->GetThreadPool());
  6676. DNASSERT(! m_fMADCAPTimerJobSubmitted);
  6677. m_fMADCAPTimerJobSubmitted = TRUE;
  6678. #ifdef DPNBUILD_ONLYONEPROCESSOR
  6679. hr = m_pSPData->GetThreadPool()->SubmitTimerJob(FALSE, // don't perform immediately
  6680. 1, // retry count
  6681. TRUE, // retry forever
  6682. dwMADCAPRetryTime, // retry timeout
  6683. TRUE, // wait forever
  6684. 0, // idle timeout
  6685. CEndpoint::MADCAPTimerFunction, // periodic callback function
  6686. CEndpoint::MADCAPTimerComplete, // completion function
  6687. this); // context
  6688. #else // ! DPNBUILD_ONLYONEPROCESSOR
  6689. DNASSERT(m_pSocketPort != NULL);
  6690. hr = m_pSPData->GetThreadPool()->SubmitTimerJob(m_pSocketPort->GetCPU(), // CPU
  6691. FALSE, // don't perform immediately
  6692. 1, // retry count
  6693. TRUE, // retry forever
  6694. dwMADCAPRetryTime, // retry timeout
  6695. TRUE, // wait forever
  6696. 0, // idle timeout
  6697. CEndpoint::MADCAPTimerFunction, // periodic callback function
  6698. CEndpoint::MADCAPTimerComplete, // completion function
  6699. this); // context
  6700. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  6701. if (hr != DPN_OK)
  6702. {
  6703. m_fMADCAPTimerJobSubmitted = FALSE;
  6704. DPFX(DPFPREP, 0, "Failed to submit timer job to watch over MADCAP lease!" );
  6705. //
  6706. // MADCAP will probably not work correctly, but that won't
  6707. // prevent us from still using that multicast address.
  6708. // Consider it non-fatal.
  6709. //
  6710. }
  6711. }
  6712. #endif // WINNT
  6713. }
  6714. //
  6715. // Nobody should have touched the port yet. It should just be a copy of
  6716. // the port bound on the network.
  6717. //
  6718. DNASSERT(psaddrinRemote->sin_port == ANY_PORT);
  6719. psaddrinRemote->sin_port = psaddrinDevice->sin_port;
  6720. //
  6721. // Since the IP multicast constants are different for Winsock1 vs. Winsock2,
  6722. // make sure we use the proper constant.
  6723. //
  6724. #ifdef DPNBUILD_ONLYWINSOCK2
  6725. iSocketOption = 12;
  6726. #else // ! DPNBUILD_ONLYWINSOCK2
  6727. #ifndef DPNBUILD_NOWINSOCK2
  6728. switch (GetWinsockVersion())
  6729. {
  6730. //
  6731. // Winsock1, use the IP_ADD_MEMBERSHIP value for Winsock1.
  6732. // See WINSOCK.H
  6733. //
  6734. case 1:
  6735. {
  6736. #endif // ! DPNBUILD_NOWINSOCK2
  6737. iSocketOption = 5;
  6738. #ifndef DPNBUILD_NOWINSOCK2
  6739. break;
  6740. }
  6741. //
  6742. // Winsock2, or greater, use the IP_ADD_MEMBERSHIP value for Winsock2.
  6743. // See WS2TCPIP.H
  6744. //
  6745. case 2:
  6746. default:
  6747. {
  6748. DNASSERT(GetWinsockVersion() == 2);
  6749. iSocketOption = 12;
  6750. break;
  6751. }
  6752. }
  6753. #endif // ! DPNBUILD_NOWINSOCK2
  6754. #endif // ! DPNBUILD_ONLYWINSOCK2
  6755. DPFX(DPFPREP, 3, "(0x%p) Socketport 0x%p joining IP multicast group:", this, pSocketPort);
  6756. DumpSocketAddress(3, pSocketAddressRemote->GetAddress(), pSocketAddressRemote->GetFamily());
  6757. //
  6758. // Copy the multicast address and interface address into the structure.
  6759. //
  6760. memcpy(&MulticastRequest.imr_interface,
  6761. &(psaddrinDevice->sin_addr),
  6762. sizeof(MulticastRequest.imr_interface));
  6763. memcpy(&MulticastRequest.imr_multiaddr,
  6764. &(psaddrinRemote->sin_addr),
  6765. sizeof(MulticastRequest.imr_multiaddr));
  6766. if (setsockopt(pSocketPort->GetSocket(), // socket
  6767. IPPROTO_IP, // option level (TCP/IP)
  6768. iSocketOption, // option (join multicast group)
  6769. (char*) (&MulticastRequest), // option data
  6770. sizeof(MulticastRequest)) != 0) // size of option data
  6771. {
  6772. #ifdef DBG
  6773. dwError = WSAGetLastError();
  6774. DPFX(DPFPREP, 0, "Failed to join IP multicast group (err = %u)!", dwError);
  6775. DisplayWinsockError(0, dwError);
  6776. #endif // DBG
  6777. hr = DPNERR_GENERIC;
  6778. goto Failure;
  6779. }
  6780. hr = DPN_OK;
  6781. Exit:
  6782. DPFX(DPFPREP, 7, "(0x%p) Return: [0x%lx]", this, hr);
  6783. return hr;
  6784. Failure:
  6785. #ifdef WINNT
  6786. if (paScopes != NULL)
  6787. {
  6788. DNFree(paScopes);
  6789. paScopes = NULL;
  6790. }
  6791. #endif // WINNT
  6792. goto Exit;
  6793. } // CEndpoint::EnableMulticastReceive
  6794. //**********************************************************************
  6795. //**********************************************************************
  6796. // ------------------------------
  6797. // CEndpoint::DisableMulticastReceive - Disables receiving multicast traffic for this endpoint
  6798. //
  6799. // Entry: Pointer to socketport
  6800. //
  6801. // Exit: HRESULT indicating success
  6802. // ------------------------------
  6803. #undef DPF_MODNAME
  6804. #define DPF_MODNAME "CEndpoint::DisableMulticastReceive"
  6805. HRESULT CEndpoint::DisableMulticastReceive( void )
  6806. {
  6807. HRESULT hr;
  6808. #ifdef DBG
  6809. DWORD dwError;
  6810. #endif // DBG
  6811. CSocketPort * pSocketPort;
  6812. const CSocketAddress * pSocketAddressRemote;
  6813. const CSocketAddress * pSocketAddressDevice;
  6814. const SOCKADDR_IN * psaddrinRemote;
  6815. const SOCKADDR_IN * psaddrinDevice;
  6816. int iSocketOption;
  6817. ip_mreq MulticastRequest;
  6818. DPFX(DPFPREP, 7, "(0x%p) Enter", this);
  6819. DNASSERT(GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN);
  6820. //
  6821. // Get the socket port and socket addresses to be used.
  6822. //
  6823. pSocketPort = GetSocketPort();
  6824. DNASSERT(pSocketPort != NULL);
  6825. DNASSERT(pSocketPort->GetSocket() != INVALID_SOCKET);
  6826. pSocketAddressDevice = pSocketPort->GetNetworkAddress();
  6827. DNASSERT(pSocketAddressDevice != NULL);
  6828. DNASSERT(pSocketAddressDevice->GetFamily() == AF_INET);
  6829. psaddrinDevice = (const SOCKADDR_IN *) pSocketAddressDevice->GetAddress();
  6830. DNASSERT(psaddrinDevice->sin_addr.S_un.S_addr != INADDR_ANY);
  6831. DNASSERT(psaddrinDevice->sin_port != ANY_PORT);
  6832. pSocketAddressRemote = GetRemoteAddressPointer();
  6833. DNASSERT(pSocketAddressRemote != NULL);
  6834. DNASSERT(pSocketAddressRemote->GetFamily() == AF_INET);
  6835. psaddrinRemote = (const SOCKADDR_IN *) pSocketAddressRemote->GetAddress();
  6836. DNASSERT(psaddrinRemote->sin_addr.S_un.S_addr != INADDR_ANY);
  6837. DNASSERT(psaddrinRemote->sin_port != ANY_PORT);
  6838. //
  6839. // Since the IP multicast constants are different for Winsock1 vs. Winsock2,
  6840. // make sure we use the proper constant.
  6841. //
  6842. #ifdef DPNBUILD_ONLYWINSOCK2
  6843. iSocketOption = 13;
  6844. #else // ! DPNBUILD_ONLYWINSOCK2
  6845. #ifndef DPNBUILD_NOWINSOCK2
  6846. switch (GetWinsockVersion())
  6847. {
  6848. //
  6849. // Winsock1, use the IP_DROP_MEMBERSHIP value for Winsock1.
  6850. // See WINSOCK.H
  6851. //
  6852. case 1:
  6853. {
  6854. #endif // ! DPNBUILD_NOWINSOCK2
  6855. iSocketOption = 6;
  6856. #ifndef DPNBUILD_NOWINSOCK2
  6857. break;
  6858. }
  6859. //
  6860. // Winsock2, or greater, use the IP_DROP_MEMBERSHIP value for Winsock2.
  6861. // See WS2TCPIP.H
  6862. //
  6863. case 2:
  6864. default:
  6865. {
  6866. DNASSERT(GetWinsockVersion() == 2);
  6867. iSocketOption = 13;
  6868. break;
  6869. }
  6870. }
  6871. #endif // ! DPNBUILD_NOWINSOCK2
  6872. #endif // ! DPNBUILD_ONLYWINSOCK2
  6873. DPFX(DPFPREP, 3, "(0x%p) Socketport 0x%p leaving IP multicast group:", this, pSocketPort);
  6874. DumpSocketAddress(3, pSocketAddressRemote->GetAddress(), pSocketAddressRemote->GetFamily());
  6875. //
  6876. // Copy the multicast address and interface address into the structure.
  6877. //
  6878. memcpy(&MulticastRequest.imr_interface,
  6879. &(psaddrinDevice->sin_addr),
  6880. sizeof(MulticastRequest.imr_interface));
  6881. memcpy(&MulticastRequest.imr_multiaddr,
  6882. &(psaddrinRemote->sin_addr),
  6883. sizeof(MulticastRequest.imr_multiaddr));
  6884. if (setsockopt(pSocketPort->GetSocket(), // socket
  6885. IPPROTO_IP, // option level (TCP/IP)
  6886. iSocketOption, // option (leave multicast group)
  6887. (char*) (&MulticastRequest), // option data
  6888. sizeof(MulticastRequest)) != 0) // size of option data
  6889. {
  6890. #ifdef DBG
  6891. dwError = WSAGetLastError();
  6892. DPFX(DPFPREP, 0, "Failed to leave IP multicast group (err = %u)!", dwError);
  6893. DisplayWinsockError(0, dwError);
  6894. #endif // DBG
  6895. hr = DPNERR_GENERIC;
  6896. goto Failure;
  6897. }
  6898. hr = DPN_OK;
  6899. Exit:
  6900. DPFX(DPFPREP, 7, "(0x%p) Return: [0x%lx]", this, hr);
  6901. return hr;
  6902. Failure:
  6903. goto Exit;
  6904. } // CEndpoint::DisableMulticastReceive
  6905. //**********************************************************************
  6906. #ifdef WINNT
  6907. //**********************************************************************
  6908. // ------------------------------
  6909. // CEndpoint::MADCAPTimerComplete - MADCAP timer job has completed
  6910. //
  6911. // Entry: Timer result code
  6912. // Context
  6913. //
  6914. // Exit: Nothing
  6915. // ------------------------------
  6916. #undef DPF_MODNAME
  6917. #define DPF_MODNAME "CEndpoint::MADCAPTimerComplete"
  6918. void CEndpoint::MADCAPTimerComplete( const HRESULT hResult, void * const pContext )
  6919. {
  6920. }
  6921. //**********************************************************************
  6922. //**********************************************************************
  6923. // ------------------------------
  6924. // CEndpoint::MADCAPTimerFunction - MADCAP timer job needs service
  6925. //
  6926. // Entry: Pointer to context
  6927. //
  6928. // Exit: Nothing
  6929. // ------------------------------
  6930. #undef DPF_MODNAME
  6931. #define DPF_MODNAME "CEndpoint::MADCAPTimerFunction"
  6932. void CEndpoint::MADCAPTimerFunction( void * const pContext )
  6933. {
  6934. CEndpoint * pThisEndpoint;
  6935. MCAST_LEASE_REQUEST McastLeaseRequest;
  6936. DWORD dwError;
  6937. DWORD dwNewRetryInterval;
  6938. DNASSERT( pContext != NULL );
  6939. pThisEndpoint = (CEndpoint*) pContext;
  6940. #pragma BUGBUG(vanceo, "Thread protection and delayed job a la NAT Help?")
  6941. memset(&McastLeaseRequest, 0, sizeof(McastLeaseRequest));
  6942. //McastLeaseRequest.LeaseStartTime = 0; // have the lease refresh right now
  6943. //McastLeaseRequest.MaxLeaseStartTime = McastLeaseRequest.LeaseStartTime;
  6944. McastLeaseRequest.LeaseDuration = MADCAP_LEASE_TIME;
  6945. McastLeaseRequest.MinLeaseDuration = McastLeaseRequest.LeaseDuration;
  6946. memcpy(&McastLeaseRequest.ServerAddress, &pThisEndpoint->m_McastLeaseResponse.ServerAddress, sizeof(McastLeaseRequest.ServerAddress));
  6947. McastLeaseRequest.MinAddrCount = 1;
  6948. McastLeaseRequest.AddrCount = 1;
  6949. McastLeaseRequest.pAddrBuf = pThisEndpoint->m_McastLeaseResponse.pAddrBuf;
  6950. dwError = McastRenewAddress(AF_INET,
  6951. &g_mcClientUid,
  6952. &McastLeaseRequest,
  6953. &pThisEndpoint->m_McastLeaseResponse);
  6954. if (dwError == ERROR_SUCCESS)
  6955. {
  6956. #pragma BUGBUG(vanceo, "Verify that start time is now instead of when we originally leased it")
  6957. //
  6958. // Tweak the timer interval to reflect a possible change in the
  6959. // lease duration.
  6960. //
  6961. // As before, assume that LeaseStartTime is now, so we can
  6962. // easily calculate the lease duration.
  6963. //
  6964. DNASSERT(pThisEndpoint->m_McastLeaseResponse.LeaseStartTime != 0);
  6965. DNASSERT(pThisEndpoint->m_McastLeaseResponse.LeaseEndTime != 0);
  6966. DNASSERT((pThisEndpoint->m_McastLeaseResponse.LeaseEndTime - pThisEndpoint->m_McastLeaseResponse.LeaseStartTime) > 0);
  6967. dwNewRetryInterval = (pThisEndpoint->m_McastLeaseResponse.LeaseEndTime - pThisEndpoint->m_McastLeaseResponse.LeaseStartTime) * 1000;
  6968. DPFX(DPFPREP, 7, "Updating MADCAP refresh timer (for every %u ms) for endpoint 0x%p.",
  6969. dwNewRetryInterval, pThisEndpoint);
  6970. #pragma BUGBUG(vanceo, "Update MADCAP refresh timer")
  6971. }
  6972. else
  6973. {
  6974. DPFX(DPFPREP, 0, "Failed renewing multicast addresses (err = %u)! Ignoring.",
  6975. dwError);
  6976. //
  6977. // Since we can't fail directly, just ignore the error. We'll
  6978. // try refreshing again after the next interval (although that
  6979. // will probably fail, too). In the meantime, we can continue
  6980. // using the address just fine, we simply won't "own" it.
  6981. //
  6982. }
  6983. }
  6984. //**********************************************************************
  6985. #endif // WINNT
  6986. #endif // ! DPNBUILD_NOMULTICAST