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.

2413 lines
70 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: SPData.cpp
  6. * Content: Global variables for the DNSerial service provider in class
  7. * format.
  8. *
  9. *
  10. * History:
  11. * Date By Reason
  12. * ==== == ======
  13. * 03/15/99 jtk Dereived from Locals.cpp
  14. * 01/10/2000 rmt Updated to build with Millennium build process
  15. * 03/22/2000 jtk Updated with changes to interface names
  16. ***************************************************************************/
  17. #include "dnwsocki.h"
  18. //**********************************************************************
  19. // Constant definitions
  20. //**********************************************************************
  21. //**********************************************************************
  22. // Macro definitions
  23. //**********************************************************************
  24. //**********************************************************************
  25. // Structure definitions
  26. //**********************************************************************
  27. //**********************************************************************
  28. // Variable definitions
  29. //**********************************************************************
  30. //**********************************************************************
  31. // Function prototypes
  32. //**********************************************************************
  33. //**********************************************************************
  34. // Function definitions
  35. //**********************************************************************
  36. //**********************************************************************
  37. // ------------------------------
  38. // CSPData::Initialize - initialize
  39. //
  40. // Entry: SP type
  41. // Pointer to SP COM vtable
  42. //
  43. // Exit: Error code
  44. //
  45. // Note: This function assumes that someone else is preventing reentry!
  46. // ------------------------------
  47. #undef DPF_MODNAME
  48. #define DPF_MODNAME "CSPData::Initialize"
  49. HRESULT CSPData::Initialize(
  50. IDP8ServiceProviderVtbl *const pVtbl
  51. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  52. ,const short sSPType
  53. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  54. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  55. ,const XDP8CREATE_PARAMS * const pDP8CreateParams
  56. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  57. )
  58. {
  59. HRESULT hr;
  60. BOOL fLockInitialized;
  61. #ifndef DPNBUILD_LIBINTERFACE
  62. BOOL fWinsockLoaded;
  63. #endif // ! DPNBUILD_LIBINTERFACE
  64. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  65. DWORD dwNumToAllocate;
  66. DWORD dwAllocated;
  67. READ_IO_DATA_POOL_CONTEXT ReadIODataPoolContext;
  68. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  69. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  70. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  71. DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p, 0x%p)", this, pVtbl, pDP8CreateParams);
  72. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  73. DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p, %u, 0x%p)", this, pVtbl, sSPType, pDP8CreateParams);
  74. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  75. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  76. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  77. DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p)", this, pVtbl);
  78. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  79. DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p, %u)", this, pVtbl, sSPType);
  80. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  81. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  82. DNASSERT( pVtbl != NULL );
  83. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  84. DNASSERT( pDP8CreateParams != NULL );
  85. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  86. //
  87. // initialize
  88. //
  89. hr = DPN_OK;
  90. #ifndef DPNBUILD_LIBINTERFACE
  91. fWinsockLoaded = FALSE;
  92. #endif // ! DPNBUILD_LIBINTERFACE
  93. fLockInitialized = FALSE;
  94. m_lRefCount = 0;
  95. m_lObjectRefCount = 0;
  96. m_hShutdownEvent = NULL;
  97. m_SPState = SPSTATE_UNINITIALIZED;
  98. m_pThreadPool = NULL;
  99. m_pSocketData = NULL;
  100. m_Sig[0] = 'S';
  101. m_Sig[1] = 'P';
  102. m_Sig[2] = 'D';
  103. m_Sig[3] = 'T';
  104. memset( &m_InitData, 0x00, sizeof( m_InitData ) );
  105. memset( &m_COMInterface, 0x00, sizeof( m_COMInterface ) );
  106. #ifndef DPNBUILD_LIBINTERFACE
  107. DNInterlockedIncrement( const_cast<LONG*>(&g_lOutstandingInterfaceCount) );
  108. #endif // ! DPNBUILD_LIBINTERFACE
  109. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  110. m_sSPType = sSPType;
  111. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  112. DNASSERT( m_COMInterface.m_pCOMVtbl == NULL );
  113. m_COMInterface.m_pCOMVtbl = pVtbl;
  114. #ifndef DPNBUILD_LIBINTERFACE
  115. //
  116. // Attempt to load Winsock.
  117. //
  118. if ( LoadWinsock() == FALSE )
  119. {
  120. DPFX(DPFPREP, 0, "Failed to load winsock!" );
  121. hr = DPNERR_OUTOFMEMORY;
  122. goto Failure;
  123. }
  124. fWinsockLoaded = TRUE;
  125. #endif // ! DPNBUILD_LIBINTERFACE
  126. //
  127. // initialize internal critical sections
  128. //
  129. if ( DNInitializeCriticalSection( &m_Lock ) == FALSE )
  130. {
  131. hr = DPNERR_OUTOFMEMORY;
  132. DPFX(DPFPREP, 0, "Problem initializing main critical section!" );
  133. goto Failure;
  134. }
  135. DebugSetCriticalSectionRecursionCount( &m_Lock, 0 );
  136. DebugSetCriticalSectionGroup( &m_Lock, &g_blDPNWSockCritSecsHeld ); // separate dpnwsock CSes from the rest of DPlay's CSes
  137. fLockInitialized = TRUE;
  138. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  139. //
  140. // Pre-allocate a socket data object.
  141. //
  142. dwNumToAllocate = 1;
  143. dwAllocated = g_SocketDataPool.Preallocate(dwNumToAllocate, NULL);
  144. if (dwAllocated < dwNumToAllocate)
  145. {
  146. DPFX(DPFPREP, 0, "Only allocated %u of %u requested socket data objects!",
  147. dwAllocated, dwNumToAllocate);
  148. hr = DPNERR_OUTOFMEMORY;
  149. goto Failure;
  150. }
  151. //
  152. // Allocate a couple addresses for each remote player (one for
  153. // each receive plus one for the endpoint), and an address for
  154. // a local listen endpoint.
  155. // Also allocate an address per command since we frequently
  156. // use temporary addresses (see below).
  157. // And finally, include addresses for the pending receives (see
  158. // below).
  159. //
  160. DNASSERT(pDP8CreateParams->dwMaxNumPlayers > 0);
  161. dwNumToAllocate = (pDP8CreateParams->dwMaxNumPlayers - 1)
  162. * (pDP8CreateParams->dwMaxReceivesPerPlayer + 1)
  163. + 1;
  164. dwNumToAllocate += pDP8CreateParams->dwMaxNumPlayers
  165. + pDP8CreateParams->dwNumSimultaneousEnumHosts;
  166. #pragma TODO(vanceo, "This represents outstanding receives; on multi-proc machines this would be multiplied by # CPUs")
  167. dwNumToAllocate += 1;
  168. dwNumToAllocate++; // include one to cover a receive that's being processed
  169. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  170. dwAllocated = g_SocketAddressPool.Preallocate(dwNumToAllocate, NULL);
  171. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  172. dwAllocated = g_SocketAddressPool.Preallocate(dwNumToAllocate, ((PVOID) ((DWORD_PTR) GetType())));
  173. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  174. if (dwAllocated < dwNumToAllocate)
  175. {
  176. DPFX(DPFPREP, 0, "Only allocated %u of %u requested socket addresses!",
  177. dwAllocated, dwNumToAllocate);
  178. hr = DPNERR_OUTOFMEMORY;
  179. goto Failure;
  180. }
  181. //
  182. // Pre-allocate one socketport.
  183. //
  184. dwNumToAllocate = 1;
  185. dwAllocated = g_SocketPortPool.Preallocate(dwNumToAllocate, (PVOID) pDP8CreateParams);
  186. if (dwAllocated < dwNumToAllocate)
  187. {
  188. DPFX(DPFPREP, 0, "Only allocated %u of %u requested socket ports!",
  189. dwAllocated, dwNumToAllocate);
  190. hr = DPNERR_OUTOFMEMORY;
  191. goto Failure;
  192. }
  193. //
  194. // Allocate an endpoint for each remote player, plus one for a
  195. // listen endpoint. If more simultaneous enums are expected than
  196. // remote players, use that instead, and allow for the connect to
  197. // be bound while the enumerations are still running.
  198. //
  199. dwNumToAllocate = pDP8CreateParams->dwMaxNumPlayers;
  200. if (dwNumToAllocate <= pDP8CreateParams->dwNumSimultaneousEnumHosts)
  201. {
  202. dwNumToAllocate = pDP8CreateParams->dwNumSimultaneousEnumHosts + 1;
  203. }
  204. dwAllocated = g_EndpointPool.Preallocate(dwNumToAllocate, this);
  205. if (dwAllocated < dwNumToAllocate)
  206. {
  207. DPFX(DPFPREP, 0, "Only allocated %u of %u requested endpoints!",
  208. dwAllocated, dwNumToAllocate);
  209. hr = DPNERR_OUTOFMEMORY;
  210. goto Failure;
  211. }
  212. //
  213. // Set the handle table size to hold all the endpoints.
  214. //
  215. hr = m_HandleTable.SetTableSize(dwNumToAllocate);
  216. if (hr != DPN_OK)
  217. {
  218. DPFX(DPFPREP, 0, "Couldn't set handle table size to %u entries!",
  219. dwNumToAllocate);
  220. goto Failure;
  221. }
  222. //
  223. // Allocate a command for connects to each remote player, plus
  224. // one for a listen endpoint.
  225. // Add in one for each enum host operation.
  226. //
  227. dwNumToAllocate = pDP8CreateParams->dwMaxNumPlayers;
  228. dwNumToAllocate += pDP8CreateParams->dwNumSimultaneousEnumHosts;
  229. dwAllocated = g_CommandDataPool.Preallocate(dwNumToAllocate, NULL);
  230. if (dwAllocated < dwNumToAllocate)
  231. {
  232. DPFX(DPFPREP, 0, "Only allocated %u of %u command data objects!",
  233. dwAllocated, dwNumToAllocate);
  234. hr = DPNERR_OUTOFMEMORY;
  235. goto Failure;
  236. }
  237. //
  238. // Allocate an endpoint command parameter object for each command.
  239. //
  240. dwAllocated = g_EndpointCommandParametersPool.Preallocate(dwNumToAllocate, NULL);
  241. if (dwAllocated < dwNumToAllocate)
  242. {
  243. DPFX(DPFPREP, 0, "Only allocated %u of %u endpoint command parameter objects!",
  244. dwAllocated, dwNumToAllocate);
  245. hr = DPNERR_OUTOFMEMORY;
  246. goto Failure;
  247. }
  248. //
  249. // Pre-allocate two address objects for each command to support the
  250. // address info indications.
  251. //
  252. hr = DNAddress_PreallocateInterfaces(dwNumToAllocate);
  253. if (hr != DPN_OK)
  254. {
  255. DPFX(DPFPREP, 0, "Couldn't pre-allocate %u address objects!",
  256. dwNumToAllocate);
  257. goto Failure;
  258. }
  259. #pragma TODO(vanceo, "This is located in DN_PopulateCorePools because m_pThreadPool isn't set at this point")
  260. /*
  261. //
  262. // Pre-allocate per-CPU items for the threadpool. We want:
  263. // + one work item for each command
  264. // + one timer per enum hosts operation
  265. // + one I/O operation per simultaneous read
  266. //
  267. #ifdef DPNBUILD_ONLYONEPROCESSOR
  268. hr = IDirectPlay8ThreadPoolWork_Preallocate(m_pThreadPool->GetDPThreadPoolWork(),
  269. dwNumToAllocate,
  270. pDP8CreateParams->dwNumSimultaneousEnumHosts,
  271. 1,
  272. 0);
  273. if (hr != DPN_OK)
  274. {
  275. DPFX(DPFPREP, 0, "Couldn't pre-allocate %u work items, %u timers, or 1 I/O operation!",
  276. dwNumToAllocate,
  277. pDP8CreateParams->dwNumSimultaneousEnumHosts);
  278. goto Failure;
  279. }
  280. #else // ! DPNBUILD_ONLYONEPROCESSOR
  281. #pragma TODO(vanceo, "This would be multiplied by number of CPUs")
  282. hr = IDirectPlay8ThreadPoolWork_Preallocate(m_pThreadPool->GetDPThreadPoolWork(),
  283. dwNumToAllocate,
  284. pDP8CreateParams->dwNumSimultaneousEnumHosts,
  285. 1,
  286. 0);
  287. if (hr != DPN_OK)
  288. {
  289. DPFX(DPFPREP, 0, "Couldn't pre-allocate %u work items, %u timers, or %u I/O operations!",
  290. dwNumToAllocate,
  291. pDP8CreateParams->dwNumSimultaneousEnumHosts,
  292. 1);
  293. goto Failure;
  294. }
  295. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  296. */
  297. //
  298. // Allocate a timer entry for each enum command.
  299. //
  300. dwNumToAllocate = pDP8CreateParams->dwNumSimultaneousEnumHosts;
  301. dwAllocated = g_TimerEntryPool.Preallocate(dwNumToAllocate, NULL);
  302. if (dwAllocated < dwNumToAllocate)
  303. {
  304. DPFX(DPFPREP, 0, "Only allocated %u of %u timer entries!",
  305. dwAllocated, dwNumToAllocate);
  306. hr = DPNERR_OUTOFMEMORY;
  307. goto Failure;
  308. }
  309. //
  310. // Allocate the desired number of receives.
  311. // Include extras for the outstanding receives that haven't been
  312. // completed by Winsock.
  313. // See socket address preallocation above.
  314. //
  315. ReadIODataPoolContext.pThreadPool = NULL;
  316. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  317. ReadIODataPoolContext.sSPType = GetType();
  318. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  319. #ifndef DPNBUILD_ONLYONEPROCESSOR
  320. ReadIODataPoolContext.dwCPU = -1; // unknown right now
  321. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  322. dwNumToAllocate = (pDP8CreateParams->dwMaxNumPlayers - 1)
  323. * pDP8CreateParams->dwMaxReceivesPerPlayer;
  324. #pragma TODO(vanceo, "This would be multiplied by number of CPUs on multiproc machines")
  325. dwNumToAllocate += 1;
  326. dwNumToAllocate++; // include one to cover a receive that's being processed
  327. dwAllocated = g_ReadIODataPool.Preallocate(dwNumToAllocate,
  328. &ReadIODataPoolContext);
  329. if (dwAllocated < dwNumToAllocate)
  330. {
  331. DPFX(DPFPREP, 0, "Only allocated %u of %u read I/O data buffers!",
  332. dwAllocated, dwNumToAllocate);
  333. hr = DPNERR_OUTOFMEMORY;
  334. goto Failure;
  335. }
  336. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  337. Exit:
  338. DPFX(DPFPREP, 4, "(0x%p) Return [0x%lx]", this, hr);
  339. return hr;
  340. Failure:
  341. if ( fLockInitialized != FALSE )
  342. {
  343. DNDeleteCriticalSection( &m_Lock );
  344. fLockInitialized = FALSE;
  345. }
  346. #ifndef DPNBUILD_LIBINTERFACE
  347. if ( fWinsockLoaded != FALSE )
  348. {
  349. UnloadWinsock();
  350. fWinsockLoaded = FALSE;
  351. }
  352. #endif // ! DPNBUILD_LIBINTERFACE
  353. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  354. m_sSPType = 0;
  355. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  356. goto Exit;
  357. }
  358. //**********************************************************************
  359. //**********************************************************************
  360. // ------------------------------
  361. // CSPData::Deinitialize - deinitialize
  362. //
  363. // Entry: Nothing
  364. //
  365. // Exit: Nothing
  366. //
  367. // Note: This function assumes that someone else is preventing reentry.
  368. // ------------------------------
  369. #undef DPF_MODNAME
  370. #define DPF_MODNAME "CSPData::Deinitialize"
  371. void CSPData::Deinitialize( void )
  372. {
  373. DPFX(DPFPREP, 4, "(0x%p) Enter", this );
  374. #ifndef DPNBUILD_LIBINTERFACE
  375. UnloadWinsock();
  376. #endif // ! DPNBUILD_LIBINTERFACE
  377. DNASSERT( m_pSocketData == NULL );
  378. DNDeleteCriticalSection( &m_Lock );
  379. SetState( SPSTATE_UNINITIALIZED );
  380. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  381. m_sSPType = 0;
  382. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  383. memset( &m_InitData, 0x00, sizeof( m_InitData ) );
  384. memset( &m_COMInterface, 0x00, sizeof( m_COMInterface ) );
  385. // The shutdown event and thread pool should have been closed in Shutdown.
  386. DNASSERT( m_hShutdownEvent == NULL );
  387. DNASSERT( GetThreadPool() == NULL );
  388. DNASSERT( m_lRefCount == 0 );
  389. DNASSERT( m_lObjectRefCount == 0 );
  390. DNASSERT( m_hShutdownEvent == NULL );
  391. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  392. DNASSERT( m_sSPType == 0 );
  393. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  394. DNASSERT( m_SPState == SPSTATE_UNINITIALIZED );
  395. DNASSERT( m_pThreadPool == NULL );
  396. #ifndef DPNBUILD_LIBINTERFACE
  397. DNInterlockedDecrement( const_cast<LONG*>(&g_lOutstandingInterfaceCount) );
  398. #endif // ! DPNBUILD_LIBINTERFACE
  399. DPFX(DPFPREP, 4, "(0x%p) Leave", this );
  400. }
  401. //**********************************************************************
  402. //**********************************************************************
  403. // ------------------------------
  404. // CSPData::Startup - start this set of SP data
  405. //
  406. // Entry: Pointer to initialization data
  407. //
  408. // Exit: Error
  409. // ------------------------------
  410. #undef DPF_MODNAME
  411. #define DPF_MODNAME "CSPData::Startup"
  412. HRESULT CSPData::Startup( SPINITIALIZEDATA *pInitializeData )
  413. {
  414. HRESULT hr;
  415. SOCKET TestSocket;
  416. BOOL fInterfaceGlobalsInitialized;
  417. #ifdef DBG
  418. #if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
  419. TCHAR * ptszSocketType;
  420. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  421. #endif // DBG
  422. DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pInitializeData);
  423. //
  424. // initialize
  425. //
  426. hr = DPN_OK;
  427. TestSocket = INVALID_SOCKET;
  428. fInterfaceGlobalsInitialized = FALSE;
  429. //
  430. // Before we get too far, check for the existance of this protocol by
  431. // attempting to create a socket.
  432. //
  433. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  434. TestSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );
  435. if ( TestSocket == INVALID_SOCKET )
  436. {
  437. DPFX(DPFPREP, 1, "Creating IPv4 socket failed, is that transport protocol installed?");
  438. hr = DPNERR_UNSUPPORTED;
  439. goto Failure;
  440. }
  441. DPFX(DPFPREP, 3, "Successfully created IPv4 socket.");
  442. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  443. switch (GetType())
  444. {
  445. #ifndef DPNBUILD_NOIPX
  446. case AF_IPX:
  447. {
  448. #ifdef DBG
  449. ptszSocketType = _T("IPX");
  450. #endif // DBG
  451. TestSocket = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  452. break;
  453. }
  454. #endif // ! DPNBUILD_NOIPX
  455. case AF_INET:
  456. {
  457. #ifdef DBG
  458. #ifdef DPNBUILD_NOIPV6
  459. ptszSocketType = _T("IPv4");
  460. #else // ! DPNBUILD_NOIPV6
  461. ptszSocketType = _T("IPv4 or IPv6");
  462. #endif // ! DPNBUILD_NOIPV6
  463. #endif // DBG
  464. DNASSERT(GetType() == AF_INET);
  465. TestSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );
  466. #ifndef DPNBUILD_NOIPV6
  467. if (TestSocket == INVALID_SOCKET )
  468. {
  469. TestSocket = socket( AF_INET6, SOCK_DGRAM, IPPROTO_IP );
  470. }
  471. #endif // ! DPNBUILD_NOIPV6
  472. break;
  473. }
  474. default:
  475. {
  476. DNASSERT(FALSE);
  477. break;
  478. }
  479. }
  480. if ( TestSocket == INVALID_SOCKET )
  481. {
  482. DPFX(DPFPREP, 1, "Creating %s socket failed, are the necessary transport protocols installed?",
  483. ptszSocketType);
  484. hr = DPNERR_UNSUPPORTED;
  485. goto Failure;
  486. }
  487. DPFX(DPFPREP, 3, "Successfully created %s socket.", ptszSocketType);
  488. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  489. closesocket( TestSocket );
  490. TestSocket = INVALID_SOCKET;
  491. //
  492. // attempt to initialize shutdown event
  493. //
  494. DNASSERT( m_hShutdownEvent == NULL );
  495. m_hShutdownEvent = DNCreateEvent( NULL, // pointer to security (none)
  496. TRUE, // manual reset
  497. TRUE, // start signalled (so close can be called without any endpoints being created)
  498. NULL // pointer to name (none)
  499. );
  500. if ( m_hShutdownEvent == NULL )
  501. {
  502. DWORD dwError;
  503. dwError = GetLastError();
  504. DPFX(DPFPREP, 0, "Failed to create event for shutting down spdata!" );
  505. DisplayErrorCode( 0, dwError );
  506. hr = DPNERR_OUTOFMEMORY;
  507. goto Failure;
  508. }
  509. //
  510. // get a thread pool
  511. //
  512. DNASSERT( m_pThreadPool == NULL );
  513. hr = InitializeInterfaceGlobals( this );
  514. if ( hr != DPN_OK )
  515. {
  516. DPFX(DPFPREP, 0, "Failed to create thread pool!" );
  517. DisplayDNError( 0, hr );
  518. goto Failure;
  519. }
  520. fInterfaceGlobalsInitialized = TRUE;
  521. //
  522. // remember our init data
  523. //
  524. DNASSERT( pInitializeData != NULL );
  525. DNASSERT( pInitializeData->dwFlags == SP_SESSION_TYPE_SERVER ||
  526. pInitializeData->dwFlags == SP_SESSION_TYPE_CLIENT ||
  527. pInitializeData->dwFlags == SP_SESSION_TYPE_PEER ||
  528. pInitializeData->dwFlags == 0);
  529. m_InitData.dwFlags = pInitializeData->dwFlags;
  530. DNASSERT( pInitializeData->pIDP != NULL );
  531. m_InitData.pIDP = pInitializeData->pIDP;
  532. //
  533. // Success from here on in
  534. //
  535. IDP8SPCallback_AddRef( DP8SPCallbackInterface() );
  536. SetState( SPSTATE_INITIALIZED );
  537. Exit:
  538. DPFX(DPFPREP, 2, "(0x%p) Return [0x%lx]", this, hr);
  539. return hr;
  540. Failure:
  541. if ( fInterfaceGlobalsInitialized != FALSE )
  542. {
  543. DeinitializeInterfaceGlobals( this );
  544. fInterfaceGlobalsInitialized = FALSE;
  545. }
  546. if ( m_hShutdownEvent != NULL )
  547. {
  548. DNCloseHandle( m_hShutdownEvent );
  549. m_hShutdownEvent = NULL;
  550. }
  551. goto Exit;
  552. }
  553. //**********************************************************************
  554. // ------------------------------
  555. // CSPData::Shutdown - shut down this set of SP data
  556. //
  557. // Entry: Nothing
  558. //
  559. // Exit: Nothing
  560. // ------------------------------
  561. #undef DPF_MODNAME
  562. #define DPF_MODNAME "CSPData::Shutdown"
  563. void CSPData::Shutdown( void )
  564. {
  565. HRESULT hr;
  566. DPFX(DPFPREP, 2, "(0x%p) Enter", this);
  567. //
  568. // Unbind this interface from the globals. This will cause a closure of all
  569. // of the I/O which will release endpoints, socket ports and then this data.
  570. //
  571. DNASSERT( GetThreadPool() != NULL );
  572. DeinitializeInterfaceGlobals( this );
  573. SetState( SPSTATE_CLOSING );
  574. //
  575. // Release the socket data, if we have any.
  576. //
  577. if ( m_pSocketData != NULL )
  578. {
  579. m_pSocketData->Release();
  580. m_pSocketData = NULL;
  581. }
  582. DNASSERT( m_hShutdownEvent != NULL );
  583. #ifdef DBG
  584. #ifndef DPNBUILD_ONLYONEADAPTER
  585. DebugPrintOutstandingAdapterEntries();
  586. #endif // ! DPNBUILD_ONLYONEADAPTER
  587. #endif // DBG
  588. DPFX(DPFPREP, 3, "(0x%p) Waiting for shutdown event 0x%p.",
  589. this, m_hShutdownEvent);
  590. hr = IDirectPlay8ThreadPoolWork_WaitWhileWorking(m_pThreadPool->GetDPThreadPoolWork(),
  591. HANDLE_FROM_DNHANDLE(m_hShutdownEvent),
  592. 0);
  593. if (hr != DPN_OK)
  594. {
  595. DPFX(DPFPREP, 0, "Failed to wait for shutdown event 0x%p (err = 0x%lx!",
  596. m_hShutdownEvent, hr );
  597. }
  598. if ( DNCloseHandle( m_hShutdownEvent ) == FALSE )
  599. {
  600. DWORD dwError;
  601. dwError = GetLastError();
  602. DPFX(DPFPREP, 0, "Failed to close shutdown event 0x%p!", m_hShutdownEvent );
  603. DisplayErrorCode( 0, dwError );
  604. }
  605. m_hShutdownEvent = NULL;
  606. DNASSERT( GetThreadPool() != NULL );
  607. GetThreadPool()->DecRef();
  608. SetThreadPool( NULL );
  609. if ( DP8SPCallbackInterface() != NULL)
  610. {
  611. IDP8SPCallback_Release( DP8SPCallbackInterface() );
  612. memset( &m_InitData, 0x00, sizeof( m_InitData ) );
  613. }
  614. DPFX(DPFPREP, 2, "(0x%p) Leave", this);
  615. }
  616. //**********************************************************************
  617. //**********************************************************************
  618. // ------------------------------
  619. // CSPData::BindEndpoint - bind an endpoint to a socket port
  620. //
  621. // Entry: Pointer to endpoint
  622. // Pointer to IDirectPlay8Address for socket port
  623. // Pointer to CSocketAddress for socket port
  624. // Gateway bind type
  625. //
  626. // Exit: Error code
  627. // ------------------------------
  628. #undef DPF_MODNAME
  629. #define DPF_MODNAME "CSPData::BindEndpoint"
  630. HRESULT CSPData::BindEndpoint( CEndpoint *const pEndpoint,
  631. IDirectPlay8Address *const pDeviceAddress,
  632. const CSocketAddress *const pSocketAddress,
  633. const GATEWAY_BIND_TYPE GatewayBindType )
  634. {
  635. HRESULT hr;
  636. CSocketAddress * pDeviceSocketAddress;
  637. CSocketData * pSocketData;
  638. CSocketPort * pSocketPort;
  639. BOOL fSocketCreated;
  640. BOOL fSocketDataLocked;
  641. #ifndef DPNBUILD_ONLYONEADAPTER
  642. BOOL fAdapterEntrySet;
  643. CAdapterEntry * pAdapterEntry;
  644. #endif // ! DPNBUILD_ONLYONEADAPTER
  645. BOOL fSocketPortInActiveList;
  646. BOOL fEndpointReferenceAdded;
  647. CBilink * pBilink;
  648. CBilink * pBilinkEndOfList;
  649. GATEWAY_BIND_TYPE NewGatewayBindType;
  650. #ifndef DPNBUILD_ONLYONEPROCESSOR
  651. DWORD dwCPU;
  652. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  653. #ifndef DPNBUILD_NOMULTICAST
  654. BYTE bMulticastTTL;
  655. #endif // ! DPNBUILD_NOMULTICAST
  656. #if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
  657. IDirectPlay8Address * pHostAddress;
  658. #endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
  659. DNASSERT( pEndpoint != NULL );
  660. DNASSERT( ( pDeviceAddress != NULL ) || ( pSocketAddress != NULL ) );
  661. DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%p, 0x%p, 0x%p, %i)",
  662. this, pEndpoint, pDeviceAddress, pSocketAddress, GatewayBindType);
  663. //
  664. // initialize
  665. //
  666. hr = DPN_OK;
  667. pDeviceSocketAddress = NULL;
  668. pSocketData = NULL;
  669. pSocketPort = NULL;
  670. fSocketCreated = FALSE;
  671. fSocketDataLocked = FALSE;
  672. #ifndef DPNBUILD_ONLYONEADAPTER
  673. fAdapterEntrySet = FALSE;
  674. pAdapterEntry = NULL;
  675. #endif // ! DPNBUILD_ONLYONEADAPTER
  676. fSocketPortInActiveList = FALSE;
  677. fEndpointReferenceAdded = FALSE;
  678. //
  679. // create and initialize a device address to be used for this socket port
  680. //
  681. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  682. pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
  683. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  684. pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) GetType()));
  685. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  686. if ( pDeviceSocketAddress == NULL )
  687. {
  688. hr = DPNERR_OUTOFMEMORY;
  689. DPFX(DPFPREP, 0, "Failed to allocate address for new socket port!" );
  690. goto Failure;
  691. }
  692. //
  693. // Initialize the socket address with the provided base addresses.
  694. //
  695. if ( pDeviceAddress != NULL )
  696. {
  697. #if ((! defined(DPNBUILD_ONLYONEADAPTER)) || (! defined(DPNBUILD_ONLYONEPROCESSOR)))
  698. DWORD dwComponentSize;
  699. DWORD dwComponentType;
  700. #endif // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONEPROCESSOR
  701. DNASSERT( pSocketAddress == NULL );
  702. hr = pDeviceSocketAddress->SocketAddressFromDP8Address( pDeviceAddress,
  703. #ifdef DPNBUILD_XNETSECURITY
  704. NULL,
  705. #endif // DPNBUILD_XNETSECURITY
  706. #ifndef DPNBUILD_ONLYONETHREAD
  707. FALSE,
  708. #endif // DPNBUILD_ONLYONETHREAD
  709. SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT );
  710. if ( hr != DPN_OK )
  711. {
  712. DPFX(DPFPREP, 0, "Failed to parse device address!" );
  713. DisplayDNError( 0, hr );
  714. goto Failure;
  715. }
  716. #ifndef DPNBUILD_ONLYONEADAPTER
  717. //
  718. // If the device gave a specific port, it's possible that the address has
  719. // our special "it's not actually a specific port" key (see
  720. // CSocketPort::GetDP8BoundNetworkAddress).
  721. //
  722. if ( pDeviceSocketAddress->GetPort() != ANY_PORT )
  723. {
  724. DWORD dwSocketPortID;
  725. dwComponentSize = sizeof(dwSocketPortID);
  726. dwComponentType = 0;
  727. hr = IDirectPlay8Address_GetComponentByName( pDeviceAddress, // interface
  728. DPNA_PRIVATEKEY_PORT_NOT_SPECIFIC, // tag
  729. &dwSocketPortID, // component buffer
  730. &dwComponentSize, // component size
  731. &dwComponentType // component type
  732. );
  733. if ( hr == DPN_OK )
  734. {
  735. //
  736. // We found the component. Make sure it's the right size and type.
  737. //
  738. if (( dwComponentSize == sizeof(dwSocketPortID) ) && ( dwComponentType == DPNA_DATATYPE_DWORD ))
  739. {
  740. DPFX(DPFPREP, 3, "Found correctly formed private port-not-specific key (socketport ID = %u), ignoring port %u.",
  741. dwSocketPortID, NTOHS(pDeviceSocketAddress->GetPort()) );
  742. pDeviceSocketAddress->SetPort( ANY_PORT ) ;
  743. }
  744. else
  745. {
  746. //
  747. // We are the only ones who should know about this key, so if it
  748. // got there without being formed correctly, either someone is
  749. // trying to imitate our address format, or it got corrupted.
  750. // We'll just ignore it.
  751. //
  752. DPFX(DPFPREP, 0, "Private port-not-specific key exists, but doesn't match expected type (%u != %u) or size (%u != %u), is someone trying to get cute with device address 0x%p?!",
  753. dwComponentSize, sizeof(dwSocketPortID),
  754. dwComponentType, DPNA_DATATYPE_DWORD,
  755. pDeviceAddress );
  756. }
  757. }
  758. else
  759. {
  760. //
  761. // The key is not there, it's the wrong size (too big for our buffer
  762. // and returned BUFFERTOOSMALL), or something else bad happened.
  763. // It doesn't matter. Carry on.
  764. //
  765. DPFX(DPFPREP, 8, "Could not get appropriate private port-not-specific key, error = 0x%lx, component size = %u, type = %u, continuing.",
  766. hr, dwComponentSize, dwComponentType);
  767. }
  768. }
  769. #endif // ! DPNBUILD_ONLYONEADAPTER
  770. #ifndef DPNBUILD_ONLYONEPROCESSOR
  771. //
  772. // Try to retrieve the CPU component, if any.
  773. //
  774. dwComponentSize = sizeof(dwCPU);
  775. dwComponentType = 0;
  776. hr = IDirectPlay8Address_GetComponentByName( pDeviceAddress, // interface
  777. DPNA_KEY_PROCESSOR, // tag
  778. &dwCPU, // component buffer
  779. &dwComponentSize, // component size
  780. &dwComponentType // component type
  781. );
  782. if ( hr == DPN_OK )
  783. {
  784. SYSTEM_INFO SystemInfo;
  785. //
  786. // We found the component. Make sure it's the right size and type.
  787. //
  788. if (( dwComponentSize != sizeof(dwCPU) ) || ( dwComponentType != DPNA_DATATYPE_DWORD ))
  789. {
  790. DPFX(DPFPREP, 0, "Processor address component exists, but doesn't match expected type (%u != %u) or size (%u != %u)!",
  791. dwComponentSize, sizeof(dwCPU),
  792. dwComponentType, DPNA_DATATYPE_DWORD );
  793. hr = DPNERR_INVALIDDEVICEADDRESS;
  794. goto Failure;
  795. }
  796. //
  797. // Make sure the processor is valid.
  798. //
  799. GetSystemInfo(&SystemInfo);
  800. if ((dwCPU != -1) && (dwCPU >= SystemInfo.dwNumberOfProcessors))
  801. {
  802. DPFX(DPFPREP, 0, "Processor address component exists, but is not valid (%i)!",
  803. dwCPU );
  804. hr = DPNERR_INVALIDDEVICEADDRESS;
  805. goto Failure;
  806. }
  807. if (dwCPU == -1)
  808. {
  809. DPFX(DPFPREP, 3, "Found correctly formed processor component, explicitly using any/all CPUs.");
  810. }
  811. else
  812. {
  813. DPFX(DPFPREP, 3, "Found correctly formed processor component, CPU = %i.",
  814. dwCPU );
  815. }
  816. }
  817. else
  818. {
  819. //
  820. // The key is not there, it's the wrong size (too big for our buffer
  821. // and returned BUFFERTOOSMALL), or something else bad happened.
  822. // It doesn't matter, we'll just use any/all processors.
  823. //
  824. DPFX(DPFPREP, 8, "Could not get processor address component, error = 0x%lx, component size = %u, type = %u, using any CPU.",
  825. hr, dwComponentSize, dwComponentType);
  826. dwCPU = -1;
  827. }
  828. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  829. }
  830. else
  831. {
  832. DNASSERT( pSocketAddress != NULL );
  833. pDeviceSocketAddress->CopyAddressSettings( pSocketAddress );
  834. #ifndef DPNBUILD_ONLYONEPROCESSOR
  835. //
  836. // Use any CPU.
  837. //
  838. dwCPU = -1;
  839. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  840. }
  841. #pragma BUGBUG(vanceo, "Find a way to organize and delay the munges (both here and in CSocketPort::BindEndpoint)")
  842. #ifndef DPNBUILD_NONATHELP
  843. //
  844. // Munge the public address into a local alias, if there is one for the given device.
  845. // It's OK for the device socket address to not have a port yet.
  846. //
  847. // Note that doing this causes all other multiplexed operations to use the munged
  848. // result from this first adapter because we indicate the modified address info,
  849. // not the original public address. The assumption is that the public address
  850. // must be globally reachable, so if we munge it here, we should be the only
  851. // adapter that can reach it locally, or if not, the other adapters should be able
  852. // to reach it using the same local address.
  853. //
  854. if ( pEndpoint->GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE )
  855. {
  856. switch ( pEndpoint->GetType() )
  857. {
  858. case ENDPOINT_TYPE_CONNECT:
  859. #ifndef DPNBUILD_NOMULTICAST
  860. case ENDPOINT_TYPE_MULTICAST_RECEIVE:
  861. #endif // ! DPNBUILD_NOMULTICAST
  862. {
  863. MungePublicAddress( pDeviceSocketAddress, pEndpoint->GetWritableRemoteAddressPointer(), FALSE );
  864. break;
  865. }
  866. case ENDPOINT_TYPE_ENUM:
  867. {
  868. MungePublicAddress( pDeviceSocketAddress, pEndpoint->GetWritableRemoteAddressPointer(), TRUE );
  869. break;
  870. }
  871. default:
  872. {
  873. break;
  874. }
  875. }
  876. }
  877. #endif // ! DPNBUILD_NONATHELP
  878. #ifndef DPNBUILD_NOIPV6
  879. //
  880. // Munge/convert the IPv4 broadcast address to the IPv6 multicast enum
  881. // address, and vice versa.
  882. //
  883. // Note that doing this causes all other multiplexed operations to use this first
  884. // adapter because we indicate the modified address info, not the original
  885. // broadcast address.
  886. //
  887. if ( pEndpoint->GetType() == ENDPOINT_TYPE_ENUM )
  888. {
  889. if ((pDeviceSocketAddress->GetFamily() == AF_INET6) &&
  890. (pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() == AF_INET) &&
  891. (((SOCKADDR_IN*) pEndpoint->GetWritableRemoteAddressPointer()->GetAddress())->sin_addr.S_un.S_addr == INADDR_BROADCAST))
  892. {
  893. SOCKADDR_IN6 saddrin6MulticastEnum;
  894. memset(&saddrin6MulticastEnum, 0, sizeof(saddrin6MulticastEnum));
  895. saddrin6MulticastEnum.sin6_family = AF_INET6;
  896. memcpy(&saddrin6MulticastEnum.sin6_addr, &c_in6addrEnumMulticast, sizeof(saddrin6MulticastEnum.sin6_addr));
  897. saddrin6MulticastEnum.sin6_port = pEndpoint->GetWritableRemoteAddressPointer()->GetPort();
  898. pEndpoint->GetWritableRemoteAddressPointer()->SetFamilyProtocolAndSize(AF_INET6);
  899. pEndpoint->GetWritableRemoteAddressPointer()->SetAddressFromSOCKADDR((SOCKADDR*) (&saddrin6MulticastEnum),
  900. sizeof(saddrin6MulticastEnum));
  901. DPFX(DPFPREP, 7, "Converting IPv4 broadcast address to IPv6 multicast enum address:");
  902. DumpSocketAddress( 7, pEndpoint->GetWritableRemoteAddressPointer()->GetAddress(), pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() );
  903. }
  904. else if ((pDeviceSocketAddress->GetFamily() == AF_INET) &&
  905. (pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() == AF_INET6) &&
  906. (IN6_ADDR_EQUAL(&(((SOCKADDR_IN6*) pEndpoint->GetWritableRemoteAddressPointer()->GetAddress())->sin6_addr), &c_in6addrEnumMulticast)))
  907. {
  908. SOCKADDR_IN saddrinBroadcast;
  909. memset(&saddrinBroadcast, 0, sizeof(saddrinBroadcast));
  910. saddrinBroadcast.sin_family = AF_INET;
  911. saddrinBroadcast.sin_addr.S_un.S_addr = INADDR_BROADCAST;
  912. saddrinBroadcast.sin_port = pEndpoint->GetWritableRemoteAddressPointer()->GetPort();
  913. pEndpoint->GetWritableRemoteAddressPointer()->SetFamilyProtocolAndSize(AF_INET);
  914. pEndpoint->GetWritableRemoteAddressPointer()->SetAddressFromSOCKADDR((SOCKADDR*) (&saddrinBroadcast),
  915. sizeof(saddrinBroadcast));
  916. DPFX(DPFPREP, 7, "Converting IPv6 multicast enum address to IPv4 broadcast address:");
  917. DumpSocketAddress( 7, pEndpoint->GetWritableRemoteAddressPointer()->GetAddress(), pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() );
  918. }
  919. }
  920. //
  921. // Mash in the appropriate IPv6 scope ID in case we don't have it.
  922. //
  923. if ((pDeviceSocketAddress->GetFamily() == AF_INET6) &&
  924. (pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() == AF_INET6))
  925. {
  926. SOCKADDR_IN6 * psaddrin6Device;
  927. SOCKADDR_IN6 * psaddrin6Remote;
  928. psaddrin6Device = (SOCKADDR_IN6*) (pDeviceSocketAddress->GetAddress());
  929. psaddrin6Remote = (SOCKADDR_IN6*) (pEndpoint->GetWritableRemoteAddressPointer()->GetAddress());
  930. psaddrin6Remote->sin6_scope_id = psaddrin6Device->sin6_scope_id;
  931. }
  932. #endif // ! DPNBUILD_NOIPV6
  933. #ifndef DPNBUILD_NOMULTICAST
  934. //
  935. // If this is a multicast send endpoint, figure out what TTL we will
  936. // be using.
  937. //
  938. if ( pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND )
  939. {
  940. GUID guidScope;
  941. pEndpoint->GetScopeGuid( &guidScope );
  942. if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_PRIVATE, sizeof(guidScope) ) == 0 )
  943. {
  944. bMulticastTTL = MULTICAST_TTL_PRIVATE;
  945. }
  946. else if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_LOCAL, sizeof(guidScope) ) == 0 )
  947. {
  948. bMulticastTTL = MULTICAST_TTL_LOCAL;
  949. }
  950. else if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_GLOBAL, sizeof(guidScope) ) == 0 )
  951. {
  952. bMulticastTTL = MULTICAST_TTL_GLOBAL;
  953. }
  954. else
  955. {
  956. //
  957. // Assume it's a valid MADCAP scope. Even on non-NT platforms
  958. // where we don't know about MADCAP, we can still parse out the
  959. // TTL value.
  960. //
  961. bMulticastTTL = CSocketAddress::GetScopeGuidTTL( &guidScope );
  962. }
  963. }
  964. #endif // ! DPNBUILD_NOMULTICAST
  965. //
  966. // Get the socket port data. This shouldn't fail, because in order to have
  967. // an open endpoint, we must have created the socket data.
  968. //
  969. pSocketData = GetSocketDataRef();
  970. if (pSocketData == NULL)
  971. {
  972. DNASSERT(! "Couldn't retrieve socket data!");
  973. hr = DPNERR_OUTOFMEMORY;
  974. goto Failure;
  975. }
  976. pSocketData->Lock();
  977. fSocketDataLocked = TRUE;
  978. #ifndef DPNBUILD_ONLYONEADAPTER
  979. //
  980. // Find the base adapter entry for this network address. If none is found,
  981. // create a new one. If a new one cannot be created, fail.
  982. //
  983. pBilink = pSocketData->GetAdapters()->GetNext();
  984. while ( pBilink != pSocketData->GetAdapters() )
  985. {
  986. CAdapterEntry *pTempAdapterEntry;
  987. pTempAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pBilink );
  988. if ( pDeviceSocketAddress->CompareToBaseAddress( pTempAdapterEntry->BaseAddress() ) == 0 )
  989. {
  990. DPFX(DPFPREP, 5, "Found adapter for network address (0x%p).", pTempAdapterEntry );
  991. DNASSERT( pAdapterEntry == NULL );
  992. pTempAdapterEntry->AddRef();
  993. pAdapterEntry = pTempAdapterEntry;
  994. }
  995. pBilink = pBilink->GetNext();
  996. }
  997. if ( pAdapterEntry == NULL )
  998. {
  999. pAdapterEntry = (CAdapterEntry*)g_AdapterEntryPool.Get();
  1000. if ( pAdapterEntry == NULL )
  1001. {
  1002. hr = DPNERR_OUTOFMEMORY;
  1003. DPFX(DPFPREP, 0, "Failed to create a new adapter entry!" );
  1004. goto Failure;
  1005. }
  1006. pAdapterEntry->SetBaseAddress( pDeviceSocketAddress->GetAddress(), pDeviceSocketAddress->GetAddressSize() );
  1007. pAdapterEntry->AddToAdapterList( pSocketData->GetAdapters() );
  1008. }
  1009. #endif // ! DPNBUILD_ONLYONEADAPTER
  1010. //
  1011. // At this point we have a reference to an adapter entry that's also in
  1012. // m_ActiveAdapterList (which has a reference, too).
  1013. //
  1014. //
  1015. // if a specific port is not needed, check the list of active adapters for a matching
  1016. // base address and reuse that CSocketPort.
  1017. //
  1018. if ( pDeviceSocketAddress->GetPort() == ANY_PORT )
  1019. {
  1020. DPFX(DPFPREP, 8, "Device socket address 0x%p not mapped to a specific port, gateway bind type = %u.",
  1021. pDeviceSocketAddress, GatewayBindType);
  1022. //
  1023. // Convert the preliminary bind type to a real one, based on the fact that
  1024. // the caller allowed any port.
  1025. //
  1026. switch (GatewayBindType)
  1027. {
  1028. case GATEWAY_BIND_TYPE_UNKNOWN:
  1029. {
  1030. //
  1031. // Caller didn't know ahead of time how to bind.
  1032. // Since there's no port, we can let the gateway bind whatever it wants.
  1033. //
  1034. NewGatewayBindType = GATEWAY_BIND_TYPE_DEFAULT;
  1035. break;
  1036. }
  1037. case GATEWAY_BIND_TYPE_NONE:
  1038. {
  1039. //
  1040. // Caller didn't actually want to bind on gateway.
  1041. //
  1042. NewGatewayBindType = GatewayBindType;
  1043. break;
  1044. }
  1045. default:
  1046. {
  1047. //
  1048. // Some wacky value, or a type was somehow already chosen.
  1049. //
  1050. DNASSERT(FALSE);
  1051. NewGatewayBindType = GatewayBindType;
  1052. break;
  1053. }
  1054. }
  1055. }
  1056. else
  1057. {
  1058. DPFX(DPFPREP, 8, "Device socket address 0x%p specified port %u, gateway bind type = %u.",
  1059. pDeviceSocketAddress, NTOHS(pDeviceSocketAddress->GetPort()),
  1060. GatewayBindType);
  1061. //
  1062. // Convert the preliminary bind type to a real one, based on the fact that
  1063. // the caller gave us a port.
  1064. //
  1065. switch (GatewayBindType)
  1066. {
  1067. case GATEWAY_BIND_TYPE_UNKNOWN:
  1068. {
  1069. //
  1070. // Caller didn't know ahead of time how to bind.
  1071. // Since there's a port, it should be fixed on the gateway, too.
  1072. //
  1073. NewGatewayBindType = GATEWAY_BIND_TYPE_SPECIFIC;
  1074. break;
  1075. }
  1076. case GATEWAY_BIND_TYPE_SPECIFIC_SHARED:
  1077. {
  1078. //
  1079. // Caller wanted to bind to a specific port on the gateway,
  1080. // and it needs to be shared (DPNSVR).
  1081. //
  1082. NewGatewayBindType = GatewayBindType;
  1083. break;
  1084. }
  1085. case GATEWAY_BIND_TYPE_NONE:
  1086. {
  1087. //
  1088. // Caller didn't actually want to bind on gateway.
  1089. //
  1090. NewGatewayBindType = GatewayBindType;
  1091. break;
  1092. }
  1093. default:
  1094. {
  1095. //
  1096. // Some wacky value, or default/specific was somehow already chosen.
  1097. // That shouldn't happen.
  1098. //
  1099. DNASSERT(FALSE);
  1100. NewGatewayBindType = GatewayBindType;
  1101. break;
  1102. }
  1103. }
  1104. }
  1105. //
  1106. // Look for an existing socketport that's compatible with the specified endpoint.
  1107. //
  1108. #ifdef DPNBUILD_ONLYONEADAPTER
  1109. pBilinkEndOfList = pSocketData->GetSocketPorts();
  1110. #else // ! DPNBUILD_ONLYONEADAPTER
  1111. pBilinkEndOfList = pAdapterEntry->SocketPortList();
  1112. #endif // ! DPNBUILD_ONLYONEADAPTER
  1113. pBilink = pBilinkEndOfList->GetNext();
  1114. while ((pBilink != pBilinkEndOfList) && (pSocketPort == NULL))
  1115. {
  1116. pSocketPort = CSocketPort::SocketPortFromBilink( pBilink );
  1117. if ((pDeviceSocketAddress->GetPort() != ANY_PORT) &&
  1118. (pDeviceSocketAddress->GetPort() != pSocketPort->GetNetworkAddress()->GetPort()))
  1119. {
  1120. DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it is for a different port (%u <> %u).",
  1121. pSocketPort, NTOHS(pDeviceSocketAddress->GetPort()), NTOHS(pSocketPort->GetNetworkAddress()->GetPort()));
  1122. pSocketPort = NULL;
  1123. }
  1124. #ifndef DPNBUILD_ONLYONEPROCESSOR
  1125. else if ((dwCPU != -1) && (dwCPU != pSocketPort->GetCPU()))
  1126. {
  1127. DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it is for a different CPU (%u <> %u).",
  1128. pSocketPort, dwCPU, pSocketPort->GetCPU());
  1129. pSocketPort = NULL;
  1130. }
  1131. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1132. #ifndef DPNBUILD_NONATHELP
  1133. else if (pSocketPort->GetUserTraversalMode() != pEndpoint->GetUserTraversalMode())
  1134. {
  1135. DPFX(DPFPREP, 7, "Skipping socket port 0x%p because its traversal mode=%u but endpoint 0x%p traversal mode=%u.",
  1136. pSocketPort, pSocketPort->GetUserTraversalMode(), pEndpoint, pEndpoint->GetUserTraversalMode());
  1137. pSocketPort = NULL;
  1138. }
  1139. #endif // ! DPNBUILD_NONATHELP
  1140. else
  1141. {
  1142. switch (pEndpoint->GetType())
  1143. {
  1144. case ENDPOINT_TYPE_LISTEN:
  1145. #ifndef DPNBUILD_NOMULTICAST
  1146. case ENDPOINT_TYPE_MULTICAST_LISTEN:
  1147. #endif // ! DPNBUILD_NOMULTICAST
  1148. {
  1149. //
  1150. // If there's already a listen/multicast listen started on the socket port,
  1151. // we can't select it.
  1152. // NOTE: The socketport's endpoint data lock is not held while checking
  1153. // the listen endpoint handle! This should be fine because we're just
  1154. // doing "if exists" check. If the endpoint later gets removed, we will
  1155. // end up binding to a new socketport that might not have been
  1156. // necessary. If an endpoint gets added, BindEndpoint will notice and
  1157. // fail. Either way, we're not going to cause any crashes.
  1158. //
  1159. if (pSocketPort->GetListenEndpoint() != NULL)
  1160. {
  1161. DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it already has a listen/multicast listen (0x%p).",
  1162. pSocketPort, pSocketPort->GetListenEndpoint());
  1163. pSocketPort = NULL;
  1164. }
  1165. else
  1166. {
  1167. DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding new listen/multicast listen.",
  1168. pSocketPort);
  1169. //
  1170. // Attempt to add a reference for the endpoint we're going to bind to
  1171. // this socket port. If it fails, the socket is in the process of being
  1172. // unbound, so we cannot use this socket port now. Move on to using
  1173. // other socket ports or creating a new one.
  1174. //
  1175. fEndpointReferenceAdded = pSocketPort->EndpointAddRef();
  1176. if (! fEndpointReferenceAdded)
  1177. {
  1178. DPFX(DPFPREP, 1, "Couldn't re-use existing socket port 0x%p for listen/multicast listen because it is unbinding, continuing.",
  1179. pSocketPort);
  1180. pSocketPort = NULL;
  1181. }
  1182. }
  1183. break;
  1184. }
  1185. case ENDPOINT_TYPE_CONNECT:
  1186. case ENDPOINT_TYPE_ENUM:
  1187. case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
  1188. #ifndef DPNBUILD_NOMULTICAST
  1189. case ENDPOINT_TYPE_MULTICAST_RECEIVE:
  1190. #endif // ! DPNBUILD_NOMULTICAST
  1191. {
  1192. DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding new connect or enum.",
  1193. pSocketPort);
  1194. //
  1195. // Attempt to add a reference for the endpoint we're going to bind to
  1196. // this socket port. If it fails, the socket is in the process of being
  1197. // unbound, so we cannot use this socket port now. Move on to using
  1198. // other socket ports or creating a new one.
  1199. //
  1200. fEndpointReferenceAdded = pSocketPort->EndpointAddRef();
  1201. if (! fEndpointReferenceAdded)
  1202. {
  1203. DPFX(DPFPREP, 1, "Couldn't re-use existing socket port 0x%p for connect/enum because it is unbinding, continuing.",
  1204. pSocketPort);
  1205. pSocketPort = NULL;
  1206. }
  1207. break;
  1208. }
  1209. #ifndef DPNBUILD_NOMULTICAST
  1210. case ENDPOINT_TYPE_MULTICAST_SEND:
  1211. {
  1212. //
  1213. // If this socketport has already had its multicast TTL value set, and
  1214. // it's not the same as what we're looking to use, we can't select it.
  1215. // NOTE: The socketport's endpoint data lock is not held while checking
  1216. // the multicast TTL setting.
  1217. //
  1218. if ((pSocketPort->GetMulticastTTL() != 0) &&
  1219. (pSocketPort->GetMulticastTTL() != bMulticastTTL))
  1220. {
  1221. DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it already has a different multicast TTL setting (%u != %u).",
  1222. pSocketPort, pSocketPort->GetMulticastTTL(), bMulticastTTL);
  1223. pSocketPort = NULL;
  1224. }
  1225. else
  1226. {
  1227. DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding new multicast send.",
  1228. pSocketPort);
  1229. //
  1230. // Attempt to add a reference for the endpoint we're going to bind to
  1231. // this socket port. If it fails, the socket is in the process of being
  1232. // unbound, so we cannot use this socket port now. Move on to using
  1233. // other socket ports or creating a new one.
  1234. //
  1235. fEndpointReferenceAdded = pSocketPort->EndpointAddRef();
  1236. if (! fEndpointReferenceAdded)
  1237. {
  1238. DPFX(DPFPREP, 1, "Couldn't re-use existing socket port 0x%p for multicast send because it is unbinding, continuing.",
  1239. pSocketPort);
  1240. pSocketPort = NULL;
  1241. }
  1242. }
  1243. break;
  1244. }
  1245. #endif // ! DPNBUILD_NOMULTICAST
  1246. default:
  1247. {
  1248. DNASSERT(FALSE);
  1249. hr = DPNERR_INVALIDENDPOINT;
  1250. goto Failure;
  1251. break;
  1252. }
  1253. }
  1254. }
  1255. pBilink = pBilink->GetNext();
  1256. }
  1257. //
  1258. // If a socket port has not been found, attempt to create a new socket port,
  1259. // initialize it, and add it to the list (may result in a duplicate, see below).
  1260. // Whatever happens there will be a socket port to bind the endpoint to.
  1261. // Save the reference on the CSocketPort from the call to 'Create' until the
  1262. // socket port is removed from the active list.
  1263. //
  1264. //
  1265. if ( pSocketPort == NULL )
  1266. {
  1267. pSocketData->Unlock();
  1268. fSocketDataLocked = FALSE;
  1269. pSocketPort = (CSocketPort*)g_SocketPortPool.Get();
  1270. if ( pSocketPort == NULL )
  1271. {
  1272. hr = DPNERR_OUTOFMEMORY;
  1273. DPFX(DPFPREP, 0, "Failed to create new socket port!" );
  1274. goto Failure;
  1275. }
  1276. pSocketPort->AddRef();
  1277. fSocketCreated = TRUE;
  1278. DPFX(DPFPREP, 6, "Created new socket port 0x%p.", pSocketPort);
  1279. //
  1280. // We don't need to add a reference for the endpoint we're going to
  1281. // bind since new socket ports should already have the endpoint
  1282. // reference added before it comes out of the pool. We can't assert
  1283. // that because we don't have access to the refcount variables.
  1284. //
  1285. //DNASSERT( pSocketPort->m_iRefCount == 1 );
  1286. //DNASSERT( pSocketPort->m_iEndpointRefCount == 1 );
  1287. fEndpointReferenceAdded = TRUE;
  1288. hr = pSocketPort->Initialize( pSocketData, m_pThreadPool, pDeviceSocketAddress );
  1289. if ( hr != DPN_OK )
  1290. {
  1291. DPFX(DPFPREP, 0, "Failed to initialize new socket port!" );
  1292. DisplayDNError( 0, hr );
  1293. goto Failure;
  1294. }
  1295. pDeviceSocketAddress = NULL;
  1296. #ifndef DPNBUILD_ONLYONEADAPTER
  1297. pAdapterEntry->AddRef();
  1298. pSocketPort->SetAdapterEntry( pAdapterEntry );
  1299. fAdapterEntrySet = TRUE;
  1300. #endif // ! DPNBUILD_ONLYONEADAPTER
  1301. #ifndef DPNBUILD_NONATHELP
  1302. pSocketPort->SetUserTraversalMode(pEndpoint->GetUserTraversalMode());
  1303. #endif // ! DPNBUILD_NONATHELP
  1304. #ifdef DPNBUILD_ONLYONEPROCESSOR
  1305. hr = pSocketPort->BindToNetwork( NewGatewayBindType );
  1306. #else // ! DPNBUILD_ONLYONEPROCESSOR
  1307. hr = pSocketPort->BindToNetwork( dwCPU, NewGatewayBindType );
  1308. #endif // ! DPNBUILD_ONLYONEPROCESSOR
  1309. if ( hr != DPN_OK )
  1310. {
  1311. DPFX(DPFPREP, 0, "Failed to bind new socket port to network!" );
  1312. DisplayDNError( 0, hr );
  1313. goto Failure;
  1314. }
  1315. pSocketData->Lock();
  1316. fSocketDataLocked = TRUE;
  1317. //
  1318. // The only way to get here is to have the socket bound to the
  1319. // network. The socket can't be bound twice, if there was a
  1320. // race to bind the socket, Winsock would have decided which
  1321. // thread lost and failed 'BindToNetwork'.
  1322. //
  1323. // However, the order in which sockets are marked as unusable
  1324. // and then pulled from the active list is such that there could
  1325. // still be an unbinding socketport with this same address in the
  1326. // list.
  1327. //
  1328. #ifdef DBG
  1329. CSocketPort *pDuplicateSocket;
  1330. if ( pSocketData->FindSocketPort( pSocketPort->GetNetworkAddress(), &pDuplicateSocket ) )
  1331. {
  1332. DPFX(DPFPREP, 1, "Socketport with same address still exists in list (0x%p).",
  1333. pDuplicateSocket);
  1334. DumpSocketAddress( 1, pSocketPort->GetNetworkAddress()->GetAddress(), pSocketPort->GetNetworkAddress()->GetFamily() );
  1335. DNASSERT( pDuplicateSocket->GetSocket() == INVALID_SOCKET );
  1336. }
  1337. #endif // DBG
  1338. #ifdef DPNBUILD_ONLYONEADAPTER
  1339. pSocketPort->AddToActiveList( pSocketData->GetSocketPorts() );
  1340. #else // ! DPNBUILD_ONLYONEADAPTER
  1341. pSocketPort->AddToActiveList( pAdapterEntry->SocketPortList() );
  1342. #endif // ! DPNBUILD_ONLYONEADAPTER
  1343. fSocketPortInActiveList = TRUE;
  1344. }
  1345. DNASSERT( pSocketPort != NULL );
  1346. DNASSERT( fEndpointReferenceAdded );
  1347. #if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
  1348. //
  1349. // Munge the public address into a local alias, if there is one for the given device.
  1350. // It's OK for the device socket address to not have a port yet.
  1351. //
  1352. // Note that doing this causes all other multiplexed operations to use the munged
  1353. // result from this first adapter because we indicate the modified address info,
  1354. // not the original proxied address.
  1355. //
  1356. switch ( pEndpoint->GetType() )
  1357. {
  1358. case ENDPOINT_TYPE_CONNECT:
  1359. #ifndef DPNBUILD_NOMULTICAST
  1360. case ENDPOINT_TYPE_MULTICAST_RECEIVE:
  1361. #endif // ! DPNBUILD_NOMULTICAST
  1362. {
  1363. pHostAddress = pEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pAddressHost;
  1364. DNASSERT( pHostAddress != NULL );
  1365. pEndpoint->MungeProxiedAddress( pSocketPort, pHostAddress, FALSE );
  1366. break;
  1367. }
  1368. case ENDPOINT_TYPE_ENUM:
  1369. {
  1370. pHostAddress = pEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost;
  1371. DNASSERT( pHostAddress != NULL );
  1372. pEndpoint->MungeProxiedAddress( pSocketPort, pHostAddress, TRUE );
  1373. break;
  1374. }
  1375. default:
  1376. {
  1377. break;
  1378. }
  1379. }
  1380. #endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
  1381. //
  1382. // bind the endpoint to whatever socketport we have
  1383. //
  1384. hr = pSocketPort->BindEndpoint( pEndpoint, NewGatewayBindType );
  1385. if ( hr != DPN_OK )
  1386. {
  1387. DPFX(DPFPREP, 0, "Failed to bind endpoint!" );
  1388. DisplayDNError( 0, hr );
  1389. goto Failure;
  1390. }
  1391. Exit:
  1392. #ifndef DPNBUILD_ONLYONEADAPTER
  1393. if (pAdapterEntry != NULL)
  1394. {
  1395. pAdapterEntry->DecRef();
  1396. pAdapterEntry = NULL;
  1397. }
  1398. #endif // ! DPNBUILD_ONLYONEADAPTER
  1399. if ( pSocketData != NULL )
  1400. {
  1401. if ( fSocketDataLocked != FALSE )
  1402. {
  1403. pSocketData->Unlock();
  1404. fSocketDataLocked = FALSE;
  1405. }
  1406. pSocketData->Release();
  1407. pSocketData = NULL;
  1408. }
  1409. if ( pDeviceSocketAddress != NULL )
  1410. {
  1411. g_SocketAddressPool.Release( pDeviceSocketAddress );
  1412. pDeviceSocketAddress = NULL;
  1413. }
  1414. DPFX(DPFPREP, 6, "(0x%p) Return [0x%lx]", this, hr);
  1415. return hr;
  1416. Failure:
  1417. //
  1418. // If we're failing and cleanup will require removal of some resources.
  1419. // This requires the socket port data lock.
  1420. //
  1421. if ( ( pSocketData != NULL ) && ( fSocketDataLocked == FALSE ) )
  1422. {
  1423. pSocketData->Lock();
  1424. fSocketDataLocked = TRUE;
  1425. }
  1426. if ( pSocketPort != NULL )
  1427. {
  1428. if ( fEndpointReferenceAdded != FALSE )
  1429. {
  1430. pSocketPort->EndpointDecRef();
  1431. fEndpointReferenceAdded = FALSE;
  1432. }
  1433. #ifndef DPNBUILD_ONLYONEADAPTER
  1434. if (fAdapterEntrySet)
  1435. {
  1436. pSocketPort->SetAdapterEntry( NULL );
  1437. pAdapterEntry->DecRef();
  1438. fAdapterEntrySet = FALSE;
  1439. }
  1440. #endif // ! DPNBUILD_ONLYONEADAPTER
  1441. if ( fSocketPortInActiveList != FALSE )
  1442. {
  1443. pSocketPort->RemoveFromActiveList();
  1444. fSocketPortInActiveList = FALSE;
  1445. }
  1446. if ( fSocketCreated != FALSE )
  1447. {
  1448. pSocketPort->DecRef();
  1449. fSocketCreated = FALSE;
  1450. pSocketPort = NULL;
  1451. }
  1452. }
  1453. goto Exit;
  1454. }
  1455. //**********************************************************************
  1456. //**********************************************************************
  1457. // ------------------------------
  1458. // CSPData::UnbindEndpoint - unbind an endpoint from a socket port
  1459. //
  1460. // Entry: Pointer to endpoint
  1461. //
  1462. // Exit: Nothing
  1463. // ------------------------------
  1464. #undef DPF_MODNAME
  1465. #define DPF_MODNAME "CSPData::UnbindEndpoint"
  1466. void CSPData::UnbindEndpoint( CEndpoint *const pEndpoint )
  1467. {
  1468. CSocketData * pSocketData;
  1469. CSocketPort * pSocketPort;
  1470. BOOL fCleanUpSocketPort;
  1471. #ifndef DPNBUILD_ONLYONEADAPTER
  1472. CAdapterEntry * pAdapterEntry;
  1473. #endif // ! DPNBUILD_ONLYONEADAPTER
  1474. DNASSERT( pEndpoint != NULL );
  1475. DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%p)", this, pEndpoint);
  1476. //
  1477. // initialize
  1478. //
  1479. pSocketData = GetSocketData();
  1480. DNASSERT( pSocketData != NULL );
  1481. pSocketPort = pEndpoint->GetSocketPort();
  1482. DNASSERT( pSocketPort != NULL );
  1483. fCleanUpSocketPort = FALSE;
  1484. pSocketPort->UnbindEndpoint( pEndpoint );
  1485. if ( pSocketPort->EndpointDecRef() == 0 )
  1486. {
  1487. fCleanUpSocketPort = TRUE;
  1488. pSocketData->Lock();
  1489. pSocketPort->RemoveFromActiveList();
  1490. #ifndef DPNBUILD_ONLYONEADAPTER
  1491. pAdapterEntry = pSocketPort->GetAdapterEntry();
  1492. DNASSERT( pAdapterEntry != NULL );
  1493. pSocketPort->SetAdapterEntry( NULL );
  1494. pAdapterEntry->DecRef();
  1495. #endif // ! DPNBUILD_ONLYONEADAPTER
  1496. pSocketData->Unlock();
  1497. }
  1498. if ( fCleanUpSocketPort != FALSE )
  1499. {
  1500. pSocketPort->DecRef();
  1501. fCleanUpSocketPort = FALSE;
  1502. }
  1503. DPFX(DPFPREP, 6, "(0x%p) Leave", this);
  1504. }
  1505. //**********************************************************************
  1506. #ifndef DPNBUILD_NOMULTICAST
  1507. //**********************************************************************
  1508. // ------------------------------
  1509. // CSPData::GetEndpointFromAddress - retrieves an endpoint handle and context given addressing info
  1510. //
  1511. // Entry: Pointer to host address
  1512. // Pointer to device address
  1513. // Place to store endpoint handle
  1514. // Place to store user context
  1515. //
  1516. // Exit: Error
  1517. // ------------------------------
  1518. #undef DPF_MODNAME
  1519. #define DPF_MODNAME "CSPData::GetEndpointFromAddress"
  1520. HRESULT CSPData::GetEndpointFromAddress( IDirectPlay8Address *const pHostAddress,
  1521. IDirectPlay8Address *const pDeviceAddress,
  1522. HANDLE * phEndpoint,
  1523. PVOID * ppvEndpointContext )
  1524. {
  1525. HRESULT hr;
  1526. CSocketAddress * pDeviceSocketAddress;
  1527. CSocketAddress * pHostSocketAddress;
  1528. CSocketData * pSocketData;
  1529. BOOL fSocketDataLocked;
  1530. CSocketPort * pSocketPort;
  1531. CEndpoint * pEndpoint;
  1532. //
  1533. // initialize
  1534. //
  1535. hr = DPN_OK;
  1536. pHostSocketAddress = NULL;
  1537. pDeviceSocketAddress = NULL;
  1538. pSocketData = NULL;
  1539. fSocketDataLocked = FALSE;
  1540. pSocketPort = NULL;
  1541. pEndpoint = NULL;
  1542. //
  1543. // Get SP addresses from the pool to perform conversions.
  1544. //
  1545. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  1546. pHostSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
  1547. pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
  1548. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  1549. pHostSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) GetType()));
  1550. pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) GetType()));
  1551. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  1552. if ((pHostSocketAddress == NULL) || (pDeviceSocketAddress == NULL))
  1553. {
  1554. DPFX(DPFPREP, 0, "Failed to get addresses for conversions!" );
  1555. hr = DPNERR_OUTOFMEMORY;
  1556. goto Failure;
  1557. }
  1558. //
  1559. // Convert the device address.
  1560. //
  1561. hr = pDeviceSocketAddress->SocketAddressFromDP8Address(pDeviceAddress,
  1562. #ifdef DPNBUILD_XNETSECURITY
  1563. NULL,
  1564. #endif // DPNBUILD_XNETSECURITY
  1565. #ifndef DPNBUILD_ONLYONETHREAD
  1566. FALSE,
  1567. #endif // DPNBUILD_ONLYONETHREAD
  1568. SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT);
  1569. if (hr != DPN_OK)
  1570. {
  1571. DPFX(DPFPREP, 0, "Couldn't get socket address from device DP8 address (err = 0x%lx)!", hr);
  1572. hr = DPNERR_INVALIDDEVICEADDRESS;
  1573. goto Failure;
  1574. }
  1575. //
  1576. // Convert the host address.
  1577. //
  1578. hr = pHostSocketAddress->SocketAddressFromDP8Address(pHostAddress,
  1579. #ifdef DPNBUILD_XNETSECURITY
  1580. NULL,
  1581. #endif // DPNBUILD_XNETSECURITY
  1582. #ifndef DPNBUILD_ONLYONETHREAD
  1583. FALSE,
  1584. #endif // DPNBUILD_ONLYONETHREAD
  1585. SP_ADDRESS_TYPE_HOST);
  1586. if (hr != DPN_OK)
  1587. {
  1588. DPFX(DPFPREP, 0, "Couldn't get socket address from host DP8 address (err = 0x%lx)!", hr);
  1589. hr = DPNERR_INVALIDHOSTADDRESS;
  1590. goto Failure;
  1591. }
  1592. #ifndef DPNBUILD_NONATHELP
  1593. //
  1594. // Make sure we have the local version of the host, as reported by NAT Help.
  1595. //
  1596. MungePublicAddress(pDeviceSocketAddress, pHostSocketAddress, FALSE);
  1597. #endif // ! DPNBUILD_NONATHELP
  1598. //
  1599. // Get the socket port data.
  1600. //
  1601. pSocketData = GetSocketDataRef();
  1602. if (pSocketData == NULL)
  1603. {
  1604. DPFX(DPFPREP, 0, "Couldn't retrieve socket data!");
  1605. hr = DPNERR_OUTOFMEMORY;
  1606. goto Failure;
  1607. }
  1608. pSocketData->Lock();
  1609. fSocketDataLocked = TRUE;
  1610. //
  1611. // Look up the socket port for the given address.
  1612. //
  1613. if (! (pSocketData->FindSocketPort(pDeviceSocketAddress, &pSocketPort)))
  1614. {
  1615. DPFX(DPFPREP, 0, "Couldn't find socket port for given device address (err = 0x%lx)!", hr);
  1616. hr = DPNERR_INVALIDDEVICEADDRESS;
  1617. goto Failure;
  1618. }
  1619. pSocketPort->AddRef();
  1620. pSocketData->Unlock();
  1621. fSocketDataLocked = FALSE;
  1622. //
  1623. // Locate the connect endpoint for the host address.
  1624. //
  1625. pSocketPort->ReadLockEndpointData();
  1626. if (pSocketPort->FindConnectEndpoint(pHostSocketAddress, &pEndpoint))
  1627. {
  1628. (*phEndpoint) = (HANDLE) pEndpoint;
  1629. (*ppvEndpointContext) = pEndpoint->GetUserEndpointContext();
  1630. }
  1631. else
  1632. {
  1633. DPFX(DPFPREP, 0, "Couldn't find endpoint for given host address!");
  1634. hr = DPNERR_INVALIDHOSTADDRESS;
  1635. //
  1636. // Drop through...
  1637. //
  1638. }
  1639. pSocketPort->UnlockEndpointData();
  1640. Exit:
  1641. if (pSocketPort != NULL)
  1642. {
  1643. pSocketPort->DecRef();
  1644. pSocketPort = NULL;
  1645. }
  1646. if (pSocketData != NULL)
  1647. {
  1648. if (fSocketDataLocked)
  1649. {
  1650. pSocketData->Unlock();
  1651. fSocketDataLocked = FALSE;
  1652. }
  1653. pSocketData->Release();
  1654. pSocketData = NULL;
  1655. }
  1656. if (pHostSocketAddress != NULL)
  1657. {
  1658. g_SocketAddressPool.Release( pHostSocketAddress );
  1659. pHostSocketAddress = NULL;
  1660. }
  1661. if (pDeviceSocketAddress != NULL)
  1662. {
  1663. g_SocketAddressPool.Release( pDeviceSocketAddress );
  1664. pDeviceSocketAddress = NULL;
  1665. }
  1666. DPFX(DPFPREP, 6, "Returning: [0x%lx] (handle = 0x%p, context = 0x%p",
  1667. hr, (*phEndpoint), (*ppvEndpointContext));
  1668. return hr;
  1669. Failure:
  1670. goto Exit;
  1671. }
  1672. //**********************************************************************
  1673. #endif // ! DPNBUILD_NOMULTICAST
  1674. //**********************************************************************
  1675. // ------------------------------
  1676. // CSPData::GetNewEndpoint - get a new endpoint
  1677. //
  1678. // Entry: Nothing
  1679. //
  1680. // Exit: Pointer to new endpoint
  1681. // NULL = out of memory
  1682. // ------------------------------
  1683. #undef DPF_MODNAME
  1684. #define DPF_MODNAME "CSPData::GetNewEndpoint"
  1685. CEndpoint *CSPData::GetNewEndpoint( void )
  1686. {
  1687. CEndpoint *pEndpoint;
  1688. pEndpoint = (CEndpoint*)g_EndpointPool.Get( this );
  1689. if ( pEndpoint == NULL )
  1690. {
  1691. DPFX(DPFPREP, 0, "Failed to create endpoint!" );
  1692. }
  1693. // NOTE: Endpoints are returned with one CommandRef and one regular Ref.
  1694. return pEndpoint;
  1695. }
  1696. //**********************************************************************
  1697. //**********************************************************************
  1698. // ------------------------------
  1699. // CSPData::EndpointFromHandle - get endpoint from handle
  1700. //
  1701. // Entry: Handle
  1702. //
  1703. // Exit: Pointer to endpoint
  1704. // NULL = invalid handle
  1705. // ------------------------------
  1706. #undef DPF_MODNAME
  1707. #define DPF_MODNAME "CSPData::EndpointFromHandle"
  1708. CEndpoint *CSPData::EndpointFromHandle( const HANDLE hEndpoint )
  1709. {
  1710. CEndpoint *pEndpoint;
  1711. BOOL fGotCommandRef;
  1712. pEndpoint = (CEndpoint*) hEndpoint;
  1713. DNASSERT( pEndpoint->IsValid() );
  1714. fGotCommandRef = pEndpoint->AddCommandRef();
  1715. DNASSERT( fGotCommandRef );
  1716. return pEndpoint;
  1717. }
  1718. //**********************************************************************
  1719. //**********************************************************************
  1720. // ------------------------------
  1721. // CSPData::CloseEndpointHandle - close endpoint handle
  1722. //
  1723. // Entry: Poiner to endpoint
  1724. //
  1725. // Exit: Nothing
  1726. // ------------------------------
  1727. #undef DPF_MODNAME
  1728. #define DPF_MODNAME "CSPData::CloseEndpointHandle"
  1729. void CSPData::CloseEndpointHandle( CEndpoint *const pEndpoint )
  1730. {
  1731. pEndpoint->DecCommandRef();
  1732. }
  1733. //**********************************************************************
  1734. //**********************************************************************
  1735. // ------------------------------
  1736. // CSPData::GetEndpointAndCloseHandle - get endpoint from handle and close the
  1737. // handle
  1738. //
  1739. // Entry: Handle
  1740. //
  1741. // Exit: Pointer to endpoint (it needs a call to 'DecCommandRef' when done)
  1742. // NULL = invalid handle
  1743. // ------------------------------
  1744. #undef DPF_MODNAME
  1745. #define DPF_MODNAME "CSPData::GetEndpointAndCloseHandle"
  1746. CEndpoint *CSPData::GetEndpointAndCloseHandle( const HANDLE hEndpoint )
  1747. {
  1748. CEndpoint *pEndpoint;
  1749. pEndpoint = (CEndpoint*) hEndpoint;
  1750. DNASSERT( pEndpoint->IsValid() );
  1751. pEndpoint->AddRef();
  1752. return pEndpoint;
  1753. }
  1754. //**********************************************************************
  1755. #ifndef DPNBUILD_NONATHELP
  1756. //**********************************************************************
  1757. // ------------------------------
  1758. // CSPData::MungePublicAddress - get a public socket address' local alias, if any
  1759. // it also converts the IPv6 loopback address to the device address
  1760. //
  1761. // Entry: Pointer to device address
  1762. // Pointer to public address to munge
  1763. // Whether it's an enum or not
  1764. //
  1765. // Exit: Nothing
  1766. // ------------------------------
  1767. #undef DPF_MODNAME
  1768. #define DPF_MODNAME "CSPData::MungePublicAddress"
  1769. void CSPData::MungePublicAddress( const CSocketAddress * const pDeviceBaseAddress, CSocketAddress * const pPublicAddress, const BOOL fEnum )
  1770. {
  1771. HRESULT hr = DPNHERR_NOMAPPING;
  1772. SOCKADDR SocketAddress;
  1773. DWORD dwTemp;
  1774. DNASSERT( pDeviceBaseAddress != NULL );
  1775. DNASSERT( pPublicAddress != NULL );
  1776. DNASSERT( m_pThreadPool != NULL );
  1777. #if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
  1778. if ( m_pThreadPool->IsNATHelpLoaded() )
  1779. #else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  1780. if (( pDeviceBaseAddress->GetFamily() == AF_INET ) &&
  1781. ( pPublicAddress->GetFamily() == AF_INET ) &&
  1782. ( m_pThreadPool->IsNATHelpLoaded() ))
  1783. #endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
  1784. {
  1785. //
  1786. // Don't bother looking up the broadcast address, that's a waste of
  1787. // time.
  1788. //
  1789. if (((SOCKADDR_IN*) pPublicAddress->GetAddress())->sin_addr.S_un.S_addr == INADDR_BROADCAST)
  1790. {
  1791. //
  1792. // This had better be an enum, you can't connect to the broadcast
  1793. // address.
  1794. //
  1795. DNASSERT(fEnum);
  1796. DPFX(DPFPREP, 8, "Not attempting to lookup alias for broadcast address." );
  1797. }
  1798. else
  1799. {
  1800. DBG_CASSERT( sizeof( SocketAddress ) == sizeof( *pPublicAddress->GetAddress() ) );
  1801. //
  1802. // Start by copying the
  1803. //
  1804. for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
  1805. {
  1806. if (g_papNATHelpObjects[dwTemp] != NULL)
  1807. {
  1808. //
  1809. // IDirectPlayNATHelp::GetCaps had better have been called with the
  1810. // DPNHGETCAPS_UPDATESERVERSTATUS flag at least once prior to this.
  1811. // See CThreadPool::EnsureNATHelpLoaded
  1812. //
  1813. hr = IDirectPlayNATHelp_QueryAddress( g_papNATHelpObjects[dwTemp],
  1814. pDeviceBaseAddress->GetAddress(),
  1815. pPublicAddress->GetAddress(),
  1816. &SocketAddress,
  1817. sizeof(SocketAddress),
  1818. (DPNHQUERYADDRESS_CACHEFOUND | DPNHQUERYADDRESS_CACHENOTFOUND) );
  1819. if ( hr == DPNH_OK )
  1820. {
  1821. //
  1822. // There is a local alias for the address.
  1823. //
  1824. //
  1825. // Bad news:
  1826. // The PAST protocol can only return one address, but the SHARED
  1827. // UDP LISTENER extension which allows multiple machines to listen
  1828. // on the same fixed port. Someone querying for the local alias
  1829. // for that address will only get the first person to register the
  1830. // shared port, which may not be the machine desired.
  1831. //
  1832. // Good news:
  1833. // Only DPNSVR uses SHARED UDP LISTENERs, and thus it only happens
  1834. // with enums on DPNSVRs port. Further, it only affects a person
  1835. // behind the same ICS machine. So we can workaround this by
  1836. // detecting an enum attempt on the public address and DPNSVR port,
  1837. // and instead of using the single address returned by PAST, use
  1838. // the broadcast address. Since anyone registered with the ICS
  1839. // server would have to be local, broadcasting should find the same
  1840. // servers (and technically more, but that shouldn't matter).
  1841. //
  1842. // So:
  1843. // If the address has a local alias, and it's the DPNSVR port
  1844. // (which is the only one that can be shared), and its an enum,
  1845. // broadcast instead.
  1846. //
  1847. if ((fEnum) && (((SOCKADDR_IN*) pPublicAddress->GetAddress())->sin_port == HTONS(DPNA_DPNSVR_PORT)))
  1848. {
  1849. ((SOCKADDR_IN*) pPublicAddress->GetAddress())->sin_addr.S_un.S_addr = INADDR_BROADCAST;
  1850. DPFX(DPFPREP, 7, "Address for enum has local alias (via object %u), but is on DPNSVR's shared fixed port, substituting broadcast address instead:",
  1851. dwTemp );
  1852. DumpSocketAddress( 7, pPublicAddress->GetAddress(), pPublicAddress->GetFamily() );
  1853. }
  1854. else
  1855. {
  1856. pPublicAddress->SetAddressFromSOCKADDR( &SocketAddress, sizeof( SocketAddress ) );
  1857. DPFX(DPFPREP, 7, "Object %u had mapping, modified address is now:", dwTemp );
  1858. DumpSocketAddress( 7, pPublicAddress->GetAddress(), pPublicAddress->GetFamily() );
  1859. }
  1860. //
  1861. // Stop searching.
  1862. //
  1863. break;
  1864. }
  1865. DPFX(DPFPREP, 8, "Address was not modified by object %u (err = 0x%lx).",
  1866. dwTemp, hr );
  1867. }
  1868. else
  1869. {
  1870. //
  1871. // No DPNATHelp object in this slot.
  1872. //
  1873. }
  1874. } // end for (each DPNATHelp object)
  1875. //
  1876. // If no object touched it, remember that.
  1877. //
  1878. if (hr != DPNH_OK)
  1879. {
  1880. DPFX(DPFPREP, 7, "Address was not modified by any objects:" );
  1881. DumpSocketAddress( 7, pPublicAddress->GetAddress(), pPublicAddress->GetFamily() );
  1882. }
  1883. }
  1884. }
  1885. else
  1886. {
  1887. DPFX(DPFPREP, 7, "NAT Help not loaded or not necessary, not modifying address." );
  1888. }
  1889. }
  1890. //**********************************************************************
  1891. #endif // !DPNBUILD_NONATHELP
  1892. #ifndef WINCE
  1893. //**********************************************************************
  1894. // ------------------------------
  1895. // CSPData::SetWinsockBufferSizeOnAllSockets - set buffer size on all sockets
  1896. //
  1897. // Entry: New buffer size
  1898. //
  1899. // Exit: Nothing
  1900. // ------------------------------
  1901. #undef DPF_MODNAME
  1902. #define DPF_MODNAME "CSPData::SetWinsockBufferSizeOnAllSockets"
  1903. void CSPData::SetWinsockBufferSizeOnAllSockets( const INT iBufferSize )
  1904. {
  1905. CSocketData *pSocketData;
  1906. #ifndef DPNBUILD_ONLYONEADAPTER
  1907. CAdapterEntry *pAdapterEntry;
  1908. CBilink *pAdapterEntryLink;
  1909. #endif // ! DPNBUILD_ONLYONEADAPTER
  1910. CBilink *pSocketPortList;
  1911. CBilink *pBilinkSocketPortListEnd;
  1912. CSocketPort *pSocketPort;
  1913. //
  1914. // Don't use GetSocketDataRef to retrieve the socket data because
  1915. // this is just a caps setting. We don't want to create the socket
  1916. // data object if it didn't exist.
  1917. //
  1918. Lock();
  1919. if (m_pSocketData != NULL)
  1920. {
  1921. m_pSocketData->AddRef();
  1922. pSocketData = m_pSocketData;
  1923. Unlock();
  1924. pSocketData->Lock();
  1925. #ifndef DPNBUILD_ONLYONEADAPTER
  1926. pAdapterEntryLink = pSocketData->GetAdapters()->GetNext();
  1927. while ( pAdapterEntryLink != pSocketData->GetAdapters() )
  1928. #endif // ! DPNBUILD_ONLYONEADAPTER
  1929. {
  1930. #ifdef DPNBUILD_ONLYONEADAPTER
  1931. pBilinkSocketPortListEnd = pSocketData->GetSocketPorts();
  1932. #else // ! DPNBUILD_ONLYONEADAPTER
  1933. pAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pAdapterEntryLink );
  1934. pBilinkSocketPortListEnd = pAdapterEntry->SocketPortList();
  1935. #endif // ! DPNBUILD_ONLYONEADAPTER
  1936. pSocketPortList = pBilinkSocketPortListEnd->GetNext();
  1937. while ( pSocketPortList != pBilinkSocketPortListEnd )
  1938. {
  1939. pSocketPort = CSocketPort::SocketPortFromBilink( pSocketPortList );
  1940. pSocketPort->SetWinsockBufferSize( iBufferSize );
  1941. pSocketPortList = pSocketPortList->GetNext();
  1942. }
  1943. #ifndef DPNBUILD_ONLYONEADAPTER
  1944. pAdapterEntryLink = pAdapterEntryLink->GetNext();
  1945. #endif // ! DPNBUILD_ONLYONEADAPTER
  1946. }
  1947. pSocketData->Unlock();
  1948. pSocketData->Release();
  1949. pSocketData = NULL;
  1950. }
  1951. else
  1952. {
  1953. Unlock();
  1954. }
  1955. }
  1956. //**********************************************************************
  1957. #endif // ! WINCE
  1958. //**********************************************************************
  1959. // ------------------------------
  1960. // CSPData::DestroyThisObject - destroy this object
  1961. //
  1962. // Entry: Nothing
  1963. //
  1964. // Exit: Nothing
  1965. // ------------------------------
  1966. #undef DPF_MODNAME
  1967. #define DPF_MODNAME "CSPData::DestroyThisObject"
  1968. void CSPData::DestroyThisObject( void )
  1969. {
  1970. Deinitialize();
  1971. DNFree(this);
  1972. }
  1973. //**********************************************************************
  1974. //**********************************************************************
  1975. // ------------------------------
  1976. // CSPData::GetSocketDataRef - retrieves a referenced pointer to this interface's
  1977. // socket data object. If none has been created yet,
  1978. // allocate one (after which we cannot begin sharing
  1979. // the socket data with another interface object).
  1980. //
  1981. // Entry: Nothing
  1982. //
  1983. // Exit: Pointer to active socket data
  1984. // ------------------------------
  1985. #undef DPF_MODNAME
  1986. #define DPF_MODNAME "CSPData::GetSocketDataRef"
  1987. CSocketData * CSPData::GetSocketDataRef( void )
  1988. {
  1989. CSocketData * pSocketData;
  1990. DNEnterCriticalSection( &m_Lock );
  1991. if ( m_pSocketData == NULL )
  1992. {
  1993. pSocketData = (CSocketData*) g_SocketDataPool.Get( m_pThreadPool );
  1994. if ( pSocketData != NULL )
  1995. {
  1996. pSocketData->AddRef();
  1997. m_pSocketData = pSocketData;
  1998. }
  1999. }
  2000. else
  2001. {
  2002. m_pSocketData->AddRef();
  2003. pSocketData = m_pSocketData;
  2004. }
  2005. DNLeaveCriticalSection( &m_Lock );
  2006. return pSocketData;
  2007. }
  2008. #ifdef DBG
  2009. #ifndef DPNBUILD_ONLYONEADAPTER
  2010. //**********************************************************************
  2011. // ------------------------------
  2012. // CSPData::DebugPrintOutstandingAdapterEntries - print out all the outstanding adapter entries for this interface
  2013. //
  2014. // Entry: None
  2015. //
  2016. // Exit: Nothing
  2017. // ------------------------------
  2018. #undef DPF_MODNAME
  2019. #define DPF_MODNAME "CSPData::DebugPrintOutstandingAdapterEntries"
  2020. void CSPData::DebugPrintOutstandingAdapterEntries( void )
  2021. {
  2022. CSocketData * pSocketData;
  2023. CBilink * pBilink;
  2024. CAdapterEntry * pAdapterEntry;
  2025. //
  2026. // Don't use GetSocketDataRef to retrieve the socket data because
  2027. // this is just a debug print routine. We don't want to create the
  2028. // socket data object if it didn't exist.
  2029. //
  2030. Lock();
  2031. if (m_pSocketData != NULL)
  2032. {
  2033. m_pSocketData->AddRef();
  2034. pSocketData = m_pSocketData;
  2035. Unlock();
  2036. DPFX(DPFPREP, 4, "SP data 0x%p (socket data 0x%p) outstanding adapter entries:",
  2037. this, pSocketData);
  2038. pSocketData->Lock();
  2039. pBilink = pSocketData->GetAdapters()->GetNext();
  2040. while (pBilink != pSocketData->GetAdapters())
  2041. {
  2042. pAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage(pBilink);
  2043. pAdapterEntry->DebugPrintOutstandingSocketPorts();
  2044. pBilink = pBilink->GetNext();
  2045. }
  2046. pSocketData->Unlock();
  2047. pSocketData->Release();
  2048. pSocketData = NULL;
  2049. }
  2050. else
  2051. {
  2052. Unlock();
  2053. DPFX(DPFPREP, 4, "SP Data 0x%p does not have socket data.", this);
  2054. }
  2055. }
  2056. //**********************************************************************
  2057. #endif // ! DPNBUILD_ONLYONEADAPTER
  2058. #endif // DBG