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.

3250 lines
75 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: NameTable.cpp
  6. * Content: NameTable Object
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 03/11/00 mjn Created
  12. * 04/09/00 mjn Track outstanding connections in NameTable
  13. * 04/18/00 mjn CConnection tracks connection status better
  14. * 04/19/00 mjn PopulateConnection makes the ALL_PLAYERS link valid before posting ADD_PLAYER
  15. * 05/03/00 mjn Implemented GetHostPlayerRef, GetLocalPlayerRef, GetAllPlayersGroupRef
  16. * 05/08/00 mjn PopulateConnection() only sets the player's connection if it was previously NULL
  17. * 05/10/00 mjn Release NameTableEntry lock during notifications in PopulateConnection()
  18. * 05/16/00 mjn Ensure dpnidGroup is actually a group in IsMember()
  19. * mjn Better use of locks when clearing short-cut pointers
  20. * 05/25/00 mjn Fixed infinite loop in UpdateTable()
  21. * 06/01/00 mjn Added code to validate NameTable array
  22. * 06/02/00 mjn Fixed logic in GrowNameTable() to handle case of existing free entries
  23. * 06/07/00 mjn Fixed logic in UpdateTable() to adjust m_dwLastFreeEntry correctly
  24. * 06/22/00 mjn UnpackNameTableInfo() returns local players DPNID
  25. * 06/29/00 mjn 64-bit build fixes (2)
  26. * 07/06/00 mjn Fixed locking problem in CNameTable::MakeLocalPlayer,MakeHostPlayer,MakeAllPlayersGroup
  27. * 07/07/00 mjn Fixed validation error in FindEntry()
  28. * 07/20/00 mjn Cleaned up CConnection refcounts and added attempted disconnects
  29. * mjn Added ClearHostWithDPNID()
  30. * 07/21/00 mjn Fixed DeletePlayer() to properly handle deleted unconnected players
  31. * 07/26/00 mjn Moved initialization code from contructor to Initialize()
  32. * mjn Allow DPNID=0 for FindEntry(), but return DPNERR_DOESNOTEXIST
  33. * 07/30/00 mjn Set reason codes for destroying players and groups
  34. * mjn Added hrReason to CNameTable::EmptyTable() and extended clean-up to include short-cut pointers
  35. * 08/02/00 mjn Dequeue queued messages when propagating CREATE_PLAYER message
  36. * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  37. * mjn AddPlayerToGroup() does a duplicate check
  38. * 08/07/00 mjn Wait until player to be added to groups before reducing outstanding connections in PopulateConnection()
  39. * 08/15/00 mjn Keep group on CGroupConnection objects
  40. * mjn Clear pGroupConnection from CGroupMembership when removing players from groups
  41. * 08/23/00 mjn Added CNameTableOp
  42. * 09/04/00 mjn Added CApplicationDesc
  43. * 09/05/00 mjn Added m_dpnidMask
  44. * mjn Removed dwIndex from InsertEntry()
  45. * 09/06/00 mjn Remove queued messages in EmptyTable() and DeletePlayer()
  46. * 09/14/00 mjn Added missing pGroupMember->AddRef() in PopulateConnection()
  47. * 09/17/00 mjn Split m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups
  48. * mjn Changed AddPlayerToGroup and RemovePlayerFromGroup to use NameTableEntry params
  49. * 09/26/00 mjn Assume NameTable locks are taken for AddMembership() and RemoveMembership()
  50. * mjn Attempt to disconnect client from Host in EmptyTable()
  51. * 09/28/00 mjn Autodestruct groups in DeletePlayer()
  52. * 10/18/00 mjn Reset m_lOutstandingConnections in UnpackNameTableInfo()
  53. * 01/11/00 mjn Proper clean up for indicated but not created players in DeletePlayer()
  54. * 01/25/01 mjn Fixed 64-bit alignment problem when unpacking NameTable
  55. * 06/02/01 mjn Remove receive buffers from active list in EmptyTable()
  56. * 06/03/01 mjn Complete and orphan connect parent before releasing in DecOutstandingConnections()
  57. *@@END_MSINTERNAL
  58. *
  59. ***************************************************************************/
  60. #include "dncorei.h"
  61. //**********************************************************************
  62. // Constant definitions
  63. //**********************************************************************
  64. //**********************************************************************
  65. // Macro definitions
  66. //**********************************************************************
  67. //**********************************************************************
  68. // Structure definitions
  69. //**********************************************************************
  70. //**********************************************************************
  71. // Variable definitions
  72. //**********************************************************************
  73. //**********************************************************************
  74. // Function prototypes
  75. //**********************************************************************
  76. //**********************************************************************
  77. // Function definitions
  78. //**********************************************************************
  79. #undef DPF_MODNAME
  80. #define DPF_MODNAME "CNameTable::Initialize"
  81. HRESULT CNameTable::Initialize(DIRECTNETOBJECT *const pdnObject)
  82. {
  83. m_dwVersion = 1;
  84. m_bilinkPlayers.Initialize();
  85. m_bilinkGroups.Initialize();
  86. m_bilinkDeleted.Initialize();
  87. m_bilinkNameTableOps.Initialize();
  88. // NOTE: It is important that we call Initialize even if we are going to fail in this
  89. // function. In other words, don't put anything above this that fails, or you will
  90. // break CReadWriteLock::Deinitialize.
  91. if (!m_RWLock.Initialize())
  92. {
  93. return(DPNERR_OUTOFMEMORY);
  94. }
  95. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  96. //
  97. // (Pre)allocate a name table entry.
  98. //
  99. if (g_NameTableEntryPool.Preallocate(1, pdnObject) < 1)
  100. {
  101. DPFX(DPFPREP, 0, "Couldn't allocate default player name table entry!");
  102. return(DPNERR_OUTOFMEMORY);
  103. }
  104. NameTableEntryNew(pdnObject,&m_pDefaultPlayer);
  105. DNASSERT(m_pDefaultPlayer != NULL);
  106. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  107. if (NameTableEntryNew(pdnObject,&m_pDefaultPlayer) != DPN_OK)
  108. {
  109. return(DPNERR_OUTOFMEMORY);
  110. }
  111. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  112. DNASSERT(m_pdnObject == NULL);
  113. m_pdnObject = pdnObject;
  114. return(DPN_OK);
  115. }
  116. #undef DPF_MODNAME
  117. #define DPF_MODNAME "CNameTable::Deinitialize"
  118. void CNameTable::Deinitialize( void )
  119. {
  120. if (m_NameTableArray)
  121. {
  122. #ifdef DBG
  123. ValidateArray();
  124. #endif // DBG
  125. DNFree(m_NameTableArray);
  126. m_NameTableArray = NULL;
  127. }
  128. // Calling this is safe as long as CReadWriteLock::Initialize was called, regardless of
  129. // whether or not it succeeded.
  130. m_RWLock.Deinitialize();
  131. m_pDefaultPlayer->Release();
  132. m_pDefaultPlayer = NULL;
  133. DNASSERT(m_bilinkPlayers.IsEmpty());
  134. DNASSERT(m_bilinkGroups.IsEmpty());
  135. DNASSERT(m_bilinkDeleted.IsEmpty());
  136. DNASSERT(m_bilinkNameTableOps.IsEmpty());
  137. DNASSERT(m_pDefaultPlayer == NULL);
  138. DNASSERT(m_pLocalPlayer == NULL);
  139. DNASSERT(m_pHostPlayer == NULL);
  140. DNASSERT(m_NameTableArray == NULL);
  141. }
  142. #ifdef DBG
  143. #undef DPF_MODNAME
  144. #define DPF_MODNAME "CNameTable::ValidateArray"
  145. void CNameTable::ValidateArray( void )
  146. {
  147. DWORD dw;
  148. DWORD dwFreeEntries;
  149. ReadLock();
  150. //
  151. // Ensure free entry count is correct
  152. //
  153. dwFreeEntries = 0;
  154. for (dw = 2 ; dw < m_dwNameTableSize ; dw++)
  155. {
  156. if (!(m_NameTableArray[dw].dwFlags & NAMETABLE_ARRAY_ENTRY_FLAG_VALID))
  157. {
  158. dwFreeEntries++;
  159. }
  160. }
  161. if (dwFreeEntries != m_dwNumFreeEntries)
  162. {
  163. DPFERR("Incorrect number of free entries in NameTable");
  164. DNASSERT(FALSE);
  165. }
  166. //
  167. // Ensure free list integrity
  168. //
  169. if (m_dwNumFreeEntries)
  170. {
  171. dwFreeEntries = 0;
  172. dw = m_dwFirstFreeEntry;
  173. do
  174. {
  175. if (m_NameTableArray[dw].dwFlags & NAMETABLE_ARRAY_ENTRY_FLAG_VALID)
  176. {
  177. DPFERR("Valid entry in NameTable array free list");
  178. DNASSERT(FALSE);
  179. }
  180. dwFreeEntries++;
  181. dw = static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(m_NameTableArray[dw].pNameTableEntry));
  182. } while (dw != 0);
  183. if (dwFreeEntries != m_dwNumFreeEntries)
  184. {
  185. DPFERR("Incorrect number of free entries in NameTable array free list");
  186. DNASSERT(FALSE);
  187. }
  188. }
  189. Unlock();
  190. }
  191. #endif // DBG
  192. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  193. #undef DPF_MODNAME
  194. #define DPF_MODNAME "CNameTable::SetNameTableSize"
  195. HRESULT CNameTable::SetNameTableSize( const DWORD dwNumEntries )
  196. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  197. #undef DPF_MODNAME
  198. #define DPF_MODNAME "CNameTable::GrowNameTable"
  199. HRESULT CNameTable::GrowNameTable( void )
  200. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  201. {
  202. NAMETABLE_ARRAY_ENTRY *pNewArray;
  203. DWORD dwNewSize;
  204. DWORD dw;
  205. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  206. DNASSERT(m_dwNameTableSize == 0);
  207. dwNewSize = dwNumEntries + 1; // + 1 because we never hand out entry 0
  208. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  209. if (m_dwNameTableSize == 0)
  210. {
  211. dwNewSize = 2;
  212. }
  213. else
  214. {
  215. dwNewSize = m_dwNameTableSize * 2;
  216. }
  217. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  218. // Allocate new array
  219. pNewArray = static_cast<NAMETABLE_ARRAY_ENTRY*>(DNMalloc(sizeof(NAMETABLE_ARRAY_ENTRY) * dwNewSize));
  220. if (pNewArray == NULL)
  221. {
  222. return(DPNERR_OUTOFMEMORY);
  223. }
  224. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  225. if (m_dwNameTableSize > 0)
  226. {
  227. DNASSERT(m_NameTableArray != NULL);
  228. // Copy old array to new array
  229. memcpy(pNewArray, m_NameTableArray, (sizeof(NAMETABLE_ARRAY_ENTRY) * m_dwNameTableSize));
  230. }
  231. else
  232. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  233. {
  234. DNASSERT(m_NameTableArray == NULL);
  235. }
  236. //
  237. // If the array is being grown because there are no free entries, then all of the new free
  238. // entries will be in the new part of the array. Otherwise, we will need to link the old
  239. // free list to the new one
  240. //
  241. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  242. if (m_dwNumFreeEntries != 0)
  243. {
  244. // Only new free entries at end of new array
  245. pNewArray[m_dwLastFreeEntry].pNameTableEntry = reinterpret_cast<CNameTableEntry*>(static_cast<DWORD_PTR>(m_dwNameTableSize));
  246. }
  247. else
  248. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  249. {
  250. // All free entries at end of new array
  251. m_dwFirstFreeEntry = m_dwNameTableSize;
  252. }
  253. m_dwLastFreeEntry = dwNewSize-1;
  254. // Very last FREE entry will not wrap to 0
  255. pNewArray[m_dwLastFreeEntry].pNameTableEntry = reinterpret_cast<CNameTableEntry*>(0);
  256. pNewArray[m_dwLastFreeEntry].dwFlags = 0;
  257. // Link new FREE entries
  258. for (dw = m_dwNameTableSize ; dw < m_dwLastFreeEntry ; dw++)
  259. {
  260. pNewArray[dw].pNameTableEntry = reinterpret_cast<CNameTableEntry*>(static_cast<DWORD_PTR>(dw+1));
  261. pNewArray[dw].dwFlags = 0;
  262. }
  263. // Update NameTable
  264. m_dwNumFreeEntries += (dwNewSize - m_dwNameTableSize);
  265. m_dwNameTableSize = dwNewSize;
  266. // New array
  267. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  268. if (m_NameTableArray)
  269. {
  270. DNFree(m_NameTableArray);
  271. }
  272. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  273. m_NameTableArray = pNewArray;
  274. // We will never allocate 0
  275. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  276. if (m_dwFirstFreeEntry == 0)
  277. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  278. {
  279. m_dwFirstFreeEntry = static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(m_NameTableArray[m_dwFirstFreeEntry].pNameTableEntry));
  280. DNASSERT(m_dwNumFreeEntries > 0);
  281. m_dwNumFreeEntries--;
  282. }
  283. // We will never allocate 1 either, for backwards compatibility
  284. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  285. if (m_dwFirstFreeEntry == 1)
  286. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  287. {
  288. m_dwFirstFreeEntry = static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(m_NameTableArray[m_dwFirstFreeEntry].pNameTableEntry));
  289. DNASSERT(m_dwNumFreeEntries > 0);
  290. m_dwNumFreeEntries--;
  291. }
  292. return(DPN_OK);
  293. }
  294. #undef DPF_MODNAME
  295. #define DPF_MODNAME "CNameTable::ResetNameTable"
  296. void CNameTable::ResetNameTable( void )
  297. {
  298. DNASSERT(m_pdnObject != NULL);
  299. DNASSERT(m_pDefaultPlayer != NULL);
  300. DNASSERT(m_pLocalPlayer == NULL);
  301. DNASSERT(m_pHostPlayer == NULL);
  302. DNASSERT(m_pAllPlayersGroup == NULL);
  303. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  304. DNASSERT(m_NameTableArray != NULL);
  305. DNASSERT(m_dwNameTableSize > 0);
  306. DNASSERT(m_dwNumFreeEntries == (m_dwNameTableSize - 1));
  307. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  308. m_dpnidMask = 0;
  309. m_dwVersion = 1;
  310. m_dwLatestVersion = 0;
  311. m_dwConnectVersion = 0;
  312. m_lOutstandingConnections = 0;
  313. #pragma TODO(vanceo, "Should we bother?")
  314. /*
  315. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  316. if (m_NameTableArray != NULL)
  317. {
  318. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  319. // Re-link the FREE entries in order.
  320. m_dwLastFreeEntry = m_dwNameTableSize - 1;
  321. // Very last FREE entry will not wrap to 0
  322. pNewArray[m_dwLastFreeEntry].pNameTableEntry = reinterpret_cast<CNameTableEntry*>(0);
  323. pNewArray[m_dwLastFreeEntry].dwFlags = 0;
  324. for (dw = 0 ; dw < m_dwLastFreeEntry ; dw++)
  325. {
  326. pNewArray[dw].pNameTableEntry = reinterpret_cast<CNameTableEntry*>(static_cast<DWORD_PTR>(dw+1));
  327. pNewArray[dw].dwFlags = 0;
  328. }
  329. m_dwFirstFreeEntry = static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(m_NameTableArray[0].pNameTableEntry));
  330. }
  331. */
  332. }
  333. #undef DPF_MODNAME
  334. #define DPF_MODNAME "CNameTable::UpdateTable"
  335. HRESULT CNameTable::UpdateTable(const DWORD dwIndex,
  336. CNameTableEntry *const pNameTableEntry)
  337. {
  338. BOOL bFound;
  339. DWORD dw;
  340. DNASSERT(dwIndex < m_dwNameTableSize);
  341. DNASSERT(!(m_NameTableArray[dwIndex].dwFlags & NAMETABLE_ARRAY_ENTRY_FLAG_VALID));
  342. if (m_dwFirstFreeEntry == dwIndex)
  343. {
  344. m_dwFirstFreeEntry = static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(m_NameTableArray[m_dwFirstFreeEntry].pNameTableEntry));
  345. bFound = TRUE;
  346. }
  347. else
  348. {
  349. bFound = FALSE;
  350. dw = m_dwFirstFreeEntry;
  351. while (!bFound && (dw != m_dwLastFreeEntry))
  352. {
  353. if (m_NameTableArray[dw].pNameTableEntry == reinterpret_cast<CNameTableEntry*>(static_cast<DWORD_PTR>(dwIndex)))
  354. {
  355. m_NameTableArray[dw].pNameTableEntry = m_NameTableArray[dwIndex].pNameTableEntry;
  356. if (m_dwLastFreeEntry == dwIndex)
  357. {
  358. m_dwLastFreeEntry = dw;
  359. }
  360. bFound = TRUE;
  361. }
  362. else
  363. {
  364. dw = static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(m_NameTableArray[dw].pNameTableEntry));
  365. }
  366. }
  367. }
  368. if (!bFound)
  369. {
  370. return(DPNERR_GENERIC);
  371. }
  372. pNameTableEntry->AddRef();
  373. m_NameTableArray[dwIndex].pNameTableEntry = pNameTableEntry;
  374. m_NameTableArray[dwIndex].dwFlags |= NAMETABLE_ARRAY_ENTRY_FLAG_VALID;
  375. //
  376. // Insert into entry bilink
  377. //
  378. if (pNameTableEntry->IsGroup())
  379. {
  380. pNameTableEntry->m_bilinkEntries.InsertBefore(&m_bilinkGroups);
  381. }
  382. else
  383. {
  384. pNameTableEntry->m_bilinkEntries.InsertBefore(&m_bilinkPlayers);
  385. }
  386. DNASSERT(m_dwNumFreeEntries > 0);
  387. m_dwNumFreeEntries--;
  388. return(DPN_OK);
  389. }
  390. #undef DPF_MODNAME
  391. #define DPF_MODNAME "CNameTable::InsertEntry"
  392. HRESULT CNameTable::InsertEntry(CNameTableEntry *const pNameTableEntry)
  393. {
  394. HRESULT hResultCode;
  395. DWORD dwIndex;
  396. DNASSERT(pNameTableEntry != NULL);
  397. DNASSERT(pNameTableEntry->GetDPNID() != 0);
  398. dwIndex = DECODE_INDEX(pNameTableEntry->GetDPNID());
  399. WriteLock();
  400. while (dwIndex >= m_dwNameTableSize)
  401. {
  402. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  403. if (GrowNameTable() != DPN_OK)
  404. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  405. {
  406. Unlock();
  407. DNASSERTX(! "Couldn't fit entry into nametable!", 2);
  408. return(DPNERR_OUTOFMEMORY);
  409. }
  410. }
  411. if ((hResultCode = UpdateTable(dwIndex,pNameTableEntry)) != DPN_OK)
  412. {
  413. Unlock();
  414. return(DPNERR_GENERIC);
  415. }
  416. Unlock();
  417. #ifdef DBG
  418. ValidateArray();
  419. #endif // DBG
  420. return(DPN_OK);
  421. }
  422. #undef DPF_MODNAME
  423. #define DPF_MODNAME "CNameTable::ReleaseEntry"
  424. void CNameTable::ReleaseEntry(const DWORD dwIndex)
  425. {
  426. CNameTableEntry *pNTEntry;
  427. DNASSERT(dwIndex != 0);
  428. pNTEntry = m_NameTableArray[dwIndex].pNameTableEntry;
  429. m_NameTableArray[dwIndex].pNameTableEntry = NULL;
  430. pNTEntry->m_bilinkEntries.RemoveFromList();
  431. pNTEntry->Release();
  432. if (m_dwNumFreeEntries == 0)
  433. {
  434. m_dwFirstFreeEntry = dwIndex;
  435. }
  436. else
  437. {
  438. m_NameTableArray[m_dwLastFreeEntry].pNameTableEntry = reinterpret_cast<CNameTableEntry*>(static_cast<DWORD_PTR>(dwIndex));
  439. }
  440. m_dwLastFreeEntry = dwIndex;
  441. m_NameTableArray[m_dwLastFreeEntry].dwFlags &= (~NAMETABLE_ARRAY_ENTRY_FLAG_VALID);
  442. m_dwNumFreeEntries++;
  443. }
  444. #undef DPF_MODNAME
  445. #define DPF_MODNAME "CNameTable::EmptyTable"
  446. void CNameTable::EmptyTable( const HRESULT hrReason )
  447. {
  448. DWORD dw;
  449. CNameTableEntry *pNTEntry;
  450. DWORD dwGroupReason;
  451. DWORD dwPlayerReason;
  452. CBilink *pBilink;
  453. CQueuedMsg *pQueuedMsg;
  454. DPFX(DPFPREP, 6,"Parameters: hrReason [0x%lx]",hrReason);
  455. DNASSERT( (hrReason == DPN_OK) || (hrReason == DPNERR_HOSTTERMINATEDSESSION) || (hrReason == DPNERR_CONNECTIONLOST));
  456. if (!(m_pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT))
  457. {
  458. //
  459. // Determine destruction reason to pass to application
  460. //
  461. switch (hrReason)
  462. {
  463. case DPN_OK:
  464. {
  465. dwPlayerReason = DPNDESTROYPLAYERREASON_NORMAL;
  466. dwGroupReason = DPNDESTROYGROUPREASON_NORMAL;
  467. break;
  468. }
  469. case DPNERR_HOSTTERMINATEDSESSION:
  470. {
  471. dwPlayerReason = DPNDESTROYPLAYERREASON_SESSIONTERMINATED;
  472. dwGroupReason = DPNDESTROYGROUPREASON_SESSIONTERMINATED;
  473. break;
  474. }
  475. case DPNERR_CONNECTIONLOST:
  476. {
  477. dwPlayerReason = DPNDESTROYPLAYERREASON_CONNECTIONLOST;
  478. dwGroupReason = DPNDESTROYGROUPREASON_NORMAL;
  479. break;
  480. }
  481. default:
  482. {
  483. DNASSERT( FALSE ); // Should never get here !
  484. dwPlayerReason = DPNDESTROYPLAYERREASON_NORMAL;
  485. dwGroupReason = DPNDESTROYGROUPREASON_NORMAL;
  486. break;
  487. }
  488. }
  489. //
  490. // To make VanceO happy, I've agreed to pre-mark the group destructions as NORMAL,
  491. // rather than AUTODESTRUCT
  492. //
  493. ReadLock();
  494. pBilink = m_bilinkGroups.GetNext();
  495. while (pBilink != &m_bilinkGroups)
  496. {
  497. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  498. pNTEntry->Lock();
  499. if (pNTEntry->GetDestroyReason() == 0)
  500. {
  501. pNTEntry->SetDestroyReason( dwGroupReason );
  502. }
  503. pNTEntry->Unlock();
  504. pNTEntry = NULL;
  505. pBilink = pBilink->GetNext();
  506. }
  507. Unlock();
  508. for (dw = 0 ; dw < m_dwNameTableSize ; dw++)
  509. {
  510. pNTEntry = NULL;
  511. ReadLock();
  512. if ((m_NameTableArray[dw].dwFlags & NAMETABLE_ARRAY_ENTRY_FLAG_VALID) &&
  513. (m_NameTableArray[dw].pNameTableEntry))
  514. {
  515. //
  516. // Cleanup this entry (if it's not disconnecting) and then release it
  517. //
  518. m_NameTableArray[dw].pNameTableEntry->Lock();
  519. if (!m_NameTableArray[dw].pNameTableEntry->IsDisconnecting())
  520. {
  521. m_NameTableArray[dw].pNameTableEntry->AddRef();
  522. pNTEntry = m_NameTableArray[dw].pNameTableEntry;
  523. }
  524. m_NameTableArray[dw].pNameTableEntry->Unlock();
  525. Unlock();
  526. if (pNTEntry)
  527. {
  528. //
  529. // Set destroy reason if required
  530. //
  531. pNTEntry->Lock();
  532. if (pNTEntry->GetDestroyReason() == 0)
  533. {
  534. if (pNTEntry->IsGroup())
  535. {
  536. pNTEntry->SetDestroyReason( dwGroupReason );
  537. }
  538. else
  539. {
  540. pNTEntry->SetDestroyReason( dwPlayerReason );
  541. }
  542. }
  543. pNTEntry->Unlock();
  544. //
  545. // Delete entry
  546. //
  547. if (pNTEntry->IsGroup())
  548. {
  549. if (!pNTEntry->IsAllPlayersGroup())
  550. {
  551. DeleteGroup(pNTEntry->GetDPNID(),NULL);
  552. }
  553. }
  554. else
  555. {
  556. CConnection *pConnection;
  557. pConnection = NULL;
  558. pNTEntry->GetConnectionRef( &pConnection );
  559. if (pConnection)
  560. {
  561. pConnection->Disconnect();
  562. pConnection->Release();
  563. pConnection = NULL;
  564. }
  565. DeletePlayer(pNTEntry->GetDPNID(),NULL);
  566. }
  567. pNTEntry->Release();
  568. pNTEntry = NULL;
  569. }
  570. }
  571. else
  572. {
  573. Unlock();
  574. }
  575. }
  576. //
  577. // Set reason for short-cut pointers (if required)
  578. //
  579. ReadLock();
  580. if (m_pLocalPlayer)
  581. {
  582. m_pLocalPlayer->Lock();
  583. if (m_pLocalPlayer->GetDestroyReason() == 0)
  584. {
  585. m_pLocalPlayer->SetDestroyReason( dwPlayerReason );
  586. }
  587. m_pLocalPlayer->Unlock();
  588. }
  589. if (m_pHostPlayer)
  590. {
  591. m_pHostPlayer->Lock();
  592. if (m_pHostPlayer->GetDestroyReason() == 0)
  593. {
  594. m_pHostPlayer->SetDestroyReason( dwPlayerReason );
  595. }
  596. m_pHostPlayer->Unlock();
  597. }
  598. if (m_pAllPlayersGroup)
  599. {
  600. m_pAllPlayersGroup->Lock();
  601. if (m_pAllPlayersGroup->GetDestroyReason() == 0)
  602. {
  603. m_pAllPlayersGroup->SetDestroyReason( dwGroupReason );
  604. }
  605. m_pAllPlayersGroup->Unlock();
  606. }
  607. Unlock();
  608. }
  609. else
  610. {
  611. //
  612. // Disconnect from Host and remove any queued messages from Host player (on Client)
  613. //
  614. if (GetHostPlayerRef(&pNTEntry) == DPN_OK)
  615. {
  616. CConnection *pConnection;
  617. pConnection = NULL;
  618. pNTEntry->GetConnectionRef( &pConnection );
  619. if (pConnection)
  620. {
  621. pConnection->Disconnect();
  622. pConnection->Release();
  623. pConnection = NULL;
  624. }
  625. pNTEntry->Lock();
  626. pBilink = pNTEntry->m_bilinkQueuedMsgs.GetNext();
  627. while (pBilink != &pNTEntry->m_bilinkQueuedMsgs)
  628. {
  629. pQueuedMsg = CONTAINING_OBJECT(pBilink,CQueuedMsg,m_bilinkQueuedMsgs);
  630. pQueuedMsg->m_bilinkQueuedMsgs.RemoveFromList();
  631. DEBUG_ONLY(pNTEntry->m_lNumQueuedMsgs--);
  632. pNTEntry->Unlock();
  633. DNASSERT(pQueuedMsg->GetAsyncOp() != NULL);
  634. DNASSERT(pQueuedMsg->GetAsyncOp()->GetHandle() != 0);
  635. DNEnterCriticalSection(&m_pdnObject->csActiveList);
  636. pQueuedMsg->GetAsyncOp()->m_bilinkActiveList.RemoveFromList();
  637. DNLeaveCriticalSection(&m_pdnObject->csActiveList);
  638. if (SUCCEEDED(m_pdnObject->HandleTable.Destroy( pQueuedMsg->GetAsyncOp()->GetHandle(), NULL )))
  639. {
  640. // Release the HandleTable reference
  641. pQueuedMsg->GetAsyncOp()->Release();
  642. }
  643. pQueuedMsg->GetAsyncOp()->Release();
  644. pQueuedMsg->SetAsyncOp( NULL );
  645. pQueuedMsg->ReturnSelfToPool();
  646. pQueuedMsg = NULL;
  647. pNTEntry->Lock();
  648. pBilink = pNTEntry->m_bilinkQueuedMsgs.GetNext();
  649. }
  650. pNTEntry->Unlock();
  651. pNTEntry->Release();
  652. pNTEntry = NULL;
  653. DNASSERT(pConnection == NULL);
  654. }
  655. }
  656. //
  657. // Remove short-cut pointers
  658. //
  659. ClearLocalPlayer();
  660. ClearHostPlayer();
  661. ClearAllPlayersGroup();
  662. DPFX(DPFPREP, 6,"Returning");
  663. }
  664. #undef DPF_MODNAME
  665. #define DPF_MODNAME "CNameTable::FindEntry"
  666. HRESULT CNameTable::FindEntry(const DPNID dpnid,
  667. CNameTableEntry **const ppNameTableEntry)
  668. {
  669. DWORD dwIndex;
  670. HRESULT hResultCode;
  671. DPFX(DPFPREP, 6,"Parameters: dpnid [0x%lx], ppNameTableEntry [0x%p]",dpnid,ppNameTableEntry);
  672. DNASSERT(ppNameTableEntry != NULL);
  673. if (dpnid == 0)
  674. {
  675. hResultCode = DPNERR_DOESNOTEXIST;
  676. goto Failure;
  677. }
  678. ReadLock();
  679. dwIndex = DECODE_INDEX(dpnid);
  680. if ((dwIndex >= m_dwNameTableSize)
  681. || !(m_NameTableArray[dwIndex].dwFlags & NAMETABLE_ARRAY_ENTRY_FLAG_VALID)
  682. || (m_NameTableArray[dwIndex].pNameTableEntry == NULL))
  683. {
  684. Unlock();
  685. hResultCode = DPNERR_DOESNOTEXIST;
  686. goto Failure;
  687. }
  688. if (!VERIFY_VERSION(dpnid,m_NameTableArray[dwIndex].pNameTableEntry->GetVersion()))
  689. {
  690. Unlock();
  691. hResultCode = DPNERR_DOESNOTEXIST;
  692. goto Failure;
  693. }
  694. m_NameTableArray[dwIndex].pNameTableEntry->AddRef();
  695. *ppNameTableEntry = m_NameTableArray[dwIndex].pNameTableEntry;
  696. Unlock();
  697. hResultCode = DPN_OK;
  698. Exit:
  699. DPFX(DPFPREP, 6,"hResultCode: [0x%lx]",hResultCode);
  700. return(hResultCode);
  701. Failure:
  702. goto Exit;
  703. }
  704. #undef DPF_MODNAME
  705. #define DPF_MODNAME "CNameTable::FindDeletedEntry"
  706. HRESULT CNameTable::FindDeletedEntry(const DPNID dpnid,
  707. CNameTableEntry **const ppNTEntry)
  708. {
  709. HRESULT hResultCode;
  710. CBilink *pBilink;
  711. CNameTableEntry *pNTEntry;
  712. DPFX(DPFPREP, 6,"Parameters: dpnid [0x%lx], ppNTEntry [0x%p]",dpnid,ppNTEntry);
  713. DNASSERT(ppNTEntry != NULL);
  714. pNTEntry = NULL;
  715. hResultCode = DPNERR_DOESNOTEXIST;
  716. ReadLock();
  717. pBilink = m_bilinkDeleted.GetNext();
  718. while (pBilink != &m_bilinkDeleted)
  719. {
  720. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkDeleted);
  721. if (pNTEntry->GetDPNID() == dpnid)
  722. {
  723. pNTEntry->AddRef();
  724. hResultCode = DPN_OK;
  725. break;
  726. }
  727. else
  728. {
  729. pBilink = pBilink->GetNext();
  730. pNTEntry = NULL;
  731. }
  732. }
  733. Unlock();
  734. if (pNTEntry)
  735. {
  736. pNTEntry->AddRef();
  737. *ppNTEntry = pNTEntry;
  738. pNTEntry->Release();
  739. pNTEntry = NULL;
  740. }
  741. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  742. return(hResultCode);
  743. }
  744. #undef DPF_MODNAME
  745. #define DPF_MODNAME "CNameTable::AddEntry"
  746. HRESULT CNameTable::AddEntry(CNameTableEntry *const pNTEntry)
  747. {
  748. DPNID dpnid;
  749. DWORD dwIndex;
  750. DWORD dwVersion;
  751. HRESULT hResultCode;
  752. WriteLock();
  753. //
  754. // Create DPNID
  755. //
  756. while (m_dwNumFreeEntries == 0)
  757. {
  758. #ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
  759. if (GrowNameTable() != DPN_OK)
  760. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  761. {
  762. DNASSERTX(! "No free slots in name table!", 2);
  763. Unlock();
  764. return(DPNERR_OUTOFMEMORY);
  765. }
  766. }
  767. DNASSERT(m_dwFirstFreeEntry != 0);
  768. dwIndex = m_dwFirstFreeEntry;
  769. dwVersion = ++m_dwVersion;
  770. DPFX(DPFPREP, 8,"Setting new version [%ld]",m_dwVersion);
  771. dpnid = CONSTRUCT_DPNID(dwIndex,dwVersion);
  772. DNASSERT(dpnid != 0);
  773. pNTEntry->Lock();
  774. pNTEntry->SetDPNID(dpnid);
  775. pNTEntry->SetVersion(dwVersion);
  776. pNTEntry->Unlock();
  777. dwIndex = DECODE_INDEX(dpnid);
  778. hResultCode = UpdateTable(dwIndex,pNTEntry);
  779. Unlock();
  780. #ifdef DBG
  781. ValidateArray();
  782. #endif // DBG
  783. return(hResultCode);
  784. }
  785. #undef DPF_MODNAME
  786. #define DPF_MODNAME "CNameTable::DeletePlayer"
  787. HRESULT CNameTable::DeletePlayer(const DPNID dpnid,
  788. DWORD *const pdwVersion)
  789. {
  790. HRESULT hResultCode;
  791. CNameTableEntry *pNTEntry;
  792. BOOL fNotifyRelease;
  793. BOOL fDecConnections;
  794. DPFX(DPFPREP, 6,"Parameters: dpnid [0x%lx], pdwVersion [0x%p]",dpnid,pdwVersion);
  795. pNTEntry = NULL;
  796. fNotifyRelease = FALSE;
  797. fDecConnections = FALSE;
  798. if ((hResultCode = FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  799. {
  800. DPFERR("Player not in NameTable");
  801. DisplayDNError(0,hResultCode);
  802. //
  803. // If a version is requested, we will give one back. This might be a host migration case
  804. // in which case even though the player was removed from the NameTable, we will want to
  805. // send out a DESTROY_PLAYER message with an updated version number
  806. //
  807. if (pdwVersion)
  808. {
  809. if (*pdwVersion == 0)
  810. {
  811. WriteLock();
  812. *pdwVersion = ++m_dwVersion;
  813. DPFX(DPFPREP, 8,"Setting new version [%ld]",m_dwVersion);
  814. Unlock();
  815. }
  816. }
  817. goto Failure;
  818. }
  819. DNASSERT(!pNTEntry->IsGroup());
  820. //
  821. // Don't do anything if already disconnecting.
  822. // Otherwise, set disconnecting to prevent others from cleaning up, and clean up
  823. //
  824. pNTEntry->Lock();
  825. if (!pNTEntry->IsDisconnecting())
  826. {
  827. pNTEntry->StartDisconnecting();
  828. if (pNTEntry->IsAvailable())
  829. {
  830. pNTEntry->MakeUnavailable();
  831. }
  832. if ((pNTEntry->IsCreated() || pNTEntry->IsIndicated() || pNTEntry->IsInUse()) && !pNTEntry->IsNeedToDestroy())
  833. {
  834. pNTEntry->SetNeedToDestroy();
  835. fNotifyRelease = TRUE;
  836. }
  837. if ( !pNTEntry->IsCreated()
  838. && pNTEntry->IsConnecting()
  839. && (m_pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_CONNECTED))
  840. && (pNTEntry->GetVersion() <= m_dwConnectVersion))
  841. {
  842. fDecConnections = TRUE;
  843. }
  844. pNTEntry->Unlock();
  845. //
  846. // Remove this player from any groups they belong to
  847. //
  848. RemoveAllGroupsFromPlayer( pNTEntry );
  849. //
  850. // Autodestruct any groups this player owns (will also remove any players from those groups first)
  851. //
  852. if (pNTEntry->GetDPNID() != 0)
  853. {
  854. AutoDestructGroups( pNTEntry->GetDPNID() );
  855. }
  856. if (fNotifyRelease)
  857. {
  858. pNTEntry->NotifyRelease();
  859. }
  860. //
  861. // Adjust player count
  862. //
  863. m_pdnObject->ApplicationDesc.DecPlayerCount();
  864. if (fDecConnections)
  865. {
  866. DecOutstandingConnections();
  867. }
  868. //
  869. // Update version and remove from NameTable
  870. //
  871. WriteLock();
  872. pNTEntry->Lock();
  873. if ((pNTEntry->IsCreated() || pNTEntry->IsInUse()) && pNTEntry->IsNeedToDestroy())
  874. {
  875. //
  876. // The DESTROY_PLAYER message has not been posted, so we will add this entry to our "deleted" list
  877. // so that some future operations (get info,context,etc.) may succeed. This entry will be removed
  878. // from the list then the DESTROY_PLAYER notification is posted
  879. //
  880. pNTEntry->m_bilinkDeleted.InsertBefore(&m_bilinkDeleted);
  881. pNTEntry->Unlock();
  882. ReleaseEntry(DECODE_INDEX(dpnid));
  883. //
  884. // Update version
  885. //
  886. if (pdwVersion)
  887. {
  888. if (*pdwVersion)
  889. {
  890. m_dwVersion = *pdwVersion;
  891. }
  892. else
  893. {
  894. *pdwVersion = ++m_dwVersion;
  895. }
  896. DPFX(DPFPREP, 8,"Setting new version [%ld]",m_dwVersion);
  897. }
  898. Unlock();
  899. }
  900. else
  901. {
  902. CBilink *pBilink;
  903. CQueuedMsg *pQueuedMsg;
  904. //
  905. // Remove any queued messages at this stage. A CREATE_PLAYER won't be generated, so no messages
  906. // will be passed up.
  907. //
  908. // This is probably wrong since for reliable traffic, we assume it got here
  909. //
  910. Unlock();
  911. #pragma BUGBUG(minara,"This is probably wrong since reliable traffic should be indicated rather than just thrown away!")
  912. pBilink = pNTEntry->m_bilinkQueuedMsgs.GetNext();
  913. while (pBilink != &pNTEntry->m_bilinkQueuedMsgs)
  914. {
  915. pQueuedMsg = CONTAINING_OBJECT(pBilink,CQueuedMsg,m_bilinkQueuedMsgs);
  916. pQueuedMsg->m_bilinkQueuedMsgs.RemoveFromList();
  917. DEBUG_ONLY(pNTEntry->m_lNumQueuedMsgs--);
  918. pNTEntry->Unlock();
  919. DNASSERT(pQueuedMsg->GetAsyncOp() != NULL);
  920. DNASSERT(pQueuedMsg->GetAsyncOp()->GetHandle() != 0);
  921. DNDoCancelCommand( m_pdnObject,pQueuedMsg->GetAsyncOp() );
  922. pQueuedMsg->GetAsyncOp()->Release();
  923. pQueuedMsg->SetAsyncOp( NULL );
  924. pQueuedMsg->ReturnSelfToPool();
  925. pQueuedMsg = NULL;
  926. pNTEntry->Lock();
  927. pBilink = pNTEntry->m_bilinkQueuedMsgs.GetNext();
  928. }
  929. pNTEntry->Unlock();
  930. //
  931. // Update version
  932. //
  933. WriteLock();
  934. ReleaseEntry(DECODE_INDEX(dpnid));
  935. if (pdwVersion)
  936. {
  937. if (*pdwVersion)
  938. {
  939. m_dwVersion = *pdwVersion;
  940. }
  941. else
  942. {
  943. *pdwVersion = ++m_dwVersion;
  944. }
  945. DPFX(DPFPREP, 8,"Setting new version [%ld]",m_dwVersion);
  946. }
  947. Unlock();
  948. }
  949. hResultCode = DPN_OK;
  950. }
  951. else
  952. {
  953. pNTEntry->Unlock();
  954. hResultCode = DPNERR_INVALIDPLAYER;
  955. }
  956. pNTEntry->Release();
  957. pNTEntry = NULL;
  958. Exit:
  959. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  960. return(hResultCode);
  961. Failure:
  962. if (pNTEntry)
  963. {
  964. pNTEntry->Release();
  965. pNTEntry = NULL;
  966. }
  967. goto Exit;
  968. }
  969. #undef DPF_MODNAME
  970. #define DPF_MODNAME "CNameTable::DeleteGroup"
  971. HRESULT CNameTable::DeleteGroup(const DPNID dpnid,
  972. DWORD *const pdwVersion)
  973. {
  974. HRESULT hResultCode;
  975. CNameTableEntry *pNTEntry;
  976. BOOL fNotifyRelease;
  977. DPFX(DPFPREP, 6,"Parameters: dpnid [0x%lx], pdwVersion [0x%p]",dpnid,pdwVersion);
  978. pNTEntry = NULL;
  979. fNotifyRelease = FALSE;
  980. if ((hResultCode = FindEntry(dpnid,&pNTEntry)) != DPN_OK)
  981. {
  982. DPFERR("Player not in NameTable");
  983. DisplayDNError(0,hResultCode);
  984. return(hResultCode);
  985. }
  986. DNASSERT(pNTEntry->IsGroup() && !pNTEntry->IsAllPlayersGroup());
  987. //
  988. // Don't do anything if already disconnecting.
  989. // Otherwise, set disconnecting to prevent others from cleaning up, and clean up
  990. //
  991. pNTEntry->Lock();
  992. if (pNTEntry->GetDestroyReason() == 0)
  993. {
  994. //
  995. // Default this if it isn't set
  996. //
  997. pNTEntry->SetDestroyReason( DPNDESTROYGROUPREASON_NORMAL );
  998. }
  999. if (!pNTEntry->IsDisconnecting())
  1000. {
  1001. pNTEntry->StartDisconnecting();
  1002. if (pNTEntry->IsAvailable())
  1003. {
  1004. pNTEntry->MakeUnavailable();
  1005. }
  1006. if (pNTEntry->IsCreated() && !pNTEntry->IsNeedToDestroy())
  1007. {
  1008. pNTEntry->SetNeedToDestroy();
  1009. fNotifyRelease = TRUE;
  1010. }
  1011. pNTEntry->Unlock();
  1012. RemoveAllPlayersFromGroup( pNTEntry );
  1013. if (fNotifyRelease)
  1014. {
  1015. pNTEntry->NotifyRelease();
  1016. }
  1017. //
  1018. // Update version and remove from NameTable
  1019. //
  1020. WriteLock();
  1021. pNTEntry->Lock();
  1022. if (pNTEntry->IsNeedToDestroy())
  1023. {
  1024. //
  1025. // The DESTROY_GROUP message has not been posted, so we will add this entry to our "deleted" list
  1026. // so that some future operations (get info,context,etc.) may succeed. This entry will be removed
  1027. // from the list then the DESTROY_GROUP notification is posted
  1028. //
  1029. pNTEntry->m_bilinkDeleted.InsertBefore(&m_bilinkDeleted);
  1030. }
  1031. pNTEntry->Unlock();
  1032. ReleaseEntry(DECODE_INDEX(dpnid));
  1033. if (pdwVersion)
  1034. {
  1035. if (*pdwVersion)
  1036. {
  1037. m_dwVersion = *pdwVersion;
  1038. }
  1039. else
  1040. {
  1041. *pdwVersion = ++m_dwVersion;
  1042. }
  1043. DPFX(DPFPREP, 8,"Setting new version [%ld]",m_dwVersion);
  1044. }
  1045. Unlock();
  1046. hResultCode = DPN_OK;
  1047. }
  1048. else
  1049. {
  1050. pNTEntry->Unlock();
  1051. hResultCode = DPNERR_INVALIDGROUP;
  1052. }
  1053. pNTEntry->Release();
  1054. pNTEntry = NULL;
  1055. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1056. return(hResultCode);
  1057. }
  1058. #undef DPF_MODNAME
  1059. #define DPF_MODNAME "CNameTable::AddPlayerToGroup"
  1060. HRESULT CNameTable::AddPlayerToGroup(CNameTableEntry *const pGroup,
  1061. CNameTableEntry *const pPlayer,
  1062. DWORD *const pdwVersion)
  1063. {
  1064. HRESULT hResultCode;
  1065. CGroupMember *pGroupMember;
  1066. CGroupConnection *pGroupConnection;
  1067. CConnection *pConnection;
  1068. BOOL fNotifyAdd;
  1069. BOOL fRemove;
  1070. DPFX(DPFPREP, 6,"Parameters: pGroup [0x%p], pPlayer [0x%p], pdwVersion [0x%p]",pGroup,pPlayer,pdwVersion);
  1071. DNASSERT(pGroup != NULL);
  1072. DNASSERT(pPlayer != NULL);
  1073. pGroupConnection = NULL;
  1074. pGroupMember = NULL;
  1075. pConnection = NULL;
  1076. if (!pGroup->IsGroup())
  1077. {
  1078. hResultCode = DPNERR_INVALIDGROUP;
  1079. goto Failure;
  1080. }
  1081. if (pPlayer->IsGroup())
  1082. {
  1083. hResultCode = DPNERR_INVALIDPLAYER;
  1084. goto Failure;
  1085. }
  1086. //
  1087. // Create the group connection
  1088. //
  1089. if ((hResultCode = GroupConnectionNew(m_pdnObject,&pGroupConnection)) != DPN_OK)
  1090. {
  1091. DPFERR("Could not allocate name table group connection entry from FPM");
  1092. DisplayDNError(0,hResultCode);
  1093. DNASSERT(FALSE);
  1094. goto Failure;
  1095. }
  1096. pGroupConnection->SetGroup( pGroup );
  1097. //
  1098. // Create new group membership record
  1099. //
  1100. if ((hResultCode = GroupMemberNew(m_pdnObject,&pGroupMember)) != DPN_OK)
  1101. {
  1102. DPFERR("Could not get new group member");
  1103. DisplayDNError(0,hResultCode);
  1104. DNASSERT(FALSE);
  1105. goto Failure;
  1106. }
  1107. //
  1108. // Set group connection on group membership record
  1109. //
  1110. pGroupMember->SetGroupConnection(pGroupConnection);
  1111. //
  1112. // Add player to group
  1113. //
  1114. fNotifyAdd = FALSE;
  1115. fRemove = FALSE;
  1116. WriteLock();
  1117. pGroup->Lock();
  1118. pPlayer->Lock();
  1119. pGroupMember->Lock();
  1120. if (!pGroup->IsDisconnecting() && !pPlayer->IsDisconnecting())
  1121. {
  1122. pGroupMember->MakeValid();
  1123. pGroupMember->GetGroupConnection()->MakeValid();
  1124. //
  1125. // Set group membership (checks for duplicates as well)
  1126. //
  1127. if ((hResultCode = pGroupMember->SetMembership(pGroup,pPlayer,pdwVersion)) != DPN_OK)
  1128. {
  1129. DPFERR("Could not set membership record");
  1130. DisplayDNError(0,hResultCode);
  1131. Unlock();
  1132. pGroup->Unlock();
  1133. pPlayer->Unlock();
  1134. pGroupMember->Unlock();
  1135. goto Failure;
  1136. }
  1137. //
  1138. // Generate notification (ALL_PLAYERS GROUP should never be "Created")
  1139. //
  1140. if (pGroup->IsCreated() && pPlayer->IsCreated())
  1141. {
  1142. //
  1143. // Add the player's connection to the group connection record
  1144. //
  1145. if (pPlayer->GetConnection() != NULL)
  1146. {
  1147. pGroupConnection->SetConnection( pPlayer->GetConnection() );
  1148. }
  1149. if (!pGroupMember->IsNeedToAdd() && !pGroupMember->IsAvailable() && pGroupMember->GetGroupConnection()->IsConnected())
  1150. {
  1151. pGroupMember->SetNeedToAdd();
  1152. fNotifyAdd = TRUE;
  1153. }
  1154. }
  1155. //
  1156. // Need to set up the group connection if this is the ALL_PLAYERS group
  1157. //
  1158. if (pGroup->IsAllPlayersGroup())
  1159. {
  1160. if (pPlayer->GetConnection() != NULL)
  1161. {
  1162. pGroupConnection->SetConnection( pPlayer->GetConnection() );
  1163. }
  1164. }
  1165. //
  1166. // Prevent a DESTROY_PLAYER/DESTROY_GROUP from occurring until this GroupMember record is cleared
  1167. //
  1168. pGroup->NotifyAddRef();
  1169. pPlayer->NotifyAddRef();
  1170. }
  1171. Unlock();
  1172. pGroup->Unlock();
  1173. pPlayer->Unlock();
  1174. pGroupMember->Unlock();
  1175. if (fNotifyAdd)
  1176. {
  1177. DNUserAddPlayerToGroup(m_pdnObject,pGroup,pPlayer);
  1178. pGroupMember->Lock();
  1179. pGroupMember->ClearNeedToAdd();
  1180. pGroupMember->MakeAvailable();
  1181. if (pGroupMember->IsNeedToRemove())
  1182. {
  1183. fRemove = TRUE;
  1184. }
  1185. pGroupMember->Unlock();
  1186. }
  1187. if (fRemove)
  1188. {
  1189. RemovePlayerFromGroup(pGroup,pPlayer,NULL);
  1190. }
  1191. pGroupConnection->Release();
  1192. pGroupConnection = NULL;
  1193. pGroupMember->Release();
  1194. pGroupMember = NULL;
  1195. hResultCode = DPN_OK;
  1196. Exit:
  1197. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1198. return(hResultCode);
  1199. Failure:
  1200. if (pGroupConnection)
  1201. {
  1202. pGroupConnection->Release();
  1203. pGroupConnection = NULL;
  1204. }
  1205. if (pGroupMember)
  1206. {
  1207. pGroupMember->Release();
  1208. pGroupMember = NULL;
  1209. }
  1210. if (pConnection)
  1211. {
  1212. pConnection->Release();
  1213. pConnection = NULL;
  1214. }
  1215. goto Exit;
  1216. }
  1217. #undef DPF_MODNAME
  1218. #define DPF_MODNAME "CNameTable::RemovePlayerFromGroup"
  1219. HRESULT CNameTable::RemovePlayerFromGroup(CNameTableEntry *const pGroup,
  1220. CNameTableEntry *const pPlayer,
  1221. DWORD *const pdwVersion)
  1222. {
  1223. CGroupMember *pGroupMember;
  1224. CBilink *pBilink;
  1225. BOOL fNotifyRemove;
  1226. HRESULT hResultCode;
  1227. DPFX(DPFPREP, 6,"Parameters: pGroup [0x%p], pPlayer [0x%p], pdwVersion [0x%p]",pGroup,pPlayer,pdwVersion);
  1228. DNASSERT(pGroup != NULL);
  1229. DNASSERT(pPlayer != NULL);
  1230. pGroupMember = NULL;
  1231. fNotifyRemove = FALSE;
  1232. WriteLock();
  1233. pGroup->Lock();
  1234. pPlayer->Lock();
  1235. //
  1236. // The first order of business is to locate the GroupMembership record.
  1237. // We will use the player's NameTable entry and scan through the
  1238. // group membership bilink until we find the required entry.
  1239. // (We're assuming that this will be faster than going the other route.)
  1240. //
  1241. pBilink = pPlayer->m_bilinkMembership.GetNext();
  1242. while (pBilink != &pPlayer->m_bilinkMembership)
  1243. {
  1244. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkGroups);
  1245. if (pGroupMember->GetGroup() == pGroup)
  1246. {
  1247. pGroupMember->AddRef();
  1248. break;
  1249. }
  1250. pGroupMember = NULL;
  1251. pBilink = pBilink->GetNext();
  1252. }
  1253. if (pGroupMember == NULL)
  1254. {
  1255. Unlock();
  1256. pGroup->Unlock();
  1257. pPlayer->Unlock();
  1258. hResultCode = DPNERR_PLAYERNOTINGROUP;
  1259. goto Failure;
  1260. }
  1261. DNASSERT(pGroupMember != NULL);
  1262. pGroupMember->Lock();
  1263. //
  1264. // Ensure no one else is trying to remove this already
  1265. //
  1266. if (!pGroupMember->IsValid() || pGroupMember->IsNeedToRemove())
  1267. {
  1268. Unlock();
  1269. pGroup->Unlock();
  1270. pPlayer->Unlock();
  1271. pGroupMember->Unlock();
  1272. hResultCode = DPNERR_PLAYERNOTINGROUP;
  1273. goto Failure;
  1274. }
  1275. pGroupMember->SetNeedToRemove();
  1276. //
  1277. // We will only notify the application if the player is not being added to a group
  1278. //
  1279. if (!pGroupMember->IsNeedToAdd())
  1280. {
  1281. //
  1282. // Either this is already indicated, or is not about to be indicated, so remove it
  1283. // (and see if we need to generate a notification)
  1284. //
  1285. pGroupMember->RemoveMembership( pdwVersion );
  1286. if (pGroupMember->IsAvailable())
  1287. {
  1288. pGroupMember->MakeUnavailable();
  1289. if (!pGroup->IsAllPlayersGroup())
  1290. {
  1291. fNotifyRemove = TRUE;
  1292. }
  1293. }
  1294. }
  1295. Unlock();
  1296. pGroup->Unlock();
  1297. pPlayer->Unlock();
  1298. pGroupMember->Unlock();
  1299. if (fNotifyRemove)
  1300. {
  1301. DNUserRemovePlayerFromGroup(m_pdnObject,pGroup,pPlayer);
  1302. }
  1303. //
  1304. // Trigger a DESTROY_PLAYER/DESTROY_GROUP if this was the last member
  1305. //
  1306. pGroup->NotifyRelease();
  1307. pPlayer->NotifyRelease();
  1308. pGroupMember->Release();
  1309. pGroupMember = NULL;
  1310. hResultCode = DPN_OK;
  1311. Exit:
  1312. return(hResultCode);
  1313. Failure:
  1314. if (pGroupMember)
  1315. {
  1316. pGroupMember->Release();
  1317. pGroupMember = NULL;
  1318. }
  1319. goto Exit;
  1320. }
  1321. #undef DPF_MODNAME
  1322. #define DPF_MODNAME "CNameTable::RemoveAllPlayersFromGroup"
  1323. HRESULT CNameTable::RemoveAllPlayersFromGroup(CNameTableEntry *const pGroup)
  1324. {
  1325. CNameTableEntry **PlayerList;
  1326. CBilink *pBilink;
  1327. HRESULT hResultCode;
  1328. DWORD dwCount;
  1329. DWORD dwActual;
  1330. DPFX(DPFPREP, 6,"Parameters: pGroup [0x%p]",pGroup);
  1331. DNASSERT(pGroup != NULL);
  1332. PlayerList = NULL;
  1333. //
  1334. // This is not an elegant solution - we will build a list of membership records and remove each one
  1335. //
  1336. dwCount = 0;
  1337. dwActual = 0;
  1338. pGroup->Lock();
  1339. DNASSERT(pGroup->IsDisconnecting());
  1340. pBilink = pGroup->m_bilinkMembership.GetNext();
  1341. while (pBilink != &pGroup->m_bilinkMembership)
  1342. {
  1343. dwCount++;
  1344. pBilink = pBilink->GetNext();
  1345. }
  1346. if (dwCount)
  1347. {
  1348. CGroupMember *pGroupMember;
  1349. pGroupMember = NULL;
  1350. if ((PlayerList = static_cast<CNameTableEntry**>(MemoryBlockAlloc(m_pdnObject,dwCount*sizeof(CNameTableEntry*)))) == NULL)
  1351. {
  1352. DPFERR("Could not allocate player list");
  1353. hResultCode = DPNERR_OUTOFMEMORY;
  1354. DNASSERT(FALSE);
  1355. pGroup->Unlock();
  1356. goto Failure;
  1357. }
  1358. pBilink = pGroup->m_bilinkMembership.GetNext();
  1359. while (pBilink != &pGroup->m_bilinkMembership)
  1360. {
  1361. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkPlayers);
  1362. pGroupMember->Lock();
  1363. if (pGroupMember->IsValid() && !pGroupMember->IsNeedToRemove() && pGroupMember->GetPlayer())
  1364. {
  1365. DNASSERT(dwActual < dwCount);
  1366. pGroupMember->GetPlayer()->AddRef();
  1367. PlayerList[dwActual] = pGroupMember->GetPlayer();
  1368. dwActual++;
  1369. }
  1370. pGroupMember->Unlock();
  1371. pBilink = pBilink->GetNext();
  1372. pGroupMember = NULL;
  1373. }
  1374. DNASSERT(pGroupMember == NULL);
  1375. }
  1376. pGroup->Unlock();
  1377. if (PlayerList)
  1378. {
  1379. DWORD dw;
  1380. for (dw = 0 ; dw < dwActual ; dw++)
  1381. {
  1382. DNASSERT(PlayerList[dw] != NULL);
  1383. RemovePlayerFromGroup(pGroup,PlayerList[dw],NULL);
  1384. PlayerList[dw]->Release();
  1385. PlayerList[dw] = NULL;
  1386. }
  1387. MemoryBlockFree(m_pdnObject,PlayerList);
  1388. PlayerList = NULL;
  1389. }
  1390. hResultCode = DPN_OK;
  1391. Exit:
  1392. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1393. return(hResultCode);
  1394. Failure:
  1395. if (PlayerList)
  1396. {
  1397. MemoryBlockFree(m_pdnObject,PlayerList);
  1398. PlayerList = NULL;
  1399. }
  1400. goto Exit;
  1401. }
  1402. #undef DPF_MODNAME
  1403. #define DPF_MODNAME "CNameTable::RemoveAllGroupsFromPlayer"
  1404. HRESULT CNameTable::RemoveAllGroupsFromPlayer(CNameTableEntry *const pPlayer)
  1405. {
  1406. CNameTableEntry *apGroupList[32];
  1407. CBilink *pBilink;
  1408. HRESULT hResultCode;
  1409. CGroupMember *pGroupMember;
  1410. DWORD dwRemainingCount;
  1411. DWORD dwCurrentCount;
  1412. #ifdef DBG
  1413. DWORD dwInitialCount;
  1414. #endif // DBG
  1415. DPFX(DPFPREP, 6,"Parameters: pPlayer [0x%p]",pPlayer);
  1416. DNASSERT(pPlayer != NULL);
  1417. memset(apGroupList, 0, sizeof(apGroupList));
  1418. pGroupMember = NULL;
  1419. //
  1420. // This is not an elegant solution - we will build a list of membership records and remove each one
  1421. //
  1422. dwRemainingCount = 0;
  1423. pPlayer->Lock();
  1424. DNASSERT(pPlayer->IsDisconnecting());
  1425. pBilink = pPlayer->m_bilinkMembership.GetNext();
  1426. while (pBilink != &pPlayer->m_bilinkMembership)
  1427. {
  1428. dwRemainingCount++;
  1429. pBilink = pBilink->GetNext();
  1430. }
  1431. pPlayer->Unlock();
  1432. #ifdef DBG
  1433. dwInitialCount = dwRemainingCount;
  1434. #endif // DBG
  1435. while (dwRemainingCount > 0)
  1436. {
  1437. dwRemainingCount = 0;
  1438. dwCurrentCount = 0;
  1439. pPlayer->Lock();
  1440. pBilink = pPlayer->m_bilinkMembership.GetNext();
  1441. while (pBilink != &pPlayer->m_bilinkMembership)
  1442. {
  1443. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkGroups);
  1444. pGroupMember->Lock();
  1445. if (pGroupMember->IsValid() && !pGroupMember->IsNeedToRemove() && pGroupMember->GetGroup())
  1446. {
  1447. if (dwCurrentCount < (sizeof(apGroupList) / sizeof(CNameTableEntry*)))
  1448. {
  1449. pGroupMember->GetGroup()->AddRef();
  1450. apGroupList[dwCurrentCount] = pGroupMember->GetGroup();
  1451. dwCurrentCount++;
  1452. #ifdef DBG
  1453. DNASSERT(dwCurrentCount <= dwInitialCount);
  1454. #endif // DBG
  1455. }
  1456. else
  1457. {
  1458. dwRemainingCount++;
  1459. //
  1460. // The list should never grow. In fact it should
  1461. // always be smaller because the current group list
  1462. // should have taken some.
  1463. //
  1464. #ifdef DBG
  1465. DNASSERT(dwRemainingCount < dwInitialCount);
  1466. #endif // DBG
  1467. }
  1468. }
  1469. pGroupMember->Unlock();
  1470. pBilink = pBilink->GetNext();
  1471. pGroupMember = NULL;
  1472. }
  1473. DNASSERT(pGroupMember == NULL);
  1474. pPlayer->Unlock();
  1475. if (dwCurrentCount > 0)
  1476. {
  1477. DWORD dw;
  1478. for (dw = 0 ; dw < dwCurrentCount ; dw++)
  1479. {
  1480. DNASSERT(apGroupList[dw] != NULL);
  1481. RemovePlayerFromGroup(apGroupList[dw],pPlayer,NULL);
  1482. apGroupList[dw]->Release();
  1483. apGroupList[dw] = NULL;
  1484. }
  1485. }
  1486. else
  1487. {
  1488. DNASSERT(dwRemainingCount == 0);
  1489. }
  1490. }
  1491. hResultCode = DPN_OK;
  1492. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1493. return(hResultCode);
  1494. }
  1495. #undef DPF_MODNAME
  1496. #define DPF_MODNAME "CNameTable::IsMember"
  1497. BOOL CNameTable::IsMember(const DPNID dpnidGroup,
  1498. const DPNID dpnidPlayer)
  1499. {
  1500. CNameTableEntry *pNTEntry;
  1501. CGroupMember *pGroupMember;
  1502. CBilink *pBilink;
  1503. BOOL bFound;
  1504. bFound = FALSE;
  1505. if (FindEntry(dpnidGroup,&pNTEntry) != DPN_OK)
  1506. {
  1507. goto Exit;
  1508. }
  1509. //
  1510. // Is this a group ?
  1511. //
  1512. if (!pNTEntry->IsGroup())
  1513. {
  1514. pNTEntry->Release();
  1515. pNTEntry = NULL;
  1516. goto Exit;
  1517. }
  1518. pNTEntry->Lock();
  1519. pBilink = pNTEntry->m_bilinkMembership.GetNext();
  1520. while (pBilink != &pNTEntry->m_bilinkMembership)
  1521. {
  1522. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkPlayers);
  1523. if (pGroupMember->GetPlayer()->GetDPNID() == dpnidPlayer)
  1524. {
  1525. bFound = TRUE;
  1526. break;
  1527. }
  1528. pBilink = pBilink->GetNext();
  1529. }
  1530. pNTEntry->Unlock();
  1531. pNTEntry->Release();
  1532. pNTEntry = NULL;
  1533. Exit:
  1534. return(bFound);
  1535. }
  1536. #undef DPF_MODNAME
  1537. #define DPF_MODNAME "CNameTable::PackNameTable"
  1538. HRESULT CNameTable::PackNameTable(CNameTableEntry *const pTarget,
  1539. CPackedBuffer *const pPackedBuffer)
  1540. {
  1541. HRESULT hResultCode;
  1542. CBilink *pBilink;
  1543. CBilink *pBilinkMembership;
  1544. CNameTableEntry *pNTEntry;
  1545. CGroupMember *pGroupMember;
  1546. DN_NAMETABLE_INFO *pdnNTInfo;
  1547. BOOL bOutOfSpace;
  1548. DWORD dwEntryCount;
  1549. DWORD dwMembershipCount;
  1550. DWORD dwVersion;
  1551. DNASSERT(pTarget != NULL);
  1552. DNASSERT(pPackedBuffer != NULL);
  1553. //
  1554. // PackedNameTable:
  1555. // <DN_NAMETABLE_INFO>
  1556. // <DN_NAMETABLE_ENTRY_INFO> (DN_NAMETABLE_INFO.dwEntryCount entries)
  1557. // <DN_MEMBERSHIP_INFO> (DN_NAMETABLE_INFO.dwMembershipCount entries)
  1558. // ...
  1559. // <strings>
  1560. //
  1561. //
  1562. // NameTable Info
  1563. //
  1564. dwVersion = pTarget->GetVersion();
  1565. bOutOfSpace = FALSE;
  1566. pdnNTInfo = static_cast<DN_NAMETABLE_INFO*>(pPackedBuffer->GetHeadAddress());
  1567. if ((hResultCode = pPackedBuffer->AddToFront(NULL,sizeof(DN_NAMETABLE_INFO))) != DPN_OK)
  1568. {
  1569. bOutOfSpace = TRUE;
  1570. }
  1571. ReadLock();
  1572. //
  1573. // NameTableEntry Info
  1574. //
  1575. if (m_pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  1576. {
  1577. dwEntryCount = 0;
  1578. //
  1579. // Players
  1580. //
  1581. pBilink = m_bilinkPlayers.GetNext();
  1582. while (pBilink != &m_bilinkPlayers)
  1583. {
  1584. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1585. if (pNTEntry->GetVersion() <= dwVersion)
  1586. {
  1587. if ((hResultCode = pNTEntry->PackEntryInfo(pPackedBuffer)) != DPN_OK)
  1588. {
  1589. bOutOfSpace = TRUE;
  1590. }
  1591. dwEntryCount++;
  1592. }
  1593. pBilink = pBilink->GetNext();
  1594. }
  1595. //
  1596. // Groups
  1597. //
  1598. pBilink = m_bilinkGroups.GetNext();
  1599. while (pBilink != &m_bilinkGroups)
  1600. {
  1601. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1602. if (pNTEntry->GetVersion() <= dwVersion)
  1603. {
  1604. if ((hResultCode = pNTEntry->PackEntryInfo(pPackedBuffer)) != DPN_OK)
  1605. {
  1606. bOutOfSpace = TRUE;
  1607. }
  1608. dwEntryCount++;
  1609. }
  1610. pBilink = pBilink->GetNext();
  1611. }
  1612. }
  1613. else
  1614. {
  1615. DNASSERT(m_pLocalPlayer != NULL);
  1616. if ((hResultCode = m_pLocalPlayer->PackEntryInfo(pPackedBuffer)) != DPN_OK)
  1617. {
  1618. bOutOfSpace = TRUE;
  1619. }
  1620. if ((hResultCode = pTarget->PackEntryInfo(pPackedBuffer)) != DPN_OK)
  1621. {
  1622. bOutOfSpace = TRUE;
  1623. }
  1624. dwEntryCount = 2;
  1625. }
  1626. //
  1627. // GroupMember Info
  1628. //
  1629. dwMembershipCount = 0;
  1630. if (m_pdnObject->dwFlags & DN_OBJECT_FLAG_PEER)
  1631. {
  1632. pBilink = m_bilinkGroups.GetNext();
  1633. while (pBilink != &m_bilinkGroups)
  1634. {
  1635. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1636. DNASSERT(pNTEntry->IsGroup());
  1637. if (!pNTEntry->IsAllPlayersGroup())
  1638. {
  1639. pBilinkMembership = pNTEntry->m_bilinkMembership.GetNext();
  1640. while (pBilinkMembership != &pNTEntry->m_bilinkMembership)
  1641. {
  1642. pGroupMember = CONTAINING_OBJECT(pBilinkMembership,CGroupMember,m_bilinkPlayers);
  1643. if (pGroupMember->GetVersion() <= dwVersion)
  1644. {
  1645. if ((hResultCode = pGroupMember->PackMembershipInfo(pPackedBuffer)) != DPN_OK)
  1646. {
  1647. bOutOfSpace = TRUE;
  1648. }
  1649. dwMembershipCount++;
  1650. }
  1651. pBilinkMembership = pBilinkMembership->GetNext();
  1652. }
  1653. }
  1654. pBilink = pBilink->GetNext();
  1655. }
  1656. }
  1657. Unlock();
  1658. if (!bOutOfSpace)
  1659. {
  1660. pdnNTInfo->dpnid = pTarget->GetDPNID();
  1661. pdnNTInfo->dwVersion = dwVersion;
  1662. pdnNTInfo->dwVersionNotUsed = 0;
  1663. pdnNTInfo->dwEntryCount = dwEntryCount;
  1664. pdnNTInfo->dwMembershipCount = dwMembershipCount;
  1665. }
  1666. return(hResultCode);
  1667. }
  1668. #undef DPF_MODNAME
  1669. #define DPF_MODNAME "CNameTable::UnpackNameTableInfo"
  1670. HRESULT CNameTable::UnpackNameTableInfo(UNALIGNED DN_NAMETABLE_INFO *const pdnNTInfo,
  1671. BYTE *const pBufferStart,
  1672. DPNID *const pdpnid)
  1673. {
  1674. HRESULT hResultCode;
  1675. DWORD dwCount;
  1676. CNameTableEntry *pNTEntry;
  1677. UNALIGNED DN_NAMETABLE_ENTRY_INFO *pdnEntryInfo;
  1678. UNALIGNED DN_NAMETABLE_MEMBERSHIP_INFO *pdnMembershipInfo;
  1679. DNASSERT(pdnNTInfo != NULL);
  1680. DNASSERT(pBufferStart != NULL);
  1681. //
  1682. // Preset outstanding connections
  1683. //
  1684. m_lOutstandingConnections = 0;
  1685. //
  1686. // NameTable Entries
  1687. //
  1688. pdnEntryInfo = reinterpret_cast<DN_NAMETABLE_ENTRY_INFO*>(pdnNTInfo+1);
  1689. for (dwCount = 0 ; dwCount < pdnNTInfo->dwEntryCount ; dwCount++)
  1690. {
  1691. if ((hResultCode = NameTableEntryNew(m_pdnObject,&pNTEntry)) != DPN_OK)
  1692. {
  1693. DPFERR("Could not get new NameTableEntry");
  1694. DNASSERT(FALSE);
  1695. return(hResultCode);
  1696. }
  1697. if ((hResultCode = pNTEntry->UnpackEntryInfo(pdnEntryInfo,pBufferStart)) != DPN_OK)
  1698. {
  1699. DPFERR("Could not unpack NameTableEntryInfo");
  1700. DNASSERT(FALSE);
  1701. pNTEntry->Release();
  1702. return(hResultCode);
  1703. }
  1704. //
  1705. // Increment outstanding connection count
  1706. //
  1707. if (!pNTEntry->IsGroup() && (pNTEntry->GetVersion() <= pdnNTInfo->dwVersion))
  1708. {
  1709. pNTEntry->StartConnecting(); // This will be cleared when the player has connected or disconnected
  1710. IncOutstandingConnections();
  1711. }
  1712. // Only put in NameTable if Host player
  1713. #ifndef DPNBUILD_NOSERVER
  1714. if (m_pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER | DN_OBJECT_FLAG_SERVER))
  1715. #else
  1716. if (m_pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER))
  1717. #endif // DPNBUILD_NOSERVER
  1718. {
  1719. if ((hResultCode = InsertEntry(pNTEntry)) != DPN_OK)
  1720. {
  1721. DPFERR("Could not add NameTableEntry to NameTable");
  1722. DNASSERT(FALSE);
  1723. pNTEntry->Release();
  1724. return(hResultCode);
  1725. }
  1726. }
  1727. // Check for ShortCut pointers
  1728. if (pNTEntry->GetDPNID() == pdnNTInfo->dpnid)
  1729. {
  1730. MakeLocalPlayer(pNTEntry);
  1731. }
  1732. else if (pNTEntry->IsHost())
  1733. {
  1734. MakeHostPlayer(pNTEntry);
  1735. }
  1736. else if (pNTEntry->IsAllPlayersGroup())
  1737. {
  1738. MakeAllPlayersGroup(pNTEntry);
  1739. }
  1740. pNTEntry->Release();
  1741. pNTEntry = NULL;
  1742. pdnEntryInfo++;
  1743. }
  1744. //
  1745. // Pass back local player's DPNID
  1746. //
  1747. if (pdpnid)
  1748. {
  1749. *pdpnid = pdnNTInfo->dpnid;
  1750. }
  1751. //
  1752. // Group Memberships
  1753. //
  1754. pdnMembershipInfo = reinterpret_cast<DN_NAMETABLE_MEMBERSHIP_INFO*>(pdnEntryInfo);
  1755. for (dwCount = 0 ; dwCount < pdnNTInfo->dwMembershipCount ; dwCount++)
  1756. {
  1757. CNameTableEntry *pGroup;
  1758. pGroup = NULL;
  1759. if ((hResultCode = m_pdnObject->NameTable.FindEntry(pdnMembershipInfo->dpnidGroup,&pGroup)) == DPN_OK)
  1760. {
  1761. CNameTableEntry *pPlayer;
  1762. pPlayer = NULL;
  1763. if ((hResultCode = m_pdnObject->NameTable.FindEntry(pdnMembershipInfo->dpnidPlayer,&pPlayer)) == DPN_OK)
  1764. {
  1765. DWORD dwVersion;
  1766. dwVersion = pdnMembershipInfo->dwVersion;
  1767. hResultCode = AddPlayerToGroup(pGroup,pPlayer,&dwVersion);
  1768. pPlayer->Release();
  1769. pPlayer = NULL;
  1770. }
  1771. pGroup->Release();
  1772. pGroup = NULL;
  1773. DNASSERT(pPlayer == NULL);
  1774. }
  1775. pdnMembershipInfo++;
  1776. DNASSERT(pGroup == NULL);
  1777. }
  1778. //
  1779. // Version
  1780. //
  1781. WriteLock();
  1782. SetVersion(pdnNTInfo->dwVersion);
  1783. SetConnectVersion(pdnNTInfo->dwVersion);
  1784. Unlock();
  1785. hResultCode = DPN_OK;
  1786. return(hResultCode);
  1787. }
  1788. #undef DPF_MODNAME
  1789. #define DPF_MODNAME "CNameTable::MakeLocalPlayer"
  1790. void CNameTable::MakeLocalPlayer(CNameTableEntry *const pNTEntry)
  1791. {
  1792. DNASSERT(pNTEntry != NULL);
  1793. DNASSERT(m_pLocalPlayer == NULL);
  1794. pNTEntry->AddRef();
  1795. pNTEntry->Lock();
  1796. pNTEntry->MakeLocal();
  1797. pNTEntry->Unlock();
  1798. WriteLock();
  1799. m_pLocalPlayer = pNTEntry;
  1800. Unlock();
  1801. }
  1802. #undef DPF_MODNAME
  1803. #define DPF_MODNAME "CNameTable::ClearLocalPlayer"
  1804. void CNameTable::ClearLocalPlayer( void )
  1805. {
  1806. BOOL fInform;
  1807. CNameTableEntry *pNTEntry;
  1808. CConnection *pConnection;
  1809. fInform = FALSE;
  1810. pNTEntry = NULL;
  1811. pConnection = NULL;
  1812. WriteLock();
  1813. if (m_pLocalPlayer)
  1814. {
  1815. pNTEntry = m_pLocalPlayer;
  1816. m_pLocalPlayer = NULL;
  1817. //
  1818. // If the player is available, we will make it unavailable. This will prevent other threads from using it.
  1819. // We will then ensure that we are the only one indicating a DESTROY_PLAYER notification.
  1820. //
  1821. pNTEntry->Lock();
  1822. if (pNTEntry->GetDestroyReason() == 0)
  1823. {
  1824. pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_NORMAL );
  1825. }
  1826. if (pNTEntry->IsAvailable())
  1827. {
  1828. pNTEntry->MakeUnavailable();
  1829. if (pNTEntry->IsInUse())
  1830. {
  1831. //
  1832. // Queue destruction notification
  1833. //
  1834. pNTEntry->SetNeedToDestroy();
  1835. }
  1836. else
  1837. {
  1838. //
  1839. // Notify destruction
  1840. //
  1841. pNTEntry->SetInUse();
  1842. fInform = TRUE;
  1843. }
  1844. }
  1845. pNTEntry->Unlock();
  1846. }
  1847. Unlock();
  1848. if (pNTEntry)
  1849. {
  1850. pNTEntry->GetConnectionRef(&pConnection);
  1851. pNTEntry->Release();
  1852. pNTEntry = NULL;
  1853. }
  1854. //
  1855. // Try to disconnect
  1856. //
  1857. if (pConnection)
  1858. {
  1859. pConnection->Disconnect();
  1860. pConnection->Release();
  1861. pConnection = NULL;
  1862. }
  1863. }
  1864. #undef DPF_MODNAME
  1865. #define DPF_MODNAME "CNameTable::MakeHostPlayer"
  1866. void CNameTable::MakeHostPlayer(CNameTableEntry *const pNTEntry)
  1867. {
  1868. BOOL bNotify;
  1869. DPNID dpnid;
  1870. PVOID pvContext;
  1871. DNASSERT(pNTEntry != NULL);
  1872. DNASSERT(m_pHostPlayer == NULL);
  1873. pNTEntry->AddRef();
  1874. pNTEntry->Lock();
  1875. pNTEntry->MakeHost();
  1876. if (pNTEntry->IsAvailable())
  1877. {
  1878. bNotify = TRUE;
  1879. dpnid = pNTEntry->GetDPNID();
  1880. pvContext = pNTEntry->GetContext();
  1881. }
  1882. else
  1883. {
  1884. bNotify = FALSE;
  1885. }
  1886. pNTEntry->Unlock();
  1887. WriteLock();
  1888. m_pHostPlayer = pNTEntry;
  1889. Unlock();
  1890. if (bNotify)
  1891. {
  1892. // Inform user that host has migrated
  1893. DN_UserHostMigrate(m_pdnObject,dpnid,pvContext);
  1894. }
  1895. }
  1896. #undef DPF_MODNAME
  1897. #define DPF_MODNAME "CNameTable::ClearHostPlayer"
  1898. void CNameTable::ClearHostPlayer( void )
  1899. {
  1900. BOOL fInform;
  1901. CNameTableEntry *pNTEntry;
  1902. CConnection *pConnection;
  1903. fInform = FALSE;
  1904. pNTEntry = NULL;
  1905. pConnection = NULL;
  1906. WriteLock();
  1907. if (m_pHostPlayer)
  1908. {
  1909. pNTEntry = m_pHostPlayer;
  1910. m_pHostPlayer = NULL;
  1911. //
  1912. // If the player is available, we will make it unavailable. This will prevent other threads from using it.
  1913. // We will then ensure that we are the only one indicating a DESTROY_PLAYER notification.
  1914. //
  1915. pNTEntry->Lock();
  1916. if (pNTEntry->GetDestroyReason() == 0)
  1917. {
  1918. pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_NORMAL );
  1919. }
  1920. if (pNTEntry->IsAvailable())
  1921. {
  1922. pNTEntry->MakeUnavailable();
  1923. if (pNTEntry->IsInUse())
  1924. {
  1925. //
  1926. // Queue destruction notification
  1927. //
  1928. pNTEntry->SetNeedToDestroy();
  1929. }
  1930. else
  1931. {
  1932. //
  1933. // Notify destruction
  1934. //
  1935. pNTEntry->SetInUse();
  1936. fInform = TRUE;
  1937. }
  1938. }
  1939. pNTEntry->Unlock();
  1940. }
  1941. Unlock();
  1942. if (pNTEntry)
  1943. {
  1944. pNTEntry->GetConnectionRef(&pConnection);
  1945. pNTEntry->Release();
  1946. pNTEntry = NULL;
  1947. }
  1948. //
  1949. // Try to disconnect
  1950. //
  1951. if (pConnection)
  1952. {
  1953. pConnection->Disconnect();
  1954. pConnection->Release();
  1955. pConnection = NULL;
  1956. }
  1957. }
  1958. //
  1959. // Clear the HostPlayer if it has a matching DPNID
  1960. //
  1961. #undef DPF_MODNAME
  1962. #define DPF_MODNAME "CNameTable::ClearHostWithDPNID"
  1963. BOOL CNameTable::ClearHostWithDPNID( const DPNID dpnid )
  1964. {
  1965. BOOL fCleared;
  1966. BOOL fInform;
  1967. CNameTableEntry *pNTEntry;
  1968. CConnection *pConnection;
  1969. fCleared = FALSE;
  1970. fInform = FALSE;
  1971. pNTEntry = NULL;
  1972. pConnection = NULL;
  1973. WriteLock();
  1974. if (m_pHostPlayer)
  1975. {
  1976. if (m_pHostPlayer->GetDPNID() == dpnid)
  1977. {
  1978. pNTEntry = m_pHostPlayer;
  1979. m_pHostPlayer = NULL;
  1980. //
  1981. // If the player is available, we will make it unavailable. This will prevent other threads from using it.
  1982. // We will then ensure that we are the only one indicating a DESTROY_PLAYER notification.
  1983. //
  1984. pNTEntry->Lock();
  1985. if (pNTEntry->GetDestroyReason() == 0)
  1986. {
  1987. pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_NORMAL );
  1988. }
  1989. if (pNTEntry->IsAvailable())
  1990. {
  1991. pNTEntry->MakeUnavailable();
  1992. if (pNTEntry->IsInUse())
  1993. {
  1994. //
  1995. // Queue destruction notification
  1996. //
  1997. pNTEntry->SetNeedToDestroy();
  1998. }
  1999. else
  2000. {
  2001. //
  2002. // Notify destruction
  2003. //
  2004. pNTEntry->SetInUse();
  2005. fInform = TRUE;
  2006. }
  2007. }
  2008. pNTEntry->Unlock();
  2009. fCleared = TRUE;
  2010. }
  2011. }
  2012. Unlock();
  2013. if (pNTEntry)
  2014. {
  2015. pNTEntry->GetConnectionRef(&pConnection);
  2016. pNTEntry->Release();
  2017. pNTEntry = NULL;
  2018. }
  2019. //
  2020. // Try to disconnect
  2021. //
  2022. if (pConnection)
  2023. {
  2024. pConnection->Disconnect();
  2025. pConnection->Release();
  2026. pConnection = NULL;
  2027. }
  2028. return(fCleared);
  2029. }
  2030. //
  2031. // Attempt to update the HostPlayer short-cut pointer with a new player entry.
  2032. // This will only be performed if the new entry has a larger version than the
  2033. // existing HostPlayer entry.
  2034. //
  2035. #undef DPF_MODNAME
  2036. #define DPF_MODNAME "CNameTable::UpdateHostPlayer"
  2037. void CNameTable::UpdateHostPlayer( CNameTableEntry *const pNewHost )
  2038. {
  2039. BOOL fInformDelete;
  2040. BOOL fInformMigrate;
  2041. DPNID dpnid;
  2042. PVOID pvContext;
  2043. CNameTableEntry *pNTEntry;
  2044. DNASSERT( pNewHost != NULL);
  2045. fInformDelete = FALSE;
  2046. fInformMigrate = FALSE;
  2047. pNTEntry = NULL;
  2048. WriteLock();
  2049. //
  2050. // Clear old Host
  2051. //
  2052. if (m_pHostPlayer)
  2053. {
  2054. if (pNewHost->GetVersion() > m_pHostPlayer->GetVersion())
  2055. {
  2056. pNTEntry = m_pHostPlayer;
  2057. m_pHostPlayer = NULL;
  2058. //
  2059. // If the player is available, we will make it unavailable. This will prevent other threads from using it.
  2060. // We will then ensure that we are the only one indicating a DESTROY_PLAYER notification.
  2061. //
  2062. pNTEntry->Lock();
  2063. if (pNTEntry->GetDestroyReason() == 0)
  2064. {
  2065. pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_NORMAL );
  2066. }
  2067. if (pNTEntry->IsAvailable())
  2068. {
  2069. pNTEntry->MakeUnavailable();
  2070. if (pNTEntry->IsInUse())
  2071. {
  2072. //
  2073. // Queue destruction notification
  2074. //
  2075. pNTEntry->SetNeedToDestroy();
  2076. }
  2077. else
  2078. {
  2079. //
  2080. // Notify destruction
  2081. //
  2082. pNTEntry->SetInUse();
  2083. fInformDelete = TRUE;
  2084. }
  2085. }
  2086. pNTEntry->Unlock();
  2087. }
  2088. }
  2089. //
  2090. // New Host player
  2091. //
  2092. if (m_pHostPlayer == NULL)
  2093. {
  2094. pNewHost->Lock();
  2095. pNewHost->MakeHost();
  2096. if (pNewHost->IsAvailable())
  2097. {
  2098. fInformMigrate = TRUE;
  2099. dpnid = pNewHost->GetDPNID();
  2100. pvContext = pNewHost->GetContext();
  2101. }
  2102. pNewHost->Unlock();
  2103. pNewHost->AddRef();
  2104. m_pHostPlayer = pNewHost;
  2105. }
  2106. Unlock();
  2107. //
  2108. // User notifications
  2109. //
  2110. if (pNTEntry)
  2111. {
  2112. pNTEntry->Release();
  2113. pNTEntry = NULL;
  2114. }
  2115. if (fInformMigrate)
  2116. {
  2117. DN_UserHostMigrate(m_pdnObject,dpnid,pvContext);
  2118. }
  2119. }
  2120. #undef DPF_MODNAME
  2121. #define DPF_MODNAME "CNameTable::MakeAllPlayersGroup"
  2122. void CNameTable::MakeAllPlayersGroup(CNameTableEntry *const pNTEntry)
  2123. {
  2124. DNASSERT(pNTEntry != NULL);
  2125. DNASSERT(m_pAllPlayersGroup == NULL);
  2126. pNTEntry->AddRef();
  2127. pNTEntry->Lock();
  2128. pNTEntry->MakeAllPlayersGroup();
  2129. pNTEntry->Unlock();
  2130. WriteLock();
  2131. m_pAllPlayersGroup = pNTEntry;
  2132. Unlock();
  2133. }
  2134. #undef DPF_MODNAME
  2135. #define DPF_MODNAME "CNameTable::ClearAllPlayersGroup"
  2136. void CNameTable::ClearAllPlayersGroup( void )
  2137. {
  2138. BOOL fInform;
  2139. CNameTableEntry *pNTEntry;
  2140. fInform = FALSE;
  2141. pNTEntry = NULL;
  2142. WriteLock();
  2143. if (m_pAllPlayersGroup)
  2144. {
  2145. pNTEntry = m_pAllPlayersGroup;
  2146. pNTEntry->Lock();
  2147. if (pNTEntry->IsAvailable())
  2148. {
  2149. pNTEntry->MakeUnavailable();
  2150. fInform = TRUE;
  2151. }
  2152. pNTEntry->Unlock();
  2153. m_pAllPlayersGroup = NULL;
  2154. pNTEntry->Release();
  2155. pNTEntry = NULL;
  2156. }
  2157. Unlock();
  2158. }
  2159. #undef DPF_MODNAME
  2160. #define DPF_MODNAME "CNameTable::PopulateConnection"
  2161. HRESULT CNameTable::PopulateConnection(CConnection *const pConnection)
  2162. {
  2163. HRESULT hResultCode;
  2164. CBilink *pBilink;
  2165. CNameTableEntry *pNTEntry;
  2166. CNameTableEntry *pAllPlayersGroup;
  2167. CGroupMember *pGroupMember;
  2168. CGroupMember *pOldGroupMember;
  2169. BOOL fNotifyCreate;
  2170. BOOL fNotifyAddPlayerToGroup;
  2171. BOOL fNotifyRemovePlayerFromGroup;
  2172. DNASSERT(pConnection != NULL);
  2173. DNASSERT(pConnection->GetDPNID() != 0);
  2174. pNTEntry = NULL;
  2175. pAllPlayersGroup = NULL;
  2176. pGroupMember = NULL;
  2177. pOldGroupMember = NULL;
  2178. if ((hResultCode = FindEntry(pConnection->GetDPNID(),&pNTEntry)) != DPN_OK)
  2179. {
  2180. return(hResultCode);
  2181. }
  2182. DNASSERT(!pNTEntry->IsGroup());
  2183. //
  2184. // Set the connection for this player
  2185. //
  2186. pNTEntry->Lock();
  2187. if (pNTEntry->GetConnection() == NULL)
  2188. {
  2189. pNTEntry->SetConnection( pConnection );
  2190. }
  2191. DNASSERT( pNTEntry->IsConnecting() );
  2192. DNASSERT( !pNTEntry->IsAvailable() );
  2193. pNTEntry->StopConnecting();
  2194. pNTEntry->MakeAvailable();
  2195. pNTEntry->Unlock();
  2196. //
  2197. // Add this player to the ALL_PLAYERS group and make the link active
  2198. //
  2199. if ((hResultCode = m_pdnObject->NameTable.GetAllPlayersGroupRef( &pAllPlayersGroup )) != DPN_OK)
  2200. {
  2201. DPFERR("Could not get ALL_PLAYERS_GROUP reference");
  2202. DisplayDNError(0,hResultCode);
  2203. goto Failure;
  2204. }
  2205. if ((hResultCode = m_pdnObject->NameTable.AddPlayerToGroup( pAllPlayersGroup,
  2206. pNTEntry,
  2207. NULL)) != DPN_OK)
  2208. {
  2209. DPFERR("Could not add player to AllPlayersGroup");
  2210. DisplayDNError(0,hResultCode);
  2211. goto Failure;
  2212. }
  2213. pAllPlayersGroup->Release();
  2214. pAllPlayersGroup = NULL;
  2215. fNotifyCreate = FALSE;
  2216. pNTEntry->Lock();
  2217. if (!pNTEntry->IsDisconnecting() && !pNTEntry->IsCreated())
  2218. {
  2219. //
  2220. // We will set the entry as InUse so that any receives will get queued.
  2221. // We will also addref the NotifyRefCount twice. Once for the
  2222. // CREATE_PLAYER notification if there was no INDICATE_CONNECT
  2223. // (so that a corresponding release will generate the DESTROY_PLAYER),
  2224. // and a second one to prevent a premature release from generating
  2225. // the DESTROY_PLAYER before we return from CREATE_PLAYER. We will
  2226. // therefore have to release the refcount as soon as the CREATE_PLAYER
  2227. // returns back to us from the user (setting the context value).
  2228. //
  2229. DNASSERT(!pNTEntry->IsInUse());
  2230. pNTEntry->SetInUse();
  2231. if (!pNTEntry->IsIndicated())
  2232. {
  2233. pNTEntry->NotifyAddRef();
  2234. }
  2235. pNTEntry->NotifyAddRef();
  2236. fNotifyCreate = TRUE;
  2237. }
  2238. pNTEntry->Unlock(); // Release lock during notifications (CREATE_PLAYER, CONNECT_COMPLETE?)
  2239. if (fNotifyCreate)
  2240. {
  2241. if (!(m_pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT))
  2242. {
  2243. DNUserCreatePlayer(m_pdnObject,pNTEntry);
  2244. }
  2245. //
  2246. // Process any queued messages for this player
  2247. //
  2248. pNTEntry->PerformQueuedOperations();
  2249. }
  2250. //
  2251. // Create any auto-destruct groups belonging to this player
  2252. //
  2253. AutoCreateGroups(pNTEntry);
  2254. pNTEntry->Lock();
  2255. //
  2256. // Ensure this entry is still available (might have been deleted)
  2257. //
  2258. if (!pNTEntry->IsAvailable() || pNTEntry->IsDisconnecting())
  2259. {
  2260. //
  2261. // Reduce outstanding connections (if required)
  2262. //
  2263. if (pNTEntry->GetVersion() <= m_dwConnectVersion)
  2264. {
  2265. DecOutstandingConnections();
  2266. }
  2267. pNTEntry->Unlock();
  2268. goto Failure;
  2269. }
  2270. pBilink = pNTEntry->m_bilinkMembership.GetNext();
  2271. while (pBilink != &pNTEntry->m_bilinkMembership)
  2272. {
  2273. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkGroups);
  2274. pGroupMember->AddRef();
  2275. pNTEntry->Unlock();
  2276. DNASSERT(pGroupMember->GetGroup() != NULL);
  2277. DNASSERT(pGroupMember->GetPlayer() != NULL);
  2278. fNotifyAddPlayerToGroup = FALSE;
  2279. fNotifyRemovePlayerFromGroup = FALSE;
  2280. pGroupMember->GetGroup()->Lock();
  2281. pGroupMember->Lock();
  2282. DNASSERT(pGroupMember->GetGroupConnection() != NULL);
  2283. if (!pGroupMember->IsAvailable() && !pGroupMember->IsNeedToAdd() && !pGroupMember->GetGroupConnection()->IsConnected())
  2284. {
  2285. //
  2286. // We will only indicate this up if the group has been created
  2287. // We don't need to see if the player has been created since he should have been and the NotifyRefCount
  2288. // on the player's entry for this group member will still be there
  2289. //
  2290. if ( pGroupMember->GetGroup()->IsCreated()
  2291. && !pGroupMember->GetGroup()->IsDisconnecting()
  2292. && !pGroupMember->GetGroup()->IsAllPlayersGroup())
  2293. {
  2294. pGroupMember->SetNeedToAdd();
  2295. fNotifyAddPlayerToGroup = TRUE;
  2296. }
  2297. }
  2298. pGroupMember->GetGroup()->Unlock();
  2299. pGroupMember->Unlock();
  2300. if (fNotifyAddPlayerToGroup)
  2301. {
  2302. DNASSERT(pGroupMember->GetGroupConnection()->GetConnection() == NULL);
  2303. pGroupMember->Lock();
  2304. pGroupMember->GetGroupConnection()->Lock();
  2305. pGroupMember->GetGroupConnection()->SetConnection(pConnection);
  2306. pGroupMember->GetGroupConnection()->Unlock();
  2307. pGroupMember->MakeAvailable();
  2308. pGroupMember->Unlock();
  2309. DNUserAddPlayerToGroup( m_pdnObject,pGroupMember->GetGroup(),pGroupMember->GetPlayer());
  2310. pGroupMember->Lock();
  2311. pGroupMember->ClearNeedToAdd();
  2312. if (pGroupMember->IsNeedToRemove())
  2313. {
  2314. fNotifyRemovePlayerFromGroup = TRUE;
  2315. }
  2316. pGroupMember->Unlock();
  2317. }
  2318. if (fNotifyRemovePlayerFromGroup)
  2319. {
  2320. DNUserRemovePlayerFromGroup(m_pdnObject,pGroupMember->GetGroup(),pGroupMember->GetPlayer());
  2321. }
  2322. //
  2323. // Release old group member and transfer reference
  2324. //
  2325. if (pOldGroupMember)
  2326. {
  2327. pOldGroupMember->Release();
  2328. pOldGroupMember = NULL;
  2329. }
  2330. pOldGroupMember = pGroupMember;
  2331. pGroupMember = NULL;
  2332. pNTEntry->Lock();
  2333. //
  2334. // Avoid infinite loops by ensuring that we are not on a "disconnected" entry
  2335. //
  2336. if ((pBilink->GetNext() != &pNTEntry->m_bilinkMembership) && (pBilink->GetNext() == pBilink))
  2337. {
  2338. //
  2339. // We have an invalid entry - need to restart
  2340. //
  2341. pBilink = pNTEntry->m_bilinkMembership.GetNext();
  2342. }
  2343. else
  2344. {
  2345. //
  2346. // We either have a valid entry or we're finished
  2347. //
  2348. pBilink = pBilink->GetNext();
  2349. }
  2350. }
  2351. pNTEntry->Unlock();
  2352. if (pOldGroupMember)
  2353. {
  2354. pOldGroupMember->Release();
  2355. pOldGroupMember = NULL;
  2356. }
  2357. //
  2358. // Reduce outstanding connections
  2359. //
  2360. if (pNTEntry->GetVersion() <= m_dwConnectVersion)
  2361. {
  2362. DecOutstandingConnections();
  2363. }
  2364. pNTEntry->Release();
  2365. pNTEntry = NULL;
  2366. Exit:
  2367. DNASSERT(pNTEntry == NULL);
  2368. DNASSERT(pGroupMember == NULL);
  2369. DNASSERT(pOldGroupMember == NULL);
  2370. return(hResultCode);
  2371. Failure:
  2372. if (pNTEntry)
  2373. {
  2374. pNTEntry->Release();
  2375. pNTEntry = NULL;
  2376. }
  2377. if (pAllPlayersGroup)
  2378. {
  2379. pAllPlayersGroup->Release();
  2380. pAllPlayersGroup = NULL;
  2381. }
  2382. if (pGroupMember)
  2383. {
  2384. pGroupMember->Release();
  2385. pGroupMember = NULL;
  2386. }
  2387. goto Exit;
  2388. }
  2389. //
  2390. // This will generate ADD_PLAYER_TO_GROUP messages for all of the CREATE'd players in a group
  2391. // (for whom a notification has not been posted)
  2392. //
  2393. #undef DPF_MODNAME
  2394. #define DPF_MODNAME "CNameTable::PopulateGroup"
  2395. HRESULT CNameTable::PopulateGroup(CNameTableEntry *const pGroup)
  2396. {
  2397. HRESULT hResultCode;
  2398. BOOL fNotifyAddPlayerToGroup;
  2399. BOOL fNotifyRemovePlayerFromGroup;
  2400. CBilink *pBilink;
  2401. CGroupMember *pGroupMember;
  2402. CGroupMember *pOldGroupMember;
  2403. CNameTableEntry *pPlayer;
  2404. DPFX(DPFPREP, 6,"Parameters: pGroup [0x%p]",pGroup);
  2405. DNASSERT(pGroup != NULL);
  2406. hResultCode = DPN_OK;
  2407. pPlayer = NULL;
  2408. pGroupMember = NULL;
  2409. pOldGroupMember = NULL;
  2410. if (!pGroup->IsGroup())
  2411. {
  2412. hResultCode = DPNERR_INVALIDGROUP;
  2413. goto Failure;
  2414. }
  2415. pGroup->Lock();
  2416. pBilink = pGroup->m_bilinkMembership.GetNext();
  2417. while (pBilink != &pGroup->m_bilinkMembership)
  2418. {
  2419. pGroupMember = CONTAINING_OBJECT(pBilink,CGroupMember,m_bilinkPlayers);
  2420. pGroupMember->AddRef();
  2421. pGroupMember->Lock();
  2422. DNASSERT(pGroupMember->GetGroup() != NULL);
  2423. DNASSERT(pGroupMember->GetPlayer() != NULL);
  2424. DNASSERT(pGroupMember->GetGroup() == pGroup);
  2425. pGroupMember->GetPlayer()->AddRef();
  2426. pPlayer = pGroupMember->GetPlayer();
  2427. pGroup->Unlock();
  2428. pGroupMember->Unlock();
  2429. fNotifyAddPlayerToGroup = FALSE;
  2430. fNotifyRemovePlayerFromGroup = FALSE;
  2431. pGroup->Lock();
  2432. pPlayer->Lock();
  2433. pGroupMember->Lock();
  2434. DNASSERT( pGroupMember->GetGroupConnection() != NULL );
  2435. if ( pPlayer->IsCreated()
  2436. && !pPlayer->IsDisconnecting()
  2437. && pGroup->IsCreated()
  2438. && !pGroup->IsDisconnecting()
  2439. && !pGroupMember->IsAvailable()
  2440. && !pGroupMember->IsNeedToAdd()
  2441. && !pGroupMember->GetGroupConnection()->IsConnected() )
  2442. {
  2443. pGroupMember->MakeAvailable();
  2444. pGroupMember->SetNeedToAdd();
  2445. fNotifyAddPlayerToGroup = TRUE;
  2446. }
  2447. pGroup->Unlock();
  2448. pPlayer->Unlock();
  2449. pGroupMember->Unlock();
  2450. if (fNotifyAddPlayerToGroup)
  2451. {
  2452. DNUserAddPlayerToGroup(m_pdnObject,pGroup,pPlayer);
  2453. pGroupMember->Lock();
  2454. pGroupMember->ClearNeedToAdd();
  2455. if (pGroupMember->IsNeedToRemove())
  2456. {
  2457. fNotifyRemovePlayerFromGroup = TRUE;
  2458. }
  2459. pGroupMember->Unlock();
  2460. }
  2461. if (fNotifyRemovePlayerFromGroup)
  2462. {
  2463. RemovePlayerFromGroup(pGroup,pPlayer,NULL);
  2464. }
  2465. pPlayer->Release();
  2466. pPlayer = NULL;
  2467. //
  2468. // Release old group member and transfer reference
  2469. //
  2470. if (pOldGroupMember)
  2471. {
  2472. pOldGroupMember->Release();
  2473. pOldGroupMember = NULL;
  2474. }
  2475. pOldGroupMember = pGroupMember;
  2476. pGroupMember = NULL;
  2477. pGroup->Lock();
  2478. if (pBilink->IsEmpty())
  2479. {
  2480. pBilink = pGroup->m_bilinkMembership.GetNext();
  2481. }
  2482. else
  2483. {
  2484. pBilink = pBilink->GetNext();
  2485. }
  2486. }
  2487. pGroup->Unlock();
  2488. if (pOldGroupMember)
  2489. {
  2490. pOldGroupMember->Release();
  2491. pOldGroupMember = NULL;
  2492. }
  2493. Exit:
  2494. DNASSERT(pPlayer == NULL);
  2495. DNASSERT(pGroupMember == NULL);
  2496. DNASSERT(pOldGroupMember == NULL);
  2497. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  2498. return(hResultCode);
  2499. Failure:
  2500. if (pPlayer)
  2501. {
  2502. pPlayer->Release();
  2503. pPlayer = NULL;
  2504. }
  2505. goto Exit;
  2506. }
  2507. //
  2508. // This will generate CREATE_GROUP messages for all of the auto-destruct groups owned by a particular player
  2509. //
  2510. #undef DPF_MODNAME
  2511. #define DPF_MODNAME "CNameTable::AutoCreateGroups"
  2512. HRESULT CNameTable::AutoCreateGroups(CNameTableEntry *const pPlayer)
  2513. {
  2514. HRESULT hResultCode;
  2515. BOOL fNotify;
  2516. CBilink *pBilink;
  2517. CNameTableEntry *pGroup;
  2518. CNameTableEntry *pOldGroup;
  2519. DPFX(DPFPREP, 6,"Parameters: pPlayer [0x%p]",pPlayer);
  2520. DNASSERT(pPlayer != NULL);
  2521. pGroup = NULL;
  2522. pOldGroup = NULL;
  2523. if (pPlayer->IsGroup())
  2524. {
  2525. hResultCode = DPNERR_INVALIDPLAYER;
  2526. goto Failure;
  2527. }
  2528. ReadLock();
  2529. pBilink = m_bilinkGroups.GetNext();
  2530. while (pBilink != &m_bilinkGroups)
  2531. {
  2532. pGroup = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  2533. pGroup->AddRef();
  2534. Unlock();
  2535. fNotify = FALSE;
  2536. pGroup->Lock();
  2537. if ( pGroup->IsAutoDestructGroup()
  2538. && (pGroup->GetOwner() == pPlayer->GetDPNID())
  2539. && !pGroup->IsAvailable()
  2540. && !pGroup->IsDisconnecting() )
  2541. {
  2542. pGroup->MakeAvailable();
  2543. pGroup->NotifyAddRef();
  2544. pGroup->NotifyAddRef();
  2545. pGroup->SetInUse();
  2546. fNotify = TRUE;
  2547. }
  2548. pGroup->Unlock();
  2549. if (fNotify)
  2550. {
  2551. DNASSERT(!pGroup->IsAllPlayersGroup());
  2552. DNUserCreateGroup(m_pdnObject,pGroup);
  2553. pGroup->PerformQueuedOperations();
  2554. //
  2555. // Attempt to populate group with connected players
  2556. //
  2557. PopulateGroup(pGroup);
  2558. }
  2559. //
  2560. // Release old group and transfer reference
  2561. //
  2562. if (pOldGroup)
  2563. {
  2564. pOldGroup->Release();
  2565. pOldGroup = NULL;
  2566. }
  2567. pOldGroup = pGroup;
  2568. pGroup = NULL;
  2569. ReadLock();
  2570. if (pBilink->IsEmpty())
  2571. {
  2572. //
  2573. // We were removed from the list of groups, so re-start at the beginning
  2574. //
  2575. pBilink = m_bilinkGroups.GetNext();
  2576. }
  2577. else
  2578. {
  2579. pBilink = pBilink->GetNext();
  2580. }
  2581. }
  2582. Unlock();
  2583. if (pOldGroup)
  2584. {
  2585. pOldGroup->Release();
  2586. pOldGroup = NULL;
  2587. }
  2588. hResultCode = DPN_OK;
  2589. Exit:
  2590. DNASSERT(pGroup == NULL);
  2591. DNASSERT(pOldGroup == NULL);
  2592. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  2593. return(hResultCode);
  2594. Failure:
  2595. if (pGroup)
  2596. {
  2597. pGroup->Release();
  2598. pGroup = NULL;
  2599. }
  2600. goto Exit;
  2601. }
  2602. #undef DPF_MODNAME
  2603. #define DPF_MODNAME "CNameTable::AutoDestructGroups"
  2604. HRESULT CNameTable::AutoDestructGroups(const DPNID dpnid)
  2605. {
  2606. CBilink *pBilink;
  2607. CNameTableEntry *pNTEntry;
  2608. CNameTableEntry *pOldNTEntry;
  2609. pNTEntry = NULL;
  2610. pOldNTEntry = NULL;
  2611. ReadLock();
  2612. pBilink = m_bilinkGroups.GetNext();
  2613. while (pBilink != &m_bilinkGroups)
  2614. {
  2615. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  2616. pNTEntry->AddRef();
  2617. Unlock();
  2618. if (pNTEntry->IsAutoDestructGroup() && (pNTEntry->GetOwner() == dpnid))
  2619. {
  2620. pNTEntry->Lock();
  2621. if (pNTEntry->GetDestroyReason() == 0)
  2622. {
  2623. pNTEntry->SetDestroyReason( DPNDESTROYGROUPREASON_AUTODESTRUCTED );
  2624. }
  2625. pNTEntry->Unlock();
  2626. DeleteGroup(pNTEntry->GetDPNID(),NULL);
  2627. }
  2628. //
  2629. // Release old entry and transfer reference
  2630. //
  2631. if (pOldNTEntry)
  2632. {
  2633. pOldNTEntry->Release();
  2634. pOldNTEntry = NULL;
  2635. }
  2636. pOldNTEntry = pNTEntry;
  2637. pNTEntry = NULL;
  2638. ReadLock();
  2639. //
  2640. // Avoid infinite loops by ensuring that we are not on a "disconnected" entry
  2641. //
  2642. if ((pBilink->GetNext() != &m_bilinkGroups) && (pBilink->GetNext() == pBilink))
  2643. {
  2644. //
  2645. // We have an invalid entry - need to restart
  2646. //
  2647. pBilink = m_bilinkGroups.GetNext();
  2648. }
  2649. else
  2650. {
  2651. //
  2652. // We either have a valid entry or we're finished
  2653. //
  2654. pBilink = pBilink->GetNext();
  2655. }
  2656. }
  2657. Unlock();
  2658. if (pOldNTEntry)
  2659. {
  2660. pOldNTEntry->Release();
  2661. pOldNTEntry = NULL;
  2662. }
  2663. DNASSERT(pNTEntry == NULL);
  2664. DNASSERT(pOldNTEntry == NULL);
  2665. return(DPN_OK);
  2666. }
  2667. #undef DPF_MODNAME
  2668. #define DPF_MODNAME "CNameTable::DecOutstandingConnections"
  2669. void CNameTable::DecOutstandingConnections( void )
  2670. {
  2671. LONG lRefCount;
  2672. lRefCount = DNInterlockedDecrement(&m_lOutstandingConnections);
  2673. DNASSERT(lRefCount >= 0);
  2674. if (lRefCount == 0)
  2675. {
  2676. CAsyncOp *pConnectParent;
  2677. pConnectParent = NULL;
  2678. //
  2679. // Clear connect handle from DirectNetObject if we are connected
  2680. //
  2681. DNEnterCriticalSection(&m_pdnObject->csDirectNetObject);
  2682. if (m_pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED|DN_OBJECT_FLAG_CONNECTING))
  2683. {
  2684. DPFX(DPFPREP, 5,"Clearing connection operation from DirectNetObject");
  2685. pConnectParent = m_pdnObject->pConnectParent;
  2686. m_pdnObject->pConnectParent = NULL;
  2687. }
  2688. DNLeaveCriticalSection(&m_pdnObject->csDirectNetObject);
  2689. if (pConnectParent)
  2690. {
  2691. //
  2692. // We will set the connect parent as complete and remove this from the parent's (if it exists - it will be the connect handle)
  2693. // bilink of children to prevent a race condition of the connect being cancelled from above
  2694. //
  2695. pConnectParent->Lock();
  2696. pConnectParent->SetComplete();
  2697. pConnectParent->Unlock();
  2698. pConnectParent->Orphan();
  2699. pConnectParent->Release();
  2700. pConnectParent = NULL;
  2701. }
  2702. }
  2703. }
  2704. #undef DPF_MODNAME
  2705. #define DPF_MODNAME "CNameTable::GetLocalPlayerRef"
  2706. HRESULT CNameTable::GetLocalPlayerRef( CNameTableEntry **const ppNTEntry )
  2707. {
  2708. HRESULT hResultCode;
  2709. ReadLock();
  2710. if (m_pLocalPlayer)
  2711. {
  2712. m_pLocalPlayer->AddRef();
  2713. *ppNTEntry = m_pLocalPlayer;
  2714. hResultCode = DPN_OK;
  2715. }
  2716. else
  2717. {
  2718. hResultCode = DPNERR_INVALIDPLAYER;
  2719. }
  2720. Unlock();
  2721. return(hResultCode);
  2722. }
  2723. #undef DPF_MODNAME
  2724. #define DPF_MODNAME "CNameTable::GetHostPlayerRef"
  2725. HRESULT CNameTable::GetHostPlayerRef( CNameTableEntry **const ppNTEntry )
  2726. {
  2727. HRESULT hResultCode;
  2728. ReadLock();
  2729. if (m_pHostPlayer)
  2730. {
  2731. m_pHostPlayer->AddRef();
  2732. *ppNTEntry = m_pHostPlayer;
  2733. hResultCode = DPN_OK;
  2734. }
  2735. else
  2736. {
  2737. hResultCode = DPNERR_INVALIDPLAYER;
  2738. }
  2739. Unlock();
  2740. return(hResultCode);
  2741. }
  2742. #undef DPF_MODNAME
  2743. #define DPF_MODNAME "CNameTable::GetAllPlayersGroupRef"
  2744. HRESULT CNameTable::GetAllPlayersGroupRef( CNameTableEntry **const ppNTEntry )
  2745. {
  2746. HRESULT hResultCode;
  2747. ReadLock();
  2748. if (m_pAllPlayersGroup)
  2749. {
  2750. m_pAllPlayersGroup->AddRef();
  2751. *ppNTEntry = m_pAllPlayersGroup;
  2752. hResultCode = DPN_OK;
  2753. }
  2754. else
  2755. {
  2756. hResultCode = DPNERR_INVALIDPLAYER;
  2757. }
  2758. Unlock();
  2759. return(hResultCode);
  2760. }