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.

1835 lines
52 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Migration.cpp
  6. * Content: DNET Host Migration Routines
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 12/23/99 mjn Created
  12. * 12/23/99 mjn Fixed basic host migration
  13. * 12/28/99 mjn Added DNCompleteOutstandingOperations
  14. * 12/28/99 mjn Added NameTable version to Host migration message
  15. * 12/28/99 mjn Moved Async Op stuff to Async.h
  16. * 01/04/00 mjn Added code to allow outstanding ops to complete at host migration
  17. * 01/06/00 mjn Moved NameTable stuff to NameTable.h
  18. * 01/11/00 mjn Moved connect/disconnect stuff to Connect.h
  19. * 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer
  20. * 01/16/00 mjn Moved User callback stuff to User.h
  21. * 01/17/00 mjn Generate DN_MSGID_HOST_MIGRATE at host migration
  22. * 01/19/00 mjn Auto destruct groups at host migration
  23. * 01/24/00 mjn Use DNNTUpdateVersion to update NameTable version
  24. * 01/25/00 mjn Send dwLatestVersion to Host at migration
  25. * 01/25/00 mjn Changed Host Migration to multi-step affair
  26. * 01/26/00 mjn Implemented NameTable re-sync at host migration
  27. * 02/01/00 mjn Implement Player/Group context values
  28. * 02/04/00 mjn Clean up NameTable to remove old entries
  29. * 03/25/00 rmt Added calls into DPNSVR modules
  30. * 04/04/00 rmt Added check for DPNSVR disable flag before attempting to register w/DPNSVR
  31. * 04/16/00 mjn DNSendMessage() used CAsyncOp
  32. * 04/18/00 mjn CConnection tracks connection status better
  33. * mjn Fixed player count problem
  34. * 04/19/00 mjn Update NameTable operations to use DN_WORKER_JOB_SEND_NAMETABLE_OPERATION
  35. * 04/25/00 mjn Fixed migration process to ensure use of CAsyncOp
  36. * mjn Migration calls CoInitialize()/CoUninitialize() before registering w/ DPNSVR
  37. * 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer()
  38. * 05/04/00 mjn Ensure local player still in session for Host migration
  39. * 05/16/00 mjn Do not take locks when clearing NameTable short-cut pointers
  40. * 06/25/00 mjn Ignore players older than old Host when determining new Host in DNFindNewHost()
  41. * 07/06/00 mjn Fixed locking problem in CNameTable::MakeLocalPlayer,MakeHostPlayer,MakeAllPlayersGroup
  42. * 07/07/00 mjn Added shut down checks to migration code.
  43. * 07/20/00 mjn Cleaned up leaking RefCountBuffers and added closing tests
  44. * 07/21/00 mjn Added code in DNCheckReceivedAllVersions() to skip disconnecting players
  45. * 07/27/00 rmt Bug #40882 - DPLSESSION_HOSTMIGRATED status update is not sent
  46. * 07/31/00 mjn Added dwDestroyReason to DNHostDisconnect()
  47. * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
  48. * 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage()
  49. * mjn Added fInternal to DNPerformChildSend()
  50. * 08/06/00 mjn Added CWorkerJob
  51. * 08/07/00 mjn Handle integrity check requests during host migration
  52. * 08/08/00 mjn Moved DN_NAMETABLE_OP_INFO to Message.h
  53. * 08/11/00 mjn Added DN_OBJECT_FLAG_HOST_MIGRATING_2 to prevent multiple threads from passing DNCheckReceivedAllVersions()
  54. * 08/15/00 mjn Perform LISTEN registration with DPNSVR in PerformHostMigration3()
  55. * 08/24/00 mjn Replace DN_NAMETABLE_OP with CNameTableOp
  56. * 09/04/00 mjn Added CApplicationDesc
  57. * 09/06/00 mjn Fixed register with DPNSVR problem
  58. * 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups
  59. * 10/12/00 mjn Ensure proper locks taken when traversing CNameTable::m_bilinkEntries
  60. * 01/25/01 mjn Fixed 64-bit alignment problem in received messages
  61. * 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's
  62. * 04/05/01 mjn Added DPNID parameter to DNProcessHostMigration3() to ensure correct new host is completing host migration
  63. * 04/13/01 mjn Use request list instead of async op list when retrying outstanding requests
  64. * 05/17/01 mjn Wait for threads performing NameTable operations to finish before sending NameTable version during host migration
  65. * 07/22/01 mjn Added DPNBUILD_NOHOSTMIGRATE compile flag
  66. *@@END_MSINTERNAL
  67. *
  68. ***************************************************************************/
  69. #include "dncorei.h"
  70. #ifndef DPNBUILD_NOHOSTMIGRATE
  71. // DNFindNewHost
  72. //
  73. // Find the new host from the entries in the NameTable.
  74. // This is based on version number of the players in the NameTable. The player with
  75. // the oldest version number (after the old Host) will be the new Host.
  76. //
  77. // DPNID *pdpnidNewHost New Host DNID
  78. #undef DPF_MODNAME
  79. #define DPF_MODNAME "DNFindNewHost"
  80. HRESULT DNFindNewHost(DIRECTNETOBJECT *const pdnObject,
  81. DPNID *const pdpnidNewHost)
  82. {
  83. CBilink *pBilink;
  84. CNameTableEntry *pNTEntry;
  85. CNameTableEntry *pLocalPlayer;
  86. CNameTableEntry *pHostPlayer;
  87. HRESULT hResultCode;
  88. DWORD dwVersionNewHost;
  89. DWORD dwVersionOldHost;
  90. DPNID dpnidNewHost;
  91. DPFX(DPFPREP, 6,"Parameters: pdpnidNewHost [0x%p]",pdpnidNewHost);
  92. DNASSERT(pdnObject != NULL);
  93. pNTEntry = NULL;
  94. pLocalPlayer = NULL;
  95. pHostPlayer = NULL;
  96. //
  97. // Seed local player as new Host
  98. //
  99. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  100. {
  101. DPFERR("Could not get local player reference");
  102. DisplayDNError(0,hResultCode);
  103. hResultCode = DPNERR_INVALIDPLAYER;
  104. goto Failure;
  105. }
  106. dpnidNewHost = pLocalPlayer->GetDPNID();
  107. dwVersionNewHost = pLocalPlayer->GetVersion();
  108. DPFX(DPFPREP, 7,"First Host Candidate: dpnid [0x%lx], dwVersion [%ld]",dpnidNewHost,dwVersionNewHost);
  109. pLocalPlayer->Release();
  110. pLocalPlayer = NULL;
  111. //
  112. // Determine old host player version
  113. //
  114. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) == DPN_OK)
  115. {
  116. dwVersionOldHost = pHostPlayer->GetVersion();
  117. pHostPlayer->Release();
  118. pHostPlayer = NULL;
  119. }
  120. else
  121. {
  122. dwVersionOldHost = 0;
  123. }
  124. //
  125. // Lock down NameTable
  126. //
  127. pdnObject->NameTable.ReadLock();
  128. // Traverse NameTable to find player with next older version
  129. // TODO - we should release the NameTable CS so that leaving players get updated in NameTable
  130. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  131. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  132. {
  133. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  134. pNTEntry->Lock();
  135. if (!pNTEntry->IsDisconnecting() && (pNTEntry->GetVersion() < dwVersionNewHost))
  136. {
  137. //
  138. // There are some conditions where we might have players older than the Host in the NameTable
  139. // Consider the following: P1,P2,P3,P4 (P1 is Host)
  140. // - P1, P2 drop
  141. // - P3 detects drop of P1 and P2
  142. // - P4 detects drop of P1 only (P2 may not yet have timed out)
  143. // - P3 sends HOST_MIGRATE message to P4
  144. // - P4 makes P3 new Host, but P2 is still in NameTable (at this stage)
  145. // - P3 drops (P2's drop sill has not been detected!)
  146. // We should therefore ignore all players older than the old Host,
  147. //
  148. if (pNTEntry->GetVersion() < dwVersionOldHost)
  149. {
  150. DPFERR("Found player older than old Host ! (Have we missed a drop ?)");
  151. }
  152. else
  153. {
  154. dpnidNewHost = pNTEntry->GetDPNID();
  155. dwVersionNewHost = pNTEntry->GetVersion();
  156. DPFX(DPFPREP, 7,"Better Host Candidate: dpnid [0x%lx], dwVersion [%ld]",
  157. dpnidNewHost,dwVersionNewHost);
  158. }
  159. }
  160. pNTEntry->Unlock();
  161. pNTEntry = NULL;
  162. pBilink = pBilink->GetNext();
  163. }
  164. //
  165. // Unlock NameTable
  166. //
  167. pdnObject->NameTable.Unlock();
  168. DPFX(DPFPREP, 7,"Found New Host: dpnid [0x%lx], dwVersion [%ld]",dpnidNewHost,dwVersionNewHost);
  169. if (pdpnidNewHost)
  170. *pdpnidNewHost = dpnidNewHost;
  171. hResultCode = DPN_OK;
  172. Exit:
  173. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  174. return(hResultCode);
  175. Failure:
  176. if (pLocalPlayer)
  177. {
  178. pLocalPlayer->Release();
  179. pLocalPlayer = NULL;
  180. }
  181. if (pHostPlayer)
  182. {
  183. pHostPlayer->Release();
  184. pHostPlayer = NULL;
  185. }
  186. goto Exit;
  187. }
  188. // DNPerformHostMigration1
  189. //
  190. // Perform host migration to become the new Host.
  191. #undef DPF_MODNAME
  192. #define DPF_MODNAME "DNPerformHostMigration1"
  193. HRESULT DNPerformHostMigration1(DIRECTNETOBJECT *const pdnObject,
  194. const DPNID dpnidOldHost)
  195. {
  196. HRESULT hResultCode;
  197. CRefCountBuffer *pRefCountBuffer;
  198. CWorkerJob *pWorkerJob;
  199. CNameTableEntry *pLocalPlayer;
  200. CPendingDeletion *pPending;
  201. DN_INTERNAL_MESSAGE_HOST_MIGRATE *pInfo;
  202. CBilink *pBilink;
  203. CNameTableOp *pNTOp;
  204. DPFX(DPFPREP, 6,"Parameters: dpnidOldHost [0x%lx]",dpnidOldHost);
  205. DNASSERT(pdnObject != NULL);
  206. pLocalPlayer = NULL;
  207. pRefCountBuffer = NULL;
  208. pPending = NULL;
  209. pWorkerJob = NULL;
  210. pNTOp = NULL;
  211. //
  212. // Need reference on local player
  213. //
  214. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  215. {
  216. DPFERR("Could not get reference on LocalPlayer");
  217. goto Failure;
  218. }
  219. //
  220. // Flag as performing host migration - ensure we're not already running this from another thread
  221. //
  222. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  223. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
  224. {
  225. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  226. hResultCode = DPN_OK;
  227. goto Failure;
  228. }
  229. if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING)
  230. {
  231. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  232. hResultCode = DPN_OK;
  233. goto Failure;
  234. }
  235. pdnObject->dwFlags |= DN_OBJECT_FLAG_HOST_MIGRATING;
  236. DNASSERT(pdnObject->pNewHost == NULL);
  237. pLocalPlayer->AddRef();
  238. pdnObject->pNewHost = pLocalPlayer;
  239. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  240. //
  241. // Put this on the Outstanding operation list
  242. //
  243. if ((hResultCode = PendingDeletionNew(pdnObject,&pPending)) == DPN_OK)
  244. {
  245. pPending->SetDPNID( dpnidOldHost );
  246. DNEnterCriticalSection(&pdnObject->csNameTableOpList);
  247. pPending->m_bilinkPendingDeletions.InsertBefore(&pdnObject->m_bilinkPendingDeletions);
  248. DNLeaveCriticalSection(&pdnObject->csNameTableOpList);
  249. pPending = NULL;
  250. }
  251. #ifndef DPNBUILD_NOLOBBY
  252. DNUpdateLobbyStatus(pdnObject,DPLSESSION_HOSTMIGRATEDHERE);
  253. #endif // ! DPNBUILD_NOLOBBY
  254. //
  255. // Make new host
  256. //
  257. pdnObject->NameTable.UpdateHostPlayer( pLocalPlayer );
  258. //
  259. // We will need to wait for all threads performing name table operations to finish running
  260. // before we send the current name table version to the host player
  261. //
  262. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  263. pdnObject->dwFlags |= DN_OBJECT_FLAG_HOST_MIGRATING_WAIT;
  264. if (pdnObject->dwRunningOpCount > 0)
  265. {
  266. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  267. DPFX(DPFPREP,7,"Waiting for running threads to finish");
  268. IDirectPlay8ThreadPoolWork_WaitWhileWorking(pdnObject->pIDPThreadPoolWork,
  269. HANDLE_FROM_DNHANDLE(pdnObject->hRunningOpEvent),
  270. 0);
  271. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  272. }
  273. else
  274. {
  275. DPFX(DPFPREP,7,"No running threads to wait for");
  276. }
  277. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  278. //
  279. // Clean-up outstanding operations
  280. //
  281. DPFX(DPFPREP,7,"Cleaning up outstanding NameTable operations");
  282. pdnObject->NameTable.WriteLock();
  283. DPFX(DPFPREP,7,"NameTable version [%ld]",pdnObject->NameTable.GetVersion());
  284. pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
  285. while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
  286. {
  287. pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
  288. pBilink = pBilink->GetNext();
  289. if (pNTOp->GetVersion() > pdnObject->NameTable.GetVersion())
  290. {
  291. DPFX(DPFPREP,7,"Removing outstanding operation [0x%p], version [%ld]",pNTOp,pNTOp->GetVersion());
  292. pNTOp->m_bilinkNameTableOps.RemoveFromList();
  293. if (pNTOp->GetRefCountBuffer())
  294. {
  295. pNTOp->GetRefCountBuffer()->Release();
  296. pNTOp->SetRefCountBuffer( NULL );
  297. }
  298. if (pNTOp->GetSP())
  299. {
  300. pNTOp->GetSP()->Release();
  301. pNTOp->SetSP( NULL );
  302. }
  303. pNTOp->ReturnSelfToPool();
  304. }
  305. pNTOp = NULL;
  306. }
  307. pdnObject->NameTable.Unlock();
  308. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  309. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_HOST_MIGRATING_WAIT);
  310. DNResetEvent(pdnObject->hRunningOpEvent);
  311. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  312. //
  313. // Update NameTable operation list version
  314. //
  315. hResultCode = DNNTPlayerSendVersion(pdnObject);
  316. //
  317. // Update protocol (and SP)
  318. DNUpdateListens(pdnObject,DN_UPDATE_LISTEN_FLAG_HOST_MIGRATE);
  319. // Only need to proceed if we're not the only player left in the session
  320. if ((hResultCode = DNCheckReceivedAllVersions(pdnObject)) != DPN_OK)
  321. {
  322. // Inform other players of host migration
  323. DPFX(DPFPREP, 7,"Informing other players of host migration");
  324. hResultCode = RefCountBufferNew(pdnObject,
  325. sizeof(DN_INTERNAL_MESSAGE_HOST_MIGRATE),
  326. MemoryBlockAlloc,
  327. MemoryBlockFree,
  328. &pRefCountBuffer);
  329. if (hResultCode != DPN_OK)
  330. {
  331. DPFERR("Could not create RefCountBuffer for Host Migration");
  332. DisplayDNError(0,hResultCode);
  333. DNASSERT(FALSE);
  334. goto Failure;
  335. }
  336. pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_HOST_MIGRATE*>(pRefCountBuffer->GetBufferAddress());
  337. pInfo->dpnidNewHost = pLocalPlayer->GetDPNID();
  338. pInfo->dpnidOldHost = dpnidOldHost;
  339. if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
  340. {
  341. DPFERR("Could not create WorkerJob for Host Migration");
  342. DisplayDNError(0,hResultCode);
  343. DNASSERT(FALSE);
  344. goto Failure;
  345. }
  346. pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION );
  347. pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_HOST_MIGRATE );
  348. pWorkerJob->SetSendNameTableOperationVersion( 0 );
  349. pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 );
  350. pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
  351. DNQueueWorkerJob(pdnObject,pWorkerJob);
  352. pWorkerJob = NULL;
  353. pRefCountBuffer->Release();
  354. pRefCountBuffer = NULL;
  355. }
  356. pLocalPlayer->Release();
  357. pLocalPlayer = NULL;
  358. hResultCode = DPN_OK;
  359. Exit:
  360. DNASSERT( pNTOp == NULL );
  361. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  362. return(hResultCode);
  363. Failure:
  364. if (pLocalPlayer)
  365. {
  366. pLocalPlayer->Release();
  367. pLocalPlayer = NULL;
  368. }
  369. if (pRefCountBuffer)
  370. {
  371. pRefCountBuffer->Release();
  372. pRefCountBuffer = NULL;
  373. }
  374. if (pPending)
  375. {
  376. pPending->ReturnSelfToPool();
  377. pPending = NULL;
  378. }
  379. goto Exit;
  380. }
  381. // DNPerformHostMigration2
  382. //
  383. // Resynchronize NameTables of all connected players
  384. #undef DPF_MODNAME
  385. #define DPF_MODNAME "DNPerformHostMigration2"
  386. HRESULT DNPerformHostMigration2(DIRECTNETOBJECT *const pdnObject)
  387. {
  388. HRESULT hResultCode;
  389. CRefCountBuffer *pRefCountBuffer;
  390. CBilink *pBilink;
  391. CNameTableEntry *pLocalPlayer;
  392. CNameTableEntry *pNTEntry;
  393. CNameTableEntry *pNTELatest;
  394. CConnection *pConnection;
  395. DN_INTERNAL_MESSAGE_REQ_NAMETABLE_OP *pInfo;
  396. DPFX(DPFPREP, 6,"Parameters: (none)");
  397. DNASSERT(pdnObject != NULL);
  398. pRefCountBuffer = NULL;
  399. pLocalPlayer = NULL;
  400. pNTEntry = NULL;
  401. pNTELatest = NULL;
  402. pConnection = NULL;
  403. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  404. {
  405. DPFERR("Could not get local player reference");
  406. DisplayDNError(0,hResultCode);
  407. goto Failure;
  408. }
  409. //
  410. // See if we (Host player) have the latest NameTable
  411. //
  412. pLocalPlayer->AddRef();
  413. pNTELatest = pLocalPlayer;
  414. DPFX(DPFPREP, 7,"Seed latest version [%ld] - player [0x%lx]",pNTELatest->GetLatestVersion(),pNTELatest->GetDPNID());
  415. pdnObject->NameTable.ReadLock();
  416. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  417. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  418. {
  419. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  420. pNTEntry->Lock();
  421. if (!pNTEntry->IsDisconnecting() && (pNTEntry->GetLatestVersion() > pNTELatest->GetLatestVersion()))
  422. {
  423. //
  424. // Only want players we can actually reach !
  425. //
  426. pNTEntry->Unlock();
  427. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) == DPN_OK)
  428. {
  429. if (!pConnection->IsDisconnecting() && !pConnection->IsInvalid())
  430. {
  431. pNTELatest->Release();
  432. pNTEntry->AddRef();
  433. pNTELatest = pNTEntry;
  434. DPFX(DPFPREP, 7,"New latest version [%ld] - player [0x%lx]",
  435. pNTELatest->GetLatestVersion(),pNTELatest->GetDPNID());
  436. }
  437. pConnection->Release();
  438. pConnection = NULL;
  439. }
  440. else
  441. {
  442. DNASSERT(pConnection == NULL);
  443. }
  444. }
  445. else
  446. {
  447. pNTEntry->Unlock();
  448. }
  449. pNTEntry = NULL;
  450. pBilink = pBilink->GetNext();
  451. }
  452. pdnObject->NameTable.Unlock();
  453. if (!pNTELatest->IsLocal())
  454. {
  455. // Request missing entries from player w/ latest NameTable
  456. DPFX(DPFPREP, 7,"Host DOES NOT have latest NameTable !");
  457. DPFX(DPFPREP, 7,"Host has [%ld], player [0x%lx] has [%ld]",pLocalPlayer->GetLatestVersion(),
  458. pNTELatest->GetDPNID(),pNTELatest->GetLatestVersion());
  459. // Create REQ
  460. hResultCode = RefCountBufferNew(pdnObject,
  461. sizeof(DN_INTERNAL_MESSAGE_REQ_NAMETABLE_OP),
  462. MemoryBlockAlloc,
  463. MemoryBlockFree,
  464. &pRefCountBuffer);
  465. if (hResultCode != DPN_OK)
  466. {
  467. DPFERR("Could not create RefCount buffer for NameTable re-sync");
  468. DisplayDNError(0,hResultCode);
  469. DNASSERT(FALSE);
  470. goto Failure;
  471. }
  472. pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_NAMETABLE_OP*>(pRefCountBuffer->GetBufferAddress());
  473. pInfo->dwVersion = pLocalPlayer->GetLatestVersion() + 1;
  474. pInfo->dwVersionNotUsed = 0;
  475. // Send REQ
  476. if ((hResultCode = pNTELatest->GetConnectionRef( &pConnection )) == DPN_OK)
  477. {
  478. hResultCode = DNSendMessage(pdnObject,
  479. pConnection,
  480. DN_MSG_INTERNAL_REQ_NAMETABLE_OP,
  481. pNTELatest->GetDPNID(),
  482. pRefCountBuffer->BufferDescAddress(),
  483. 1,
  484. pRefCountBuffer,
  485. 0,
  486. DN_SENDFLAGS_RELIABLE,
  487. NULL,
  488. NULL);
  489. if (hResultCode != DPNERR_PENDING)
  490. {
  491. DPFERR("Could not send NameTable re-sync REQ");
  492. DisplayDNError(0,hResultCode);
  493. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  494. DNASSERT(FALSE);
  495. goto Failure;
  496. }
  497. pConnection->Release();
  498. pConnection = NULL;
  499. }
  500. pRefCountBuffer->Release(); // Added 19/07/00 MJN - is this needed ?
  501. pRefCountBuffer = NULL;
  502. }
  503. else
  504. {
  505. DPFX(DPFPREP, 7,"Host has latest NameTable - proceed with Host Migration");
  506. hResultCode = DNPerformHostMigration3(pdnObject,NULL);
  507. }
  508. pNTELatest->Release();
  509. pNTELatest = NULL;
  510. pLocalPlayer->Release();
  511. pLocalPlayer = NULL;
  512. Exit:
  513. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  514. return(hResultCode);
  515. Failure:
  516. if (pRefCountBuffer)
  517. {
  518. pRefCountBuffer->Release();
  519. pRefCountBuffer = NULL;
  520. }
  521. if (pLocalPlayer)
  522. {
  523. pLocalPlayer->Release();
  524. pLocalPlayer = NULL;
  525. }
  526. if (pNTEntry)
  527. {
  528. pNTEntry->Release();
  529. pNTEntry = NULL;
  530. }
  531. if (pNTELatest)
  532. {
  533. pNTELatest->Release();
  534. pNTELatest = NULL;
  535. }
  536. if (pConnection)
  537. {
  538. pConnection->Release();
  539. pConnection = NULL;
  540. }
  541. goto Exit;
  542. }
  543. // DNPerformHostMigration3
  544. //
  545. // Finish host migration.
  546. // - perform missing NameTable operations and pass them on
  547. // - send pending operations
  548. // - inform players that host migration is complete
  549. // - complete (local) outstanding async operations
  550. // - initiate new listen (if required) to handle enums on known port
  551. // As they say on the TTC, "All operations have returned to normal."
  552. #undef DPF_MODNAME
  553. #define DPF_MODNAME "DNPerformHostMigration3"
  554. HRESULT DNPerformHostMigration3(DIRECTNETOBJECT *const pdnObject,
  555. void *const pMsg)
  556. {
  557. HRESULT hResultCode;
  558. CBilink *pBilink;
  559. CNameTableEntry **PlayerList;
  560. CNameTableEntry *pNTEntry;
  561. CConnection *pConnection;
  562. CPendingDeletion *pPending;
  563. DWORD dwNameTableVersion;
  564. DWORD dw;
  565. DWORD dwCount;
  566. DWORD dwActual;
  567. DWORD dwUpdateFlags;
  568. CNameTableOp *pNTOp;
  569. UNALIGNED DN_NAMETABLE_OP_INFO *pInfo;
  570. UNALIGNED DN_INTERNAL_MESSAGE_ACK_NAMETABLE_OP *pAck;
  571. DPFX(DPFPREP, 6,"Parameters: pMsg [0x%p]",pMsg);
  572. DNASSERT(pdnObject != NULL);
  573. pNTOp = NULL;
  574. pNTEntry = NULL;
  575. pConnection = NULL;
  576. pPending = NULL;
  577. PlayerList = NULL;
  578. //
  579. // Update missing NameTable operations on Host
  580. //
  581. if (pMsg != NULL)
  582. {
  583. pAck = static_cast<DN_INTERNAL_MESSAGE_ACK_NAMETABLE_OP*>(pMsg);
  584. DPFX(DPFPREP, 7,"Number of missing NameTable entries [%ld]",pAck->dwNumEntries);
  585. pInfo = reinterpret_cast<DN_NAMETABLE_OP_INFO*>(pAck+1);
  586. for (dw = 0; dw < pAck->dwNumEntries ; dw++)
  587. {
  588. DPFX(DPFPREP, 7,"Adding missing entry [%ld] of [%ld]",dw+1,pAck->dwNumEntries);
  589. hResultCode = DNNTAddOperation( pdnObject,
  590. pInfo->dwMsgId,
  591. static_cast<void*>(reinterpret_cast<BYTE*>(pMsg) + pInfo->dwOpOffset),
  592. pInfo->dwOpSize,
  593. 0,
  594. NULL );
  595. if (hResultCode != DPN_OK)
  596. {
  597. DPFERR("Could not add missing NameTable operation - ignore and continue");
  598. DisplayDNError(0,hResultCode);
  599. DNASSERT(FALSE);
  600. }
  601. pInfo++;
  602. }
  603. }
  604. //
  605. // Update missing NameTable operations on other players
  606. //
  607. //
  608. // Determine player list
  609. //
  610. dwCount = 0;
  611. dwActual = 0;
  612. pdnObject->NameTable.ReadLock();
  613. dwNameTableVersion = pdnObject->NameTable.GetVersion();
  614. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  615. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  616. {
  617. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  618. pNTEntry->Lock();
  619. if (!pNTEntry->IsDisconnecting() && (pNTEntry->GetLatestVersion() < dwNameTableVersion))
  620. {
  621. dwCount++;
  622. }
  623. pNTEntry->Unlock();
  624. pNTEntry = NULL;
  625. pBilink = pBilink->GetNext();
  626. }
  627. if (dwCount)
  628. {
  629. if ((PlayerList = static_cast<CNameTableEntry**>(DNMalloc(dwCount * sizeof(CNameTableEntry*)))) == NULL)
  630. {
  631. DPFERR("Could not allocate target list");
  632. DNASSERT(FALSE);
  633. pdnObject->NameTable.Unlock();
  634. hResultCode = DPN_OK;
  635. goto Exit;
  636. }
  637. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  638. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  639. {
  640. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  641. pNTEntry->Lock();
  642. if (!pNTEntry->IsDisconnecting() && (pNTEntry->GetLatestVersion() < dwNameTableVersion))
  643. {
  644. DNASSERT(dwActual < dwCount);
  645. pNTEntry->AddRef();
  646. PlayerList[dwActual] = pNTEntry;
  647. dwActual++;
  648. }
  649. pNTEntry->Unlock();
  650. pNTEntry = NULL;
  651. pBilink = pBilink->GetNext();
  652. }
  653. }
  654. pdnObject->NameTable.Unlock();
  655. //
  656. // Send missing entries to players in player list
  657. //
  658. for (dwCount = 0 ; dwCount < dwActual ; dwCount++)
  659. {
  660. //
  661. // Ensure player is reachable
  662. //
  663. if ((hResultCode = PlayerList[dwCount]->GetConnectionRef( &pConnection )) == DPN_OK)
  664. {
  665. if (!pConnection->IsDisconnecting() && !pConnection->IsInvalid())
  666. {
  667. DPFX(DPFPREP, 7,"Player [0x%lx] is missing entries: dwLatestVersion [%ld] should be [%ld]",
  668. PlayerList[dwCount]->GetDPNID(),PlayerList[dwCount]->GetLatestVersion(),dwNameTableVersion);
  669. // Send required entries
  670. for ( dw = PlayerList[dwCount]->GetLatestVersion() + 1 ; dw <= dwNameTableVersion ; dw++ )
  671. {
  672. DPFX(DPFPREP, 7,"Send entry [%ld] to player [0x%lx]",dw,PlayerList[dwCount]->GetDPNID());
  673. // Get entry to send
  674. pNTOp = NULL;
  675. if ((hResultCode = DNNTFindOperation(pdnObject,dw,&pNTOp)) != DPN_OK)
  676. {
  677. DPFERR("Could not retrieve NameTable operation - advance to next player");
  678. DisplayDNError(0,hResultCode);
  679. break;
  680. }
  681. hResultCode = DNSendMessage(pdnObject,
  682. pConnection,
  683. pNTOp->GetMsgId(),
  684. PlayerList[dwCount]->GetDPNID(),
  685. pNTOp->GetRefCountBuffer()->BufferDescAddress(),
  686. 1,
  687. pNTOp->GetRefCountBuffer(),
  688. 0,
  689. DN_SENDFLAGS_RELIABLE,
  690. NULL,
  691. NULL);
  692. if (hResultCode != DPNERR_PENDING)
  693. {
  694. DPFERR("Could not send missing NameTable entry - advance to next player");
  695. DisplayDNError(0,hResultCode);
  696. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  697. DNASSERT(FALSE);
  698. break;
  699. }
  700. } // for
  701. } // if
  702. pConnection->Release();
  703. pConnection = NULL;
  704. } // if
  705. PlayerList[dwCount]->Release();
  706. PlayerList[dwCount] = NULL;
  707. }
  708. if (PlayerList != NULL)
  709. {
  710. DNFree(PlayerList);
  711. PlayerList = NULL;
  712. }
  713. //
  714. // Host finished migration process
  715. //
  716. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  717. pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_HOST_MIGRATING | DN_OBJECT_FLAG_HOST_MIGRATING_2));
  718. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
  719. {
  720. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  721. hResultCode = DPN_OK;
  722. goto Exit;
  723. }
  724. DNASSERT(pdnObject->pNewHost != NULL); // This should be set !
  725. pdnObject->pNewHost->Release();
  726. pdnObject->pNewHost = NULL;
  727. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  728. //
  729. // Cleanup NameTable
  730. //
  731. DPFX(DPFPREP, 7,"Cleaning up NameTable");
  732. hResultCode = DNCleanUpNameTable(pdnObject);
  733. //
  734. // Send pending deletions
  735. //
  736. DPFX(DPFPREP, 7,"Running pending operations");
  737. DNEnterCriticalSection(&pdnObject->csNameTableOpList);
  738. pBilink = pdnObject->m_bilinkPendingDeletions.GetNext();
  739. while (pBilink != &pdnObject->m_bilinkPendingDeletions)
  740. {
  741. pPending = CONTAINING_OBJECT(pBilink,CPendingDeletion,m_bilinkPendingDeletions);
  742. pPending->m_bilinkPendingDeletions.RemoveFromList();
  743. DNLeaveCriticalSection(&pdnObject->csNameTableOpList);
  744. DNHostDisconnect(pdnObject,pPending->GetDPNID(),DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
  745. pPending->ReturnSelfToPool();
  746. pPending = NULL;
  747. DNEnterCriticalSection(&pdnObject->csNameTableOpList);
  748. pBilink = pdnObject->m_bilinkPendingDeletions.GetNext();
  749. }
  750. DNLeaveCriticalSection(&pdnObject->csNameTableOpList);
  751. //
  752. // Inform connected players that Host migration is complete
  753. //
  754. DPFX(DPFPREP, 7,"Sending HOST_MIGRATE_COMPLETE messages");
  755. hResultCode = DNSendHostMigrateCompleteMessage(pdnObject);
  756. //
  757. // Ensure outstanding operations complete
  758. //
  759. DPFX(DPFPREP, 7,"Completing outstanding operations");
  760. hResultCode = DNCompleteOutstandingOperations(pdnObject);
  761. //
  762. // Update listens
  763. //
  764. dwUpdateFlags = 0;
  765. #ifndef DPNBUILD_SINGLEPROCESS
  766. if(pdnObject->ApplicationDesc.UseDPNSVR())
  767. {
  768. dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DPNSVR;
  769. }
  770. #endif // ! DPNBUILD_SINGLEPROCESS
  771. if (pdnObject->ApplicationDesc.DisallowEnums())
  772. {
  773. dwUpdateFlags |= DN_UPDATE_LISTEN_FLAG_DISALLOW_ENUMS;
  774. }
  775. if (dwUpdateFlags)
  776. {
  777. DNUpdateListens(pdnObject,dwUpdateFlags);
  778. }
  779. hResultCode = DPN_OK;
  780. Exit:
  781. DNASSERT(pNTEntry == NULL);
  782. DNASSERT(pConnection == NULL);
  783. DNASSERT(pPending == NULL);
  784. DNASSERT(PlayerList == NULL);
  785. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  786. return(hResultCode);
  787. }
  788. // DNProcessHostMigration1
  789. //
  790. // Perform an instructed host migration
  791. #undef DPF_MODNAME
  792. #define DPF_MODNAME "DNProcessHostMigration1"
  793. HRESULT DNProcessHostMigration1(DIRECTNETOBJECT *const pdnObject,
  794. void *const pvMsg)
  795. {
  796. HRESULT hResultCode;
  797. CNameTableEntry *pNTEntry;
  798. UNALIGNED DN_INTERNAL_MESSAGE_HOST_MIGRATE *pInfo;
  799. DPFX(DPFPREP, 6,"Parameters: pvMsg [0x%p]",pvMsg);
  800. DNASSERT(pdnObject != NULL);
  801. DNASSERT(pvMsg != NULL);
  802. pNTEntry = NULL;
  803. pInfo = static_cast<DN_INTERNAL_MESSAGE_HOST_MIGRATE*>(pvMsg);
  804. DPFX(DPFPREP, 7,"New Host [0x%lx], Old Host [0x%lx]",pInfo->dpnidNewHost,pInfo->dpnidOldHost);
  805. DNASSERT(pInfo->dpnidNewHost != NULL);
  806. DNASSERT(pInfo->dpnidOldHost != NULL);
  807. //
  808. // Update destruction of old host as normal, and disconnect if possible
  809. //
  810. if ((hResultCode = pdnObject->NameTable.FindEntry(pInfo->dpnidOldHost,&pNTEntry)) == DPN_OK)
  811. {
  812. CConnection *pConnection;
  813. pConnection = NULL;
  814. pNTEntry->Lock();
  815. if (pNTEntry->GetDestroyReason() == 0)
  816. {
  817. pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_NORMAL );
  818. }
  819. pNTEntry->Unlock();
  820. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) == DPN_OK)
  821. {
  822. if (pConnection->IsConnected())
  823. {
  824. pConnection->Disconnect();
  825. }
  826. pConnection->Release();
  827. pConnection = NULL;
  828. }
  829. pNTEntry->Release();
  830. pNTEntry = NULL;
  831. DNASSERT( pConnection == NULL );
  832. }
  833. //
  834. // Get new host entry
  835. //
  836. if ((hResultCode = pdnObject->NameTable.FindEntry(pInfo->dpnidNewHost,&pNTEntry)) != DPN_OK)
  837. {
  838. DPFERR("Could not find new host NameTableEntry");
  839. DisplayDNError(0,hResultCode);
  840. hResultCode = DPN_OK;
  841. goto Failure;
  842. }
  843. //
  844. // Set HOST_MIGRATE status on DirectNet object
  845. //
  846. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  847. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
  848. {
  849. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  850. hResultCode = DPN_OK;
  851. goto Failure;
  852. }
  853. if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING)
  854. {
  855. //
  856. // If we are already host migrating, ensure that this message
  857. // is not from on older host than we expect. If it is, we
  858. // will ignore it, and continue
  859. //
  860. DNASSERT(pdnObject->pNewHost != NULL);
  861. if (pdnObject->pNewHost->GetVersion() > pNTEntry->GetVersion())
  862. {
  863. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  864. hResultCode = DPN_OK;
  865. goto Failure;
  866. }
  867. pdnObject->pNewHost->Release();
  868. pdnObject->pNewHost = NULL;
  869. }
  870. pdnObject->dwFlags |= DN_OBJECT_FLAG_HOST_MIGRATING;
  871. DNASSERT( pdnObject->pNewHost == NULL );
  872. pNTEntry->AddRef();
  873. pdnObject->pNewHost = pNTEntry;
  874. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  875. // Delete old host
  876. pdnObject->NameTable.DeletePlayer(pInfo->dpnidOldHost,NULL);
  877. #ifndef DPNBUILD_NOLOBBY
  878. //
  879. // Indicate to lobby (if there is one) that a host migration has occured
  880. //
  881. DNUpdateLobbyStatus(pdnObject,DPLSESSION_HOSTMIGRATED);
  882. #endif // ! DPNBUILD_NOLOBBY
  883. //
  884. // Make new host
  885. //
  886. pdnObject->NameTable.UpdateHostPlayer( pNTEntry );
  887. //
  888. // We will need to wait for all threads performing name table operations to finish running
  889. // before we send the current name table version to the host player
  890. //
  891. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  892. pdnObject->dwFlags |= DN_OBJECT_FLAG_HOST_MIGRATING_WAIT;
  893. pdnObject->dwWaitingThreadID = GetCurrentThreadId();
  894. if (pdnObject->dwRunningOpCount > 0)
  895. {
  896. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  897. DPFX(DPFPREP,7,"Waiting for running threads to finish");
  898. IDirectPlay8ThreadPoolWork_WaitWhileWorking(pdnObject->pIDPThreadPoolWork,
  899. HANDLE_FROM_DNHANDLE(pdnObject->hRunningOpEvent),
  900. 0);
  901. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  902. }
  903. else
  904. {
  905. DPFX(DPFPREP,7,"No running threads to wait for");
  906. }
  907. if (pdnObject->dwWaitingThreadID == GetCurrentThreadId())
  908. {
  909. CBilink *pBilink;
  910. CNameTableOp *pNTOp;
  911. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  912. //
  913. // Clean-up outstanding operations
  914. //
  915. DPFX(DPFPREP,7,"Cleaning up outstanding NameTable operations");
  916. pdnObject->NameTable.WriteLock();
  917. DPFX(DPFPREP,7,"NameTable version [%ld]",pdnObject->NameTable.GetVersion());
  918. pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
  919. while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
  920. {
  921. pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
  922. pBilink = pBilink->GetNext();
  923. if (pNTOp->GetVersion() > pdnObject->NameTable.GetVersion())
  924. {
  925. DPFX(DPFPREP,7,"Removing outstanding operation [0x%p], version [%ld]",pNTOp,pNTOp->GetVersion());
  926. pNTOp->m_bilinkNameTableOps.RemoveFromList();
  927. if (pNTOp->GetRefCountBuffer())
  928. {
  929. pNTOp->GetRefCountBuffer()->Release();
  930. pNTOp->SetRefCountBuffer( NULL );
  931. }
  932. if (pNTOp->GetSP())
  933. {
  934. pNTOp->GetSP()->Release();
  935. pNTOp->SetSP( NULL );
  936. }
  937. pNTOp->ReturnSelfToPool();
  938. }
  939. pNTOp = NULL;
  940. }
  941. pdnObject->NameTable.Unlock();
  942. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  943. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_HOST_MIGRATING_WAIT);
  944. pdnObject->dwWaitingThreadID = 0;
  945. DNResetEvent(pdnObject->hRunningOpEvent);
  946. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  947. }
  948. else
  949. {
  950. //
  951. // Don't continue because a newer host migration on another thread is now waiting
  952. //
  953. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  954. DPFX(DPFPREP,7,"Looks like a newer host migration is running - exiting");
  955. goto Failure;
  956. }
  957. //
  958. // Send NameTable version to Host player
  959. //
  960. DNNTPlayerSendVersion(pdnObject);
  961. pNTEntry->Release();
  962. pNTEntry = NULL;
  963. hResultCode = DPN_OK;
  964. Exit:
  965. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  966. return(hResultCode);
  967. Failure:
  968. if (pNTEntry)
  969. {
  970. pNTEntry->Release();
  971. pNTEntry = NULL;
  972. }
  973. goto Exit;
  974. }
  975. // DNProcessHostMigration2
  976. //
  977. // Send Host player NameTable entries missing from its (Host's) NameTable
  978. #undef DPF_MODNAME
  979. #define DPF_MODNAME "DNProcessHostMigration2"
  980. HRESULT DNProcessHostMigration2(DIRECTNETOBJECT *const pdnObject,
  981. void *const pMsg)
  982. {
  983. HRESULT hResultCode;
  984. DWORD dwAckMsgSize;
  985. CBilink *pBilink;
  986. CNameTableEntry *pHostPlayer;
  987. CConnection *pConnection;
  988. CRefCountBuffer *pRefCountBuffer;
  989. CPackedBuffer PackedBuffer;
  990. CNameTableOp *pNTOp;
  991. DN_NAMETABLE_OP_INFO *pInfo;
  992. UNALIGNED DN_INTERNAL_MESSAGE_REQ_NAMETABLE_OP *pReq;
  993. DN_INTERNAL_MESSAGE_ACK_NAMETABLE_OP *pAck;
  994. DPFX(DPFPREP, 6,"Parameters: pMsg [0x%p]",pMsg);
  995. DNASSERT(pdnObject != NULL);
  996. DNASSERT(pMsg != NULL);
  997. pHostPlayer = NULL;
  998. pConnection = NULL;
  999. pRefCountBuffer = NULL;
  1000. pReq = static_cast<DN_INTERNAL_MESSAGE_REQ_NAMETABLE_OP*>(pMsg);
  1001. DPFX(DPFPREP, 5,"Host requested NameTable ops [%ld] to [%ld]",
  1002. pReq->dwVersion,pdnObject->NameTable.GetVersion());
  1003. //
  1004. // Determine ACK message size
  1005. //
  1006. pdnObject->NameTable.ReadLock();
  1007. DNASSERT(pdnObject->NameTable.GetVersion() >= pReq->dwVersion);
  1008. dwAckMsgSize = sizeof(DN_INTERNAL_MESSAGE_ACK_NAMETABLE_OP); // Number of entries
  1009. dwAckMsgSize += ((pdnObject->NameTable.GetVersion() - pReq->dwVersion + 1) // Message info
  1010. * sizeof(DN_NAMETABLE_OP_INFO));
  1011. pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
  1012. while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
  1013. {
  1014. pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
  1015. if ((pNTOp->GetVersion() >= pReq->dwVersion) && (pNTOp->GetVersion() <= pdnObject->NameTable.GetVersion()))
  1016. {
  1017. DNASSERT(pNTOp->GetRefCountBuffer() != NULL);
  1018. dwAckMsgSize += pNTOp->GetRefCountBuffer()->GetBufferSize();
  1019. }
  1020. pBilink = pBilink->GetNext();
  1021. }
  1022. //
  1023. // Create ACK buffer
  1024. //
  1025. if ((hResultCode = RefCountBufferNew(pdnObject,dwAckMsgSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK)
  1026. {
  1027. DPFERR("Could not create RefCount buffer for NameTable re-sync ACK");
  1028. DisplayDNError(0,hResultCode);
  1029. DNASSERT(FALSE);
  1030. pdnObject->NameTable.Unlock();
  1031. goto Failure;
  1032. }
  1033. PackedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
  1034. pAck = reinterpret_cast<DN_INTERNAL_MESSAGE_ACK_NAMETABLE_OP *>(pRefCountBuffer->GetBufferAddress());
  1035. // Header
  1036. pAck->dwNumEntries = pdnObject->NameTable.GetVersion() - pReq->dwVersion + 1;
  1037. PackedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_ACK_NAMETABLE_OP));
  1038. // Offset list
  1039. pInfo = reinterpret_cast<DN_NAMETABLE_OP_INFO*>(PackedBuffer.GetHeadAddress());
  1040. PackedBuffer.AddToFront(NULL,pAck->dwNumEntries * sizeof(DN_NAMETABLE_OP_INFO));
  1041. // Messages
  1042. pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext();
  1043. while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps)
  1044. {
  1045. pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps);
  1046. if ((pNTOp->GetVersion() >= pReq->dwVersion) && (pNTOp->GetVersion() <= pdnObject->NameTable.GetVersion()))
  1047. {
  1048. DNASSERT(pNTOp->GetRefCountBuffer() != NULL);
  1049. if ((hResultCode = PackedBuffer.AddToBack(pNTOp->GetRefCountBuffer()->GetBufferAddress(),
  1050. pNTOp->GetRefCountBuffer()->GetBufferSize())) != DPN_OK)
  1051. {
  1052. DPFERR("Could not fill NameTable re-sync ACK");
  1053. DisplayDNError(0,hResultCode);
  1054. DNASSERT(FALSE);
  1055. pdnObject->NameTable.Unlock();
  1056. goto Failure;
  1057. }
  1058. pInfo->dwMsgId = pNTOp->GetMsgId();
  1059. pInfo->dwOpOffset = PackedBuffer.GetTailOffset();
  1060. pInfo->dwOpSize = pNTOp->GetRefCountBuffer()->GetBufferSize();
  1061. pInfo++;
  1062. }
  1063. pBilink = pBilink->GetNext();
  1064. }
  1065. pdnObject->NameTable.Unlock();
  1066. // Send ACK buffer
  1067. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK)
  1068. {
  1069. DPFERR("Could not find Host player");
  1070. DisplayDNError(0,hResultCode);
  1071. DNASSERT(FALSE);
  1072. goto Failure;
  1073. }
  1074. if ((hResultCode = pHostPlayer->GetConnectionRef( &pConnection )) != DPN_OK)
  1075. {
  1076. DPFERR("Could not get Connection reference");
  1077. DisplayDNError(0,hResultCode);
  1078. goto Failure;
  1079. }
  1080. hResultCode = DNSendMessage(pdnObject,
  1081. pConnection,
  1082. DN_MSG_INTERNAL_ACK_NAMETABLE_OP,
  1083. pHostPlayer->GetDPNID(),
  1084. pRefCountBuffer->BufferDescAddress(),
  1085. 1,
  1086. pRefCountBuffer,
  1087. 0,
  1088. DN_SENDFLAGS_RELIABLE,
  1089. NULL,
  1090. NULL);
  1091. if (hResultCode != DPNERR_PENDING)
  1092. {
  1093. DPFERR("Could not send NameTable re-sync ACK");
  1094. DisplayDNError(0,hResultCode);
  1095. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  1096. DNASSERT(FALSE);
  1097. goto Failure;
  1098. }
  1099. pRefCountBuffer->Release(); // Added 19/07/00 MJN - Is this needed ?
  1100. pRefCountBuffer = NULL;
  1101. pConnection->Release();
  1102. pConnection = NULL;
  1103. pHostPlayer->Release();
  1104. pHostPlayer = NULL;
  1105. hResultCode = DPN_OK;
  1106. Exit:
  1107. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1108. return(hResultCode);
  1109. Failure:
  1110. if (pHostPlayer)
  1111. {
  1112. pHostPlayer->Release();
  1113. pHostPlayer = NULL;
  1114. }
  1115. if (pConnection)
  1116. {
  1117. pConnection->Release();
  1118. pConnection = NULL;
  1119. }
  1120. if (pRefCountBuffer)
  1121. {
  1122. pRefCountBuffer->Release();
  1123. pRefCountBuffer = NULL;
  1124. }
  1125. goto Exit;
  1126. }
  1127. // DNProcessHostMigration3
  1128. //
  1129. //
  1130. #undef DPF_MODNAME
  1131. #define DPF_MODNAME "DNProcessHostMigration3"
  1132. HRESULT DNProcessHostMigration3(DIRECTNETOBJECT *const pdnObject,
  1133. const DPNID dpnid)
  1134. {
  1135. HRESULT hResultCode;
  1136. CNameTableEntry *pNTEntry;
  1137. DPFX(DPFPREP, 6,"Parameters: dpnid [0x%lx]",dpnid);
  1138. pNTEntry = NULL;
  1139. // No longer in Host migration mode
  1140. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1141. pdnObject->dwFlags &= (~DN_OBJECT_FLAG_HOST_MIGRATING);
  1142. if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING)
  1143. {
  1144. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1145. hResultCode = DPN_OK;
  1146. goto Exit;
  1147. }
  1148. //
  1149. // If we receive a HOST_MIGRATION_COMPLETE, we need to ensure that it is for the current host migration,
  1150. // and that another one hasn't started after.
  1151. // If this is the correct new host (i.e. pdnObject->pNewHost != NULL and DPNID's match),
  1152. // then we will continue. Otherwise, we will exit this function.
  1153. //
  1154. if (pdnObject->pNewHost)
  1155. {
  1156. if (pdnObject->pNewHost->GetDPNID() == dpnid)
  1157. {
  1158. pNTEntry = pdnObject->pNewHost;
  1159. pdnObject->pNewHost = NULL;
  1160. }
  1161. }
  1162. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1163. if (pNTEntry)
  1164. {
  1165. pNTEntry->Release();
  1166. pNTEntry = NULL;
  1167. //
  1168. // Complete outstanding operations
  1169. //
  1170. DPFX(DPFPREP, 7,"Completing outstanding operations");
  1171. hResultCode = DNCompleteOutstandingOperations(pdnObject);
  1172. }
  1173. else
  1174. {
  1175. DPFX(DPFPREP,7,"Host migration completed by wrong new host - ignore and continue");
  1176. }
  1177. hResultCode = DPN_OK;
  1178. Exit:
  1179. DNASSERT( pNTEntry == NULL );
  1180. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1181. return(hResultCode);
  1182. }
  1183. // DNCompleteOutstandingOperations
  1184. //
  1185. // We will attempt to complete any outstanding asynchronous NameTable operations
  1186. // (i.e. create/destroy group, add/delete player to/from group, update info).
  1187. // If we are the Host player,
  1188. // - try processing the request directly
  1189. // - release the async op to generate completions
  1190. // Otherwise
  1191. // - resend the request to the Host
  1192. #undef DPF_MODNAME
  1193. #define DPF_MODNAME "DNCompleteOutstandingOperations"
  1194. HRESULT DNCompleteOutstandingOperations(DIRECTNETOBJECT *const pdnObject)
  1195. {
  1196. HRESULT hResultCode;
  1197. CBilink *pBilink;
  1198. CAsyncOp *pAsyncOp;
  1199. CAsyncOp *pSend;
  1200. CAsyncOp **RequestList;
  1201. CConnection *pConnection;
  1202. CNameTableEntry *pHostPlayer;
  1203. CNameTableEntry *pLocalPlayer;
  1204. DN_SEND_OP_DATA *pSendOpData;
  1205. DWORD dwCount;
  1206. DWORD dwActual;
  1207. DPFX(DPFPREP, 6,"Parameters: none");
  1208. DNASSERT(pdnObject != NULL);
  1209. pAsyncOp = NULL;
  1210. pSend = NULL;
  1211. RequestList = NULL;
  1212. pConnection = NULL;
  1213. pHostPlayer = NULL;
  1214. pLocalPlayer = NULL;
  1215. //
  1216. // Get Host connection
  1217. //
  1218. if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK)
  1219. {
  1220. DPFERR("Could not get host player reference");
  1221. DisplayDNError(0,hResultCode);
  1222. goto Failure;
  1223. }
  1224. if ((hResultCode = pHostPlayer->GetConnectionRef( &pConnection )) != DPN_OK)
  1225. {
  1226. DPFERR("Could not get host connection reference");
  1227. DisplayDNError(0,hResultCode);
  1228. goto Failure;
  1229. }
  1230. pHostPlayer->Release();
  1231. pHostPlayer = NULL;
  1232. //
  1233. // Get local player
  1234. //
  1235. if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
  1236. {
  1237. DPFERR("Could not get local player reference");
  1238. DisplayDNError(0,hResultCode);
  1239. goto Failure;
  1240. }
  1241. dwCount = 0;
  1242. dwActual = 0;
  1243. //
  1244. // Determine outstanding request list size and build it
  1245. //
  1246. DNEnterCriticalSection(&pdnObject->csActiveList);
  1247. pBilink = pdnObject->m_bilinkRequestList.GetNext();
  1248. while (pBilink != &pdnObject->m_bilinkRequestList)
  1249. {
  1250. dwCount++;
  1251. pBilink = pBilink->GetNext();
  1252. }
  1253. if (dwCount > 0)
  1254. {
  1255. if ((RequestList = static_cast<CAsyncOp**>(MemoryBlockAlloc(pdnObject,dwCount * sizeof(CAsyncOp*)))) == NULL)
  1256. {
  1257. DNLeaveCriticalSection(&pdnObject->csActiveList);
  1258. DPFERR("Could not allocate request list");
  1259. hResultCode = DPNERR_OUTOFMEMORY;
  1260. goto Failure;
  1261. }
  1262. pBilink = pdnObject->m_bilinkRequestList.GetNext();
  1263. while (pBilink != &pdnObject->m_bilinkRequestList)
  1264. {
  1265. pAsyncOp = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkActiveList);
  1266. DNASSERT(dwActual < dwCount);
  1267. DNASSERT(pAsyncOp->GetOpType() == ASYNC_OP_REQUEST);
  1268. pAsyncOp->AddRef();
  1269. RequestList[dwActual] = pAsyncOp;
  1270. pAsyncOp = NULL;
  1271. dwActual++;
  1272. pBilink = pBilink->GetNext();
  1273. }
  1274. }
  1275. DNLeaveCriticalSection(&pdnObject->csActiveList);
  1276. //
  1277. // Perform outstanding requests
  1278. //
  1279. if (RequestList)
  1280. {
  1281. DWORD dw;
  1282. for ( dw = 0 ; dw < dwActual ; dw++ )
  1283. {
  1284. pSendOpData = RequestList[dw]->GetLocalSendOpData();
  1285. if ( pSendOpData->dwMsgId == DN_MSG_INTERNAL_REQ_CREATE_GROUP
  1286. || pSendOpData->dwMsgId == DN_MSG_INTERNAL_REQ_DESTROY_GROUP
  1287. || pSendOpData->dwMsgId == DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP
  1288. || pSendOpData->dwMsgId == DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP
  1289. || pSendOpData->dwMsgId == DN_MSG_INTERNAL_REQ_UPDATE_INFO
  1290. || pSendOpData->dwMsgId == DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK)
  1291. {
  1292. DPFX(DPFPREP, 7,"Found outstanding operation: dwMsgId [0x%lx]",pSendOpData->dwMsgId);
  1293. if (pLocalPlayer->IsHost())
  1294. {
  1295. //
  1296. // Remove request from request list
  1297. //
  1298. DNEnterCriticalSection(&pdnObject->csActiveList);
  1299. RequestList[dw]->m_bilinkActiveList.RemoveFromList();
  1300. DNLeaveCriticalSection(&pdnObject->csActiveList);
  1301. hResultCode = DNHostProcessRequest( pdnObject,
  1302. pSendOpData->dwMsgId,
  1303. pSendOpData->BufferDesc[1].pBufferData,
  1304. pLocalPlayer->GetDPNID() );
  1305. }
  1306. else
  1307. {
  1308. //
  1309. // re-SEND REQUEST
  1310. //
  1311. hResultCode = DNPerformChildSend( pdnObject,
  1312. RequestList[dw],
  1313. pConnection,
  1314. 0,
  1315. &pSend,
  1316. TRUE);
  1317. if (hResultCode == DPNERR_PENDING)
  1318. {
  1319. //
  1320. // Reset SEND AsyncOp to complete apropriately.
  1321. //
  1322. pSend->SetCompletion( DNCompleteSendRequest );
  1323. pSend->Release();
  1324. pSend = NULL;
  1325. }
  1326. }
  1327. }
  1328. pSendOpData = NULL;
  1329. RequestList[dw]->Release();
  1330. RequestList[dw] = NULL;
  1331. }
  1332. MemoryBlockFree(pdnObject,RequestList);
  1333. RequestList = NULL;
  1334. }
  1335. pLocalPlayer->Release();
  1336. pLocalPlayer = NULL;
  1337. pConnection->Release();
  1338. pConnection = NULL;
  1339. hResultCode = DPN_OK;
  1340. Exit:
  1341. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1342. return(hResultCode);
  1343. Failure:
  1344. if (pLocalPlayer)
  1345. {
  1346. pLocalPlayer->Release();
  1347. pLocalPlayer = NULL;
  1348. }
  1349. if (pHostPlayer)
  1350. {
  1351. pHostPlayer->Release();
  1352. pHostPlayer = NULL;
  1353. }
  1354. if (pConnection)
  1355. {
  1356. pConnection->Release();
  1357. pConnection = NULL;
  1358. }
  1359. if (RequestList)
  1360. {
  1361. MemoryBlockFree(pdnObject,RequestList);
  1362. RequestList = NULL;
  1363. }
  1364. goto Exit;
  1365. }
  1366. // DNCheckReceivedAllVersions
  1367. //
  1368. // Check to see if all players in the NameTable have returned their
  1369. // NameTable versions. If so, ensure the NameTables are re-sync'd and
  1370. // then finish the Host migration
  1371. #undef DPF_MODNAME
  1372. #define DPF_MODNAME "DNCheckReceivedAllVersions"
  1373. HRESULT DNCheckReceivedAllVersions(DIRECTNETOBJECT *const pdnObject)
  1374. {
  1375. HRESULT hResultCode;
  1376. CBilink *pBilink;
  1377. CNameTableEntry *pNTEntry;
  1378. BOOL bNotReady;
  1379. DPFX(DPFPREP, 6,"Parameters: (none)");
  1380. DNASSERT(pdnObject != NULL);
  1381. bNotReady = FALSE;
  1382. pdnObject->NameTable.ReadLock();
  1383. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  1384. while ((pBilink != &pdnObject->NameTable.m_bilinkPlayers) && (!bNotReady))
  1385. {
  1386. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1387. pNTEntry->Lock();
  1388. if (!pNTEntry->IsDisconnecting() && (pNTEntry->GetLatestVersion() == 0))
  1389. {
  1390. //
  1391. // Ensure that we are not including dropped/disconnected players who have yet to be processed
  1392. //
  1393. CConnection *pConnection;
  1394. pConnection = NULL;
  1395. pNTEntry->Unlock();
  1396. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) == DPN_OK)
  1397. {
  1398. if (!pConnection->IsDisconnecting() && !pConnection->IsInvalid())
  1399. {
  1400. DPFX(DPFPREP, 7,"Player [0x%lx] has not returned dwLatestVersion",pNTEntry->GetDPNID());
  1401. bNotReady = TRUE; // these must all be non-zero
  1402. }
  1403. pConnection->Release();
  1404. pConnection = NULL;
  1405. }
  1406. }
  1407. else
  1408. {
  1409. pNTEntry->Unlock();
  1410. }
  1411. pNTEntry = NULL;
  1412. pBilink = pBilink->GetNext();
  1413. }
  1414. pdnObject->NameTable.Unlock();
  1415. if (bNotReady)
  1416. {
  1417. DPFX(DPFPREP, 7,"All players have not responded");
  1418. return(DPNERR_PENDING);
  1419. }
  1420. //
  1421. // Ensure only one thread runs this from here on out
  1422. //
  1423. DNEnterCriticalSection(&pdnObject->csDirectNetObject);
  1424. if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING))
  1425. {
  1426. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1427. DPFX(DPFPREP, 7,"Another thread has already finished Host Migration - returning");
  1428. hResultCode = DPN_OK;
  1429. goto Exit;
  1430. }
  1431. if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING_2)
  1432. {
  1433. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1434. DPFX(DPFPREP, 7,"Another thread will proceed with Host Migration - returning");
  1435. hResultCode = DPN_OK;
  1436. goto Exit;
  1437. }
  1438. pdnObject->dwFlags |= DN_OBJECT_FLAG_HOST_MIGRATING_2;
  1439. DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
  1440. DPFX(DPFPREP, 7,"All players have responded - host migration stage 1 complete");
  1441. hResultCode = DNPerformHostMigration2(pdnObject);
  1442. hResultCode = DPN_OK;
  1443. Exit:
  1444. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1445. return(hResultCode);
  1446. }
  1447. // DNCleanUpNameTable
  1448. //
  1449. // Clean up the NameTable.
  1450. // There are some cases where dropped players are not properly removed from the NameTable.
  1451. // An example is when the Host-elect drops right after the Host before it has a chance
  1452. // to send out a HOST_MIGRATE message. In this case, since the HOST_MIGRATE message
  1453. // implicitly includes the DELETE_PLAYER message for the original Host, the original
  1454. // Host player never gets removed from current players' NameTables, though it DOES get
  1455. // marked as DISCONNECTING.
  1456. // Delete all DISCONNECTING players with older NameTable versions than ourselves.
  1457. // Players with newer NameTable versions imply WE are the Host player, so we will
  1458. // take care of them later (Pending Operations)
  1459. #undef DPF_MODNAME
  1460. #define DPF_MODNAME "DNCleanUpNameTable"
  1461. HRESULT DNCleanUpNameTable(DIRECTNETOBJECT *const pdnObject)
  1462. {
  1463. HRESULT hResultCode;
  1464. CBilink *pBilink;
  1465. CNameTableEntry *pNTEntry;
  1466. DPNID *List;
  1467. DWORD dwCount;
  1468. DWORD dwActual;
  1469. DWORD dw;
  1470. DPFX(DPFPREP, 6,"Parameters: (none)");
  1471. DNASSERT(pdnObject != NULL);
  1472. List = NULL;
  1473. //
  1474. // Create list of old player DPNID's
  1475. //
  1476. dwCount = 0;
  1477. dwActual = 0;
  1478. pdnObject->NameTable.ReadLock();
  1479. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  1480. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  1481. {
  1482. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1483. pNTEntry->Lock();
  1484. if (pNTEntry->IsDisconnecting() && (pNTEntry->GetVersion() < pdnObject->NameTable.GetLocalPlayer()->GetVersion()))
  1485. {
  1486. DPFX(DPFPREP, 7,"Found old player [0x%lx]",pNTEntry->GetDPNID());
  1487. dwCount++;
  1488. }
  1489. pNTEntry->Unlock();
  1490. pBilink = pBilink->GetNext();
  1491. }
  1492. if (dwCount)
  1493. {
  1494. if ((List = static_cast<DPNID*>(DNMalloc(dwCount * sizeof(DPNID*)))) != NULL)
  1495. {
  1496. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  1497. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  1498. {
  1499. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1500. pNTEntry->Lock();
  1501. if (pNTEntry->IsDisconnecting() && (pNTEntry->GetVersion() < pdnObject->NameTable.GetLocalPlayer()->GetVersion()))
  1502. {
  1503. DNASSERT(dwActual < dwCount);
  1504. List[dwActual] = pNTEntry->GetDPNID();
  1505. dwActual++;
  1506. }
  1507. pNTEntry->Unlock();
  1508. pBilink = pBilink->GetNext();
  1509. }
  1510. }
  1511. }
  1512. pdnObject->NameTable.Unlock();
  1513. //
  1514. // Remove old players
  1515. //
  1516. if (List)
  1517. {
  1518. for (dw = 0 ; dw < dwActual ; dw++)
  1519. {
  1520. DPFX(DPFPREP, 7,"Removing old player [0x%lx]",List[dw]);
  1521. DNHostDisconnect(pdnObject,List[dw],DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
  1522. List[dw] = 0;
  1523. }
  1524. DNFree(List);
  1525. List = NULL;
  1526. }
  1527. hResultCode = DPN_OK;
  1528. DNASSERT(List == NULL);
  1529. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1530. return(hResultCode);
  1531. }
  1532. // DNSendHostMigrateCompleteMessage
  1533. //
  1534. // Send a HOST_MIGRATE_COMPLETE message to connected players
  1535. #undef DPF_MODNAME
  1536. #define DPF_MODNAME "DNSendHostMigrateCompleteMessage"
  1537. HRESULT DNSendHostMigrateCompleteMessage(DIRECTNETOBJECT *const pdnObject)
  1538. {
  1539. HRESULT hResultCode;
  1540. CAsyncOp *pParent;
  1541. CBilink *pBilink;
  1542. CNameTableEntry *pNTEntry;
  1543. CConnection *pConnection;
  1544. DPFX(DPFPREP, 6,"Parameters: (none)");
  1545. DNASSERT(pdnObject != NULL);
  1546. pParent = NULL;
  1547. pNTEntry = NULL;
  1548. pConnection = NULL;
  1549. hResultCode = DNCreateSendParent( pdnObject,
  1550. DN_MSG_INTERNAL_HOST_MIGRATE_COMPLETE,
  1551. NULL,
  1552. 0,
  1553. DN_SENDFLAGS_RELIABLE,
  1554. &pParent);
  1555. if (hResultCode != DPN_OK)
  1556. {
  1557. DPFERR("Could not create AsyncOp");
  1558. DisplayDNError(0,hResultCode);
  1559. DNASSERT(FALSE);
  1560. goto Failure;
  1561. }
  1562. //
  1563. // Lock NameTable
  1564. //
  1565. pdnObject->NameTable.ReadLock();
  1566. pBilink = pdnObject->NameTable.m_bilinkPlayers.GetNext();
  1567. while (pBilink != &pdnObject->NameTable.m_bilinkPlayers)
  1568. {
  1569. pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries);
  1570. if (!pNTEntry->IsDisconnecting() && !pNTEntry->IsLocal())
  1571. {
  1572. if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) == DPN_OK)
  1573. {
  1574. hResultCode = DNPerformChildSend( pdnObject,
  1575. pParent,
  1576. pConnection,
  1577. 0,
  1578. NULL,
  1579. TRUE);
  1580. if (hResultCode != DPNERR_PENDING)
  1581. {
  1582. DPFERR("Could not perform part of group send - ignore and continue");
  1583. DisplayDNError(0,hResultCode);
  1584. DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
  1585. }
  1586. pConnection->Release();
  1587. pConnection = NULL;
  1588. }
  1589. }
  1590. pBilink = pBilink->GetNext();
  1591. }
  1592. //
  1593. // Unlock NameTable
  1594. //
  1595. pdnObject->NameTable.Unlock();
  1596. pParent->Release();
  1597. pParent = NULL;
  1598. Exit:
  1599. DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
  1600. return(hResultCode);
  1601. Failure:
  1602. if (pParent)
  1603. {
  1604. pParent->Release();
  1605. pParent = NULL;
  1606. }
  1607. goto Exit;
  1608. }
  1609. #endif // !DPNBUILD_NOHOSTMIGRATE